aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2019-12-29 15:50:22 -0800
committerGitHub <noreply@github.com>2019-12-29 15:50:22 -0800
commit0828e8fceec86333f81d5b8cf204184ecc58f0ef (patch)
tree52c2bef109a430aac85c03494a5fd4515e4455e5 /app/src/main
parentee68ef07ca0f0afd00bfe32f7e7dbba8ef6a6ae2 (diff)
parent597c884d88b8716d49e0abb00674ce44699df08b (diff)
downloadfrost-0828e8fceec86333f81d5b8cf204184ecc58f0ef.tar.gz
frost-0828e8fceec86333f81d5b8cf204184ecc58f0ef.tar.bz2
frost-0828e8fceec86333f81d5b8cf204184ecc58f0ef.zip
Merge pull request #1601 from AllanWang/nav-rewrite
Nav rewrite
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt24
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt653
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt18
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt4
-rw-r--r--app/src/main/res/drawable/nav_item_background.xml14
-rw-r--r--app/src/main/res/layout/activity_debug.xml4
-rw-r--r--app/src/main/res/layout/activity_main.xml16
-rw-r--r--app/src/main/res/layout/activity_main_bottom_tabs.xml23
-rw-r--r--app/src/main/res/layout/activity_main_drawer_wrapper.xml22
-rw-r--r--app/src/main/res/layout/view_main_fab.xml7
-rw-r--r--app/src/main/res/layout/view_main_tab_layout.xml10
-rw-r--r--app/src/main/res/layout/view_main_toolbar.xml8
-rw-r--r--app/src/main/res/layout/view_main_viewpager.xml7
-rw-r--r--app/src/main/res/layout/view_nav_header.xml121
-rw-r--r--app/src/main/res/values/dimens.xml3
-rw-r--r--app/src/main/res/values/strings.xml4
-rw-r--r--app/src/main/res/values/styles.xml92
21 files changed, 745 insertions, 297 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index ea0de778..b33f00e2 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -18,20 +18,12 @@ package com.pitchedapps.frost
import android.app.Activity
import android.app.Application
-import android.graphics.drawable.Drawable
-import android.net.Uri
import android.os.Bundle
-import android.widget.ImageView
import ca.allanwang.kau.logging.KL
import ca.allanwang.kau.utils.buildIsLollipopAndUp
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
-import com.bumptech.glide.request.RequestOptions
-import com.bumptech.glide.signature.ApplicationVersionSignature
-import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
-import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.pitchedapps.frost.db.FrostDatabase
-import com.pitchedapps.frost.glide.GlideApp
import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs
import com.pitchedapps.frost.services.setupNotificationChannels
import com.pitchedapps.frost.utils.BuildUtils
@@ -75,22 +67,6 @@ class FrostApp : Application() {
scheduleNotificationsFromPrefs()
- /**
- * Drawer profile loading logic
- * Reload the image on every version update
- */
- DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
- override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
- val c = imageView.context
- val request = GlideApp.with(c)
- val old = request.load(uri).apply(RequestOptions().placeholder(placeholder))
- request.load(uri).apply(
- RequestOptions()
- .signature(ApplicationVersionSignature.obtain(c))
- )
- .thumbnail(old).into(imageView)
- }
- })
if (BuildConfig.DEBUG) {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityPaused(activity: Activity) {}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
index 0ef70bcd..17b475da 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt
@@ -74,7 +74,6 @@ class AboutActivity : AboutActivityBase(null, {
"kau",
"kotterknife",
"materialdialogs",
- "materialdrawer",
"subsamplingscaleimageview"
)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
index 858f8590..62138b19 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt
@@ -18,28 +18,41 @@ package com.pitchedapps.frost.activities
import android.annotation.SuppressLint
import android.app.ActivityOptions
+import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.PointF
-import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.RippleDrawable
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
+import android.view.View
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.widget.FrameLayout
-import androidx.annotation.StringRes
-import androidx.coordinatorlayout.widget.CoordinatorLayout
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.appcompat.app.ActionBarDrawerToggle
+import androidx.appcompat.widget.Toolbar
+import androidx.core.view.updateLayoutParams
+import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentPagerAdapter
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.bindView
+import ca.allanwang.kau.ui.ProgressAnimator
+import ca.allanwang.kau.utils.adjustAlpha
+import ca.allanwang.kau.utils.colorToForeground
+import ca.allanwang.kau.utils.dimenPixelSize
+import ca.allanwang.kau.utils.drawable
import ca.allanwang.kau.utils.fadeScaleTransition
+import ca.allanwang.kau.utils.gone
+import ca.allanwang.kau.utils.invisible
import ca.allanwang.kau.utils.materialDialog
import ca.allanwang.kau.utils.restart
import ca.allanwang.kau.utils.setIcon
@@ -47,33 +60,31 @@ import ca.allanwang.kau.utils.setMenuIcons
import ca.allanwang.kau.utils.showIf
import ca.allanwang.kau.utils.string
import ca.allanwang.kau.utils.tint
+import ca.allanwang.kau.utils.toDrawable
import ca.allanwang.kau.utils.toast
+import ca.allanwang.kau.utils.visible
import ca.allanwang.kau.utils.withMinAlpha
-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.afollestad.materialdialogs.checkbox.checkBoxPrompt
+import com.bumptech.glide.Glide
+import com.bumptech.glide.request.target.CustomTarget
+import com.bumptech.glide.request.transition.Transition
import com.google.android.material.appbar.AppBarLayout
+import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.tabs.TabLayout
-import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
-import com.mikepenz.iconics.utils.colorInt
-import com.mikepenz.iconics.utils.paddingDp
-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.databinding.ActivityMainBinding
+import com.pitchedapps.frost.databinding.ActivityMainBottomTabsBinding
+import com.pitchedapps.frost.databinding.ActivityMainDrawerWrapperBinding
+import com.pitchedapps.frost.databinding.ViewNavHeaderBinding
import com.pitchedapps.frost.db.CookieDao
+import com.pitchedapps.frost.db.CookieEntity
import com.pitchedapps.frost.db.GenericDao
import com.pitchedapps.frost.db.currentCookie
import com.pitchedapps.frost.db.getTabs
@@ -85,6 +96,8 @@ import com.pitchedapps.frost.facebook.parsers.SearchParser
import com.pitchedapps.frost.facebook.profilePictureUrl
import com.pitchedapps.frost.fragments.BaseFragment
import com.pitchedapps.frost.fragments.WebFragment
+import com.pitchedapps.frost.glide.FrostGlide
+import com.pitchedapps.frost.glide.GlideApp
import com.pitchedapps.frost.services.scheduleNotificationsFromPrefs
import com.pitchedapps.frost.utils.ACTIVITY_SETTINGS
import com.pitchedapps.frost.utils.BiometricUtils
@@ -112,10 +125,6 @@ import com.pitchedapps.frost.views.BadgedIcon
import com.pitchedapps.frost.views.FrostVideoViewer
import com.pitchedapps.frost.views.FrostViewPager
import com.pitchedapps.frost.widgets.NotificationWidget
-import kotlinx.android.synthetic.main.activity_frame_wrapper.*
-import kotlinx.android.synthetic.main.view_main_fab.*
-import kotlinx.android.synthetic.main.view_main_toolbar.*
-import kotlinx.android.synthetic.main.view_main_viewpager.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
@@ -135,23 +144,24 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
* Note that tabs themselves are initialized through a coroutine during onCreate
*/
protected val adapter: SectionsPagerAdapter = SectionsPagerAdapter()
- override val frameWrapper: FrameLayout get() = frame_wrapper
- val viewPager: FrostViewPager get() = container
+ override val frameWrapper: FrameLayout get() = drawerWrapperBinding.mainContainer
+ lateinit var drawerWrapperBinding: ActivityMainDrawerWrapperBinding
+ lateinit var contentBinding: ActivityMainContentBinding
val cookieDao: CookieDao by inject()
val genericDao: GenericDao by inject()
- /*
- * Components with the same id in multiple layout files
- */
- 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)
+ interface ActivityMainContentBinding {
+ val root: View
+ val toolbar: Toolbar
+ val viewpager: FrostViewPager
+ val tabs: TabLayout
+ val appbar: AppBarLayout
+ val fab: FloatingActionButton
+ }
protected var lastPosition = -1
override var videoViewer: FrostVideoViewer? = null
- private lateinit var drawer: Drawer
- private lateinit var drawerHeader: AccountHeader
private var lastAccessTime = -1L
override var searchView: SearchView? = null
@@ -161,16 +171,45 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
final override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val start = System.currentTimeMillis()
- setFrameContentView(Prefs.mainActivityLayout.layoutRes)
- setFrostColors {
- toolbar(toolbar)
- themeWindow = false
- header(appBar)
- background(viewPager)
+ drawerWrapperBinding = ActivityMainDrawerWrapperBinding.inflate(layoutInflater)
+ setContentView(drawerWrapperBinding.root)
+ contentBinding = when (Prefs.mainActivityLayout) {
+ MainActivityLayout.TOP_BAR -> {
+ val binding = ActivityMainBinding.inflate(layoutInflater)
+ object : ActivityMainContentBinding {
+ override val root: View = binding.root
+ override val toolbar: Toolbar = binding.toolbar
+ override val viewpager: FrostViewPager = binding.viewpager
+ override val tabs: TabLayout = binding.tabs
+ override val appbar: AppBarLayout = binding.appbar
+ override val fab: FloatingActionButton = binding.fab
+ }
+ }
+ MainActivityLayout.BOTTOM_BAR -> {
+ val binding = ActivityMainBottomTabsBinding.inflate(layoutInflater)
+ object : ActivityMainContentBinding {
+ override val root: View = binding.root
+ override val toolbar: Toolbar = binding.toolbar
+ override val viewpager: FrostViewPager = binding.viewpager
+ override val tabs: TabLayout = binding.tabs
+ override val appbar: AppBarLayout = binding.appbar
+ override val fab: FloatingActionButton = binding.fab
+ }
+ }
+ }
+ drawerWrapperBinding.mainContainer.addView(contentBinding.root)
+ with(contentBinding) {
+ setFrostColors {
+ toolbar(toolbar)
+ themeWindow = false
+ header(appbar)
+ background(viewpager)
+ }
+ setSupportActionBar(toolbar)
+ viewpager.adapter = adapter
+ tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor())
+
}
- setSupportActionBar(toolbar)
- viewPager.adapter = adapter
- tabs.setBackgroundColor(Prefs.mainActivityLayout.backgroundColor())
onNestedCreate(savedInstanceState)
L.i { "Main finished loading UI in ${System.currentTimeMillis() - start} ms" }
launch {
@@ -192,9 +231,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
)
}
}
- setupDrawer(savedInstanceState)
+// setupDrawer(savedInstanceState)
L.i { "Main started in ${System.currentTimeMillis() - start} ms" }
- initFab()
+ drawerWrapperBinding.initDrawer()
+ contentBinding.initFab()
lastAccessTime = System.currentTimeMillis()
}
@@ -206,182 +246,378 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
private var hasFab = false
private var shouldShow = false
- private fun initFab() {
+ private class FrostMenuBuilder(private val context: Context, private val menu: Menu) {
+ private var order: Int = 0
+ private var groupId: Int = 13
+ private val items: MutableList<Menu> = mutableListOf()
+
+ fun primaryFrostItem(fbItem: FbItem) {
+ val item = menu.add(groupId, fbItem.ordinal, order++, context.string(fbItem.titleId))
+ item.icon = fbItem.icon.toDrawable(context, 18)
+ }
+
+ fun divider() {
+ groupId++
+ }
+
+ fun secondaryFrostItem(fbItem: FbItem) {
+ menu.add(groupId, fbItem.ordinal, order++, context.string(fbItem.titleId))
+ }
+ }
+
+ private fun createNavDrawable(): RippleDrawable {
+ val drawable = drawable(R.drawable.nav_item_background) as RippleDrawable
+ drawable.setColor(
+ ColorStateList(
+ arrayOf(intArrayOf()),
+ intArrayOf(Prefs.accentColor.adjustAlpha(0.16f))
+ )
+ )
+ return drawable
+ }
+
+ private fun ActivityMainDrawerWrapperBinding.initDrawer() {
+
+ val toggle = ActionBarDrawerToggle(
+ this@BaseMainActivity, drawer, contentBinding.toolbar,
+ R.string.open,
+ R.string.close
+ )
+ toggle.isDrawerSlideAnimationEnabled = false
+ drawer.addDrawerListener(toggle)
+ toggle.syncState()
+
+ val foregroundColor = ColorStateList.valueOf(Prefs.textColor)
+
+ with(navigation) {
+ FrostMenuBuilder(this@BaseMainActivity, menu).apply {
+ 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)
+ primaryFrostItem(FbItem.MARKETPLACE)
+ }
+ setNavigationItemSelectedListener {
+ val item = FbItem.values[it.itemId]
+ frostEvent("Drawer Tab", "name" to item.name)
+ drawer.closeDrawer(navigation)
+ launchWebOverlay(item.url)
+ false
+ }
+ val navBg = Prefs.bgColor.withMinAlpha(200)
+ setBackgroundColor(navBg)
+ itemBackground = createNavDrawable()
+ itemTextColor = foregroundColor
+ itemIconTintList = foregroundColor
+
+ val header = NavHeader()
+ addHeaderView(header.root)
+ }
+ }
+
+ private fun ActivityMainContentBinding.initFab() {
hasFab = false
shouldShow = false
fab.backgroundTintList = ColorStateList.valueOf(Prefs.headerColor.withMinAlpha(200))
fab.hide()
- appBar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
+ appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (!hasFab) return@OnOffsetChangedListener
val percent = abs(verticalOffset.toFloat() / appBarLayout.totalScrollRange)
val shouldShow = percent < 0.2
- if (this.shouldShow != shouldShow) {
- this.shouldShow = shouldShow
+ if (this@BaseMainActivity.shouldShow != shouldShow) {
+ this@BaseMainActivity.shouldShow = shouldShow
fab.showIf(shouldShow)
}
})
}
override fun showFab(iicon: IIcon, clickEvent: () -> Unit) {
- hasFab = true
- fab.setOnClickListener { clickEvent() }
- if (shouldShow) {
- if (fab.isShown) {
- fab.fadeScaleTransition {
- setIcon(iicon, Prefs.iconColor)
+ with(contentBinding) {
+ hasFab = true
+ fab.setOnClickListener { clickEvent() }
+ if (shouldShow) {
+ if (fab.isShown) {
+ fab.fadeScaleTransition {
+ setIcon(iicon, Prefs.iconColor)
+ }
+ return
}
- return
}
+ fab.setIcon(iicon, Prefs.iconColor)
+ fab.showIf(shouldShow)
}
- fab.setIcon(iicon, Prefs.iconColor)
- fab.showIf(shouldShow)
}
override fun hideFab() {
- hasFab = false
- fab.setOnClickListener(null)
- fab.hide()
+ with(contentBinding) {
+ hasFab = false
+ fab.setOnClickListener(null)
+ fab.hide()
+ }
}
fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) {
- (0 until tabs.tabCount).asSequence().forEach { i ->
- action(i, tabs.getTabAt(i)!!.customView as BadgedIcon)
+ with(contentBinding) {
+ (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 {
- textColor = Prefs.iconColor.toLong()
- backgroundDrawable = ColorDrawable(navHeader)
- selectionSecondLineShown = false
- cookies().forEach { (id, name) ->
- profile(name = name ?: "") {
- iconUrl = profilePictureUrl(id)
- textColor = Prefs.textColor.toLong()
- selectedTextColor = Prefs.textColor.toLong()
- selectedColor = 0x00000001.toLong()
- identifier = id
+ private inner class NavHeader {
+
+ private var orderedAccounts: List<CookieEntity> = cookies()
+ private var pendingUpdate: Boolean = false
+ private val binding = ViewNavHeaderBinding.inflate(layoutInflater)
+ val root: View get() = binding.root
+
+ init {
+ setPrimary(Prefs.userId)
+ binding.updateAccounts()
+ with(drawerWrapperBinding) {
+ drawer.addDrawerListener(object : DrawerLayout.SimpleDrawerListener() {
+ override fun onDrawerClosed(drawerView: View) {
+ if (drawer !== navigation) return
+ if (!pendingUpdate) return
+ pendingUpdate = false
+ binding.updateAccounts()
}
+ })
+ }
+ with(binding) {
+ optionsContainer.setBackgroundColor(
+ Prefs.bgColor.withMinAlpha(200).colorToForeground(
+ 0.1f
+ )
+ )
+ var showOptions = false
+ val animator: ProgressAnimator = ProgressAnimator.ofFloat { }
+ background.setOnClickListener {
+ animator.reset()
+ if (showOptions) {
+ animator.apply {
+ withAnimator(optionsContainer.height.toFloat(), 0f) {
+ optionsContainer.updateLayoutParams {
+ height = it.toInt()
+ }
+ }
+ withAnimator(arrow.rotation, 0f) {
+ arrow.rotation = it
+ }
+ withEndAction {
+ optionsContainer.gone()
+ }
+ }
+ } else {
+ animator.apply {
+ optionsContainer.measure(
+ View.MeasureSpec.UNSPECIFIED,
+ View.MeasureSpec.UNSPECIFIED
+ )
+ withAnimator(
+ optionsContainer.height.toFloat(),
+ optionsContainer.measuredHeight.toFloat()
+ ) {
+ optionsContainer.updateLayoutParams {
+ height = it.toInt()
+ }
+ }
+ withAnimator(arrow.rotation, 180f) {
+ arrow.rotation = it
+ }
+ withStartAction {
+ optionsContainer.visible()
+ }
+ }
+ }
+ showOptions = !showOptions
+ animator.start()
}
- 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)
- .colorInt(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
+
+ val textColor = Prefs.textColor
+
+ fun TextView.setOptionsIcon(iicon: IIcon) {
+ setCompoundDrawablesRelativeWithIntrinsicBounds(
+ iicon.toDrawable(this@BaseMainActivity, color = textColor, sizeDp = 20),
+ null,
+ null,
+ null
+ )
+ setTextColor(textColor)
+ background = createNavDrawable()
}
- onProfileChanged { _, profile, current ->
- if (current) launchWebOverlay(FbItem.PROFILE.url)
- else when (profile.identifier) {
- -2L -> {
- // TODO no backpressure support
- this@BaseMainActivity.launch {
- val currentCookie = cookieDao.currentCookie()
- if (currentCookie == null) {
- toast(R.string.account_not_found)
- FbCookie.reset()
- launchLogin(cookies(), true)
- } else {
- materialDialog {
- title(R.string.kau_logout)
- message(
- text =
- String.format(
- string(R.string.kau_logout_confirm_as_x),
- currentCookie.name ?: Prefs.userId.toString()
- )
+
+ with(optionsLogout) {
+ setOptionsIcon(GoogleMaterial.Icon.gmd_exit_to_app)
+ setOnClickListener {
+ launch {
+ val currentCookie = cookieDao.currentCookie()
+ if (currentCookie == null) {
+ toast(R.string.account_not_found)
+ FbCookie.reset()
+ launchLogin(cookies(), true)
+ } else {
+ materialDialog {
+ title(R.string.kau_logout)
+ message(
+ text =
+ String.format(
+ string(R.string.kau_logout_confirm_as_x),
+ currentCookie.name ?: Prefs.userId.toString()
)
- positiveButton(R.string.kau_yes) {
- this@BaseMainActivity.launch {
- FbCookie.logout(this@BaseMainActivity)
- }
+ )
+ positiveButton(R.string.kau_yes) {
+ this@BaseMainActivity.launch {
+ FbCookie.logout(this@BaseMainActivity)
}
- negativeButton(R.string.kau_no)
}
+ negativeButton(R.string.kau_no)
}
}
}
- -3L -> launchNewTask<LoginActivity>(clearStack = false)
- -4L -> launchNewTask<SelectorActivity>(cookies(), false)
- else -> {
- this@BaseMainActivity.launch {
- FbCookie.switchUser(profile.identifier)
- tabsForEachView { _, view -> view.badgeText = null }
- refreshAll()
- }
- }
}
- false
}
+ with(optionsAddAccount) {
+ setOptionsIcon(GoogleMaterial.Icon.gmd_add)
+ setOnClickListener {
+ launchNewTask<LoginActivity>(clearStack = false)
+ }
+ }
+ with(optionsManageAccount) {
+ setOptionsIcon(GoogleMaterial.Icon.gmd_settings)
+ setOnClickListener {
+ launchNewTask<SelectorActivity>(cookies(), false)
+ }
+ }
+ arrow.setImageDrawable(
+ GoogleMaterial.Icon.gmd_arrow_drop_down.toDrawable(
+ this@BaseMainActivity,
+ color = Prefs.textColor
+ )
+ )
}
- 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)
- primaryFrostItem(FbItem.MARKETPLACE)
}
- }
- 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 { _ ->
- frostEvent("Drawer Tab", "name" to item.name)
- launchWebOverlay(item.url)
- false
+ private fun setPrimary(id: Long) {
+ val (primaries, others) = orderedAccounts.partition { it.id == id }
+ if (primaries.size != 1) {
+ L._e(null) { "Updating account primaries, could not find specified id" }
+ }
+ orderedAccounts = primaries + others
+ }
+
+ /**
+ * Syncs UI to match [orderedAccounts].
+ *
+ * We keep this separate as we usually only want to update when the drawer is hidden.
+ */
+ private fun ViewNavHeaderBinding.updateAccounts() {
+ avatarPrimary.setAccount(orderedAccounts.getOrNull(0), true)
+ avatarSecondary.setAccount(orderedAccounts.getOrNull(1), false)
+ avatarTertiary.setAccount(orderedAccounts.getOrNull(2), false)
+ optionsAccountsContainer.removeAllViews()
+ name.text = orderedAccounts.getOrNull(0)?.name
+ name.setTextColor(Prefs.textColor)
+ val glide = Glide.with(root)
+ val accountSize = dimenPixelSize(R.dimen.drawer_account_avatar_size)
+ val textColor = Prefs.textColor
+ val navBackground = createNavDrawable()
+ orderedAccounts.forEach { cookie ->
+ val tv =
+ TextView(
+ this@BaseMainActivity,
+ null,
+ 0,
+ R.style.Main_DrawerAccountUserOptions
+ )
+ glide.load(profilePictureUrl(cookie.id)).transform(FrostGlide.circleCrop)
+ .into(object : CustomTarget<Drawable>(accountSize, accountSize) {
+ override fun onLoadCleared(placeholder: Drawable?) {
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ placeholder,
+ null,
+ null,
+ null
+ )
+ }
+
+ override fun onResourceReady(
+ resource: Drawable,
+ transition: Transition<in Drawable>?
+ ) {
+ tv.setCompoundDrawablesRelativeWithIntrinsicBounds(
+ resource,
+ null,
+ null,
+ null
+ )
+ }
+ })
+ tv.text = cookie.name
+ tv.setTextColor(textColor)
+ tv.background = navBackground
+ tv.setOnClickListener {
+ switchAccount(cookie.id)
+ }
+ optionsAccountsContainer.addView(tv)
+ }
+ }
+
+ private fun closeDrawer() {
+ with(drawerWrapperBinding) {
+ drawer.closeDrawer(navigation)
+ }
}
- }
- 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 }
+ private fun ImageView.setAccount(
+ cookie: CookieEntity?,
+ primary: Boolean
+ ) {
+ if (cookie == null) {
+ invisible()
+ setOnClickListener(null)
+ } else {
+ visible()
+ GlideApp.with(this)
+ .load(profilePictureUrl(cookie.id))
+ .transform(FrostGlide.circleCrop)
+ .into(this)
+ setOnClickListener {
+ if (primary) {
+ launchWebOverlay(FbItem.PROFILE.url)
+ } else {
+ switchAccount(cookie.id)
+ }
+ closeDrawer()
+ }
+ }
}
+ private fun switchAccount(id: Long) {
+ if (Prefs.userId == id) return
+ setPrimary(id)
+ pendingUpdate = true
+ closeDrawer()
+ launch {
+ FbCookie.switchUser(id)
+ tabsForEachView { _, view -> view.badgeText = null }
+ refreshAll()
+ }
+ }
+ }
+
private fun refreshAll() {
L.d { "Refresh all" }
fragmentChannel.offer(REQUEST_REFRESH)
@@ -389,7 +625,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
- toolbar.tint(Prefs.iconColor)
+ contentBinding.toolbar.tint(Prefs.iconColor)
setMenuIcons(
menu, Prefs.iconColor,
R.id.action_settings to GoogleMaterial.Icon.gmd_settings,
@@ -504,8 +740,6 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
}
- private val STATE_FORCE_FALLBACK = "frost_state_force_fallback"
-
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
adapter.saveInstanceState(outState)
@@ -545,13 +779,17 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
override fun collapseAppBar() {
- appBar.post { appBar.setExpanded(false) }
+ with(contentBinding) {
+ appbar.post { appbar.setExpanded(false) }
+ }
}
override fun backConsumer(): Boolean {
- if (drawer.isDrawerOpen) {
- drawer.closeDrawer()
- return true
+ with(drawerWrapperBinding) {
+ if (drawer.isDrawerOpen(navigation)) {
+ drawer.closeDrawer(navigation)
+ return true
+ }
}
if (currentFragment.onBackPressed()) return true
if (Prefs.exitConfirmation) {
@@ -570,7 +808,7 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
inline val currentFragment
- get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as BaseFragment
+ get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${contentBinding.viewpager.currentItem}") as BaseFragment
override fun reloadFragment(fragment: BaseFragment) {
runOnUiThread { adapter.reloadFragment(fragment) }
@@ -589,25 +827,27 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
this.pages.clear()
this.pages.addAll(pages)
notifyDataSetChanged()
- tabs.removeAllTabs()
- this.pages.forEachIndexed { index, fbItem ->
- tabs.addTab(
- tabs.newTab()
- .setCustomView(BadgedIcon(this@BaseMainActivity).apply {
- iicon = fbItem.icon
- }.also {
- it.setAllAlpha(if (index == 0) SELECTED_TAB_ALPHA else UNSELECTED_TAB_ALPHA)
- })
- )
- }
- lastPosition = 0
- viewPager.setCurrentItem(0, false)
- viewPager.offscreenPageLimit = pages.size
- viewPager.post {
- if (!fragmentChannel.isClosedForSend) {
- fragmentChannel.offer(0)
+ with(contentBinding) {
+ tabs.removeAllTabs()
+ this@SectionsPagerAdapter.pages.forEachIndexed { index, fbItem ->
+ tabs.addTab(
+ tabs.newTab()
+ .setCustomView(BadgedIcon(this@BaseMainActivity).apply {
+ iicon = fbItem.icon
+ }.also {
+ it.setAllAlpha(if (index == 0) SELECTED_TAB_ALPHA else UNSELECTED_TAB_ALPHA)
+ })
+ )
}
- } // trigger hook so title is set
+ lastPosition = 0
+ viewpager.setCurrentItem(0, false)
+ viewpager.offscreenPageLimit = pages.size
+ viewpager.post {
+ if (!fragmentChannel.isClosedForSend) {
+ fragmentChannel.offer(0)
+ }
+ } // trigger hook so title is set
+ }
}
fun saveInstanceState(outState: Bundle) {
@@ -652,14 +892,19 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
}
}
+ private val lowerVideoPaddingPointF = PointF()
+
override val lowerVideoPadding: PointF
- get() =
+ get() {
if (Prefs.mainActivityLayout == MainActivityLayout.BOTTOM_BAR)
- PointF(0f, toolbar.height.toFloat())
+ lowerVideoPaddingPointF.set(0f, contentBinding.toolbar.height.toFloat())
else
- PointF(0f, 0f)
+ lowerVideoPaddingPointF.set(0f, 0f)
+ return lowerVideoPaddingPointF
+ }
companion object {
+ private const val STATE_FORCE_FALLBACK = "frost_state_force_fallback"
const val SELECTED_TAB_ALPHA = 255f
const val UNSELECTED_TAB_ALPHA = 128f
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
index e0dc409b..c8177604 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt
@@ -34,7 +34,6 @@ import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.setFrostColors
import kotlinx.android.synthetic.main.activity_debug.*
-import kotlinx.android.synthetic.main.view_main_fab.*
import kotlinx.coroutines.CoroutineExceptionHandler
import java.io.File
import kotlin.coroutines.resume
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 fc9eca37..e0053402 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
@@ -37,12 +37,14 @@ class MainActivity : BaseMainActivity() {
override val headerBadgeChannel = BroadcastChannel<String>(Channel.CONFLATED)
override fun onNestedCreate(savedInstanceState: Bundle?) {
- setupTabs()
- setupViewPager()
+ with(contentBinding) {
+ setupTabs()
+ setupViewPager()
+ }
}
- private fun setupViewPager() {
- viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
+ private fun ActivityMainContentBinding.setupViewPager() {
+ viewpager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
if (lastPosition == position) {
@@ -75,9 +77,9 @@ class MainActivity : BaseMainActivity() {
})
}
- private fun setupTabs() {
- viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
- tabs.addOnTabSelectedListener(object : TabLayout.ViewPagerOnTabSelectedListener(viewPager) {
+ private fun ActivityMainContentBinding.setupTabs() {
+ viewpager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs))
+ tabs.addOnTabSelectedListener(object : TabLayout.ViewPagerOnTabSelectedListener(viewpager) {
override fun onTabReselected(tab: TabLayout.Tab) {
super.onTabReselected(tab)
currentFragment.onTabClick()
@@ -88,7 +90,7 @@ class MainActivity : BaseMainActivity() {
(tab.customView as BadgedIcon).badgeText = null
}
})
- headerBadgeChannel.subscribeDuringJob(this, Dispatchers.IO) { html ->
+ headerBadgeChannel.subscribeDuringJob(this@MainActivity, Dispatchers.IO) { html ->
try {
val doc = Jsoup.parse(html)
if (doc.select("[data-sigil=count]").isEmpty())
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
index a3a4c1a4..92aa93ab 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt
@@ -24,23 +24,20 @@ import com.pitchedapps.frost.utils.Prefs
*/
enum class MainActivityLayout(
val titleRes: Int,
- val layoutRes: Int,
val backgroundColor: () -> Int,
val iconColor: () -> Int
) {
TOP_BAR(R.string.top_bar,
- R.layout.activity_main,
{ Prefs.headerColor },
{ Prefs.iconColor }),
BOTTOM_BAR(R.string.bottom_bar,
- R.layout.activity_main_bottom_tabs,
{ Prefs.bgColor },
{ Prefs.textColor });
companion object {
val values = values() // save one instance
- operator fun invoke(index: Int) = values[index]
+ operator fun invoke(index: Int) = values.getOrElse(index) { TOP_BAR }
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
index 9089d891..becc9f02 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
@@ -47,7 +47,10 @@ fun Context.showWebContextMenu(wc: WebContext) {
}
onDismiss {
// showing the dialog interrupts the touch down event, so we must ensure that the viewpager's swipe is enabled
- (this@showWebContextMenu as? MainActivity)?.viewPager?.enableSwipe = true
+ (this@showWebContextMenu as? MainActivity)
+ ?.contentBinding
+ ?.viewpager
+ ?.enableSwipe = true
}
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
index 0988e331..c8e551a3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -88,7 +88,7 @@ class FrostJSI(val web: FrostWebView) {
*/
@JavascriptInterface
fun longClick(start: Boolean) {
- activity?.viewPager?.enableSwipe = !start
+ activity?.contentBinding?.viewpager?.enableSwipe = !start
if (web.frostWebClient.urlSupportsRefresh) {
web.parent.swipeEnabled = !start
}
@@ -151,7 +151,7 @@ class FrostJSI(val web: FrostWebView) {
@JavascriptInterface
fun allowHorizontalScrolling(enable: Boolean) {
- activity?.viewPager?.enableSwipe = enable
+ activity?.contentBinding?.viewpager?.enableSwipe = enable
(context as? WebOverlayActivityBase)?.swipeBack?.disallowIntercept = !enable
}
}
diff --git a/app/src/main/res/drawable/nav_item_background.xml b/app/src/main/res/drawable/nav_item_background.xml
new file mode 100644
index 00000000..415dd9f2
--- /dev/null
+++ b/app/src/main/res/drawable/nav_item_background.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="#f0f">
+ <item
+ android:id="@android:id/mask"
+ android:right="16dp">
+ <shape android:shape="rectangle">
+ <corners
+ android:bottomRightRadius="50dp"
+ android:topRightRadius="50dp" />
+ <solid android:color="#fff" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_debug.xml b/app/src/main/res/layout/activity_debug.xml
index c3818749..d2f9a397 100644
--- a/app/src/main/res/layout/activity_debug.xml
+++ b/app/src/main/res/layout/activity_debug.xml
@@ -31,6 +31,8 @@
</com.pitchedapps.frost.views.SwipeRefreshLayout>
- <include layout="@layout/view_main_fab" />
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/fab"
+ style="@style/Main.Fab" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 8fa9283f..f46175d1 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -13,14 +13,22 @@
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
- <include layout="@layout/view_main_toolbar" />
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ style="@style/Main.Toolbar" />
- <include layout="@layout/view_main_tab_layout" />
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tabs"
+ style="@style/Main.TabLayout" />
</com.google.android.material.appbar.AppBarLayout>
- <include layout="@layout/view_main_viewpager" />
+ <com.pitchedapps.frost.views.FrostViewPager
+ android:id="@+id/viewpager"
+ style="@style/Main.ViewPager" />
- <include layout="@layout/view_main_fab" />
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/fab"
+ style="@style/Main.Fab" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/app/src/main/res/layout/activity_main_bottom_tabs.xml b/app/src/main/res/layout/activity_main_bottom_tabs.xml
index 2c2527cd..419bbc33 100644
--- a/app/src/main/res/layout/activity_main_bottom_tabs.xml
+++ b/app/src/main/res/layout/activity_main_bottom_tabs.xml
@@ -3,15 +3,16 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:orientation="vertical">
+ android:fitsSystemWindows="true"
+ android:orientation="vertical"
+ tools:context=".activities.MainActivity">
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:fitsSystemWindows="true"
- tools:context=".activities.MainActivity">
+ android:fitsSystemWindows="true">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
@@ -19,17 +20,25 @@
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
- <include layout="@layout/view_main_toolbar" />
+ <androidx.appcompat.widget.Toolbar
+ android:id="@+id/toolbar"
+ style="@style/Main.Toolbar" />
</com.google.android.material.appbar.AppBarLayout>
- <include layout="@layout/view_main_viewpager" />
+ <com.pitchedapps.frost.views.FrostViewPager
+ android:id="@+id/viewpager"
+ style="@style/Main.ViewPager" />
- <include layout="@layout/view_main_fab" />
+ <com.google.android.material.floatingactionbutton.FloatingActionButton
+ android:id="@+id/fab"
+ style="@style/Main.Fab" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
- <include layout="@layout/view_main_tab_layout" />
+ <com.google.android.material.tabs.TabLayout
+ android:id="@+id/tabs"
+ style="@style/Main.TabLayout" />
</LinearLayout>
diff --git a/app/src/main/res/layout/activity_main_drawer_wrapper.xml b/app/src/main/res/layout/activity_main_drawer_wrapper.xml
new file mode 100644
index 00000000..d5efcf0d
--- /dev/null
+++ b/app/src/main/res/layout/activity_main_drawer_wrapper.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/drawer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
+ tools:openDrawer="end">
+
+ <FrameLayout
+ android:id="@+id/main_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true" />
+
+ <com.google.android.material.navigation.NavigationView
+ android:id="@+id/navigation"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:theme="@style/ThemeOverlay.Frost.NavigationView" />
+</androidx.drawerlayout.widget.DrawerLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/view_main_fab.xml b/app/src/main/res/layout/view_main_fab.xml
deleted file mode 100644
index e9fe9981..00000000
--- a/app/src/main/res/layout/view_main_fab.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.google.android.material.floatingactionbutton.FloatingActionButton xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/fab"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end|bottom"
- android:layout_margin="@dimen/kau_fab_margin" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/view_main_tab_layout.xml b/app/src/main/res/layout/view_main_tab_layout.xml
deleted file mode 100644
index 1218b4f7..00000000
--- a/app/src/main/res/layout/view_main_tab_layout.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.google.android.material.tabs.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/tabs"
- style="@style/Widget.Design.TabLayout"
- android:layout_width="match_parent"
- android:layout_height="@dimen/tab_bar_height"
- app:tabGravity="fill"
- app:tabIndicatorHeight="0dp"
- app:tabMode="fixed" />
diff --git a/app/src/main/res/layout/view_main_toolbar.xml b/app/src/main/res/layout/view_main_toolbar.xml
deleted file mode 100644
index 054eaac3..00000000
--- a/app/src/main/res/layout/view_main_toolbar.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/toolbar"
- android:layout_width="match_parent"
- android:layout_height="?attr/actionBarSize"
- app:layout_scrollFlags="scroll|enterAlways|snap"
- app:popupTheme="@style/AppTheme.PopupOverlay" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/view_main_viewpager.xml b/app/src/main/res/layout/view_main_viewpager.xml
deleted file mode 100644
index 0c3f314c..00000000
--- a/app/src/main/res/layout/view_main_viewpager.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<com.pitchedapps.frost.views.FrostViewPager xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:id="@+id/container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- app:layout_behavior="@string/appbar_scrolling_view_behavior" /> \ No newline at end of file
diff --git a/app/src/main/res/layout/view_nav_header.xml b/app/src/main/res/layout/view_nav_header.xml
new file mode 100644
index 00000000..ff70e48c
--- /dev/null
+++ b/app/src/main/res/layout/view_nav_header.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <androidx.constraintlayout.widget.ConstraintLayout
+ android:layout_width="match_parent"
+ android:layout_height="160dp"
+ android:elevation="2dp">
+
+ <ImageView
+ android:id="@+id/background"
+ android:layout_width="0dp"
+ android:layout_height="160dp"
+ android:scaleType="centerCrop"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ tools:src="@tools:sample/backgrounds/scenic" />
+
+ <androidx.constraintlayout.widget.Guideline
+ android:id="@+id/status_bar_guide"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ app:layout_constraintGuide_begin="24dp" />
+
+ <ImageView
+ android:id="@+id/avatar_primary"
+ style="@style/Main.DrawerPrimaryAvatar"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/status_bar_guide"
+ tools:src="@tools:sample/avatars" />
+
+ <ImageView
+ android:id="@+id/avatar_secondary"
+ style="@style/Main.DrawerSecondaryAvatar"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/status_bar_guide"
+ tools:src="@tools:sample/avatars" />
+
+ <ImageView
+ android:id="@+id/avatar_tertiary"
+ style="@style/Main.DrawerSecondaryAvatar"
+ app:layout_constraintEnd_toStartOf="@id/avatar_secondary"
+ app:layout_constraintTop_toBottomOf="@id/status_bar_guide"
+ tools:src="@tools:sample/avatars" />
+
+ <TextView
+ android:id="@+id/name"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/drawer_nav_horizontal_margins"
+ android:layout_marginTop="@dimen/kau_activity_vertical_margin"
+ android:layout_marginEnd="@dimen/drawer_nav_horizontal_margins"
+ android:layout_marginBottom="@dimen/kau_activity_vertical_margin"
+ android:clickable="false"
+ android:lines="1"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/arrow"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/avatar_primary"
+ app:layout_constraintVertical_bias="1"
+ tools:text="@tools:sample/full_names" />
+
+ <ImageView
+ android:id="@+id/arrow"
+ android:layout_width="12dp"
+ android:layout_height="12dp"
+ android:layout_marginStart="@dimen/drawer_nav_horizontal_margins"
+ android:layout_marginEnd="@dimen/drawer_nav_horizontal_margins"
+ app:layout_constraintBottom_toBottomOf="@id/name"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toTopOf="@id/name" />
+
+ </androidx.constraintlayout.widget.ConstraintLayout>
+
+ <LinearLayout
+ android:id="@+id/options_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:visibility="gone"
+ tools:visibility="visible">
+
+ <LinearLayout
+ android:id="@+id/options_accounts_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical" />
+
+ <TextView
+ android:id="@+id/options_logout"
+ style="@style/Main.DrawerAccountOptions"
+ android:text="@string/kau_logout"
+ tools:drawableStart="@drawable/abc_vector_test"
+ tools:ignore="PrivateResource" />
+
+ <TextView
+ android:id="@+id/options_add_account"
+ style="@style/Main.DrawerAccountOptions"
+ android:text="@string/kau_add_account"
+ tools:drawableStart="@drawable/abc_vector_test"
+ tools:ignore="PrivateResource" />
+
+ <TextView
+ android:id="@+id/options_manage_account"
+ style="@style/Main.DrawerAccountOptions"
+ android:text="@string/kau_manage_account"
+ tools:drawableStart="@drawable/abc_vector_test"
+ tools:ignore="PrivateResource" />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 1f66683d..b2df756d 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -13,4 +13,7 @@
<dimen name="toolbar_icon_size">24dp</dimen>
<dimen name="dialog_corner_radius">8dp</dimen>
+
+ <dimen name="drawer_account_avatar_size">32dp</dimen>
+ <dimen name="drawer_nav_horizontal_margins">24dp</dimen>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index dda6c789..96957c4c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -40,12 +40,14 @@
<string name="show_all_results">Show All Results</string>
-
<string name="frost_description">Frost is a fully themable,
fully functional alternative to the official Facebook app, made from scratch and proudly open sourced.</string>
<string name="faq_title">Frost FAQ</string>
+ <string name="open">Open</string>
+ <string name="close">Close</string>
+
<string name="html_extraction_error">An error occurred in the html extraction.</string>
<string name="html_extraction_cancelled">The request has been cancelled.</string>
<string name="html_extraction_timeout">The request has timed out.</string>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 90978724..f17d005c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,6 +1,6 @@
<resources>
- <style name="FrostThemeBase" parent="MaterialDrawerTheme.ActionBar">
+ <style name="FrostTheme" parent="Theme.MaterialComponents.NoActionBar">
<item name="colorPrimary">@color/facebook_blue</item>
<item name="colorPrimaryDark">@color/facebook_blue_dark</item>
<item name="colorAccent">@android:color/white</item>
@@ -11,12 +11,7 @@
<item name="md_corner_radius">@dimen/dialog_corner_radius</item>
</style>
- <style name="FrostTheme" parent="@style/FrostThemeBase">
- <item name="windowActionBar">false</item>
- <item name="windowNoTitle">true</item>
- </style>
-
- <style name="FrostTheme.Light" parent="MaterialDrawerTheme.Light.DarkToolbar">
+ <style name="FrostTheme.Light" parent="Theme.MaterialComponents.Light.NoActionBar">
<item name="colorPrimary">@color/facebook_blue</item>
<item name="colorPrimaryDark">@color/facebook_blue_dark</item>
<item name="colorAccent">@android:color/black</item>
@@ -103,4 +98,87 @@
<item name="android:padding">@dimen/kau_padding_large</item>
</style>
+ <!-- Main Activity Styles -->
+
+ <style name="Main.Toolbar" parent="">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">?actionBarSize</item>
+ <item name="layout_scrollFlags">scroll|enterAlways|snap</item>
+ <item name="popupTheme">@style/AppTheme.PopupOverlay</item>
+ </style>
+
+ <style name="Main.ViewPager" parent="">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">match_parent</item>
+ <item name="layout_behavior">@string/appbar_scrolling_view_behavior</item>
+ </style>
+
+ <style name="Main.Fab" parent="Widget.Design.NavigationView">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:layout_gravity">end|bottom</item>
+ <item name="android:layout_margin">16dp</item>
+ </style>
+
+ <style name="Main.TabLayout" parent="Widget.Design.TabLayout">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">@dimen/tab_bar_height</item>
+ <item name="tabGravity">fill</item>
+ <item name="tabIndicatorHeight">0dp</item>
+ <item name="tabMode">fixed</item>
+ </style>
+
+ <style name="ThemeOverlay.Frost.NavigationView" parent="">
+ <item name="android:colorControlHighlight">@android:color/transparent</item>
+ </style>
+
+ <!-- <style name="ShapeAppearanceOverlay.Item" parent="">-->
+ <!-- <item name="cornerFamily">rounded</item>-->
+ <!-- <item name="cornerSizeTopRight">10dp</item>-->
+ <!-- <item name="cornerSizeBottomRight">10dp</item>-->
+ <!-- <item name="cornerSizeBottomLeft">0dp</item>-->
+ <!-- <item name="cornerSizeTopLeft">0dp</item>-->
+ <!-- </style>-->
+
+ <style name="Main.DrawerMargins" parent="">
+ <item name="android:layout_marginStart">@dimen/drawer_nav_horizontal_margins</item>
+ <item name="android:layout_marginEnd">@dimen/drawer_nav_horizontal_margins</item>
+ <item name="android:layout_marginTop">@dimen/kau_activity_vertical_margin</item>
+ <item name="android:layout_marginBottom">@dimen/kau_activity_vertical_margin</item>
+ </style>
+
+ <style name="Main.DrawerPrimaryAvatar" parent="Main.DrawerMargins">
+ <item name="android:layout_width">56dp</item>
+ <item name="android:layout_height">56dp</item>
+ </style>
+
+ <style name="Main.DrawerSecondaryAvatar" parent="Main.DrawerMargins">
+ <item name="android:layout_width">40dp</item>
+ <item name="android:layout_height">40dp</item>
+ </style>
+
+ <!-- Expected icon size is 20dp to match NavigationView -->
+ <style name="Main.DrawerAccountOptions" parent="">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:drawablePadding">16dp</item>
+ <item name="android:paddingStart">@dimen/drawer_nav_horizontal_margins</item>
+ <item name="android:paddingEnd">@dimen/drawer_nav_horizontal_margins</item>
+ <item name="android:paddingTop">16dp</item>
+ <item name="android:paddingBottom">16dp</item>
+ <item name="android:gravity">center_vertical</item>
+ </style>
+
+ <!-- Avatar size is 32dp (R.dimen.drawer_account_avatar_size) -->
+ <style name="Main.DrawerAccountUserOptions" parent="">
+ <item name="android:layout_width">match_parent</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:paddingTop">10dp</item>
+ <item name="android:paddingBottom">10dp</item>
+ <item name="android:drawablePadding">10dp</item>
+ <item name="android:gravity">center_vertical</item>
+ <item name="android:paddingStart">18dp</item>
+ <item name="android:paddingEnd">@dimen/drawer_nav_horizontal_margins</item>
+ </style>
+
</resources>