From 5dcedfd5aa13f659932a846ee1a70c87c345f20e Mon Sep 17 00:00:00 2001 From: LTFan Date: Sun, 21 Jan 2024 15:04:29 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=8F=91=E9=80=81=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build-number.properties | 2 +- .../src/androidMain/AndroidManifest.xml | 1 + .../kotlin/Notification.android.kt | 27 +++++++++++++++++++ .../xyz/xfqlittlefan/fhraise/MainActivity.kt | 24 ++++++++++++++--- .../src/commonMain/kotlin/Notification.kt | 19 +++++++++++++ .../data/components/root/SignInComponent.kt | 10 ++++++- .../kotlin/Notification.desktop.kt | 27 +++++++++++++++++++ composeApp/src/desktopMain/kotlin/main.kt | 15 ++++++++--- .../wasmJsMain/kotlin/Notification.wasmJs.kt | 26 ++++++++++++++++++ shared/src/jvmMain/kotlin/Platform.jvm.kt | 19 +++++++++++++ 10 files changed, 162 insertions(+), 8 deletions(-) create mode 100644 composeApp/src/androidMain/kotlin/Notification.android.kt create mode 100644 composeApp/src/commonMain/kotlin/Notification.kt create mode 100644 composeApp/src/desktopMain/kotlin/Notification.desktop.kt create mode 100644 composeApp/src/wasmJsMain/kotlin/Notification.wasmJs.kt diff --git a/build-number.properties b/build-number.properties index 16f3a87..e15d733 100644 --- a/build-number.properties +++ b/build-number.properties @@ -15,4 +15,4 @@ # You should have received a copy of the GNU General Public License along # with Fhraise. If not, see . # -buildNumber=28 +buildNumber=30 diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml index 944c5a7..b30d819 100644 --- a/composeApp/src/androidMain/AndroidManifest.xml +++ b/composeApp/src/androidMain/AndroidManifest.xml @@ -20,6 +20,7 @@ xmlns:tools="http://schemas.android.com/tools"> + . + */ + +import androidx.core.app.NotificationCompat + +object Notification { + var send: (channel: String, title: String, message: String, priority: Int) -> Unit = { _, _, _, _ -> } +} + +actual fun sendVerifyCodeNotification(code: String) { + Notification.send("verifyCode", "验证码", code, NotificationCompat.PRIORITY_HIGH) +} diff --git a/composeApp/src/androidMain/kotlin/xyz/xfqlittlefan/fhraise/MainActivity.kt b/composeApp/src/androidMain/kotlin/xyz/xfqlittlefan/fhraise/MainActivity.kt index 8cf4c42..4cee96b 100644 --- a/composeApp/src/androidMain/kotlin/xyz/xfqlittlefan/fhraise/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/xyz/xfqlittlefan/fhraise/MainActivity.kt @@ -18,7 +18,9 @@ package xyz.xfqlittlefan.fhraise +import Notification import Permission +import android.app.NotificationManager import android.content.pm.PackageManager import android.graphics.Color import android.os.Build @@ -32,6 +34,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import com.arkivanov.decompose.defaultComponentContext @@ -67,7 +70,7 @@ class MainActivity : ComponentActivity() { val verifyCodeChannelId = "verifyCode" val verifyCodeChannelName = "模拟验证码" val verifyCodeChannelDescription = "模拟验证码的通知" - val verifyCodeChannelImportance = android.app.NotificationManager.IMPORTANCE_HIGH + val verifyCodeChannelImportance = NotificationManager.IMPORTANCE_HIGH val verifyCodeChannel = android.app.NotificationChannel( verifyCodeChannelId, verifyCodeChannelName, verifyCodeChannelImportance ).apply { @@ -85,13 +88,13 @@ class MainActivity : ComponentActivity() { } Permission.checkNotificationPermissionGranted = { - ContextCompat.checkSelfPermission( + Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU || ContextCompat.checkSelfPermission( this, android.Manifest.permission.POST_NOTIFICATIONS ) == PackageManager.PERMISSION_GRANTED } Permission.requestNotificationPermission = { - if (Permission.checkNotificationPermissionGranted() != true) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && Permission.checkNotificationPermissionGranted() != true) { suspendCoroutine { notificationPermissionRequestContinuation = it notificationPermissionRequestLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS) @@ -101,6 +104,21 @@ class MainActivity : ComponentActivity() { } } + Notification.send = { channel, title, message, priority -> + val notification = NotificationCompat.Builder(this, "verifyCode").apply { + setSmallIcon(R.drawable.ic_launcher_foreground) + setContentTitle(title) + setContentText(message) + setPriority(priority) + setCategory(NotificationCompat.CATEGORY_MESSAGE) + setDefaults(NotificationCompat.DEFAULT_SOUND or NotificationCompat.DEFAULT_VIBRATE) + }.build() + val notificationManager = getSystemService(android.app.NotificationManager::class.java) + val id = + (channel.hashCode() shl 48) or (title.hashCode() shl 32) or (message.hashCode() shl 16) or priority.hashCode() + notificationManager.notify(id, notification) + } + val rootComponent = AppRootComponent(componentContext = defaultComponentContext()) setContent { diff --git a/composeApp/src/commonMain/kotlin/Notification.kt b/composeApp/src/commonMain/kotlin/Notification.kt new file mode 100644 index 0000000..9118d5c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/Notification.kt @@ -0,0 +1,19 @@ +/* + * This file is part of Fhraise. + * Copyright (c) 2024 HSAS Foodies. All Rights Reserved. + * + * Fhraise 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. + * + * Fhraise 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 Fhraise. If not, see . + */ + +expect fun sendVerifyCodeNotification(code: String) diff --git a/composeApp/src/commonMain/kotlin/data/components/root/SignInComponent.kt b/composeApp/src/commonMain/kotlin/data/components/root/SignInComponent.kt index a6840c3..1a5c526 100644 --- a/composeApp/src/commonMain/kotlin/data/components/root/SignInComponent.kt +++ b/composeApp/src/commonMain/kotlin/data/components/root/SignInComponent.kt @@ -30,6 +30,7 @@ import data.componentScope import kotlinx.coroutines.Job import kotlinx.coroutines.launch import notificationPermissionGranted +import sendVerifyCodeNotification interface SignInComponent : AppComponentContext { val nextColorMode: ColorMode @@ -170,13 +171,20 @@ class AppSignInComponent( if (notificationPermissionGranted != true) { componentScope.launch { val result = requestAppNotificationPermission() - if (result == false) { + if (result != false) { + doSendVerifyCode() + } else { verifyCode = "114514" // TODO verifyCodeSentSnackbarJob?.cancel() snackbarHostState.showSnackbar("通知权限未授予,验证码已自动填写", withDismissAction = true) } } } + doSendVerifyCode() + } + + private fun doSendVerifyCode() { + sendVerifyCodeNotification("114514") // TODO verifyCodeSentSnackbarJob?.cancel() verifyCodeSentSnackbarJob = componentScope.launch { snackbarHostState.showSnackbar("验证码已发送", withDismissAction = true) diff --git a/composeApp/src/desktopMain/kotlin/Notification.desktop.kt b/composeApp/src/desktopMain/kotlin/Notification.desktop.kt new file mode 100644 index 0000000..f942b39 --- /dev/null +++ b/composeApp/src/desktopMain/kotlin/Notification.desktop.kt @@ -0,0 +1,27 @@ +/* + * This file is part of Fhraise. + * Copyright (c) 2024 HSAS Foodies. All Rights Reserved. + * + * Fhraise 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. + * + * Fhraise 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 Fhraise. If not, see . + */ + +import androidx.compose.ui.window.Notification.Type + +object Notification { + var send: (title: String, message: String, type: Type) -> Unit = { _, _, _ -> } +} + +actual fun sendVerifyCodeNotification(code: String) { + Notification.send("验证码", code, Type.Info) +} diff --git a/composeApp/src/desktopMain/kotlin/main.kt b/composeApp/src/desktopMain/kotlin/main.kt index 8bcf2dd..25524f5 100644 --- a/composeApp/src/desktopMain/kotlin/main.kt +++ b/composeApp/src/desktopMain/kotlin/main.kt @@ -19,9 +19,7 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Window -import androidx.compose.ui.window.application -import androidx.compose.ui.window.rememberWindowState +import androidx.compose.ui.window.* import com.arkivanov.decompose.DefaultComponentContext import com.arkivanov.decompose.ExperimentalDecomposeApi import com.arkivanov.decompose.extensions.compose.lifecycle.LifecycleController @@ -46,6 +44,17 @@ fun main() { application { val windowState = rememberWindowState(size = DpSize(width = 1000.dp, height = 800.dp)) + val trayState = rememberTrayState() + + Notification.send = { title, message, type -> + trayState.sendNotification(Notification(title, message, type)) + } + + Tray( + icon = painterResource(DrawableResource("drawable/fhraise_logo.xml")), + state = trayState, + tooltip = "Fhraise", + ) LifecycleController(lifecycleRegistry, windowState) diff --git a/composeApp/src/wasmJsMain/kotlin/Notification.wasmJs.kt b/composeApp/src/wasmJsMain/kotlin/Notification.wasmJs.kt new file mode 100644 index 0000000..f17d499 --- /dev/null +++ b/composeApp/src/wasmJsMain/kotlin/Notification.wasmJs.kt @@ -0,0 +1,26 @@ +/* + * This file is part of Fhraise. + * Copyright (c) 2024 HSAS Foodies. All Rights Reserved. + * + * Fhraise 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. + * + * Fhraise 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 Fhraise. If not, see . + */ + +import org.w3c.notifications.Notification +import org.w3c.notifications.NotificationOptions + +actual fun sendVerifyCodeNotification(code: String) { + Notification( + title = "验证码", options = NotificationOptions(body = code) + ) +} diff --git a/shared/src/jvmMain/kotlin/Platform.jvm.kt b/shared/src/jvmMain/kotlin/Platform.jvm.kt index 43f4bd3..c4792f0 100644 --- a/shared/src/jvmMain/kotlin/Platform.jvm.kt +++ b/shared/src/jvmMain/kotlin/Platform.jvm.kt @@ -21,3 +21,22 @@ class JVMPlatform : Platform { } actual fun getPlatform(): Platform = JVMPlatform() + +enum class DesktopPlatform { + Linux, Windows, MacOS, Unknown; + + companion object { + /** + * Identify OS on which the application is currently running. + */ + val Current: DesktopPlatform by lazy { + val name = System.getProperty("os.name") + when { + name?.startsWith("Linux") == true -> Linux + name?.startsWith("Win") == true -> Windows + name == "Mac OS X" -> MacOS + else -> Unknown + } + } + } +}