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 +- 6 files changed, 177 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 (limited to 'app/src') 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 @@