diff --git a/.github/workflows/android-build.yml b/.github/workflows/android-build.yml
index 4b4b39b3..985c39e8 100644
--- a/.github/workflows/android-build.yml
+++ b/.github/workflows/android-build.yml
@@ -32,3 +32,4 @@ jobs:
with:
webhook: ${{ secrets.DISCORD_WEBHOOK }}
status: ${{ job.status }}
+ content: "<@${{ secrets.DISCORD_NOTIFY_USER_ID }}> チェック終わったみたい ${{ secrets.DISCORD_NOTIFY_SUFFIX }}"
diff --git a/AndroidApp/app/src/main/AndroidManifest.xml b/AndroidApp/app/src/main/AndroidManifest.xml
index 4011bff2..291d236c 100644
--- a/AndroidApp/app/src/main/AndroidManifest.xml
+++ b/AndroidApp/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
DetailViewModel(get(), get(), get(), get(), params.get()) }
viewModel { TargetViewModel(get()) }
- viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get()) }
+ viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get()) }
// UseCase
factory { AddTargetAppUseCaseImpl(get()) }
@@ -102,7 +107,7 @@ class App : Application() {
factory { LoadAppUseCaseImpl(get(), get()) }
factory { LoadFilterConditionUseCaseImpl(get()) }
factory {
- NotifyTargetAppNotificationUseCaseImpl(get(), get())
+ NotifyTargetAppNotificationUseCaseImpl(get(), get(), get(), get())
}
factory { NotifyUseCaseImpl(get()) }
factory { PackageVisibilityGrantedUseCaseImpl(get()) }
@@ -110,5 +115,10 @@ class App : Application() {
factory { SaveAddressUseCaseImpl(get()) }
factory { SaveFilterConditionUseCaseImpl(get()) }
factory { ToggleIgnoreSummaryUseCaseImpl(get()) }
+ factory {
+ SaveWifiOnlyNotificationSettingUseCaseImpl(
+ get()
+ )
+ }
}
}
\ No newline at end of file
diff --git a/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/source/UserSettingsDataStore.kt b/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/source/UserSettingsDataStore.kt
index e150b741..544fc043 100644
--- a/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/source/UserSettingsDataStore.kt
+++ b/AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/source/UserSettingsDataStore.kt
@@ -6,12 +6,24 @@ import me.nya_n.notificationnotifier.model.UserSettings
class UserSettingsDataStore(
pref: SharedPreferences
) : KeyValueDataStore(pref) {
+ companion object {
+ const val DATA_STORE_NAME = "settings"
+ const val KEY_HOST = "host"
+ const val DEFAULT_HOST = ""
+ const val KEY_PORT = "port"
+ const val DEFAULT_PORT = -1
+ const val KEY_IS_PACKAGE_VISIBILITY_GRANTED = "isPackageVisibilityGranted"
+ const val DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED = false
+ const val KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED = "isWifiOnlyNotificationEnabled"
+ const val DEFAULT_IS_WIFI_ONLY_NOTIFICATION_ENABLED = false
+ }
fun get(): UserSettings {
return UserSettings(
get(KEY_HOST, DEFAULT_HOST),
get(KEY_PORT, DEFAULT_PORT),
- get(KEY_IS_PACKAGE_VISIBILITY_GRANTED, DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED)
+ get(KEY_IS_PACKAGE_VISIBILITY_GRANTED, DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED),
+ get(KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED, DEFAULT_IS_WIFI_ONLY_NOTIFICATION_ENABLED)
)
}
@@ -19,15 +31,6 @@ class UserSettingsDataStore(
put(KEY_HOST, settings.host)
put(KEY_PORT, settings.port)
put(KEY_IS_PACKAGE_VISIBILITY_GRANTED, settings.isPackageVisibilityGranted)
- }
-
- companion object {
- const val DATA_STORE_NAME = "settings"
- const val KEY_HOST = "host"
- const val DEFAULT_HOST = ""
- const val KEY_PORT = "port"
- const val DEFAULT_PORT = -1
- const val KEY_IS_PACKAGE_VISIBILITY_GRANTED = "isPackageVisibilityGranted"
- const val DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED = false
+ put(KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED, settings.isWifiOnlyNotificationEnabled)
}
}
\ No newline at end of file
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/SaveWifiOnlyNotificationSettingUseCase.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/SaveWifiOnlyNotificationSettingUseCase.kt
new file mode 100644
index 00000000..2e057d9f
--- /dev/null
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/SaveWifiOnlyNotificationSettingUseCase.kt
@@ -0,0 +1,5 @@
+package me.nya_n.notificationnotifier.domain.usecase
+
+interface SaveWifiOnlyNotificationSettingUseCase {
+ operator fun invoke(isWifiOnlyNotificationEnabled: Boolean): Result
+}
\ No newline at end of file
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
index 0230e740..1cfdf6a6 100644
--- a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt
@@ -1,14 +1,29 @@
package me.nya_n.notificationnotifier.domain.usecase.impl
+import android.Manifest
import android.app.Notification
+import android.net.ConnectivityManager
+import android.net.NetworkCapabilities
+import androidx.annotation.RequiresPermission
import me.nya_n.notificationnotifier.data.repository.AppRepository
+import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
import me.nya_n.notificationnotifier.domain.usecase.NotifyTargetAppNotificationUseCase
import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
class NotifyTargetAppNotificationUseCaseImpl(
+ private val connectionManager: ConnectivityManager,
private val appRepository: AppRepository,
+ private val userSettingsRepository: UserSettingsRepository,
private val notifyUseCase: NotifyUseCase,
) : NotifyTargetAppNotificationUseCase {
+ @get:RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
+ private val isConnectedToWifi: Boolean
+ get() {
+ val network = connectionManager.activeNetwork ?: return false
+ val capabilities = connectionManager.getNetworkCapabilities(network) ?: return false
+ return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
+ }
+
override suspend operator fun invoke(
packageName: String,
title: String,
@@ -16,6 +31,11 @@ class NotifyTargetAppNotificationUseCaseImpl(
flags: Int
): Result {
return runCatching {
+ val settings = userSettingsRepository.getUserSettings()
+ if (settings.isWifiOnlyNotificationEnabled && !isConnectedToWifi) {
+ return Result.success(Unit)
+ }
+
val targets = appRepository.getTargetAppList()
if (!targets.any { t -> t.packageName == packageName }) {
return Result.success(Unit)
diff --git a/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/SaveWifiOnlyNotificationSettingUseCaseImpl.kt b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/SaveWifiOnlyNotificationSettingUseCaseImpl.kt
new file mode 100644
index 00000000..7c3f15cf
--- /dev/null
+++ b/AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/SaveWifiOnlyNotificationSettingUseCaseImpl.kt
@@ -0,0 +1,20 @@
+package me.nya_n.notificationnotifier.domain.usecase.impl
+
+import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
+import me.nya_n.notificationnotifier.domain.usecase.SaveWifiOnlyNotificationSettingUseCase
+
+class SaveWifiOnlyNotificationSettingUseCaseImpl(
+ private val userSettingsRepository: UserSettingsRepository
+) : SaveWifiOnlyNotificationSettingUseCase {
+ override fun invoke(isWifiOnlyNotificationEnabled: Boolean): Result {
+ return runCatching {
+ val settings = userSettingsRepository.getUserSettings()
+ userSettingsRepository.saveUserSettings(
+ settings.copy(
+ isWifiOnlyNotificationEnabled = isWifiOnlyNotificationEnabled
+ )
+ )
+ return Result.success(Unit)
+ }
+ }
+}
\ No newline at end of file
diff --git a/AndroidApp/domain/src/test/java/me/nya_n/notificationnotifier/UseCaseTest.kt b/AndroidApp/domain/src/test/java/me/nya_n/notificationnotifier/UseCaseTest.kt
index 15492f19..f43faffa 100644
--- a/AndroidApp/domain/src/test/java/me/nya_n/notificationnotifier/UseCaseTest.kt
+++ b/AndroidApp/domain/src/test/java/me/nya_n/notificationnotifier/UseCaseTest.kt
@@ -49,7 +49,7 @@ class UseCaseTest {
@Test
fun `インストール済みアプリの取得_許可あり`() {
- every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, true)
+ every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, true, false)
every { appRepository.loadInstalledAppList() } returns listOf(InstalledApp("", ""))
val ret = loadAppUseCase.loadInstalledAppList()
@@ -61,7 +61,7 @@ class UseCaseTest {
@Test
fun `インストール済みアプリの取得_許可なし`() {
- every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, false)
+ every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, false, false)
every { appRepository.loadInstalledAppList() } throws PermissionDeniedException()
val ret = loadAppUseCase.loadInstalledAppList()
@@ -76,7 +76,8 @@ class UseCaseTest {
every { userSettingsRepository.getUserSettings() } returns UserSettings(
"192.168.10.18",
8484,
- true
+ true,
+ false
)
every { userSettingsRepository.saveUserSettings(any()) } just Runs
@@ -115,7 +116,8 @@ class UseCaseTest {
every { userSettingsRepository.getUserSettings() } returns UserSettings(
"192.168.10.18",
8484,
- true
+ true,
+ false
)
runTest(testDispatcher) {
diff --git a/AndroidApp/model/src/main/kotlin/me/nya_n/notificationnotifier/model/UserSettings.kt b/AndroidApp/model/src/main/kotlin/me/nya_n/notificationnotifier/model/UserSettings.kt
index 5552b5ea..16b6cca0 100644
--- a/AndroidApp/model/src/main/kotlin/me/nya_n/notificationnotifier/model/UserSettings.kt
+++ b/AndroidApp/model/src/main/kotlin/me/nya_n/notificationnotifier/model/UserSettings.kt
@@ -6,8 +6,10 @@ data class UserSettings(
val host: String,
val port: Int,
/**
- * @see https://support.google.com/googleplay/android-developer/answer/10158779
+ * @see パッケージ(アプリ)の広範な一覧取得(QUERY_ALL_PACKAGES)権限の使用
*/
@SerializedName("is_package_visibility_granted")
- val isPackageVisibilityGranted: Boolean
+ val isPackageVisibilityGranted: Boolean,
+ @SerializedName("is_wifi_only_notification_enabled")
+ val isWifiOnlyNotificationEnabled: Boolean
)
\ No newline at end of file
diff --git a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsScreen.kt b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsScreen.kt
index 20bcdd4e..0c6bbbb5 100644
--- a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsScreen.kt
+++ b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsScreen.kt
@@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -23,6 +24,7 @@ import androidx.compose.material.icons.outlined.CloudDownload
import androidx.compose.material.icons.outlined.CloudUpload
import androidx.compose.material.icons.outlined.Code
import androidx.compose.material.icons.outlined.Devices
+import androidx.compose.material3.Checkbox
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.SnackbarHostState
@@ -115,6 +117,8 @@ fun SettingsScreen(
versionName = uiState.appConfig.versionString,
onValueChange = { viewModel.updateAddress(it) },
onNotifyTest = { viewModel.notifyTest() },
+ isWifiOnlyNotificationEnabled = uiState.isWifiOnlyNotificationEnabled,
+ onWifiOnlySettingChanged = { viewModel.updateWifiOnlySetting(it) },
onExportData = { viewModel.event(UiEvent.ExportData()) },
onImportData = { viewModel.event(UiEvent.ImportData()) },
onLicense = { navController.navigate(Screen.License.route) },
@@ -130,6 +134,8 @@ fun SettingsContent(
versionName: String,
onValueChange: (String) -> Unit,
onNotifyTest: () -> Unit,
+ isWifiOnlyNotificationEnabled: Boolean,
+ onWifiOnlySettingChanged: (Boolean) -> Unit,
onExportData: () -> Unit,
onImportData: () -> Unit,
onLicense: () -> Unit,
@@ -147,7 +153,9 @@ fun SettingsContent(
NotifySettings(
address = address,
onValueChange = onValueChange,
- onNotifyTest = onNotifyTest
+ onNotifyTest = onNotifyTest,
+ isWifiOnlyNotificationEnabled = isWifiOnlyNotificationEnabled,
+ onWifiOnlySettingChanged = onWifiOnlySettingChanged
)
OtherSettings(
onExportData = onExportData,
@@ -176,7 +184,9 @@ fun SettingsContent(
private fun NotifySettings(
address: String,
onValueChange: (String) -> Unit,
- onNotifyTest: () -> Unit
+ onNotifyTest: () -> Unit,
+ isWifiOnlyNotificationEnabled: Boolean,
+ onWifiOnlySettingChanged: (Boolean) -> Unit
) {
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current
@@ -216,6 +226,15 @@ private fun NotifySettings(
text = stringResource(id = R.string.notify_test),
onClick = onNotifyTest
)
+ Row(
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Checkbox(
+ checked = isWifiOnlyNotificationEnabled,
+ onCheckedChange = onWifiOnlySettingChanged
+ )
+ Text("Wi-Fi接続時のみ転送する。")
+ }
}
/** その他の項目
@@ -293,6 +312,8 @@ private fun SettingsPreview() {
versionName = "1.0",
onValueChange = { },
onNotifyTest = { },
+ isWifiOnlyNotificationEnabled = true,
+ onWifiOnlySettingChanged = { },
onExportData = { },
onImportData = { },
onLicense = { },
diff --git a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsViewModel.kt b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsViewModel.kt
index f32fc666..a3639600 100644
--- a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsViewModel.kt
+++ b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsViewModel.kt
@@ -12,6 +12,7 @@ import me.nya_n.notificationnotifier.domain.usecase.ImportDataUseCase
import me.nya_n.notificationnotifier.domain.usecase.LoadAddressUseCase
import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
import me.nya_n.notificationnotifier.domain.usecase.SaveAddressUseCase
+import me.nya_n.notificationnotifier.domain.usecase.SaveWifiOnlyNotificationSettingUseCase
import me.nya_n.notificationnotifier.model.AppConfig
import me.nya_n.notificationnotifier.model.Message
import me.nya_n.notificationnotifier.ui.R
@@ -22,6 +23,7 @@ class SettingsViewModel(
loadAddressUseCase: LoadAddressUseCase,
private val saveAddressUseCase: SaveAddressUseCase,
private val notifyUseCase: NotifyUseCase,
+ private val saveWifiOnlyNotificationSettingUseCase: SaveWifiOnlyNotificationSettingUseCase,
private val exportDataUseCase: ExportDataUseCase,
private val importDataUseCase: ImportDataUseCase
) : BaseViewModel() {
@@ -59,6 +61,11 @@ class SettingsViewModel(
}
}
+ fun updateWifiOnlySetting(isWifiOnlyNotificationEnabled: Boolean) {
+ saveWifiOnlyNotificationSettingUseCase(isWifiOnlyNotificationEnabled)
+ _uiState.update { it.copy(isWifiOnlyNotificationEnabled = isWifiOnlyNotificationEnabled) }
+ }
+
/** バックアップのために外部ストレージにデータを保存 */
fun exportData(uri: Uri?) {
if (uri == null) {
diff --git a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/UiState.kt b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/UiState.kt
index b322643a..bb3e279b 100644
--- a/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/UiState.kt
+++ b/AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/UiState.kt
@@ -6,5 +6,6 @@ import me.nya_n.notificationnotifier.model.Message
data class UiState(
val appConfig: AppConfig,
val address: String = "",
- val message: Message? = null
+ val message: Message? = null,
+ val isWifiOnlyNotificationEnabled: Boolean = false
)
\ No newline at end of file
diff --git a/README.md b/README.md
index 7f35fca2..eb57434f 100644
--- a/README.md
+++ b/README.md
@@ -47,8 +47,10 @@ Google Playからインストールしてください。
###### 権限の説明
- インターネット接続
- 指定したアドレスに通知データを送信するために必要です。
+- ネットワーク状態の取得
+ - Wi-Fiに接続しているか確認するために必要です。
- インストール済みアプリの取得
- - 通知対象のアプリを選択するための必要です。
+ - 通知対象のアプリを選択するために必要です。
- 通知へのアクセス
- PCに通知する内容を知るために、通知へアクセスする必要があります。