distinguished incoming and outgoing message with color

supported notification channel settings on Android 8.0
This commit is contained in:
Mariotaku Lee 2017-08-30 20:17:55 +08:00
parent b4224b099d
commit 20d014e370
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
12 changed files with 248 additions and 95 deletions

View File

@ -20,14 +20,19 @@
package org.mariotaku.twidere.adapter
import android.content.Context
import android.content.res.ColorStateList
import android.support.v4.graphics.ColorUtils
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bumptech.glide.RequestManager
import org.apache.commons.lang3.time.DateUtils
import org.mariotaku.chameleon.Chameleon
import org.mariotaku.chameleon.ChameleonUtils
import org.mariotaku.kpreferences.get
import org.mariotaku.library.objectcursor.ObjectCursor
import org.mariotaku.twidere.R
import org.mariotaku.twidere.adapter.iface.IItemCountsAdapter
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter
import org.mariotaku.twidere.annotation.PreviewStyle
@ -40,6 +45,7 @@ import org.mariotaku.twidere.model.*
import org.mariotaku.twidere.model.ParcelableMessage.MessageType
import org.mariotaku.twidere.provider.TwidereDataStore.Messages
import org.mariotaku.twidere.util.DirectMessageOnLinkClickHandler
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.util.TwidereLinkify
import org.mariotaku.twidere.view.CardMediaContainer.OnMediaClickListener
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder
@ -78,6 +84,9 @@ class MessagesConversationAdapter(
var listener: Listener? = null
var displaySenderProfile: Boolean = false
val bubbleColorOutgoing: ColorStateList? = ThemeUtils.getColorStateListFromAttribute(context, R.attr.messageBubbleColor)
val bubbleColorIncoming: ColorStateList? = context.getIncomingMessageColor()
override var loadMoreIndicatorPosition: Long
get() = super.loadMoreIndicatorPosition
set(value) {
@ -213,6 +222,19 @@ class MessagesConversationAdapter(
private const val ITEM_TYPE_STICKER_MESSAGE = 2
private const val ITEM_TYPE_NOTICE_MESSAGE = 3
private const val ITEM_LOAD_OLDER_INDICATOR = 4
private fun Context.getIncomingMessageColor(): ColorStateList {
val foregroundColor = ThemeUtils.getColorForeground(this)
val themeColor = Chameleon.getOverrideTheme(this, ChameleonUtils.getActivity(this)).colorAccent
val normalColor = ThemeUtils.getOptimalAccentColor(themeColor, foregroundColor)
val pressedColor = if (ColorUtils.calculateLuminance(normalColor) < 0.1) {
ColorUtils.compositeColors(0x20FFFFFF, normalColor)
} else {
ColorUtils.compositeColors(0x20000000, normalColor)
}
return ColorStateList(arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf(0)),
intArrayOf(pressedColor, normalColor))
}
}

View File

@ -41,3 +41,12 @@ fun UserKey.notificationChannelId(id: String): String {
fun UserKey.notificationChannelGroupId(): String {
return Uri.encode(toString())
}
fun NotificationChannelSpec.getName(context: Context): String {
return context.getString(nameRes)
}
fun NotificationChannelSpec.getDescription(context: Context): String? {
if (descriptionRes == 0) return null
return context.getString(descriptionRes)
}

View File

@ -22,6 +22,7 @@ package org.mariotaku.twidere.fragment
import android.os.Bundle
import org.mariotaku.twidere.R
import org.mariotaku.twidere.constant.SharedPreferenceConstants.*
import org.mariotaku.twidere.preference.notification.AccountNotificationChannelsPreference
class AccountNotificationSettingsFragment : BaseAccountPreferenceFragment() {
@ -36,11 +37,13 @@ class AccountNotificationSettingsFragment : BaseAccountPreferenceFragment() {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
val preference = findPreference(KEY_NOTIFICATION_LIGHT_COLOR)
val account = account
if (preference != null && account != null) {
preference.setDefaultValue(account.color)
val account = this.account
findPreference(KEY_NOTIFICATION_LIGHT_COLOR)?.let {
if (account != null) {
it.setDefaultValue(account.color)
}
}
(findPreference("notification_channels") as? AccountNotificationChannelsPreference)?.account = account
}
}

View File

@ -59,12 +59,14 @@ enum class NotificationChannelSpec(
* Such as new statuses posted by friends.
*/
contentUpdates("content_updates", R.string.notification_channel_name_content_updates,
descriptionRes = R.string.notification_channel_descriptions_content_updates,
importance = NotificationManager.IMPORTANCE_DEFAULT, showBadge = true, grouped = 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,
descriptionRes = R.string.notification_channel_descriptions_content_subscriptions,
importance = NotificationManager.IMPORTANCE_HIGH, showBadge = true, grouped = true),
/**
* For interactions related to micro-blogging features.

View File

@ -20,6 +20,7 @@
package org.mariotaku.twidere.preference
import android.accounts.AccountManager
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
@ -93,7 +94,7 @@ abstract class AccountsListPreference(context: Context, attrs: AttributeSet? = n
switchPreference = context.getSharedPreferences(switchPreferenceName, Context.MODE_PRIVATE)
switchPreference.registerOnSharedPreferenceChangeListener(this)
title = account.user.name
summary = String.format("@%s", account.user.screen_name)
summary = "@${account.user.screen_name}"
widgetLayoutResource = R.layout.layout_preference_switch_indicator
}
@ -102,17 +103,17 @@ abstract class AccountsListPreference(context: Context, attrs: AttributeSet? = n
}
@SuppressLint("RestrictedApi")
override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder)
val iconView = holder.findViewById(android.R.id.icon)
if (iconView is PreferenceImageView) {
val imageView = iconView
val maxSize = context.resources.getDimensionPixelSize(R.dimen.element_size_normal)
imageView.minimumWidth = maxSize
imageView.minimumHeight = maxSize
imageView.maxWidth = maxSize
imageView.maxHeight = maxSize
imageView.scaleType = ImageView.ScaleType.CENTER_CROP
iconView.minimumWidth = maxSize
iconView.minimumHeight = maxSize
iconView.maxWidth = maxSize
iconView.maxHeight = maxSize
iconView.scaleType = ImageView.ScaleType.CENTER_CROP
}
val titleView = holder.findViewById(android.R.id.title)
if (titleView is TextView) {

View File

@ -0,0 +1,66 @@
/*
* 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.preference.notification
import android.annotation.TargetApi
import android.content.Context
import android.content.Intent
import android.os.Build
import android.provider.Settings
import android.support.v7.preference.Preference
import android.support.v7.preference.PreferenceManager
import android.util.AttributeSet
import org.mariotaku.twidere.BuildConfig
import org.mariotaku.twidere.extension.model.getDescription
import org.mariotaku.twidere.extension.model.getName
import org.mariotaku.twidere.extension.model.notificationChannelId
import org.mariotaku.twidere.model.AccountDetails
import org.mariotaku.twidere.model.notification.NotificationChannelSpec
import org.mariotaku.twidere.preference.TintedPreferenceCategory
@TargetApi(Build.VERSION_CODES.O)
class AccountNotificationChannelsPreference(context: Context, attrs: AttributeSet? = null) : TintedPreferenceCategory(context, attrs) {
var account: AccountDetails? = null
override fun onAttachedToHierarchy(preferenceManager: PreferenceManager?) {
super.onAttachedToHierarchy(preferenceManager)
initItems()
}
private fun initItems() {
removeAll()
val specs = NotificationChannelSpec.values().filter { it.grouped }.sortedBy { it.getName(context) }
specs.forEach { spec ->
val preference = Preference(context)
preference.title = spec.getName(context)
preference.summary = spec.getDescription(context)
preference.setOnPreferenceClickListener lambda@ {
val account = this.account ?: return@lambda true
val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID)
.putExtra(Settings.EXTRA_CHANNEL_ID, account.key.notificationChannelId(spec.id))
context.startActivity(intent)
return@lambda true
}
addPreference(preference)
}
}
}

View File

@ -21,6 +21,7 @@ package org.mariotaku.twidere.util
import android.content.Context
import android.content.SharedPreferences
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.Color
import android.graphics.PorterDuff
@ -458,6 +459,15 @@ object ThemeUtils {
}
}
fun getColorStateListFromAttribute(context: Context, @AttrRes attr: Int, styleRes: Int = 0): ColorStateList? {
val a = context.obtainStyledAttributes(null, intArrayOf(attr), 0, styleRes)
try {
return a.getColorStateList(0)
} finally {
a.recycle()
}
}
fun getBooleanFromAttribute(context: Context, @AttrRes attr: Int, styleRes: Int = 0, def: Boolean = false): Boolean {
val a = context.obtainStyledAttributes(null, intArrayOf(attr), 0, styleRes)
try {

View File

@ -31,6 +31,7 @@ import org.mariotaku.twidere.adapter.MessagesConversationAdapter
import org.mariotaku.twidere.extension.model.applyTo
import org.mariotaku.twidere.model.ParcelableMessage
import org.mariotaku.twidere.model.SpanItem
import org.mariotaku.twidere.util.ThemeUtils
import org.mariotaku.twidere.view.FixedTextView
import org.mariotaku.twidere.view.ProfileImageView
@ -64,8 +65,15 @@ class MessageViewHolder(itemView: View, adapter: MessagesConversationAdapter) :
override fun display(message: ParcelableMessage, showDate: Boolean) {
super.display(message, showDate)
messageBubble.bubbleColor = if (message.is_outgoing) {
adapter.bubbleColorOutgoing
} else {
adapter.bubbleColorIncoming
}
messageBubble.setOutgoing(message.is_outgoing)
text.setTextColor(ThemeUtils.getColorDependent(messageBubble.bubbleColor.defaultColor))
// Loop through text and spans to found non-space char count
val hideText = run {

View File

@ -55,6 +55,7 @@
android:layout_toEndOf="@+id/profileImage"
android:layout_toRightOf="@+id/profileImage"
android:clickable="true"
android:focusable="true"
android:minHeight="@dimen/profile_image_size_direct_message"
android:minWidth="@dimen/element_size_normal"
app:bubbleColor="?messageBubbleColor"

View File

@ -774,6 +774,8 @@
<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_descriptions_content_subscriptions">User\'s tweet notifications</string>
<string name="notification_channel_descriptions_content_updates">Updates like new tweets in home timeline</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">Interactions</string>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--suppress AndroidElementNotAllowed -->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/notifications">
<org.mariotaku.twidere.preference.notification.AccountNotificationChannelsPreference
android:key="notification_channels"/>
<org.mariotaku.twidere.preference.TintedPreferenceCategory
android:key="cat_other_settings"
android:title="@string/other_settings">
<org.mariotaku.twidere.preference.ColorPickerPreference
android:key="notification_light_color"
android:title="@string/notification_light_color"
app:defaultColor="@color/branding_color"/>
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="notification_following_only"
android:summary="@string/following_only_summary"
android:title="@string/following_only"/>
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="notification_mentions_only"
android:title="@string/mentions_only"/>
</org.mariotaku.twidere.preference.TintedPreferenceCategory>
</PreferenceScreen>