Twidere-App-Android-Twitter.../twidere/src/main/kotlin/org/mariotaku/twidere/activity/HomeActivity.kt

1002 lines
40 KiB
Kotlin
Raw Normal View History

2016-07-02 05:54:53 +02:00
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.activity
import android.accounts.Account
import android.accounts.AccountManager
import android.accounts.OnAccountsUpdateListener
2016-12-17 05:10:24 +01:00
import android.app.Dialog
2016-07-02 05:54:53 +02:00
import android.app.PendingIntent
import android.app.SearchManager
import android.content.Context
import android.content.DialogInterface
2016-07-02 05:54:53 +02:00
import android.content.Intent
2016-12-24 15:05:15 +01:00
import android.content.SharedPreferences
2016-07-02 05:54:53 +02:00
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.content.res.Configuration
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.AsyncTask
import android.os.Bundle
import android.support.annotation.StringRes
import android.support.v4.app.Fragment
import android.support.v4.app.NotificationCompat
import android.support.v4.view.GravityCompat
import android.support.v4.view.ViewPager.OnPageChangeListener
import android.support.v4.widget.DrawerLayout
import android.support.v4.widget.DrawerLayoutAccessor
import android.support.v7.app.ActionBarDrawerToggle
2016-12-17 05:10:24 +01:00
import android.support.v7.app.AlertDialog
2016-07-02 05:54:53 +02:00
import android.support.v7.app.AppCompatDelegate
import android.support.v7.widget.TintTypedArray
import android.util.SparseIntArray
import android.view.Gravity
import android.view.KeyEvent
import android.view.MenuItem
import android.view.View
import android.view.View.OnClickListener
import android.view.View.OnLongClickListener
import android.view.ViewGroup.MarginLayoutParams
2016-12-13 12:35:25 +01:00
import com.getkeepsafe.taptargetview.TapTarget
import com.getkeepsafe.taptargetview.TapTargetView
2016-07-02 05:54:53 +02:00
import com.squareup.otto.Subscribe
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.activity_home_content.*
import kotlinx.android.synthetic.main.layout_empty_tab_hint.*
import org.mariotaku.abstask.library.AbstractTask
import org.mariotaku.abstask.library.TaskStarter
2016-12-22 11:21:17 +01:00
import org.mariotaku.chameleon.ChameleonUtils
2016-12-13 12:35:25 +01:00
import org.mariotaku.kpreferences.get
import org.mariotaku.kpreferences.set
2017-03-13 06:35:11 +01:00
import org.mariotaku.ktextension.*
2017-04-10 11:35:35 +02:00
import org.mariotaku.sqliteqb.library.Expression
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.Constants.*
import org.mariotaku.twidere.R
2017-02-16 07:50:25 +01:00
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarShowHideHelper
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.adapter.SupportTabsAdapter
import org.mariotaku.twidere.annotation.CustomTabType
import org.mariotaku.twidere.annotation.ReadPositionTag
import org.mariotaku.twidere.constant.*
2017-02-05 14:42:20 +01:00
import org.mariotaku.twidere.extension.applyTheme
2017-02-16 07:50:25 +01:00
import org.mariotaku.twidere.fragment.AccountsDashboardFragment
import org.mariotaku.twidere.fragment.BaseDialogFragment
2017-02-15 07:48:10 +01:00
import org.mariotaku.twidere.fragment.iface.IFloatingActionButtonFragment
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface
import org.mariotaku.twidere.fragment.iface.SupportFragmentCallback
import org.mariotaku.twidere.graphic.EmptyDrawable
2016-12-04 06:45:57 +01:00
import org.mariotaku.twidere.model.AccountDetails
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.model.SupportTabSpec
2016-12-01 08:55:38 +01:00
import org.mariotaku.twidere.model.Tab
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.model.UserKey
2017-02-09 09:00:12 +01:00
import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
2017-03-13 06:35:11 +01:00
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
2017-03-13 08:13:39 +01:00
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
2016-07-02 05:54:53 +02:00
import org.mariotaku.twidere.service.StreamingService
import org.mariotaku.twidere.util.*
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
import org.mariotaku.twidere.view.HomeDrawerLayout
import org.mariotaku.twidere.view.TabPagerIndicator
2017-01-17 18:59:44 +01:00
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
OnLongClickListener, DrawerLayout.DrawerListener {
2016-07-02 05:54:53 +02:00
2016-12-12 14:19:02 +01:00
private val accountUpdatedListener = AccountUpdatedListener(this)
2016-07-02 05:54:53 +02:00
2016-12-04 06:45:57 +01:00
private var selectedAccountToSearch: AccountDetails? = null
2016-07-02 05:54:53 +02:00
2016-12-06 02:26:53 +01:00
private lateinit var multiSelectHandler: MultiSelectEventHandler
private lateinit var pagerAdapter: SupportTabsAdapter
private lateinit var drawerToggle: ActionBarDrawerToggle
2016-07-02 05:54:53 +02:00
private var propertiesInitialized = false
2016-07-02 05:54:53 +02:00
private var updateUnreadCountTask: UpdateUnreadCountTask? = null
private val readStateChangeListener = OnSharedPreferenceChangeListener { _, _ -> updateUnreadCount() }
2017-02-16 07:50:25 +01:00
private val controlBarShowHideHelper = ControlBarShowHideHelper(this)
2016-07-02 05:54:53 +02:00
private val homeDrawerToggleDelegate = object : ActionBarDrawerToggle.Delegate {
override fun setActionBarUpIndicator(upDrawable: Drawable, @StringRes contentDescRes: Int) {
drawerToggleButton.setImageDrawable(upDrawable)
2016-12-22 11:21:17 +01:00
drawerToggleButton.setColorFilter(ChameleonUtils.getColorDependent(overrideTheme.colorToolbar))
2016-07-02 05:54:53 +02:00
drawerToggleButton.contentDescription = getString(contentDescRes)
}
override fun setActionBarDescription(@StringRes contentDescRes: Int) {
drawerToggleButton.contentDescription = getString(contentDescRes)
}
override fun getThemeUpIndicator(): Drawable {
2016-12-22 11:21:17 +01:00
val a = TintTypedArray.obtainStyledAttributes(actionBarThemedContext, null,
HOME_AS_UP_ATTRS)
2016-07-02 05:54:53 +02:00
val result = a.getDrawable(0)
a.recycle()
return result
}
override fun getActionBarThemedContext(): Context {
return toolbar.context
2016-07-02 05:54:53 +02:00
}
override fun isNavigationVisible(): Boolean {
return true
}
}
override val controlBarHeight: Int
get() {
return mainTabs.height - mainTabs.stripHeight
}
2016-07-02 05:54:53 +02:00
fun closeAccountsDrawer() {
if (homeMenu == null) return
homeMenu.closeDrawers()
}
2016-12-03 16:45:13 +01:00
private val activatedAccountKeys: Array<UserKey>
get() = DataStoreUtils.getActivatedAccountKeys(this)
2016-07-02 05:54:53 +02:00
2016-07-06 15:21:34 +02:00
override val currentVisibleFragment: Fragment?
get() {
val currentItem = mainPager.currentItem
if (currentItem < 0 || currentItem >= pagerAdapter.count) return null
2017-02-04 08:39:08 +01:00
return pagerAdapter.instantiateItem(mainPager, currentItem)
2016-07-06 15:21:34 +02:00
}
2016-07-02 05:54:53 +02:00
override fun triggerRefresh(position: Int): Boolean {
2017-02-04 08:39:08 +01:00
val f = pagerAdapter.instantiateItem(mainPager, position)
2016-07-02 05:54:53 +02:00
if (f.activity == null || f.isDetached) return false
2016-12-06 02:26:53 +01:00
if (f !is RefreshScrollTopInterface) return false
2016-07-02 05:54:53 +02:00
return f.triggerRefresh()
}
2016-08-31 05:24:31 +02:00
val leftDrawerFragment: Fragment?
2016-07-02 05:54:53 +02:00
get() = supportFragmentManager.findFragmentById(R.id.leftDrawer)
private val isDrawerOpen: Boolean
get() {
val drawer = homeMenu ?: return false
return drawer.isDrawerOpen(GravityCompat.START) || drawer.isDrawerOpen(GravityCompat.END)
}
/**
* Called when the context is first created.
*/
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
multiSelectHandler = MultiSelectEventHandler(this)
2016-12-06 02:26:53 +01:00
multiSelectHandler.dispatchOnCreate()
DataStoreUtils.prepareDatabase(this)
2016-07-02 05:54:53 +02:00
if (!DataStoreUtils.hasAccount(this)) {
val signInIntent = Intent(INTENT_ACTION_TWITTER_LOGIN)
signInIntent.setClass(this, SignInActivity::class.java)
startActivity(signInIntent)
finish()
2016-12-23 02:26:52 +01:00
if (defaultAutoRefreshAskedKey !in kPreferences) {
2016-12-17 05:10:24 +01:00
// Assume first install
2016-12-23 02:26:52 +01:00
kPreferences[defaultAutoRefreshAskedKey] = false
2016-12-17 05:10:24 +01:00
}
2016-07-02 05:54:53 +02:00
return
} else {
notifyAccountsChanged()
}
supportRequestWindowFeature(AppCompatDelegate.FEATURE_ACTION_MODE_OVERLAY)
setContentView(R.layout.activity_home)
setSupportActionBar(toolbar)
drawerToggle = ActionBarDrawerToggle(this, homeMenu, R.string.open_accounts_dashboard,
R.string.close_accounts_dashboard)
pagerAdapter = SupportTabsAdapter(this, supportFragmentManager, mainTabs)
propertiesInitialized = true
2016-07-02 05:54:53 +02:00
ThemeUtils.setCompatContentViewOverlay(window, EmptyDrawable())
val refreshOnStart = preferences.getBoolean(SharedPreferenceConstants.KEY_REFRESH_ON_START, false)
var tabDisplayOptionInt = Utils.getTabDisplayOptionInt(this)
homeContent.setOnFitSystemWindowsListener(this)
mainPager.adapter = pagerAdapter
2016-07-02 05:54:53 +02:00
mainTabs.setViewPager(mainPager)
mainTabs.setOnPageChangeListener(this)
if (tabDisplayOptionInt == 0) {
tabDisplayOptionInt = TabPagerIndicator.DisplayOption.ICON
2016-07-02 05:54:53 +02:00
}
mainTabs.setTabDisplayOption(tabDisplayOptionInt)
mainTabs.setTabExpandEnabled(TabPagerIndicator.DisplayOption.LABEL !in tabDisplayOptionInt)
2016-12-23 02:26:52 +01:00
mainTabs.setDisplayBadge(preferences[unreadCountKey])
2016-07-02 05:54:53 +02:00
mainTabs.updateAppearance()
2016-12-23 02:26:52 +01:00
if (preferences[drawerToggleKey]) {
2016-07-02 05:54:53 +02:00
drawerToggleButton.visibility = View.VISIBLE
} else {
drawerToggleButton.visibility = View.GONE
}
2016-12-23 02:26:52 +01:00
if (preferences[fabVisibleKey]) {
actionsButton.visibility = View.VISIBLE
} else {
actionsButton.visibility = View.GONE
}
homeContent.addOnLayoutChangeListener { _, _, top, _, _, _, oldTop, _, _ ->
2016-07-02 05:54:53 +02:00
if (top != oldTop) {
val fragment = leftDrawerFragment
if (fragment is AccountsDashboardFragment) {
fragment.setStatusBarHeight(top)
}
}
}
actionsButton.setOnClickListener(this)
actionsButton.setOnLongClickListener(this)
drawerToggleButton.setOnClickListener(this)
emptyTabHint.setOnClickListener(this)
setupSlidingMenu()
setupBars()
showDataProfilingRequest()
initUnreadCount()
setupHomeTabs()
updateActionsButton()
if (savedInstanceState == null) {
if (refreshOnStart) {
twitterWrapper.refreshAll(activatedAccountKeys)
}
if (intent.getBooleanExtra(EXTRA_OPEN_ACCOUNTS_DRAWER, false)) {
openAccountsDrawer()
}
}
2017-02-04 08:39:08 +01:00
val initialTabPosition = handleIntent(intent, savedInstanceState == null)
2016-07-02 05:54:53 +02:00
setTabPosition(initialTabPosition)
2017-03-13 08:13:39 +01:00
StreamingService.startOrStopService(this)
2016-12-13 12:35:25 +01:00
2016-12-23 02:26:52 +01:00
if (!showDrawerTutorial() && !kPreferences[defaultAutoRefreshAskedKey]) {
2016-12-17 05:10:24 +01:00
showAutoRefreshConfirm()
}
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
// Sync the toggle state after onRestoreInstanceState has occurred.
drawerToggle.syncState()
}
2016-07-02 05:54:53 +02:00
override fun onStart() {
super.onStart()
2016-12-06 02:26:53 +01:00
multiSelectHandler.dispatchOnStart()
AccountManager.get(this).addOnAccountsUpdatedListenerSafe(accountUpdatedListener, updateImmediately = false)
2016-07-02 05:54:53 +02:00
bus.register(this)
readStateManager.registerOnSharedPreferenceChangeListener(readStateChangeListener)
updateUnreadCount()
}
override fun onResume() {
super.onResume()
invalidateOptionsMenu()
updateActionsButton()
}
override fun onStop() {
2016-12-06 02:26:53 +01:00
multiSelectHandler.dispatchOnStop()
2016-07-02 05:54:53 +02:00
readStateManager.unregisterOnSharedPreferenceChangeListener(readStateChangeListener)
bus.unregister(this)
AccountManager.get(this).removeOnAccountsUpdatedListenerSafe(accountUpdatedListener)
2017-04-13 18:57:14 +02:00
preferences.edit().putInt(KEY_SAVED_TAB_POSITION, mainPager.currentItem).apply()
timelineSyncManager?.commit()
2016-07-02 05:54:53 +02:00
super.onStop()
}
2017-02-16 07:50:25 +01:00
override fun onDestroy() {
2017-03-12 14:27:55 +01:00
if (isFinishing) {
// Stop only when exiting explicitly
2017-03-13 08:13:39 +01:00
StreamingService.startOrStopService(this)
2017-03-12 14:27:55 +01:00
}
2016-07-02 05:54:53 +02:00
2017-02-16 07:50:25 +01:00
// Delete unused items in databases.
val context = applicationContext
TaskStarter.execute(object : AbstractTask<Any?, Any?, Any?>() {
2017-03-07 13:40:04 +01:00
override fun doLongOperation(params: Any?): Any? {
2017-02-16 07:50:25 +01:00
DataStoreUtils.cleanDatabasesByItemLimit(context)
return null
}
})
super.onDestroy()
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
override fun onAttachFragment(fragment: Fragment?) {
super.onAttachFragment(fragment)
updateActionsButton()
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
2016-07-02 05:54:53 +02:00
}
override fun onClick(v: View) {
when (v) {
actionsButton -> {
triggerActionsClick()
}
emptyTabHint -> {
2017-03-13 06:35:11 +01:00
startActivityForResult(IntentUtils.settings("tabs"), REQUEST_SETTINGS)
2016-07-02 05:54:53 +02:00
}
drawerToggleButton -> {
if (homeMenu.isDrawerOpen(GravityCompat.START) || homeMenu.isDrawerOpen(GravityCompat.END)) {
homeMenu.closeDrawers()
} else {
homeMenu.openDrawer(GravityCompat.START)
}
}
}
}
override fun onLongClick(v: View): Boolean {
when (v) {
actionsButton -> {
Utils.showMenuItemToast(v, v.contentDescription, true)
return true
}
}
return false
}
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
}
override fun onPageSelected(position: Int) {
//TODO handle secondary drawer
if (homeMenu.isDrawerOpen(GravityCompat.START)) {
homeMenu.closeDrawers()
}
updateActionsButton()
}
override fun onPageScrollStateChanged(state: Int) {
setControlBarVisibleAnimate(true)
}
override fun onSearchRequested(): Boolean {
startActivity(Intent(this, QuickSearchBarActivity::class.java))
return true
}
override fun onFitSystemWindows(insets: Rect) {
super.onFitSystemWindows(insets)
val fragment = leftDrawerFragment
if (fragment is AccountsDashboardFragment) {
fragment.requestFitSystemWindows()
}
}
override fun onNewIntent(intent: Intent) {
2017-02-04 08:39:08 +01:00
val tabPosition = handleIntent(intent, false)
2016-07-02 05:54:53 +02:00
if (tabPosition >= 0) {
2017-02-04 11:42:14 +01:00
mainPager.currentItem = tabPosition.coerceInOr(0 until pagerAdapter.count, 0)
2016-07-02 05:54:53 +02:00
}
}
2017-02-16 07:50:25 +01:00
override fun getSystemWindowsInsets(insets: Rect): Boolean {
if (mainTabs == null || homeContent == null) return false
val height = mainTabs.height
if (height != 0) {
insets.top = height
} else {
insets.top = ThemeUtils.getActionBarHeight(this)
}
return true
}
2016-07-02 05:54:53 +02:00
2017-02-16 07:50:25 +01:00
override fun setControlBarVisibleAnimate(visible: Boolean,
listener: ControlBarShowHideHelper.ControlBarAnimationListener?) {
controlBarShowHideHelper.setControlBarVisibleAnimate(visible, listener)
}
2016-07-02 05:54:53 +02:00
2017-02-16 07:50:25 +01:00
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (drawerToggle.onOptionsItemSelected(item)) {
return true
}
when (item.itemId) {
android.R.id.home -> {
val fm = supportFragmentManager
val count = fm.backStackEntryCount
if (homeMenu.isDrawerOpen(GravityCompat.START) || homeMenu.isDrawerOpen(GravityCompat.END)) {
homeMenu.closeDrawers()
return true
} else if (count == 0) {
homeMenu.openDrawer(GravityCompat.START)
return true
}
return true
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
R.id.search -> {
openSearchView(selectedAccountToSearch)
return true
}
R.id.actions -> {
triggerActionsClick()
return true
}
}
return super.onOptionsItemSelected(item)
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
override fun handleKeyboardShortcutSingle(handler: KeyboardShortcutsHandler, keyCode: Int,
event: KeyEvent, metaState: Int): Boolean {
if (handleFragmentKeyboardShortcutSingle(handler, keyCode, event, metaState)) return true
var action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_HOME, keyCode, event, metaState)
if (action != null) {
when (action) {
KeyboardShortcutConstants.ACTION_HOME_ACCOUNTS_DASHBOARD -> {
if (homeMenu.isDrawerOpen(GravityCompat.START)) {
homeMenu.closeDrawers()
} else {
homeMenu.openDrawer(GravityCompat.START)
setControlBarVisibleAnimate(true)
}
return true
}
}
}
action = handler.getKeyAction(KeyboardShortcutConstants.CONTEXT_TAG_NAVIGATION, keyCode, event, metaState)
if (action != null) {
when (action) {
KeyboardShortcutConstants.ACTION_NAVIGATION_PREVIOUS_TAB -> {
val previous = mainPager.currentItem - 1
if (previous < 0 && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.START) != null) {
homeMenu.openDrawer(GravityCompat.START)
setControlBarVisibleAnimate(true)
} else if (previous < pagerAdapter.count) {
if (homeMenu.isDrawerOpen(GravityCompat.END)) {
homeMenu.closeDrawers()
} else {
mainPager.setCurrentItem(previous, true)
}
}
return true
}
KeyboardShortcutConstants.ACTION_NAVIGATION_NEXT_TAB -> {
val next = mainPager.currentItem + 1
if (next >= pagerAdapter.count && DrawerLayoutAccessor.findDrawerWithGravity(homeMenu, Gravity.END) != null) {
homeMenu.openDrawer(GravityCompat.END)
setControlBarVisibleAnimate(true)
} else if (next >= 0) {
if (homeMenu.isDrawerOpen(GravityCompat.START)) {
homeMenu.closeDrawers()
} else {
mainPager.setCurrentItem(next, true)
}
}
return true
}
}
}
return handler.handleKey(this, null, keyCode, event, metaState)
}
override fun isKeyboardShortcutHandled(handler: KeyboardShortcutsHandler, keyCode: Int,
event: KeyEvent, metaState: Int): Boolean {
if (isFragmentKeyboardShortcutHandled(handler, keyCode, event, metaState)) return true
return super.isKeyboardShortcutHandled(handler, keyCode, event, metaState)
}
override fun handleKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler, keyCode: Int,
repeatCount: Int, event: KeyEvent, metaState: Int): Boolean {
if (handleFragmentKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState))
return true
return super.handleKeyboardShortcutRepeat(handler, keyCode, repeatCount, event, metaState)
2016-07-02 05:54:53 +02:00
}
2017-02-16 07:50:25 +01:00
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
when (keyCode) {
KeyEvent.KEYCODE_MENU -> {
if (isDrawerOpen) {
homeMenu.closeDrawers()
} else {
homeMenu.openDrawer(GravityCompat.START)
}
return true
}
KeyEvent.KEYCODE_BACK -> {
if (isDrawerOpen) {
homeMenu.closeDrawers()
return true
}
}
}
return super.onKeyUp(keyCode, event)
}
fun notifyAccountsChanged() {
}
@Subscribe
fun notifyUnreadCountUpdated(event: UnreadCountUpdatedEvent) {
updateUnreadCount()
}
fun openSearchView(account: AccountDetails?) {
selectedAccountToSearch = account
onSearchRequested()
}
fun updateUnreadCount() {
if (mainTabs == null || updateUnreadCountTask != null && updateUnreadCountTask!!.status == AsyncTask.Status.RUNNING)
return
updateUnreadCountTask = UpdateUnreadCountTask(this, preferences, readStateManager, mainTabs,
pagerAdapter.tabs.toTypedArray())
AsyncTaskUtils.executeTask<UpdateUnreadCountTask, Any>(updateUnreadCountTask)
mainTabs.setDisplayBadge(preferences.getBoolean(SharedPreferenceConstants.KEY_UNREAD_COUNT, true))
}
val tabs: List<SupportTabSpec>
get() = pagerAdapter.tabs
2016-07-02 05:54:53 +02:00
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// Pass any configuration change to the drawer toggle
drawerToggle.onConfigurationChanged(newConfig)
}
override var controlBarOffset: Float
get() {
if (mainTabs.columns > 1) {
val lp = actionsButton.layoutParams
val total: Float
if (lp is MarginLayoutParams) {
total = (lp.bottomMargin + actionsButton.height).toFloat()
} else {
total = actionsButton.height.toFloat()
}
return 1 - actionsButton.translationY / total
}
val totalHeight = controlBarHeight.toFloat()
return 1 + toolbar.translationY / totalHeight
}
set(offset) {
val translationY = if (mainTabs.columns > 1) 0 else (controlBarHeight * (offset - 1)).toInt()
toolbar.translationY = translationY.toFloat()
windowOverlay.translationY = translationY.toFloat()
2016-07-02 05:54:53 +02:00
val lp = actionsButton.layoutParams
if (lp is MarginLayoutParams) {
actionsButton.translationY = (lp.bottomMargin + actionsButton.height) * (1 - offset)
2016-07-02 05:54:53 +02:00
} else {
actionsButton.translationY = actionsButton.height * (1 - offset)
2016-07-02 05:54:53 +02:00
}
notifyControlBarOffsetChanged()
2016-07-02 05:54:53 +02:00
}
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
}
override fun onDrawerOpened(drawerView: View) {
}
override fun onDrawerClosed(drawerView: View) {
}
override fun onDrawerStateChanged(newState: Int) {
val fragment = leftDrawerFragment
if (newState == DrawerLayout.STATE_DRAGGING && fragment is AccountsDashboardFragment) {
2017-02-05 15:15:03 +01:00
fragment.loadAccounts()
2016-07-02 05:54:53 +02:00
}
}
override fun getDrawerToggleDelegate(): ActionBarDrawerToggle.Delegate? {
return homeDrawerToggleDelegate
}
private val keyboardShortcutRecipient: Fragment?
get() {
if (homeMenu.isDrawerOpen(GravityCompat.START)) {
return leftDrawerFragment
} else if (homeMenu.isDrawerOpen(GravityCompat.END)) {
return null
} else {
return currentVisibleFragment
}
}
private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, repeatCount: Int,
event: KeyEvent, metaState: Int): Boolean {
2016-07-02 05:54:53 +02:00
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutRepeat(handler, keyCode,
repeatCount, event, metaState)
}
return false
}
private fun handleFragmentKeyboardShortcutSingle(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, event: KeyEvent,
metaState: Int): Boolean {
2016-07-02 05:54:53 +02:00
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.handleKeyboardShortcutSingle(handler, keyCode,
event, metaState)
}
return false
}
private fun isFragmentKeyboardShortcutHandled(handler: KeyboardShortcutsHandler,
2017-02-15 07:48:10 +01:00
keyCode: Int, event: KeyEvent, metaState: Int): Boolean {
2016-07-02 05:54:53 +02:00
val fragment = keyboardShortcutRecipient
if (fragment is KeyboardShortcutCallback) {
return fragment.isKeyboardShortcutHandled(handler, keyCode,
event, metaState)
}
return false
}
2017-02-04 08:39:08 +01:00
private fun handleIntent(intent: Intent, handleExtraIntent: Boolean): Int {
2016-07-02 05:54:53 +02:00
// use package's class loader to prevent BadParcelException
intent.setExtrasClassLoader(classLoader)
// reset intent
setIntent(Intent(this, HomeActivity::class.java))
val action = intent.action
if (Intent.ACTION_SEARCH == action) {
val query = intent.getStringExtra(SearchManager.QUERY)
val appSearchData = intent.getBundleExtra(SearchManager.APP_DATA)
val accountKey: UserKey?
if (appSearchData != null && appSearchData.containsKey(EXTRA_ACCOUNT_KEY)) {
accountKey = appSearchData.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
} else {
accountKey = Utils.getDefaultAccountKey(this)
}
IntentUtils.openSearch(this, accountKey, query)
return -1
}
val refreshOnStart = preferences.getBoolean(SharedPreferenceConstants.KEY_REFRESH_ON_START, false)
if (handleExtraIntent && refreshOnStart) {
twitterWrapper.refreshAll()
}
val extraIntent = intent.getParcelableExtra<Intent>(EXTRA_EXTRA_INTENT)
val uri = intent.data
@CustomTabType
val tabType = if (uri != null) Utils.matchTabType(uri) else null
var initialTab = -1
if (tabType != null) {
2017-02-17 11:42:39 +01:00
val accountKey = uri?.getQueryParameter(QUERY_PARAM_ACCOUNT_KEY)?.let(UserKey::valueOf)
val adapter = pagerAdapter
2016-12-05 14:18:20 +01:00
for (i in 0 until adapter.count) {
2017-03-27 05:08:09 +02:00
val tab = adapter.get(i)
2016-12-01 08:55:38 +01:00
if (tabType == Tab.getTypeAlias(tab.type)) {
2016-07-07 05:42:08 +02:00
val args = tab.args
2017-04-12 14:58:08 +02:00
if (args != null && CustomTabUtils.hasAccountKey(this, args,
2016-07-02 05:54:53 +02:00
activatedAccountKeys, accountKey)) {
initialTab = i
break
}
}
}
if (initialTab == -1 && (extraIntent == null || !handleExtraIntent)) {
// Tab not found, open account specific page
when (tabType) {
CustomTabType.NOTIFICATIONS_TIMELINE -> {
IntentUtils.openInteractions(this, accountKey)
return -1
}
CustomTabType.DIRECT_MESSAGES -> {
IntentUtils.openDirectMessages(this, accountKey)
return -1
}
}
}
}
if (extraIntent != null && handleExtraIntent) {
extraIntent.setExtrasClassLoader(classLoader)
startActivity(extraIntent)
}
return initialTab
}
private fun initUnreadCount() {
for (i in 0 until mainTabs.count) {
2016-07-02 05:54:53 +02:00
mainTabs.setBadge(i, 0)
}
}
private fun openAccountsDrawer() {
if (homeMenu == null) return
homeMenu.openDrawer(GravityCompat.START)
}
2016-12-17 05:10:24 +01:00
private fun showDrawerTutorial(): Boolean {
2016-12-13 12:35:25 +01:00
if (preferences[drawerTutorialCompleted]) return false
val targetSize = resources.getDimensionPixelSize(R.dimen.element_size_mlarge)
val height = resources.displayMetrics.heightPixels
val listener: TapTargetView.Listener = object : TapTargetView.Listener() {
override fun onTargetClick(view: TapTargetView?) {
if (!homeMenu.isDrawerOpen(GravityCompat.START)) {
homeMenu.openDrawer(GravityCompat.START)
}
super.onTargetClick(view)
}
override fun onTargetDismissed(view: TapTargetView?, userInitiated: Boolean) {
preferences[drawerTutorialCompleted] = true
2016-12-17 05:10:24 +01:00
showAutoRefreshConfirm()
2016-12-13 12:35:25 +01:00
}
}
val target = Rect(0, 0, targetSize, targetSize)
target.offsetTo(0, height / 2 - targetSize / 2)
TapTargetView.showFor(this, TapTarget.forBounds(target,
getString(R.string.hint_accounts_dashboard_title),
getString(R.string.hint_accounts_dashboard_message))
.apply {
outerCircleColor(R.color.branding_color)
dimColor(android.R.color.black)
}, listener)
2016-07-02 05:54:53 +02:00
return true
}
2016-12-17 05:10:24 +01:00
private fun showAutoRefreshConfirm() {
if (isFinishing) return
executeAfterFragmentResumed { activity ->
val df = AutoRefreshConfirmDialogFragment()
df.show(activity.supportFragmentManager, "auto_refresh_confirm")
}
2016-12-17 05:10:24 +01:00
}
2016-07-02 05:54:53 +02:00
private fun setTabPosition(initialTab: Int) {
val rememberPosition = preferences.getBoolean(SharedPreferenceConstants.KEY_REMEMBER_POSITION, true)
if (initialTab >= 0) {
2017-02-04 11:42:14 +01:00
mainPager.currentItem = initialTab.coerceInOr(0 until pagerAdapter.count, 0)
2016-07-02 05:54:53 +02:00
} else if (rememberPosition) {
val position = preferences.getInt(SharedPreferenceConstants.KEY_SAVED_TAB_POSITION, 0)
2017-02-04 11:42:14 +01:00
mainPager.currentItem = position.coerceInOr(0 until pagerAdapter.count, 0)
2016-07-02 05:54:53 +02:00
}
}
private fun setupBars() {
val backgroundOption = currentThemeBackgroundOption
val isTransparent = ThemeUtils.isTransparentBackground(backgroundOption)
2017-03-21 03:33:27 +01:00
val actionBarAlpha = if (isTransparent) {
ThemeUtils.getActionBarAlpha(preferences[themeBackgroundAlphaKey])
} else {
0xFF
}
2016-07-02 05:54:53 +02:00
actionsButton.alpha = actionBarAlpha / 255f
}
private fun setupHomeTabs() {
pagerAdapter.clear()
2017-03-27 05:08:09 +02:00
pagerAdapter.addAll(CustomTabUtils.getHomeTabs(this))
val hasNoTab = pagerAdapter.count == 0
2016-07-02 05:54:53 +02:00
emptyTabHint.visibility = if (hasNoTab) View.VISIBLE else View.GONE
mainPager.visibility = if (hasNoTab) View.GONE else View.VISIBLE
if (pagerAdapter.count > 1 && hasMultiColumns()) {
mainPager.pageMargin = resources.getDimensionPixelOffset(R.dimen.home_page_margin)
2017-01-17 18:59:44 +01:00
mainPager.setPageMarginDrawable(ThemeUtils.getDrawableFromThemeAttribute(this, R.attr.dividerVertical))
2017-01-18 08:35:00 +01:00
pagerAdapter.hasMultipleColumns = true
pagerAdapter.preferredColumnWidth = when (preferences[multiColumnWidthKey]) {
"narrow" -> resources.getDimension(R.dimen.preferred_tab_column_width_narrow)
"wide" -> resources.getDimension(R.dimen.preferred_tab_column_width_wide)
else -> resources.getDimension(R.dimen.preferred_tab_column_width_normal)
}
2017-01-23 15:26:29 +01:00
mainTabs.columns = Math.floor(1.0 / pagerAdapter.getPageWidth(0)).toInt()
} else {
mainPager.pageMargin = 0
mainPager.setPageMarginDrawable(null)
2017-01-18 08:35:00 +01:00
pagerAdapter.hasMultipleColumns = false
2017-01-23 15:26:29 +01:00
mainTabs.columns = 1
}
2016-07-02 05:54:53 +02:00
}
private fun setupSlidingMenu() {
homeMenu.setDrawerShadow(R.drawable.drawer_shadow_start, GravityCompat.START)
homeMenu.addDrawerListener(drawerToggle)
homeMenu.addDrawerListener(this)
homeMenu.setShouldDisableDecider(HomeDrawerLayout.ShouldDisableDecider { e ->
val fragment = leftDrawerFragment
if (fragment is AccountsDashboardFragment) {
2016-12-05 04:39:22 +01:00
return@ShouldDisableDecider fragment.shouldDisableDrawerSlide(e)
2016-07-02 05:54:53 +02:00
}
false
})
}
private fun showDataProfilingRequest() {
//spice
if (preferences.contains(KEY_USAGE_STATISTICS)) {
return
}
val intent = Intent(this, UsageStatisticsActivity::class.java)
val contentIntent = PendingIntent.getActivity(this, 0, intent, 0)
val builder = NotificationCompat.Builder(this)
builder.setAutoCancel(true)
builder.setSmallIcon(R.drawable.ic_stat_info)
builder.setTicker(getString(R.string.usage_statistics))
builder.setContentTitle(getString(R.string.usage_statistics))
builder.setContentText(getString(R.string.usage_statistics_notification_summary))
builder.setContentIntent(contentIntent)
notificationManager.notify(NOTIFICATION_ID_DATA_PROFILING, builder.build())
}
private fun triggerActionsClick() {
val position = mainPager.currentItem
if (pagerAdapter.count == 0) return
2017-02-15 09:11:11 +01:00
val fragment = pagerAdapter.instantiateItem(mainPager, position) as? IFloatingActionButtonFragment
val handled = fragment?.onActionClick("home") ?: false
2017-02-15 07:55:18 +01:00
if (!handled) {
startActivity(Intent(INTENT_ACTION_COMPOSE))
2016-07-02 05:54:53 +02:00
}
}
private fun updateActionsButton() {
if (!propertiesInitialized) return
2017-02-16 07:50:25 +01:00
val fragment = run {
if (pagerAdapter.count == 0) return@run null
val position = mainPager.currentItem
val f = pagerAdapter.instantiateItem(mainPager, position) as? IFloatingActionButtonFragment
if (f is Fragment && (f.isDetached || f.host == null)) {
return@run null
}
return@run f
}
2017-02-15 07:48:10 +01:00
val info = fragment?.getActionInfo("home") ?: run {
actionsButton.setImageResource(R.drawable.ic_action_status_compose)
actionsButton.contentDescription = getString(R.string.action_compose)
return
2016-07-02 05:54:53 +02:00
}
2017-02-15 07:48:10 +01:00
actionsButton.setImageResource(info.icon)
actionsButton.contentDescription = info.title
2016-07-02 05:54:53 +02:00
}
fun hasMultiColumns(): Boolean {
if (!Utils.isDeviceTablet(this) || !Utils.isScreenTablet(this)) return false
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
return preferences.getBoolean("multi_column_tabs_landscape", resources.getBoolean(R.bool.default_multi_column_tabs_land))
}
return preferences.getBoolean("multi_column_tabs_portrait", resources.getBoolean(R.bool.default_multi_column_tabs_port))
}
2016-12-12 14:19:02 +01:00
private class AccountUpdatedListener(private val activity: HomeActivity) : OnAccountsUpdateListener {
2016-07-02 05:54:53 +02:00
override fun onAccountsUpdated(accounts: Array<out Account>?) {
activity.notifyAccountsChanged()
activity.updateUnreadCount()
2016-07-02 05:54:53 +02:00
}
}
2017-03-02 02:08:54 +01:00
private class UpdateUnreadCountTask(
2016-07-02 05:54:53 +02:00
private val context: Context,
2016-12-24 15:05:15 +01:00
private val preferences: SharedPreferences,
2016-07-02 05:54:53 +02:00
private val readStateManager: ReadStateManager,
private val indicator: TabPagerIndicator,
2017-03-02 02:08:54 +01:00
private val tabs: Array<SupportTabSpec>
) : AsyncTask<Any, UpdateUnreadCountTask.TabBadge, SparseIntArray>() {
private val activatedKeys = DataStoreUtils.getActivatedAccountKeys(context)
2016-07-02 05:54:53 +02:00
override fun doInBackground(vararg params: Any): SparseIntArray {
val result = SparseIntArray()
tabs.forEachIndexed { i, spec ->
if (spec.type == null) {
publishProgress(TabBadge(i, -1))
return@forEachIndexed
}
when (spec.type) {
CustomTabType.HOME_TIMELINE -> {
2017-03-02 02:08:54 +01:00
val accountKeys = Utils.getAccountKeys(context, spec.args) ?: activatedKeys
2016-07-08 03:44:43 +02:00
val position = accountKeys.map {
val tag = Utils.getReadPositionTagWithAccount(ReadPositionTag.HOME_TIMELINE, it)
readStateManager.getPosition(tag)
}.fold(0L, Math::max)
2016-12-24 15:05:15 +01:00
val count = DataStoreUtils.getStatusesCount(context, preferences,
2017-04-10 11:35:35 +02:00
Statuses.CONTENT_URI, spec.args, Statuses.STATUS_TIMESTAMP, position,
2016-12-24 15:05:15 +01:00
true, accountKeys)
2016-07-02 05:54:53 +02:00
result.put(i, count)
publishProgress(TabBadge(i, count))
}
CustomTabType.NOTIFICATIONS_TIMELINE -> {
2017-03-02 02:08:54 +01:00
val accountKeys = Utils.getAccountKeys(context, spec.args) ?: activatedKeys
2016-07-08 03:44:43 +02:00
val position = accountKeys.map {
val tag = Utils.getReadPositionTagWithAccount(ReadPositionTag.ACTIVITIES_ABOUT_ME, it)
readStateManager.getPosition(tag)
}.fold(0L, Math::max)
2016-07-02 05:54:53 +02:00
val count = DataStoreUtils.getInteractionsCount(context, spec.args,
2016-07-08 03:44:43 +02:00
accountKeys, position, Activities.TIMESTAMP)
2016-07-02 05:54:53 +02:00
publishProgress(TabBadge(i, count))
result.put(i, count)
}
2017-03-13 06:35:11 +01:00
CustomTabType.DIRECT_MESSAGES -> {
val accountKeys = Utils.getAccountKeys(context, spec.args) ?: activatedKeys
val projection = (Conversations.COLUMNS + Conversations.UNREAD_COUNT).map {
TwidereQueryBuilder.mapConversationsProjection(it)
}.toTypedArray()
2017-04-10 11:35:35 +02:00
val unreadHaving = Expression.greaterThan(Conversations.UNREAD_COUNT, 0)
2017-03-13 06:35:11 +01:00
val count = context.contentResolver.getUnreadMessagesEntriesCursor(projection,
2017-04-10 11:35:35 +02:00
accountKeys, extraHaving = unreadHaving)?.useCursor { cur ->
2017-03-13 06:35:11 +01:00
return@useCursor cur.count
} ?: -1
publishProgress(TabBadge(i, count))
result.put(i, count)
}
2016-07-02 05:54:53 +02:00
else -> {
publishProgress(TabBadge(i, -1))
}
}
}
return result
}
override fun onPostExecute(result: SparseIntArray) {
indicator.clearBadge()
for (i in 0 until result.size()) {
2016-07-02 05:54:53 +02:00
indicator.setBadge(result.keyAt(i), result.valueAt(i))
}
}
override fun onProgressUpdate(vararg values: TabBadge) {
for (value in values) {
indicator.setBadge(value.index, value.count)
}
}
internal class TabBadge(var index: Int, var count: Int)
}
2016-12-17 05:10:24 +01:00
class AutoRefreshConfirmDialogFragment : BaseDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.auto_refresh)
builder.setMessage(R.string.message_auto_refresh_confirm)
builder.setPositiveButton(android.R.string.ok) { _, _ ->
kPreferences[defaultAutoRefreshKey] = true
2016-12-17 05:10:24 +01:00
}
builder.setNegativeButton(R.string.no_thanks) { _, _ ->
kPreferences[defaultAutoRefreshKey] = false
2016-12-17 05:10:24 +01:00
}
2017-02-05 14:42:20 +01:00
val dialog = builder.create()
dialog.setOnShowListener {
it as AlertDialog
it.applyTheme()
}
return dialog
2016-12-17 05:10:24 +01:00
}
override fun onDismiss(dialog: DialogInterface?) {
2016-12-23 02:26:52 +01:00
kPreferences[defaultAutoRefreshAskedKey] = true
super.onDismiss(dialog)
}
2016-12-17 05:10:24 +01:00
}
2016-07-02 05:54:53 +02:00
companion object {
private val HOME_AS_UP_ATTRS = intArrayOf(android.support.v7.appcompat.R.attr.homeAsUpIndicator)
}
}