instagram

This commit is contained in:
Mateusz Hinc 2020-01-11 18:18:34 +01:00
parent 066400f700
commit 61f2af2cb9
22 changed files with 2000 additions and 194 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -76,4 +76,9 @@ dependencies {
implementation 'com.facebook.android:facebook-share:[5,6)' implementation 'com.facebook.android:facebook-share:[5,6)'
implementation 'com.squareup.picasso:picasso:2.5.2' implementation 'com.squareup.picasso:picasso:2.5.2'
implementation([
'com.snapchat.kit.sdk:creative:1.1.4',
'com.snapchat.kit.sdk:core:1.1.4'
])
} }

View File

@ -2,6 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="pl.edu.amu.wmi.socialaggregator"> package="pl.edu.amu.wmi.socialaggregator">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application <application
@ -68,6 +69,24 @@
android:name="com.facebook.FacebookContentProvider" android:name="com.facebook.FacebookContentProvider"
android:exported="true"/> android:exported="true"/>
<meta-data android:name="com.snapchat.kit.sdk.clientId" android:value="240836fb-b762-4be8-a42f-5472a22f2114" />
<!-- <meta-data android:name="com.snapchat.kit.sdk.clientId" android:value="your apps client id" />-->
<!-- <meta-data android:name="com.snapchat.kit.sdk.redirectUrl" android:value="the url that will handle login completion" />-->
<!-- <meta-data android:name="com.snapchat.kit.sdk.scopes" android:resource="@array/snap_connect_scopes" />-->
<provider
android:authorities="${applicationId}.fileprovider,pl.edu.amu.wmi.socialaggregator.activity.NewPostActivity"
android:name="androidx.core.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths"
/>
</provider>
</application> </application>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>

View File

@ -2,24 +2,16 @@ package pl.edu.amu.wmi.socialaggregator.activity
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.facebook.CallbackManager
import com.facebook.FacebookCallback
import com.facebook.FacebookException
import com.facebook.login.LoginResult
import com.jakewharton.rxbinding2.view.RxView import com.jakewharton.rxbinding2.view.RxView
import io.reactivex.Observable
import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.CompositeDisposable
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
import pl.edu.amu.wmi.socialaggregator.R import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager
import pl.edu.amu.wmi.socialaggregator.viewholders.PostSummaryRecycler import pl.edu.amu.wmi.socialaggregator.viewholders.PostSummaryRecycler
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
import com.facebook.AccessToken
import com.facebook.login.LoginManager
import com.facebook.share.widget.ShareDialog
import io.reactivex.Observable
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -38,30 +30,6 @@ class MainActivity : AppCompatActivity() {
val intent = Intent(this, NewPostActivity::class.java) val intent = Intent(this, NewPostActivity::class.java)
startActivity(intent) startActivity(intent)
}, },
// RxView.clicks(connectedSocialsButton)
// .subscribe {
// val accessToken = AccessToken.getCurrentAccessToken()
// val isLoggedIn = accessToken != null && !accessToken.isExpired
//
// Log.i(TAG, isLoggedIn.toString())
//
// LoginManager.getInstance().logInWithReadPermissions(this, listOf("public_profile"))
//
//// val request = GraphRequest.newMeRequest(
//// accessToken
//// ) { `object`, response ->
//// Log.v("LoginActivity", response.toString())
////
//// // Application code
//// }
//// val parameters = Bundle()
//// parameters.putString("fields", "id,name,email,gender,birthday")
//// request.parameters = parameters
//// request.executeAsync()
// ShareDialog(this).show()
//// val intent = Intent(this, AddSocialActivity::class.java)
//// startActivity(intent)
// },
RxView.clicks(previousPostsButton) RxView.clicks(previousPostsButton)
.subscribe { .subscribe {
val intent = Intent(this, PostHistoryActivity::class.java) val intent = Intent(this, PostHistoryActivity::class.java)
@ -72,7 +40,7 @@ class MainActivity : AppCompatActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
SocialPlatformsManager.getAll() SocialPlatformsManager.getAll()
.forEach { it.onActivityResult(requestCode, resultCode, data)} .forEach { it.onActivityResult(requestCode, resultCode, data) }
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
} }
@ -88,12 +56,13 @@ class MainActivity : AppCompatActivity() {
previousPostsRecyclerView.apply { previousPostsRecyclerView.apply {
layoutManager = LinearLayoutManager(this@MainActivity) layoutManager = LinearLayoutManager(this@MainActivity)
adapter = PostSummaryRecycler( adapter = PostSummaryRecycler(
Observable.fromIterable(SocialPlatformsManager.getLoggedIn(this@MainActivity)) Observable.merge(SocialPlatformsManager.getLoggedIn(this@MainActivity)
.flatMap { social -> .map { social ->
return@flatMap social.getPosts(this@MainActivity) social.getPosts(this@MainActivity)
.map { social to it } .map { social to it }
.toObservable() .toObservable()
}) })
)
} }
} }

View File

@ -2,12 +2,13 @@ package pl.edu.amu.wmi.socialaggregator.activity
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.MediaStore import android.provider.MediaStore
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -15,16 +16,25 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import com.jakewharton.rxbinding2.view.RxView import com.jakewharton.rxbinding2.view.RxView
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.functions.BiFunction
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import kotlinx.android.synthetic.main.activity_new_post.* import kotlinx.android.synthetic.main.activity_new_post.*
import kotlinx.android.synthetic.main.content_new_post.* import kotlinx.android.synthetic.main.content_new_post.*
import pl.edu.amu.wmi.socialaggregator.R import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithToggleRecycler import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithToggleRecycler
class NewPostActivity : AppCompatActivity() { class NewPostActivity : AppCompatActivity() {
var file: String? = null var file: String? = null
val postedSubject = PublishSubject.create<Any>()
val resumedSubject = PublishSubject.create<Any>()
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -47,16 +57,48 @@ class NewPostActivity : AppCompatActivity() {
RxView.clicks(publishPost) RxView.clicks(publishPost)
.filter { file != null } .filter { file != null }
.subscribe { .doOnNext {
availablesRecycler.chips.entries val sdk = android.os.Build.VERSION.SDK_INT
.filter { (_, chip) -> chip.isChecked } if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
.forEach { (social, _) -> val clipboard =
getSystemService(Context.CLIPBOARD_SERVICE) as android.text.ClipboardManager
clipboard.text = postText.text?.toString() ?: ""
} else {
val clipboard =
getSystemService(Context.CLIPBOARD_SERVICE) as android.content.ClipboardManager
val clip = android.content.ClipData.newPlainText(
"text label",
postText.text?.toString() ?: ""
)
clipboard.primaryClip = clip
}
}
.observeOn(Schedulers.io())
.doOnNext {
resumedSubject.zipWith(
Observable.fromIterable(availablesRecycler.chips.entries
.filter { (_, chip) -> chip.isChecked }
.map { it.key }),
BiFunction<Any, SocialPlatform, SocialPlatform> { _, t2 -> t2 }
)
.doOnNext {
val bitmap = BitmapFactory.decodeFile(file!!) val bitmap = BitmapFactory.decodeFile(file!!)
social.addPost(this, postText.text?.toString() ?: "test", listOf(bitmap)) it.addPost(
.blockingSubscribe() postedSubject, this,
Toast.makeText(this, "Posted to ${social.getName()}!", Toast.LENGTH_SHORT) postText.text?.toString() ?: "",
.show() listOf(bitmap),
listOf(file!!)
)
} }
.take(availablesRecycler.chips.count { it.value.isChecked }.toLong())
.toList()
.subscribe { _ ->
finish()
}
}
.subscribe {
resumedSubject.onNext(Any())
} }
RxView.clicks(imageView2) RxView.clicks(imageView2)
@ -86,18 +128,33 @@ class NewPostActivity : AppCompatActivity() {
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
SocialPlatformsManager.getAll()
.forEach { it.onActivityResult(requestCode, resultCode, data) }
super.onActivityResult(requestCode, resultCode, data) super.onActivityResult(requestCode, resultCode, data)
if (requestCode == PICK_IMAGE_REQUEST_CODE) { if (requestCode == PICK_IMAGE_REQUEST_CODE) {
data?.data?.let { uri -> data?.data?.let { uri ->
uri.pathSegments?.last()?.let { file = getPath(uri)
file = it
}
imageView2.setImageURI(uri) imageView2.setImageURI(uri)
} }
} }
} }
fun getPath(uri: Uri): String? {
val projection = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(uri, projection, null, null, null) ?: return null
val column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
val s = cursor.getString(column_index)
cursor.close()
return s
}
override fun onResume() {
super.onResume()
resumedSubject.onNext(Any())
}
private fun canAccessGallery() = private fun canAccessGallery() =
(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)

View File

@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.icu.text.SimpleDateFormat
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
@ -12,11 +11,9 @@ import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet import androidx.constraintlayout.widget.ConstraintSet
import com.facebook.* import com.facebook.*
import com.facebook.login.LoginManager
import com.facebook.login.LoginResult import com.facebook.login.LoginResult
import com.facebook.login.widget.LoginButton import com.facebook.login.widget.LoginButton
import pl.edu.amu.wmi.socialaggregator.utils.Utils
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
import com.facebook.login.LoginManager
import com.facebook.share.Sharer import com.facebook.share.Sharer
import com.facebook.share.model.ShareMediaContent import com.facebook.share.model.ShareMediaContent
import com.facebook.share.model.SharePhoto import com.facebook.share.model.SharePhoto
@ -28,7 +25,8 @@ import io.reactivex.subjects.PublishSubject
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import pl.edu.amu.wmi.socialaggregator.R import pl.edu.amu.wmi.socialaggregator.R
import java.lang.Exception import pl.edu.amu.wmi.socialaggregator.utils.Utils
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
class Facebook : SocialPlatform { class Facebook : SocialPlatform {
@ -52,15 +50,21 @@ class Facebook : SocialPlatform {
return accessToken != null && !accessToken.isExpired return accessToken != null && !accessToken.isExpired
} }
override fun addPost(context: Context, text: String, images: List<Bitmap>) : PublishSubject<Any> { override fun addPost(
publishSubject: PublishSubject<Any>,
context: Context,
text: String,
images: List<Bitmap>,
imagePaths: List<String>
) {
val content = ShareMediaContent.Builder().apply { val content = ShareMediaContent.Builder().apply {
images.forEach {addMedium( images.forEach {
SharePhoto.Builder().setBitmap(it).build() addMedium(
)} SharePhoto.Builder().setBitmap(it).build()
)
}
}.build() }.build()
val publishSubject = PublishSubject.create<Any>()
val shareDialog = ShareDialog(context as Activity) val shareDialog = ShareDialog(context as Activity)
shareDialog.registerCallback(callbackManager, object : FacebookCallback<Sharer.Result?> { shareDialog.registerCallback(callbackManager, object : FacebookCallback<Sharer.Result?> {
override fun onSuccess(result: Sharer.Result?) { override fun onSuccess(result: Sharer.Result?) {
@ -68,7 +72,7 @@ class Facebook : SocialPlatform {
} }
override fun onCancel() { override fun onCancel() {
publishSubject.onError(Exception("Cancelled")) publishSubject.onNext(Any())
} }
override fun onError(error: FacebookException?) { override fun onError(error: FacebookException?) {
@ -76,23 +80,26 @@ class Facebook : SocialPlatform {
} }
}) })
shareDialog.show(content, ShareDialog.Mode.AUTOMATIC) shareDialog.show(content, ShareDialog.Mode.AUTOMATIC)
return publishSubject
} }
override fun getPosts(context: Context): Single<List<Post>> { override fun getPosts(context: Context): Single<List<Post>> {
return Single.just(AccessToken.getCurrentAccessToken()) return Single.just(AccessToken.getCurrentAccessToken())
.observeOn(Schedulers.io())
.map { token -> .map { token ->
if (token.isExpired) { if (token.isExpired) {
return@map emptyList<Post>() return@map emptyList<Post>()
} else { } else {
val request = GraphRequest.newGraphPathRequest( val request = GraphRequest.newGraphPathRequest(
AccessToken.getCurrentAccessToken(), AccessToken.getCurrentAccessToken(),
"/me/posts") { "/me/posts"
) {
Log.i(getName(), it.toString()) Log.i(getName(), it.toString())
} }
val parameters = Bundle() val parameters = Bundle()
parameters.putString("fields", "likes.summary(true),created_time,message,attachments{url,unshimmed_url,media,subattachments}") parameters.putString(
"fields",
"likes.summary(true),created_time,message,attachments{url,unshimmed_url,media,subattachments}"
)
request.parameters = parameters request.parameters = parameters
val res = request.executeAndWait() val res = request.executeAndWait()
@ -100,14 +107,14 @@ class Facebook : SocialPlatform {
val size = data.length() val size = data.length()
return@map (0 until size).map { return@map (0 until size).map {
val obj = data[it] as JSONObject val obj = data[it] as JSONObject
val msg = if(obj.has("message")) obj.getString("message") else "" val msg = if (obj.has("message")) obj.getString("message") else ""
val date = if(obj.has("created_time")) obj.getString("created_time") else "" val date =
if (obj.has("created_time")) obj.getString("created_time") else ""
// SimpleDateFormat("YYYY-MM-DD\'T\'hh:mm:ssZ").parse(date) // SimpleDateFormat("YYYY-MM-DD\'T\'hh:mm:ssZ").parse(date)
Post(this, msg, date, getImages(obj)) Post(this, msg, date, getImages(obj))
} }
} }
} }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
} }
@ -122,12 +129,15 @@ class Facebook : SocialPlatform {
.flatMap { .flatMap {
val urls = mutableListOf<String>() val urls = mutableListOf<String>()
if (it.has("media")) { if (it.has("media")) {
urls.add(it.getJSONObject("media") urls.add(
.getJSONObject("image") it.getJSONObject("media")
.getString("src")) .getJSONObject("image")
.getString("src")
)
} }
if (it.has("subattachments")) { if (it.has("subattachments")) {
val subattachments = it.getJSONObject("subattachments").getJSONArray("data") val subattachments =
it.getJSONObject("subattachments").getJSONArray("data")
urls.addAll((0 until subattachments.length()) urls.addAll((0 until subattachments.length())
.map { subattachments[it] as JSONObject } .map { subattachments[it] as JSONObject }
.map { .map {
@ -158,21 +168,35 @@ class Facebook : SocialPlatform {
parent.addView(button) parent.addView(button)
constraintSet.clone(parent as ConstraintLayout) constraintSet.clone(parent as ConstraintLayout)
constraintSet.connect(button.id, ConstraintSet.TOP, constraintSet.connect(
parent.id, ConstraintSet.TOP, 8.toPx(context)) button.id, ConstraintSet.TOP,
constraintSet.connect(button.id, ConstraintSet.END, parent.id, ConstraintSet.TOP, 8.toPx(context)
parent.id, ConstraintSet.END) )
constraintSet.connect(button.id, ConstraintSet.BOTTOM, constraintSet.connect(
parent.id, ConstraintSet.BOTTOM, 8.toPx(context)) button.id, ConstraintSet.END,
parent.id, ConstraintSet.END
)
constraintSet.connect(
button.id, ConstraintSet.BOTTOM,
parent.id, ConstraintSet.BOTTOM, 8.toPx(context)
)
constraintSet.connect(viewHolder.textView.id, ConstraintSet.BOTTOM, constraintSet.connect(
button.id, ConstraintSet.BOTTOM) viewHolder.textView.id, ConstraintSet.BOTTOM,
constraintSet.connect(viewHolder.textView.id, ConstraintSet.END, button.id, ConstraintSet.BOTTOM
button.id, ConstraintSet.START, 8.toPx(context)) )
constraintSet.connect(viewHolder.textView.id, ConstraintSet.START, constraintSet.connect(
parent.id, ConstraintSet.START) viewHolder.textView.id, ConstraintSet.END,
constraintSet.connect(viewHolder.textView.id, ConstraintSet.TOP, button.id, ConstraintSet.START, 8.toPx(context)
button.id, ConstraintSet.TOP) )
constraintSet.connect(
viewHolder.textView.id, ConstraintSet.START,
parent.id, ConstraintSet.START
)
constraintSet.connect(
viewHolder.textView.id, ConstraintSet.TOP,
button.id, ConstraintSet.TOP
)
constraintSet.setHorizontalBias(viewHolder.textView.id, 0.toFloat()) constraintSet.setHorizontalBias(viewHolder.textView.id, 0.toFloat())
constraintSet.applyTo(parent) constraintSet.applyTo(parent)
@ -180,8 +204,10 @@ class Facebook : SocialPlatform {
val callback = object : FacebookCallback<LoginResult> { val callback = object : FacebookCallback<LoginResult> {
override fun onSuccess(result: LoginResult?) { override fun onSuccess(result: LoginResult?) {
Log.i(getName(), "SUCCESS!") Log.i(getName(), "SUCCESS!")
LoginManager.getInstance().logInWithReadPermissions(context as Activity, LoginManager.getInstance().logInWithReadPermissions(
listOf("email")) context as Activity,
listOf("email")
)
} }
override fun onCancel() { override fun onCancel() {

View File

@ -1,84 +0,0 @@
package pl.edu.amu.wmi.socialaggregator.socialplatforms
import android.content.Context
import android.graphics.Bitmap
import android.util.Log
import io.reactivex.Single
import io.reactivex.subjects.PublishSubject
import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.utils.InternalStorage
import java.io.ByteArrayOutputStream
import java.io.File
import java.text.DateFormat
import java.util.*
abstract class FacebookMock : SocialPlatform {
companion object {
val TAG = FacebookMock::class.java.canonicalName
}
override fun getName(): String = "Facebook Mock"
override fun getLogo(): Int = R.mipmap.ic_logo_facebook
override fun login(context: Context) {
val loginsDir = InternalStorage.getFileOrDir(context, "logins")
loginsDir?.mkdir()
if (loginsDir != null) {
val loginFile = File(loginsDir, "facebook")
loginFile.createNewFile()
} else {
Log.e(TAG, "Could not create logins directory")
}
}
override fun logout(context: Context) {
InternalStorage.getFileOrDir(context, "logins/facebook")?.delete()
}
override fun isLoggedIn(context: Context): Boolean {
return InternalStorage.getFileOrDir(context, "logins/facebook")?.exists() ?: false
}
override fun addPost(context: Context, text: String, images: List<Bitmap>): PublishSubject<Any> {
val postsDir = InternalStorage.getFileOrDir(context, "posts/facebook")
if (postsDir != null) {
val postDir = File(postsDir, System.currentTimeMillis().toString())
postDir.mkdirs()
val textFile = File(postDir, "content")
textFile.createNewFile()
textFile.writeText(text)
images.forEachIndexed { index, image ->
val imageFile = File(postDir, "image$index")
imageFile.createNewFile()
ByteArrayOutputStream().use { stream ->
image.compress(Bitmap.CompressFormat.JPEG, 100, stream)
imageFile.writeBytes(stream.toByteArray())
}
}
} else {
Log.e(TAG, "Could not create posts directory")
}
return PublishSubject.create()
}
override fun getPosts(context: Context): Single<List<Post>> {
val postsDir = InternalStorage.getFileOrDir(context, "posts/facebook")
return Single.just(postsDir?.listFiles()?.flatMap {
it.listFiles().map {
val dt = Date(it.lastModified())
Post(
this,
it.readText(),
DateFormat.getDateTimeInstance().format(dt),
emptyList()
)
}
}?.toList() ?: emptyList())
}
}

View File

@ -0,0 +1,5 @@
package pl.edu.amu.wmi.socialaggregator.socialplatforms
import java.lang.Exception
class NotApplicableException(val socialPlatform: SocialPlatform) : Exception()

View File

@ -0,0 +1,79 @@
package pl.edu.amu.wmi.socialaggregator.socialplatforms
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.util.Log
import com.snapchat.kit.sdk.SnapCreative
import com.snapchat.kit.sdk.creative.api.SnapCreativeKitCompletionCallback
import com.snapchat.kit.sdk.creative.api.SnapCreativeKitSendError
import com.snapchat.kit.sdk.creative.exceptions.SnapMediaSizeException
import com.snapchat.kit.sdk.creative.models.SnapPhotoContent
import io.reactivex.Single
import io.reactivex.subjects.PublishSubject
import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
import java.io.File
import java.lang.Exception
class Snapchat : SocialPlatform {
override fun getName(): String = "Snapchat"
override fun login(context: Context) {
}
override fun logout(context: Context) {
}
override fun isLoggedIn(context: Context): Boolean = true
override fun addPost(
publishSubject: PublishSubject<Any>,
context: Context,
text: String,
images: List<Bitmap>,
imagePaths: List<String>
) {
val snapCreativeKitApi = SnapCreative.getApi(context)
val content = imagePaths.map {
val snapMediaFactory = SnapCreative.getMediaFactory(context)
val photoFile = try {
snapMediaFactory.getSnapPhotoFromFile(File(it))
} catch (e: SnapMediaSizeException) {
Log.e(getName(), e.toString())
null
}
SnapPhotoContent(photoFile!!)
}.first()
snapCreativeKitApi.sendWithCompletionHandler(
content,
object : SnapCreativeKitCompletionCallback {
override fun onSendSuccess() {
publishSubject.onNext(Any())
}
override fun onSendFailed(p0: SnapCreativeKitSendError?) {
publishSubject.onError(Exception("Snapchat error"))
}
})
}
override fun getPosts(context: Context): Single<List<Post>> {
return Single.just(emptyList())
}
override fun getLogo(): Int = R.drawable.ic_icon_snapchat
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
}
override fun handleButtonView(context: Context): (SocialWithButtonRecycler.ViewHolder) -> Unit =
{
it.image.setImageResource(getLogo())
it.textView.text = getName()
}
}

View File

@ -13,7 +13,10 @@ interface SocialPlatform {
fun login(context: Context) fun login(context: Context)
fun logout(context: Context) fun logout(context: Context)
fun isLoggedIn(context: Context): Boolean fun isLoggedIn(context: Context): Boolean
fun addPost(context: Context, text: String, images: List<Bitmap>): PublishSubject<Any> fun addPost(publishSubject: PublishSubject<Any>,
context: Context, text: String, images: List<Bitmap>,
imagePaths: List<String>)
fun getPosts(context: Context): Single<List<Post>> fun getPosts(context: Context): Single<List<Post>>
fun getLogo(): Int fun getLogo(): Int
fun handleButtonView(context: Context): (SocialWithButtonRecycler.ViewHolder) -> Unit = {} fun handleButtonView(context: Context): (SocialWithButtonRecycler.ViewHolder) -> Unit = {}

View File

@ -2,13 +2,14 @@ package pl.edu.amu.wmi.socialaggregator.utils
import android.content.Context import android.content.Context
import pl.edu.amu.wmi.socialaggregator.socialplatforms.Facebook import pl.edu.amu.wmi.socialaggregator.socialplatforms.Facebook
import pl.edu.amu.wmi.socialaggregator.socialplatforms.FacebookMock import pl.edu.amu.wmi.socialaggregator.socialplatforms.Snapchat
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
object SocialPlatformsManager { object SocialPlatformsManager {
private val IMPLEMENTED_PLATFORMS = listOf<SocialPlatform>( private val IMPLEMENTED_PLATFORMS = listOf(
// FacebookMock() // FacebookMock()
Facebook() Facebook(),
Snapchat()
) )
fun getAll() = IMPLEMENTED_PLATFORMS fun getAll() = IMPLEMENTED_PLATFORMS

View File

@ -1,5 +1,6 @@
package pl.edu.amu.wmi.socialaggregator.viewholders package pl.edu.amu.wmi.socialaggregator.viewholders
import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -11,8 +12,11 @@ import androidx.recyclerview.widget.RecyclerView
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import io.reactivex.Observable import io.reactivex.Observable
import pl.edu.amu.wmi.socialaggregator.R import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.socialplatforms.NotApplicableException
import pl.edu.amu.wmi.socialaggregator.socialplatforms.Post import pl.edu.amu.wmi.socialaggregator.socialplatforms.Post
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
@SuppressLint("CheckResult")
class PostDetailsRecycler( class PostDetailsRecycler(
postsObservable: Observable<List<Post>> postsObservable: Observable<List<Post>>
) : RecyclerView.Adapter<PostDetailsRecycler.ViewHolder>() { ) : RecyclerView.Adapter<PostDetailsRecycler.ViewHolder>() {
@ -20,10 +24,11 @@ class PostDetailsRecycler(
val posts = emptyList<Post>().toMutableList() val posts = emptyList<Post>().toMutableList()
init { init {
postsObservable.subscribe { postsObservable
posts.addAll(it) .subscribe {
notifyDataSetChanged() posts.addAll(it)
} notifyDataSetChanged()
}
} }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {

View File

@ -1,5 +1,6 @@
package pl.edu.amu.wmi.socialaggregator.viewholders package pl.edu.amu.wmi.socialaggregator.viewholders
import android.annotation.SuppressLint
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
@ -7,22 +8,27 @@ import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observable import io.reactivex.Observable
import io.reactivex.Single
import pl.edu.amu.wmi.socialaggregator.R import pl.edu.amu.wmi.socialaggregator.R
import pl.edu.amu.wmi.socialaggregator.socialplatforms.NotApplicableException
import pl.edu.amu.wmi.socialaggregator.socialplatforms.Post import pl.edu.amu.wmi.socialaggregator.socialplatforms.Post
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
@SuppressLint("CheckResult")
class PostSummaryRecycler( class PostSummaryRecycler(
socialsObservable: Observable<Pair<SocialPlatform, List<Post>>> socialsObservable: Observable<Pair<SocialPlatform, List<Post>?>>
) : RecyclerView.Adapter<PostSummaryRecycler.ViewHolder>() { ) : RecyclerView.Adapter<PostSummaryRecycler.ViewHolder>() {
init { private val socials = mutableListOf<Pair<SocialPlatform, List<Post>?>>()
socialsObservable.subscribe {
socials.add(it)
notifyDataSetChanged()
}
}
val socials = emptyList<Pair<SocialPlatform, List<Post>>>().toMutableList() init {
socialsObservable
.doOnNext {
socials.add(it)
notifyDataSetChanged()
}
.subscribe()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layout = LayoutInflater.from(parent.context) val layout = LayoutInflater.from(parent.context)
@ -41,9 +47,11 @@ class PostSummaryRecycler(
override fun onBindViewHolder(holder: ViewHolder, position: Int) { override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val (social, posts) = socials[position] val (social, posts) = socials[position]
val count = posts.size val count = posts?.size
holder.socialName.text = social.getName() holder.socialName.text = social.getName()
holder.postCount.text = count.toString() + if (count > 1) " posts" else " post" holder.postCount.text = count?.let {
count.toString() + if (count > 1) " posts" else " post"
} ?: "Not applicable"
holder.imageView.setImageResource(social.getLogo()) holder.imageView.setImageResource(social.getLogo())
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -6,4 +6,10 @@
<string name="facebook_app_id">2437098899888167</string> <string name="facebook_app_id">2437098899888167</string>
<string name="fb_login_protocol_scheme">fb2437098899888167</string> <string name="fb_login_protocol_scheme">fb2437098899888167</string>
<!-- <key>SCSDKScopes</key>-->
<!-- <array name="snap_connect_scopes">-->
<!-- <string>https://auth.snapchat.com/oauth2/api/user.bitmoji.avatar</string>-->
<!-- &lt;!&ndash; other scopes you might have... &ndash;&gt;-->
<!-- </array>-->
</resources> </resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<paths>
<root-path name="root" path="." />
<external-cache-path name="external_files" path="."/>
<external-path name="external_files" path="."/>
</paths>

View File

@ -19,7 +19,10 @@ allprojects {
repositories { repositories {
google() google()
jcenter() jcenter()
maven {
url "https://storage.googleapis.com/snap-kit-build/maven"
}
} }
} }