diff options
author | Allan Wang <me@allanwang.ca> | 2018-12-31 18:57:28 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-31 18:57:28 -0500 |
commit | 149c6be1bfd4bd84381757940fece1be7b9801aa (patch) | |
tree | 85fe10e3ee3ea34ad717f0d61975ca0119dd36d5 /app/src/main/kotlin/com/pitchedapps/frost/activities | |
parent | 7661bbfc9b8f34bf9d92dc08a9fcd7cc6ec7cbb3 (diff) | |
download | frost-149c6be1bfd4bd84381757940fece1be7b9801aa.tar.gz frost-149c6be1bfd4bd84381757940fece1be7b9801aa.tar.bz2 frost-149c6be1bfd4bd84381757940fece1be7b9801aa.zip |
Enhancement/coroutines (#1273)
* Convert rest of fbcookie to suspended methods
* Replace active checks with yield
* Apply spotless
* Switch cookie domain to exact url
* Optimize imports and enable travis tests again
* Update proguard rules
* Remove unnecessary yield
* Remove unused flyweight
* Remove unused disposable and method
* Use contexthelper instead of dispatcher main
* Convert login activity to coroutines
* Use kau helper methods for coroutines
* Enhancement/offline site (#1288)
* Begin conversion of offline site logic
* Fix offline tests and add validation tests
* Ignore cookie in jsoup if it is blank
* Force load and zip to be in io
* Use different zip files to fix tests
* Log all test output
* Do not log stdout
* Allow test skip for fb offline
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/activities')
6 files changed, 130 insertions, 112 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt index 08b5ab0c..5965e5cf 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -22,8 +22,6 @@ import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.searchview.SearchViewHolder import com.pitchedapps.frost.contracts.VideoViewHolder import com.pitchedapps.frost.utils.setFrostTheme -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.disposables.Disposable /** * Created by Allan Wang on 2017-06-12. @@ -35,8 +33,6 @@ abstract class BaseActivity : KauBaseActivity() { */ protected open fun backConsumer(): Boolean = false - private val compositeDisposable = CompositeDisposable() - final override fun onBackPressed() { if (this is SearchViewHolder && searchViewOnBackPress()) return if (this is VideoViewHolder && videoOnBackPress()) return @@ -49,15 +45,6 @@ abstract class BaseActivity : KauBaseActivity() { if (this !is WebOverlayActivityBase) setFrostTheme() } - override fun onDestroy() { - compositeDisposable.dispose() - super.onDestroy() - } - - fun Disposable.disposeOnDestroy() { - compositeDisposable.add(this) - } - // // private var networkDisposable: Disposable? = null // private var networkConsumer: ((Connectivity) -> Unit)? = null diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt index 7f69cc27..13253bcf 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -108,6 +108,7 @@ import kotlinx.android.synthetic.main.view_main_fab.* import kotlinx.android.synthetic.main.view_main_toolbar.* import kotlinx.android.synthetic.main.view_main_viewpager.* import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch /** * Created by Allan Wang on 20/12/17. @@ -276,7 +277,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, val currentCookie = loadFbCookie(Prefs.userId) if (currentCookie == null) { toast(R.string.account_not_found) - FbCookie.reset { launchLogin(cookies(), true) } + launch { + FbCookie.reset() + launchLogin(cookies(), true) + } } else { materialDialogThemed { title(R.string.kau_logout) @@ -288,15 +292,22 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, ) positiveText(R.string.kau_yes) negativeText(R.string.kau_no) - onPositive { _, _ -> FbCookie.logout(this@BaseMainActivity) } + onPositive { _, _ -> + launch { + FbCookie.logout(this@BaseMainActivity) + } + } } } } -3L -> launchNewTask<LoginActivity>(clearStack = false) -4L -> launchNewTask<SelectorActivity>(cookies(), false) else -> { - FbCookie.switchUser(profile.identifier, this@BaseMainActivity::refreshAll) - tabsForEachView { _, view -> view.badgeText = null } + launch { + FbCookie.switchUser(profile.identifier) + tabsForEachView { _, view -> view.badgeText = null } + refreshAll() + } } } false @@ -456,12 +467,14 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, override fun onResume() { super.onResume() - FbCookie.switchBackUser {} + val shouldReload = System.currentTimeMillis() - lastAccessTime > MAIN_TIMEOUT_DURATION + lastAccessTime = System.currentTimeMillis() // precaution to avoid loops controlWebview?.resumeTimers() - if (System.currentTimeMillis() - lastAccessTime > MAIN_TIMEOUT_DURATION) { - refreshAll() + launch { + FbCookie.switchBackUser() + if (shouldReload) + refreshAll() } - lastAccessTime = System.currentTimeMillis() // precaution to avoid loops } override fun onPause() { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt index 8b5fe38d..9540636a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -18,7 +18,6 @@ package com.pitchedapps.frost.activities import android.graphics.drawable.Drawable import android.os.Bundle -import android.os.Handler import android.widget.ImageView import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.Toolbar @@ -26,6 +25,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.fadeIn import ca.allanwang.kau.utils.fadeOut +import ca.allanwang.kau.utils.withMainContext import com.bumptech.glide.RequestManager import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException @@ -34,7 +34,7 @@ import com.bumptech.glide.request.target.Target import com.pitchedapps.frost.R import com.pitchedapps.frost.dbflow.CookieModel import com.pitchedapps.frost.dbflow.fetchUsername -import com.pitchedapps.frost.dbflow.loadFbCookiesAsync +import com.pitchedapps.frost.dbflow.loadFbCookiesSuspend import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.profilePictureUrl import com.pitchedapps.frost.glide.FrostGlide @@ -46,11 +46,16 @@ import com.pitchedapps.frost.utils.frostEvent import com.pitchedapps.frost.utils.launchNewTask import com.pitchedapps.frost.utils.logFrostEvent import com.pitchedapps.frost.utils.setFrostColors +import com.pitchedapps.frost.utils.uniqueOnly import com.pitchedapps.frost.web.LoginWebView -import io.reactivex.Single -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.functions.BiFunction -import io.reactivex.subjects.SingleSubject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import kotlin.coroutines.resume /** * Created by Allan Wang on 2017-06-01. @@ -63,18 +68,8 @@ class LoginActivity : BaseActivity() { private val textview: AppCompatTextView by bindView(R.id.textview) private val profile: ImageView by bindView(R.id.profile) - private val profileSubject = SingleSubject.create<Boolean>() - private val usernameSubject = SingleSubject.create<String>() private lateinit var profileLoader: RequestManager - - // Helper to set and enable swipeRefresh - private var refresh: Boolean - get() = swipeRefresh.isRefreshing - set(value) { - if (value) swipeRefresh.isEnabled = true - swipeRefresh.isRefreshing = value - if (!value) swipeRefresh.isEnabled = false - } + private val refreshChannel = Channel<Boolean>(10) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -84,80 +79,96 @@ class LoginActivity : BaseActivity() { setFrostColors { toolbar(toolbar) } - web.loadLogin({ refresh = it != 100 }) { cookie -> + profileLoader = GlideApp.with(profile) + launch { + for (refreshing in refreshChannel.uniqueOnly(this)) { + if (refreshing) swipeRefresh.isEnabled = true + swipeRefresh.isRefreshing = refreshing + if (!refreshing) swipeRefresh.isEnabled = false + } + } + launch { + val cookie = web.loadLogin { refresh(it != 100) } L.d { "Login found" } FbCookie.save(cookie.id) web.fadeOut(onFinish = { profile.fadeIn() - loadInfo(cookie) + launch { loadInfo(cookie) } }) } - profileLoader = GlideApp.with(profile) } - private fun loadInfo(cookie: CookieModel) { - refresh = true - Single.zip<Boolean, String, Pair<Boolean, String>>( - profileSubject, - usernameSubject, - BiFunction(::Pair) - ) - .observeOn(AndroidSchedulers.mainThread()).subscribe { (foundImage, name) -> - refresh = false - if (!foundImage) { - L.e { "Could not get profile photo; Invalid userId?" } - L._i { cookie } - } - textview.text = String.format(getString(R.string.welcome), name) - textview.fadeIn() - frostEvent("Login", "success" to true) - /* - * The user may have logged into an account that is already in the database - * We will let the db handle duplicates and load it now after the new account has been saved - */ - loadFbCookiesAsync { - val cookies = ArrayList(it) - Handler().postDelayed({ - if (Showcase.intro) - launchNewTask<IntroActivity>(cookies, true) - else - launchNewTask<MainActivity>(cookies, true) - }, 1000) - } - }.disposeOnDestroy() - loadProfile(cookie.id) - loadUsername(cookie) + private fun refresh(refreshing: Boolean) { + refreshChannel.offer(refreshing) } - private fun loadProfile(id: Long) { - profileLoader.load(profilePictureUrl(id)) - .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { - override fun onResourceReady( - resource: Drawable?, - model: Any?, - target: Target<Drawable>?, - dataSource: DataSource?, - isFirstResource: Boolean - ): Boolean { - profileSubject.onSuccess(true) - return false - } - - override fun onLoadFailed( - e: GlideException?, - model: Any?, - target: Target<Drawable>?, - isFirstResource: Boolean - ): Boolean { - e.logFrostEvent("Profile loading exception") - profileSubject.onSuccess(false) - return false - } - }).into(profile) + private suspend fun loadInfo(cookie: CookieModel): Unit = withMainContext { + refresh(true) + + val imageDeferred = async { loadProfile(cookie.id) } + val nameDeferred = async { loadUsername(cookie) } + + val foundImage = imageDeferred.await() + val name = nameDeferred.await() + + refresh(false) + + if (!foundImage) { + L.e { "Could not get profile photo; Invalid userId?" } + L._i { cookie } + } + + textview.text = String.format(getString(R.string.welcome), name) + textview.fadeIn() + frostEvent("Login", "success" to true) + + /* + * The user may have logged into an account that is already in the database + * We will let the db handle duplicates and load it now after the new account has been saved + */ + val cookies = ArrayList(loadFbCookiesSuspend()) + delay(1000) + if (Showcase.intro) + launchNewTask<IntroActivity>(cookies, true) + else + launchNewTask<MainActivity>(cookies, true) + } + + private suspend fun loadProfile(id: Long): Boolean = withMainContext { + suspendCancellableCoroutine<Boolean> { cont -> + profileLoader.load(profilePictureUrl(id)) + .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target<Drawable>?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + cont.resume(true) + return false + } + + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target<Drawable>?, + isFirstResource: Boolean + ): Boolean { + e.logFrostEvent("Profile loading exception") + cont.resume(false) + return false + } + }).into(profile) + } } - private fun loadUsername(cookie: CookieModel) { - cookie.fetchUsername(usernameSubject::onSuccess).disposeOnDestroy() + private suspend fun loadUsername(cookie: CookieModel): String = withContext(Dispatchers.IO) { + suspendCancellableCoroutine<String> { cont -> + cookie.fetchUsername { + cont.resume(it) + } + } } override fun backConsumer(): Boolean { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt index 90f38e9e..9a0c6270 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -18,6 +18,7 @@ package com.pitchedapps.frost.activities import android.os.Bundle import androidx.viewpager.widget.ViewPager +import ca.allanwang.kau.utils.withMainContext import com.google.android.material.tabs.TabLayout import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.utils.L @@ -27,7 +28,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.BroadcastChannel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import org.jsoup.Jsoup @UseExperimental(ExperimentalCoroutinesApi::class) @@ -97,8 +97,8 @@ class MainActivity : BaseMainActivity() { .map { "[data-sigil*=$it] [data-sigil=count]" } .map { doc.select(it) } .map { e -> e?.getOrNull(0)?.ownText() } - L._d { "Badges $feed $requests $messages $notifications" } - withContext(Dispatchers.Main) { + L.v { "Badges $feed $requests $messages $notifications" } + withMainContext { tabsForEachView { _, view -> when (view.iicon) { FbItem.FEED.icon -> view.badgeText = feed diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt index 2907bac6..c3224237 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt @@ -32,6 +32,7 @@ import com.pitchedapps.frost.utils.cookies import com.pitchedapps.frost.utils.launchNewTask import com.pitchedapps.frost.utils.setFrostColors import com.pitchedapps.frost.views.AccountItem +import kotlinx.coroutines.launch /** * Created by Allan Wang on 2017-06-04. @@ -55,7 +56,10 @@ class SelectorActivity : BaseActivity() { override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<AccountItem>, item: AccountItem) { if (item.cookie == null) this@SelectorActivity.launchNewTask<LoginActivity>() - else FbCookie.switchUser(item.cookie) { launchNewTask<MainActivity>(cookies()) } + else launch { + FbCookie.switchUser(item.cookie) + launchNewTask<MainActivity>(cookies()) + } } }) setFrostColors { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt index 19a1109f..a8c25050 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -43,6 +43,7 @@ import ca.allanwang.kau.utils.tint import ca.allanwang.kau.utils.toDrawable import ca.allanwang.kau.utils.toast import ca.allanwang.kau.utils.withAlpha +import ca.allanwang.kau.utils.withMainContext import com.google.android.material.snackbar.BaseTransientBottomBar import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial @@ -74,7 +75,6 @@ import com.pitchedapps.frost.views.FrostWebView import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import okhttp3.HttpUrl /** @@ -106,7 +106,7 @@ class FrostWebActivity : WebOverlayActivityBase(false) { content.scope.launch(Dispatchers.IO) { refreshReceiver.receive() refreshReceiver.cancel() - withContext(Dispatchers.Main) { + withMainContext { materialDialogThemed { title(R.string.invalid_share_url) content(R.string.invalid_share_url_desc) @@ -216,12 +216,15 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc if (forceBasicAgent) //todo check; the webview already adds it dynamically userAgentString = USER_AGENT_BASIC Prefs.prevId = Prefs.userId - if (userId != Prefs.userId) FbCookie.switchUser(userId) { reloadBase(true) } - else reloadBase(true) - if (Showcase.firstWebOverlay) { - coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) { - duration = BaseTransientBottomBar.LENGTH_INDEFINITE - setAction(R.string.kau_got_it) { _ -> this.dismiss() } + launch { + if (userId != Prefs.userId) + FbCookie.switchUser(userId) + reloadBase(true) + if (Showcase.firstWebOverlay) { + coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) { + duration = BaseTransientBottomBar.LENGTH_INDEFINITE + setAction(R.string.kau_got_it) { dismiss() } + } } } } |