From 8618670b82641d5fbaec9c333f1290bab429ce27 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Wed, 31 May 2017 17:11:46 -0700 Subject: add more cookie handling --- app/src/main/AndroidManifest.xml | 39 ++---- .../main/kotlin/com/pitchedapps/frost/FrostApp.kt | 4 +- .../kotlin/com/pitchedapps/frost/MainActivity.kt | 6 +- .../com/pitchedapps/frost/dbflow/CookiesDb.kt | 13 +- .../kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt | 24 ++++ .../com/pitchedapps/frost/dbflow/FbTabsDb.kt | 4 +- .../com/pitchedapps/frost/events/WebEvent.kt | 22 ++++ .../com/pitchedapps/frost/facebook/FbCookie.kt | 45 +++++-- .../com/pitchedapps/frost/facebook/UrlData.kt | 28 ----- .../pitchedapps/frost/fragments/BaseFragment.kt | 21 +--- .../com/pitchedapps/frost/fragments/WebFragment.kt | 23 ++-- .../com/pitchedapps/frost/injectors/JsBuilder.kt | 36 ++++++ .../com/pitchedapps/frost/injectors/JsInjector.kt | 24 +--- .../frost/services/NotificationReceiver.kt | 20 +++ .../kotlin/com/pitchedapps/frost/utils/DbUtils.kt | 25 ---- .../com/pitchedapps/frost/utils/GlideUtils.kt | 26 ++++ .../main/kotlin/com/pitchedapps/frost/utils/L.kt | 2 +- .../kotlin/com/pitchedapps/frost/utils/Prefs.kt | 37 ++++-- .../com/pitchedapps/frost/views/FrostWebView.kt | 138 -------------------- .../com/pitchedapps/frost/views/LoginWebView.kt | 73 ----------- .../pitchedapps/frost/views/SwipeRefreshBase.kt | 31 ----- .../com/pitchedapps/frost/web/FrostWebView.kt | 139 +++++++++++++++++++++ .../pitchedapps/frost/web/FrostWebViewClient.kt | 48 +++++++ .../com/pitchedapps/frost/web/SwipeRefreshBase.kt | 30 +++++ app/src/main/res/layout/swipe_webview.xml | 6 +- .../kotlin/com/pitchedapps/frost/BaseUnitTest.kt | 11 ++ .../com/pitchedapps/frost/utils/PrefsTest.kt | 41 ++++++ 27 files changed, 498 insertions(+), 418 deletions(-) create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/injectors/JsBuilder.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/services/NotificationReceiver.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshBase.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/SwipeRefreshBase.kt create mode 100644 app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt (limited to 'app/src') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 793e3983..d44aa950 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,6 +1,5 @@ @@ -92,37 +91,17 @@ android:scheme="https" /> - - - - - - - - - + + + + + - - - - - - + \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt index 0ad5259d..b5e7f5df 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt @@ -4,6 +4,7 @@ import android.app.Application import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.retro.FrostApi import com.pitchedapps.frost.utils.CrashReportingTree +import com.pitchedapps.frost.utils.GlideUtils import com.pitchedapps.frost.utils.Prefs import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager @@ -21,8 +22,9 @@ class FrostApp : Application() { else Timber.plant(CrashReportingTree()) FlowManager.init(FlowConfig.Builder(this).build()) Prefs(this) + GlideUtils(this) FrostApi(this) - FbCookie.init() + FbCookie() super.onCreate() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt index 5c7c3a9e..7bff3b58 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt @@ -24,9 +24,7 @@ import com.pitchedapps.frost.utils.* import io.reactivex.subjects.PublishSubject import io.reactivex.subjects.Subject -class MainActivity : AppCompatActivity(), KeyPairObservable { - - override val observable: Subject> = PublishSubject.create>() +class MainActivity : AppCompatActivity() { lateinit var adapter: SectionsPagerAdapter val toolbar: Toolbar by bindView(R.id.toolbar) @@ -75,7 +73,7 @@ class MainActivity : AppCompatActivity(), KeyPairObservable { finish() } R.id.action_changelog -> Changelog.show(this) - R.id.action_call -> frostApi.me().enqueueFrost { _, response -> L.e(response.toString())} + R.id.action_call -> frostApi.me().enqueueFrost { _, response -> L.e(response.toString()) } R.id.action_db -> adapter.pages.saveAsync(this) R.id.action_restart -> { finish(); 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 d8f349a0..12443cf1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt @@ -1,6 +1,5 @@ package com.pitchedapps.frost.dbflow -import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.raizlabs.android.dbflow.annotation.ConflictAction @@ -23,10 +22,16 @@ object CookiesDb { @Table(database = CookiesDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE) data class CookieModel(@PrimaryKey var id: Long = Prefs.userIdDefault, var cookie: String? = null) : BaseModel() -fun loadFbCookie(): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq Prefs.userId)).querySingle() +fun loadFbCookie(id: Long): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq id)).querySingle() -fun saveFbCookie() { - CookieModel(FbCookie.userId, FbCookie.webCookie).async save { +fun saveFbCookie(id: Long, cookie: String?) { + CookieModel(id, cookie).async save { L.d("Fb cookie saved") } +} + +fun removeCookie(id: Long) { + loadFbCookie(id)?.async?.delete({ + L.d("Fb cookie deleted") + }) } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt new file mode 100644 index 00000000..bb2627a5 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt @@ -0,0 +1,24 @@ +package com.pitchedapps.frost.dbflow + +import android.content.Context +import com.pitchedapps.frost.utils.L +import com.raizlabs.android.dbflow.config.FlowManager +import com.raizlabs.android.dbflow.structure.database.transaction.FastStoreModelTransaction + +/** + * Created by Allan Wang on 2017-05-30. + */ + +object DbUtils { + + fun db(name: String) = FlowManager.getDatabase(name) + fun dbName(name: String) = "$name.db" + fun deleteDatabase(c: Context, name: String) = c.deleteDatabase(dbName(name)) + +} + +inline fun List.replace(context: Context, dbName: String) { + L.d("Replacing $dbName.db") + DbUtils.db(dbName).reset(context) + FastStoreModelTransaction.saveBuilder(FlowManager.getModelAdapter(T::class.java)).addAll(this).build() +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt index 067a07bf..bfd0b0fe 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt @@ -7,9 +7,7 @@ import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic import com.pitchedapps.frost.R -import com.pitchedapps.frost.facebook.FB_KEY import com.pitchedapps.frost.utils.L -import com.pitchedapps.frost.utils.replace import com.raizlabs.android.dbflow.annotation.Database import com.raizlabs.android.dbflow.annotation.ForeignKey import com.raizlabs.android.dbflow.annotation.PrimaryKey @@ -66,7 +64,7 @@ enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: Stri PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "me"), EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "events/upcoming"), FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "friends/center/requests"), - MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages"), + MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages?disable_interstitial=1"), NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications"); val url = "$FB_URL_BASE$relativeUrl" diff --git a/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt b/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt new file mode 100644 index 00000000..64c91955 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt @@ -0,0 +1,22 @@ +package com.pitchedapps.frost.events + +import com.pitchedapps.frost.web.FrostWebView + +/** + * Created by Allan Wang on 2017-05-31. + */ +class WebEvent(val key: Int, val urlMatch: String? = null) { + + companion object { + const val REFRESH = 0 + const val REFRESH_BASE = 1 + } + + fun execute(webView: FrostWebView) { + if (urlMatch != null && !webView.url.contains(urlMatch)) return + when (key) { + REFRESH -> webView.reload() + REFRESH_BASE -> webView.loadUrl(webView.baseUrl) + } + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt index 80fc3b72..3316bb65 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt @@ -3,24 +3,30 @@ package com.pitchedapps.frost.facebook import android.webkit.CookieManager import com.pitchedapps.frost.dbflow.FB_URL_BASE import com.pitchedapps.frost.dbflow.loadFbCookie +import com.pitchedapps.frost.dbflow.removeCookie import com.pitchedapps.frost.dbflow.saveFbCookie +import com.pitchedapps.frost.events.WebEvent +import com.pitchedapps.frost.utils.GlideUtils import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs +import org.greenrobot.eventbus.EventBus /** * Created by Allan Wang on 2017-05-30. */ object FbCookie { - var userId: Long = Prefs.userIdDefault var dbCookie: String? = null var webCookie: String? get() = CookieManager.getInstance().getCookie(FB_URL_BASE) - set(value) = CookieManager.getInstance().setCookie(FB_URL_BASE, value) + set(value) { + CookieManager.getInstance().setCookie(FB_URL_BASE, value) + CookieManager.getInstance().flush() + } - fun init() { - userId = Prefs.userId - dbCookie = loadFbCookie()?.cookie + operator fun invoke() { + L.d("User ${Prefs.userId}") + dbCookie = loadFbCookie(Prefs.userId)?.cookie if (dbCookie != null && webCookie == null) { L.d("DbCookie found & WebCookie is null; setting webcookie") webCookie = dbCookie @@ -30,34 +36,47 @@ object FbCookie { private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") } fun checkUserId(url: String, cookie: String?) { - if (userId != Prefs.userIdDefault || cookie == null) return + if (Prefs.userId != Prefs.userIdDefault || cookie == null) return L.d("Checking cookie for $url\n\t$cookie") if (!url.contains("facebook") || !cookie.contains(userMatcher)) return val id = userMatcher.find(cookie)?.groups?.get(1)?.value if (id != null) { try { - userId = id.toLong() - save() + save(id.toLong()) } catch (e: NumberFormatException) { //todo send report that id has changed } } } - fun save() { - L.d("New cookie found for $userId") - Prefs.userId = userId + fun save(id: Long) { + L.d("New cookie found for $id") + Prefs.userId = id CookieManager.getInstance().flush() - saveFbCookie() + EventBus.getDefault().post(WebEvent(WebEvent.REFRESH_BASE)) + saveFbCookie(Prefs.userId, webCookie) + GlideUtils.downloadProfile(id) } //TODO reset when new account is added; reset and clear when account is logged out fun reset() { Prefs.userId = Prefs.userIdDefault - userId = Prefs.userIdDefault with(CookieManager.getInstance()) { removeAllCookies(null) flush() } } + + fun switchUser(id: Long) { + val cookie = loadFbCookie(id) ?: return + Prefs.userId = id + dbCookie = cookie.cookie + webCookie = dbCookie + } + + fun logout() { + L.d("Logging out user ${Prefs.userId}") + removeCookie(Prefs.userId) + reset() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt deleted file mode 100644 index c5c2a86b..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.pitchedapps.frost.facebook - -import android.content.Context -import android.support.annotation.StringRes -import com.mikepenz.community_material_typeface_library.CommunityMaterial -import com.mikepenz.google_material_typeface_library.GoogleMaterial -import com.mikepenz.iconics.typeface.IIcon -import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic -import com.pitchedapps.frost.R -import com.pitchedapps.frost.dbflow.FbTab - -/** - * Created by Allan Wang on 2017-05-29. - */ -enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, val url: String) { - LOGIN(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://www.facebook.com/v2.9/dialog/oauth?client_id=$FB_KEY&redirect_uri=https://touch.facebook.com/&response_type=token,granted_scopes"), - FEED(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://touch.facebook.com/"), - PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "https://touch.facebook.com/me/"), - EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "https://touch.facebook.com/events/upcoming"), - FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "https://touch.facebook.com/friends/center/requests/"), - MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "https://touch.facebook.com/messages"), - NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "https://touch.facebook.com/notifications"); - - fun tabInfo(c: Context) = FbTab(c.getString(titleId), icon, url) -} - -//BOOKMARKS("https://touch.facebook.com/bookmarks"), -//SEARCH("https://touch.facebook.com/search"), \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/BaseFragment.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/BaseFragment.kt index 435b87a2..cb3bb713 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/BaseFragment.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/BaseFragment.kt @@ -12,12 +12,10 @@ import io.reactivex.functions.Consumer * Created by Allan Wang on 2017-05-29. */ interface BaseFragmentContract { - fun onActivityEvent(position: Int, key: Int) fun onBackPressed(): Boolean } -abstract class BaseFragment : Fragment(), Consumer>, BaseFragmentContract { - var disposable: Disposable? = null +abstract class BaseFragment : Fragment(), BaseFragmentContract { val position: Int by lazy { arguments.getInt(ARG_POSITION) } companion object { @@ -29,21 +27,4 @@ abstract class BaseFragment : Fragment(), Consumer>, BaseFragment } } - override fun onAttach(context: Context?) { - super.onAttach(context) - if (activity is KeyPairObservable && disposable == null) - disposable = (activity as KeyPairObservable).observable.subscribe(this, Consumer { - t: Throwable -> - L.e(t.message ?: "Observable error") - }) - } - - override fun onDestroyView() { - disposable?.dispose() - disposable = null - super.onDestroyView() - } - - override fun accept(t: Pair) = onActivityEvent(t.first, t.second) - } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt index d7bf4061..ba9584eb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt @@ -8,13 +8,10 @@ import android.view.ViewGroup import butterknife.ButterKnife import butterknife.Unbinder import com.pitchedapps.frost.R -import com.pitchedapps.frost.facebook.FbUrl -import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.bindView import com.pitchedapps.frost.utils.putString -import com.pitchedapps.frost.views.FrostWebView -import com.pitchedapps.frost.views.SwipeRefreshBase -import com.pitchedapps.frost.views.WebStatus +import com.pitchedapps.frost.web.FrostWebView +import com.pitchedapps.frost.web.WebStatus /** * Created by Allan Wang on 2017-05-29. @@ -23,10 +20,6 @@ import com.pitchedapps.frost.views.WebStatus class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener { - override fun onActivityEvent(position: Int, key: Int) { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. - } - override fun onRefresh() { web.reload() } @@ -34,10 +27,9 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener { companion object { private val ARG_URL = "arg_url" fun newInstance(position: Int, url: String) = BaseFragment.newInstance(WebFragment(), position).putString(ARG_URL, url) - fun newInstance(position: Int, url: FbUrl = FbUrl.FEED) = newInstance(position, url.url) } - val refresh: SwipeRefreshBase by bindView(R.id.swipe_refresh) + val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh) val web: FrostWebView by bindView(R.id.frost_webview) lateinit var url: String private lateinit var unbinder: Unbinder @@ -56,6 +48,7 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener { override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + web.baseUrl = url web.observable.subscribe { t: WebStatus -> when (t) { @@ -64,10 +57,10 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener { } } refresh.setOnRefreshListener(this) - refresh.shouldSwipe = { - L.e("Y ${web.scrollY}") - SwipeRefreshBase.shouldScroll(web) - } +// refresh.shouldSwipe = { +// L.e("Y ${web.scrollY}") +// SwipeRefreshBase.shouldScroll(web) +// } web.loadUrl(url) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsBuilder.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsBuilder.kt new file mode 100644 index 00000000..9844e5d5 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsBuilder.kt @@ -0,0 +1,36 @@ +package com.pitchedapps.frost.injectors + +import android.webkit.WebView + +/** + * Created by Allan Wang on 2017-05-31. + */ +class JsBuilder { + private val builder = StringBuilder() + + init { + builder.append("javascript:(function(){") + } + + private fun getElementById(id: String) = "document.getElementById(\"$id\")" + + private fun hideElementById(id: String) { + builder.append(getElementById(id)).append(".style.display=\"none\";") + } + + fun hideElementById(vararg ids: String) { + ids.forEach { hideElementById(it) } + } + + fun build() = builder.toString() + "})()" + + fun inject(webView: WebView) { + webView.loadUrl(build()) + } + + fun removeAllStyles() { + + } + + override fun toString() = build() +} \ No newline at end of file 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 e7a9df5a..2d1659cc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt @@ -5,28 +5,8 @@ import android.webkit.WebView /** * Created by Allan Wang on 2017-05-31. */ -class JsInjector { - private val builder = StringBuilder() - - init { - builder.append("javascript:(function(){") - } - - private fun getElementById(id: String) = "document.getElementById(\"$id\")" - - private fun hideElementById(id: String) { - builder.append(getElementById(id)).append(".style.display=\"none\";") - } - - fun hideElementById(vararg ids: String) { - ids.forEach { hideElementById(it) } - } - - fun build() = builder.toString() + "})()" - +object JsInjector { fun inject(webView: WebView) { - webView.loadUrl(build()) - } - override fun toString() = build() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationReceiver.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationReceiver.kt new file mode 100644 index 00000000..b37ca1f8 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationReceiver.kt @@ -0,0 +1,20 @@ +package com.pitchedapps.frost.services + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent + +/** + * Created by Allan Wang on 2017-05-31. + */ +class NotificationReceiver : BroadcastReceiver() { + + companion object { + const val ACTION = "com.pitchedapps.frost.NOTIFICATIONS" + } + + override fun onReceive(context: Context, intent: Intent) { + if (intent.action != ACTION) return + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt deleted file mode 100644 index 32d232b7..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.pitchedapps.frost.utils - -import android.content.Context -import com.raizlabs.android.dbflow.config.FlowManager -import com.raizlabs.android.dbflow.kotlinextensions.* -import com.raizlabs.android.dbflow.structure.database.transaction.FastStoreModelTransaction -import com.raizlabs.android.dbflow.structure.database.transaction.Transaction - -/** - * Created by Allan Wang on 2017-05-30. - */ - -object DbUtils { - - fun db(name: String) = FlowManager.getDatabase(name) - fun dbName(name: String) = "$name.db" - fun deleteDatabase(c: Context, name: String) = c.deleteDatabase(dbName(name)) - -} - -inline fun List.replace(context: Context, dbName: String) { - L.d("Replacing $dbName.db") - DbUtils.db(dbName).reset(context) - FastStoreModelTransaction.saveBuilder(FlowManager.getModelAdapter(T::class.java)).addAll(this).build() -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt new file mode 100644 index 00000000..6fbcced1 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt @@ -0,0 +1,26 @@ +package com.pitchedapps.frost.utils + +import android.content.Context +import com.bumptech.glide.Glide + +/** + * Created by Allan Wang on 2017-05-31. + */ +object GlideUtils { + + lateinit var applicationContext: Context + + operator fun invoke(applicationContext: Context) { + this.applicationContext = applicationContext + } + + fun downloadForLater(url: String) { + Glide.with(applicationContext).download(url) + } + + fun downloadProfile(id: Long) { + L.d("Downloading profile photo") + downloadForLater("http://graph.facebook.com/$id/picture?type=large") + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt index fe1fdc7c..49cc2f9b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt @@ -8,7 +8,7 @@ import timber.log.Timber * Created by Allan Wang on 2017-05-28. */ object L { - val TAG = "Frost: %s" + const val TAG = "Frost: %s" fun e(s: String) = Timber.e(TAG, s) fun d(s: String) = Timber.d(TAG, s) } 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 52a75929..d99e8417 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -5,6 +5,8 @@ import android.content.SharedPreferences /** * Created by Allan Wang on 2017-05-28. + * + * Shared Preference object with lazy cached retrievals */ private val PREFERENCE_NAME = "${com.pitchedapps.frost.BuildConfig.APPLICATION_ID}.prefs" @@ -13,6 +15,8 @@ private val USER_ID = "user_id" object Prefs { + private const val prefDefaultLong = -2L + lateinit private var c: Context operator fun invoke(c: Context) { this.c = c @@ -21,17 +25,36 @@ object Prefs { private val sp: SharedPreferences by lazy { c.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) } - var lastActive: Long - get() = sp.getLong(LAST_ACTIVE, -1) - set(value) = set(LAST_ACTIVE, System.currentTimeMillis()) + var lastActive: Long = prefDefaultLong + get() { + if (field == prefDefaultLong) field = sp.getLong(LAST_ACTIVE, -1) + return field + } + set(value) { + field = value + if (value != prefDefaultLong) set(LAST_ACTIVE, System.currentTimeMillis()) + } const val userIdDefault = -1L - var userId: Long - get() = sp.getLong(USER_ID, userIdDefault) - set(value) = set(USER_ID, value) + var userId: Long = prefDefaultLong + get() { + if (field == prefDefaultLong) field = sp.getLong(USER_ID, userIdDefault) + return field + } + set(value) { + field = value + if (value != prefDefaultLong) set(USER_ID, value) + } private fun set(key: String, value: Boolean) = sp.edit().putBoolean(key, value).apply() private fun set(key: String, value: Int) = sp.edit().putInt(key, value).apply() private fun set(key: String, value: Long) = sp.edit().putLong(key, value).apply() private fun set(key: String, value: String) = sp.edit().putString(key, value).apply() -} \ No newline at end of file + + fun clear() { + L.d("Clearing Prefs") + sp.edit().clear().apply() + lastActive = prefDefaultLong + userId = prefDefaultLong + } +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt deleted file mode 100644 index d537d623..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt +++ /dev/null @@ -1,138 +0,0 @@ -package com.pitchedapps.frost.views - -import android.annotation.SuppressLint -import android.content.Context -import android.graphics.Bitmap -import android.support.v4.view.MotionEventCompat -import android.support.v4.view.NestedScrollingChild -import android.support.v4.view.NestedScrollingChildHelper -import android.support.v4.view.ViewCompat -import android.util.AttributeSet -import android.view.MotionEvent -import android.view.View -import android.webkit.* -import com.pitchedapps.frost.facebook.FbCookie -import com.pitchedapps.frost.utils.L -import com.pitchedapps.frost.utils.ObservableContainer -import io.reactivex.subjects.BehaviorSubject -import io.reactivex.subjects.Subject - -enum class WebStatus { - LOADING, LOADED, ERROR -} - -/** - * Created by Allan Wang on 2017-05-29. - * - * Courtesy of takahirom - * - * https://github.com/takahirom/webview-in-coordinatorlayout/blob/master/app/src/main/java/com/github/takahirom/webview_in_coodinator_layout/NestedWebView.java - */ -class FrostWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : WebView(context, attrs, defStyleAttr), NestedScrollingChild, ObservableContainer { - - private val childHelper = NestedScrollingChildHelper(this) - private var lastY: Int = 0 - private val scrollOffset = IntArray(2) - private val scrollConsumed = IntArray(2) - private var nestedOffsetY: Int = 0 - override val observable: Subject - - init { - isNestedScrollingEnabled = true - observable = BehaviorSubject.create() - setupWebview() - } - - @SuppressLint("SetJavaScriptEnabled") - fun setupWebview() { - settings.javaScriptEnabled = true - setLayerType(View.LAYER_TYPE_HARDWARE, null) - setWebViewClient(object : WebViewClient() { - override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { - super.onReceivedError(view, request, error) - observable.onNext(WebStatus.ERROR) - L.e("FWV Error ${request}") - } - - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - super.onPageStarted(view, url, favicon) - observable.onNext(WebStatus.LOADING) - L.d("FWV Loading $url") - } - - override fun onPageFinished(view: WebView, url: String) { - super.onPageFinished(view, url) - observable.onNext(WebStatus.LOADED) - FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url)) - } - }) - } - - override fun onTouchEvent(ev: MotionEvent): Boolean { - val event = MotionEvent.obtain(ev) - val action = MotionEventCompat.getActionMasked(event) - if (action == MotionEvent.ACTION_DOWN) - nestedOffsetY = 0 - val eventY = event.y.toInt() - event.offsetLocation(0f, nestedOffsetY.toFloat()) - val returnValue: Boolean - when (action) { - MotionEvent.ACTION_MOVE -> { - var deltaY = lastY - eventY - // NestedPreScroll - if (dispatchNestedPreScroll(0, deltaY, scrollConsumed, scrollOffset)) { - deltaY -= scrollConsumed[1] - event.offsetLocation(0f, -scrollOffset[1].toFloat()) - nestedOffsetY += scrollOffset[1] - } - lastY = eventY - scrollOffset[1] - returnValue = super.onTouchEvent(event) - // NestedScroll - if (dispatchNestedScroll(0, scrollOffset[1], 0, deltaY, scrollOffset)) { - event.offsetLocation(0f, scrollOffset[1].toFloat()) - nestedOffsetY += scrollOffset[1] - lastY -= scrollOffset[1] - } - } - MotionEvent.ACTION_DOWN -> { - returnValue = super.onTouchEvent(event) - lastY = eventY - startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL) - } - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - returnValue = super.onTouchEvent(event) - stopNestedScroll() - } - else -> return false - } - return returnValue - } - - // Nested Scroll implements - override fun setNestedScrollingEnabled(enabled: Boolean) { - childHelper.isNestedScrollingEnabled = enabled - } - - override fun isNestedScrollingEnabled() = childHelper.isNestedScrollingEnabled - - override fun startNestedScroll(axes: Int) = childHelper.startNestedScroll(axes) - - override fun stopNestedScroll() = childHelper.stopNestedScroll() - - override fun hasNestedScrollingParent() = childHelper.hasNestedScrollingParent() - - override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?) - = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow) - - override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?) - = childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow) - - override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean) - = childHelper.dispatchNestedFling(velocityX, velocityY, consumed) - - override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float) - = childHelper.dispatchNestedPreFling(velocityX, velocityY) - -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt deleted file mode 100644 index 17557b4d..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt +++ /dev/null @@ -1,73 +0,0 @@ -package com.pitchedapps.frost.views - -import android.annotation.SuppressLint -import android.content.Context -import android.graphics.Bitmap -import android.net.UrlQuerySanitizer -import android.util.AttributeSet -import android.view.View -import android.webkit.WebResourceError -import android.webkit.WebResourceRequest -import android.webkit.WebView -import android.webkit.WebViewClient -import com.facebook.AccessToken -import com.pitchedapps.frost.facebook.FB_KEY -import com.pitchedapps.frost.facebook.retro.FrostApi.frostApi -import com.pitchedapps.frost.facebook.retro.Me -import com.pitchedapps.frost.facebook.retro.enqueueFrost -import com.pitchedapps.frost.utils.L -import retrofit2.Call -import retrofit2.Callback -import retrofit2.Response - -/** - * Created by Allan Wang on 2017-05-29. - */ -class LoginWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : WebView(context, attrs, defStyleAttr) { - - init { - setupWebview() - } - - @SuppressLint("SetJavaScriptEnabled") - fun setupWebview() { - settings.javaScriptEnabled = true - setLayerType(View.LAYER_TYPE_HARDWARE, null) - setWebViewClient(object : WebViewClient() { - override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { - super.onReceivedError(view, request, error) - L.e("Error ${request}") - } - - override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) { - super.onPageStarted(view, url, favicon) - L.d("Loading $url") - } - - override fun onPageFinished(view: WebView?, url: String?) { - super.onPageFinished(view, url) - if (url == null) return - val sanitizer = UrlQuerySanitizer(url) - val accessToken = sanitizer.getValue("access_token") - val expiresIn = sanitizer.getValue("expires_in") - val grantedScopes = sanitizer.getValue("granted_scopes") - val deniedScopes = sanitizer.getValue("deniedScopes") - - - L.d("Loaded $url") - } - }) - } - - fun saveAccessToken(accessToken: String, expiresIn: String, grantedScopes: String?, deniedScopes: String?) { - L.d("Granted $grantedScopes") - L.d("Denied $deniedScopes") - frostApi.me().enqueueFrost { call, response -> - - } - - } - -} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshBase.kt deleted file mode 100644 index 59d42722..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/SwipeRefreshBase.kt +++ /dev/null @@ -1,31 +0,0 @@ -package com.pitchedapps.frost.views - -import android.content.Context -import android.support.v4.widget.SwipeRefreshLayout -import android.util.AttributeSet -import android.view.MotionEvent -import android.webkit.WebView -import com.pitchedapps.frost.utils.L -import com.pitchedapps.frost.utils.Utils - - -/** - * Created by Allan Wang on 2017-05-28. - */ -class SwipeRefreshBase @JvmOverloads constructor( - context: Context?, attrs: AttributeSet? = null -) : SwipeRefreshLayout(context, attrs) { - - lateinit var shouldSwipe: (ev: MotionEvent) -> Boolean - - companion object { - private val SCROLL_BUFFER by lazy { Utils.dpToPx(5) } - fun shouldScroll(webview: WebView) = webview.scrollY <= SCROLL_BUFFER - } - -// override fun onInterceptTouchEvent(ev: MotionEvent):Boolean { -// val b = shouldSwipe.invoke(ev) && super.onInterceptTouchEvent(ev) -// L.e("Should swipe $b") -// return b -// } -} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt new file mode 100644 index 00000000..27312763 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt @@ -0,0 +1,139 @@ +package com.pitchedapps.frost.web + +import android.annotation.SuppressLint +import android.content.Context +import android.support.v4.view.MotionEventCompat +import android.support.v4.view.NestedScrollingChild +import android.support.v4.view.NestedScrollingChildHelper +import android.support.v4.view.ViewCompat +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.webkit.WebView +import com.pitchedapps.frost.events.WebEvent +import com.pitchedapps.frost.utils.ObservableContainer +import io.reactivex.subjects.BehaviorSubject +import io.reactivex.subjects.Subject +import org.greenrobot.eventbus.EventBus +import org.greenrobot.eventbus.Subscribe + +enum class WebStatus { + LOADING, LOADED, ERROR +} + +/** + * Created by Allan Wang on 2017-05-29. + * + * Courtesy of takahirom + * + * https://github.com/takahirom/webview-in-coordinatorlayout/blob/master/app/src/main/java/com/github/takahirom/webview_in_coodinator_layout/NestedWebView.java + */ +class FrostWebView @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : WebView(context, attrs, defStyleAttr), NestedScrollingChild, ObservableContainer { + + private val childHelper = NestedScrollingChildHelper(this) + private var lastY: Int = 0 + private val scrollOffset = IntArray(2) + private val scrollConsumed = IntArray(2) + private var nestedOffsetY: Int = 0 + override val observable: Subject //TODO see if we need this + var baseUrl: String? = null + + init { + isNestedScrollingEnabled = true + observable = BehaviorSubject.create() + setupWebview() + } + + @SuppressLint("SetJavaScriptEnabled") + fun setupWebview() { + settings.javaScriptEnabled = true + setLayerType(View.LAYER_TYPE_HARDWARE, null) + setWebViewClient(FrostWebViewClient(observable)) + } + + override fun loadUrl(url: String?) { + if (url != null) + super.loadUrl(url) + } + + override fun onTouchEvent(ev: MotionEvent): Boolean { + val event = MotionEvent.obtain(ev) + val action = MotionEventCompat.getActionMasked(event) + if (action == MotionEvent.ACTION_DOWN) + nestedOffsetY = 0 + val eventY = event.y.toInt() + event.offsetLocation(0f, nestedOffsetY.toFloat()) + val returnValue: Boolean + when (action) { + MotionEvent.ACTION_MOVE -> { + var deltaY = lastY - eventY + // NestedPreScroll + if (dispatchNestedPreScroll(0, deltaY, scrollConsumed, scrollOffset)) { + deltaY -= scrollConsumed[1] + event.offsetLocation(0f, -scrollOffset[1].toFloat()) + nestedOffsetY += scrollOffset[1] + } + lastY = eventY - scrollOffset[1] + returnValue = super.onTouchEvent(event) + // NestedScroll + if (dispatchNestedScroll(0, scrollOffset[1], 0, deltaY, scrollOffset)) { + event.offsetLocation(0f, scrollOffset[1].toFloat()) + nestedOffsetY += scrollOffset[1] + lastY -= scrollOffset[1] + } + } + MotionEvent.ACTION_DOWN -> { + returnValue = super.onTouchEvent(event) + lastY = eventY + startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL) + } + MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { + returnValue = super.onTouchEvent(event) + stopNestedScroll() + } + else -> return false + } + return returnValue + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + EventBus.getDefault().register(this); + } + + override fun onDetachedFromWindow() { + EventBus.getDefault().unregister(this) + super.onDetachedFromWindow() + } + + @Subscribe + fun webEvent(event: WebEvent) = event.execute(this) + + // Nested Scroll implements + override fun setNestedScrollingEnabled(enabled: Boolean) { + childHelper.isNestedScrollingEnabled = enabled + } + + override fun isNestedScrollingEnabled() = childHelper.isNestedScrollingEnabled + + override fun startNestedScroll(axes: Int) = childHelper.startNestedScroll(axes) + + override fun stopNestedScroll() = childHelper.stopNestedScroll() + + override fun hasNestedScrollingParent() = childHelper.hasNestedScrollingParent() + + override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?) + = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow) + + override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?) + = childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow) + + override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean) + = childHelper.dispatchNestedFling(velocityX, velocityY, consumed) + + override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float) + = childHelper.dispatchNestedPreFling(velocityX, velocityY) + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt new file mode 100644 index 00000000..14fcc22a --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt @@ -0,0 +1,48 @@ +package com.pitchedapps.frost.web + +import android.graphics.Bitmap +import android.webkit.* +import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.utils.L +import io.reactivex.subjects.Subject + +/** + * Created by Allan Wang on 2017-05-31. + */ +class FrostWebViewClient(val observable: Subject) : WebViewClient() { + + private var injectionCount: Int = 0 + + companion object { + //Collections of jewels mapped with url match -> id + val jewelMap: Map = mapOf("a" to "b") + fun test() { + + } + } + + override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) { + super.onReceivedError(view, request, error) + observable.onNext(WebStatus.ERROR) + L.e("FWV Error ${request}") + } + + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + injectionCount = 0 + observable.onNext(WebStatus.LOADING) + L.d("FWV Loading $url") + if (url.contains("logout.php")) FbCookie.logout() + } + + override fun onPageFinished(view: WebView, url: String) { + super.onPageFinished(view, url) + observable.onNext(WebStatus.LOADED) + FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url)) + } + + fun logout() { + + } + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/SwipeRefreshBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/SwipeRefreshBase.kt new file mode 100644 index 00000000..0e303e49 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/SwipeRefreshBase.kt @@ -0,0 +1,30 @@ +package com.pitchedapps.frost.web + +import android.content.Context +import android.support.v4.widget.SwipeRefreshLayout +import android.util.AttributeSet +import android.view.MotionEvent +import android.webkit.WebView +import com.pitchedapps.frost.utils.Utils + + +/** + * Created by Allan Wang on 2017-05-28. + */ +class SwipeRefreshBase @JvmOverloads constructor( + context: Context?, attrs: AttributeSet? = null +) : SwipeRefreshLayout(context, attrs) { + + lateinit var shouldSwipe: (ev: MotionEvent) -> Boolean + + companion object { + private val SCROLL_BUFFER by lazy { Utils.dpToPx(5) } + fun shouldScroll(webview: WebView) = webview.scrollY <= SCROLL_BUFFER + } + +// override fun onInterceptTouchEvent(ev: MotionEvent):Boolean { +// val b = shouldSwipe.invoke(ev) && super.onInterceptTouchEvent(ev) +// L.e("Should swipe $b") +// return b +// } +} \ No newline at end of file diff --git a/app/src/main/res/layout/swipe_webview.xml b/app/src/main/res/layout/swipe_webview.xml index 87df67b2..4873b6cc 100644 --- a/app/src/main/res/layout/swipe_webview.xml +++ b/app/src/main/res/layout/swipe_webview.xml @@ -1,15 +1,15 @@ - - - + diff --git a/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt index 55208aae..43d6bbf9 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt @@ -7,6 +7,7 @@ import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import org.robolectric.RuntimeEnvironment import org.robolectric.annotation.Config +import timber.log.Timber /** * Created by Allan Wang on 2017-05-30. @@ -22,4 +23,14 @@ abstract class BaseUnitTest { val context: Context get() = RuntimeEnvironment.application + + init { + Timber.plant(TestTree()) + } + + internal class TestTree : Timber.Tree() { + override fun log(priority: Int, tag: String, message: String, t: Throwable?) { + System.out.println("$tag-$priority: $message") + } + } } diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt new file mode 100644 index 00000000..56ec4c02 --- /dev/null +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt @@ -0,0 +1,41 @@ +package com.pitchedapps.frost.utils + +import org.junit.Before +import org.junit.Test +import kotlin.test.assertEquals + +/** + * Created by Allan Wang on 2017-05-31. + */ +class PrefsTest { + + //Replicate logic + var test: Long = -1L + get() { + if (field == -1L) field = file + return field + } + set(value) { + field = value + if (value != -1L) file = value + } + + var file: Long = -1L + + @Before + fun verify() { + test = -1L + file = -1L + } + + @Test + fun laziness() { + assertEquals(-1L, test) + file = 2L + assertEquals(2L, test) + file = -3L + assertEquals(2L, test) + test = 3L + assertEquals(3L, file) + } +} \ No newline at end of file -- cgit v1.2.3