From 5796566137995c8d244720f87ba85bce0e0d2f00 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sat, 3 Jun 2017 00:22:10 -0700 Subject: css updates and beginning login migration --- app/build.gradle | 19 ++-- app/proguard-rules.pro | 33 ++----- app/src/main/AndroidManifest.xml | 4 +- app/src/main/assets/core/_colors.scss | 4 + app/src/main/assets/core/header.compact.css | 1 + app/src/main/assets/core/header.scss | 6 ++ app/src/main/assets/core/login.compact.css | 13 +++ app/src/main/assets/core/login.scss | 32 ++++++ app/src/main/assets/facebook.compact.css | 3 - app/src/main/assets/facebook.scss | 11 --- .../main/kotlin/com/pitchedapps/frost/FrostApp.kt | 26 ++++- .../kotlin/com/pitchedapps/frost/LoginActivity.kt | 81 ++++++++++++++++ .../kotlin/com/pitchedapps/frost/MainActivity.kt | 108 ++++++++++++++++----- .../kotlin/com/pitchedapps/frost/StartActivity.kt | 19 +++- .../com/pitchedapps/frost/WebOverlayActivity.kt | 7 +- .../com/pitchedapps/frost/dbflow/CookiesDb.kt | 24 ++++- .../com/pitchedapps/frost/dbflow/FbTabsDb.kt | 3 +- .../com/pitchedapps/frost/events/FbAccountEvent.kt | 66 +++++++++++++ .../com/pitchedapps/frost/events/WebEvent.kt | 22 ----- .../com/pitchedapps/frost/events/WebLaunchEvent.kt | 11 +++ .../com/pitchedapps/frost/facebook/FbConst.kt | 8 ++ .../com/pitchedapps/frost/facebook/FbCookie.kt | 39 +++++--- .../kotlin/com/pitchedapps/frost/facebook/FbTab.kt | 30 ++++++ .../com/pitchedapps/frost/facebook/FbTabs.kt | 24 ----- .../pitchedapps/frost/facebook/UsernameFetcher.kt | 36 +++++++ .../com/pitchedapps/frost/fragments/WebFragment.kt | 20 ++++ .../com/pitchedapps/frost/injectors/CssAssets.kt | 16 +-- .../com/pitchedapps/frost/injectors/JsInjector.kt | 3 +- .../com/pitchedapps/frost/utils/GlideUtils.kt | 26 ----- .../main/kotlin/com/pitchedapps/frost/utils/L.kt | 2 + .../com/pitchedapps/frost/views/ViewUtils.kt | 11 ++- .../kotlin/com/pitchedapps/frost/web/FrostJSI.kt | 13 +++ .../com/pitchedapps/frost/web/FrostWebView.kt | 7 +- .../pitchedapps/frost/web/FrostWebViewClient.kt | 18 ++-- .../com/pitchedapps/frost/web/FrostWebViewCore.kt | 12 ++- .../com/pitchedapps/frost/web/LoginWebView.kt | 101 +++++++++++++++++++ app/src/main/res/layout/activity_login.xml | 21 ++++ app/src/main/res/layout/activity_main.xml | 5 +- app/src/main/res/layout/activity_web_overlay.xml | 3 +- app/src/main/res/layout/login_webview.xml | 36 +++++++ app/src/main/res/values/strings.xml | 7 ++ app/src/main/res/values/styles.xml | 8 +- .../pitchedapps/frost/injector/JsBuilderTest.kt | 14 --- gradle.properties | 5 +- 44 files changed, 739 insertions(+), 219 deletions(-) create mode 100644 app/src/main/assets/core/_colors.scss create mode 100644 app/src/main/assets/core/header.compact.css create mode 100644 app/src/main/assets/core/header.scss create mode 100644 app/src/main/assets/core/login.compact.css create mode 100644 app/src/main/assets/core/login.scss delete mode 100644 app/src/main/assets/facebook.compact.css delete mode 100644 app/src/main/assets/facebook.scss create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/events/FbAccountEvent.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/events/WebLaunchEvent.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/facebook/UsernameFetcher.kt delete mode 100644 app/src/main/kotlin/com/pitchedapps/frost/utils/GlideUtils.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt create mode 100644 app/src/main/res/layout/activity_login.xml create mode 100644 app/src/main/res/layout/login_webview.xml delete mode 100644 app/src/test/kotlin/com/pitchedapps/frost/injector/JsBuilderTest.kt 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 ; +} +-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 @@ - + 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() + val progressObservable = BehaviorSubject.create() + + 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 { + override fun onResourceReady(resource: Drawable?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { + return false + } + + override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, 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 + + companion object { + const val EXTRA_COOKIES = "extra_cookies" + fun launch(activity: Activity, cookies: List) { + 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(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) : 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) -> 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 { val tabs: List? = 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.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/FbTab.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt new file mode 100644 index 00000000..6b4a2f35 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTab.kt @@ -0,0 +1,30 @@ +package com.pitchedapps.frost.facebook + +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 + +enum class FbTab(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: String) { + 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"), + 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" +} + +fun defaultTabs():List = listOf(FbTab.FEED, FbTab.MESSAGES, FbTab.FRIENDS, FbTab.NOTIFICATIONS) +fun defaultDrawers():List = 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/FbTabs.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt deleted file mode 100644 index d391d20f..00000000 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbTabs.kt +++ /dev/null @@ -1,24 +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 - -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"); - - 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 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 //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>() + lateinit var loginObservable: SingleSubject + lateinit var progressObservable: Subject + + 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 @@ + + + + + + + + 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"> @@ -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" /> 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"> + + + + + + + + + + + \ 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 @@ Friends Messages Notifications + Activity Log + Pages + Groups + Saved + Birthdays + Chat + Photos 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 @@ - + + +