aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/build.gradle19
-rw-r--r--app/proguard-rules.pro33
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/assets/core/_colors.scss4
-rw-r--r--app/src/main/assets/core/header.compact.css1
-rw-r--r--app/src/main/assets/core/header.scss6
-rw-r--r--app/src/main/assets/core/login.compact.css13
-rw-r--r--app/src/main/assets/core/login.scss32
-rw-r--r--app/src/main/assets/facebook.compact.css3
-rw-r--r--app/src/main/assets/facebook.scss11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt26
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt81
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt108
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt24
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/events/FbAccountEvent.kt66
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt22
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/events/WebLaunchEvent.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt39
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt (renamed from app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt)16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/UsernameFetcher.kt36
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt20
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt26
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/ViewUtils.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt13
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt18
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt101
-rw-r--r--app/src/main/res/layout/activity_login.xml21
-rw-r--r--app/src/main/res/layout/activity_main.xml5
-rw-r--r--app/src/main/res/layout/activity_web_overlay.xml3
-rw-r--r--app/src/main/res/layout/login_webview.xml36
-rw-r--r--app/src/main/res/values/strings.xml7
-rw-r--r--app/src/main/res/values/styles.xml8
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/injector/JsBuilderTest.kt14
-rw-r--r--gradle.properties5
43 files changed, 720 insertions, 200 deletions
diff --git a/app/build.gradle b/app/build.gradle
index b2929faa..9c76f38c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -88,8 +88,8 @@ dependencies {
compile "com.github.Raizlabs.DBFlow:dbflow-kotlinextensions:${DBFLOW}"
compile "com.github.Raizlabs.DBFlow:dbflow-rx2:${DBFLOW}"
compile "com.github.Raizlabs.DBFlow:dbflow-rx2-kotlinextensions:${DBFLOW}"
- compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${DBFLOW}"
- compile "net.zetetic:android-database-sqlcipher:${SQL_CIPHER}@aar"
+// compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${DBFLOW}"
+// compile "net.zetetic:android-database-sqlcipher:${SQL_CIPHER}@aar"
testCompile "org.robolectric:robolectric:${ROBOELECTRIC}"
@@ -116,7 +116,7 @@ dependencies {
compile "org.jsoup:jsoup:${JSOUP}"
- compile "org.jetbrains.anko:anko:${ANKO}"
+// compile "org.jetbrains.anko:anko:${ANKO}"
// compile "com.squareup.retrofit2:retrofit:${RETROFIT}"
// compile "com.squareup.retrofit2:adapter-rxjava2:${RETROFIT}"
@@ -132,11 +132,16 @@ dependencies {
compile "com.f2prateek.rx.preferences2:rx-preferences:${RX_PREFS}"
- compile("com.mikepenz:materialdrawer:${MATERIAL_DRAWER}@aar") {
- transitive = true
- }
+// compile("com.mikepenz:materialdrawer:${MATERIAL_DRAWER}@aar") {
+// transitive = true
+// }
+ compile "co.zsmb:materialdrawer-kt:${MATERIAL_DRAWER_KT}"
+
+ compile "nz.bradcampbell:paperparcel:${PAPER_PARCEL}"
+ compile "nz.bradcampbell:paperparcel-kotlin:${PAPER_PARCEL}"
+ kapt "nz.bradcampbell:paperparcel-compiler:${PAPER_PARCEL}"
- compile 'com.jude:swipebackhelper:3.1.2'
+ compile "com.jude:swipebackhelper:${SWIPE_BACK}"
}
kapt {
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 2b766bc4..550646f0 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,25 +1,8 @@
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in C:\Users\User7681\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the proguardFiles
-# directive in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
+-ignorewarnings
+
+-keep class * extends com.raizlabs.android.dbflow.config.DatabaseHolder { *; }
+-keepattributes *Annotation*
+-keepclassmembers class ** {
+ @org.greenrobot.eventbus.Subscribe <methods>;
+}
+-keep enum org.greenrobot.eventbus.ThreadMode { *; } \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 27405db4..c09c1209 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -90,7 +90,9 @@
<activity
android:name=".WebOverlayActivity"
android:theme="@style/AppTheme.Overlay" />
-
+ <activity
+ android:name=".LoginActivity"
+ android:theme="@style/AppTheme.NoActionBar" />
<receiver
android:name=".services.NotificationReceiver"
android:enabled="true"
diff --git a/app/src/main/assets/core/_colors.scss b/app/src/main/assets/core/_colors.scss
new file mode 100644
index 00000000..456cce17
--- /dev/null
+++ b/app/src/main/assets/core/_colors.scss
@@ -0,0 +1,4 @@
+$text: #fff !default;
+$background: #000 !default;
+$background2: #111 !default;
+$transparent: transparent !default;
diff --git a/app/src/main/assets/core/header.compact.css b/app/src/main/assets/core/header.compact.css
new file mode 100644
index 00000000..560a8465
--- /dev/null
+++ b/app/src/main/assets/core/header.compact.css
@@ -0,0 +1 @@
+#header[data-sigil="MTopBlueBarHeader"], #header-notices, [data-sigil*=m-promo-jewel-header] { display: None !important; }
diff --git a/app/src/main/assets/core/header.scss b/app/src/main/assets/core/header.scss
new file mode 100644
index 00000000..4e4a2148
--- /dev/null
+++ b/app/src/main/assets/core/header.scss
@@ -0,0 +1,6 @@
+// remove blue header
+
+#header[data-sigil="MTopBlueBarHeader"], #header-notices,
+[data-sigil*=m-promo-jewel-header] {
+ display: None !important;
+}
diff --git a/app/src/main/assets/core/login.compact.css b/app/src/main/assets/core/login.compact.css
new file mode 100644
index 00000000..765ac466
--- /dev/null
+++ b/app/src/main/assets/core/login.compact.css
@@ -0,0 +1,13 @@
+body, #root, #header, .aclb, ._55wo, ._1upc, input { background: #000 !important; }
+
+button::before, ._56be::before, .btnS, .touch::before { background: #111 !important; }
+
+._56bf, .touch .btn { border-radius: 0 !important; border: 0 !important; }
+
+.touch .btnS { box-shadow: none !important; }
+
+input, ._43mh, .touch .btn, a, .fcg, button, ._52j9, ::-webkit-input-placeholder, ::-moz-placeholder, ::-ms-input-placeholder { color: #fff !important; }
+
+._43mh::before, ._43mh::after { background: #fff !important; }
+
+._1rrd { border: 1px solid #fff !important; color: #fff !important; }
diff --git a/app/src/main/assets/core/login.scss b/app/src/main/assets/core/login.scss
new file mode 100644
index 00000000..81cb4c73
--- /dev/null
+++ b/app/src/main/assets/core/login.scss
@@ -0,0 +1,32 @@
+@import "colors";
+
+body, #root,#header,.aclb,._55wo,._1upc,input {
+ background: $background !important;
+}
+
+button::before, ._56be::before, .btnS, .touch::before {
+ background: $background2 !important;
+}
+
+._56bf, .touch .btn {
+ border-radius: 0 !important;
+ border: 0 !important;
+}
+
+.touch .btnS {
+ box-shadow: none !important;
+}
+
+input,._43mh, .touch .btn,a, .fcg, button, ._52j9, ::-webkit-input-placeholder,::-moz-placeholder ,::-ms-input-placeholder {
+ color: $text !important
+}
+
+// divider lines
+._43mh::before, ._43mh::after {
+ background: $text !important
+}
+
+._1rrd {
+ border: 1px solid $text !important;
+ color: $text !important;
+}
diff --git a/app/src/main/assets/facebook.compact.css b/app/src/main/assets/facebook.compact.css
deleted file mode 100644
index a3a67d95..00000000
--- a/app/src/main/assets/facebook.compact.css
+++ /dev/null
@@ -1,3 +0,0 @@
-#header[data-sigil="MTopBlueBarHeader"], #header-notices { display: None !important; }
-
-textarea, ._2gn4 { background-color: transparent !important; }
diff --git a/app/src/main/assets/facebook.scss b/app/src/main/assets/facebook.scss
deleted file mode 100644
index 0798eb8a..00000000
--- a/app/src/main/assets/facebook.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-$text: #fff;
-$background: #000;
-$transparent: transparent;
-
-#header[data-sigil="MTopBlueBarHeader"], #header-notices {
- display: None !important;
-}
-
-textarea, ._2gn4 {
- background-color: $transparent !important;
-}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index 068cf739..4c34ccfc 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -1,16 +1,23 @@
package com.pitchedapps.frost
import android.app.Application
+import android.content.Context
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.widget.ImageView
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.RequestOptions
+import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
+import com.mikepenz.materialdrawer.util.DrawerImageLoader
+import com.mikepenz.materialdrawer.util.DrawerUIUtils
import com.pitchedapps.frost.facebook.FbCookie
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
import timber.log.Timber
import timber.log.Timber.DebugTree
-
/**
* Created by Allan Wang on 2017-05-28.
*/
@@ -21,9 +28,22 @@ class FrostApp : Application() {
else Timber.plant(CrashReportingTree())
FlowManager.init(FlowConfig.Builder(this).build())
Prefs(this)
- GlideUtils(this)
FbCookie()
super.onCreate()
+
+ //Drawer profile loading logic
+ DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
+ override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String) {
+ Glide.with(imageView.context).load(uri).apply(RequestOptions().placeholder(placeholder)).into(imageView)
+ }
+
+ override fun placeholder(ctx: Context, tag: String): Drawable {
+ when (tag) {
+ DrawerImageLoader.Tags.PROFILE.name, DrawerImageLoader.Tags.ACCOUNT_HEADER.name -> DrawerUIUtils.getPlaceHolder(ctx)
+ }
+ return super.placeholder(ctx, tag);
+ }
+ })
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt
new file mode 100644
index 00000000..03c40aaf
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt
@@ -0,0 +1,81 @@
+package com.pitchedapps.frost
+
+import android.content.Context
+import android.content.Intent
+import android.graphics.drawable.Drawable
+import android.os.Bundle
+import android.support.v4.app.ActivityOptionsCompat
+import android.support.v4.content.ContextCompat
+import android.support.v4.widget.SwipeRefreshLayout
+import android.support.v7.app.AppCompatActivity
+import android.support.v7.widget.AppCompatTextView
+import android.support.v7.widget.Toolbar
+import android.widget.ImageView
+import butterknife.ButterKnife
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.DataSource
+import com.bumptech.glide.load.engine.GlideException
+import com.bumptech.glide.request.RequestListener
+import com.bumptech.glide.request.target.Target
+import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
+import com.pitchedapps.frost.utils.bindView
+import com.pitchedapps.frost.web.LoginWebView
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.subjects.BehaviorSubject
+import io.reactivex.subjects.SingleSubject
+
+
+/**
+ * Created by Allan Wang on 2017-06-01.
+ */
+class LoginActivity : AppCompatActivity() {
+
+ val toolbar: Toolbar by bindView(R.id.toolbar)
+ val web: LoginWebView by bindView(R.id.login_webview)
+ val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
+ val textview: AppCompatTextView by bindView(R.id.textview)
+ val profile: ImageView by bindView(R.id.profile)
+
+ val loginObservable = SingleSubject.create<CookieModel>()
+ val progressObservable = BehaviorSubject.create<Int>()
+
+ companion object {
+ fun newInstance(context: Context) {
+ val intent = Intent(context, LoginActivity::class.java)
+ val bundle = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_in_right, R.anim.slide_out_right).toBundle()
+ ContextCompat.startActivity(context, intent, bundle)
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_login)
+ ButterKnife.bind(this)
+ setSupportActionBar(toolbar)
+ web.loginObservable = loginObservable
+ web.progressObservable = progressObservable
+ loginObservable.observeOn(AndroidSchedulers.mainThread()).subscribe {
+ cookieModel ->
+ Glide.with(this@LoginActivity).load(PROFILE_PICTURE_URL(cookieModel.id)).listener(object : RequestListener<Drawable> {
+ override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
+ return false
+ }
+
+ override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
+ return false
+ }
+
+ }).into(profile)
+ }
+ progressObservable.observeOn(AndroidSchedulers.mainThread()).subscribe {
+ val loading = it != 100
+ if (loading) refresh.isEnabled = true
+ refresh.isRefreshing = loading
+ if (!loading) refresh.isEnabled = false
+ }
+ web.loadLogin()
+ }
+
+
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
index c167dfdb..8b01e0c3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
@@ -1,5 +1,7 @@
package com.pitchedapps.frost
+import android.app.Activity
+import android.content.Intent
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.support.design.widget.Snackbar
@@ -11,15 +13,29 @@ import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
-import android.view.ViewTreeObserver
import butterknife.ButterKnife
+import co.zsmb.materialdrawerkt.builders.Builder
+import co.zsmb.materialdrawerkt.builders.accountHeader
+import co.zsmb.materialdrawerkt.builders.drawer
+import co.zsmb.materialdrawerkt.draweritems.badgeable.primaryItem
+import co.zsmb.materialdrawerkt.draweritems.profile.profile
+import com.mikepenz.materialdrawer.AccountHeader
import com.mikepenz.materialdrawer.Drawer
+import com.pitchedapps.frost.dbflow.CookieModel
import com.pitchedapps.frost.dbflow.loadFbTabs
import com.pitchedapps.frost.dbflow.saveAsync
+import com.pitchedapps.frost.events.FbAccountEvent
+import com.pitchedapps.frost.facebook.FbCookie.switchUser
import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.fragments.BaseFragment
import com.pitchedapps.frost.fragments.WebFragment
-import com.pitchedapps.frost.utils.*
+import com.pitchedapps.frost.utils.Changelog
+import com.pitchedapps.frost.utils.bindView
+import com.pitchedapps.frost.utils.toDrawable
+import org.greenrobot.eventbus.EventBus
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode
class MainActivity : AppCompatActivity() {
@@ -29,15 +45,25 @@ class MainActivity : AppCompatActivity() {
val fab: FloatingActionButton by bindView(R.id.fab)
val tabs: TabLayout by bindView(R.id.tabs)
lateinit var drawer: Drawer
+ lateinit var drawerHeader: AccountHeader
+ lateinit var cookies: ArrayList<CookieModel>
+
+ companion object {
+ const val EXTRA_COOKIES = "extra_cookies"
+ fun launch(activity: Activity, cookies: List<CookieModel>) {
+ val intent = (Intent(activity, MainActivity::class.java))
+ intent.putParcelableArrayListExtra(EXTRA_COOKIES, ArrayList(cookies))
+ activity.startActivity(intent)
+ activity.finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
-// SwipeBackHelper.onCreate(this)
-// SwipeBackHelper.getCurrentPage(this).setSwipeBackEnable(false)
setContentView(R.layout.activity_main)
ButterKnife.bind(this)
setSupportActionBar(toolbar)
-
+ cookies = intent.extras.getParcelableArrayList<CookieModel>(EXTRA_COOKIES)
adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs())
viewPager.adapter = adapter
viewPager.offscreenPageLimit = 5
@@ -56,42 +82,63 @@ class MainActivity : AppCompatActivity() {
}
})
setupTabs()
+ setupDrawer(savedInstanceState)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
}
-
- override fun onPostCreate(savedInstanceState: Bundle?) {
- super.onPostCreate(savedInstanceState)
-// SwipeBackHelper.onPostCreate(this)
- }
-
- override fun onDestroy() {
- super.onDestroy()
-// SwipeBackHelper.onDestroy(this)
- }
-
fun setupTabs() {
-
viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(TabLayout.ViewPagerOnTabSelectedListener(viewPager))
-// tabs.setupWithViewPager(viewPager)
adapter.pages.forEach { tabs.addTab(tabs.newTab().setIcon(it.icon.toDrawable(this))) }
}
+ fun setupDrawer(savedInstanceState: Bundle?) {
+ drawer = drawer {
+ toolbar = this@MainActivity.toolbar
+ savedInstance = savedInstanceState
+ translucentStatusBar = false
+ drawerHeader = accountHeader {
+ cookies.forEach {
+ profile(name = it.name ?: "") {
+ iconUrl = PROFILE_PICTURE_URL(it.id)
+ }
+ }
+ onProfileChanged { _, profile, current ->
+ if (current) WebOverlayActivity.newInstance(this@MainActivity, FbTab.PROFILE)
+ else switchUser(profile.name.text, -1)
+ false
+ }
+ }
+// profile("a") {
+//
+// }
+// if (Prefs.userId != Prefs.userIdDefault) {
+// profile("a")
+// }
+ primaryItem(FbTab.ACTIVITY_LOG)
+ primaryItem(FbTab.PHOTOS)
+ primaryItem(FbTab.GROUPS)
+ }
+ }
+
+ fun Builder.primaryItem(item: FbTab) = this.primaryItem(item.titleId) {
+ iicon = item.icon
+ identifier = item.titleId.toLong()
+ onClick { _ ->
+ WebOverlayActivity.newInstance(this@MainActivity, item.url)
+ false
+ }
+ }
override fun onCreateOptionsMenu(menu: Menu): Boolean {
- // Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
- // Handle action bar item clicks here. The action bar will
- // automatically handle clicks on the Home/Up button, so long
- // as you specify a parent activity in AndroidManifest.xml.
when (item.itemId) {
R.id.action_settings -> {
// startActivity(Intent(this, LoginActivity::class.java))
@@ -119,10 +166,6 @@ class MainActivity : AppCompatActivity() {
val currentFragment: BaseFragment
get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as BaseFragment
- /**
- * A [FragmentPagerAdapter] that returns a fragment corresponding to
- * one of the sections/tabs/pages.
- */
inner class SectionsPagerAdapter(fm: FragmentManager, val pages: List<FbTab>) : FragmentPagerAdapter(fm) {
override fun getItem(position: Int) = WebFragment.newInstance(position, pages[position].url)
@@ -131,4 +174,17 @@ class MainActivity : AppCompatActivity() {
override fun getPageTitle(position: Int): CharSequence = getString(pages[position].titleId)
}
+
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun accountEvent(event: FbAccountEvent) = event.execute(drawerHeader)
+
+ override fun onStart() {
+ super.onStart();
+ EventBus.getDefault().register(this);
+ }
+
+ override fun onStop() {
+ EventBus.getDefault().unregister(this);
+ super.onStop();
+ }
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
index e8c65be3..5d7d145f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
@@ -1,8 +1,10 @@
package com.pitchedapps.frost
-import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
+import com.pitchedapps.frost.dbflow.loadFbCookiesAsync
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-05-28.
@@ -11,7 +13,18 @@ class StartActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- startActivity(Intent(this, MainActivity::class.java))
- finish()
+
+ L.d("Load cookies ${System.currentTimeMillis()}")
+ loadFbCookiesAsync {
+ cookies ->
+ L.d("Cookies loaded ${System.currentTimeMillis()} $cookies")
+ val sorted = cookies.toMutableList()
+ val current = cookies.filter { it.id == Prefs.userId }
+ if (current.isNotEmpty()) {
+ sorted.remove(current[0])
+ sorted.add(0, current[0])
+ }
+ MainActivity.launch(this, sorted)
+ }
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
index fafcf7ae..9f6169cf 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
@@ -5,14 +5,13 @@ import android.content.Intent
import android.os.Bundle
import android.support.v4.app.ActivityOptionsCompat
import android.support.v4.content.ContextCompat
-import android.support.v4.widget.SwipeRefreshLayout
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import butterknife.ButterKnife
import com.jude.swipbackhelper.SwipeBackHelper
+import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.utils.bindView
import com.pitchedapps.frost.web.FrostWebView
-import com.pitchedapps.frost.web.FrostWebViewCore
/**
@@ -21,7 +20,7 @@ import com.pitchedapps.frost.web.FrostWebViewCore
class WebOverlayActivity : AppCompatActivity() {
val toolbar: Toolbar by bindView(R.id.toolbar)
- val frostWeb:FrostWebView by bindView(R.id.frost_webview)
+ val frostWeb: FrostWebView by bindView(R.id.frost_webview)
companion object {
private const val ARG_URL = "arg_url"
@@ -31,6 +30,8 @@ class WebOverlayActivity : AppCompatActivity() {
val bundle = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_in_right, R.anim.slide_out_right).toBundle()
ContextCompat.startActivity(context, intent, bundle)
}
+
+ fun newInstance(context: Context, url: FbTab) = newInstance(context, url.url)
}
override fun onCreate(savedInstanceState: Bundle?) {
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 12443cf1..28ad0800 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
@@ -1,5 +1,7 @@
package com.pitchedapps.frost.dbflow
+import android.os.Parcel
+import android.os.Parcelable
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.raizlabs.android.dbflow.annotation.ConflictAction
@@ -8,6 +10,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 paperparcel.PaperParcel
/**
* Created by Allan Wang on 2017-05-30.
@@ -16,16 +19,29 @@ import com.raizlabs.android.dbflow.structure.BaseModel
@Database(name = CookiesDb.NAME, version = CookiesDb.VERSION)
object CookiesDb {
const val NAME = "Cookies"
- const val VERSION = 1
+ const val VERSION = 2
}
+@PaperParcel
@Table(database = CookiesDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
-data class CookieModel(@PrimaryKey var id: Long = Prefs.userIdDefault, var cookie: String? = null) : BaseModel()
+data class CookieModel(@PrimaryKey var id: Long = Prefs.userIdDefault, var name: String? = null, var cookie: String? = null) : BaseModel(), Parcelable {
+ companion object {
+ @JvmField val CREATOR = PaperParcelCookieModel.CREATOR
+ }
+
+ override fun describeContents() = 0
+ override fun writeToParcel(dest: Parcel, flags: Int) = PaperParcelCookieModel.writeToParcel(this, dest, flags)
+}
fun loadFbCookie(id: Long): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq id)).querySingle()
+fun loadFbCookie(name: String): CookieModel? = (select from CookieModel::class where (CookieModel_Table.name eq name)).querySingle()
+
+fun loadFbCookiesAsync(callback: (cookies: List<CookieModel>) -> Unit) {
+ (select from CookieModel::class).async().queryListResultCallback { _, tResult -> callback.invoke(tResult) }.execute()
+}
-fun saveFbCookie(id: Long, cookie: String?) {
- CookieModel(id, cookie).async save {
+fun saveFbCookie(cookie: CookieModel) {
+ cookie.async save {
L.d("Fb cookie saved")
}
}
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 bed50527..2182f9ff 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
@@ -2,6 +2,7 @@ package com.pitchedapps.frost.dbflow
import android.content.Context
import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.defaultTabs
import com.pitchedapps.frost.utils.L
import com.raizlabs.android.dbflow.annotation.Database
import com.raizlabs.android.dbflow.annotation.PrimaryKey
@@ -32,7 +33,7 @@ fun loadFbTabs(): List<FbTab> {
val tabs: List<FbTabModel>? = SQLite.select().from(FbTabModel::class).orderBy(FbTabModel_Table.position, true).queryList()
if (tabs?.isNotEmpty() ?: false) return tabs!!.map { it.tab }
L.d("No tabs; loading default")
- return listOf(FbTab.FEED, FbTab.MESSAGES, FbTab.FRIENDS, FbTab.NOTIFICATIONS)
+ return defaultTabs()
}
fun List<FbTab>.saveAsync(c: Context) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/events/FbAccountEvent.kt b/app/src/main/kotlin/com/pitchedapps/frost/events/FbAccountEvent.kt
new file mode 100644
index 00000000..538a7919
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/events/FbAccountEvent.kt
@@ -0,0 +1,66 @@
+package com.pitchedapps.frost.events
+
+import com.mikepenz.materialdrawer.AccountHeader
+import com.mikepenz.materialdrawer.model.ProfileDrawerItem
+import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
+import com.pitchedapps.frost.facebook.UsernameFetcher
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.web.FrostWebViewCore
+
+/**
+ * Created by Allan Wang on 2017-06-02.
+ *
+ * An emitter for whenever a change occurs relating to the active facebook account
+ * All subscribers will call one of the execute methods below so the logic is handled within this class
+ * [data] [CookieModel] content
+ * [sender] Webview position that sent the event; or -1 otherwise
+ * [flag] See companion object
+ */
+class FbAccountEvent(val data: CookieModel, val sender: Int, val flag: Int) {
+
+ init {
+ L.d(toString())
+ }
+
+ companion object {
+ const val FLAG_LOGOUT = -2
+ const val FLAG_RESET = -1
+ const val FLAG_NEW = 0
+ const val FLAG_SWITCH = 1
+ const val FLAG_USER_NAME = 2
+ }
+
+ fun execute(webView: FrostWebViewCore) {
+ if (sender != -1 && sender == webView.position) return
+ when (flag) {
+ FLAG_LOGOUT, FLAG_RESET, FLAG_NEW, FLAG_SWITCH -> webView.loadBaseUrl()
+ }
+ }
+
+ /**
+ * If new user id is found; create an account header and fetch the username
+ * If the username is found and the current account is nameless, set the name
+ * Ignore other flags
+ */
+ fun execute(accountHeader: AccountHeader) {
+ when (flag) {
+ FLAG_NEW -> {
+ val profile = ProfileDrawerItem()
+ .withName(data.name)
+ .withIcon(PROFILE_PICTURE_URL(data.id))
+ accountHeader.addProfile(profile, 0)
+ accountHeader.setActiveProfile(profile, true)
+ if (data.name == null)
+ UsernameFetcher.fetch(data, sender)
+ }
+ FLAG_USER_NAME -> {
+ if (accountHeader.activeProfile.name == null)
+ accountHeader.activeProfile.withName(data.name)
+ }
+ FLAG_LOGOUT -> {
+
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt b/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt
deleted file mode 100644
index a2eb6907..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.pitchedapps.frost.events
-
-import com.pitchedapps.frost.web.FrostWebViewCore
-
-/**
- * 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: FrostWebViewCore) {
- 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/events/WebLaunchEvent.kt b/app/src/main/kotlin/com/pitchedapps/frost/events/WebLaunchEvent.kt
new file mode 100644
index 00000000..e32c01ae
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/events/WebLaunchEvent.kt
@@ -0,0 +1,11 @@
+package com.pitchedapps.frost.events
+
+import android.content.Context
+import com.pitchedapps.frost.WebOverlayActivity
+
+/**
+ * Created by Allan Wang on 2017-06-01.
+ */
+class WebLaunchEvent(val url: String) {
+ fun execute(context: Context) = WebOverlayActivity.newInstance(context, url)
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
new file mode 100644
index 00000000..59d76954
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt
@@ -0,0 +1,8 @@
+package com.pitchedapps.frost.facebook
+
+/**
+ * Created by Allan Wang on 2017-06-01.
+ */
+const val FACEBOOK_COM = "facebook.com"
+const val FB_URL_BASE = "https://m.facebook.com/"
+fun PROFILE_PICTURE_URL(id: Long) = "https://graph.facebook.com/$id/picture?type=large" \ 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 e44b872a..7829998f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt
@@ -1,11 +1,11 @@
package com.pitchedapps.frost.facebook
import android.webkit.CookieManager
+import com.pitchedapps.frost.dbflow.CookieModel
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.events.FbAccountEvent
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import org.greenrobot.eventbus.EventBus
@@ -34,48 +34,55 @@ object FbCookie {
private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") }
- fun checkUserId(url: String, cookie: String?) {
- if (Prefs.userId != Prefs.userIdDefault || cookie == null) return
+ fun hasLoggedIn(url: String, cookie: String?):Boolean {
+ if (cookie == null || !url.contains("facebook") || !cookie.contains(userMatcher)) return false
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 {
- save(id.toLong())
+ save(id.toLong(), -1)
+ return true
} catch (e: NumberFormatException) {
//todo send report that id has changed
}
}
+ return false
}
- fun save(id: Long) {
+ fun save(id: Long, sender: Int) {
L.d("New cookie found for $id")
Prefs.userId = id
CookieManager.getInstance().flush()
- EventBus.getDefault().post(WebEvent(WebEvent.REFRESH_BASE))
- saveFbCookie(Prefs.userId, webCookie)
- GlideUtils.downloadProfile(id)
+ val cookie = CookieModel(Prefs.userId, "", webCookie)
+ EventBus.getDefault().post(FbAccountEvent(cookie, sender, FbAccountEvent.FLAG_NEW))
+ saveFbCookie(cookie)
}
//TODO reset when new account is added; reset and clear when account is logged out
- fun reset() {
+ fun reset(loggedOut: Boolean = false, sender: Int) {
Prefs.userId = Prefs.userIdDefault
with(CookieManager.getInstance()) {
removeAllCookies(null)
flush()
}
+ EventBus.getDefault().post(FbAccountEvent(CookieModel(), sender, if (loggedOut) FbAccountEvent.FLAG_LOGOUT else FbAccountEvent.FLAG_RESET))
}
- fun switchUser(id: Long) {
- val cookie = loadFbCookie(id) ?: return
- Prefs.userId = id
+ fun switchUser(id: Long, sender: Int) = switchUser(loadFbCookie(id), sender)
+
+ fun switchUser(name: String, sender: Int) = switchUser(loadFbCookie(name), sender)
+
+ fun switchUser(cookie: CookieModel?, sender: Int) {
+ if (cookie == null) return
+ Prefs.userId = cookie.id
dbCookie = cookie.cookie
webCookie = dbCookie
+ EventBus.getDefault().post(FbAccountEvent(cookie, sender, FbAccountEvent.FLAG_SWITCH))
}
- fun logout() {
+ fun logout(sender: Int) {
L.d("Logging out user ${Prefs.userId}")
removeCookie(Prefs.userId)
- reset()
+ reset(true, sender)
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt
index d391d20f..6b4a2f35 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt
@@ -1,6 +1,5 @@
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
@@ -9,16 +8,23 @@ import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic
import com.pitchedapps.frost.R
enum class FbTab(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: 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, ""),
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?disable_interstitial=1&rdr"),
- NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications");
+ NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications"),
+ ACTIVITY_LOG(R.string.activity_log, GoogleMaterial.Icon.gmd_list, "me/allactivity"),
+ PAGES(R.string.pages, GoogleMaterial.Icon.gmd_flag, "pages"),
+ GROUPS(R.string.groups, GoogleMaterial.Icon.gmd_group, "groups"),
+ SAVED(R.string.saved, GoogleMaterial.Icon.gmd_bookmark, "saved"),
+ BIRTHDAYS(R.string.birthdays, GoogleMaterial.Icon.gmd_cake, "events/birthdays"),
+ CHAT(R.string.chat, GoogleMaterial.Icon.gmd_chat, "buddylist"),
+ PHOTOS(R.string.photos, GoogleMaterial.Icon.gmd_photo, "me/photos"),
+ ;
val url = "$FB_URL_BASE$relativeUrl"
}
-const val FACEBOOK_COM = "facebook.com"
-const val FB_URL_BASE = "https://m.facebook.com/" \ No newline at end of file
+fun defaultTabs():List<FbTab> = listOf(FbTab.FEED, FbTab.MESSAGES, FbTab.FRIENDS, FbTab.NOTIFICATIONS)
+fun defaultDrawers():List<FbTab> = listOf(FbTab.ACTIVITY_LOG, FbTab.PAGES, FbTab.GROUPS, FbTab.SAVED) \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/UsernameFetcher.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/UsernameFetcher.kt
new file mode 100644
index 00000000..da244ba3
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/UsernameFetcher.kt
@@ -0,0 +1,36 @@
+package com.pitchedapps.frost.facebook
+
+import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.dbflow.saveFbCookie
+import com.pitchedapps.frost.events.FbAccountEvent
+import com.pitchedapps.frost.utils.L
+import org.greenrobot.eventbus.EventBus
+import org.jsoup.Jsoup
+import kotlin.concurrent.thread
+
+/**
+ * Created by Allan Wang on 2017-06-02.
+ */
+object UsernameFetcher {
+
+ fun fetch(data: CookieModel, sender: Int) {
+ thread {
+ try {
+ val title = Jsoup.connect(FbTab.PROFILE.url)
+ .cookie(FACEBOOK_COM, data.cookie)
+ .get().title()
+ L.d("User name found: $title")
+ data.name = title
+ } catch (e: Exception) {
+ L.e("User name fetching failed: ${e.message}")
+ data.name = ""
+ } finally {
+ if (data.name != null) {
+ saveFbCookie(data)
+ EventBus.getDefault().post(FbAccountEvent(data, sender, FbAccountEvent.FLAG_USER_NAME))
+ }
+ }
+ }
+ }
+
+} \ 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 21d019e7..39c93b01 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt
@@ -5,6 +5,7 @@ import android.support.v4.widget.SwipeRefreshLayout
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.putString
import com.pitchedapps.frost.web.FrostWebView
import com.pitchedapps.frost.web.FrostWebViewCore
@@ -25,6 +26,7 @@ class WebFragment : BaseFragment() {
val web: FrostWebViewCore by lazy { frostWebView.web }
lateinit var url: String
lateinit private var frostWebView: FrostWebView
+ private var firstLoad = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -34,9 +36,27 @@ class WebFragment : BaseFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
super.onCreateView(inflater, container, savedInstanceState)
frostWebView = FrostWebView(context)
+ frostWebView.position = position
frostWebView.baseUrl = url
return frostWebView
}
+ override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ firstLoad()
+ }
+
+ override fun setUserVisibleHint(isVisibleToUser: Boolean) {
+ super.setUserVisibleHint(isVisibleToUser)
+ firstLoad()
+ }
+
+ fun firstLoad() {
+ if (userVisibleHint && isVisible && firstLoad) {
+ web.loadBaseUrl()
+ firstLoad = false
+ }
+ }
+
override fun onBackPressed() = frostWebView.onBackPressed()
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
index 0482fdc9..5433be60 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
@@ -5,19 +5,21 @@ import com.pitchedapps.frost.utils.L
/**
* Created by Allan Wang on 2017-05-31.
+ * Mapping of the available assets
+ * The enum name must match the css file name
+ * //TODO add folder mapping using Prefs
*/
-enum class CssAssets(f: String) {
- BASE("facebook");
+enum class CssAssets {
+ HEADER, LOGIN
+ ;
- var file = "$f.compact.css"
- var content: String? = null
+ var file = "${name.toLowerCase()}.compact.css"
var injector: JsInjector? = null
fun inject(webView: WebView, callback: ((String) -> Unit)?) {
if (injector == null) {
- if (content == null)
- content = webView.context.assets.open(file).bufferedReader().use { it.readText() }
- injector = JsBuilder().css(content!!).build()
+ val content = webView.context.assets.open("core/$file").bufferedReader().use { it.readText() }
+ injector = JsBuilder().css(content).build()
}
injector!!.inject(webView, callback)
L.d("CSS ${injector!!.function}")
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 c7b4eaf8..4ab48bdb 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
@@ -64,7 +64,8 @@ class JsBuilder {
}
if (css.isNotBlank()) {
val name = v.next
- builder.append("var $name=document.createElement('style');$name.innerHTML='$css';document.head.appendChild($name);")
+ val cssMin = css.replace(Regex("\\s+"), "")
+ builder.append("var $name=document.createElement('style');$name.innerHTML='$cssMin';document.head.appendChild($name);")
}
return builder.append("}()").toString()
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt
deleted file mode 100644
index 6fbcced1..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-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 49cc2f9b..2465980d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt
@@ -11,6 +11,8 @@ object L {
const val TAG = "Frost: %s"
fun e(s: String) = Timber.e(TAG, s)
fun d(s: String) = Timber.d(TAG, s)
+ fun i(s: String) = Timber.i(TAG, s)
+ fun v(s: String) = Timber.v(TAG, s)
}
internal class CrashReportingTree : Timber.Tree() {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/ViewUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/ViewUtils.kt
index 01a49f7e..8dc3f01f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/ViewUtils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/ViewUtils.kt
@@ -1,9 +1,10 @@
package com.pitchedapps.frost.views
import android.content.res.ColorStateList
-import android.graphics.PorterDuff
import android.support.annotation.ColorInt
import android.support.annotation.ColorRes
+import android.support.annotation.StringRes
+import android.support.design.widget.Snackbar
import android.support.v4.content.ContextCompat
import android.view.View
import android.view.ViewGroup
@@ -27,4 +28,12 @@ fun ProgressBar.tint(@ColorInt color: Int) {
progressTintList = sl
secondaryProgressTintList = sl
indeterminateTintList = sl
+}
+
+fun View.snackbar(text: String, duration: Int = Snackbar.LENGTH_LONG) {
+ Snackbar.make(this, text, duration).show()
+}
+
+fun View.snackbar(@StringRes textId: Int, duration: Int = Snackbar.LENGTH_LONG) {
+ Snackbar.make(this, textId, duration).show()
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
new file mode 100644
index 00000000..8be4e278
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -0,0 +1,13 @@
+package com.pitchedapps.frost.web
+
+import android.webkit.JavascriptInterface
+import com.pitchedapps.frost.events.WebLaunchEvent
+import org.greenrobot.eventbus.EventBus
+
+/**
+ * Created by Allan Wang on 2017-06-01.
+ */
+class FrostJSI {
+ @JavascriptInterface
+ fun loadUrl(url: String) = EventBus.getDefault().post(WebLaunchEvent(url))
+} \ 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
index a9cf0559..087e9174 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
@@ -9,7 +9,6 @@ import android.widget.FrameLayout
import android.widget.ProgressBar
import butterknife.ButterKnife
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.bindView
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -22,11 +21,15 @@ class FrostWebView @JvmOverloads constructor(context: Context, attrs: AttributeS
get() = web.baseUrl
set(value) {
web.baseUrl = value
- if (value != null) web.loadUrl(value)
}
val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
val web: FrostWebViewCore by bindView(R.id.frost_webview_core)
val progress: ProgressBar by bindView(R.id.progressBar)
+ var position: Int
+ get() = web.position
+ set(value) {
+ web.position = value
+ }
init {
inflate(getContext(), R.layout.swipe_webview, this)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
index 143c9f5a..4dcf0d9e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
@@ -9,12 +9,11 @@ import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.views.circularReveal
import com.pitchedapps.frost.views.fadeOut
-import io.reactivex.subjects.Subject
/**
* Created by Allan Wang on 2017-05-31.
*/
-class FrostWebViewClient : WebViewClient() {
+class FrostWebViewClient(val position: () -> Int) : WebViewClient() {
companion object {
//Collections of jewels mapped with url match -> id
@@ -27,17 +26,17 @@ class FrostWebViewClient : WebViewClient() {
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
- L.d("FWV Loading $url")
+ L.i("FWV Loading $url")
if (!url.contains(FACEBOOK_COM)) return
- if (url.contains("logout.php")) FbCookie.logout()
+ if (url.contains("logout.php")) FbCookie.logout(position.invoke())
view.fadeOut(duration = 200L)
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
if (!url.contains(FACEBOOK_COM)) return
- FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url))
- CssAssets.BASE.inject(view, {
+ FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url), position.invoke())
+ CssAssets.HEADER.inject(view, {
view.circularReveal(offset = 150L)
})
}
@@ -48,23 +47,22 @@ class FrostWebViewClient : WebViewClient() {
}
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
- L.d("Hi")
L.d("Url Loading ${request.url?.path}")
return super.shouldOverrideUrlLoading(view, request)
}
override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? {
if (!request.url.host.contains(FACEBOOK_COM)) return super.shouldInterceptRequest(view, request)
- L.d("Url intercept ${request.url.path}")
+ L.v("Url intercept ${request.url.path}")
return super.shouldInterceptRequest(view, request)
}
override fun onLoadResource(view: WebView, url: String) {
if (!url.contains(FACEBOOK_COM)) return super.onLoadResource(view, url)
- L.d("Resource $url")
+ L.v("Resource $url")
FrostWebOverlay.values.forEach {
if (url.contains(it.match))
- L.d("Loaded $it")
+ L.d("Resource Loaded $it")
}
super.onLoadResource(view, url)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
index 03659908..b2260b6f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
@@ -10,12 +10,13 @@ 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.events.FbAccountEvent
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
+import org.greenrobot.eventbus.ThreadMode
/**
* Created by Allan Wang on 2017-05-29.
@@ -35,6 +36,7 @@ class FrostWebViewCore @JvmOverloads constructor(
private var nestedOffsetY: Int = 0
override val progressObservable: Subject<Int> //TODO see if we need this
var baseUrl: String? = null
+ var position: Int = -1
init {
isNestedScrollingEnabled = true
@@ -47,7 +49,7 @@ class FrostWebViewCore @JvmOverloads constructor(
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
setLayerType(View.LAYER_TYPE_HARDWARE, null)
- setWebViewClient(FrostWebViewClient())
+ setWebViewClient(FrostWebViewClient({position}))
setWebChromeClient(FrostChromeClient(progressObservable))
}
@@ -56,6 +58,8 @@ class FrostWebViewCore @JvmOverloads constructor(
super.loadUrl(url)
}
+ fun loadBaseUrl() = loadUrl(baseUrl)
+
override fun onTouchEvent(ev: MotionEvent): Boolean {
val event = MotionEvent.obtain(ev)
val action = MotionEventCompat.getActionMasked(event)
@@ -106,8 +110,8 @@ class FrostWebViewCore @JvmOverloads constructor(
super.onDetachedFromWindow()
}
- @Subscribe
- fun webEvent(event: WebEvent) = event.execute(this)
+ @Subscribe(threadMode = ThreadMode.MAIN)
+ fun webEvent(event: FbAccountEvent) = event.execute(this)
// Nested Scroll implements
override fun setNestedScrollingEnabled(enabled: Boolean) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
new file mode 100644
index 00000000..6e0cf201
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
@@ -0,0 +1,101 @@
+package com.pitchedapps.frost.web
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.util.AttributeSet
+import android.view.View
+import android.webkit.*
+import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.facebook.FACEBOOK_COM
+import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.injectors.CssAssets
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.views.circularReveal
+import com.pitchedapps.frost.views.snackbar
+import io.reactivex.subjects.PublishSubject
+import io.reactivex.subjects.SingleSubject
+import io.reactivex.subjects.Subject
+
+/**
+ * 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 LoginWebView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
+) : WebView(context, attrs, defStyleAttr) {
+
+ companion object {
+ const val LOGIN_URL = "https://touch.facebook.com/login"
+ private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") }
+ }
+
+ val cookieObservable = PublishSubject.create<Pair<String, String?>>()
+ lateinit var loginObservable: SingleSubject<CookieModel>
+ lateinit var progressObservable: Subject<Int>
+
+ init {
+ cookieObservable.filter { (_, cookie) -> cookie?.contains(userMatcher) ?: false }
+ .subscribe {
+ (url, cookie) ->
+ L.d("Checking cookie for $url\n\t$cookie")
+ val id = userMatcher.find(cookie!!)?.groups?.get(1)?.value
+ if (id != null) {
+ try {
+ FbCookie.save(id.toLong(), -1)
+ //TODO proceed to next view
+ cookieObservable.onComplete()
+ } catch (e: NumberFormatException) {
+ //todo send report that id has changed
+ }
+ }
+ }
+ setupWebview()
+ }
+
+ @SuppressLint("SetJavaScriptEnabled")
+ fun setupWebview() {
+ settings.javaScriptEnabled = true
+ setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ setWebViewClient(LoginClient())
+ setWebChromeClient(LoginChromeClient())
+ }
+
+ fun loadLogin() {
+ loadUrl(LOGIN_URL)
+ }
+
+
+ inner class LoginClient : WebViewClient() {
+
+ override fun onPageFinished(view: WebView, url: String) {
+ super.onPageFinished(view, url)
+ if (!url.contains(FACEBOOK_COM)) {
+ view.snackbar("No longer under facebook; refreshing...")
+ loadLogin()
+ return
+ }
+ CssAssets.LOGIN.inject(view, {
+ if (view.visibility == View.INVISIBLE)
+ view.circularReveal(offset = 150L)
+ })
+ cookieObservable.onNext(Pair(url, CookieManager.getInstance().getCookie(url)))
+ }
+ }
+
+ inner class LoginChromeClient : WebChromeClient() {
+ override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean {
+ L.d("Login Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}")
+ return super.onConsoleMessage(consoleMessage)
+ }
+
+ override fun onProgressChanged(view: WebView, newProgress: Int) {
+ super.onProgressChanged(view, newProgress)
+ progressObservable.onNext(newProgress)
+ }
+ }
+} \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 00000000..2c03624b
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.design.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:id="@+id/main_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ tools:context=".LoginActivity">
+
+ <android.support.v7.widget.Toolbar
+ android:id="@+id/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="?attr/actionBarSize"
+ android:background="?attr/colorPrimary"
+ app:layout_scrollFlags="scroll|enterAlways"
+ app:popupTheme="@style/AppTheme.PopupOverlay" />
+
+ <include layout="@layout/login_webview" />
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 7f6c06c3..f6c29f8b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -12,14 +12,16 @@
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:fitsSystemWindows="true"
android:paddingTop="@dimen/appbar_padding_top"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
+ android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
+ android:fitsSystemWindows="true"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/AppTheme.PopupOverlay">
@@ -45,6 +47,7 @@
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
+ android:visibility="gone"
app:srcCompat="@android:drawable/ic_dialog_email" />
</android.support.design.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_web_overlay.xml b/app/src/main/res/layout/activity_web_overlay.xml
index bfe177fd..f962b396 100644
--- a/app/src/main/res/layout/activity_web_overlay.xml
+++ b/app/src/main/res/layout/activity_web_overlay.xml
@@ -5,8 +5,9 @@
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:background="@android:color/white"
android:fitsSystemWindows="true"
- tools:context=".MainActivity">
+ tools:context=".WebOverlayActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
diff --git a/app/src/main/res/layout/login_webview.xml b/app/src/main/res/layout/login_webview.xml
new file mode 100644
index 00000000..35b5f681
--- /dev/null
+++ b/app/src/main/res/layout/login_webview.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/swipe_refresh"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/profile"
+ android:layout_width="144dp"
+ android:layout_height="144dp"
+ android:layout_centerInParent="true"
+ android:layout_marginBottom="8dp"
+ android:contentDescription="Profile Picture"
+ android:scaleType="centerInside"/>
+
+ <android.support.v7.widget.AppCompatTextView
+ android:id="@+id/textview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerHorizontal="true"
+ android:layout_below="@id/profile"
+ android:visibility="gone" />
+
+ <com.pitchedapps.frost.web.LoginWebView
+ android:id="@+id/login_webview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:visibility="invisible" />
+ </RelativeLayout>
+</android.support.v4.widget.SwipeRefreshLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8bf0e417..a58e995e 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -13,4 +13,11 @@
<string name="friends">Friends</string>
<string name="messages">Messages</string>
<string name="notifications">Notifications</string>
+ <string name="activity_log">Activity Log</string>
+ <string name="pages">Pages</string>
+ <string name="groups">Groups</string>
+ <string name="saved">Saved</string>
+ <string name="birthdays">Birthdays</string>
+ <string name="chat">Chat</string>
+ <string name="photos">Photos</string>
</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 92c75507..ded59278 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,16 +1,18 @@
<resources>
<!-- Base application theme. -->
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <style name="AppTheme" parent="MaterialDrawerTheme.Light.DarkToolbar.ActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
+
<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
+
<style name="AppTheme.Overlay" parent="AppTheme.NoActionBar">
<item name="android:windowIsTranslucent">true</item>
<item name="android:activityOpenEnterAnimation">@anim/slide_in_right</item>
@@ -18,10 +20,12 @@
<item name="android:activityCloseEnterAnimation">@anim/slide_in_right</item>
<item name="android:activityCloseExitAnimation">@anim/slide_out_right</item>
</style>
+
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
+
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
- <style name="Theme.Splash" parent="AppTheme">
+ <style name="Theme.Splash" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">@drawable/splash_screen</item>
<item name="android:navigationBarColor">@color/splashBackground</item>
<item name="colorPrimaryDark">@color/splashBackground</item>
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injector/JsBuilderTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injector/JsBuilderTest.kt
deleted file mode 100644
index d5fcdc50..00000000
--- a/app/src/test/kotlin/com/pitchedapps/frost/injector/JsBuilderTest.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package com.pitchedapps.frost.injector
-
-import com.pitchedapps.frost.injectors.JsInjector
-import org.junit.Test
-
-/**
- * Created by Allan Wang on 2017-05-31.
- */
-class JsBuilderTest {
- @Test
- fun misc() {
- println(JsInjector.idRemovals.function)
- }
-} \ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 207290f0..726ebeea 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -23,6 +23,7 @@ ANDROID_SUPPORT_LIBS=25.3.1
TIMBER=4.5.1
MATERIAL_DIALOG=0.9.4.3
MATERIAL_DRAWER=5.9.2
+MATERIAL_DRAWER_KT=1.0.2
ICONICS=2.8.5
IICON_GOOGLE=3.0.1.0
IICON_MATERIAL=2.2.0.2
@@ -44,4 +45,6 @@ ROBOELECTRIC=3.3.2
AUTO=1.4.1
AUTO_VALUE_PARCEL=0.2.5
RX_PREFS=2.0.0-RC2
-EVENT_BUS=3.0.0 \ No newline at end of file
+EVENT_BUS=3.0.0
+PAPER_PARCEL=2.0.1
+SWIPE_BACK=3.1.2 \ No newline at end of file