Skip to content

Commit 51bdb80

Browse files
authored
Merge pull request #305 from ptkNktq/feature/only_wifi
Wi-Fi接続時のみ転送設定の追加
2 parents d5de644 + 309222b commit 51bdb80

13 files changed

Lines changed: 118 additions & 23 deletions

File tree

.github/workflows/android-build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,4 @@ jobs:
3232
with:
3333
webhook: ${{ secrets.DISCORD_WEBHOOK }}
3434
status: ${{ job.status }}
35+
content: "<@${{ secrets.DISCORD_NOTIFY_USER_ID }}> チェック終わったみたい ${{ secrets.DISCORD_NOTIFY_SUFFIX }}"

AndroidApp/app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<uses-permission
77
android:name="android.permission.QUERY_ALL_PACKAGES"
88
tools:ignore="QueryAllPackagesPermission" />
9+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
910

1011
<application
1112
android:name=".App"

AndroidApp/app/src/main/kotlin/me/nya_n/notificationnotifier/App.kt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package me.nya_n.notificationnotifier
22

33
import android.app.Application
4+
import android.net.ConnectivityManager
45
import me.nya_n.notificationnotifier.data.repository.AppRepository
56
import me.nya_n.notificationnotifier.data.repository.BackupRepository
67
import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
@@ -23,6 +24,7 @@ import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
2324
import me.nya_n.notificationnotifier.domain.usecase.PackageVisibilityGrantedUseCase
2425
import me.nya_n.notificationnotifier.domain.usecase.SaveAddressUseCase
2526
import me.nya_n.notificationnotifier.domain.usecase.SaveFilterConditionUseCase
27+
import me.nya_n.notificationnotifier.domain.usecase.SaveWifiOnlyNotificationSettingUseCase
2628
import me.nya_n.notificationnotifier.domain.usecase.ToggleIgnoreSummaryUseCase
2729
import me.nya_n.notificationnotifier.domain.usecase.impl.AddTargetAppUseCaseImpl
2830
import me.nya_n.notificationnotifier.domain.usecase.impl.CheckPackageVisibilityUseCaseImpl
@@ -37,6 +39,7 @@ import me.nya_n.notificationnotifier.domain.usecase.impl.NotifyUseCaseImpl
3739
import me.nya_n.notificationnotifier.domain.usecase.impl.PackageVisibilityGrantedUseCaseImpl
3840
import me.nya_n.notificationnotifier.domain.usecase.impl.SaveAddressUseCaseImpl
3941
import me.nya_n.notificationnotifier.domain.usecase.impl.SaveFilterConditionUseCaseImpl
42+
import me.nya_n.notificationnotifier.domain.usecase.impl.SaveWifiOnlyNotificationSettingUseCaseImpl
4043
import me.nya_n.notificationnotifier.domain.usecase.impl.ToggleIgnoreSummaryUseCaseImpl
4144
import me.nya_n.notificationnotifier.model.AppConfig
4245
import me.nya_n.notificationnotifier.ui.screen.app.AppViewModel
@@ -60,6 +63,8 @@ class App : Application() {
6063
}
6164

6265
private val modules = module {
66+
single { applicationContext.getSystemService(ConnectivityManager::class.java) }
67+
6368
// BuildConfigのデータ共有用
6469
single {
6570
AppConfig(
@@ -91,7 +96,7 @@ class App : Application() {
9196
viewModel { SelectionViewModel(get(), get()) }
9297
viewModel { params -> DetailViewModel(get(), get(), get(), get(), params.get()) }
9398
viewModel { TargetViewModel(get()) }
94-
viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get()) }
99+
viewModel { SettingsViewModel(get(), get(), get(), get(), get(), get(), get()) }
95100

96101
// UseCase
97102
factory<AddTargetAppUseCase> { AddTargetAppUseCaseImpl(get()) }
@@ -102,13 +107,18 @@ class App : Application() {
102107
factory<LoadAppUseCase> { LoadAppUseCaseImpl(get(), get()) }
103108
factory<LoadFilterConditionUseCase> { LoadFilterConditionUseCaseImpl(get()) }
104109
factory<NotifyTargetAppNotificationUseCase> {
105-
NotifyTargetAppNotificationUseCaseImpl(get(), get())
110+
NotifyTargetAppNotificationUseCaseImpl(get(), get(), get(), get())
106111
}
107112
factory<NotifyUseCase> { NotifyUseCaseImpl(get()) }
108113
factory<PackageVisibilityGrantedUseCase> { PackageVisibilityGrantedUseCaseImpl(get()) }
109114
factory<CheckPackageVisibilityUseCase> { CheckPackageVisibilityUseCaseImpl(get()) }
110115
factory<SaveAddressUseCase> { SaveAddressUseCaseImpl(get()) }
111116
factory<SaveFilterConditionUseCase> { SaveFilterConditionUseCaseImpl(get()) }
112117
factory<ToggleIgnoreSummaryUseCase> { ToggleIgnoreSummaryUseCaseImpl(get()) }
118+
factory<SaveWifiOnlyNotificationSettingUseCase> {
119+
SaveWifiOnlyNotificationSettingUseCaseImpl(
120+
get()
121+
)
122+
}
113123
}
114124
}

AndroidApp/data/repository/src/main/kotlin/me/nya_n/notificationnotifier/data/repository/source/UserSettingsDataStore.kt

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,31 @@ import me.nya_n.notificationnotifier.model.UserSettings
66
class UserSettingsDataStore(
77
pref: SharedPreferences
88
) : KeyValueDataStore(pref) {
9+
companion object {
10+
const val DATA_STORE_NAME = "settings"
11+
const val KEY_HOST = "host"
12+
const val DEFAULT_HOST = ""
13+
const val KEY_PORT = "port"
14+
const val DEFAULT_PORT = -1
15+
const val KEY_IS_PACKAGE_VISIBILITY_GRANTED = "isPackageVisibilityGranted"
16+
const val DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED = false
17+
const val KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED = "isWifiOnlyNotificationEnabled"
18+
const val DEFAULT_IS_WIFI_ONLY_NOTIFICATION_ENABLED = false
19+
}
920

1021
fun get(): UserSettings {
1122
return UserSettings(
1223
get(KEY_HOST, DEFAULT_HOST),
1324
get(KEY_PORT, DEFAULT_PORT),
14-
get(KEY_IS_PACKAGE_VISIBILITY_GRANTED, DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED)
25+
get(KEY_IS_PACKAGE_VISIBILITY_GRANTED, DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED),
26+
get(KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED, DEFAULT_IS_WIFI_ONLY_NOTIFICATION_ENABLED)
1527
)
1628
}
1729

1830
fun save(settings: UserSettings) {
1931
put(KEY_HOST, settings.host)
2032
put(KEY_PORT, settings.port)
2133
put(KEY_IS_PACKAGE_VISIBILITY_GRANTED, settings.isPackageVisibilityGranted)
22-
}
23-
24-
companion object {
25-
const val DATA_STORE_NAME = "settings"
26-
const val KEY_HOST = "host"
27-
const val DEFAULT_HOST = ""
28-
const val KEY_PORT = "port"
29-
const val DEFAULT_PORT = -1
30-
const val KEY_IS_PACKAGE_VISIBILITY_GRANTED = "isPackageVisibilityGranted"
31-
const val DEFAULT_IS_PACKAGE_VISIBILITY_GRANTED = false
34+
put(KEY_IS_WIFI_ONLY_NOTIFICATION_ENABLED, settings.isWifiOnlyNotificationEnabled)
3235
}
3336
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package me.nya_n.notificationnotifier.domain.usecase
2+
3+
interface SaveWifiOnlyNotificationSettingUseCase {
4+
operator fun invoke(isWifiOnlyNotificationEnabled: Boolean): Result<Unit>
5+
}

AndroidApp/domain/src/main/kotlin/me/nya_n/notificationnotifier/domain/usecase/impl/NotifyTargetAppNotificationUseCaseImpl.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,41 @@
11
package me.nya_n.notificationnotifier.domain.usecase.impl
22

3+
import android.Manifest
34
import android.app.Notification
5+
import android.net.ConnectivityManager
6+
import android.net.NetworkCapabilities
7+
import androidx.annotation.RequiresPermission
48
import me.nya_n.notificationnotifier.data.repository.AppRepository
9+
import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
510
import me.nya_n.notificationnotifier.domain.usecase.NotifyTargetAppNotificationUseCase
611
import me.nya_n.notificationnotifier.domain.usecase.NotifyUseCase
712

813
class NotifyTargetAppNotificationUseCaseImpl(
14+
private val connectionManager: ConnectivityManager,
915
private val appRepository: AppRepository,
16+
private val userSettingsRepository: UserSettingsRepository,
1017
private val notifyUseCase: NotifyUseCase,
1118
) : NotifyTargetAppNotificationUseCase {
19+
@get:RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
20+
private val isConnectedToWifi: Boolean
21+
get() {
22+
val network = connectionManager.activeNetwork ?: return false
23+
val capabilities = connectionManager.getNetworkCapabilities(network) ?: return false
24+
return capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
25+
}
26+
1227
override suspend operator fun invoke(
1328
packageName: String,
1429
title: String,
1530
message: String,
1631
flags: Int
1732
): Result<Unit> {
1833
return runCatching {
34+
val settings = userSettingsRepository.getUserSettings()
35+
if (settings.isWifiOnlyNotificationEnabled && !isConnectedToWifi) {
36+
return Result.success(Unit)
37+
}
38+
1939
val targets = appRepository.getTargetAppList()
2040
if (!targets.any { t -> t.packageName == packageName }) {
2141
return Result.success(Unit)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package me.nya_n.notificationnotifier.domain.usecase.impl
2+
3+
import me.nya_n.notificationnotifier.data.repository.UserSettingsRepository
4+
import me.nya_n.notificationnotifier.domain.usecase.SaveWifiOnlyNotificationSettingUseCase
5+
6+
class SaveWifiOnlyNotificationSettingUseCaseImpl(
7+
private val userSettingsRepository: UserSettingsRepository
8+
) : SaveWifiOnlyNotificationSettingUseCase {
9+
override fun invoke(isWifiOnlyNotificationEnabled: Boolean): Result<Unit> {
10+
return runCatching {
11+
val settings = userSettingsRepository.getUserSettings()
12+
userSettingsRepository.saveUserSettings(
13+
settings.copy(
14+
isWifiOnlyNotificationEnabled = isWifiOnlyNotificationEnabled
15+
)
16+
)
17+
return Result.success(Unit)
18+
}
19+
}
20+
}

AndroidApp/domain/src/test/java/me/nya_n/notificationnotifier/UseCaseTest.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class UseCaseTest {
4949

5050
@Test
5151
fun `インストール済みアプリの取得_許可あり`() {
52-
every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, true)
52+
every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, true, false)
5353
every { appRepository.loadInstalledAppList() } returns listOf(InstalledApp("", ""))
5454

5555
val ret = loadAppUseCase.loadInstalledAppList()
@@ -61,7 +61,7 @@ class UseCaseTest {
6161

6262
@Test
6363
fun `インストール済みアプリの取得_許可なし`() {
64-
every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, false)
64+
every { userSettingsRepository.getUserSettings() } returns UserSettings("", 0, false, false)
6565
every { appRepository.loadInstalledAppList() } throws PermissionDeniedException()
6666

6767
val ret = loadAppUseCase.loadInstalledAppList()
@@ -76,7 +76,8 @@ class UseCaseTest {
7676
every { userSettingsRepository.getUserSettings() } returns UserSettings(
7777
"192.168.10.18",
7878
8484,
79-
true
79+
true,
80+
false
8081
)
8182
every { userSettingsRepository.saveUserSettings(any()) } just Runs
8283

@@ -115,7 +116,8 @@ class UseCaseTest {
115116
every { userSettingsRepository.getUserSettings() } returns UserSettings(
116117
"192.168.10.18",
117118
8484,
118-
true
119+
true,
120+
false
119121
)
120122

121123
runTest(testDispatcher) {

AndroidApp/model/src/main/kotlin/me/nya_n/notificationnotifier/model/UserSettings.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ data class UserSettings(
66
val host: String,
77
val port: Int,
88
/**
9-
* @see <a href="https://support.google.com/googleplay/android-developer/answer/10158779?hl=ja">https://support.google.com/googleplay/android-developer/answer/10158779</a>
9+
* @see <a href="https://support.google.com/googleplay/android-developer/answer/10158779?hl=ja">パッケージ(アプリ)の広範な一覧取得(QUERY_ALL_PACKAGES)権限の使用</a>
1010
*/
1111
@SerializedName("is_package_visibility_granted")
12-
val isPackageVisibilityGranted: Boolean
12+
val isPackageVisibilityGranted: Boolean,
13+
@SerializedName("is_wifi_only_notification_enabled")
14+
val isWifiOnlyNotificationEnabled: Boolean
1315
)

AndroidApp/ui/src/main/kotlin/me/nya_n/notificationnotifier/ui/screen/settings/SettingsScreen.kt

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.appcompat.app.AppCompatActivity
77
import androidx.compose.foundation.Image
88
import androidx.compose.foundation.layout.Box
99
import androidx.compose.foundation.layout.Column
10+
import androidx.compose.foundation.layout.Row
1011
import androidx.compose.foundation.layout.Spacer
1112
import androidx.compose.foundation.layout.fillMaxSize
1213
import androidx.compose.foundation.layout.fillMaxWidth
@@ -23,6 +24,7 @@ import androidx.compose.material.icons.outlined.CloudDownload
2324
import androidx.compose.material.icons.outlined.CloudUpload
2425
import androidx.compose.material.icons.outlined.Code
2526
import androidx.compose.material.icons.outlined.Devices
27+
import androidx.compose.material3.Checkbox
2628
import androidx.compose.material3.MaterialTheme
2729
import androidx.compose.material3.OutlinedTextField
2830
import androidx.compose.material3.SnackbarHostState
@@ -115,6 +117,8 @@ fun SettingsScreen(
115117
versionName = uiState.appConfig.versionString,
116118
onValueChange = { viewModel.updateAddress(it) },
117119
onNotifyTest = { viewModel.notifyTest() },
120+
isWifiOnlyNotificationEnabled = uiState.isWifiOnlyNotificationEnabled,
121+
onWifiOnlySettingChanged = { viewModel.updateWifiOnlySetting(it) },
118122
onExportData = { viewModel.event(UiEvent.ExportData()) },
119123
onImportData = { viewModel.event(UiEvent.ImportData()) },
120124
onLicense = { navController.navigate(Screen.License.route) },
@@ -130,6 +134,8 @@ fun SettingsContent(
130134
versionName: String,
131135
onValueChange: (String) -> Unit,
132136
onNotifyTest: () -> Unit,
137+
isWifiOnlyNotificationEnabled: Boolean,
138+
onWifiOnlySettingChanged: (Boolean) -> Unit,
133139
onExportData: () -> Unit,
134140
onImportData: () -> Unit,
135141
onLicense: () -> Unit,
@@ -147,7 +153,9 @@ fun SettingsContent(
147153
NotifySettings(
148154
address = address,
149155
onValueChange = onValueChange,
150-
onNotifyTest = onNotifyTest
156+
onNotifyTest = onNotifyTest,
157+
isWifiOnlyNotificationEnabled = isWifiOnlyNotificationEnabled,
158+
onWifiOnlySettingChanged = onWifiOnlySettingChanged
151159
)
152160
OtherSettings(
153161
onExportData = onExportData,
@@ -176,7 +184,9 @@ fun SettingsContent(
176184
private fun NotifySettings(
177185
address: String,
178186
onValueChange: (String) -> Unit,
179-
onNotifyTest: () -> Unit
187+
onNotifyTest: () -> Unit,
188+
isWifiOnlyNotificationEnabled: Boolean,
189+
onWifiOnlySettingChanged: (Boolean) -> Unit
180190
) {
181191
val keyboardController = LocalSoftwareKeyboardController.current
182192
val focusManager = LocalFocusManager.current
@@ -216,6 +226,15 @@ private fun NotifySettings(
216226
text = stringResource(id = R.string.notify_test),
217227
onClick = onNotifyTest
218228
)
229+
Row(
230+
verticalAlignment = Alignment.CenterVertically
231+
) {
232+
Checkbox(
233+
checked = isWifiOnlyNotificationEnabled,
234+
onCheckedChange = onWifiOnlySettingChanged
235+
)
236+
Text("Wi-Fi接続時のみ転送する。")
237+
}
219238
}
220239

221240
/** その他の項目
@@ -293,6 +312,8 @@ private fun SettingsPreview() {
293312
versionName = "1.0",
294313
onValueChange = { },
295314
onNotifyTest = { },
315+
isWifiOnlyNotificationEnabled = true,
316+
onWifiOnlySettingChanged = { },
296317
onExportData = { },
297318
onImportData = { },
298319
onLicense = { },

0 commit comments

Comments
 (0)