From 6aeeb3cb879a6ccf70824ba5e7b8ce0cf0e36091 Mon Sep 17 00:00:00 2001 From: karam <1ahmedkaram1@gmail.com> Date: Tue, 3 Jun 2025 13:58:20 +0400 Subject: [PATCH 1/2] Create notification sample content to start use notification core implementation --- .../components/NotificationsSamplesContent.kt | 255 +++++++++++++++++- 1 file changed, 251 insertions(+), 4 deletions(-) diff --git a/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt b/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt index a288af20..30ff1cf6 100644 --- a/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt +++ b/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt @@ -1,11 +1,32 @@ package com.metacto.catalogapp.presentation.notifications.components +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import com.metacto.core.ui.navigation.NavManager +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.metacto.catalogapp.presentation.app.globalState.IAppGlobalState import com.metacto.catalogapp.presentation.components.containers.AppScreenColumn import com.metacto.catalogapp.presentation.notifications.NotificationsSamplesContract.Event import com.metacto.catalogapp.presentation.notifications.NotificationsSamplesContract.State +import com.metacto.catalogapp.presentation.theme.spacings +import com.metacto.core.notifications.INotificationManager +import com.metacto.core.notifications.Notification +import com.metacto.core.ui.components.buttons.PrimaryFilledButton +import com.metacto.core.ui.navigation.NavManager +import kotlinx.coroutines.launch +import kotlinx.datetime.Clock +import kotlinx.datetime.DateTimePeriod +import kotlinx.datetime.TimeZone +import kotlinx.datetime.plus +import kotlinx.datetime.toLocalDateTime import org.koin.compose.koinInject +import kotlin.random.Random @Composable internal fun NotificationsSamplesContent( @@ -14,10 +35,16 @@ internal fun NotificationsSamplesContent( ) { // Di val navManager = koinInject() + val notificationManager = koinInject() + val globalState = koinInject() + val coroutineScope = rememberCoroutineScope() + + var lastScheduledNotificationId by remember { mutableStateOf(null) } + var currentPushToken by remember { mutableStateOf(null) } // Container column AppScreenColumn( - title = "Notifications", + title = "Notifications Samples", isScrollable = true, showToolbar = true, showBack = true, @@ -25,6 +52,226 @@ internal fun NotificationsSamplesContent( navManager.goBack() }, ) { - // TODO: Render content + PrimaryFilledButton( + text = "Schedule Notification (in 10s)", + onClick = { + val notificationId = Random.nextInt(1000, 2000) + val notification = Notification.new( + id = notificationId, + title = "Test Notification $notificationId", + body = "This is a scheduled notification.", + ) + val scheduleTime = Clock.System.now() + .plus(DateTimePeriod(seconds = 10), TimeZone.currentSystemDefault()) + .toLocalDateTime(TimeZone.currentSystemDefault()) + + try { + notificationManager.schedule(notification, scheduleTime) + lastScheduledNotificationId = notificationId + globalState.showSuccess("Notification $notificationId scheduled for $scheduleTime.") + } catch (e: Throwable) { + globalState.showError("Failed to schedule notification: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth() + ) + + PrimaryFilledButton( + text = "Schedule Repeating Daily (14:30)", + onClick = { + val notificationId = Random.nextInt(2000, 3000) + val notification = Notification.new( + id = notificationId, + title = "Daily Repeat $notificationId", + body = "This is a daily repeating notification for 14:30.", + ) + try { + notificationManager.scheduleRepeating(notification, hourOfDay = 14, minute = 30) + lastScheduledNotificationId = notificationId + globalState.showSuccess("Notification $notificationId scheduled for daily 14:30.") + } catch (e: Throwable) { + globalState.showError("Failed to schedule daily repeating: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Schedule Repeating Interval (1 min)", + onClick = { + val notificationId = Random.nextInt(3000, 4000) + val notification = Notification.new( + id = notificationId, + title = "Interval Repeat $notificationId", + body = "This repeats every 1 minute.", + ) + try { + notificationManager.scheduleRepeating(notification, intervalMinutes = 1) + lastScheduledNotificationId = notificationId + globalState.showSuccess("Notification $notificationId scheduled for 1 min interval.") + } catch (e: Throwable) { + globalState.showError("Failed to schedule interval repeating: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Cancel Scheduled Notification", + onClick = { + lastScheduledNotificationId?.let { + try { + notificationManager.cancelScheduled(it) + globalState.showSuccess("Cancelled scheduled notification: $it") + lastScheduledNotificationId = null + } catch (e: Throwable) { + globalState.showError("Failed to cancel notification $it: ${e.message}") + } + } ?: globalState.showError("No notification ID to cancel.") + }, + isEnabled = lastScheduledNotificationId != null, // Corrected: Using the isEnabled parameter + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Remove Delivered Notification", + onClick = { + lastScheduledNotificationId?.let { + try { + notificationManager.removeDelivered(it) + globalState.showSuccess("Attempted to remove delivered notification: $it") + } catch (e: Throwable) { + globalState.showError("Failed to remove delivered $it: ${e.message}") + } + } ?: globalState.showError("No notification ID to remove (using last scheduled ID for demo).") + }, + isEnabled = lastScheduledNotificationId != null, // Corrected: Using the isEnabled parameter + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Remove All Delivered Notifications", + onClick = { + try { + notificationManager.removeAllDelivered() + globalState.showSuccess("Removed all delivered notifications.") + } catch (e: Throwable) { + globalState.showError("Failed to remove all delivered: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Clear Badge Count", + onClick = { + try { + notificationManager.clearBadgeCount() + globalState.showSuccess("Badge count cleared.") + } catch (e: Throwable) { + globalState.showError("Failed to clear badge count: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Get Push Token", + onClick = { + coroutineScope.launch { + try { + val token = notificationManager.getPushNotificationToken() + currentPushToken = token + if (token != null) { + globalState.showSuccess("Push Token: $token") + } else { + globalState.showError("Failed to get push token or token is null.") + } + } catch (e: Throwable) { + currentPushToken = null + globalState.showError("Error getting push token: ${e.message}") + } + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + currentPushToken?.let { token -> + Text( + text = "Current Token: $token", + modifier = Modifier.padding(top = spacings.spacing8) + ) + } + + PrimaryFilledButton( + text = "Delete Push Token", + onClick = { + coroutineScope.launch { + try { + notificationManager.deletePushNotificationToken() + currentPushToken = null + globalState.showSuccess("Push token deleted.") + } catch (e: Throwable) { + globalState.showError("Failed to delete push token: ${e.message}") + } + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Subscribe to 'testTopic'", + onClick = { + coroutineScope.launch { + try { + notificationManager.subscribeToTopic("testTopic") + globalState.showSuccess("Subscribed to 'testTopic'.") + } catch (e: Throwable) { + globalState.showError("Failed to subscribe: ${e.message}") + } + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Unsubscribe from 'testTopic'", + onClick = { + coroutineScope.launch { + try { + notificationManager.unSubscribeFromTopic("testTopic") + globalState.showSuccess("Unsubscribed from 'testTopic'.") + } catch (e: Throwable) { + globalState.showError("Failed to unsubscribe: ${e.message}") + } + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) + + PrimaryFilledButton( + text = "Setup Notification Listeners", + onClick = { + try { + notificationManager.onNewTokenListener { token -> + globalState.showSuccess("Listener: New Token: $token") + currentPushToken = token + } + notificationManager.onReceiveMessageNotification { title, body -> + globalState.showSuccess("Listener: Message: $title - $body") + } + notificationManager.onReceiveDataNotification { payload -> + globalState.showSuccess("Listener: Data: $payload") + } + notificationManager.onNotificationClicked { payload -> + globalState.showSuccess("Listener: Clicked: $payload") + } + globalState.showSuccess("Notification listeners have been set up.") + } catch (e: Throwable) { + globalState.showError("Failed to set up listeners: ${e.message}") + } + }, + modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + ) } -} +} \ No newline at end of file From c7b786e8578035ee546c0f306ae225b45e1611d3 Mon Sep 17 00:00:00 2001 From: karam <1ahmedkaram1@gmail.com> Date: Tue, 3 Jun 2025 14:57:13 +0400 Subject: [PATCH 2/2] Create notification sample content to start use notification core implementation --- .../components/NotificationsSamplesContent.kt | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt b/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt index 30ff1cf6..4350465e 100644 --- a/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt +++ b/samples/catalog-app-shared/src/commonMain/kotlin/com/metacto/catalogapp/presentation/notifications/components/NotificationsSamplesContent.kt @@ -1,5 +1,6 @@ package com.metacto.catalogapp.presentation.notifications.components +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.Text @@ -44,6 +45,7 @@ internal fun NotificationsSamplesContent( // Container column AppScreenColumn( + verticalArrangement = Arrangement.spacedBy(spacings.spacing16), title = "Notifications Samples", isScrollable = true, showToolbar = true, @@ -93,7 +95,7 @@ internal fun NotificationsSamplesContent( globalState.showError("Failed to schedule daily repeating: ${e.message}") } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -113,7 +115,7 @@ internal fun NotificationsSamplesContent( globalState.showError("Failed to schedule interval repeating: ${e.message}") } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -129,8 +131,8 @@ internal fun NotificationsSamplesContent( } } ?: globalState.showError("No notification ID to cancel.") }, - isEnabled = lastScheduledNotificationId != null, // Corrected: Using the isEnabled parameter - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + isEnabled = lastScheduledNotificationId != null, + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -145,8 +147,8 @@ internal fun NotificationsSamplesContent( } } ?: globalState.showError("No notification ID to remove (using last scheduled ID for demo).") }, - isEnabled = lastScheduledNotificationId != null, // Corrected: Using the isEnabled parameter - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + isEnabled = lastScheduledNotificationId != null, + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -159,7 +161,7 @@ internal fun NotificationsSamplesContent( globalState.showError("Failed to remove all delivered: ${e.message}") } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -172,7 +174,7 @@ internal fun NotificationsSamplesContent( globalState.showError("Failed to clear badge count: ${e.message}") } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -193,7 +195,7 @@ internal fun NotificationsSamplesContent( } } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) currentPushToken?.let { token -> @@ -216,7 +218,7 @@ internal fun NotificationsSamplesContent( } } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -231,7 +233,7 @@ internal fun NotificationsSamplesContent( } } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -246,7 +248,7 @@ internal fun NotificationsSamplesContent( } } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) PrimaryFilledButton( @@ -271,7 +273,7 @@ internal fun NotificationsSamplesContent( globalState.showError("Failed to set up listeners: ${e.message}") } }, - modifier = Modifier.fillMaxWidth().padding(top = spacings.spacing16) + modifier = Modifier.fillMaxWidth() ) } } \ No newline at end of file