Merge pull request #278 from cyb3rko/notification-channels
Separate Notification channels for each app
This commit is contained in:
@@ -1,56 +1,93 @@
|
||||
package com.github.gotify
|
||||
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationChannelGroup
|
||||
import android.app.NotificationManager
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.gotify.client.model.Application
|
||||
import com.github.gotify.log.Log
|
||||
|
||||
internal object NotificationSupport {
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun createChannels(notificationManager: NotificationManager) {
|
||||
try {
|
||||
// Low importance so that persistent notification can be sorted towards bottom of
|
||||
// notification shade. Also prevents vibrations caused by persistent notification
|
||||
val foreground = NotificationChannel(
|
||||
Channel.FOREGROUND,
|
||||
"Gotify foreground notification",
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
foreground.setShowBadge(false)
|
||||
fun createForegroundChannel(context: Context, notificationManager: NotificationManager) {
|
||||
// Low importance so that persistent notification can be sorted towards bottom of
|
||||
// notification shade. Also prevents vibrations caused by persistent notification
|
||||
val foreground = NotificationChannel(
|
||||
Channel.FOREGROUND,
|
||||
context.getString(R.string.notification_channel_title_foreground),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
setShowBadge(false)
|
||||
}
|
||||
notificationManager.createNotificationChannel(foreground)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
fun createChannels(
|
||||
context: Context,
|
||||
notificationManager: NotificationManager,
|
||||
applications: List<Application>
|
||||
) {
|
||||
if (areAppChannelsRequested(context)) {
|
||||
notificationManager.notificationChannels.forEach { channel ->
|
||||
if (channel.id != Channel.FOREGROUND) {
|
||||
notificationManager.deleteNotificationChannel(channel.id)
|
||||
}
|
||||
}
|
||||
applications.forEach { app ->
|
||||
createAppChannels(context, notificationManager, app.id.toString(), app.name)
|
||||
}
|
||||
} else {
|
||||
notificationManager.notificationChannelGroups.forEach { group ->
|
||||
notificationManager.deleteNotificationChannelGroup(group.id)
|
||||
}
|
||||
createGeneralChannels(context, notificationManager)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createGeneralChannels(
|
||||
context: Context,
|
||||
notificationManager: NotificationManager
|
||||
) {
|
||||
try {
|
||||
val messagesImportanceMin = NotificationChannel(
|
||||
Channel.MESSAGES_IMPORTANCE_MIN,
|
||||
"Min priority messages (<1)",
|
||||
context.getString(R.string.notification_channel_title_min),
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
)
|
||||
|
||||
val messagesImportanceLow = NotificationChannel(
|
||||
Channel.MESSAGES_IMPORTANCE_LOW,
|
||||
"Low priority messages (1-3)",
|
||||
context.getString(R.string.notification_channel_title_low),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
)
|
||||
|
||||
val messagesImportanceDefault = NotificationChannel(
|
||||
Channel.MESSAGES_IMPORTANCE_DEFAULT,
|
||||
"Normal priority messages (4-7)",
|
||||
context.getString(R.string.notification_channel_title_normal),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
)
|
||||
messagesImportanceDefault.enableLights(true)
|
||||
messagesImportanceDefault.lightColor = Color.CYAN
|
||||
messagesImportanceDefault.enableVibration(true)
|
||||
).apply {
|
||||
enableLights(true)
|
||||
lightColor = Color.CYAN
|
||||
enableVibration(true)
|
||||
}
|
||||
|
||||
val messagesImportanceHigh = NotificationChannel(
|
||||
Channel.MESSAGES_IMPORTANCE_HIGH,
|
||||
"High priority messages (>7)",
|
||||
context.getString(R.string.notification_channel_title_high),
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
)
|
||||
messagesImportanceHigh.enableLights(true)
|
||||
messagesImportanceHigh.lightColor = Color.CYAN
|
||||
messagesImportanceHigh.enableVibration(true)
|
||||
).apply {
|
||||
enableLights(true)
|
||||
lightColor = Color.CYAN
|
||||
enableVibration(true)
|
||||
}
|
||||
|
||||
notificationManager.createNotificationChannel(foreground)
|
||||
notificationManager.createNotificationChannel(messagesImportanceMin)
|
||||
notificationManager.createNotificationChannel(messagesImportanceLow)
|
||||
notificationManager.createNotificationChannel(messagesImportanceDefault)
|
||||
@@ -60,6 +97,88 @@ internal object NotificationSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
fun createChannelIfNonexistent(
|
||||
context: Context,
|
||||
groupId: String,
|
||||
channelId: String
|
||||
) {
|
||||
if (!doesNotificationChannelExist(context, channelId)) {
|
||||
val notificationManager = (context as Service)
|
||||
.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
createAppChannels(context, notificationManager, groupId, groupId)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
private fun createAppChannels(
|
||||
context: Context,
|
||||
notificationManager: NotificationManager,
|
||||
groupId: String,
|
||||
groupName: String
|
||||
) {
|
||||
try {
|
||||
notificationManager.createNotificationChannelGroup(
|
||||
NotificationChannelGroup(
|
||||
groupId,
|
||||
groupName
|
||||
)
|
||||
)
|
||||
|
||||
val messagesImportanceMin = NotificationChannel(
|
||||
getChannelID(Channel.MESSAGES_IMPORTANCE_MIN, groupId),
|
||||
context.getString(R.string.notification_channel_title_min),
|
||||
NotificationManager.IMPORTANCE_MIN
|
||||
).apply {
|
||||
group = groupId
|
||||
}
|
||||
|
||||
val messagesImportanceLow = NotificationChannel(
|
||||
getChannelID(Channel.MESSAGES_IMPORTANCE_LOW, groupId),
|
||||
context.getString(R.string.notification_channel_title_low),
|
||||
NotificationManager.IMPORTANCE_LOW
|
||||
).apply {
|
||||
group = groupId
|
||||
}
|
||||
|
||||
val messagesImportanceDefault = NotificationChannel(
|
||||
getChannelID(Channel.MESSAGES_IMPORTANCE_DEFAULT, groupId),
|
||||
context.getString(R.string.notification_channel_title_normal),
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
).apply {
|
||||
enableLights(true)
|
||||
lightColor = Color.CYAN
|
||||
enableVibration(true)
|
||||
group = groupId
|
||||
}
|
||||
|
||||
val messagesImportanceHigh = NotificationChannel(
|
||||
getChannelID(Channel.MESSAGES_IMPORTANCE_HIGH, groupId),
|
||||
context.getString(R.string.notification_channel_title_high),
|
||||
NotificationManager.IMPORTANCE_HIGH
|
||||
).apply {
|
||||
enableLights(true)
|
||||
lightColor = Color.CYAN
|
||||
enableVibration(true)
|
||||
group = groupId
|
||||
}
|
||||
|
||||
notificationManager.createNotificationChannel(messagesImportanceMin)
|
||||
notificationManager.createNotificationChannel(messagesImportanceLow)
|
||||
notificationManager.createNotificationChannel(messagesImportanceDefault)
|
||||
notificationManager.createNotificationChannel(messagesImportanceHigh)
|
||||
} catch (e: Exception) {
|
||||
Log.e("Could not create channel", e)
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private fun doesNotificationChannelExist(context: Context, channelId: String): Boolean {
|
||||
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val channel = manager.getNotificationChannel(channelId)
|
||||
return channel != null
|
||||
}
|
||||
|
||||
/**
|
||||
* Map {@link com.github.gotify.client.model.Message#getPriority() Gotify message priorities to
|
||||
* Android channels.
|
||||
@@ -87,6 +206,21 @@ internal object NotificationSupport {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getChannelID(importance: String, groupId: String): String {
|
||||
return "$groupId::$importance"
|
||||
}
|
||||
|
||||
fun getChannelID(priority: Long, groupId: String): String {
|
||||
return getChannelID(convertPriorityToChannel(priority), groupId)
|
||||
}
|
||||
|
||||
fun areAppChannelsRequested(context: Context): Boolean {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
context.getString(R.string.setting_key_notification_channels),
|
||||
context.resources.getBoolean(R.bool.notification_channels)
|
||||
)
|
||||
}
|
||||
|
||||
object Group {
|
||||
const val MESSAGES = "GOTIFY_GROUP_MESSAGES"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.github.gotify.init
|
||||
|
||||
import android.Manifest
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
@@ -41,8 +42,9 @@ internal class InitializationActivity : AppCompatActivity() {
|
||||
ThemeHelper.setTheme(this, theme)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationSupport.createChannels(
|
||||
this.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
|
||||
NotificationSupport.createForegroundChannel(
|
||||
this,
|
||||
(this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
|
||||
)
|
||||
}
|
||||
UncaughtExceptionHandler.registerCurrentThread()
|
||||
|
||||
@@ -9,7 +9,7 @@ internal object MessageImageCombiner {
|
||||
return messages.map { MessageWithImage(message = it, image = appIdToImage[it.appid]) }
|
||||
}
|
||||
|
||||
fun appIdToImage(applications: List<Application>): Map<Long, String> {
|
||||
private fun appIdToImage(applications: List<Application>): Map<Long, String> {
|
||||
val map = mutableMapOf<Long, String>()
|
||||
applications.forEach {
|
||||
map[it.id] = it.image
|
||||
|
||||
@@ -6,19 +6,15 @@ import android.graphics.BitmapFactory
|
||||
import com.github.gotify.R
|
||||
import com.github.gotify.Settings
|
||||
import com.github.gotify.Utils
|
||||
import com.github.gotify.api.Callback
|
||||
import com.github.gotify.api.CertUtils
|
||||
import com.github.gotify.api.ClientFactory
|
||||
import com.github.gotify.client.api.ApplicationApi
|
||||
import com.github.gotify.client.model.Application
|
||||
import com.github.gotify.log.Log
|
||||
import com.github.gotify.messages.provider.MessageImageCombiner
|
||||
import com.squareup.picasso.OkHttp3Downloader
|
||||
import com.squareup.picasso.Picasso
|
||||
import okhttp3.Cache
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
internal class PicassoHandler(private val context: Context, private val settings: Settings) {
|
||||
companion object {
|
||||
@@ -32,7 +28,6 @@ internal class PicassoHandler(private val context: Context, private val settings
|
||||
)
|
||||
|
||||
private val picasso = makePicasso()
|
||||
private val appIdToAppImage = ConcurrentHashMap<Long, String>()
|
||||
|
||||
private fun makePicasso(): Picasso {
|
||||
val builder = OkHttpClient.Builder()
|
||||
@@ -48,13 +43,13 @@ internal class PicassoHandler(private val context: Context, private val settings
|
||||
@Throws(IOException::class)
|
||||
fun getImageFromUrl(url: String?): Bitmap = picasso.load(url).get()
|
||||
|
||||
fun getIcon(appId: Long): Bitmap {
|
||||
if (appId == -1L) {
|
||||
fun getIcon(app: Application?): Bitmap {
|
||||
if (app == null) {
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
try {
|
||||
return getImageFromUrl(
|
||||
Utils.resolveAbsoluteUrl("${settings.url}/", appIdToAppImage[appId])
|
||||
Utils.resolveAbsoluteUrl("${settings.url}/", app.image)
|
||||
)
|
||||
} catch (e: IOException) {
|
||||
Log.e("Could not load image for notification", e)
|
||||
@@ -62,21 +57,6 @@ internal class PicassoHandler(private val context: Context, private val settings
|
||||
return BitmapFactory.decodeResource(context.resources, R.drawable.gotify)
|
||||
}
|
||||
|
||||
fun updateAppIds() {
|
||||
ClientFactory.clientToken(settings.url, settings.sslSettings(), settings.token)
|
||||
.createService(ApplicationApi::class.java)
|
||||
.apps
|
||||
.enqueue(
|
||||
Callback.call(
|
||||
onSuccess = Callback.SuccessBody { apps ->
|
||||
appIdToAppImage.clear()
|
||||
appIdToAppImage.putAll(MessageImageCombiner.appIdToImage(apps))
|
||||
},
|
||||
onError = { appIdToAppImage.clear() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun get() = picasso
|
||||
|
||||
@Throws(IOException::class)
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.graphics.Color
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.Uri
|
||||
@@ -23,7 +22,9 @@ import com.github.gotify.Settings
|
||||
import com.github.gotify.Utils
|
||||
import com.github.gotify.api.Callback
|
||||
import com.github.gotify.api.ClientFactory
|
||||
import com.github.gotify.client.api.ApplicationApi
|
||||
import com.github.gotify.client.api.MessageApi
|
||||
import com.github.gotify.client.model.Application
|
||||
import com.github.gotify.client.model.Message
|
||||
import com.github.gotify.log.Log
|
||||
import com.github.gotify.log.UncaughtExceptionHandler
|
||||
@@ -31,6 +32,7 @@ import com.github.gotify.messages.Extras
|
||||
import com.github.gotify.messages.MessagesActivity
|
||||
import com.github.gotify.picasso.PicassoHandler
|
||||
import io.noties.markwon.Markwon
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
|
||||
internal class WebSocketService : Service() {
|
||||
@@ -41,6 +43,7 @@ internal class WebSocketService : Service() {
|
||||
|
||||
private lateinit var settings: Settings
|
||||
private var connection: WebSocketConnection? = null
|
||||
private val appIdToApp = ConcurrentHashMap<Long, Application>()
|
||||
|
||||
private val lastReceivedMessage = AtomicLong(NOT_LOADED)
|
||||
private lateinit var missingMessageUtil: MissedMessageUtil
|
||||
@@ -108,10 +111,29 @@ internal class WebSocketService : Service() {
|
||||
.onReconnected { notifyMissedNotifications() }
|
||||
.start()
|
||||
|
||||
val intentFilter = IntentFilter()
|
||||
intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION)
|
||||
fetchApps()
|
||||
}
|
||||
|
||||
picassoHandler.updateAppIds()
|
||||
private fun fetchApps() {
|
||||
ClientFactory.clientToken(settings.url, settings.sslSettings(), settings.token)
|
||||
.createService(ApplicationApi::class.java)
|
||||
.apps
|
||||
.enqueue(
|
||||
Callback.call(
|
||||
onSuccess = Callback.SuccessBody { apps ->
|
||||
appIdToApp.clear()
|
||||
appIdToApp.putAll(apps.associateBy { it.id })
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationSupport.createChannels(
|
||||
this,
|
||||
(this.getSystemService(NOTIFICATION_SERVICE) as NotificationManager),
|
||||
apps
|
||||
)
|
||||
}
|
||||
},
|
||||
onError = { appIdToApp.clear() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun onClose() {
|
||||
@@ -312,20 +334,31 @@ internal class WebSocketService : Service() {
|
||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val b = NotificationCompat.Builder(
|
||||
this,
|
||||
NotificationSupport.convertPriorityToChannel(priority)
|
||||
)
|
||||
val channelId: String
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||
NotificationSupport.areAppChannelsRequested(this)
|
||||
) {
|
||||
channelId = NotificationSupport.getChannelID(priority, appId.toString())
|
||||
NotificationSupport.createChannelIfNonexistent(
|
||||
this,
|
||||
appId.toString(),
|
||||
channelId
|
||||
)
|
||||
} else {
|
||||
channelId = NotificationSupport.convertPriorityToChannel(priority)
|
||||
}
|
||||
|
||||
val b = NotificationCompat.Builder(this, channelId)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
showNotificationGroup(priority)
|
||||
showNotificationGroup(channelId)
|
||||
}
|
||||
|
||||
b.setAutoCancel(true)
|
||||
.setDefaults(Notification.DEFAULT_ALL)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setSmallIcon(R.drawable.ic_gotify)
|
||||
.setLargeIcon(picassoHandler.getIcon(appId))
|
||||
.setLargeIcon(picassoHandler.getIcon(appIdToApp[appId]))
|
||||
.setTicker("${getString(R.string.app_name)} - $title")
|
||||
.setGroup(NotificationSupport.Group.MESSAGES)
|
||||
.setContentTitle(title)
|
||||
@@ -365,7 +398,7 @@ internal class WebSocketService : Service() {
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
fun showNotificationGroup(priority: Long) {
|
||||
fun showNotificationGroup(channelId: String) {
|
||||
val intent = Intent(this, MessagesActivity::class.java)
|
||||
val contentIntent = PendingIntent.getActivity(
|
||||
this,
|
||||
@@ -376,7 +409,7 @@ internal class WebSocketService : Service() {
|
||||
|
||||
val builder = NotificationCompat.Builder(
|
||||
this,
|
||||
NotificationSupport.convertPriorityToChannel(priority)
|
||||
channelId
|
||||
)
|
||||
|
||||
builder.setAutoCancel(true)
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
@@ -14,6 +15,7 @@ import androidx.preference.ListPreferenceDialogFragmentCompat
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import com.github.gotify.R
|
||||
import com.github.gotify.databinding.SettingsActivityBinding
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@@ -48,38 +50,43 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL
|
||||
}
|
||||
|
||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||
if (getString(R.string.setting_key_theme) == key) {
|
||||
ThemeHelper.setTheme(
|
||||
this,
|
||||
sharedPreferences.getString(key, getString(R.string.theme_default))!!
|
||||
)
|
||||
when (key) {
|
||||
getString(R.string.setting_key_theme) -> {
|
||||
ThemeHelper.setTheme(
|
||||
this,
|
||||
sharedPreferences.getString(key, getString(R.string.theme_default))!!
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
findPreference<SwitchPreferenceCompat>(
|
||||
getString(R.string.setting_key_notification_channels)
|
||||
)?.isEnabled = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val messageLayout: ListPreference? =
|
||||
findPreference(getString(R.string.setting_key_message_layout))
|
||||
val notificationChannels: SwitchPreferenceCompat? =
|
||||
findPreference(getString(R.string.setting_key_notification_channels))
|
||||
messageLayout?.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _, _ ->
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.setting_message_layout_dialog_title)
|
||||
.setMessage(R.string.setting_message_layout_dialog_message)
|
||||
.setPositiveButton(
|
||||
getString(R.string.setting_message_layout_dialog_button1)
|
||||
) { _, _ ->
|
||||
restartApp()
|
||||
}
|
||||
.setNegativeButton(
|
||||
getString(R.string.setting_message_layout_dialog_button2),
|
||||
null
|
||||
)
|
||||
.show()
|
||||
showRestartDialog()
|
||||
true
|
||||
}
|
||||
notificationChannels?.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _, _ ->
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return@OnPreferenceChangeListener false
|
||||
}
|
||||
showRestartDialog()
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -102,6 +109,17 @@ internal class SettingsActivity : AppCompatActivity(), OnSharedPreferenceChangeL
|
||||
)
|
||||
}
|
||||
|
||||
private fun showRestartDialog() {
|
||||
MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.setting_restart_dialog_title)
|
||||
.setMessage(R.string.setting_restart_dialog_message)
|
||||
.setPositiveButton(getString(R.string.setting_restart_dialog_button1)) { _, _ ->
|
||||
restartApp()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.setting_restart_dialog_button2), null)
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun restartApp() {
|
||||
val packageManager = requireContext().packageManager
|
||||
val packageName = requireContext().packageName
|
||||
|
||||
6
app/src/main/res/layout/preference_switch.xml
Normal file
6
app/src/main/res/layout/preference_switch.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/switchWidget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -34,4 +34,5 @@
|
||||
</string-array>
|
||||
<string name="time_format_value_absolute">time_format_absolute</string>
|
||||
<string name="time_format_value_relative">time_format_relative</string>
|
||||
<bool name="notification_channels">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -74,12 +74,15 @@
|
||||
<string name="setting_key_theme">theme</string>
|
||||
<string name="setting_message_layout">Message layout</string>
|
||||
<string name="setting_key_message_layout">message_layout</string>
|
||||
<string name="setting_message_layout_dialog_title">Restart App?</string>
|
||||
<string name="setting_message_layout_dialog_message">The change will be effective on next app start.\n\nDo you want to restart now?</string>
|
||||
<string name="setting_message_layout_dialog_button1">Restart</string>
|
||||
<string name="setting_message_layout_dialog_button2">Later</string>
|
||||
<string name="setting_restart_dialog_title">Restart App?</string>
|
||||
<string name="setting_restart_dialog_message">The change will be effective on next app start.\n\nDo you want to restart now?</string>
|
||||
<string name="setting_restart_dialog_button1">Restart</string>
|
||||
<string name="setting_restart_dialog_button2">Later</string>
|
||||
<string name="setting_time_format">Time format</string>
|
||||
<string name="setting_key_time_format">time_format</string>
|
||||
<string name="setting_notifications">Notifications</string>
|
||||
<string name="setting_notification_channels">Separate app notification channels</string>
|
||||
<string name="setting_key_notification_channels">notification_channels</string>
|
||||
<string name="push_message">Push message</string>
|
||||
<string name="appListDescription">App:</string>
|
||||
<string name="priorityDescription">Priority:</string>
|
||||
@@ -97,4 +100,10 @@
|
||||
<item quantity="one">in %d minute</item>
|
||||
<item quantity="other">in %d minutes</item>
|
||||
</plurals>
|
||||
|
||||
<string name="notification_channel_title_foreground">Gotify foreground notification</string>
|
||||
<string name="notification_channel_title_min">Min priority messages (<1)</string>
|
||||
<string name="notification_channel_title_low">Low priority messages (1–3)</string>
|
||||
<string name="notification_channel_title_normal">Normal priority messages (4–7)</string>
|
||||
<string name="notification_channel_title_high">High priority messages (>7)</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- Base application theme. -->
|
||||
<style name="AppTheme" parent="Theme.Material3.DayNight">
|
||||
@@ -25,4 +25,8 @@
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="AppTheme" />
|
||||
|
||||
<style name="Preference.SwitchPreferenceCompat" parent="@style/Preference.SwitchPreferenceCompat.Material" tools:ignore="ResourceCycle">
|
||||
<item name="widgetLayout">@layout/preference_switch</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -24,4 +24,13 @@
|
||||
android:title="@string/setting_time_format" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/setting_notifications" >
|
||||
<SwitchPreferenceCompat
|
||||
android:enabled="false"
|
||||
android:defaultValue="@bool/notification_channels"
|
||||
android:key="@string/setting_key_notification_channels"
|
||||
android:title="@string/setting_notification_channels"
|
||||
app:singleLineTitle="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
Reference in New Issue
Block a user