Hide username in Live Notifications push

This change will allow you to hide your name in the permanent
notification.
This commit is contained in:
Adolfo Santiago 2022-05-08 09:40:21 +02:00
parent 6670cd079f
commit cd69679e9a
No known key found for this signature in database
GPG key ID: 244D6F9A317B4A65
6 changed files with 155 additions and 46 deletions

View file

@ -44,6 +44,8 @@
<string name="pref_title_other">Other</string>
<string name="pref_title_privacy">Privacy</string>
<string name="key_hide_live_notification_desc">hideLiveNotifDesc</string>
<string name="pref_title_composing">Composing</string>
<string name="pref_title_composing_title">Composing using zero-width space characters in emojis</string>
@ -52,6 +54,8 @@
<string name="key_enable_acra">acra.enable</string>
<string name="pref_title_anonymize_upload_filenames">Anonymize uploaded file names</string>
<string name="pref_title_hide_live_notification_description">Hide Live Notification username</string>
<string name="pref_title_hide_live_notification_description_toast">This will be changed once you go back to the timeline.</string>
<string name="pref_title_live_notifications">Live notifications</string>
<string name="pref_summary_live_notifications">May slightly increase power consumption</string>
<string name="pref_title_default_formatting">Default formatting syntax(if supported by instance)</string>

View file

@ -53,7 +53,13 @@ import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy
import com.keylesspalace.tusky.appstore.*
import com.keylesspalace.tusky.appstore.AnnouncementReadEvent
import com.keylesspalace.tusky.appstore.CacheUpdater
import com.keylesspalace.tusky.appstore.Event
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.MainTabsChangedEvent
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.appstore.ProfileEditedEvent
import com.keylesspalace.tusky.components.announcements.AnnouncementsActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity
import com.keylesspalace.tusky.components.compose.ComposeActivity.Companion.canHandleMimeType
@ -74,7 +80,14 @@ import com.keylesspalace.tusky.interfaces.ReselectableFragment
import com.keylesspalace.tusky.pager.MainPagerAdapter
import com.keylesspalace.tusky.service.StreamingService
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.*
import com.keylesspalace.tusky.util.ThemeUtils
import com.keylesspalace.tusky.util.ViewPager2Fix
import com.keylesspalace.tusky.util.deleteStaleCachedMedia
import com.keylesspalace.tusky.util.emojify
import com.keylesspalace.tusky.util.hide
import com.keylesspalace.tusky.util.removeShortcut
import com.keylesspalace.tusky.util.updateShortcut
import com.keylesspalace.tusky.util.visible
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
@ -83,9 +96,27 @@ import com.mikepenz.materialdrawer.holder.BadgeStyle
import com.mikepenz.materialdrawer.holder.ColorHolder
import com.mikepenz.materialdrawer.holder.StringHolder
import com.mikepenz.materialdrawer.iconics.iconicsIcon
import com.mikepenz.materialdrawer.model.*
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.util.*
import com.mikepenz.materialdrawer.model.AbstractDrawerItem
import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.IProfile
import com.mikepenz.materialdrawer.model.interfaces.descriptionRes
import com.mikepenz.materialdrawer.model.interfaces.descriptionText
import com.mikepenz.materialdrawer.model.interfaces.iconRes
import com.mikepenz.materialdrawer.model.interfaces.iconUrl
import com.mikepenz.materialdrawer.model.interfaces.nameRes
import com.mikepenz.materialdrawer.model.interfaces.nameText
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.util.addItemAtPosition
import com.mikepenz.materialdrawer.util.addItems
import com.mikepenz.materialdrawer.util.addItemsAtPosition
import com.mikepenz.materialdrawer.util.getDrawerItem
import com.mikepenz.materialdrawer.util.removeItems
import com.mikepenz.materialdrawer.util.updateBadge
import com.mikepenz.materialdrawer.widget.AccountHeaderView
import com.uber.autodispose.android.lifecycle.autoDispose
import dagger.android.DispatchingAndroidInjector
@ -93,7 +124,14 @@ import dagger.android.HasAndroidInjector
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.activity_main.bottomNav
import kotlinx.android.synthetic.main.activity_main.bottomTabLayout
import kotlinx.android.synthetic.main.activity_main.composeButton
import kotlinx.android.synthetic.main.activity_main.mainDrawer
import kotlinx.android.synthetic.main.activity_main.mainDrawerLayout
import kotlinx.android.synthetic.main.activity_main.mainToolbar
import kotlinx.android.synthetic.main.activity_main.tabLayout
import kotlinx.android.synthetic.main.activity_main.viewPager
import timber.log.Timber
class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInjector {
@ -237,6 +275,9 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
PrefKeys.LIVE_NOTIFICATIONS -> {
initPullNotifications()
}
PrefKeys.HIDE_LIVE_NOTIFICATION_DESCRIPTION -> {
initPullNotifications(rebootPush = true)
}
}
}
is AnnouncementReadEvent -> {
@ -259,7 +300,11 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
)
}
private fun initPullNotifications() {
private fun initPullNotifications(rebootPush: Boolean = false) {
if(rebootPush) {
disablePushNotifications()
}
if(NotificationHelper.areNotificationsEnabled(this, accountManager)) {
if(accountManager.areNotificationsStreamingEnabled()) {
StreamingService.startStreaming(this)
@ -269,12 +314,16 @@ class MainActivity : BottomSheetActivity(), ActionButtonActivity, HasAndroidInje
NotificationHelper.enablePullNotifications(this)
}
} else {
StreamingService.stopStreaming(this)
NotificationHelper.disablePullNotifications(this)
disablePushNotifications()
}
draftWarning()
}
private fun disablePushNotifications() {
StreamingService.stopStreaming(this)
NotificationHelper.disablePullNotifications(this)
}
override fun onResume() {
super.onResume()
NotificationHelper.clearNotificationsForActiveAccount(this, accountManager)

View file

@ -21,12 +21,17 @@
package com.keylesspalace.tusky.components.preference
import android.os.Bundle
import android.widget.Toast
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.appstore.EventHub
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
import com.keylesspalace.tusky.components.notifications.NotificationHelper
import com.keylesspalace.tusky.db.AccountManager
import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.service.StreamingService
import com.keylesspalace.tusky.settings.AppTheme
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.settings.emojiPreference
@ -55,6 +60,9 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
@Inject
lateinit var accountManager: AccountManager
@Inject
lateinit var eventHub: EventHub
private val iconSize by lazy { resources.getDimensionPixelSize(R.dimen.preference_icon_size) }
private var httpProxyPref: Preference? = null
@ -246,6 +254,24 @@ class PreferencesFragment : PreferenceFragmentCompat(), Injectable {
setTitle(R.string.pref_title_anonymize_upload_filenames)
isSingleLineTitle = false
}
switchPreference {
setDefaultValue(false)
key = PrefKeys.HIDE_LIVE_NOTIFICATION_DESCRIPTION
setTitle(R.string.pref_title_hide_live_notification_description)
isSingleLineTitle = false
setOnPreferenceChangeListener { _, _ ->
eventHub.dispatch(PreferenceChangedEvent(key))
Toast.makeText(
context,
getString(R.string.pref_title_hide_live_notification_description_toast),
Toast.LENGTH_LONG
).show()
true
}
}
}
preferenceCategory(R.string.pref_title_browser_settings) {

View file

@ -7,10 +7,10 @@ import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import androidx.preference.PreferenceManager
import com.google.gson.Gson
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.appstore.ChatMessageReceivedEvent
@ -22,12 +22,19 @@ import com.keylesspalace.tusky.di.Injectable
import com.keylesspalace.tusky.entity.Notification
import com.keylesspalace.tusky.entity.StreamEvent
import com.keylesspalace.tusky.network.MastodonApi
import com.keylesspalace.tusky.settings.PrefKeys
import com.keylesspalace.tusky.util.isLessThan
import dagger.android.AndroidInjection
import okhttp3.*
import javax.inject.Inject
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.WebSocket
import okhttp3.WebSocketListener
import timber.log.Timber
class StreamingService : Service(), Injectable {
class StreamingService: Service(), Injectable {
@Inject
lateinit var api: MastodonApi
@ -58,7 +65,7 @@ class StreamingService: Service(), Injectable {
private fun stopStreamingForId(id: Long) {
if(id in sockets) {
sockets[id]!!.close(1000, null)
sockets[id]?.close(1000, null)
sockets.remove(id)
}
}
@ -69,7 +76,7 @@ class StreamingService: Service(), Injectable {
}
sockets.clear()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
}
@ -87,7 +94,7 @@ class StreamingService: Service(), Injectable {
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
if(intent.getBooleanExtra(KEY_STOP_STREAMING, false)) {
Log.d(TAG, "Stream goes suya..")
Timber.d("Stream goes suya..")
stopStreaming()
stopSelfResult(startId)
return START_NOT_STICKY
@ -99,20 +106,22 @@ class StreamingService: Service(), Injectable {
for(account in accounts) {
stopStreamingForId(account.id)
if(!account.notificationsStreamingEnabled)
if(!account.notificationsStreamingEnabled) {
continue
}
val endpoint = "wss://${account.domain}/api/v1/streaming/?access_token=${account.accessToken}&stream=user:notification"
val endpoint =
"wss://${account.domain}/api/v1/streaming/?access_token=${account.accessToken}&stream=user:notification"
val request = Request.Builder().url(endpoint).build()
Log.d(TAG, "Running stream for ${account.fullName}")
Timber.d("Running stream for ${account.fullName}")
sockets[account.id] = client.newWebSocket(
request,
makeStreamingListener(
"${account.fullName}/user:notification",
account
)
request,
makeStreamingListener(
"${account.fullName}/user:notification",
account
)
)
description += "\n" + account.fullName
@ -120,27 +129,36 @@ class StreamingService: Service(), Injectable {
}
if(count <= 0) {
Log.d(TAG, "No accounts. Stopping stream")
Timber.d("No accounts. Stopping stream")
stopStreaming()
stopSelfResult(startId)
return START_NOT_STICKY
}
if (NotificationHelper.NOTIFICATION_USE_CHANNELS) {
val channel = NotificationChannel(CHANNEL_ID, getString(R.string.streaming_notification_name), NotificationManager.IMPORTANCE_LOW)
if(NotificationHelper.NOTIFICATION_USE_CHANNELS) {
val channel = NotificationChannel(
CHANNEL_ID,
getString(R.string.streaming_notification_name),
NotificationManager.IMPORTANCE_LOW
)
notificationManager.createNotificationChannel(channel)
}
val builder = NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notify)
.setContentTitle(getString(R.string.streaming_notification_name))
.setContentText(description)
.setOngoing(true)
.setNotificationSilent()
.setPriority(NotificationCompat.PRIORITY_MIN)
.setColor(ContextCompat.getColor(this, R.color.tusky_blue))
.setSmallIcon(R.drawable.ic_notify)
.setContentTitle(getString(R.string.streaming_notification_name))
.setOngoing(true)
.setSilent(true)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setColor(ContextCompat.getColor(this, R.color.tusky_blue))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val showDescription = PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean(PrefKeys.HIDE_LIVE_NOTIFICATION_DESCRIPTION, false)
if(!showDescription) {
builder.setContentText(description)
}
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_DETACH)
startForeground(1337, builder.build())
} else {
@ -155,9 +173,8 @@ class StreamingService: Service(), Injectable {
}
companion object {
val CHANNEL_ID = "streaming"
val KEY_STOP_STREAMING = "stop_streaming"
val TAG = "StreamingService"
const val CHANNEL_ID = "streaming"
const val KEY_STOP_STREAMING = "stop_streaming"
@JvmStatic
var serviceRunning = false
@ -176,7 +193,7 @@ class StreamingService: Service(), Injectable {
val intent = Intent(context, StreamingService::class.java)
intent.putExtra(KEY_STOP_STREAMING, false)
Log.d(TAG, "Starting notifications streaming service...")
Timber.d("Starting notifications streaming service...")
startForegroundService(context, intent)
}
@ -184,13 +201,14 @@ class StreamingService: Service(), Injectable {
@JvmStatic
fun stopStreaming(context: Context) {
synchronized(serviceRunning) {
if(!serviceRunning)
if(!serviceRunning) {
return
}
val intent = Intent(context, StreamingService::class.java)
intent.putExtra(KEY_STOP_STREAMING, true)
Log.d(TAG, "Stopping notifications streaming service...")
Timber.d("Stopping notifications streaming service...")
serviceRunning = false
@ -199,18 +217,20 @@ class StreamingService: Service(), Injectable {
}
}
private fun makeStreamingListener(tag: String, account: AccountEntity) : WebSocketListener {
private fun makeStreamingListener(tag: String, account: AccountEntity): WebSocketListener {
return object : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response) {
Log.d(TAG, "Stream connected to: $tag")
Timber.d("Stream connected to: $tag")
}
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
Log.d(TAG, "Stream closed for: $tag")
Timber.d("Stream closed for: $tag")
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
Log.d(TAG, "Stream failed for $tag", t)
Timber.e("Stream failed for $tag", t)
}
override fun onMessage(webSocket: WebSocket, text: String) {
@ -230,7 +250,7 @@ class StreamingService: Service(), Injectable {
}
}
else -> {
Log.d(TAG, "Unknown event type: ${event.event}")
Timber.w("Unknown event type: ${event.event}")
}
}
}

View file

@ -54,6 +54,7 @@ object PrefKeys {
const val BIG_EMOJIS = "bigEmojis"
const val STICKERS = "stickers"
const val ANONYMIZE_FILENAMES = "anonymizeFilenames"
const val HIDE_LIVE_NOTIFICATION_DESCRIPTION = "hideLiveNotifDesc"
const val HIDE_MUTED_USERS = "hideMutedUsers"
const val ANIMATE_CUSTOM_EMOJIS = "animateCustomEmojis"
const val RENDER_STATUS_AS_MENTION = "renderStatusAsMention"

View file

@ -1,6 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory android:title="@string/pref_title_privacy">
<CheckBoxPreference
android:defaultValue="false"
android:key="@string/key_hide_live_notification_desc"
android:title="@string/pref_title_hide_live_notification_description" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/pref_acra_category">
<CheckBoxPreference