From 0fe9d4e60b52b613b6b58fd8354a42d94f5a0e5c Mon Sep 17 00:00:00 2001 From: Raphael Teyssandier Date: Mon, 18 Aug 2025 16:01:03 +0200 Subject: [PATCH] Feature/system notification (#101) * feature: System notification * feature: Type * fix: Settings --------- Co-authored-by: TEYSSANDIER Raphael --- .gitignore | 2 + .../flocondesktop/app/di/AppModule.kt | 4 +- .../common/ui/feedback/FeedbackDisplayer.kt | 13 --- .../ui/feedback/FeedbackDisplayerImpl.kt | 28 ++++-- .../ui/feedback/FeedbackDisplayerView.kt | 1 + .../features/analytics/AnalyticsViewModel.kt | 2 +- .../features/dashboard/DashboardViewModel.kt | 2 +- .../features/database/DatabaseViewModel.kt | 2 +- .../features/deeplinks/DeepLinkViewModel.kt | 2 +- .../features/files/FilesViewModel.kt | 2 +- .../features/images/ImagesViewModel.kt | 2 +- .../features/network/NetworkMocksViewModel.kt | 2 +- .../features/network/NetworkViewModel.kt | 2 +- .../SharedPreferencesViewModel.kt | 2 +- .../features/table/TableViewModel.kt | 2 +- .../flocondesktop/main/ui/MainScreen.kt | 12 ++- .../main/ui/settings/SettingsViewModel.kt | 2 +- .../messages/ui/MessagesServerDelegate.kt | 2 +- .../github/openflocon/flocondesktop/Main.kt | 87 ++++++++++++++++--- .../domain/feedback/FeedbackDisplayer.kt | 27 ++++++ .../feedback/FeedbackDisplayerHandler.kt | 9 +- .../usecase/HandleIncomingMessagesUseCase.kt | 2 +- 22 files changed, 158 insertions(+), 51 deletions(-) create mode 100644 .gitignore delete mode 100644 FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayer.kt create mode 100644 FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayer.kt rename FloconDesktop/{composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui => domain/src/commonMain/kotlin/io/github/openflocon/domain}/feedback/FeedbackDisplayerHandler.kt (50%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..9bea4330 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.DS_Store diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppModule.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppModule.kt index 2edd061a..bc7db06b 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppModule.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/app/di/AppModule.kt @@ -1,8 +1,8 @@ package io.github.openflocon.flocondesktop.app.di import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerHandler +import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayerImpl import org.koin.core.module.dsl.bind import org.koin.core.module.dsl.singleOf diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayer.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayer.kt deleted file mode 100644 index 01fb3c63..00000000 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayer.kt +++ /dev/null @@ -1,13 +0,0 @@ -package io.github.openflocon.flocondesktop.common.ui.feedback - -interface FeedbackDisplayer { - fun displayMessage( - message: String, - type: MessageType = MessageType.Success, - ) - - enum class MessageType { - Success, - Error, - } -} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerImpl.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerImpl.kt index 9563b03f..6793efca 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerImpl.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerImpl.kt @@ -1,6 +1,10 @@ package io.github.openflocon.flocondesktop.common.ui.feedback import io.github.openflocon.domain.common.DispatcherProvider +import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler.MessageToDisplayUi +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler.NotificationToDisplayUi import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.Channel @@ -14,10 +18,11 @@ class FeedbackDisplayerImpl( FeedbackDisplayerHandler { private val scope = CoroutineScope(dispatcherProvider.ui + SupervisorJob()) - private val _messagesToDisplay: Channel = - Channel() - override val messagesToDisplay: Flow = - _messagesToDisplay.receiveAsFlow() + private val _messagesToDisplay: Channel = Channel() + override val messagesToDisplay: Flow = _messagesToDisplay.receiveAsFlow() + + private val _notificationsToDisplay: Channel = Channel() + override val notificationsToDisplay: Flow = _notificationsToDisplay.receiveAsFlow() override fun displayMessage( message: String, @@ -25,7 +30,7 @@ class FeedbackDisplayerImpl( ) { scope.launch { _messagesToDisplay.send( - FeedbackDisplayerHandler.MessageToDisplayUi( + MessageToDisplayUi( message = message, type = type, id = System.currentTimeMillis().toString(), @@ -33,4 +38,17 @@ class FeedbackDisplayerImpl( ) } } + + override fun displayNotification(title: String, message: String, type: FeedbackDisplayer.NotificationType) { + scope.launch { + _notificationsToDisplay.send( + NotificationToDisplayUi( + title = title, + message = message, + type = type + ) + ) + } + } + } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerView.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerView.kt index 1f1a8c3b..c128d4f5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerView.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerView.kt @@ -15,6 +15,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler import io.github.openflocon.library.designsystem.FloconTheme import org.koin.compose.koinInject diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt index 49fab7f3..588120b5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/analytics/AnalyticsViewModel.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.analytics.usecase.ObserveCurrentDeviceAnalyticsContentUseCase import io.github.openflocon.domain.analytics.usecase.ResetCurrentDeviceSelectedAnalyticsUseCase import io.github.openflocon.domain.common.DispatcherProvider -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.analytics.delegate.AnalyticsSelectorDelegate import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsContentStateUiModel import io.github.openflocon.flocondesktop.features.analytics.model.AnalyticsRowUiModel diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardViewModel.kt index 0cf98f8d..e105c029 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/dashboard/DashboardViewModel.kt @@ -7,7 +7,7 @@ import io.github.openflocon.domain.dashboard.usecase.ObserveCurrentDeviceDashboa import io.github.openflocon.domain.dashboard.usecase.SendCheckBoxUpdateDeviceDeviceUseCase import io.github.openflocon.domain.dashboard.usecase.SendClickEventToDeviceDeviceUseCase import io.github.openflocon.domain.dashboard.usecase.SubmitTextFieldToDeviceDeviceUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.dashboard.delegate.DashboardSelectorDelegate import io.github.openflocon.flocondesktop.features.dashboard.mapper.toUi import io.github.openflocon.flocondesktop.features.dashboard.model.DashboardViewState diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/DatabaseViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/DatabaseViewModel.kt index 25ef11ee..dce553bb 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/DatabaseViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/database/DatabaseViewModel.kt @@ -6,7 +6,7 @@ import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.database.models.DatabaseExecuteSqlResponseDomainModel import io.github.openflocon.domain.database.usecase.ExecuteDatabaseQueryUseCase import io.github.openflocon.domain.database.usecase.ObserveLastSuccessQueriesUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.database.delegate.DatabaseSelectorDelegate import io.github.openflocon.flocondesktop.features.database.model.DatabaseRowUiModel import io.github.openflocon.flocondesktop.features.database.model.DatabaseScreenState diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/DeepLinkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/DeepLinkViewModel.kt index 6bf5d387..3947a72a 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/DeepLinkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/deeplinks/DeepLinkViewModel.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.deeplink.usecase.ExecuteDeeplinkUseCase import io.github.openflocon.domain.deeplink.usecase.ObserveCurrentDeviceDeeplinkUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.deeplinks.mapper.mapToUi import io.github.openflocon.flocondesktop.features.deeplinks.model.DeeplinkPart import io.github.openflocon.flocondesktop.features.deeplinks.model.DeeplinkViewState diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/FilesViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/FilesViewModel.kt index b0679c95..3acadf9f 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/FilesViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/files/FilesViewModel.kt @@ -10,7 +10,7 @@ import io.github.openflocon.domain.files.usecase.DeleteFileUseCase import io.github.openflocon.domain.files.usecase.DeleteFolderContentUseCase import io.github.openflocon.domain.files.usecase.ObserveFolderContentUseCase import io.github.openflocon.domain.files.usecase.RefreshFolderContentUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.files.mapper.buildContextualActions import io.github.openflocon.flocondesktop.features.files.mapper.toDomain import io.github.openflocon.flocondesktop.features.files.mapper.toUi diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/ImagesViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/ImagesViewModel.kt index fa48993c..7679a759 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/ImagesViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/images/ImagesViewModel.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.images.usecase.ObserveImagesUseCase import io.github.openflocon.domain.images.usecase.ResetCurrentDeviceImagesUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.images.model.ImagesStateUiModel import io.github.openflocon.flocondesktop.features.images.model.ImagesUiModel import io.github.openflocon.flocondesktop.features.network.mapper.formatTimestamp diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt index f80b18a3..ce590e5c 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkMocksViewModel.kt @@ -10,7 +10,7 @@ import io.github.openflocon.domain.network.usecase.mocks.GenerateNetworkMockFrom import io.github.openflocon.domain.network.usecase.mocks.GetNetworkMockByIdUseCase import io.github.openflocon.domain.network.usecase.mocks.ObserveNetworkMocksUseCase import io.github.openflocon.domain.network.usecase.mocks.UpdateNetworkMockIsEnabledUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.network.mapper.toDomain import io.github.openflocon.flocondesktop.features.network.mapper.toLineUi import io.github.openflocon.flocondesktop.features.network.mapper.toUi diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkViewModel.kt index 32b90763..765545fd 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/network/NetworkViewModel.kt @@ -9,7 +9,7 @@ import io.github.openflocon.domain.network.usecase.ObserveHttpRequestsUseCase import io.github.openflocon.domain.network.usecase.RemoveHttpRequestUseCase import io.github.openflocon.domain.network.usecase.RemoveHttpRequestsBeforeUseCase import io.github.openflocon.domain.network.usecase.ResetCurrentDeviceHttpRequestsUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.network.delegate.HeaderDelegate import io.github.openflocon.flocondesktop.features.network.mapper.toDetailUi import io.github.openflocon.flocondesktop.features.network.mapper.toUi diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/SharedPreferencesViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/SharedPreferencesViewModel.kt index 8d9fb2a9..fd4bd1d6 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/SharedPreferencesViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/sharedpreferences/SharedPreferencesViewModel.kt @@ -6,7 +6,7 @@ import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.sharedpreference.models.SharedPreferenceRowDomainModel import io.github.openflocon.domain.sharedpreference.usecase.EditSharedPrefFieldUseCase import io.github.openflocon.domain.sharedpreference.usecase.ObserveCurrentDeviceSharedPreferenceValuesUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.sharedpreferences.delegate.SharedPrefSelectorDelegate import io.github.openflocon.flocondesktop.features.sharedpreferences.model.DeviceSharedPrefUiModel import io.github.openflocon.flocondesktop.features.sharedpreferences.model.SharedPreferencesRowUiModel diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/TableViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/TableViewModel.kt index bfd02fe8..fe8a9a26 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/TableViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/features/table/TableViewModel.kt @@ -5,7 +5,7 @@ import androidx.lifecycle.viewModelScope import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.table.usecase.ObserveCurrentDeviceTableContentUseCase import io.github.openflocon.domain.table.usecase.ResetCurrentDeviceSelectedTableUseCase -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.flocondesktop.features.network.mapper.formatTimestamp import io.github.openflocon.flocondesktop.features.table.delegate.TableSelectorDelegate import io.github.openflocon.flocondesktop.features.table.model.DeviceTableUiModel diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt index 3bc94207..48f491f5 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/MainScreen.kt @@ -165,25 +165,23 @@ private fun MainScreen( SubScreen.Settings -> { SettingsScreen( - modifier = - Modifier - .fillMaxSize(), + modifier = Modifier.fillMaxSize(), ) } SubScreen.Deeplinks -> { DeeplinkScreen( modifier = - Modifier - .fillMaxSize(), + Modifier + .fillMaxSize(), ) } SubScreen.Analytics -> { AnalyticsScreen( modifier = - Modifier - .fillMaxSize(), + Modifier + .fillMaxSize(), ) } } diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt index bb9e66f8..11f713a1 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/main/ui/settings/SettingsViewModel.kt @@ -6,7 +6,7 @@ import io.github.openflocon.domain.common.DispatcherProvider import io.github.openflocon.domain.settings.repository.SettingsRepository import io.github.openflocon.domain.settings.usecase.TestAdbUseCase import io.github.openflocon.flocondesktop.app.InitialSetupStateHolder -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/messages/ui/MessagesServerDelegate.kt b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/messages/ui/MessagesServerDelegate.kt index 2894c11a..cb44f411 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/messages/ui/MessagesServerDelegate.kt +++ b/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/messages/ui/MessagesServerDelegate.kt @@ -7,7 +7,7 @@ import io.github.openflocon.domain.common.Failure import io.github.openflocon.domain.common.Success import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableDelegate import io.github.openflocon.flocondesktop.common.coroutines.closeable.CloseableScoped -import io.github.openflocon.flocondesktop.common.ui.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayer import io.github.openflocon.domain.messages.usecase.HandleIncomingMessagesUseCase import io.github.openflocon.domain.messages.usecase.StartServerUseCase import kotlinx.coroutines.delay diff --git a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt index f6bc49a9..40dfdad4 100644 --- a/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt +++ b/FloconDesktop/composeApp/src/desktopMain/kotlin/io/github/openflocon/flocondesktop/Main.kt @@ -1,17 +1,27 @@ package io.github.openflocon.flocondesktop +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.window.ApplicationScope +import androidx.compose.ui.window.FrameWindowScope +import androidx.compose.ui.window.MenuBar +import androidx.compose.ui.window.Notification +import androidx.compose.ui.window.Tray import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberTrayState import androidx.compose.ui.window.rememberWindowState import coil3.ImageLoader import coil3.compose.setSingletonImageLoaderFactory import coil3.network.ktor3.KtorNetworkFetcherFactory import flocondesktop.composeapp.generated.resources.Res import flocondesktop.composeapp.generated.resources.app_icon_small +import io.github.openflocon.domain.feedback.FeedbackDisplayer +import io.github.openflocon.domain.feedback.FeedbackDisplayerHandler import io.github.openflocon.flocondesktop.about.AboutScreen import io.github.openflocon.flocondesktop.window.MIN_WINDOW_HEIGHT import io.github.openflocon.flocondesktop.window.MIN_WINDOW_WIDTH @@ -20,14 +30,22 @@ import io.github.openflocon.flocondesktop.window.WindowStateSaver import io.github.openflocon.flocondesktop.window.size import io.github.openflocon.flocondesktop.window.windowPosition import org.jetbrains.compose.resources.painterResource +import org.koin.compose.koinInject import java.awt.Desktop import java.awt.Dimension +private const val ACTIVATE_TRAY_NOTIFICATION = false + fun main() { System.setProperty("apple.awt.application.name", "Flocon") return application { var openAbout by remember { mutableStateOf(false) } + val savedState = remember { WindowStateSaver.load() } + val windowState = rememberWindowState( + size = savedState.size(), + position = savedState.windowPosition(), + ) Desktop.getDesktop().setAboutHandler { openAbout = true @@ -41,15 +59,6 @@ fun main() { }.build() } - val savedState = remember { - WindowStateSaver.load() - } - - val windowState = rememberWindowState( - size = savedState.size(), - position = savedState.windowPosition(), - ) - Window( state = windowState, onCloseRequest = { @@ -70,8 +79,12 @@ fun main() { icon = painterResource(Res.drawable.app_icon_small), // Remove black behind icon ) { window.minimumSize = Dimension(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) - App() + if (ACTIVATE_TRAY_NOTIFICATION) { + FloconTray() + } + // TODO later +// FloconMenu() if (openAbout) { AboutScreen( @@ -81,3 +94,57 @@ fun main() { } } } + +@Composable +private fun FrameWindowScope.FloconMenu() { + var openSettings by remember { mutableStateOf(false) } + + MenuBar { + Menu( + text = "Settings" + ) { + Item( + text = "Open", + onClick = { + openSettings = true + } + ) + } + } + + // TODO Later +// if (openSettings) { +// SettingsScreen( +// onCloseRequest = { openSettings = false } +// ) +// } +} + +@Composable +private fun ApplicationScope.FloconTray() { + val trayState = rememberTrayState() + val feedbackDisplayerHandler = koinInject() + + LaunchedEffect(Unit) { + feedbackDisplayerHandler.notificationsToDisplay + .collect { notification -> + trayState.sendNotification( + Notification( + title = notification.title, + message = notification.message, + type = when (notification.type) { + FeedbackDisplayer.NotificationType.None -> Notification.Type.None + FeedbackDisplayer.NotificationType.Info -> Notification.Type.Info + FeedbackDisplayer.NotificationType.Warning -> Notification.Type.Warning + FeedbackDisplayer.NotificationType.Error -> Notification.Type.Error + } + ) + ) + } + } + + Tray( + state = trayState, + icon = painterResource(Res.drawable.app_icon_small) + ) +} diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayer.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayer.kt new file mode 100644 index 00000000..8817358f --- /dev/null +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayer.kt @@ -0,0 +1,27 @@ +package io.github.openflocon.domain.feedback + +interface FeedbackDisplayer { + + fun displayMessage( + message: String, + type: MessageType = MessageType.Success, + ) + + fun displayNotification( + title: String, + message: String, + type: NotificationType = NotificationType.None + ) + + enum class MessageType { + Success, + Error, + } + + enum class NotificationType { + None, + Info, + Warning, + Error + } +} diff --git a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerHandler.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayerHandler.kt similarity index 50% rename from FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerHandler.kt rename to FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayerHandler.kt index 181853a2..f376cbc2 100644 --- a/FloconDesktop/composeApp/src/commonMain/kotlin/io/github/openflocon/flocondesktop/common/ui/feedback/FeedbackDisplayerHandler.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/feedback/FeedbackDisplayerHandler.kt @@ -1,13 +1,20 @@ -package io.github.openflocon.flocondesktop.common.ui.feedback +package io.github.openflocon.domain.feedback import kotlinx.coroutines.flow.Flow interface FeedbackDisplayerHandler { val messagesToDisplay: Flow + val notificationsToDisplay: Flow data class MessageToDisplayUi( val message: String, val type: FeedbackDisplayer.MessageType, val id: String, ) + + data class NotificationToDisplayUi( + val title: String, + val message: String, + val type: FeedbackDisplayer.NotificationType + ) } diff --git a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/messages/usecase/HandleIncomingMessagesUseCase.kt b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/messages/usecase/HandleIncomingMessagesUseCase.kt index b22dbb3c..ee2f5e41 100644 --- a/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/messages/usecase/HandleIncomingMessagesUseCase.kt +++ b/FloconDesktop/domain/src/commonMain/kotlin/io/github/openflocon/domain/messages/usecase/HandleIncomingMessagesUseCase.kt @@ -22,7 +22,7 @@ class HandleIncomingMessagesUseCase( .listenMessages() .onEach { val handleDeviceResult = handleDeviceUseCase(device = getDevice(it)) - if(handleDeviceResult.isNewDevice) { + if (handleDeviceResult.isNewDevice) { handleNewDeviceUseCase( deviceIdAndPackageName = DeviceIdAndPackageNameDomainModel( deviceId = handleDeviceResult.deviceId,