aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps/frost/activities
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-12-21 02:16:34 -0500
committerGitHub <noreply@github.com>2017-12-21 02:16:34 -0500
commitd683cae6ffe644a9f63eea6cf3b7e59d2bde617b (patch)
tree517fe1d44c27084ccd87507d9804ba28f15c1647 /app/src/main/kotlin/com/pitchedapps/frost/activities
parent82f9aca96493316bc62008f2b3167d34a6029b38 (diff)
downloadfrost-d683cae6ffe644a9f63eea6cf3b7e59d2bde617b.tar.gz
frost-d683cae6ffe644a9f63eea6cf3b7e59d2bde617b.tar.bz2
frost-d683cae6ffe644a9f63eea6cf3b7e59d2bde617b.zip
Enhancement/fragment interface (#564)
* Begin fragment interfaces and themable contracts * Prepare swiperefresh interface * Snapshot * Add compilable version * Revamp once more * Finalize layouts * Cleanup
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps/frost/activities')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt402
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt416
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt77
4 files changed, 464 insertions, 433 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
new file mode 100644
index 00000000..389ff88e
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
@@ -0,0 +1,402 @@
+package com.pitchedapps.frost.activities
+
+import android.annotation.SuppressLint
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.graphics.PointF
+import android.graphics.drawable.ColorDrawable
+import android.net.Uri
+import android.os.Bundle
+import android.support.annotation.StringRes
+import android.support.design.widget.AppBarLayout
+import android.support.design.widget.CoordinatorLayout
+import android.support.design.widget.FloatingActionButton
+import android.support.design.widget.TabLayout
+import android.support.v4.app.ActivityOptionsCompat
+import android.support.v4.app.Fragment
+import android.support.v4.app.FragmentManager
+import android.support.v4.app.FragmentPagerAdapter
+import android.support.v7.widget.Toolbar
+import android.view.Menu
+import android.view.MenuItem
+import android.webkit.ValueCallback
+import android.webkit.WebChromeClient
+import android.widget.FrameLayout
+import ca.allanwang.kau.searchview.SearchItem
+import ca.allanwang.kau.searchview.SearchView
+import ca.allanwang.kau.searchview.SearchViewHolder
+import ca.allanwang.kau.searchview.bindSearchView
+import ca.allanwang.kau.utils.*
+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.badgeable.secondaryItem
+import co.zsmb.materialdrawerkt.draweritems.divider
+import co.zsmb.materialdrawerkt.draweritems.profile.profile
+import co.zsmb.materialdrawerkt.draweritems.profile.profileSetting
+import com.crashlytics.android.answers.ContentViewEvent
+import com.mikepenz.google_material_typeface_library.GoogleMaterial
+import com.mikepenz.iconics.IconicsDrawable
+import com.mikepenz.materialdrawer.AccountHeader
+import com.mikepenz.materialdrawer.Drawer
+import com.pitchedapps.frost.BuildConfig
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.contracts.FileChooserContract
+import com.pitchedapps.frost.contracts.FileChooserDelegate
+import com.pitchedapps.frost.contracts.MainActivityContract
+import com.pitchedapps.frost.contracts.VideoViewHolder
+import com.pitchedapps.frost.dbflow.TAB_COUNT
+import com.pitchedapps.frost.dbflow.loadFbCookie
+import com.pitchedapps.frost.dbflow.loadFbTabs
+import com.pitchedapps.frost.enums.MainActivityLayout
+import com.pitchedapps.frost.enums.Theme
+import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
+import com.pitchedapps.frost.fragments.BaseFragment
+import com.pitchedapps.frost.parsers.SearchParser
+import com.pitchedapps.frost.utils.*
+import com.pitchedapps.frost.utils.iab.FrostBilling
+import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
+import com.pitchedapps.frost.utils.iab.IabMain
+import com.pitchedapps.frost.views.BadgedIcon
+import com.pitchedapps.frost.views.FrostVideoViewer
+import com.pitchedapps.frost.views.FrostViewPager
+import org.jetbrains.anko.doAsync
+import org.jetbrains.anko.uiThread
+
+/**
+ * Created by Allan Wang on 20/12/17.
+ *
+ * Most of the logic that is unrelated to handling fragments
+ */
+abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
+ FileChooserContract by FileChooserDelegate(),
+ VideoViewHolder, SearchViewHolder,
+ FrostBilling by IabMain() {
+
+ lateinit var adapter: SectionsPagerAdapter
+ override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
+ val toolbar: Toolbar by bindView(R.id.toolbar)
+ val viewPager: FrostViewPager by bindView(R.id.container)
+ val fab: FloatingActionButton by bindView(R.id.fab)
+ val tabs: TabLayout by bindView(R.id.tabs)
+ val appBar: AppBarLayout by bindView(R.id.appbar)
+ val coordinator: CoordinatorLayout by bindView(R.id.main_content)
+ override var videoViewer: FrostVideoViewer? = null
+ lateinit var drawer: Drawer
+ lateinit var drawerHeader: AccountHeader
+
+ override var searchView: SearchView? = null
+ private val searchViewCache = mutableMapOf<String, List<SearchItem>>()
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ if (BuildConfig.VERSION_CODE > Prefs.versionCode) {
+ Prefs.versionCode = BuildConfig.VERSION_CODE
+ if (!BuildConfig.DEBUG) {
+ frostChangelog()
+ frostAnswersCustom("Version",
+ "Version code" to BuildConfig.VERSION_CODE,
+ "Version name" to BuildConfig.VERSION_NAME,
+ "Build type" to BuildConfig.BUILD_TYPE,
+ "Frost id" to Prefs.frostId)
+ }
+ }
+ setFrameContentView(Prefs.mainActivityLayout.layoutRes)
+ setSupportActionBar(toolbar)
+ adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs())
+ viewPager.adapter = adapter
+ viewPager.offscreenPageLimit = TAB_COUNT
+ setupDrawer(savedInstanceState)
+
+// fab.setOnClickListener { view ->
+// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
+// .setAction("Action", null).show()
+// }
+ setFrostColors(toolbar, themeWindow = false, headers = arrayOf(appBar), backgrounds = arrayOf(viewPager))
+ tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor())
+ onCreateBilling()
+ }
+
+ fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) {
+ (0 until tabs.tabCount).asSequence().forEach { i ->
+ action(i, tabs.getTabAt(i)!!.customView as BadgedIcon)
+ }
+ }
+
+ private fun setupDrawer(savedInstanceState: Bundle?) {
+ val navBg = Prefs.bgColor.withMinAlpha(200).toLong()
+ val navHeader = Prefs.headerColor.withMinAlpha(200)
+ drawer = drawer {
+ toolbar = this@BaseMainActivity.toolbar
+ savedInstance = savedInstanceState
+ translucentStatusBar = false
+ sliderBackgroundColor = navBg
+ drawerHeader = accountHeader {
+ customViewRes = R.layout.material_drawer_header
+ textColor = Prefs.iconColor.toLong()
+ backgroundDrawable = ColorDrawable(navHeader)
+ selectionSecondLineShown = false
+ cookies().forEach { (id, name) ->
+ profile(name = name ?: "") {
+ iconUrl = PROFILE_PICTURE_URL(id)
+ textColor = Prefs.textColor.toLong()
+ selectedTextColor = Prefs.textColor.toLong()
+ selectedColor = 0x00000001.toLong()
+ identifier = id
+ }
+ }
+ profileSetting(nameRes = R.string.kau_logout) {
+ iicon = GoogleMaterial.Icon.gmd_exit_to_app
+ iconColor = Prefs.textColor.toLong()
+ textColor = Prefs.textColor.toLong()
+ identifier = -2L
+ }
+ profileSetting(nameRes = R.string.kau_add_account) {
+ iconDrawable = IconicsDrawable(this@BaseMainActivity, GoogleMaterial.Icon.gmd_add).actionBar().paddingDp(5).color(Prefs.textColor)
+ textColor = Prefs.textColor.toLong()
+ identifier = -3L
+ }
+ profileSetting(nameRes = R.string.kau_manage_account) {
+ iicon = GoogleMaterial.Icon.gmd_settings
+ iconColor = Prefs.textColor.toLong()
+ textColor = Prefs.textColor.toLong()
+ identifier = -4L
+ }
+ onProfileChanged { _, profile, current ->
+ if (current) launchWebOverlay(FbItem.PROFILE.url)
+ else when (profile.identifier) {
+ -2L -> {
+ val currentCookie = loadFbCookie(Prefs.userId)
+ if (currentCookie == null) {
+ toast(R.string.account_not_found)
+ FbCookie.reset { launchLogin(cookies(), true) }
+ } else {
+ materialDialogThemed {
+ title(R.string.kau_logout)
+ content(String.format(string(R.string.kau_logout_confirm_as_x), currentCookie.name ?: Prefs.userId.toString()))
+ positiveText(R.string.kau_yes)
+ negativeText(R.string.kau_no)
+ onPositive { _, _ -> FbCookie.logout(this@BaseMainActivity) }
+ }
+ }
+ }
+ -3L -> launchNewTask(LoginActivity::class.java, clearStack = false)
+ -4L -> launchNewTask(SelectorActivity::class.java, cookies(), false)
+ else -> {
+ FbCookie.switchUser(profile.identifier, { refreshAll() })
+ tabsForEachView { _, view -> view.badgeText = null }
+ }
+ }
+ false
+ }
+ }
+ drawerHeader.setActiveProfile(Prefs.userId)
+ primaryFrostItem(FbItem.FEED_MOST_RECENT)
+ primaryFrostItem(FbItem.FEED_TOP_STORIES)
+ primaryFrostItem(FbItem.ACTIVITY_LOG)
+ divider()
+ primaryFrostItem(FbItem.PHOTOS)
+ primaryFrostItem(FbItem.GROUPS)
+ primaryFrostItem(FbItem.FRIENDS)
+ primaryFrostItem(FbItem.CHAT)
+ primaryFrostItem(FbItem.PAGES)
+ divider()
+ primaryFrostItem(FbItem.EVENTS)
+ primaryFrostItem(FbItem.BIRTHDAYS)
+ primaryFrostItem(FbItem.ON_THIS_DAY)
+ divider()
+ primaryFrostItem(FbItem.NOTES)
+ primaryFrostItem(FbItem.SAVED)
+ }
+ }
+
+ private fun Builder.primaryFrostItem(item: FbItem) = this.primaryItem(item.titleId) {
+ iicon = item.icon
+ iconColor = Prefs.textColor.toLong()
+ textColor = Prefs.textColor.toLong()
+ selectedIconColor = Prefs.textColor.toLong()
+ selectedTextColor = Prefs.textColor.toLong()
+ selectedColor = 0x00000001.toLong()
+ identifier = item.titleId.toLong()
+ onClick { _ ->
+ frostAnswers {
+ logContentView(ContentViewEvent()
+ .putContentName(item.name)
+ .putContentType("drawer_item"))
+ }
+ launchWebOverlay(item.url)
+ false
+ }
+ }
+
+ private fun Builder.secondaryFrostItem(@StringRes title: Int, onClick: () -> Unit) = this.secondaryItem(title) {
+ textColor = Prefs.textColor.toLong()
+ selectedIconColor = Prefs.textColor.toLong()
+ selectedTextColor = Prefs.textColor.toLong()
+ selectedColor = 0x00000001.toLong()
+ identifier = title.toLong()
+ onClick { _ -> onClick(); false }
+ }
+
+ fun refreshAll() {
+ fragmentSubject.onNext(REQUEST_REFRESH)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
+ menuInflater.inflate(R.menu.menu_main, menu)
+ toolbar.tint(Prefs.iconColor)
+ setMenuIcons(menu, Prefs.iconColor,
+ R.id.action_settings to GoogleMaterial.Icon.gmd_settings,
+ R.id.action_search to GoogleMaterial.Icon.gmd_search)
+ searchViewBindIfNull {
+ bindSearchView(menu, R.id.action_search, Prefs.iconColor) {
+ textCallback = { query, _ ->
+ val results = searchViewCache[query]
+ if (results != null)
+ runOnUiThread { searchView?.results = results }
+ else
+ doAsync {
+ val data = SearchParser.query(query) ?: return@doAsync
+ val items = data.map { SearchItem(it.href, it.title, it.description) }.toMutableList()
+ if (items.isNotEmpty())
+ items.add(SearchItem("${FbItem._SEARCH.url}?q=$query", string(R.string.show_all_results), iicon = null))
+ searchViewCache.put(query, items)
+ uiThread { searchView?.results = items }
+ }
+ }
+ textDebounceInterval = 300
+ searchCallback = { query, _ -> launchWebOverlay("${FbItem._SEARCH.url}/?q=$query"); true }
+ closeListener = { _ -> searchViewCache.clear() }
+ foregroundColor = Prefs.textColor
+ backgroundColor = Prefs.bgColor.withMinAlpha(200)
+ onItemClick = { _, key, _, _ -> launchWebOverlay(key) }
+ }
+ }
+ return true
+ }
+
+ @SuppressLint("RestrictedApi")
+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_settings -> {
+ val intent = Intent(this, SettingsActivity::class.java)
+ intent.putParcelableArrayListExtra(EXTRA_COOKIES, cookies())
+ val bundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.kau_slide_in_right, R.anim.kau_fade_out).toBundle()
+ startActivityForResult(intent, ACTIVITY_SETTINGS, bundle)
+ }
+ else -> return super.onOptionsItemSelected(item)
+ }
+ return true
+ }
+
+ override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) {
+ openMediaPicker(filePathCallback, fileChooserParams)
+ }
+
+ @SuppressLint("NewApi")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (onActivityResultWeb(requestCode, resultCode, data)) return
+ super.onActivityResult(requestCode, resultCode, data)
+ if (requestCode == ACTIVITY_SETTINGS) {
+ if (resultCode and REQUEST_RESTART_APPLICATION > 0) { //completely restart application
+ L.d("Restart Application Requested")
+ val intent = packageManager.getLaunchIntentForPackage(packageName)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+ val pending = PendingIntent.getActivity(this, 666, intent, PendingIntent.FLAG_CANCEL_CURRENT)
+ val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
+ if (buildIsMarshmallowAndUp)
+ alarm.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
+ else
+ alarm.setExact(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
+ finish()
+ System.exit(0)
+ return
+ }
+ if (resultCode and REQUEST_RESTART > 0) return restart()
+ /*
+ * These results can be stacked
+ */
+ if (resultCode and REQUEST_REFRESH > 0) fragmentSubject.onNext(REQUEST_REFRESH)
+ if (resultCode and REQUEST_NAV > 0) frostNavigationBar()
+ if (resultCode and REQUEST_TEXT_ZOOM > 0) fragmentSubject.onNext(REQUEST_TEXT_ZOOM)
+ if (resultCode and REQUEST_SEARCH > 0) invalidateOptionsMenu()
+ }
+ }
+
+ override fun onResume() {
+ super.onResume()
+ FbCookie.switchBackUser { }
+ }
+
+ override fun onStart() {
+ //validate some pro features
+ if (!IS_FROST_PRO) {
+ if (Prefs.theme == Theme.CUSTOM.ordinal) Prefs.theme = Theme.DEFAULT.ordinal
+ }
+ super.onStart()
+ }
+
+ override fun onDestroy() {
+ onDestroyBilling()
+ super.onDestroy()
+ }
+
+ override fun backConsumer(): Boolean {
+ if (currentFragment.onBackPressed()) return true
+ if (Prefs.exitConfirmation) {
+ materialDialogThemed {
+ title(R.string.kau_exit)
+ content(R.string.kau_exit_confirmation)
+ positiveText(R.string.kau_yes)
+ negativeText(R.string.kau_no)
+ onPositive { _, _ -> finish() }
+ checkBoxPromptRes(R.string.kau_do_not_show_again, false, { _, b -> Prefs.exitConfirmation = !b })
+ }
+ return true
+ }
+ return false
+ }
+
+ inline val currentFragment
+ get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as BaseFragment
+
+ inner class SectionsPagerAdapter(fm: FragmentManager, val pages: List<FbItem>) : FragmentPagerAdapter(fm) {
+
+ override fun getItem(position: Int): Fragment {
+ val item = pages[position]
+ val fragment = BaseFragment(item.fragmentCreator, item, position)
+ //If first load hasn't occurred, add a listener
+ // todo check
+// if (!firstLoadFinished) {
+// var disposable: Disposable? = null
+// fragment.post {
+// disposable = it.web.refreshObservable.subscribe {
+// if (!it) {
+// //Ensure first load finisher only happens once
+// if (!firstLoadFinished) firstLoadFinished = true
+// disposable?.dispose()
+// disposable = null
+// }
+// }
+// }
+// }
+ return fragment
+ }
+
+ override fun getCount() = pages.size
+
+ override fun getPageTitle(position: Int): CharSequence = getString(pages[position].titleId)
+ }
+
+ override val lowerVideoPadding: PointF
+ get() =
+ if (Prefs.mainActivityLayout == MainActivityLayout.BOTTOM_BAR)
+ PointF(0f, toolbar.height.toFloat())
+ else
+ PointF(0f, 0f)
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
index 1ba7f4c3..f72807d1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
@@ -1,98 +1,20 @@
package com.pitchedapps.frost.activities
-import android.annotation.SuppressLint
-import android.app.AlarmManager
-import android.app.PendingIntent
-import android.content.Context
-import android.content.Intent
-import android.graphics.PointF
-import android.graphics.drawable.ColorDrawable
-import android.net.Uri
import android.os.Bundle
-import android.support.annotation.StringRes
-import android.support.design.widget.AppBarLayout
-import android.support.design.widget.CoordinatorLayout
-import android.support.design.widget.FloatingActionButton
import android.support.design.widget.TabLayout
-import android.support.v4.app.ActivityOptionsCompat
-import android.support.v4.app.Fragment
-import android.support.v4.app.FragmentManager
-import android.support.v4.app.FragmentPagerAdapter
import android.support.v4.view.ViewPager
-import android.support.v7.widget.Toolbar
-import android.view.Menu
-import android.view.MenuItem
-import android.webkit.ValueCallback
-import android.webkit.WebChromeClient
-import android.widget.FrameLayout
-import ca.allanwang.kau.searchview.SearchItem
-import ca.allanwang.kau.searchview.SearchView
-import ca.allanwang.kau.searchview.SearchViewHolder
-import ca.allanwang.kau.searchview.bindSearchView
-import ca.allanwang.kau.utils.*
-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.badgeable.secondaryItem
-import co.zsmb.materialdrawerkt.draweritems.divider
-import co.zsmb.materialdrawerkt.draweritems.profile.profile
-import co.zsmb.materialdrawerkt.draweritems.profile.profileSetting
-import com.crashlytics.android.answers.ContentViewEvent
-import com.mikepenz.google_material_typeface_library.GoogleMaterial
-import com.mikepenz.iconics.IconicsDrawable
-import com.mikepenz.materialdrawer.AccountHeader
-import com.mikepenz.materialdrawer.Drawer
-import com.pitchedapps.frost.BuildConfig
-import com.pitchedapps.frost.R
-import com.pitchedapps.frost.contracts.ActivityWebContract
-import com.pitchedapps.frost.contracts.FileChooserContract
-import com.pitchedapps.frost.contracts.FileChooserDelegate
-import com.pitchedapps.frost.contracts.VideoViewHolder
-import com.pitchedapps.frost.dbflow.TAB_COUNT
-import com.pitchedapps.frost.dbflow.loadFbCookie
-import com.pitchedapps.frost.dbflow.loadFbTabs
-import com.pitchedapps.frost.enums.MainActivityLayout
-import com.pitchedapps.frost.enums.Theme
-import com.pitchedapps.frost.facebook.FbCookie
-import com.pitchedapps.frost.facebook.FbCookie.switchUser
import com.pitchedapps.frost.facebook.FbItem
-import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
-import com.pitchedapps.frost.fragments.WebFragment
-import com.pitchedapps.frost.parsers.SearchParser
-import com.pitchedapps.frost.utils.*
-import com.pitchedapps.frost.utils.iab.FrostBilling
-import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
-import com.pitchedapps.frost.utils.iab.IabMain
+import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.views.BadgedIcon
-import com.pitchedapps.frost.views.FrostVideoViewer
-import com.pitchedapps.frost.views.FrostViewPager
import io.reactivex.android.schedulers.AndroidSchedulers
-import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
-import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.uiThread
import org.jsoup.Jsoup
import java.util.concurrent.TimeUnit
-class MainActivity : BaseActivity(),
- ActivityWebContract, FileChooserContract by FileChooserDelegate(),
- VideoViewHolder, SearchViewHolder,
- FrostBilling by IabMain() {
+class MainActivity : BaseMainActivity() {
- lateinit var adapter: SectionsPagerAdapter
- override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
- val toolbar: Toolbar by bindView(R.id.toolbar)
- val viewPager: FrostViewPager by bindView(R.id.container)
- val fab: FloatingActionButton by bindView(R.id.fab)
- val tabs: TabLayout by bindView(R.id.tabs)
- val appBar: AppBarLayout by bindView(R.id.appbar)
- val coordinator: CoordinatorLayout by bindView(R.id.main_content)
- override var videoViewer: FrostVideoViewer? = null
- lateinit var drawer: Drawer
- lateinit var drawerHeader: AccountHeader
- var webFragmentObservable = PublishSubject.create<Int>()!!
+ override val fragmentSubject = PublishSubject.create<Int>()!!
var lastPosition = -1
val headerBadgeObservable = PublishSubject.create<String>()
var firstLoadFinished = false
@@ -101,47 +23,20 @@ class MainActivity : BaseActivity(),
L.i("First fragment load has finished")
field = value
}
- override var searchView: SearchView? = null
- private val searchViewCache = mutableMapOf<String, List<SearchItem>>()
-
- companion object {
- const val ACTIVITY_SETTINGS = 97
- /*
- * Possible responses from the SettingsActivity
- * after the configurations have changed
- */
- const val REQUEST_RESTART_APPLICATION = 1 shl 1
- const val REQUEST_RESTART = 1 shl 2
- const val REQUEST_REFRESH = 1 shl 3
- const val REQUEST_WEB_ZOOM = 1 shl 4
- const val REQUEST_NAV = 1 shl 5
- const val REQUEST_SEARCH = 1 shl 6
- }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- if (BuildConfig.VERSION_CODE > Prefs.versionCode) {
- Prefs.versionCode = BuildConfig.VERSION_CODE
- if (!BuildConfig.DEBUG) {
- frostChangelog()
- frostAnswersCustom("Version",
- "Version code" to BuildConfig.VERSION_CODE,
- "Version name" to BuildConfig.VERSION_NAME,
- "Build type" to BuildConfig.BUILD_TYPE,
- "Frost id" to Prefs.frostId)
- }
- }
- setFrameContentView(Prefs.mainActivityLayout.layoutRes)
- setSupportActionBar(toolbar)
- adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs())
- viewPager.adapter = adapter
- viewPager.offscreenPageLimit = TAB_COUNT
+ setupViewPager()
+ setupTabs()
+ }
+
+ private fun setupViewPager() {
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (lastPosition == position) return
- if (lastPosition != -1) webFragmentObservable.onNext(-(lastPosition + 1))
- webFragmentObservable.onNext(position)
+ if (lastPosition != -1) fragmentSubject.onNext(-(lastPosition + 1))
+ fragmentSubject.onNext(position)
lastPosition = position
}
@@ -157,30 +52,17 @@ class MainActivity : BaseActivity(),
}
}
})
- viewPager.post { webFragmentObservable.onNext(0); lastPosition = 0 } //trigger hook so title is set
- setupDrawer(savedInstanceState)
- setupTabs()
-// fab.setOnClickListener { view ->
-// Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
-// .setAction("Action", null).show()
-// }
- setFrostColors(toolbar, themeWindow = false, headers = arrayOf(appBar), backgrounds = arrayOf(viewPager))
- tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor())
- onCreateBilling()
- }
+ viewPager.post { fragmentSubject.onNext(0); lastPosition = 0 } //trigger hook so title is set
- fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) {
- (0 until tabs.tabCount).asSequence().forEach { i ->
- action(i, tabs.getTabAt(i)!!.customView as BadgedIcon)
- }
}
- fun setupTabs() {
+
+ private fun setupTabs() {
viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
tabs.addOnTabSelectedListener(object : TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
override fun onTabReselected(tab: TabLayout.Tab) {
super.onTabReselected(tab)
- currentFragment.web.scrollOrRefresh()
+ currentFragment.onTabClick()
}
override fun onTabSelected(tab: TabLayout.Tab) {
@@ -215,274 +97,4 @@ class MainActivity : BaseActivity(),
}
}
- fun setupDrawer(savedInstanceState: Bundle?) {
- val navBg = Prefs.bgColor.withMinAlpha(200).toLong()
- val navHeader = Prefs.headerColor.withMinAlpha(200)
- drawer = drawer {
- toolbar = this@MainActivity.toolbar
- savedInstance = savedInstanceState
- translucentStatusBar = false
- sliderBackgroundColor = navBg
- drawerHeader = accountHeader {
- customViewRes = R.layout.material_drawer_header
- textColor = Prefs.iconColor.toLong()
- backgroundDrawable = ColorDrawable(navHeader)
- selectionSecondLineShown = false
- cookies().forEach { (id, name) ->
- profile(name = name ?: "") {
- iconUrl = PROFILE_PICTURE_URL(id)
- textColor = Prefs.textColor.toLong()
- selectedTextColor = Prefs.textColor.toLong()
- selectedColor = 0x00000001.toLong()
- identifier = id
- }
- }
- profileSetting(nameRes = R.string.kau_logout) {
- iicon = GoogleMaterial.Icon.gmd_exit_to_app
- iconColor = Prefs.textColor.toLong()
- textColor = Prefs.textColor.toLong()
- identifier = -2L
- }
- profileSetting(nameRes = R.string.kau_add_account) {
- iconDrawable = IconicsDrawable(this@MainActivity, GoogleMaterial.Icon.gmd_add).actionBar().paddingDp(5).color(Prefs.textColor)
- textColor = Prefs.textColor.toLong()
- identifier = -3L
- }
- profileSetting(nameRes = R.string.kau_manage_account) {
- iicon = GoogleMaterial.Icon.gmd_settings
- iconColor = Prefs.textColor.toLong()
- textColor = Prefs.textColor.toLong()
- identifier = -4L
- }
- onProfileChanged { _, profile, current ->
- if (current) launchWebOverlay(FbItem.PROFILE.url)
- else when (profile.identifier) {
- -2L -> {
- val currentCookie = loadFbCookie(Prefs.userId)
- if (currentCookie == null) {
- toast(R.string.account_not_found)
- FbCookie.reset { launchLogin(cookies(), true) }
- } else {
- materialDialogThemed {
- title(R.string.kau_logout)
- content(String.format(string(R.string.kau_logout_confirm_as_x), currentCookie.name ?: Prefs.userId.toString()))
- positiveText(R.string.kau_yes)
- negativeText(R.string.kau_no)
- onPositive { _, _ -> FbCookie.logout(this@MainActivity) }
- }
- }
- }
- -3L -> launchNewTask(LoginActivity::class.java, clearStack = false)
- -4L -> launchNewTask(SelectorActivity::class.java, cookies(), false)
- else -> {
- switchUser(profile.identifier, { refreshAll() })
- tabsForEachView { _, view -> view.badgeText = null }
- }
- }
- false
- }
- }
- drawerHeader.setActiveProfile(Prefs.userId)
- primaryFrostItem(FbItem.FEED_MOST_RECENT)
- primaryFrostItem(FbItem.FEED_TOP_STORIES)
- primaryFrostItem(FbItem.ACTIVITY_LOG)
- divider()
- primaryFrostItem(FbItem.PHOTOS)
- primaryFrostItem(FbItem.GROUPS)
- primaryFrostItem(FbItem.FRIENDS)
- primaryFrostItem(FbItem.CHAT)
- primaryFrostItem(FbItem.PAGES)
- divider()
- primaryFrostItem(FbItem.EVENTS)
- primaryFrostItem(FbItem.BIRTHDAYS)
- primaryFrostItem(FbItem.ON_THIS_DAY)
- divider()
- primaryFrostItem(FbItem.NOTES)
- primaryFrostItem(FbItem.SAVED)
- }
- }
-
- private fun Builder.primaryFrostItem(item: FbItem) = this.primaryItem(item.titleId) {
- iicon = item.icon
- iconColor = Prefs.textColor.toLong()
- textColor = Prefs.textColor.toLong()
- selectedIconColor = Prefs.textColor.toLong()
- selectedTextColor = Prefs.textColor.toLong()
- selectedColor = 0x00000001.toLong()
- identifier = item.titleId.toLong()
- onClick { _ ->
- frostAnswers {
- logContentView(ContentViewEvent()
- .putContentName(item.name)
- .putContentType("drawer_item"))
- }
- launchWebOverlay(item.url)
- false
- }
- }
-
- private fun Builder.secondaryFrostItem(@StringRes title: Int, onClick: () -> Unit) = this.secondaryItem(title) {
- textColor = Prefs.textColor.toLong()
- selectedIconColor = Prefs.textColor.toLong()
- selectedTextColor = Prefs.textColor.toLong()
- selectedColor = 0x00000001.toLong()
- identifier = title.toLong()
- onClick { _ -> onClick(); false }
- }
-
- fun refreshAll() {
- webFragmentObservable.onNext(WebFragment.REQUEST_REFRESH)
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_main, menu)
- toolbar.tint(Prefs.iconColor)
- setMenuIcons(menu, Prefs.iconColor,
- R.id.action_settings to GoogleMaterial.Icon.gmd_settings,
- R.id.action_search to GoogleMaterial.Icon.gmd_search)
- searchViewBindIfNull {
- bindSearchView(menu, R.id.action_search, Prefs.iconColor) {
- textCallback = { query, _ ->
- val results = searchViewCache[query]
- if (results != null)
- runOnUiThread { searchView?.results = results }
- else
- doAsync {
- val data = SearchParser.query(query) ?: return@doAsync
- val items = data.map { SearchItem(it.href, it.title, it.description) }.toMutableList()
- if (items.isNotEmpty())
- items.add(SearchItem("${FbItem._SEARCH.url}?q=$query", string(R.string.show_all_results), iicon = null))
- searchViewCache.put(query, items)
- uiThread { searchView?.results = items }
- }
- }
- textDebounceInterval = 300
- searchCallback = { query, _ -> launchWebOverlay("${FbItem._SEARCH.url}/?q=$query"); true }
- closeListener = { _ -> searchViewCache.clear() }
- foregroundColor = Prefs.textColor
- backgroundColor = Prefs.bgColor.withMinAlpha(200)
- onItemClick = { _, key, _, _ -> launchWebOverlay(key) }
- }
- }
- return true
- }
-
- @SuppressLint("RestrictedApi")
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.action_settings -> {
- val intent = Intent(this, SettingsActivity::class.java)
- intent.putParcelableArrayListExtra(EXTRA_COOKIES, cookies())
- val bundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.kau_slide_in_right, R.anim.kau_fade_out).toBundle()
- startActivityForResult(intent, ACTIVITY_SETTINGS, bundle)
- }
- else -> return super.onOptionsItemSelected(item)
- }
- return true
- }
-
- override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) {
- openMediaPicker(filePathCallback, fileChooserParams)
- }
-
- @SuppressLint("NewApi")
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- if (onActivityResultWeb(requestCode, resultCode, data)) return
- super.onActivityResult(requestCode, resultCode, data)
- if (requestCode == ACTIVITY_SETTINGS) {
- if (resultCode and REQUEST_RESTART_APPLICATION > 0) { //completely restart application
- L.d("Restart Application Requested")
- val intent = packageManager.getLaunchIntentForPackage(packageName)
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
- val pending = PendingIntent.getActivity(this, 666, intent, PendingIntent.FLAG_CANCEL_CURRENT)
- val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
- if (buildIsMarshmallowAndUp)
- alarm.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
- else
- alarm.setExact(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
- finish()
- System.exit(0)
- return
- }
- if (resultCode and REQUEST_RESTART > 0) return restart()
- /*
- * These results can be stacked
- */
- if (resultCode and REQUEST_REFRESH > 0) webFragmentObservable.onNext(WebFragment.REQUEST_REFRESH)
- if (resultCode and REQUEST_NAV > 0) frostNavigationBar()
- if (resultCode and REQUEST_WEB_ZOOM > 0) webFragmentObservable.onNext(WebFragment.REQUEST_TEXT_ZOOM)
- if (resultCode and REQUEST_SEARCH > 0) invalidateOptionsMenu()
- }
- }
-
- override fun onResume() {
- super.onResume()
- FbCookie.switchBackUser { }
- }
-
- override fun onStart() {
- //validate some pro features
- if (!IS_FROST_PRO) {
- if (Prefs.theme == Theme.CUSTOM.ordinal) Prefs.theme = Theme.DEFAULT.ordinal
- }
- super.onStart()
- }
-
- override fun onDestroy() {
- onDestroyBilling()
- super.onDestroy()
- }
-
- override fun backConsumer(): Boolean {
- if (currentFragment.onBackPressed()) return true
- if (Prefs.exitConfirmation) {
- materialDialogThemed {
- title(R.string.kau_exit)
- content(R.string.kau_exit_confirmation)
- positiveText(R.string.kau_yes)
- negativeText(R.string.kau_no)
- onPositive { _, _ -> finish() }
- checkBoxPromptRes(R.string.kau_do_not_show_again, false, { _, b -> Prefs.exitConfirmation = !b })
- }
- return true
- }
- return false
- }
-
- inline val currentFragment
- get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as WebFragment
-
- inner class SectionsPagerAdapter(fm: FragmentManager, val pages: List<FbItem>) : FragmentPagerAdapter(fm) {
-
- override fun getItem(position: Int): Fragment {
- val fragment = WebFragment(pages[position], position)
- //If first load hasn't occurred, add a listener
- if (!firstLoadFinished) {
- var disposable: Disposable? = null
- fragment.post {
- disposable = it.web.refreshObservable.subscribe {
- if (!it) {
- //Ensure first load finisher only happens once
- if (!firstLoadFinished) firstLoadFinished = true
- disposable?.dispose()
- disposable = null
- }
- }
- }
- }
- return fragment
- }
-
- override fun getCount() = pages.size
-
- override fun getPageTitle(position: Int): CharSequence = getString(pages[position].titleId)
- }
-
- override val lowerVideoPadding: PointF
- get() =
- if (Prefs.mainActivityLayout == MainActivityLayout.BOTTOM_BAR)
- PointF(0f, toolbar.height.toFloat())
- else
- PointF(0f, 0f)
-
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
index f17ccf20..19f5102a 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
@@ -161,7 +161,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
}
fun shouldRestartMain() {
- setFrostResult(MainActivity.REQUEST_RESTART)
+ setFrostResult(REQUEST_RESTART)
}
@SuppressLint("MissingSuperCall")
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
index c41964cd..0dbbacbc 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
@@ -1,5 +1,6 @@
package com.pitchedapps.frost.activities
+import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.PointF
import android.net.Uri
@@ -18,15 +19,14 @@ import ca.allanwang.kau.utils.*
import com.mikepenz.community_material_typeface_library.CommunityMaterial
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.contracts.ActivityWebContract
-import com.pitchedapps.frost.contracts.FileChooserContract
-import com.pitchedapps.frost.contracts.FileChooserDelegate
-import com.pitchedapps.frost.contracts.VideoViewHolder
+import com.pitchedapps.frost.contracts.*
import com.pitchedapps.frost.enums.OverlayContext
import com.pitchedapps.frost.facebook.*
import com.pitchedapps.frost.utils.*
+import com.pitchedapps.frost.views.FrostContentWeb
import com.pitchedapps.frost.views.FrostVideoViewer
-import com.pitchedapps.frost.web.FrostWebView
+import com.pitchedapps.frost.views.FrostWebView
+import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import okhttp3.HttpUrl
@@ -56,7 +56,7 @@ class FrostWebActivity : WebOverlayActivityBase(false) {
* and pop a dialog giving the user the option to copy the shared text
*/
var disposable: Disposable? = null
- disposable = frostWeb.web.refreshObservable.subscribe {
+ disposable = content.refreshObservable.subscribe {
disposable?.dispose()
materialDialogThemed {
title(R.string.invalid_share_url)
@@ -98,26 +98,36 @@ class WebOverlayBasicActivity : WebOverlayActivityBase(true)
*/
class WebOverlayActivity : WebOverlayActivityBase(false)
+@SuppressLint("Registered")
open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseActivity(),
- ActivityWebContract, VideoViewHolder, FileChooserContract by FileChooserDelegate() {
+ ActivityContract, FrostContentContainer,
+ VideoViewHolder, FileChooserContract by FileChooserDelegate() {
override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
val toolbar: Toolbar by bindView(R.id.overlay_toolbar)
- val frostWeb: FrostWebView by bindView(R.id.overlay_frost_webview)
+ val content: FrostContentWeb by bindView(R.id.frost_content_web)
+ val web: FrostWebView
+ get() = content.coreView
val coordinator: CoordinatorLayout by bindView(R.id.overlay_main_content)
- inline val urlTest: String?
+ private inline val urlTest: String?
get() = intent.extras?.getString(ARG_URL) ?: intent.dataString
- open val url: String
+ override val baseUrl: String
get() = (intent.extras?.getString(ARG_URL) ?: intent.dataString).formattedFbUrl
- inline val userId: Long
+ override val baseEnum: FbItem? = null
+
+ private inline val userId: Long
get() = intent.extras?.getLong(ARG_USER_ID, Prefs.userId) ?: Prefs.userId
- inline val overlayContext: OverlayContext?
+ private inline val overlayContext: OverlayContext?
get() = intent.extras?.getSerializable(ARG_OVERLAY_CONTEXT) as OverlayContext?
+ override fun setTitle(title: String) {
+ toolbar.title = title
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (urlTest == null) {
@@ -136,17 +146,24 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc
setFrostColors(toolbar, themeWindow = false)
coordinator.setBackgroundColor(Prefs.bgColor.withAlpha(255))
- frostWeb.setupWebview(url)
- if (forceBasicAgent)
- frostWeb.web.userAgentString = USER_AGENT_BASIC
- frostWeb.web.addTitleListener({ toolbar.title = it })
- Prefs.prevId = Prefs.userId
- if (userId != Prefs.userId) FbCookie.switchUser(userId) { frostWeb.web.loadBaseUrl() }
- else frostWeb.web.loadBaseUrl()
- if (Showcase.firstWebOverlay) {
- coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) {
- duration = Snackbar.LENGTH_INDEFINITE
- setAction(R.string.kau_got_it) { _ -> this.dismiss() }
+ content.bind(this)
+ web.reloadBase(true)
+
+ content.titleObservable
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe { toolbar.title = it }
+
+ with(web) {
+ if (forceBasicAgent)
+ userAgentString = USER_AGENT_BASIC
+ Prefs.prevId = Prefs.userId
+ if (userId != Prefs.userId) FbCookie.switchUser(userId) { reloadBase(true) }
+ else reloadBase(true)
+ if (Showcase.firstWebOverlay) {
+ coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) {
+ duration = Snackbar.LENGTH_INDEFINITE
+ setAction(R.string.kau_got_it) { _ -> this.dismiss() }
+ }
}
}
@@ -165,15 +182,15 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc
super.onNewIntent(intent)
val newUrl = (intent.extras?.getString(ARG_URL) ?: intent.dataString ?: return).formattedFbUrl
L.d("New intent")
- if (url != newUrl) {
+ if (baseUrl != newUrl) {
this.intent = intent
- frostWeb.web.baseUrl = newUrl
- frostWeb.web.loadBaseUrl()
+ content.baseUrl = newUrl
+ web.reloadBase(true)
}
}
override fun backConsumer(): Boolean {
- if (!frostWeb.onBackPressed())
+ if (!web.onBackPressed())
finishSlideOut()
return true
}
@@ -216,9 +233,9 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
- R.id.action_copy_link -> copyToClipboard(frostWeb.web.url)
- R.id.action_share -> shareText(frostWeb.web.url)
- else -> if (!OverlayContext.onOptionsItemSelected(frostWeb.web, item.itemId))
+ R.id.action_copy_link -> copyToClipboard(web.currentUrl)
+ R.id.action_share -> shareText(web.currentUrl)
+ else -> if (!OverlayContext.onOptionsItemSelected(web, item.itemId))
return super.onOptionsItemSelected(item)
}
return true