Compare commits
No commits in common. "master" and "feature/SA-28-facebook-api-poc-impl" have entirely different histories.
master
...
feature/SA
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -25,16 +25,6 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
testOptions {
|
||||
unitTests {
|
||||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -49,36 +39,9 @@ dependencies {
|
||||
implementation "io.reactivex.rxjava2:rxandroid:2.1.0"
|
||||
implementation 'com.jakewharton.rxbinding2:rxbinding:2.2.0'
|
||||
implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.2.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
|
||||
androidTestImplementation 'androidx.test:core-ktx:1.2.0'
|
||||
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
androidTestImplementation 'androidx.test:runner:' + rootProject.runnerVersion
|
||||
androidTestImplementation 'androidx.test:rules:' + rootProject.rulesVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-intents:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion
|
||||
androidTestImplementation 'androidx.test.ext:truth:' + rootProject.extTruthVersion
|
||||
androidTestImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
androidTestImplementation 'org.robolectric:annotations:' + rootProject.robolectricVersion
|
||||
|
||||
testImplementation 'androidx.test:core:' + rootProject.coreVersion
|
||||
testImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-intents:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion
|
||||
testImplementation 'androidx.test.ext:truth:' + rootProject.extTruthVersion
|
||||
testImplementation 'androidx.test.ext:junit:' + rootProject.extJUnitVersion
|
||||
testImplementation 'org.robolectric:robolectric:' + rootProject.robolectricVersion
|
||||
|
||||
implementation 'com.facebook.android:facebook-login:[5,6)'
|
||||
implementation 'com.facebook.android:facebook-share:[5,6)'
|
||||
|
||||
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'
|
||||
])
|
||||
}
|
||||
|
@ -1,82 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.core.app.launchActivity
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import junit.framework.Assert.assertEquals
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.actionOnChild
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.cleanLocalStorage
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.AddSocialActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AddSocialActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(AddSocialActivity::class.java)
|
||||
|
||||
|
||||
@Test
|
||||
fun initialState_noAddedSocials_oneAvailableSocial() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
val newActivity = launchActivity<AddSocialActivity>()
|
||||
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickingSocials_movesThemFormAvailableToAdded_etViceVersa() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
onView(withId(R.id.addSocialRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
|
||||
onView(withId(R.id.availableSocialsRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
0, activity.activity.findViewById<RecyclerView>(R.id.availableSocialsRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
assertEquals(
|
||||
1, activity.activity.findViewById<RecyclerView>(R.id.addSocialRecyclerView)
|
||||
.adapter?.itemCount
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -15,12 +15,10 @@ import org.junit.Assert.*
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
appContext.filesDir.delete()
|
||||
assertEquals("pl.edu.amu.wmi.socialaggregator", appContext.packageName)
|
||||
}
|
||||
}
|
||||
|
@ -1,38 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.test.espresso.Espresso.onView
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.intent.Intents.intended
|
||||
import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.withId
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.AddSocialActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.MainActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.NewPostActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class MainActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun clickAddNewSocial_shouldOpenAddNewSocialActivity() {
|
||||
onView(withId(R.id.connectedSocialsButton)).perform(click())
|
||||
|
||||
intended(hasComponent(AddSocialActivity::class.java.name))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickCreatePost_shouldOpenAddNewNewPostActivity() {
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
intended(hasComponent(NewPostActivity::class.java.name))
|
||||
}
|
||||
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.Espresso.*
|
||||
import androidx.test.espresso.action.ViewActions.click
|
||||
import androidx.test.espresso.assertion.ViewAssertions.matches
|
||||
import androidx.test.espresso.contrib.RecyclerViewActions
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.ViewMatchers.*
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.atPosition
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.cleanLocalStorage
|
||||
import pl.edu.amu.wmi.socialaggregator.TestUtils.getCurrentActivity
|
||||
import pl.edu.amu.wmi.socialaggregator.activity.MainActivity
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class NewPostActivityTest {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val activity = IntentsTestRule(MainActivity::class.java)
|
||||
|
||||
@Test
|
||||
fun clickPublishPost_shouldEndActivity() {
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
closeSoftKeyboard()
|
||||
|
||||
onView(withId(R.id.publishPost)).perform(click())
|
||||
|
||||
assertTrue(getCurrentActivity()!!::class.java.simpleName == "MainActivity")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun clickPublishPost_shouldIncreasePostCount() {
|
||||
cleanLocalStorage(activity)
|
||||
|
||||
onView(withId(R.id.connectedSocialsButton)).perform(click())
|
||||
|
||||
onView(withId(R.id.addSocialRecyclerView))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
TestUtils.actionOnChild(click(), R.id.socialPlatformImage)
|
||||
)
|
||||
)
|
||||
|
||||
pressBack()
|
||||
|
||||
onView(withId(R.id.createPostButton)).perform(click())
|
||||
|
||||
closeSoftKeyboard()
|
||||
|
||||
onView(withId(R.id.availableSocials))
|
||||
.perform(
|
||||
RecyclerViewActions.actionOnItemAtPosition<RecyclerView.ViewHolder>(
|
||||
0,
|
||||
TestUtils.actionOnChild(click(), R.id.chip)
|
||||
)
|
||||
)
|
||||
|
||||
onView(withId(R.id.publishPost)).perform(click())
|
||||
|
||||
onView(withId(R.id.previousPostsRecyclerView)).check(
|
||||
matches(atPosition(0, hasDescendant(withText("Facebook"))))
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.test.espresso.NoMatchingViewException
|
||||
import androidx.test.espresso.UiController
|
||||
import androidx.test.espresso.ViewAction
|
||||
import androidx.test.espresso.ViewAssertion
|
||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||
import androidx.test.espresso.matcher.BoundedMatcher
|
||||
import androidx.test.espresso.matcher.ViewMatchers
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry
|
||||
import androidx.test.runner.lifecycle.Stage
|
||||
import org.hamcrest.CoreMatchers
|
||||
import org.hamcrest.Description
|
||||
import org.hamcrest.Matcher
|
||||
import org.hamcrest.core.AllOf
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.File
|
||||
|
||||
object TestUtils {
|
||||
|
||||
fun cleanLocalStorage(activity: IntentsTestRule<out Activity>) {
|
||||
deleteRecursive(activity.activity.filesDir)
|
||||
}
|
||||
|
||||
private fun deleteRecursive(fileOrDirectory: File) {
|
||||
if (fileOrDirectory.isDirectory())
|
||||
for (child in fileOrDirectory.listFiles())
|
||||
deleteRecursive(child)
|
||||
|
||||
fileOrDirectory.delete()
|
||||
}
|
||||
|
||||
fun actionOnChild(action: ViewAction, childId: Int): ViewAction? {
|
||||
return object : ViewAction {
|
||||
override fun getDescription(): String {
|
||||
return "Action on child"
|
||||
}
|
||||
|
||||
override fun getConstraints(): Matcher<View> {
|
||||
return AllOf.allOf(
|
||||
ViewMatchers.isDisplayed(),
|
||||
ViewMatchers.isAssignableFrom(View::class.java)
|
||||
)
|
||||
}
|
||||
|
||||
override fun perform(uiController: UiController?, view: View?) {
|
||||
view?.let {
|
||||
val child = it.findViewById<View>(childId)
|
||||
action.perform(uiController, child)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fun atPosition(position: Int, itemMatcher: Matcher<View>): Matcher<View> {
|
||||
checkNotNull(itemMatcher)
|
||||
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("has item at position $position: ")
|
||||
itemMatcher.describeTo(description)
|
||||
}
|
||||
|
||||
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||
val viewHolder = view.findViewHolderForAdapterPosition(position)
|
||||
?: // has no item on such position
|
||||
return false
|
||||
return itemMatcher.matches(viewHolder.itemView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun atPosition(position: Int, id: Int, itemMatcher: Matcher<View>): Matcher<View> {
|
||||
checkNotNull(itemMatcher)
|
||||
return object : BoundedMatcher<View, RecyclerView>(RecyclerView::class.java) {
|
||||
override fun describeTo(description: Description) {
|
||||
description.appendText("has item at position $position: ")
|
||||
itemMatcher.describeTo(description)
|
||||
}
|
||||
|
||||
override fun matchesSafely(view: RecyclerView): Boolean {
|
||||
val viewHolder = view.findViewHolderForAdapterPosition(position)
|
||||
?: // has no item on such position
|
||||
return false
|
||||
val view = viewHolder.itemView.findViewById<View>(id)
|
||||
return itemMatcher.matches(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentActivity(): Activity? {
|
||||
var currentActivity: Activity? = null
|
||||
getInstrumentation().runOnMainSync {
|
||||
run {
|
||||
currentActivity =
|
||||
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(
|
||||
Stage.RESUMED
|
||||
).elementAtOrNull(0)
|
||||
}
|
||||
}
|
||||
return currentActivity
|
||||
}
|
||||
|
||||
}
|
@ -2,25 +2,13 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="pl.edu.amu.wmi.socialaggregator">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
<activity
|
||||
android:name=".activity.PostHistoryActivity"
|
||||
android:label="@string/title_activity_post_history"
|
||||
android:parentActivityName=".activity.MainActivity"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="pl.edu.amu.wmi.socialaggregator.activity.MainActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.AddSocialActivity"
|
||||
android:label="@string/title_activity_add_social"
|
||||
@ -46,50 +34,6 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<meta-data android:name="com.facebook.sdk.ApplicationId"
|
||||
android:value="@string/facebook_app_id"/>
|
||||
|
||||
<activity android:name="com.facebook.FacebookActivity"
|
||||
android:configChanges=
|
||||
"keyboard|keyboardHidden|screenLayout|screenSize|orientation"
|
||||
android:label="@string/app_name" />
|
||||
<activity
|
||||
android:name="com.facebook.CustomTabActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="@string/fb_login_protocol_scheme" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<provider android:authorities="com.facebook.app.FacebookContentProvider2437098899888167"
|
||||
android:name="com.facebook.FacebookContentProvider"
|
||||
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 app’s 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"
|
||||
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>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
|
||||
</manifest>
|
@ -8,7 +8,7 @@ import kotlinx.android.synthetic.main.activity_add_social.*
|
||||
import kotlinx.android.synthetic.main.content_add_social.*
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithImageRecycler
|
||||
|
||||
class AddSocialActivity : AppCompatActivity() {
|
||||
|
||||
@ -23,33 +23,33 @@ class AddSocialActivity : AppCompatActivity() {
|
||||
val loggedInSocials = SocialPlatformsManager.getLoggedIn(this)
|
||||
val recyclers = mutableListOf(availableSocialsRecyclerView, addSocialRecyclerView)
|
||||
|
||||
// availableSocialsRecyclerView.apply {
|
||||
// layoutManager = LinearLayoutManager(this@AddSocialActivity)
|
||||
// adapter = SocialWithButtonRecycler(
|
||||
// loggedInSocials,
|
||||
// R.mipmap.ic_opaque_remove
|
||||
// ) {
|
||||
// it.logout(context)
|
||||
// loggedInSocials.remove(it)
|
||||
// notLoggedInSocials.add(it)
|
||||
// recyclers.forEach { it.adapter?.notifyDataSetChanged() }
|
||||
// Toast.makeText(context, "Logged out from ${it.getName()}!", Toast.LENGTH_SHORT).show()
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// addSocialRecyclerView.apply {
|
||||
// layoutManager = LinearLayoutManager(this@AddSocialActivity)
|
||||
// adapter = SocialWithButtonRecycler(
|
||||
// notLoggedInSocials,
|
||||
// R.mipmap.ic_opaque_add
|
||||
// ) {
|
||||
// it.login(context)
|
||||
// notLoggedInSocials.remove(it)
|
||||
// loggedInSocials.add(it)
|
||||
// recyclers.forEach { it.adapter?.notifyDataSetChanged() }
|
||||
// Toast.makeText(context, "Logged in to ${it.getName()}!", Toast.LENGTH_SHORT).show()
|
||||
// }
|
||||
// }
|
||||
availableSocialsRecyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@AddSocialActivity)
|
||||
adapter = SocialWithImageRecycler(
|
||||
loggedInSocials,
|
||||
R.drawable.ic_remove_circle
|
||||
) {
|
||||
it.logout(context)
|
||||
loggedInSocials.remove(it)
|
||||
notLoggedInSocials.add(it)
|
||||
recyclers.forEach { it.adapter?.notifyDataSetChanged() }
|
||||
Toast.makeText(context, "Logged out from ${it.getName()}!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
addSocialRecyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@AddSocialActivity)
|
||||
adapter = SocialWithImageRecycler(
|
||||
notLoggedInSocials,
|
||||
R.drawable.ic_add_circle
|
||||
) {
|
||||
it.login(context)
|
||||
notLoggedInSocials.remove(it)
|
||||
loggedInSocials.add(it)
|
||||
recyclers.forEach { it.adapter?.notifyDataSetChanged() }
|
||||
Toast.makeText(context, "Logged in to ${it.getName()}!", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,21 +5,17 @@ import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.jakewharton.rxbinding2.view.RxView
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.PostSummaryRecycler
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
|
||||
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.PostTextRecycler
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithImageRecycler
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val subs = CompositeDisposable()
|
||||
|
||||
private val TAG = MainActivity::class.java.simpleName
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
@ -30,18 +26,13 @@ class MainActivity : AppCompatActivity() {
|
||||
val intent = Intent(this, NewPostActivity::class.java)
|
||||
startActivity(intent)
|
||||
},
|
||||
RxView.clicks(previousPostsButton)
|
||||
RxView.clicks(connectedSocialsButton)
|
||||
.subscribe {
|
||||
val intent = Intent(this, PostHistoryActivity::class.java)
|
||||
val intent = Intent(this, AddSocialActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
SocialPlatformsManager.getAll()
|
||||
.forEach { it.onActivityResult(requestCode, resultCode, data) }
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
@ -49,20 +40,14 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
connectedSocialsRecyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@MainActivity)
|
||||
adapter =
|
||||
SocialWithButtonRecycler(SocialPlatformsManager.getAll(), this@MainActivity)
|
||||
adapter = SocialWithImageRecycler(SocialPlatformsManager.getLoggedIn(this@MainActivity),
|
||||
R.drawable.ic_launcher_background) {}
|
||||
}
|
||||
|
||||
previousPostsRecyclerView.apply {
|
||||
layoutManager = LinearLayoutManager(this@MainActivity)
|
||||
adapter = PostSummaryRecycler(
|
||||
Observable.merge(SocialPlatformsManager.getLoggedIn(this@MainActivity)
|
||||
.map { social ->
|
||||
social.getPosts(this@MainActivity)
|
||||
.map { social to it }
|
||||
.toObservable()
|
||||
})
|
||||
)
|
||||
adapter = PostTextRecycler(SocialPlatformsManager.getLoggedIn(this@MainActivity)
|
||||
.map { it to it.getPosts(this@MainActivity).size })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,41 +1,20 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.activity
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.provider.MediaStore
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.jakewharton.rxbinding2.view.RxView
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
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.content_new_post.*
|
||||
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.viewholders.SocialWithToggleRecycler
|
||||
|
||||
|
||||
class NewPostActivity : AppCompatActivity() {
|
||||
|
||||
var file: String? = null
|
||||
|
||||
val postedSubject = PublishSubject.create<Any>()
|
||||
|
||||
val resumedSubject = PublishSubject.create<Any>()
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -57,115 +36,16 @@ class NewPostActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
RxView.clicks(publishPost)
|
||||
.filter { file != null }
|
||||
.doOnNext {
|
||||
val sdk = android.os.Build.VERSION.SDK_INT
|
||||
if (sdk < android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
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
|
||||
.subscribe {
|
||||
availablesRecycler.chips.entries.forEach { (social, chip) ->
|
||||
if (chip.isChecked) {
|
||||
social.addPost(this, postText.text?.toString() ?: "test", emptyList())
|
||||
Toast.makeText(this, "Posted to ${social.getName()}!", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
.observeOn(Schedulers.io())
|
||||
.doOnNext {
|
||||
resumedSubject
|
||||
.zipWith(
|
||||
Observable.fromIterable(availablesRecycler.chips.entries
|
||||
.filter { (_, chip) -> chip.isChecked }
|
||||
.map { it.key }),
|
||||
BiFunction<Any, SocialPlatform, SocialPlatform> { _, t2 -> t2 }
|
||||
)
|
||||
.observeOn(Schedulers.io())
|
||||
.doOnNext {
|
||||
val bitmap = BitmapFactory.decodeFile(file!!)
|
||||
it.addPost(
|
||||
postedSubject, this,
|
||||
postText.text?.toString() ?: "",
|
||||
listOf(bitmap),
|
||||
listOf(file!!)
|
||||
)
|
||||
}
|
||||
.take(availablesRecycler.chips.count { it.value.isChecked }.toLong() + 1)
|
||||
.toList()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe { _ ->
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
.subscribe {
|
||||
resumedSubject.onNext(Any())
|
||||
}
|
||||
|
||||
RxView.clicks(imageView2)
|
||||
.subscribe {
|
||||
val getIntent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
getIntent.type = "image/*"
|
||||
|
||||
val pickIntent = Intent(
|
||||
Intent.ACTION_PICK,
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
)
|
||||
pickIntent.type = "image/*"
|
||||
|
||||
val chooserIntent = Intent.createChooser(getIntent, "Select Image")
|
||||
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(pickIntent))
|
||||
|
||||
startActivityForResult(chooserIntent, PICK_IMAGE_REQUEST_CODE)
|
||||
}
|
||||
|
||||
|
||||
if (canAccessGallery()) {
|
||||
ActivityCompat.requestPermissions(
|
||||
this,
|
||||
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
SocialPlatformsManager.getAll()
|
||||
.forEach { it.onActivityResult(requestCode, resultCode, data) }
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
|
||||
if (requestCode == PICK_IMAGE_REQUEST_CODE) {
|
||||
data?.data?.let { uri ->
|
||||
file = getPath(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() =
|
||||
(ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED)
|
||||
|
||||
companion object {
|
||||
const val PICK_IMAGE_REQUEST_CODE = 69
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,41 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import io.reactivex.Observable
|
||||
import kotlinx.android.synthetic.main.activity_post_history.*
|
||||
import kotlinx.android.synthetic.main.content_post_history.*
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.utils.SocialPlatformsManager
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.PostDetailsRecycler
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
|
||||
|
||||
|
||||
class PostHistoryActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_post_history)
|
||||
setSupportActionBar(toolbar)
|
||||
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
|
||||
postHistoryRecycler.apply {
|
||||
layoutManager = LinearLayoutManager(this@PostHistoryActivity)
|
||||
adapter = PostDetailsRecycler(
|
||||
Observable.fromIterable(SocialPlatformsManager.getLoggedIn(this@PostHistoryActivity))
|
||||
.flatMap {
|
||||
it.getPosts(this@PostHistoryActivity)
|
||||
.toObservable()
|
||||
})
|
||||
addItemDecoration(
|
||||
DividerItemDecoration(
|
||||
context,
|
||||
(layoutManager as LinearLayoutManager).orientation
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.socialplatforms
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import com.facebook.*
|
||||
import com.facebook.login.LoginManager
|
||||
import com.facebook.login.LoginResult
|
||||
import com.facebook.login.widget.LoginButton
|
||||
import com.facebook.share.Sharer
|
||||
import com.facebook.share.model.ShareMediaContent
|
||||
import com.facebook.share.model.SharePhoto
|
||||
import com.facebook.share.widget.ShareDialog
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.utils.Utils
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
|
||||
|
||||
|
||||
class Facebook : SocialPlatform {
|
||||
|
||||
private var callbackManager: CallbackManager = CallbackManager.Factory.create()
|
||||
|
||||
override fun getName(): String = "Facebook"
|
||||
|
||||
override fun getLogo(): Int = R.mipmap.ic_logo_facebook
|
||||
|
||||
override fun login(context: Context) {
|
||||
|
||||
}
|
||||
|
||||
override fun logout(context: Context) {
|
||||
|
||||
}
|
||||
|
||||
override fun isLoggedIn(context: Context): Boolean {
|
||||
val accessToken = AccessToken.getCurrentAccessToken()
|
||||
return accessToken != null && !accessToken.isExpired
|
||||
}
|
||||
|
||||
override fun addPost(
|
||||
publishSubject: PublishSubject<Any>,
|
||||
context: Context,
|
||||
text: String,
|
||||
images: List<Bitmap>,
|
||||
imagePaths: List<String>
|
||||
) {
|
||||
val content = ShareMediaContent.Builder().apply {
|
||||
images.forEach {
|
||||
addMedium(
|
||||
SharePhoto.Builder().setBitmap(it).build()
|
||||
)
|
||||
}
|
||||
}.build()
|
||||
|
||||
val shareDialog = ShareDialog(context as Activity)
|
||||
shareDialog.registerCallback(callbackManager, object : FacebookCallback<Sharer.Result?> {
|
||||
override fun onSuccess(result: Sharer.Result?) {
|
||||
publishSubject.onNext(Any())
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
publishSubject.onNext(Any())
|
||||
}
|
||||
|
||||
override fun onError(error: FacebookException?) {
|
||||
publishSubject.onError(Exception(error?.localizedMessage))
|
||||
}
|
||||
})
|
||||
shareDialog.show(content, ShareDialog.Mode.AUTOMATIC)
|
||||
}
|
||||
|
||||
override fun getPosts(context: Context): Single<List<Post>> {
|
||||
return Single.just(AccessToken.getCurrentAccessToken())
|
||||
.observeOn(Schedulers.io())
|
||||
.map { token ->
|
||||
if (token.isExpired) {
|
||||
return@map emptyList<Post>()
|
||||
} else {
|
||||
val request = GraphRequest.newGraphPathRequest(
|
||||
AccessToken.getCurrentAccessToken(),
|
||||
"/me/posts"
|
||||
) {
|
||||
Log.i(getName(), it.toString())
|
||||
}
|
||||
val parameters = Bundle()
|
||||
parameters.putString(
|
||||
"fields",
|
||||
"likes.summary(true),created_time,message,attachments{url,unshimmed_url,media,subattachments}"
|
||||
)
|
||||
request.parameters = parameters
|
||||
val res = request.executeAndWait()
|
||||
|
||||
val data = res.jsonObject["data"] as JSONArray
|
||||
val size = data.length()
|
||||
return@map (0 until size).map {
|
||||
val obj = data[it] as JSONObject
|
||||
val msg = if (obj.has("message")) obj.getString("message") else ""
|
||||
val date =
|
||||
if (obj.has("created_time")) obj.getString("created_time") else ""
|
||||
// SimpleDateFormat("YYYY-MM-DD\'T\'hh:mm:ssZ").parse(date)
|
||||
Post(this, msg, date, getImages(obj))
|
||||
}
|
||||
}
|
||||
}
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
|
||||
}
|
||||
|
||||
private fun getImages(obj: JSONObject): List<String> {
|
||||
val list = emptyList<String>().toMutableList()
|
||||
if (obj.has("attachments")) {
|
||||
val attachments = obj.getJSONObject("attachments").getJSONArray("data")
|
||||
try {
|
||||
list.addAll((0 until attachments.length())
|
||||
.map { attachments[it] as JSONObject }
|
||||
.flatMap {
|
||||
val urls = mutableListOf<String>()
|
||||
if (it.has("media")) {
|
||||
urls.add(
|
||||
it.getJSONObject("media")
|
||||
.getJSONObject("image")
|
||||
.getString("src")
|
||||
)
|
||||
}
|
||||
if (it.has("subattachments")) {
|
||||
val subattachments =
|
||||
it.getJSONObject("subattachments").getJSONArray("data")
|
||||
urls.addAll((0 until subattachments.length())
|
||||
.map { subattachments[it] as JSONObject }
|
||||
.map {
|
||||
it.getJSONObject("media")
|
||||
.getJSONObject("image")
|
||||
.getString("src")
|
||||
})
|
||||
}
|
||||
return@flatMap urls
|
||||
})
|
||||
} catch (e: Exception) {
|
||||
Log.e(getName(), e.toString())
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
override fun handleButtonView(context: Context): (SocialWithButtonRecycler.ViewHolder) -> Unit =
|
||||
{ viewHolder ->
|
||||
viewHolder.textView.text = this.getName()
|
||||
|
||||
val constraintSet = ConstraintSet()
|
||||
val button = LoginButton(context)
|
||||
button.id = View.generateViewId()
|
||||
|
||||
val parent = viewHolder.image.parent as ViewGroup
|
||||
parent.removeView(viewHolder.image)
|
||||
parent.addView(button)
|
||||
|
||||
constraintSet.clone(parent as ConstraintLayout)
|
||||
constraintSet.connect(
|
||||
button.id, ConstraintSet.TOP,
|
||||
parent.id, ConstraintSet.TOP, 8.toPx(context)
|
||||
)
|
||||
constraintSet.connect(
|
||||
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,
|
||||
button.id, ConstraintSet.BOTTOM
|
||||
)
|
||||
constraintSet.connect(
|
||||
viewHolder.textView.id, ConstraintSet.END,
|
||||
button.id, ConstraintSet.START, 8.toPx(context)
|
||||
)
|
||||
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.applyTo(parent)
|
||||
|
||||
button.setPermissions(listOf("email"))
|
||||
val callback = object : FacebookCallback<LoginResult> {
|
||||
override fun onSuccess(result: LoginResult?) {
|
||||
Log.i(getName(), "SUCCESS!")
|
||||
LoginManager.getInstance().logInWithReadPermissions(
|
||||
context as Activity,
|
||||
listOf("email")
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
Log.i(getName(), "CANCEL!")
|
||||
}
|
||||
|
||||
override fun onError(error: FacebookException?) {
|
||||
Log.i(getName(), "FAIL!")
|
||||
}
|
||||
|
||||
}
|
||||
button.registerCallback(callbackManager, callback)
|
||||
LoginManager.getInstance().registerCallback(callbackManager, callback)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
callbackManager.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
|
||||
private fun Int.toPx(context: Context): Int {
|
||||
return Utils.convertDpToPixel(this.toFloat(), context).toInt()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,65 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.socialplatforms
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.util.Log
|
||||
import pl.edu.amu.wmi.socialaggregator.utils.InternalStorage
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
|
||||
class FacebookMock : SocialPlatform {
|
||||
|
||||
companion object {
|
||||
val TAG = FacebookMock::class.java.canonicalName
|
||||
}
|
||||
|
||||
override fun getName(): String = "Facebook"
|
||||
|
||||
override fun login(context: Context) {
|
||||
val loginsDir = InternalStorage.getFileOrDir(context, "logins")
|
||||
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>) {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getPosts(context: Context): List<String> {
|
||||
val postsDir = InternalStorage.getFileOrDir(context, "posts/facebook")
|
||||
return postsDir?.listFiles()?.map { it.name }?.toList() ?: emptyList()
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.socialplatforms
|
||||
|
||||
import java.lang.Exception
|
||||
|
||||
class NotApplicableException(val socialPlatform: SocialPlatform) : Exception()
|
@ -1,8 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.socialplatforms
|
||||
|
||||
data class Post(
|
||||
val social: SocialPlatform,
|
||||
val content: String,
|
||||
val dateTime: String,
|
||||
val images: List<String>
|
||||
)
|
@ -1,83 +0,0 @@
|
||||
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()
|
||||
|
||||
if (text.isNotBlank()) {
|
||||
content.captionText = text
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
@ -1,11 +1,7 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.socialplatforms
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import io.reactivex.Single
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import pl.edu.amu.wmi.socialaggregator.viewholders.SocialWithButtonRecycler
|
||||
|
||||
interface SocialPlatform {
|
||||
|
||||
@ -13,12 +9,6 @@ interface SocialPlatform {
|
||||
fun login(context: Context)
|
||||
fun logout(context: Context)
|
||||
fun isLoggedIn(context: Context): Boolean
|
||||
fun addPost(publishSubject: PublishSubject<Any>,
|
||||
context: Context, text: String, images: List<Bitmap>,
|
||||
imagePaths: List<String>)
|
||||
|
||||
fun getPosts(context: Context): Single<List<Post>>
|
||||
fun getLogo(): Int
|
||||
fun handleButtonView(context: Context): (SocialWithButtonRecycler.ViewHolder) -> Unit = {}
|
||||
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {}
|
||||
fun addPost(context: Context, text: String, images: List<Bitmap>)
|
||||
fun getPosts(context: Context): List<String>
|
||||
}
|
@ -1,19 +1,14 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.utils
|
||||
|
||||
import android.content.Context
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.Facebook
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.Snapchat
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.FacebookMock
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
|
||||
|
||||
object SocialPlatformsManager {
|
||||
private val IMPLEMENTED_PLATFORMS = listOf(
|
||||
// FacebookMock()
|
||||
Facebook(),
|
||||
Snapchat()
|
||||
private val IMPLEMENTED_PLATFORMS = listOf<SocialPlatform>(
|
||||
FacebookMock()
|
||||
)
|
||||
|
||||
fun getAll() = IMPLEMENTED_PLATFORMS
|
||||
|
||||
fun getLoggedIn(context: Context) =
|
||||
IMPLEMENTED_PLATFORMS.filter { it.isLoggedIn(context) }.toMutableList()
|
||||
|
||||
|
@ -1,12 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.util.DisplayMetrics
|
||||
|
||||
|
||||
object Utils {
|
||||
|
||||
fun convertDpToPixel(dp: Float, context: Context): Float {
|
||||
return dp * (context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.viewholders
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.squareup.picasso.Picasso
|
||||
import io.reactivex.Observable
|
||||
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.SocialPlatform
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
class PostDetailsRecycler(
|
||||
postsObservable: Observable<List<Post>>
|
||||
) : RecyclerView.Adapter<PostDetailsRecycler.ViewHolder>() {
|
||||
|
||||
val posts = emptyList<Post>().toMutableList()
|
||||
|
||||
init {
|
||||
postsObservable
|
||||
.subscribe {
|
||||
posts.addAll(it)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.item_post, parent, false) as ConstraintLayout
|
||||
|
||||
val dateTime = layout.findViewById<TextView>(R.id.postDateTimeTextView)
|
||||
val postContent = layout.findViewById<TextView>(R.id.postContentTextView)
|
||||
val imageView = layout.findViewById<ImageView>(R.id.postSocialImage)
|
||||
val imagesContainer = layout.findViewById<LinearLayout>(R.id.imagesContainer)
|
||||
|
||||
return ViewHolder(layout, dateTime, postContent, imageView, imagesContainer)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return posts.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val post = posts[position]
|
||||
holder.dateTime.text = formatDate(post.dateTime)
|
||||
holder.postContent.text = post.content
|
||||
holder.postContent.visibility = if (post.content.isBlank()) View.GONE else View.VISIBLE
|
||||
|
||||
holder.imageView.setImageResource(post.social.getLogo())
|
||||
|
||||
holder.imagesContainer.apply {
|
||||
removeAllViews()
|
||||
|
||||
|
||||
post {
|
||||
|
||||
val imgWidth = (parent as ConstraintLayout).width / post.images.size - 10
|
||||
post.images.forEach {
|
||||
val imageView = ImageView(context)
|
||||
addView(imageView)
|
||||
|
||||
imageView.apply {
|
||||
(layoutParams as ViewGroup.MarginLayoutParams)
|
||||
.apply {
|
||||
marginEnd = 10
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Picasso.with(context)
|
||||
.load(it)
|
||||
.placeholder(android.R.drawable.ic_menu_gallery)
|
||||
.resize(imgWidth, imgWidth)
|
||||
.centerCrop()
|
||||
.into(imageView)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatDate(str: String): String {
|
||||
val regex = """(\d+-\d+-\d+)T(\d+:\d+:\d+)""".toRegex()
|
||||
val matchResult = regex.find(str)
|
||||
val (date, time) = matchResult!!.destructured
|
||||
|
||||
return "$date $time"
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
root: ConstraintLayout,
|
||||
val dateTime: TextView,
|
||||
val postContent: TextView,
|
||||
val imageView: ImageView,
|
||||
val imagesContainer: LinearLayout
|
||||
|
||||
) : RecyclerView.ViewHolder(root)
|
||||
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.viewholders
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.Single
|
||||
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.SocialPlatform
|
||||
|
||||
@SuppressLint("CheckResult")
|
||||
class PostSummaryRecycler(
|
||||
socialsObservable: Observable<Pair<SocialPlatform, List<Post>?>>
|
||||
) : RecyclerView.Adapter<PostSummaryRecycler.ViewHolder>() {
|
||||
|
||||
private val socials = mutableListOf<Pair<SocialPlatform, List<Post>?>>()
|
||||
|
||||
init {
|
||||
socialsObservable
|
||||
.doOnNext {
|
||||
socials.add(it)
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.previous_posts, parent, false) as ConstraintLayout
|
||||
|
||||
val socialName = layout.findViewById<TextView>(R.id.socialTextView)
|
||||
val postCount = layout.findViewById<TextView>(R.id.post)
|
||||
val imageView = layout.findViewById<ImageView>(R.id.postSocialImage)
|
||||
|
||||
return ViewHolder(layout, socialName, postCount, imageView)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return socials.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val (social, posts) = socials[position]
|
||||
val count = posts?.size
|
||||
holder.socialName.text = social.getName()
|
||||
holder.postCount.text = count?.let {
|
||||
count.toString() + if (count > 1) " posts" else " post"
|
||||
} ?: "Not applicable"
|
||||
holder.imageView.setImageResource(social.getLogo())
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
root: ConstraintLayout,
|
||||
val socialName: TextView,
|
||||
val postCount: TextView,
|
||||
val imageView: ImageView
|
||||
) : RecyclerView.ViewHolder(root)
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.viewholders
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.jakewharton.rxbinding2.view.RxView
|
||||
import io.reactivex.disposables.Disposable
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
|
||||
|
||||
class PostTextRecycler(
|
||||
val socials: List<Pair<SocialPlatform, Int>>) : RecyclerView.Adapter<PostTextRecycler.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val layout = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.previous_posts, parent, false) as ConstraintLayout
|
||||
|
||||
val socialName = layout.findViewById<TextView>(R.id.socialTextView)
|
||||
val postCount = layout.findViewById<TextView>(R.id.postCountTextView)
|
||||
|
||||
return ViewHolder(layout, socialName, postCount)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return socials.size
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val pair = socials[position]
|
||||
holder.socialName.text = pair.first.getName()
|
||||
val count = pair.second
|
||||
holder.postCount.text = count.toString() + if (count > 1) " posts" else " post"
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
root: ConstraintLayout,
|
||||
val socialName: TextView,
|
||||
val postCount: TextView
|
||||
) : RecyclerView.ViewHolder(root)
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package pl.edu.amu.wmi.socialaggregator.viewholders
|
||||
|
||||
import android.content.Context
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
@ -12,10 +11,11 @@ import io.reactivex.disposables.Disposable
|
||||
import pl.edu.amu.wmi.socialaggregator.R
|
||||
import pl.edu.amu.wmi.socialaggregator.socialplatforms.SocialPlatform
|
||||
|
||||
class SocialWithButtonRecycler(
|
||||
class SocialWithImageRecycler(
|
||||
val availableSocials: List<SocialPlatform>,
|
||||
val context: Context
|
||||
) : RecyclerView.Adapter<SocialWithButtonRecycler.ViewHolder>() {
|
||||
private val imageResource: Int,
|
||||
private val action: (SocialPlatform) -> Unit
|
||||
) : RecyclerView.Adapter<SocialWithImageRecycler.ViewHolder>() {
|
||||
|
||||
private val disposables = HashMap<SocialPlatform, Disposable>()
|
||||
|
||||
@ -34,18 +34,18 @@ class SocialWithButtonRecycler(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
availableSocials[position].handleButtonView(context)(holder)
|
||||
// holder.textView.text = social.getName()
|
||||
// holder.image.setImageResource(imageResource ?: social.getLogo())
|
||||
//
|
||||
// disposables[social] = RxView.clicks(holder.image)
|
||||
// .map { social }
|
||||
// .subscribe(action)
|
||||
val social = availableSocials[position]
|
||||
holder.text.text = social.getName()
|
||||
holder.image.setImageResource(imageResource)
|
||||
|
||||
disposables[social] = RxView.clicks(holder.image)
|
||||
.map { social }
|
||||
.subscribe(action)
|
||||
}
|
||||
|
||||
class ViewHolder(
|
||||
root: ConstraintLayout,
|
||||
val textView: TextView,
|
||||
val text: TextView,
|
||||
val image: ImageView
|
||||
) : RecyclerView.ViewHolder(root)
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 725 B |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.6 KiB |
@ -14,7 +14,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/logo" />
|
||||
app:srcCompat="@mipmap/ic_launcher" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connectedSocialsTextView"
|
||||
@ -22,14 +22,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="Available Socials"
|
||||
android:text="Connected Socials"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/connectedSocialsRecyclerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="150dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
@ -41,6 +41,17 @@
|
||||
|
||||
</androidx.recyclerview.widget.RecyclerView>
|
||||
|
||||
<Button
|
||||
android:id="@+id/connectedSocialsButton"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="Connect new"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/connectedSocialsRecyclerView" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="0dp"
|
||||
@ -52,7 +63,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/connectedSocialsRecyclerView" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/connectedSocialsButton" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
@ -118,12 +129,11 @@
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:clickable="true"
|
||||
android:tint="@android:color/background_light"
|
||||
android:tint="#00FFFFFF"
|
||||
app:fabSize="auto"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/previousPostsButton"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
app:srcCompat="@mipmap/ic_opaque_add" />
|
||||
app:srcCompat="@android:drawable/ic_input_add" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.PostHistoryActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?attr/colorPrimary"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include layout="@layout/content_post_history" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -61,11 +61,10 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clickable="true"
|
||||
android:tint="@android:color/background_light"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/availableSocials"
|
||||
app:srcCompat="@mipmap/ic_opaque_send" />
|
||||
app:srcCompat="@drawable/ic_add_circle" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</ScrollView>
|
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:context=".activity.PostHistoryActivity"
|
||||
tools:showIn="@layout/activity_post_history">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/postHistoryRecycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1,58 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/linearLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/postContentTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="TextView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/postSocialImage"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/postDateTimeTextView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/postSocialImage"
|
||||
android:layout_width="@dimen/social_logo_size"
|
||||
android:layout_height="@dimen/social_logo_size"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintVertical_bias="0.0"
|
||||
app:srcCompat="@mipmap/ic_logo_facebook" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/postDateTimeTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="TextView"
|
||||
android:textSize="10sp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/postSocialImage"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/imagesContainer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal"
|
||||
android:layout_gravity="center"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/postContentTextView" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -13,32 +13,32 @@
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="Bla bla bla"
|
||||
android:textColor="@android:color/primary_text_light"
|
||||
app:layout_constraintBottom_toTopOf="@+id/post"
|
||||
app:layout_constraintEnd_toStartOf="@+id/postSocialImage"
|
||||
app:layout_constraintBottom_toTopOf="@+id/postCountTextView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/imageView3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/postSocialImage"
|
||||
app:layout_constraintTop_toTopOf="@+id/imageView3"
|
||||
app:layout_constraintVertical_chainStyle="packed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/post"
|
||||
android:id="@+id/postCountTextView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="Bla bla bla"
|
||||
android:textColor="@android:color/secondary_text_light"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/postSocialImage"
|
||||
app:layout_constraintEnd_toStartOf="@+id/imageView3"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/socialTextView" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/postSocialImage"
|
||||
android:layout_width="@dimen/social_logo_size"
|
||||
android:layout_height="@dimen/social_logo_size"
|
||||
android:id="@+id/imageView3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@mipmap/ic_logo_facebook" />
|
||||
app:srcCompat="@mipmap/ic_launcher_round" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -9,23 +9,23 @@
|
||||
android:id="@+id/socialPlatformName"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/socialPlatformImage"
|
||||
app:layout_constraintEnd_toStartOf="@+id/socialPlatformImage"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/socialPlatformImage"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Some Sample Text" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/socialPlatformImage"
|
||||
android:layout_width="@dimen/social_logo_size"
|
||||
android:layout_height="@dimen/social_logo_size"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:layout_marginBottom="-4dp"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/socialPlatformName"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:srcCompat="@mipmap/ic_logo_facebook" />
|
||||
app:layout_constraintTop_toTopOf="@+id/socialPlatformName"
|
||||
tools:srcCompat="@mipmap/ic_launcher_round" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
5
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 634 B |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.0 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 742 B |
Before Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 907 B |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 6.2 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 8.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 7.6 KiB |
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="colorPrimary">#512DA8</color>
|
||||
<color name="colorAccent">#5E35B1</color>
|
||||
<color name="colorPrimaryDark">#4A148C</color>
|
||||
<color name="colorPrimary">#4267b2</color>
|
||||
<color name="colorPrimaryDark">#4267b2</color>
|
||||
<color name="colorAccent">#4267b2</color>
|
||||
</resources>
|
||||
|
@ -1,4 +1,3 @@
|
||||
<resources>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="social_logo_size">32dp</dimen>
|
||||
</resources>
|
||||
|
@ -1,15 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">Social Aggregator</string>
|
||||
<string name="title_activity_new_post">Create new post!</string>
|
||||
<string name="title_activity_new_post">NewPostActivity</string>
|
||||
<string name="title_activity_add_social">AddSocialActivity</string>
|
||||
<string name="title_activity_post_history">Posts history</string>
|
||||
|
||||
<string name="facebook_app_id">2437098899888167</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>-->
|
||||
<!-- <!– other scopes you might have... –>-->
|
||||
<!-- </array>-->
|
||||
</resources>
|
||||
|
@ -1,7 +0,0 @@
|
||||
<?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>
|
20
build.gradle
@ -19,28 +19,10 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
maven {
|
||||
url "https://storage.googleapis.com/snap-kit-build/maven"
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
|
||||
|
||||
|
||||
ext {
|
||||
buildToolsVersion = "28.0.3"
|
||||
androidxLibVersion = "1.0.0"
|
||||
coreVersion = "1.3.0-alpha03"
|
||||
extJUnitVersion = "1.1.2-alpha03"
|
||||
runnerVersion = "1.3.0-alpha03"
|
||||
rulesVersion = "1.3.0-alpha03"
|
||||
espressoVersion = "3.3.0-alpha03"
|
||||
extJUnitVersion = "1.1.2-alpha03"
|
||||
extTruthVersion = "1.3.0-alpha03"
|
||||
robolectricVersion = "4.3.1"
|
||||
}
|
@ -19,4 +19,3 @@ android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
android.enableUnitTestBinaryResources=true
|
||||
|