From 550a6b1f622868f23413f08a766bee00723923bb Mon Sep 17 00:00:00 2001
From: pacien
Date: Sun, 30 Jul 2023 03:06:35 +0200
Subject: errors: handle notifications internally
---
.../activities/start/ErrorNotificationFragment.kt | 60 ++++++++++++++++
.../tincapp/context/AppNotificationManager.kt | 81 ++++++++++------------
app/src/main/res/layout/start_activity.xml | 6 ++
.../main/res/layout/start_error_notification.xml | 69 ++++++++++++++++++
app/src/main/res/values/colors.xml | 3 +-
app/src/main/res/values/styles.xml | 6 +-
changelog.md | 2 +
7 files changed, 179 insertions(+), 48 deletions(-)
create mode 100644 app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
create mode 100644 app/src/main/res/layout/start_error_notification.xml
diff --git a/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt b/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
new file mode 100644
index 0000000..ed60d63
--- /dev/null
+++ b/app/src/main/java/org/pacien/tincapp/activities/start/ErrorNotificationFragment.kt
@@ -0,0 +1,60 @@
+/*
+ * Tinc App, an Android binding and user interface for the tinc mesh VPN daemon
+ * Copyright (C) 2017-2023 Pacien TRAN-GIRARD
+ *
+ * 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 .
+ */
+
+package org.pacien.tincapp.activities.start
+
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.pacien.tincapp.activities.BaseFragment
+import org.pacien.tincapp.context.App
+import org.pacien.tincapp.context.AppNotificationManager
+import org.pacien.tincapp.databinding.StartErrorNotificationBinding
+
+/**
+ * @author pacien
+ */
+class ErrorNotificationFragment : BaseFragment() {
+ private val notificationManager by lazy { AppNotificationManager(context!!) }
+ private val notificationListener = OnSharedPreferenceChangeListener { _, _ -> updateView() }
+ private lateinit var viewBinding: StartErrorNotificationBinding
+
+ override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ viewBinding = StartErrorNotificationBinding.inflate(inflater, container, false)
+ updateView()
+ return viewBinding.root
+ }
+
+ override fun onResume() {
+ super.onResume()
+ notificationManager.registerListener(notificationListener)
+ }
+
+ override fun onPause() {
+ super.onPause()
+ notificationManager.unregisterListener(notificationListener)
+ }
+
+ private fun updateView() {
+ val maybeError = notificationManager.getError()
+ viewBinding.errorNotification = maybeError
+ viewBinding.openManualAction = { App.openURL(maybeError?.manualLink!!) }
+ }
+}
diff --git a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
index d6e21f5..29f72de 100644
--- a/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
+++ b/app/src/main/java/org/pacien/tincapp/context/AppNotificationManager.kt
@@ -18,70 +18,59 @@
package org.pacien.tincapp.context
-import android.app.NotificationChannel
-import android.app.NotificationManager
import android.content.Context
-import android.content.Intent
-import android.net.Uri
-import android.os.Build
-import androidx.annotation.RequiresApi
-import androidx.core.app.NotificationCompat
-import androidx.core.app.NotificationManagerCompat
-import org.pacien.tincapp.R
-import org.pacien.tincapp.utils.PendingIntentUtils
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener
/**
* @author pacien
*/
class AppNotificationManager(private val context: Context) {
+ data class ErrorNotification(
+ val title: String,
+ val message: String,
+ val manualLink: String?
+ )
+
companion object {
- private const val ERROR_CHANNEL_ID = "org.pacien.tincapp.notification.channels.error"
- const val ERROR_NOTIFICATION_ID = 0
+ private val STORE_NAME = this::class.java.`package`!!.name
+ private const val STORE_KEY_TITLE = "title"
+ private const val STORE_KEY_MESSAGE = "message"
+ private const val STORE_KEY_MANUAL_LINK = "manual_link"
}
- init {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) registerChannels()
- }
+ private val store by lazy { context.getSharedPreferences(STORE_NAME, Context.MODE_PRIVATE)!! }
- fun notifyError(title: String, message: String, manualLink: String? = null) {
- val notification = NotificationCompat.Builder(context, ERROR_CHANNEL_ID)
- .setSmallIcon(R.drawable.ic_warning_primary_24dp)
- .setContentTitle(title)
- .setContentText(message)
- .setStyle(NotificationCompat.BigTextStyle().bigText(message))
- .setHighPriority()
- .setAutoCancel(true)
- .apply { if (manualLink != null) setManualLink(manualLink) }
- .build()
+ fun getError(): ErrorNotification? {
+ if (!store.contains(STORE_KEY_TITLE)) return null;
- NotificationManagerCompat.from(context)
- .notify(ERROR_NOTIFICATION_ID, notification)
+ return ErrorNotification(
+ store.getString(STORE_KEY_TITLE, null)!!,
+ store.getString(STORE_KEY_MESSAGE, null)!!,
+ store.getString(STORE_KEY_MANUAL_LINK, null)
+ )
}
- fun dismissAll() {
- NotificationManagerCompat.from(context).cancelAll()
+ fun notifyError(title: String, message: String, manualLink: String? = null) {
+ store
+ .edit()
+ .putString(STORE_KEY_TITLE, title)
+ .putString(STORE_KEY_MESSAGE, message)
+ .putString(STORE_KEY_MANUAL_LINK, manualLink)
+ .apply()
}
- @RequiresApi(Build.VERSION_CODES.O)
- private fun registerChannels() {
- context.getSystemService(NotificationManager::class.java)
- .apply {
- createNotificationChannel(NotificationChannel(
- ERROR_CHANNEL_ID,
- context.getString(R.string.notification_error_channel_name),
- NotificationManager.IMPORTANCE_HIGH
- ))
- }
+ fun dismissAll() {
+ store
+ .edit()
+ .clear()
+ .apply()
}
- private fun NotificationCompat.Builder.setHighPriority() = apply {
- priority = NotificationCompat.PRIORITY_MAX
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) setDefaults(NotificationCompat.DEFAULT_SOUND) // force heads-up notification
+ fun registerListener(listener: OnSharedPreferenceChangeListener) {
+ store.registerOnSharedPreferenceChangeListener(listener)
}
- private fun NotificationCompat.Builder.setManualLink(manualLink: String) = apply {
- val intent = Intent(Intent.ACTION_VIEW, Uri.parse(manualLink))
- val pendingIntent = PendingIntentUtils.getActivity(context, 0, intent, 0)
- addAction(R.drawable.ic_help_primary_24dp, context.getString(R.string.notification_error_action_open_manual), pendingIntent)
+ fun unregisterListener(listener: OnSharedPreferenceChangeListener) {
+ store.unregisterOnSharedPreferenceChangeListener(listener)
}
}
diff --git a/app/src/main/res/layout/start_activity.xml b/app/src/main/res/layout/start_activity.xml
index 2960711..f2069d5 100644
--- a/app/src/main/res/layout/start_activity.xml
+++ b/app/src/main/res/layout/start_activity.xml
@@ -30,6 +30,12 @@
style="@style/AppTheme.ListBlock.Placeholder"
android:text="@string/start_network_list_warning_text"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 7520cd8..3d05b1c 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -2,7 +2,7 @@