diff options
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps')
14 files changed, 84 insertions, 57 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 267a07a2..08728ae4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -6,6 +6,9 @@ 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 +import io.reactivex.rxkotlin.addTo /** * Created by Allan Wang on 2017-06-12. @@ -17,6 +20,8 @@ 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 @@ -29,7 +34,16 @@ 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 0cd7dacd..db49d994 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -138,15 +138,15 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, shouldShow = false fab.backgroundTintList = ColorStateList.valueOf(Prefs.headerColor.withMinAlpha(200)) fab.hide() - appBar.addOnOffsetChangedListener { appBarLayout, verticalOffset -> - if (!hasFab) return@addOnOffsetChangedListener + appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset -> + if (!hasFab) return@OnOffsetChangedListener val percent = Math.abs(verticalOffset.toFloat() / appBarLayout.totalScrollRange) val shouldShow = percent < 0.2 if (this.shouldShow != shouldShow) { this.shouldShow = shouldShow fab.showIf(shouldShow) } - } + }) } override fun showFab(iicon: IIcon, clickEvent: () -> Unit) { 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 dd0649b3..b5e2119f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -103,7 +103,7 @@ class LoginActivity : BaseActivity() { launchNewTask<MainActivity>(cookies, true) }, 1000) } - } + }.disposeOnDestroy() loadProfile(cookie.id) loadUsername(cookie) } @@ -126,7 +126,7 @@ class LoginActivity : BaseActivity() { } private fun loadUsername(cookie: CookieModel) { - cookie.fetchUsername(usernameSubject::onSuccess) + cookie.fetchUsername(usernameSubject::onSuccess).disposeOnDestroy() } 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 d153b5d9..77ca37f3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -6,6 +6,8 @@ import android.support.v4.view.ViewPager import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.views.BadgedIcon import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo import io.reactivex.schedulers.Schedulers import io.reactivex.subjects.PublishSubject import org.jsoup.Jsoup @@ -83,7 +85,7 @@ class MainActivity : BaseMainActivity() { FbItem.NOTIFICATIONS.icon -> view.badgeText = notifications } } - } + }.disposeOnDestroy() adapter.pages.forEach { tabs.addTab(tabs.newTab() .setCustomView(BadgedIcon(this).apply { iicon = it.icon })) 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 ec8f11ff..3081c463 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -158,6 +158,7 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc content.titleObservable .observeOn(AndroidSchedulers.mainThread()) .subscribe { toolbar.title = it } + .disposeOnDestroy() with(web) { if (forceBasicAgent) //todo check; the webview already adds it dynamically diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt index 69cf32b7..1fe65d5a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt @@ -13,6 +13,7 @@ import com.raizlabs.android.dbflow.annotation.PrimaryKey import com.raizlabs.android.dbflow.annotation.Table import com.raizlabs.android.dbflow.kotlinextensions.* import com.raizlabs.android.dbflow.structure.BaseModel +import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import paperparcel.PaperParcel import java.net.UnknownHostException @@ -67,26 +68,25 @@ fun removeCookie(id: Long) { } } -inline fun CookieModel.fetchUsername(crossinline callback: (String) -> Unit) { - ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ -> - if (!yes) return@subscribe callback("") - var result = "" - try { - result = frostJsoup(cookie, FbItem.PROFILE.url).title() - L.d { "Fetch username found" } - } catch (e: Exception) { - if (e !is UnknownHostException) - e.logFrostEvent("Fetch username failed") - } finally { - if (result.isBlank() && (name?.isNotBlank() == true)) { - callback(name!!) - return@subscribe +inline fun CookieModel.fetchUsername(crossinline callback: (String) -> Unit): Disposable = + ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ -> + if (!yes) return@subscribe callback("") + var result = "" + try { + result = frostJsoup(cookie, FbItem.PROFILE.url).title() + L.d { "Fetch username found" } + } catch (e: Exception) { + if (e !is UnknownHostException) + e.logFrostEvent("Fetch username failed") + } finally { + if (result.isBlank() && (name?.isNotBlank() == true)) { + callback(name!!) + return@subscribe + } + if (name != result) { + name = result + saveFbCookie(this@fetchUsername) + } + callback(result) } - if (name != result) { - name = result - saveFbCookie(this@fetchUsername) - } - callback(result) } - } -}
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt b/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt index 95162932..f5f7463d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt @@ -10,6 +10,8 @@ import com.pitchedapps.frost.utils.createFreshDir import com.pitchedapps.frost.utils.createFreshFile import com.pitchedapps.frost.utils.frostJsoup import com.pitchedapps.frost.utils.unescapeHtml +import io.reactivex.disposables.CompositeDisposable +import io.reactivex.rxkotlin.addTo import okhttp3.Request import okhttp3.ResponseBody import org.jsoup.Jsoup @@ -71,6 +73,8 @@ class OfflineWebsite(private val url: String, .get() .call() + private val compositeDisposable = CompositeDisposable() + /** * Caller to bind callbacks and start the load * Callback is guaranteed to be called unless the load is cancelled @@ -155,7 +159,7 @@ class OfflineWebsite(private val url: String, progress(100) callback(true) } - } + }.addTo(compositeDisposable) } fun zip(name: String): Boolean { @@ -217,7 +221,7 @@ class OfflineWebsite(private val url: String, }) private fun downloadCss() = cssQueue.clean().toTypedArray().zip<String, Set<String>, Set<String>>({ - it.flatMap { it }.toSet() + it.flatMap { l -> l }.toSet() }, { it.downloadUrl({ emptySet() }) { file, body -> var content = body.string() @@ -319,6 +323,7 @@ class OfflineWebsite(private val url: String, fun cancel() { cancelled = true + compositeDisposable.dispose() L.v { "Request cancelled" } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt index a02cbe59..d6915f75 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt @@ -39,7 +39,7 @@ enum class FbItem( PHOTOS(R.string.photos, GoogleMaterial.Icon.gmd_photo, "me/photos"), PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "me"), SAVED(R.string.saved, GoogleMaterial.Icon.gmd_bookmark, "saved"), - _SEARCH(R.string.search_menu_title, GoogleMaterial.Icon.gmd_search, "search/top"), + _SEARCH(R.string.kau_search, GoogleMaterial.Icon.gmd_search, "search/top"), SETTINGS(R.string.settings, GoogleMaterial.Icon.gmd_settings, "settings"), ; diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt index 1698ae13..e45e86b1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt @@ -5,6 +5,7 @@ import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.web.FrostWebViewClient import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable import io.reactivex.subjects.SingleSubject import org.apache.commons.text.StringEscapeUtils import java.util.* @@ -76,28 +77,29 @@ interface InjectorContract { /** * Helper method to inject multiple functions simultaneously with a single callback */ -fun WebView.jsInject(vararg injectors: InjectorContract, callback: ((Int) -> Unit)? = null) { +fun WebView.jsInject(vararg injectors: InjectorContract, callback: ((Int) -> Unit)? = null): Disposable? { val validInjectors = injectors.filter { it != JsActions.EMPTY } if (validInjectors.isEmpty()) { callback?.invoke(0) - return + return null } L.d { "Injecting ${validInjectors.size} items" } if (callback == null) { validInjectors.forEach { it.inject(this) } - return + return null } - val observables = Array(validInjectors.size, { SingleSubject.create<Unit>() }) - Single.zip<Unit, Int>(observables.asList(), { it.size }) + val observables = Array(validInjectors.size) { SingleSubject.create<Unit>() } + val disposable = Single.zip<Unit, Int>(observables.asList()) { it.size } .observeOn(AndroidSchedulers.mainThread()) .subscribe { res, _ -> callback(res) } (0 until validInjectors.size).forEach { i -> - validInjectors[i].inject(this, { + validInjectors[i].inject(this) { observables[i].onSuccess(Unit) - }) + } } + return disposable } fun FrostWebViewClient.jsInject(vararg injectors: InjectorContract, diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt index a89fdc54..dbd4d0d1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -3,7 +3,6 @@ package com.pitchedapps.frost.utils import android.graphics.Color import ca.allanwang.kau.kotlin.lazyResettable import ca.allanwang.kau.kpref.KPref -import ca.allanwang.kau.kpref.StringSet import ca.allanwang.kau.kpref.kpref import ca.allanwang.kau.utils.colorToForeground import ca.allanwang.kau.utils.isColorVisibleOn @@ -111,7 +110,7 @@ object Prefs : KPref() { var animate: Boolean by kpref("fancy_animations", true) - var notificationKeywords: StringSet by kpref("notification_keywords", mutableSetOf()) + var notificationKeywords: Set<String> by kpref("notification_keywords", mutableSetOf()) var notificationsGeneral: Boolean by kpref("notification_general", true) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt index b4b78bf2..66ef9723 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -9,8 +9,8 @@ import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.net.Uri import android.support.annotation.StringRes -import android.support.design.internal.SnackbarContentLayout import android.support.design.widget.Snackbar +import android.support.design.widget.SnackbarContentLayout import android.support.v4.content.FileProvider import android.support.v7.widget.Toolbar import android.view.View diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt index 4622971b..19b1176e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt @@ -17,7 +17,9 @@ import com.pitchedapps.frost.facebook.WEB_LOAD_DELAY import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.CompositeDisposable import io.reactivex.disposables.Disposable +import io.reactivex.rxkotlin.addTo import io.reactivex.subjects.BehaviorSubject import io.reactivex.subjects.PublishSubject @@ -53,6 +55,8 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( override val refreshObservable: PublishSubject<Boolean> = PublishSubject.create() override val titleObservable: BehaviorSubject<String> = BehaviorSubject.create() + private val compositeDisposable = CompositeDisposable() + override lateinit var baseUrl: String override var baseEnum: FbItem? = null @@ -81,14 +85,14 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( progress.setProgress(it, true) else progress.progress = it - } + }.addTo(compositeDisposable) refreshObservable .observeOn(AndroidSchedulers.mainThread()) .subscribe { refresh.isRefreshing = it refresh.isEnabled = true - } + }.addTo(compositeDisposable) refresh.setOnRefreshListener { coreView.reload(true) } reloadThemeSelf() @@ -126,6 +130,7 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( progressObservable.onComplete() refreshObservable.onComplete() core.destroy() + compositeDisposable.dispose() } private var dispose: Disposable? = null diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt index c45bf23d..d7f44420 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt @@ -14,6 +14,7 @@ import ca.allanwang.kau.utils.AnimHolder import ca.allanwang.kau.utils.dpToPx import ca.allanwang.kau.utils.scaleXY import ca.allanwang.kau.utils.toast +import com.devbrackets.android.exomedia.ui.widget.VideoControls import com.devbrackets.android.exomedia.ui.widget.VideoView import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.L @@ -78,7 +79,7 @@ class FrostVideoView @JvmOverloads constructor( if (!isPlaying) showControls() else viewerContract.onControlsHidden() } - } + }.start() } else { hideControls() val (scale, tX, tY) = mapBounds() @@ -89,7 +90,7 @@ class FrostVideoView @JvmOverloads constructor( withAnimator(origScale, scale) { scaleXY = it } withAnimator(origX, tX) { translationX = it } withAnimator(origY, tY) { translationY = it } - } + }.start() } } @@ -144,7 +145,8 @@ class FrostVideoView @JvmOverloads constructor( } setOnTouchListener(FrameTouchListener(context)) v.setOnTouchListener(VideoTouchListener(context)) - setOnVideoSizedChangedListener { intrinsicWidth, intrinsicHeight -> + setOnVideoSizedChangedListener { intrinsicWidth, intrinsicHeight, pixelWidthHeightRatio -> + // todo use provided ratio? val ratio = Math.min(width.toFloat() / intrinsicWidth, height.toFloat() / intrinsicHeight.toFloat()) /** * Only remap if not expanded and if dimensions have changed @@ -158,7 +160,7 @@ class FrostVideoView @JvmOverloads constructor( fun setViewerContract(contract: FrostVideoViewerContract) { this.viewerContract = contract - videoControls?.setVisibilityListener(viewerContract) + (videoControls as? VideoControls)?.setVisibilityListener(viewerContract) } fun jumpToStart() { @@ -186,7 +188,7 @@ class FrostVideoView @JvmOverloads constructor( private fun hideControls() { if (videoControls?.isVisible == true) - videoControls?.hide() + videoControls?.hide(false) } private fun toggleControls() { @@ -204,11 +206,11 @@ class FrostVideoView @JvmOverloads constructor( fun destroy() { stopPlayback() if (alpha > 0f) - ProgressAnimator.ofFloat(alpha, 0f) { + ProgressAnimator.ofFloat { duration = FAST_ANIMATION_DURATION - withAnimator { alpha = it } + withAnimator(alpha, 0f) { alpha = it } withEndAction { onFinishedListener() } - } + }.start() else onFinishedListener() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt index d005e58a..8092133b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt @@ -10,7 +10,6 @@ import android.support.v7.widget.RecyclerView import android.util.AttributeSet import android.view.View import android.widget.ImageView -import ca.allanwang.kau.kpref.StringSet import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.string import ca.allanwang.kau.utils.tint @@ -42,10 +41,10 @@ class Keywords @JvmOverloads constructor( editText.tint(Prefs.textColor) addIcon.setImageDrawable(GoogleMaterial.Icon.gmd_add.keywordDrawable(context)) addIcon.setOnClickListener { - if (editText.text.isEmpty()) editText.error = context.string(R.string.empty_keyword) + if (editText.text.isNullOrEmpty()) editText.error = context.string(R.string.empty_keyword) else { adapter.add(0, KeywordItem(editText.text.toString())) - editText.text.clear() + editText.text?.clear() } } adapter.add(Prefs.notificationKeywords.map { KeywordItem(it) }) @@ -61,11 +60,9 @@ class Keywords @JvmOverloads constructor( } fun save() { - val keywords = adapter.adapterItems.map { it.keyword } - Prefs.notificationKeywords = StringSet(keywords) + Prefs.notificationKeywords = adapter.adapterItems.mapTo(mutableSetOf()) { it.keyword } } - } private fun IIcon.keywordDrawable(context: Context): Drawable = toDrawable(context, 20, Prefs.textColor) |