parent
5a095a9178
commit
1d81c8cdf8
|
@ -38,7 +38,6 @@ import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.support.annotation.StringRes
|
import android.support.annotation.StringRes
|
||||||
import android.support.v4.app.Fragment
|
import android.support.v4.app.Fragment
|
||||||
import android.support.v4.app.NotificationCompat
|
|
||||||
import android.support.v4.view.GravityCompat
|
import android.support.v4.view.GravityCompat
|
||||||
import android.support.v4.view.ViewCompat
|
import android.support.v4.view.ViewCompat
|
||||||
import android.support.v4.view.ViewPager.OnPageChangeListener
|
import android.support.v4.view.ViewPager.OnPageChangeListener
|
||||||
|
@ -79,6 +78,7 @@ import org.mariotaku.twidere.annotation.NavbarStyle
|
||||||
import org.mariotaku.twidere.annotation.ReadPositionTag
|
import org.mariotaku.twidere.annotation.ReadPositionTag
|
||||||
import org.mariotaku.twidere.constant.*
|
import org.mariotaku.twidere.constant.*
|
||||||
import org.mariotaku.twidere.extension.applyTheme
|
import org.mariotaku.twidere.extension.applyTheme
|
||||||
|
import org.mariotaku.twidere.extension.model.notificationBuilder
|
||||||
import org.mariotaku.twidere.extension.onShow
|
import org.mariotaku.twidere.extension.onShow
|
||||||
import org.mariotaku.twidere.fragment.AccountsDashboardFragment
|
import org.mariotaku.twidere.fragment.AccountsDashboardFragment
|
||||||
import org.mariotaku.twidere.fragment.BaseDialogFragment
|
import org.mariotaku.twidere.fragment.BaseDialogFragment
|
||||||
|
@ -91,6 +91,7 @@ import org.mariotaku.twidere.model.SupportTabSpec
|
||||||
import org.mariotaku.twidere.model.Tab
|
import org.mariotaku.twidere.model.Tab
|
||||||
import org.mariotaku.twidere.model.UserKey
|
import org.mariotaku.twidere.model.UserKey
|
||||||
import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
|
import org.mariotaku.twidere.model.event.UnreadCountUpdatedEvent
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
import org.mariotaku.twidere.provider.TwidereDataStore.Activities
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
import org.mariotaku.twidere.provider.TwidereDataStore.Statuses
|
||||||
|
@ -99,6 +100,7 @@ import org.mariotaku.twidere.util.*
|
||||||
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
|
import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback
|
||||||
import org.mariotaku.twidere.view.HomeDrawerLayout
|
import org.mariotaku.twidere.view.HomeDrawerLayout
|
||||||
import org.mariotaku.twidere.view.TabPagerIndicator
|
import org.mariotaku.twidere.view.TabPagerIndicator
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
|
class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, SupportFragmentCallback,
|
||||||
OnLongClickListener, DrawerLayout.DrawerListener {
|
OnLongClickListener, DrawerLayout.DrawerListener {
|
||||||
|
@ -118,6 +120,18 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
private val readStateChangeListener = OnSharedPreferenceChangeListener { _, _ -> updateUnreadCount() }
|
private val readStateChangeListener = OnSharedPreferenceChangeListener { _, _ -> updateUnreadCount() }
|
||||||
private val controlBarShowHideHelper = ControlBarShowHideHelper(this)
|
private val controlBarShowHideHelper = ControlBarShowHideHelper(this)
|
||||||
|
|
||||||
|
override val controlBarHeight: Int
|
||||||
|
get() {
|
||||||
|
return mainTabs.height - mainTabs.stripHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
override val currentVisibleFragment: Fragment?
|
||||||
|
get() {
|
||||||
|
val currentItem = mainPager.currentItem
|
||||||
|
if (currentItem < 0 || currentItem >= pagerAdapter.count) return null
|
||||||
|
return pagerAdapter.instantiateItem(mainPager, currentItem)
|
||||||
|
}
|
||||||
|
|
||||||
private val homeDrawerToggleDelegate = object : ActionBarDrawerToggle.Delegate {
|
private val homeDrawerToggleDelegate = object : ActionBarDrawerToggle.Delegate {
|
||||||
override fun setActionBarUpIndicator(upDrawable: Drawable, @StringRes contentDescRes: Int) {
|
override fun setActionBarUpIndicator(upDrawable: Drawable, @StringRes contentDescRes: Int) {
|
||||||
drawerToggleButton.setImageDrawable(upDrawable)
|
drawerToggleButton.setImageDrawable(upDrawable)
|
||||||
|
@ -146,34 +160,17 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val controlBarHeight: Int
|
private val keyboardShortcutRecipient: Fragment?
|
||||||
get() {
|
get() = when {
|
||||||
return mainTabs.height - mainTabs.stripHeight
|
homeMenu.isDrawerOpen(GravityCompat.START) -> leftDrawerFragment
|
||||||
|
homeMenu.isDrawerOpen(GravityCompat.END) -> null
|
||||||
|
else -> currentVisibleFragment
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeAccountsDrawer() {
|
|
||||||
if (homeMenu == null) return
|
|
||||||
homeMenu.closeDrawers()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val activatedAccountKeys: Array<UserKey>
|
private val activatedAccountKeys: Array<UserKey>
|
||||||
get() = DataStoreUtils.getActivatedAccountKeys(this)
|
get() = DataStoreUtils.getActivatedAccountKeys(this)
|
||||||
|
|
||||||
override val currentVisibleFragment: Fragment?
|
private val leftDrawerFragment: Fragment?
|
||||||
get() {
|
|
||||||
val currentItem = mainPager.currentItem
|
|
||||||
if (currentItem < 0 || currentItem >= pagerAdapter.count) return null
|
|
||||||
return pagerAdapter.instantiateItem(mainPager, currentItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun triggerRefresh(position: Int): Boolean {
|
|
||||||
val f = pagerAdapter.instantiateItem(mainPager, position)
|
|
||||||
if (f.activity == null || f.isDetached) return false
|
|
||||||
if (f !is RefreshScrollTopInterface) return false
|
|
||||||
return f.triggerRefresh()
|
|
||||||
}
|
|
||||||
|
|
||||||
val leftDrawerFragment: Fragment?
|
|
||||||
get() = supportFragmentManager.findFragmentById(R.id.leftDrawer)
|
get() = supportFragmentManager.findFragmentById(R.id.leftDrawer)
|
||||||
|
|
||||||
private val isDrawerOpen: Boolean
|
private val isDrawerOpen: Boolean
|
||||||
|
@ -220,7 +217,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(homeContent, this)
|
ViewCompat.setOnApplyWindowInsetsListener(homeContent, this)
|
||||||
homeMenu.fitsSystemWindows = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ||
|
homeMenu.fitsSystemWindows = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ||
|
||||||
preferences[navbarStyleKey] != NavbarStyle.TRANSPARENT
|
preferences[navbarStyleKey] != NavbarStyle.TRANSPARENT
|
||||||
if (!homeMenu.fitsSystemWindows) {
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || !ViewCompat.getFitsSystemWindows(homeMenu)) {
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(homeMenu, null)
|
ViewCompat.setOnApplyWindowInsetsListener(homeMenu, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -544,6 +541,12 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
return super.onKeyUp(keyCode, event)
|
return super.onKeyUp(keyCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun triggerRefresh(position: Int): Boolean {
|
||||||
|
val f = pagerAdapter.instantiateItem(mainPager, position)
|
||||||
|
if (f.activity == null || f.isDetached) return false
|
||||||
|
if (f !is RefreshScrollTopInterface) return false
|
||||||
|
return f.triggerRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
fun notifyAccountsChanged() {
|
fun notifyAccountsChanged() {
|
||||||
}
|
}
|
||||||
|
@ -553,11 +556,6 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
updateUnreadCount()
|
updateUnreadCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openSearchView(account: AccountDetails?) {
|
|
||||||
selectedAccountToSearch = account
|
|
||||||
onSearchRequested()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateUnreadCount() {
|
fun updateUnreadCount() {
|
||||||
if (mainTabs == null || updateUnreadCountTask != null && updateUnreadCountTask!!.status == AsyncTask.Status.RUNNING)
|
if (mainTabs == null || updateUnreadCountTask != null && updateUnreadCountTask!!.status == AsyncTask.Status.RUNNING)
|
||||||
return
|
return
|
||||||
|
@ -580,10 +578,10 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
if (mainTabs.columns > 1) {
|
if (mainTabs.columns > 1) {
|
||||||
val lp = actionsButton.layoutParams
|
val lp = actionsButton.layoutParams
|
||||||
val total: Float
|
val total: Float
|
||||||
if (lp is MarginLayoutParams) {
|
total = if (lp is MarginLayoutParams) {
|
||||||
total = (lp.bottomMargin + actionsButton.height).toFloat()
|
(lp.bottomMargin + actionsButton.height).toFloat()
|
||||||
} else {
|
} else {
|
||||||
total = actionsButton.height.toFloat()
|
actionsButton.height.toFloat()
|
||||||
}
|
}
|
||||||
return 1 - actionsButton.translationY / total
|
return 1 - actionsButton.translationY / total
|
||||||
}
|
}
|
||||||
|
@ -626,16 +624,15 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
return homeDrawerToggleDelegate
|
return homeDrawerToggleDelegate
|
||||||
}
|
}
|
||||||
|
|
||||||
private val keyboardShortcutRecipient: Fragment?
|
fun closeAccountsDrawer() {
|
||||||
get() {
|
if (homeMenu == null) return
|
||||||
if (homeMenu.isDrawerOpen(GravityCompat.START)) {
|
homeMenu.closeDrawers()
|
||||||
return leftDrawerFragment
|
}
|
||||||
} else if (homeMenu.isDrawerOpen(GravityCompat.END)) {
|
|
||||||
return null
|
private fun openSearchView(account: AccountDetails?) {
|
||||||
} else {
|
selectedAccountToSearch = account
|
||||||
return currentVisibleFragment
|
onSearchRequested()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
|
private fun handleFragmentKeyboardShortcutRepeat(handler: KeyboardShortcutsHandler,
|
||||||
keyCode: Int, repeatCount: Int,
|
keyCode: Int, repeatCount: Int,
|
||||||
|
@ -678,11 +675,10 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
if (Intent.ACTION_SEARCH == action) {
|
if (Intent.ACTION_SEARCH == action) {
|
||||||
val query = intent.getStringExtra(SearchManager.QUERY)
|
val query = intent.getStringExtra(SearchManager.QUERY)
|
||||||
val appSearchData = intent.getBundleExtra(SearchManager.APP_DATA)
|
val appSearchData = intent.getBundleExtra(SearchManager.APP_DATA)
|
||||||
val accountKey: UserKey?
|
val accountKey = if (appSearchData != null && appSearchData.containsKey(EXTRA_ACCOUNT_KEY)) {
|
||||||
if (appSearchData != null && appSearchData.containsKey(EXTRA_ACCOUNT_KEY)) {
|
appSearchData.getParcelable(EXTRA_ACCOUNT_KEY)
|
||||||
accountKey = appSearchData.getParcelable<UserKey>(EXTRA_ACCOUNT_KEY)
|
|
||||||
} else {
|
} else {
|
||||||
accountKey = Utils.getDefaultAccountKey(this)
|
Utils.getDefaultAccountKey(this)
|
||||||
}
|
}
|
||||||
IntentUtils.openSearch(this, accountKey, query)
|
IntentUtils.openSearch(this, accountKey, query)
|
||||||
return -1
|
return -1
|
||||||
|
@ -847,7 +843,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
val intent = Intent(this, UsageStatisticsActivity::class.java)
|
val intent = Intent(this, UsageStatisticsActivity::class.java)
|
||||||
val contentIntent = PendingIntent.getActivity(this, 0, intent, 0)
|
val contentIntent = PendingIntent.getActivity(this, 0, intent, 0)
|
||||||
val builder = NotificationCompat.Builder(this)
|
val builder = NotificationChannelSpec.appNotices.notificationBuilder(this)
|
||||||
builder.setAutoCancel(true)
|
builder.setAutoCancel(true)
|
||||||
builder.setSmallIcon(R.drawable.ic_stat_info)
|
builder.setSmallIcon(R.drawable.ic_stat_info)
|
||||||
builder.setTicker(getString(R.string.usage_statistics))
|
builder.setTicker(getString(R.string.usage_statistics))
|
||||||
|
@ -889,7 +885,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun hasMultiColumns(): Boolean {
|
private fun hasMultiColumns(): Boolean {
|
||||||
if (!DeviceUtils.isDeviceTablet(this) || !DeviceUtils.isScreenTablet(this)) return false
|
if (!DeviceUtils.isDeviceTablet(this) || !DeviceUtils.isScreenTablet(this)) return false
|
||||||
if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
|
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_landscape", resources.getBoolean(R.bool.default_multi_column_tabs_land))
|
||||||
|
@ -907,17 +903,20 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
|
|
||||||
private class UpdateUnreadCountTask(
|
private class UpdateUnreadCountTask(
|
||||||
private val context: Context,
|
context: Context,
|
||||||
private val preferences: SharedPreferences,
|
private val preferences: SharedPreferences,
|
||||||
private val readStateManager: ReadStateManager,
|
private val readStateManager: ReadStateManager,
|
||||||
private val indicator: TabPagerIndicator,
|
indicator: TabPagerIndicator,
|
||||||
private val tabs: Array<SupportTabSpec>
|
private val tabs: Array<SupportTabSpec>
|
||||||
) : AsyncTask<Any, UpdateUnreadCountTask.TabBadge, SparseIntArray>() {
|
) : AsyncTask<Any, UpdateUnreadCountTask.TabBadge, SparseIntArray>() {
|
||||||
|
|
||||||
private val activatedKeys = DataStoreUtils.getActivatedAccountKeys(context)
|
private val activatedKeys = DataStoreUtils.getActivatedAccountKeys(context)
|
||||||
|
private val contextRef = WeakReference(context)
|
||||||
|
private val indicatorRef = WeakReference(indicator)
|
||||||
|
|
||||||
override fun doInBackground(vararg params: Any): SparseIntArray {
|
override fun doInBackground(vararg params: Any): SparseIntArray {
|
||||||
val result = SparseIntArray()
|
val result = SparseIntArray()
|
||||||
|
val context = contextRef.get() ?: return result
|
||||||
tabs.forEachIndexed { i, spec ->
|
tabs.forEachIndexed { i, spec ->
|
||||||
if (spec.type == null) {
|
if (spec.type == null) {
|
||||||
publishProgress(TabBadge(i, -1))
|
publishProgress(TabBadge(i, -1))
|
||||||
|
@ -969,6 +968,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPostExecute(result: SparseIntArray) {
|
override fun onPostExecute(result: SparseIntArray) {
|
||||||
|
val indicator = indicatorRef.get() ?: return
|
||||||
indicator.clearBadge()
|
indicator.clearBadge()
|
||||||
for (i in 0 until result.size()) {
|
for (i in 0 until result.size()) {
|
||||||
indicator.setBadge(result.keyAt(i), result.valueAt(i))
|
indicator.setBadge(result.keyAt(i), result.valueAt(i))
|
||||||
|
@ -976,6 +976,7 @@ class HomeActivity : BaseActivity(), OnClickListener, OnPageChangeListener, Supp
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgressUpdate(vararg values: TabBadge) {
|
override fun onProgressUpdate(vararg values: TabBadge) {
|
||||||
|
val indicator = indicatorRef.get() ?: return
|
||||||
for (value in values) {
|
for (value in values) {
|
||||||
indicator.setBadge(value.index, value.count)
|
indicator.setBadge(value.index, value.count)
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,9 +35,6 @@ import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.Priority
|
import com.bumptech.glide.Priority
|
||||||
import com.bumptech.glide.load.resource.drawable.GlideDrawable
|
|
||||||
import com.bumptech.glide.request.RequestListener
|
|
||||||
import com.bumptech.glide.request.target.Target
|
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import nl.komponents.kovenant.Promise
|
import nl.komponents.kovenant.Promise
|
||||||
import org.mariotaku.chameleon.Chameleon
|
import org.mariotaku.chameleon.Chameleon
|
||||||
|
@ -52,7 +49,7 @@ import org.mariotaku.twidere.R
|
||||||
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
import org.mariotaku.twidere.TwidereConstants.SHARED_PREFERENCES_NAME
|
||||||
import org.mariotaku.twidere.activity.iface.IBaseActivity
|
import org.mariotaku.twidere.activity.iface.IBaseActivity
|
||||||
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_INTENT
|
import org.mariotaku.twidere.constant.IntentConstants.EXTRA_INTENT
|
||||||
import org.mariotaku.twidere.constant.lastLaunchPresentationTimeKey
|
import org.mariotaku.twidere.constant.lastLaunchTimeKey
|
||||||
import org.mariotaku.twidere.constant.promotionsEnabledKey
|
import org.mariotaku.twidere.constant.promotionsEnabledKey
|
||||||
import org.mariotaku.twidere.constant.themeColorKey
|
import org.mariotaku.twidere.constant.themeColorKey
|
||||||
import org.mariotaku.twidere.constant.themeKey
|
import org.mariotaku.twidere.constant.themeKey
|
||||||
|
@ -148,14 +145,14 @@ open class MainActivity : ChameleonActivity(), IBaseActivity<MainActivity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showPresentationOrLaunch() {
|
private fun showPresentationOrLaunch() {
|
||||||
val lastLaunchPresentationTime = preferences[lastLaunchPresentationTimeKey]
|
val lastLaunchTime = preferences[lastLaunchTimeKey]
|
||||||
val maximumDuration = if (BuildConfig.DEBUG) {
|
val maximumDuration = if (BuildConfig.DEBUG) {
|
||||||
TimeUnit.SECONDS.toMillis(30)
|
TimeUnit.SECONDS.toMillis(30)
|
||||||
} else {
|
} else {
|
||||||
TimeUnit.HOURS.toMillis(6)
|
TimeUnit.HOURS.toMillis(6)
|
||||||
}
|
}
|
||||||
// Show again at least 6 hours later (30 secs for debug builds)
|
// Show again at least 6 hours later (30 secs for debug builds)
|
||||||
if (lastLaunchPresentationTime >= 0 && System.currentTimeMillis() - lastLaunchPresentationTime < maximumDuration) {
|
if (lastLaunchTime >= 0 && System.currentTimeMillis() - lastLaunchTime < maximumDuration) {
|
||||||
launchDirectly()
|
launchDirectly()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -212,20 +209,6 @@ open class MainActivity : ChameleonActivity(), IBaseActivity<MainActivity> {
|
||||||
skipPresentation.visibility = View.VISIBLE
|
skipPresentation.visibility = View.VISIBLE
|
||||||
controlOverlay.tag = presentation
|
controlOverlay.tag = presentation
|
||||||
Glide.with(this).load(presentation.images.first().url)
|
Glide.with(this).load(presentation.images.first().url)
|
||||||
.listener(object : RequestListener<String, GlideDrawable> {
|
|
||||||
override fun onException(e: Exception?, model: String?,
|
|
||||||
target: Target<GlideDrawable>?, isFirstResource: Boolean): Boolean {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResourceReady(resource: GlideDrawable?, model: String?,
|
|
||||||
target: Target<GlideDrawable>?, isFromMemoryCache: Boolean,
|
|
||||||
isFirstResource: Boolean): Boolean {
|
|
||||||
preferences[lastLaunchPresentationTimeKey] = System.currentTimeMillis()
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
.priority(Priority.HIGH)
|
.priority(Priority.HIGH)
|
||||||
.into(presentationView)
|
.into(presentationView)
|
||||||
}
|
}
|
||||||
|
@ -245,6 +228,7 @@ open class MainActivity : ChameleonActivity(), IBaseActivity<MainActivity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performLaunch() {
|
private fun performLaunch() {
|
||||||
|
preferences[lastLaunchTimeKey] = System.currentTimeMillis()
|
||||||
val am = AccountManager.get(this)
|
val am = AccountManager.get(this)
|
||||||
if (!DeviceUtils.checkCompatibility()) {
|
if (!DeviceUtils.checkCompatibility()) {
|
||||||
startActivity(Intent(this, IncompatibleAlertActivity::class.java))
|
startActivity(Intent(this, IncompatibleAlertActivity::class.java))
|
||||||
|
|
|
@ -65,6 +65,8 @@ import org.mariotaku.twidere.util.kovenant.stopKovenant
|
||||||
import org.mariotaku.twidere.util.media.MediaPreloader
|
import org.mariotaku.twidere.util.media.MediaPreloader
|
||||||
import org.mariotaku.twidere.util.media.ThumborWrapper
|
import org.mariotaku.twidere.util.media.ThumborWrapper
|
||||||
import org.mariotaku.twidere.util.net.TwidereDns
|
import org.mariotaku.twidere.util.net.TwidereDns
|
||||||
|
import org.mariotaku.twidere.util.notification.ContentNotificationManager
|
||||||
|
import org.mariotaku.twidere.util.notification.NotificationChannelsManager
|
||||||
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
||||||
import org.mariotaku.twidere.util.refresh.AutoRefreshController
|
import org.mariotaku.twidere.util.refresh.AutoRefreshController
|
||||||
import org.mariotaku.twidere.util.sync.DataSyncProvider
|
import org.mariotaku.twidere.util.sync.DataSyncProvider
|
||||||
|
@ -132,6 +134,7 @@ class TwidereApplication : Application(), Constants, OnSharedPreferenceChangeLis
|
||||||
}
|
}
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
EmojioneTranslator.init(this)
|
EmojioneTranslator.init(this)
|
||||||
|
NotificationChannelsManager.createChannels(this)
|
||||||
applyLanguageSettings()
|
applyLanguageSettings()
|
||||||
startKovenant()
|
startKovenant()
|
||||||
initializeAsyncTask()
|
initializeAsyncTask()
|
||||||
|
|
|
@ -85,7 +85,7 @@ val homeRefreshDirectMessagesKey = KBooleanKey(KEY_HOME_REFRESH_DIRECT_MESSAGES,
|
||||||
val homeRefreshSavedSearchesKey = KBooleanKey(KEY_HOME_REFRESH_SAVED_SEARCHES, true)
|
val homeRefreshSavedSearchesKey = KBooleanKey(KEY_HOME_REFRESH_SAVED_SEARCHES, true)
|
||||||
val composeStatusVisibilityKey = KNullableStringKey("compose_status_visibility", null)
|
val composeStatusVisibilityKey = KNullableStringKey("compose_status_visibility", null)
|
||||||
val navbarStyleKey = KStringKey(KEY_NAVBAR_STYLE, NavbarStyle.DEFAULT)
|
val navbarStyleKey = KStringKey(KEY_NAVBAR_STYLE, NavbarStyle.DEFAULT)
|
||||||
val lastLaunchPresentationTimeKey = KLongKey("last_launch_presentation_time", -1)
|
val lastLaunchTimeKey = KLongKey("last_launch_time", -1)
|
||||||
val promotionsEnabledKey = KBooleanKey("promotions_enabled", false)
|
val promotionsEnabledKey = KBooleanKey("promotions_enabled", false)
|
||||||
|
|
||||||
object cacheSizeLimitKey : KSimpleKey<Int>(KEY_CACHE_SIZE_LIMIT, 300) {
|
object cacheSizeLimitKey : KSimpleKey<Int>(KEY_CACHE_SIZE_LIMIT, 300) {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Twidere - Twitter client for Android
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2017 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.extension.model
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.support.v4.app.NotificationCompat
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2017/8/25.
|
||||||
|
*/
|
||||||
|
fun NotificationChannelSpec.notificationBuilder(context: Context): NotificationCompat.Builder {
|
||||||
|
return NotificationCompat.Builder(context, id)
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/*
|
||||||
|
* Twidere - Twitter client for Android
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2017 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.model.notification
|
||||||
|
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.support.annotation.StringRes
|
||||||
|
import org.mariotaku.twidere.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2017/8/25.
|
||||||
|
*/
|
||||||
|
enum class NotificationChannelSpec(
|
||||||
|
val id: String,
|
||||||
|
@StringRes val nameRes: Int,
|
||||||
|
@StringRes val descriptionRes: Int = 0,
|
||||||
|
val importance: Int,
|
||||||
|
val showBadge: Boolean = false) {
|
||||||
|
/**
|
||||||
|
* For notifications send by app itself.
|
||||||
|
* Such as "what's new"
|
||||||
|
*/
|
||||||
|
appNotices("app_notices", R.string.notification_channel_name_app_notices,
|
||||||
|
importance = NotificationManager.IMPORTANCE_LOW, showBadge = true),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For notifications indicate that some lengthy operations are performing in the background.
|
||||||
|
* Such as sending attachment process.
|
||||||
|
*/
|
||||||
|
backgroundProgresses("background_progresses", R.string.notification_channel_name_background_progresses,
|
||||||
|
importance = NotificationManager.IMPORTANCE_MIN),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For ongoing notifications indicating service statuses.
|
||||||
|
* Such as notification showing streaming service running
|
||||||
|
*/
|
||||||
|
serviceStatuses("service_statuses", R.string.notification_channel_name_service_statuses,
|
||||||
|
importance = NotificationManager.IMPORTANCE_MIN),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For import notifications related to micro-blogging features.
|
||||||
|
* Such as failure to update status.
|
||||||
|
*/
|
||||||
|
contentNotices("content_notices", R.string.notification_channel_name_content_notices,
|
||||||
|
importance = NotificationManager.IMPORTANCE_HIGH, showBadge = true),
|
||||||
|
/**
|
||||||
|
* For updates related to micro-blogging features.
|
||||||
|
* Such as new statuses posted by friends.
|
||||||
|
*/
|
||||||
|
contentUpdates("content_updates", R.string.notification_channel_name_content_updates,
|
||||||
|
importance = NotificationManager.IMPORTANCE_DEFAULT, showBadge = true),
|
||||||
|
/**
|
||||||
|
* For updates related to micro-blogging features.
|
||||||
|
* Such as new statuses posted by friends user subscribed to.
|
||||||
|
*/
|
||||||
|
contentSubscriptions("content_subscriptions", R.string.notification_channel_name_content_subscriptions,
|
||||||
|
importance = NotificationManager.IMPORTANCE_HIGH, showBadge = true),
|
||||||
|
/**
|
||||||
|
* For interactions related to micro-blogging features.
|
||||||
|
* Such as replies and likes.
|
||||||
|
*/
|
||||||
|
contentInteractions("content_interactions", R.string.notification_channel_name_content_interactions,
|
||||||
|
descriptionRes = R.string.notification_channel_description_content_interactions,
|
||||||
|
importance = NotificationManager.IMPORTANCE_HIGH, showBadge = true),
|
||||||
|
/**
|
||||||
|
* For messages related to micro-blogging features.
|
||||||
|
* Such as direct messages.
|
||||||
|
*/
|
||||||
|
contentMessages("content_messages", R.string.notification_channel_name_content_messages,
|
||||||
|
descriptionRes = R.string.notification_channel_description_content_messages,
|
||||||
|
importance = NotificationManager.IMPORTANCE_HIGH, showBadge = true)
|
||||||
|
|
||||||
|
}
|
|
@ -54,6 +54,7 @@ import org.mariotaku.twidere.util.SQLiteDatabaseWrapper.LazyLoadCallback
|
||||||
import org.mariotaku.twidere.util.dagger.GeneralComponent
|
import org.mariotaku.twidere.util.dagger.GeneralComponent
|
||||||
import org.mariotaku.twidere.util.database.CachedUsersQueryBuilder
|
import org.mariotaku.twidere.util.database.CachedUsersQueryBuilder
|
||||||
import org.mariotaku.twidere.util.database.SuggestionsCursorCreator
|
import org.mariotaku.twidere.util.database.SuggestionsCursorCreator
|
||||||
|
import org.mariotaku.twidere.util.notification.ContentNotificationManager
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.twitter.Extractor
|
||||||
import com.twitter.Validator
|
import com.twitter.Validator
|
||||||
import org.mariotaku.twidere.util.*
|
import org.mariotaku.twidere.util.*
|
||||||
import org.mariotaku.twidere.util.dagger.GeneralComponent
|
import org.mariotaku.twidere.util.dagger.GeneralComponent
|
||||||
|
import org.mariotaku.twidere.util.notification.ContentNotificationManager
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
abstract class BaseService : Service() {
|
abstract class BaseService : Service() {
|
||||||
|
|
|
@ -23,16 +23,13 @@ import android.accounts.AccountManager
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.Notification
|
import android.app.Notification
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.ContentValues
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.provider.BaseColumns
|
|
||||||
import android.support.annotation.UiThread
|
import android.support.annotation.UiThread
|
||||||
import android.support.annotation.WorkerThread
|
import android.support.annotation.WorkerThread
|
||||||
import android.support.v4.app.NotificationCompat
|
import android.support.v4.app.NotificationCompat
|
||||||
import android.support.v4.app.NotificationCompat.Builder
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
@ -41,7 +38,6 @@ import nl.komponents.kovenant.ui.successUi
|
||||||
import org.mariotaku.abstask.library.AbstractTask
|
import org.mariotaku.abstask.library.AbstractTask
|
||||||
import org.mariotaku.abstask.library.ManualTaskStarter
|
import org.mariotaku.abstask.library.ManualTaskStarter
|
||||||
import org.mariotaku.kpreferences.get
|
import org.mariotaku.kpreferences.get
|
||||||
import org.mariotaku.ktextension.configure
|
|
||||||
import org.mariotaku.ktextension.getNullableTypedArrayExtra
|
import org.mariotaku.ktextension.getNullableTypedArrayExtra
|
||||||
import org.mariotaku.ktextension.toLongOr
|
import org.mariotaku.ktextension.toLongOr
|
||||||
import org.mariotaku.ktextension.useCursor
|
import org.mariotaku.ktextension.useCursor
|
||||||
|
@ -58,9 +54,12 @@ import org.mariotaku.twidere.R
|
||||||
import org.mariotaku.twidere.TwidereConstants.*
|
import org.mariotaku.twidere.TwidereConstants.*
|
||||||
import org.mariotaku.twidere.constant.refreshAfterTweetKey
|
import org.mariotaku.twidere.constant.refreshAfterTweetKey
|
||||||
import org.mariotaku.twidere.extension.getErrorMessage
|
import org.mariotaku.twidere.extension.getErrorMessage
|
||||||
|
import org.mariotaku.twidere.extension.model.notificationBuilder
|
||||||
|
import org.mariotaku.twidere.extension.withAppendedPath
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
import org.mariotaku.twidere.model.draft.SendDirectMessageActionExtras
|
||||||
import org.mariotaku.twidere.model.draft.StatusObjectActionExtras
|
import org.mariotaku.twidere.model.draft.StatusObjectActionExtras
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
import org.mariotaku.twidere.model.schedule.ScheduleInfo
|
import org.mariotaku.twidere.model.schedule.ScheduleInfo
|
||||||
import org.mariotaku.twidere.model.util.AccountUtils
|
import org.mariotaku.twidere.model.util.AccountUtils
|
||||||
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
import org.mariotaku.twidere.model.util.ParcelableStatusUpdateUtils
|
||||||
|
@ -183,7 +182,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
|
||||||
|
|
||||||
private fun sendMessage(message: ParcelableNewMessage) {
|
private fun sendMessage(message: ParcelableNewMessage) {
|
||||||
val title = getString(R.string.sending_direct_message)
|
val title = getString(R.string.sending_direct_message)
|
||||||
val builder = Builder(this)
|
val builder = NotificationChannelSpec.backgroundProgresses.notificationBuilder(this)
|
||||||
builder.setSmallIcon(R.drawable.ic_stat_send)
|
builder.setSmallIcon(R.drawable.ic_stat_send)
|
||||||
builder.setProgress(100, 0, true)
|
builder.setProgress(100, 0, true)
|
||||||
builder.setTicker(title)
|
builder.setTicker(title)
|
||||||
|
@ -239,7 +238,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
|
||||||
|
|
||||||
private fun updateStatuses(statuses: Array<ParcelableStatusUpdate>, scheduleInfo: ScheduleInfo? = null) {
|
private fun updateStatuses(statuses: Array<ParcelableStatusUpdate>, scheduleInfo: ScheduleInfo? = null) {
|
||||||
val context = this
|
val context = this
|
||||||
val builder = Builder(context)
|
val builder = NotificationChannelSpec.backgroundProgresses.notificationBuilder(context)
|
||||||
startForeground(NOTIFICATION_ID_UPDATE_STATUS, updateUpdateStatusNotification(context,
|
startForeground(NOTIFICATION_ID_UPDATE_STATUS, updateUpdateStatusNotification(context,
|
||||||
builder, 0, null))
|
builder, 0, null))
|
||||||
for (item in statuses) {
|
for (item in statuses) {
|
||||||
|
@ -321,9 +320,7 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") {
|
||||||
invokeAfterExecute(task, result)
|
invokeAfterExecute(task, result)
|
||||||
|
|
||||||
if (!result.succeed) {
|
if (!result.succeed) {
|
||||||
contentResolver.insert(Drafts.CONTENT_URI_NOTIFICATIONS, configure(ContentValues()) {
|
contentResolver.insert(Drafts.CONTENT_URI_NOTIFICATIONS.withAppendedPath(result.draftId.toString()), null)
|
||||||
put(BaseColumns._ID, result.draftId)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (preferences[refreshAfterTweetKey]) {
|
if (preferences[refreshAfterTweetKey]) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.mariotaku.twidere.extension.model.api.key
|
||||||
import org.mariotaku.twidere.extension.model.api.microblog.toParcelable
|
import org.mariotaku.twidere.extension.model.api.microblog.toParcelable
|
||||||
import org.mariotaku.twidere.extension.model.api.toParcelable
|
import org.mariotaku.twidere.extension.model.api.toParcelable
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
import org.mariotaku.twidere.model.pagination.SinceMaxPagination
|
||||||
import org.mariotaku.twidere.model.util.AccountUtils
|
import org.mariotaku.twidere.model.util.AccountUtils
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||||
|
@ -172,7 +173,7 @@ class StreamingService : BaseService() {
|
||||||
val contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
val contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||||
val contentTitle = getString(R.string.app_name)
|
val contentTitle = getString(R.string.app_name)
|
||||||
val contentText = getString(R.string.timeline_streaming_running)
|
val contentText = getString(R.string.timeline_streaming_running)
|
||||||
val builder = NotificationCompat.Builder(this)
|
val builder = NotificationChannelSpec.serviceStatuses.notificationBuilder(this)
|
||||||
builder.setOngoing(true)
|
builder.setOngoing(true)
|
||||||
builder.setSmallIcon(R.drawable.ic_stat_streaming)
|
builder.setSmallIcon(R.drawable.ic_stat_streaming)
|
||||||
builder.setContentTitle(contentTitle)
|
builder.setContentTitle(contentTitle)
|
||||||
|
|
|
@ -58,6 +58,7 @@ import org.mariotaku.twidere.util.media.MediaPreloader
|
||||||
import org.mariotaku.twidere.util.media.ThumborWrapper
|
import org.mariotaku.twidere.util.media.ThumborWrapper
|
||||||
import org.mariotaku.twidere.util.media.TwidereMediaDownloader
|
import org.mariotaku.twidere.util.media.TwidereMediaDownloader
|
||||||
import org.mariotaku.twidere.util.net.TwidereDns
|
import org.mariotaku.twidere.util.net.TwidereDns
|
||||||
|
import org.mariotaku.twidere.util.notification.ContentNotificationManager
|
||||||
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
import org.mariotaku.twidere.util.premium.ExtraFeaturesService
|
||||||
import org.mariotaku.twidere.util.refresh.AutoRefreshController
|
import org.mariotaku.twidere.util.refresh.AutoRefreshController
|
||||||
import org.mariotaku.twidere.util.refresh.JobSchedulerAutoRefreshController
|
import org.mariotaku.twidere.util.refresh.JobSchedulerAutoRefreshController
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.mariotaku.twidere.util
|
package org.mariotaku.twidere.util.notification
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
|
@ -48,21 +48,22 @@ import org.mariotaku.twidere.constant.nameFirstKey
|
||||||
import org.mariotaku.twidere.extension.model.api.formattedTextWithIndices
|
import org.mariotaku.twidere.extension.model.api.formattedTextWithIndices
|
||||||
import org.mariotaku.twidere.extension.model.getSummaryText
|
import org.mariotaku.twidere.extension.model.getSummaryText
|
||||||
import org.mariotaku.twidere.extension.model.getTitle
|
import org.mariotaku.twidere.extension.model.getTitle
|
||||||
|
import org.mariotaku.twidere.extension.model.notificationBuilder
|
||||||
import org.mariotaku.twidere.extension.model.notificationDisabled
|
import org.mariotaku.twidere.extension.model.notificationDisabled
|
||||||
import org.mariotaku.twidere.extension.rawQuery
|
import org.mariotaku.twidere.extension.rawQuery
|
||||||
import org.mariotaku.twidere.model.*
|
import org.mariotaku.twidere.model.*
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
import org.mariotaku.twidere.model.util.ParcelableActivityUtils
|
import org.mariotaku.twidere.model.util.ParcelableActivityUtils
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
import org.mariotaku.twidere.provider.TwidereDataStore.*
|
||||||
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
import org.mariotaku.twidere.provider.TwidereDataStore.Messages.Conversations
|
||||||
import org.mariotaku.twidere.receiver.NotificationReceiver
|
import org.mariotaku.twidere.receiver.NotificationReceiver
|
||||||
import org.mariotaku.twidere.service.LengthyOperationsService
|
import org.mariotaku.twidere.service.LengthyOperationsService
|
||||||
|
import org.mariotaku.twidere.util.*
|
||||||
|
import org.mariotaku.twidere.util.Utils
|
||||||
import org.mariotaku.twidere.util.database.FilterQueryBuilder
|
import org.mariotaku.twidere.util.database.FilterQueryBuilder
|
||||||
import org.oshkimaadziig.george.androidutils.SpanFormatter
|
import org.oshkimaadziig.george.androidutils.SpanFormatter
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by mariotaku on 2017/2/16.
|
|
||||||
*/
|
|
||||||
class ContentNotificationManager(
|
class ContentNotificationManager(
|
||||||
val context: Context,
|
val context: Context,
|
||||||
val activityTracker: ActivityTracker,
|
val activityTracker: ActivityTracker,
|
||||||
|
@ -134,7 +135,7 @@ class ContentNotificationManager(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup notification
|
// Setup notification
|
||||||
val builder = NotificationCompat.Builder(context)
|
val builder = NotificationChannelSpec.contentUpdates.notificationBuilder(context)
|
||||||
builder.setAutoCancel(true)
|
builder.setAutoCancel(true)
|
||||||
builder.setSmallIcon(R.drawable.ic_stat_twitter)
|
builder.setSmallIcon(R.drawable.ic_stat_twitter)
|
||||||
builder.setTicker(notificationTitle)
|
builder.setTicker(notificationTitle)
|
||||||
|
@ -175,7 +176,7 @@ class ContentNotificationManager(
|
||||||
@SuppressLint("Recycle")
|
@SuppressLint("Recycle")
|
||||||
val c = cr.query(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS, where, whereArgs,
|
val c = cr.query(Activities.AboutMe.CONTENT_URI, Activities.COLUMNS, where, whereArgs,
|
||||||
OrderBy(Activities.TIMESTAMP, false).sql) ?: return
|
OrderBy(Activities.TIMESTAMP, false).sql) ?: return
|
||||||
val builder = NotificationCompat.Builder(context)
|
val builder = NotificationChannelSpec.contentInteractions.notificationBuilder(context)
|
||||||
val pebbleNotificationStringBuilder = StringBuilder()
|
val pebbleNotificationStringBuilder = StringBuilder()
|
||||||
try {
|
try {
|
||||||
val count = c.count
|
val count = c.count
|
||||||
|
@ -277,18 +278,18 @@ class ContentNotificationManager(
|
||||||
|
|
||||||
var messageSum: Int = 0
|
var messageSum: Int = 0
|
||||||
var newLastReadTimestamp = -1L
|
var newLastReadTimestamp = -1L
|
||||||
cur.forEachRow { cur, _ ->
|
cur.forEachRow { c, _ ->
|
||||||
val unreadCount = cur.getInt(indices[Conversations.UNREAD_COUNT])
|
val unreadCount = c.getInt(indices[Conversations.UNREAD_COUNT])
|
||||||
if (unreadCount <= 0) return@forEachRow false
|
if (unreadCount <= 0) return@forEachRow false
|
||||||
if (newLastReadTimestamp != -1L) {
|
if (newLastReadTimestamp != -1L) {
|
||||||
newLastReadTimestamp = cur.getLong(indices[Conversations.LAST_READ_TIMESTAMP])
|
newLastReadTimestamp = c.getLong(indices[Conversations.LAST_READ_TIMESTAMP])
|
||||||
}
|
}
|
||||||
messageSum += unreadCount
|
messageSum += unreadCount
|
||||||
return@forEachRow true
|
return@forEachRow true
|
||||||
}
|
}
|
||||||
if (messageSum == 0) return
|
if (messageSum == 0) return
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(context)
|
val builder = NotificationChannelSpec.contentMessages.notificationBuilder(context)
|
||||||
applyNotificationPreferences(builder, pref, pref.directMessagesNotificationType)
|
applyNotificationPreferences(builder, pref, pref.directMessagesNotificationType)
|
||||||
builder.setSmallIcon(R.drawable.ic_stat_message)
|
builder.setSmallIcon(R.drawable.ic_stat_message)
|
||||||
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
builder.setCategory(NotificationCompat.CATEGORY_SOCIAL)
|
||||||
|
@ -305,8 +306,8 @@ class ContentNotificationManager(
|
||||||
builder.setDeleteIntent(getMarkReadDeleteIntent(context, NotificationType.DIRECT_MESSAGES,
|
builder.setDeleteIntent(getMarkReadDeleteIntent(context, NotificationType.DIRECT_MESSAGES,
|
||||||
accountKey, newLastReadTimestamp, false))
|
accountKey, newLastReadTimestamp, false))
|
||||||
|
|
||||||
val remaining = cur.forEachRow(5) { cur, pos ->
|
val remaining = cur.forEachRow(5) { c, pos ->
|
||||||
val conversation = indices.newObject(cur)
|
val conversation = indices.newObject(c)
|
||||||
if (conversation.notificationDisabled) return@forEachRow false
|
if (conversation.notificationDisabled) return@forEachRow false
|
||||||
val title = conversation.getTitle(context, userColorNameManager, nameFirst)
|
val title = conversation.getTitle(context, userColorNameManager, nameFirst)
|
||||||
val summary = conversation.getSummaryText(context, userColorNameManager, nameFirst)
|
val summary = conversation.getSummaryText(context, userColorNameManager, nameFirst)
|
||||||
|
@ -336,7 +337,7 @@ class ContentNotificationManager(
|
||||||
val userDisplayName = userColorNameManager.getDisplayName(status.user,
|
val userDisplayName = userColorNameManager.getDisplayName(status.user,
|
||||||
preferences[nameFirstKey])
|
preferences[nameFirstKey])
|
||||||
val statusUri = LinkCreator.getTwidereStatusLink(accountKey, status.id)
|
val statusUri = LinkCreator.getTwidereStatusLink(accountKey, status.id)
|
||||||
val builder = NotificationCompat.Builder(context)
|
val builder = NotificationChannelSpec.contentSubscriptions.notificationBuilder(context)
|
||||||
builder.color = userColorNameManager.getUserColor(userKey)
|
builder.color = userColorNameManager.getUserColor(userKey)
|
||||||
builder.setAutoCancel(true)
|
builder.setAutoCancel(true)
|
||||||
builder.setWhen(status.createdAt?.time ?: 0)
|
builder.setWhen(status.createdAt?.time ?: 0)
|
||||||
|
@ -381,7 +382,7 @@ class ContentNotificationManager(
|
||||||
uriBuilder.scheme(SCHEME_TWIDERE)
|
uriBuilder.scheme(SCHEME_TWIDERE)
|
||||||
uriBuilder.authority(AUTHORITY_DRAFTS)
|
uriBuilder.authority(AUTHORITY_DRAFTS)
|
||||||
intent.data = uriBuilder.build()
|
intent.data = uriBuilder.build()
|
||||||
val nb = NotificationCompat.Builder(context)
|
val nb = NotificationChannelSpec.contentNotices.notificationBuilder(context)
|
||||||
nb.setTicker(message)
|
nb.setTicker(message)
|
||||||
nb.setContentTitle(title)
|
nb.setContentTitle(title)
|
||||||
nb.setContentText(item.text)
|
nb.setContentText(item.text)
|
||||||
|
@ -401,7 +402,6 @@ class ContentNotificationManager(
|
||||||
PendingIntent.getService(context, 0, sendIntent, PendingIntent.FLAG_ONE_SHOT))
|
PendingIntent.getService(context, 0, sendIntent, PendingIntent.FLAG_ONE_SHOT))
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
|
||||||
nb.setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT))
|
nb.setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT))
|
||||||
nb.setGroup("drafts")
|
|
||||||
notificationManager.notify(draftUri.toString(), NOTIFICATION_ID_DRAFTS, nb.build())
|
notificationManager.notify(draftUri.toString(), NOTIFICATION_ID_DRAFTS, nb.build())
|
||||||
return draftId
|
return draftId
|
||||||
}
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Twidere - Twitter client for Android
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2017 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.util.notification
|
||||||
|
|
||||||
|
import android.annotation.TargetApi
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationChannelGroup
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import org.mariotaku.kpreferences.get
|
||||||
|
import org.mariotaku.twidere.constant.nameFirstKey
|
||||||
|
import org.mariotaku.twidere.model.AccountDetails
|
||||||
|
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
|
||||||
|
import org.mariotaku.twidere.util.dagger.DependencyHolder
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by mariotaku on 2017/8/25.
|
||||||
|
*/
|
||||||
|
object NotificationChannelsManager {
|
||||||
|
fun createChannels(context: Context) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
|
NotificationChannelCreatorImpl.createChannels(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createAccountGroup(context: Context, account: AccountDetails) {
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return
|
||||||
|
NotificationChannelCreatorImpl.createAccountGroup(context, account)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TargetApi(Build.VERSION_CODES.O)
|
||||||
|
private object NotificationChannelCreatorImpl {
|
||||||
|
|
||||||
|
fun createChannels(context: Context) {
|
||||||
|
val nm = context.getSystemService(NotificationManager::class.java)
|
||||||
|
val values = NotificationChannelSpec.values()
|
||||||
|
nm.notificationChannels.filterNot { channel ->
|
||||||
|
values.any { channel.id == it.id }
|
||||||
|
}.forEach {
|
||||||
|
nm.deleteNotificationChannel(it.id)
|
||||||
|
}
|
||||||
|
for (spec in values) {
|
||||||
|
val channel = NotificationChannel(spec.id, context.getString(spec.nameRes), spec.importance)
|
||||||
|
if (spec.descriptionRes != 0) {
|
||||||
|
channel.description = context.getString(spec.descriptionRes)
|
||||||
|
}
|
||||||
|
channel.setShowBadge(spec.showBadge)
|
||||||
|
nm.createNotificationChannel(channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createAccountGroup(context: Context, account: AccountDetails) {
|
||||||
|
val nm = context.getSystemService(NotificationManager::class.java)
|
||||||
|
val holder = DependencyHolder.get(context)
|
||||||
|
val pref = holder.preferences
|
||||||
|
val ucnm = holder.userColorNameManager
|
||||||
|
val group = NotificationChannelGroup(account.key.toString(),
|
||||||
|
ucnm.getDisplayName(account.user, pref[nameFirstKey]))
|
||||||
|
nm.createNotificationChannelGroup(group)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,6 +44,7 @@
|
||||||
<!-- [verb] Action for deleting a file or a twitter object like tweet-->
|
<!-- [verb] Action for deleting a file or a twitter object like tweet-->
|
||||||
<string name="action_delete">Delete</string>
|
<string name="action_delete">Delete</string>
|
||||||
<string name="action_delete_messages">Delete messages</string>
|
<string name="action_delete_messages">Delete messages</string>
|
||||||
|
<string name="action_disable_promotions">Disable promotions</string>
|
||||||
<string name="action_dont_restart">Don\'t restart</string>
|
<string name="action_dont_restart">Don\'t restart</string>
|
||||||
<string name="action_dont_terminate">Don\'t quit</string>
|
<string name="action_dont_terminate">Don\'t quit</string>
|
||||||
<!-- [verb] Edit image/settings etc. -->
|
<!-- [verb] Edit image/settings etc. -->
|
||||||
|
@ -769,6 +770,16 @@
|
||||||
|
|
||||||
<string name="none">None</string>
|
<string name="none">None</string>
|
||||||
|
|
||||||
|
<string name="notification_channel_description_content_interactions">Interactions like mentions and retweets</string>
|
||||||
|
<string name="notification_channel_description_content_messages">Important messages like DMs</string>
|
||||||
|
<string name="notification_channel_name_app_notices">App notices</string>
|
||||||
|
<string name="notification_channel_name_background_progresses">Background operations</string>
|
||||||
|
<string name="notification_channel_name_content_interactions">Content interactions</string>
|
||||||
|
<string name="notification_channel_name_content_messages">Content messages</string>
|
||||||
|
<string name="notification_channel_name_content_notices">Content notices</string>
|
||||||
|
<string name="notification_channel_name_content_subscriptions">Content subscriptions</string>
|
||||||
|
<string name="notification_channel_name_content_updates">Content updates</string>
|
||||||
|
<string name="notification_channel_name_service_statuses">Service statuses</string>
|
||||||
<string name="notification_direct_message"><xliff:g id="user">%s</xliff:g> sent you a direct message.</string>
|
<string name="notification_direct_message"><xliff:g id="user">%s</xliff:g> sent you a direct message.</string>
|
||||||
<string name="notification_direct_message_multiple_messages"><xliff:g id="user">%1$s</xliff:g> sent you <xliff:g id="messages_count">%2$d</xliff:g> direct messages.</string>
|
<string name="notification_direct_message_multiple_messages"><xliff:g id="user">%1$s</xliff:g> sent you <xliff:g id="messages_count">%2$d</xliff:g> direct messages.</string>
|
||||||
<string name="notification_direct_message_multiple_users"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="users_count">%2$d</xliff:g> others sent you <xliff:g id="messages_count">%3$d</xliff:g> direct messages.</string>
|
<string name="notification_direct_message_multiple_users"><xliff:g id="user">%1$s</xliff:g> and <xliff:g id="users_count">%2$d</xliff:g> others sent you <xliff:g id="messages_count">%3$d</xliff:g> direct messages.</string>
|
||||||
|
@ -1329,5 +1340,4 @@
|
||||||
<string name="users_blocked">Blocked these users.</string>
|
<string name="users_blocked">Blocked these users.</string>
|
||||||
<string name="users_lists_with_name"><xliff:g id="name">%s</xliff:g>\'s lists</string>
|
<string name="users_lists_with_name"><xliff:g id="name">%s</xliff:g>\'s lists</string>
|
||||||
<string name="users_statuses">User\'s tweets</string>
|
<string name="users_statuses">User\'s tweets</string>
|
||||||
<string name="action_disable_promotions">Disable promotions</string>
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue