From 3c5aff31aa2f6d8b0e6304c9bf8909a12182b3ed Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Fri, 15 Sep 2023 07:24:19 -0400 Subject: [PATCH] refactor: objectbox to room Migrated app from using ObjectBox library for db to Room as ObjectBox is not FLOSS compliant. Migrated app to using version catalog for managing dependancies. Added floss build flavor for F-Droid and general build flavor for all other builds. Floss build excludes google analytics and crashlytics. Other performance improvements and refactors. --- app/build.gradle.kts | 138 ++++++++++-------- app/objectbox-models/default.json | 99 ------------- app/objectbox-models/default.json.bak | 94 ------------ app/src/main/AndroidManifest.xml | 3 - .../wireguardautotunnel/Constants.kt | 9 +- .../WireGuardAutoTunnel.kt | 15 -- .../wireguardautotunnel/module/BoxModule.kt | 40 ----- .../module/DatabaseModule.kt | 25 ++++ .../module/RepositoryModule.kt | 24 +-- .../receiver/BootReceiver.kt | 5 +- .../receiver/NotificationActionReceiver.kt | 10 +- .../repository/AppDatabase.kt | 14 ++ .../repository/DatabaseListConverters.kt | 15 ++ .../repository/Repository.kt | 16 -- .../repository/SettingsBox.kt | 63 -------- .../repository/SettingsDoa.kt | 34 +++++ .../repository/TunnelBox.kt | 57 -------- .../repository/TunnelConfigDao.kt | 34 +++++ .../repository/model/Settings.kt | 15 ++ .../model/TunnelConfig.kt | 24 ++- .../service/foreground/ServiceManager.kt | 5 +- .../WireGuardConnectivityWatcherService.kt | 8 +- .../foreground/WireGuardTunnelService.kt | 9 +- .../service/shortcut/ShortcutsActivity.kt | 7 +- .../service/shortcut/ShortcutsManager.kt | 2 +- .../service/tile/TunnelControlTile.kt | 10 +- .../service/tunnel/VpnService.kt | 2 +- .../service/tunnel/WireGuardTunnel.kt | 2 +- .../service/tunnel/model/Settings.kt | 15 -- .../wireguardautotunnel/ui/MainActivity.kt | 27 ++-- .../ui/screens/config/ConfigViewModel.kt | 27 ++-- .../ui/screens/detail/DetailViewModel.kt | 6 +- .../ui/screens/main/MainScreen.kt | 6 +- .../ui/screens/main/MainViewModel.kt | 76 +++++----- .../ui/screens/settings/SettingsScreen.kt | 2 +- .../ui/screens/settings/SettingsViewModel.kt | 20 ++- .../wireguardautotunnel/util/NumberUtils.kt | 4 + app/src/main/res/values/strings.xml | 1 + build.gradle.kts | 24 ++- buildSrc/build.gradle.kts | 8 + buildSrc/src/main/kotlin/BuildHelper.kt | 29 ++++ gradle.properties | 2 - gradle/libs.versions.toml | 89 +++++++++++ 43 files changed, 504 insertions(+), 611 deletions(-) delete mode 100644 app/objectbox-models/default.json delete mode 100644 app/objectbox-models/default.json.bak delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BoxModule.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/module/DatabaseModule.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/Repository.kt delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsBox.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsDoa.kt delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelBox.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelConfigDao.kt create mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt rename app/src/main/java/com/zaneschepke/wireguardautotunnel/{service/tunnel => repository}/model/TunnelConfig.kt (88%) delete mode 100644 app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/Settings.kt create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/kotlin/BuildHelper.kt create mode 100644 gradle/libs.versions.toml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9f3b9c6..773d63f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,14 +1,9 @@ -val rExtra = rootProject.extra - plugins { - id("com.android.application") - id("org.jetbrains.kotlin.android") - kotlin("kapt") - id("com.google.dagger.hilt.android") - id("com.google.gms.google-services") - id("com.google.firebase.crashlytics") + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.hilt.android) id("org.jetbrains.kotlin.plugin.serialization") - id("io.objectbox") + alias(libs.plugins.ksp) } android { @@ -16,8 +11,8 @@ android { compileSdk = 34 val versionMajor = 2 - val versionMinor = 4 - val versionPatch = 5 + val versionMinor = 5 + val versionPatch = 0 val versionBuild = 0 defaultConfig { @@ -27,6 +22,10 @@ android { versionCode = versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild versionName = "${versionMajor}.${versionMinor}.${versionPatch}" + multiDexEnabled = true + + resourceConfigurations.addAll(listOf("en")) + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" vectorDrawables { useSupportLibrary = true @@ -36,13 +35,35 @@ android { buildTypes { release { isDebuggable = false - isMinifyEnabled = false + isMinifyEnabled = true + isShrinkResources = true proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) + //for release testing + signingConfig = signingConfigs.getByName("debug") + } + debug { + isDebuggable = true } } + flavorDimensions.add("type") + productFlavors { + create("floss") { + dimension = "type" + applicationIdSuffix = ".floss" + } + create("general") { + dimension = "type" + if (BuildHelper.isReleaseBuild(gradle) && BuildHelper.isGeneralFlavor(gradle)) + { + apply(plugin = "com.google.gms.google-services") + apply(plugin = "com.google.firebase.crashlytics") + } + } + } + compileOptions { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 @@ -52,9 +73,11 @@ android { } buildFeatures { compose = true + buildConfig = true + } composeOptions { - kotlinCompilerExtensionVersion = "1.4.8" + kotlinCompilerExtensionVersion = libs.versions.composeCompiler.get() } packaging { resources { @@ -63,68 +86,69 @@ android { } } +val generalImplementation by configurations dependencies { - implementation("androidx.core:core-ktx:1.12.0") - implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.2") - implementation("androidx.activity:activity-compose:1.7.2") - implementation(platform("androidx.compose:compose-bom:2023.03.00")) - implementation("androidx.compose.ui:ui") - implementation("androidx.compose.ui:ui-graphics") - implementation("androidx.compose.ui:ui-tooling-preview") - implementation("androidx.compose.material3:material3:1.1.1") - implementation("androidx.appcompat:appcompat:1.6.1") + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.compose.ui) + implementation(libs.androidx.compose.ui.graphics) + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.material3) + implementation(libs.androidx.appcompat) - testImplementation("junit:junit:4.13.2") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") - androidTestImplementation(platform("androidx.compose:compose-bom:2023.03.00")) - androidTestImplementation("androidx.compose.ui:ui-test-junit4") - debugImplementation("androidx.compose.ui:ui-tooling") - debugImplementation("androidx.compose.ui:ui-test-manifest") + //test + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.compose.ui.test) + debugImplementation(libs.androidx.compose.ui.tooling) + debugImplementation(libs.androidx.compose.manifest) - //wireguard tunnel - implementation("com.wireguard.android:tunnel:1.0.20230706") + //wg + implementation(libs.tunnel) //logging - implementation("com.jakewharton.timber:timber:5.0.1") + implementation(libs.timber) // compose navigation - implementation("androidx.navigation:navigation-compose:2.7.2") - implementation("androidx.hilt:hilt-navigation-compose:1.0.0") + implementation(libs.androidx.navigation.compose) + implementation(libs.androidx.hilt.navigation.compose) // hilt - implementation("com.google.dagger:hilt-android:${rExtra.get("hiltVersion")}") - kapt("com.google.dagger:hilt-android-compiler:${rExtra.get("hiltVersion")}") + implementation(libs.hilt.android) + ksp(libs.hilt.android.compiler) //accompanist - implementation("com.google.accompanist:accompanist-systemuicontroller:${rExtra.get("accompanistVersion")}") - implementation("com.google.accompanist:accompanist-permissions:${rExtra.get("accompanistVersion")}") - implementation("com.google.accompanist:accompanist-flowlayout:${rExtra.get("accompanistVersion")}") - implementation("com.google.accompanist:accompanist-navigation-animation:${rExtra.get("accompanistVersion")}") - implementation("com.google.accompanist:accompanist-drawablepainter:${rExtra.get("accompanistVersion")}") + implementation(libs.accompanist.systemuicontroller) + implementation(libs.accompanist.permissions) + implementation(libs.accompanist.flowlayout) + implementation(libs.accompanist.navigation.animation) + implementation(libs.accompanist.drawablepainter) + + //room + implementation(libs.androidx.room.runtime) + annotationProcessor(libs.androidx.room.compiler) + ksp(libs.androidx.room.compiler) + implementation(libs.androidx.room.ktx) + - //db - implementation("io.objectbox:objectbox-kotlin:${rExtra.get("objectBoxVersion")}") //lifecycle - implementation("androidx.lifecycle:lifecycle-runtime-compose:2.6.2") + implementation(libs.lifecycle.runtime.compose) //icons - implementation("androidx.compose.material:material-icons-extended:1.5.1") - - - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") - + implementation(libs.material.icons.extended) + //serialization + implementation(libs.kotlinx.serialization.json) //firebase crashlytics - implementation(platform("com.google.firebase:firebase-bom:32.0.0")) - implementation("com.google.firebase:firebase-crashlytics-ktx") - implementation("com.google.firebase:firebase-analytics-ktx") + generalImplementation(platform(libs.firebase.bom)) + generalImplementation(libs.google.firebase.crashlytics.ktx) + generalImplementation(libs.google.firebase.analytics.ktx) //barcode scanning - implementation("com.google.android.gms:play-services-code-scanner:16.1.0") -} - -kapt { - correctErrorTypes = true + implementation(libs.play.services.code.scanner) } \ No newline at end of file diff --git a/app/objectbox-models/default.json b/app/objectbox-models/default.json deleted file mode 100644 index dd7a8ab..0000000 --- a/app/objectbox-models/default.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", - "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", - "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", - "entities": [ - { - "id": "1:2692736974585027589", - "lastPropertyId": "15:5057486545428188436", - "name": "TunnelConfig", - "properties": [ - { - "id": "1:1985347930017457084", - "name": "id", - "type": 6, - "flags": 1 - }, - { - "id": "12:2409068226744965585", - "name": "name", - "indexId": "1:4811206443952699137", - "type": 9, - "flags": 34848 - }, - { - "id": "13:8987443291286312275", - "name": "wgQuick", - "type": 9 - } - ], - "relations": [] - }, - { - "id": "2:8887605597748372702", - "lastPropertyId": "9:4468844863383145378", - "name": "Settings", - "properties": [ - { - "id": "1:7485739868216068651", - "name": "id", - "type": 6, - "flags": 1 - }, - { - "id": "2:5814013113141456749", - "name": "isAutoTunnelEnabled", - "type": 1 - }, - { - "id": "4:5645665441196906014", - "name": "trustedNetworkSSIDs", - "type": 30 - }, - { - "id": "5:4989886999117763881", - "name": "isTunnelOnMobileDataEnabled", - "type": 1 - }, - { - "id": "6:3370284381040192129", - "name": "defaultTunnel", - "type": 9 - }, - { - "id": "9:4468844863383145378", - "name": "isAlwaysOnVpnEnabled", - "type": 1 - } - ], - "relations": [] - } - ], - "lastEntityId": "2:8887605597748372702", - "lastIndexId": "1:4811206443952699137", - "lastRelationId": "0:0", - "lastSequenceId": "0:0", - "modelVersion": 5, - "modelVersionParserMinimum": 5, - "retiredEntityUids": [], - "retiredIndexUids": [], - "retiredPropertyUids": [ - 1763475292291320186, - 6483820955437198310, - 8323071516033820771, - 5904440563612311217, - 1408037976996390989, - 7737847485212546994, - 8215616901775229364, - 8021610768066328637, - 6174306582797008721, - 2175939938544485767, - 7555225587864607050, - 969146862000617878, - 5057486545428188436, - 2814640993034665120, - 4981008812459251156 - ], - "retiredRelationUids": [], - "version": 1 -} \ No newline at end of file diff --git a/app/objectbox-models/default.json.bak b/app/objectbox-models/default.json.bak deleted file mode 100644 index d408486..0000000 --- a/app/objectbox-models/default.json.bak +++ /dev/null @@ -1,94 +0,0 @@ -{ - "_note1": "KEEP THIS FILE! Check it into a version control system (VCS) like git.", - "_note2": "ObjectBox manages crucial IDs for your object model. See docs for details.", - "_note3": "If you have VCS merge conflicts, you must resolve them according to ObjectBox docs.", - "entities": [ - { - "id": "1:2692736974585027589", - "lastPropertyId": "15:5057486545428188436", - "name": "TunnelConfig", - "properties": [ - { - "id": "1:1985347930017457084", - "name": "id", - "type": 6, - "flags": 1 - }, - { - "id": "12:2409068226744965585", - "name": "name", - "indexId": "1:4811206443952699137", - "type": 9, - "flags": 34848 - }, - { - "id": "13:8987443291286312275", - "name": "wgQuick", - "type": 9 - } - ], - "relations": [] - }, - { - "id": "2:8887605597748372702", - "lastPropertyId": "8:4981008812459251156", - "name": "Settings", - "properties": [ - { - "id": "1:7485739868216068651", - "name": "id", - "type": 6, - "flags": 1 - }, - { - "id": "2:5814013113141456749", - "name": "isAutoTunnelEnabled", - "type": 1 - }, - { - "id": "4:5645665441196906014", - "name": "trustedNetworkSSIDs", - "type": 30 - }, - { - "id": "5:4989886999117763881", - "name": "isTunnelOnMobileDataEnabled", - "type": 1 - }, - { - "id": "6:3370284381040192129", - "name": "defaultTunnel", - "type": 9 - } - ], - "relations": [] - } - ], - "lastEntityId": "2:8887605597748372702", - "lastIndexId": "1:4811206443952699137", - "lastRelationId": "0:0", - "lastSequenceId": "0:0", - "modelVersion": 5, - "modelVersionParserMinimum": 5, - "retiredEntityUids": [], - "retiredIndexUids": [], - "retiredPropertyUids": [ - 1763475292291320186, - 6483820955437198310, - 8323071516033820771, - 5904440563612311217, - 1408037976996390989, - 7737847485212546994, - 8215616901775229364, - 8021610768066328637, - 6174306582797008721, - 2175939938544485767, - 7555225587864607050, - 969146862000617878, - 5057486545428188436, - 2814640993034665120, - 4981008812459251156 - ], - "retiredRelationUids": [], - "version": 1 -} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f674159..d762f13 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -114,8 +114,5 @@ - \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt index 7bffe0b..2cf4afe 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/Constants.kt @@ -1,6 +1,11 @@ package com.zaneschepke.wireguardautotunnel object Constants { - const val VPN_CONNECTIVITY_CHECK_INTERVAL = 3000L; - const val VPN_STATISTIC_CHECK_INTERVAL = 10000L; + const val VPN_CONNECTIVITY_CHECK_INTERVAL = 3000L + const val VPN_STATISTIC_CHECK_INTERVAL = 10000L + const val SNACKBAR_DELAY = 3000L + const val TOGGLE_TUNNEL_DELAY = 1000L + const val FADE_IN_ANIMATION_DURATION = 1000 + const val SLIDE_IN_ANIMATION_DURATION = 500 + const val SLIDE_IN_TRANSITION_OFFSET = 1000 } \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/WireGuardAutoTunnel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/WireGuardAutoTunnel.kt index 39204da..2a0368e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/WireGuardAutoTunnel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/WireGuardAutoTunnel.kt @@ -3,32 +3,17 @@ package com.zaneschepke.wireguardautotunnel import android.app.Application import android.content.Context import android.content.pm.PackageManager -import com.google.firebase.crashlytics.FirebaseCrashlytics -import com.google.mlkit.common.MlKit -import com.zaneschepke.wireguardautotunnel.repository.Repository -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings import dagger.hilt.android.HiltAndroidApp import timber.log.Timber -import javax.inject.Inject @HiltAndroidApp class WireGuardAutoTunnel : Application() { - @Inject - lateinit var settingsRepo : Repository - override fun onCreate() { super.onCreate() if(BuildConfig.DEBUG) { - FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false); Timber.plant(Timber.DebugTree()) } - try { - MlKit.initialize(this) - } catch (e : Exception) { - Timber.e(e.message) - } - settingsRepo.init() } companion object { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BoxModule.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BoxModule.kt deleted file mode 100644 index 45a74f0..0000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BoxModule.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.module - -import android.content.Context -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.MyObjectBox -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import io.objectbox.Box -import io.objectbox.BoxStore -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -class BoxModule { - - @Provides - @Singleton - fun provideBoxStore(@ApplicationContext context : Context) : BoxStore { - return MyObjectBox.builder() - .androidContext(context.applicationContext) - .build() - } - - @Provides - @Singleton - fun provideBoxForSettings(store : BoxStore) : Box { - return store.boxFor(Settings::class.java) - } - - @Provides - @Singleton - fun provideBoxForTunnels(store : BoxStore) : Box { - return store.boxFor(TunnelConfig::class.java) - } - -} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/DatabaseModule.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/DatabaseModule.kt new file mode 100644 index 0000000..32aa46c --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/DatabaseModule.kt @@ -0,0 +1,25 @@ +package com.zaneschepke.wireguardautotunnel.module + +import android.content.Context +import androidx.room.Room +import com.zaneschepke.wireguardautotunnel.R +import com.zaneschepke.wireguardautotunnel.repository.AppDatabase +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +class DatabaseModule { + @Provides + @Singleton + fun provideDatabase(@ApplicationContext context : Context) : AppDatabase { + return Room.databaseBuilder( + context, + AppDatabase::class.java, context.getString(R.string.db_name) + ).build() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/RepositoryModule.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/RepositoryModule.kt index 4626425..ca056b8 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/RepositoryModule.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/RepositoryModule.kt @@ -1,25 +1,27 @@ package com.zaneschepke.wireguardautotunnel.module -import com.zaneschepke.wireguardautotunnel.repository.Repository -import com.zaneschepke.wireguardautotunnel.repository.SettingsBox -import com.zaneschepke.wireguardautotunnel.repository.TunnelBox -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig -import dagger.Binds +import com.zaneschepke.wireguardautotunnel.repository.AppDatabase +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao import dagger.Module +import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -abstract class RepositoryModule { +class RepositoryModule { - @Binds @Singleton - abstract fun provideSettingsRepository(settingsBox: SettingsBox) : Repository + @Provides + fun provideSettingsRepository(appDatabase: AppDatabase) : SettingsDoa { + return appDatabase.settingDao() + } - @Binds @Singleton - abstract fun provideTunnelRepository(tunnelBox: TunnelBox) : Repository + @Provides + fun provideTunnelConfigRepository(appDatabase: AppDatabase) : TunnelConfigDao { + return appDatabase.tunnelConfigDoa() + } } \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt index 03b8e9f..ae743f0 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/BootReceiver.kt @@ -3,9 +3,8 @@ package com.zaneschepke.wireguardautotunnel.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -17,7 +16,7 @@ import javax.inject.Inject class BootReceiver : BroadcastReceiver() { @Inject - lateinit var settingsRepo : Repository + lateinit var settingsRepo : SettingsDoa override fun onReceive(context: Context, intent: Intent) { if (intent.action == Intent.ACTION_BOOT_COMPLETED) { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt index 93a10ae..ebe4120 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/receiver/NotificationActionReceiver.kt @@ -3,9 +3,9 @@ package com.zaneschepke.wireguardautotunnel.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.Constants +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -18,16 +18,16 @@ import javax.inject.Inject class NotificationActionReceiver : BroadcastReceiver() { @Inject - lateinit var settingsRepo : Repository + lateinit var settingsRepo : SettingsDoa override fun onReceive(context: Context, intent: Intent?) { CoroutineScope(Dispatchers.IO).launch { try { val settings = settingsRepo.getAll() - if (!settings.isNullOrEmpty()) { + if (settings.isNotEmpty()) { val setting = settings.first() if (setting.defaultTunnel != null) { ServiceManager.stopVpnService(context) - delay(1000) + delay(Constants.TOGGLE_TUNNEL_DELAY) ServiceManager.startVpnService(context, setting.defaultTunnel.toString()) } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt new file mode 100644 index 0000000..9e3d162 --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/AppDatabase.kt @@ -0,0 +1,14 @@ +package com.zaneschepke.wireguardautotunnel.repository + +import androidx.room.Database +import androidx.room.RoomDatabase +import androidx.room.TypeConverters +import com.zaneschepke.wireguardautotunnel.repository.model.Settings +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig + +@Database(entities = [Settings::class, TunnelConfig::class], version = 1) +@TypeConverters(DatabaseListConverters::class) +abstract class AppDatabase : RoomDatabase() { + abstract fun settingDao(): SettingsDoa + abstract fun tunnelConfigDoa() : TunnelConfigDao +} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt new file mode 100644 index 0000000..e4e94c8 --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/DatabaseListConverters.kt @@ -0,0 +1,15 @@ +package com.zaneschepke.wireguardautotunnel.repository + +import androidx.room.TypeConverter + +class DatabaseListConverters { + @TypeConverter + fun listToString(value: MutableList): String { + return value.joinToString() + } + @TypeConverter + fun stringToList(value: String): MutableList { + if(value.isEmpty()) return mutableListOf() + return value.split(",").toMutableList() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/Repository.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/Repository.kt deleted file mode 100644 index 4f1b59f..0000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/Repository.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.repository - -import kotlinx.coroutines.flow.Flow - -interface Repository { - suspend fun save(t : T) - suspend fun saveAll(t : List) - suspend fun getById(id : Long) : T? - suspend fun getAll() : List? - suspend fun delete(t : T) : Boolean? - suspend fun count() : Long? - - val itemFlow : Flow> - - fun init() -} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsBox.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsBox.kt deleted file mode 100644 index 0ba02d3..0000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsBox.kt +++ /dev/null @@ -1,63 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.repository - -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import io.objectbox.Box -import io.objectbox.BoxStore -import io.objectbox.kotlin.awaitCallInTx -import io.objectbox.kotlin.toFlow -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.launch -import javax.inject.Inject - - -class SettingsBox @Inject constructor(private val box : Box, private val boxStore : BoxStore) : Repository { - - @OptIn(ExperimentalCoroutinesApi::class) - override val itemFlow = box.query().build().subscribe().toFlow() - - override fun init() { - CoroutineScope(Dispatchers.IO).launch { - if(getAll().isNullOrEmpty()) { - save(Settings()) - } - } - } - - override suspend fun save(t : Settings) { - boxStore.awaitCallInTx { - box.put(t) - } - } - - override suspend fun saveAll(t : List) { - boxStore.awaitCallInTx { - box.put(t) - } - } - - override suspend fun getById(id: Long): Settings? { - return boxStore.awaitCallInTx { - box[id] - } - } - - override suspend fun getAll(): List? { - return boxStore.awaitCallInTx { - box.all - } - } - - override suspend fun delete(t : Settings): Boolean? { - return boxStore.awaitCallInTx { - box.remove(t) - } - } - - override suspend fun count() : Long? { - return boxStore.awaitCallInTx { - box.count() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsDoa.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsDoa.kt new file mode 100644 index 0000000..49120a3 --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/SettingsDoa.kt @@ -0,0 +1,34 @@ +package com.zaneschepke.wireguardautotunnel.repository + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.zaneschepke.wireguardautotunnel.repository.model.Settings +import kotlinx.coroutines.flow.Flow + +@Dao +interface SettingsDoa { + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun save(t: Settings) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun saveAll(t: List) + + @Query("SELECT * FROM settings WHERE id=:id") + suspend fun getById(id: Long): Settings? + + @Query("SELECT * FROM settings") + suspend fun getAll(): List + + @Query("SELECT * FROM settings") + fun getAllFlow(): Flow> + + @Delete + suspend fun delete(t: Settings) + + @Query("SELECT COUNT('id') FROM settings") + suspend fun count(): Long +} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelBox.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelBox.kt deleted file mode 100644 index ea845da..0000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelBox.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.repository - -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig -import io.objectbox.Box -import io.objectbox.BoxStore -import io.objectbox.kotlin.awaitCallInTx -import io.objectbox.kotlin.toFlow -import kotlinx.coroutines.ExperimentalCoroutinesApi -import timber.log.Timber -import javax.inject.Inject - -class TunnelBox @Inject constructor(private val box : Box,private val boxStore : BoxStore) : Repository { - - @OptIn(ExperimentalCoroutinesApi::class) - override val itemFlow = box.query().build().subscribe().toFlow() - override fun init() { - - } - - override suspend fun save(t : TunnelConfig) { - Timber.d("Saving tunnel config") - boxStore.awaitCallInTx { - box.put(t) - } - - } - - override suspend fun saveAll(t : List) { - boxStore.awaitCallInTx { - box.put(t) - } - } - - override suspend fun getById(id: Long): TunnelConfig? { - return boxStore.awaitCallInTx { - box[id] - } - } - - override suspend fun getAll(): List? { - return boxStore.awaitCallInTx { - box.all - } - } - - override suspend fun delete(t : TunnelConfig): Boolean? { - return boxStore.awaitCallInTx { - box.remove(t) - } - } - - override suspend fun count() : Long? { - return boxStore.awaitCallInTx { - box.count() - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelConfigDao.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelConfigDao.kt new file mode 100644 index 0000000..2533c7a --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/TunnelConfigDao.kt @@ -0,0 +1,34 @@ +package com.zaneschepke.wireguardautotunnel.repository + +import androidx.room.Dao +import androidx.room.Delete +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig +import kotlinx.coroutines.flow.Flow + +@Dao +interface TunnelConfigDao{ + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun save(t: TunnelConfig) + + @Insert(onConflict = OnConflictStrategy.REPLACE) + suspend fun saveAll(t: List) + + @Query("SELECT * FROM TunnelConfig WHERE id=:id") + suspend fun getById(id: Long): TunnelConfig? + + @Query("SELECT * FROM TunnelConfig") + suspend fun getAll(): List + + @Delete + suspend fun delete(t: TunnelConfig) + + @Query("SELECT COUNT('id') FROM TunnelConfig") + suspend fun count(): Long + + @Query("SELECT * FROM tunnelconfig") + fun getAllFlow(): Flow> +} \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt new file mode 100644 index 0000000..dd67942 --- /dev/null +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/Settings.kt @@ -0,0 +1,15 @@ +package com.zaneschepke.wireguardautotunnel.repository.model + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity +data class Settings( + @PrimaryKey(autoGenerate = true) val id : Int = 0, + @ColumnInfo(name = "is_tunnel_enabled") var isAutoTunnelEnabled : Boolean = false, + @ColumnInfo(name = "is_tunnel_on_mobile_data_enabled") var isTunnelOnMobileDataEnabled : Boolean = false, + @ColumnInfo(name = "trusted_network_ssids") var trustedNetworkSSIDs : MutableList = mutableListOf(), + @ColumnInfo(name = "default_tunnel") var defaultTunnel : String? = null, + @ColumnInfo(name = "is_always_on_vpn_enabled") var isAlwaysOnVpnEnabled : Boolean = false, +) \ No newline at end of file diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/TunnelConfig.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/TunnelConfig.kt similarity index 88% rename from app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/TunnelConfig.kt rename to app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/TunnelConfig.kt index 2d22faa..bd80f66 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/TunnelConfig.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/repository/model/TunnelConfig.kt @@ -1,25 +1,21 @@ -package com.zaneschepke.wireguardautotunnel.service.tunnel.model +package com.zaneschepke.wireguardautotunnel.repository.model +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Index +import androidx.room.PrimaryKey import com.wireguard.config.Config -import io.objectbox.annotation.ConflictStrategy -import io.objectbox.annotation.Entity -import io.objectbox.annotation.Id -import io.objectbox.annotation.Unique import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import java.io.InputStream - -@Entity +@Entity(indices = [Index(value = ["name"], unique = true)]) @Serializable data class TunnelConfig( - @Id - var id : Long = 0, - @Unique(onConflict = ConflictStrategy.REPLACE) - var name : String, - var wgQuick : String -) { - + @PrimaryKey(autoGenerate = true) val id : Int = 0, + @ColumnInfo(name = "name") var name : String, + @ColumnInfo(name = "wg_quick") var wgQuick : String, +){ override fun toString(): String { return Json.encodeToString(serializer(), this) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt index 816eea5..35b00a8 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt @@ -5,9 +5,8 @@ import android.app.Service import android.content.Context import android.content.Context.ACTIVITY_SERVICE import android.content.Intent -import com.google.firebase.crashlytics.ktx.crashlytics -import com.google.firebase.ktx.Firebase import com.zaneschepke.wireguardautotunnel.R +import timber.log.Timber object ServiceManager { @Suppress("DEPRECATION") @@ -43,7 +42,7 @@ object ServiceManager { Action.STOP -> context.startService(intent) } } catch (e : Exception) { - e.message?.let { Firebase.crashlytics.log(it) } + Timber.e(e.message) } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt index e24faec..37e24d4 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardConnectivityWatcherService.kt @@ -10,14 +10,14 @@ import android.os.SystemClock import com.wireguard.android.backend.Tunnel import com.zaneschepke.wireguardautotunnel.Constants import com.zaneschepke.wireguardautotunnel.R -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.model.Settings import com.zaneschepke.wireguardautotunnel.service.network.MobileDataService import com.zaneschepke.wireguardautotunnel.service.network.NetworkService import com.zaneschepke.wireguardautotunnel.service.network.NetworkStatus import com.zaneschepke.wireguardautotunnel.service.network.WifiService import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -39,7 +39,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() { lateinit var mobileDataService : NetworkService @Inject - lateinit var settingsRepo: Repository + lateinit var settingsRepo: SettingsDoa @Inject lateinit var notificationService : NotificationService @@ -131,7 +131,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() { private fun startWatcherJob() { watcherJob = CoroutineScope(Dispatchers.IO).launch { val settings = settingsRepo.getAll(); - if(!settings.isNullOrEmpty()) { + if(settings.isNotEmpty()) { setting = settings[0] } launch { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardTunnelService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardTunnelService.kt index b875591..62d9c9e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardTunnelService.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/WireGuardTunnelService.kt @@ -5,12 +5,11 @@ import android.content.Intent import android.os.Bundle import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.receiver.NotificationActionReceiver -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -28,7 +27,7 @@ class WireGuardTunnelService : ForegroundService() { lateinit var vpnService : VpnService @Inject - lateinit var settingsRepo: Repository + lateinit var settingsRepo: SettingsDoa @Inject lateinit var notificationService : NotificationService @@ -62,7 +61,7 @@ class WireGuardTunnelService : ForegroundService() { } else { Timber.d("Tunnel config null, starting default tunnel") val settings = settingsRepo.getAll(); - if(!settings.isNullOrEmpty()) { + if(settings.isNotEmpty()) { val setting = settings[0] if(setting.defaultTunnel != null && setting.isAlwaysOnVpnEnabled) { val tunnelConfig = TunnelConfig.from(setting.defaultTunnel!!) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsActivity.kt index 2ebb866..bb5cc30 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsActivity.kt @@ -3,11 +3,10 @@ package com.zaneschepke.wireguardautotunnel.service.shortcut import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.zaneschepke.wireguardautotunnel.R -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa import com.zaneschepke.wireguardautotunnel.service.foreground.Action import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.service.foreground.WireGuardTunnelService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -18,14 +17,14 @@ import javax.inject.Inject class ShortcutsActivity : AppCompatActivity() { @Inject - lateinit var settingsRepo : Repository + lateinit var settingsRepo : SettingsDoa private val scope = CoroutineScope(Dispatchers.Main); private fun attemptWatcherServiceToggle(tunnelConfig : String) { scope.launch { val settings = settingsRepo.getAll() - if (!settings.isNullOrEmpty()) { + if (settings.isNotEmpty()) { val setting = settings.first() if(setting.isAutoTunnelEnabled) { ServiceManager.toggleWatcherServiceForeground(this@ShortcutsActivity, tunnelConfig) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsManager.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsManager.kt index 04c0e9d..8798319 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsManager.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/shortcut/ShortcutsManager.kt @@ -8,7 +8,7 @@ import androidx.core.graphics.drawable.IconCompat import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.service.foreground.Action import com.zaneschepke.wireguardautotunnel.service.foreground.WireGuardTunnelService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig object ShortcutsManager { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt index 65e8469..0dc9479 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tile/TunnelControlTile.kt @@ -5,11 +5,11 @@ import android.service.quicksettings.Tile import android.service.quicksettings.TileService import com.wireguard.android.backend.Tunnel import com.zaneschepke.wireguardautotunnel.R -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -23,10 +23,10 @@ import javax.inject.Inject class TunnelControlTile : TileService() { @Inject - lateinit var settingsRepo : Repository + lateinit var settingsRepo : SettingsDoa @Inject - lateinit var configRepo : Repository + lateinit var configRepo : TunnelConfigDao @Inject lateinit var vpnService : VpnService diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/VpnService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/VpnService.kt index 346a49a..1557c20 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/VpnService.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/VpnService.kt @@ -3,7 +3,7 @@ package com.zaneschepke.wireguardautotunnel.service.tunnel import com.wireguard.android.backend.Statistics import com.wireguard.android.backend.Tunnel import com.wireguard.crypto.Key -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import kotlinx.coroutines.flow.SharedFlow interface VpnService : Tunnel { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt index 2f40c71..87116c7 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt @@ -6,7 +6,7 @@ import com.wireguard.android.backend.Statistics import com.wireguard.android.backend.Tunnel import com.wireguard.crypto.Key import com.zaneschepke.wireguardautotunnel.Constants -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.util.NumberUtils import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/Settings.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/Settings.kt deleted file mode 100644 index a868467..0000000 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/model/Settings.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.zaneschepke.wireguardautotunnel.service.tunnel.model - -import io.objectbox.annotation.Entity -import io.objectbox.annotation.Id - -@Entity -data class Settings( - @Id - var id : Long = 0, - var isAutoTunnelEnabled : Boolean = false, - var isTunnelOnMobileDataEnabled : Boolean = false, - var trustedNetworkSSIDs : MutableList = mutableListOf(), - var defaultTunnel : String? = null, - var isAlwaysOnVpnEnabled : Boolean = false, -) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt index 4e5758a..b72f801 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/MainActivity.kt @@ -33,6 +33,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.wireguard.android.backend.GoBackend +import com.zaneschepke.wireguardautotunnel.Constants import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.ui.common.PermissionRequestFailedScreen import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar @@ -143,12 +144,12 @@ class MainActivity : AppCompatActivity() { when (initialState.destination.route) { Routes.Settings.name, Routes.Support.name -> slideInHorizontally( - initialOffsetX = { -1000 }, - animationSpec = tween(500) + initialOffsetX = { -Constants.SLIDE_IN_TRANSITION_OFFSET }, + animationSpec = tween(Constants.SLIDE_IN_ANIMATION_DURATION) ) else -> { - fadeIn(animationSpec = tween(1000)) + fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION)) } } }) { @@ -158,19 +159,19 @@ class MainActivity : AppCompatActivity() { when (initialState.destination.route) { Routes.Main.name -> slideInHorizontally( - initialOffsetX = { 1000 }, - animationSpec = tween(500) + initialOffsetX = { Constants.SLIDE_IN_TRANSITION_OFFSET }, + animationSpec = tween(Constants.SLIDE_IN_ANIMATION_DURATION) ) Routes.Support.name -> { slideInHorizontally( - initialOffsetX = { -1000 }, - animationSpec = tween(500) + initialOffsetX = { -Constants.SLIDE_IN_TRANSITION_OFFSET }, + animationSpec = tween(Constants.SLIDE_IN_ANIMATION_DURATION) ) } else -> { - fadeIn(animationSpec = tween(1000)) + fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION)) } } }) { SettingsScreen(padding = padding, snackbarHostState = snackbarHostState, navController = navController, focusRequester = focusRequester) } @@ -178,20 +179,20 @@ class MainActivity : AppCompatActivity() { when (initialState.destination.route) { Routes.Settings.name, Routes.Main.name -> slideInHorizontally( - initialOffsetX = { 1000 }, - animationSpec = tween(500) + initialOffsetX = { Constants.SLIDE_IN_ANIMATION_DURATION }, + animationSpec = tween(Constants.SLIDE_IN_ANIMATION_DURATION) ) else -> { - fadeIn(animationSpec = tween(1000)) + fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION)) } } }) { SupportScreen(padding = padding, focusRequester) } composable("${Routes.Config.name}/{id}", enterTransition = { - fadeIn(animationSpec = tween(1000)) + fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION)) }) { ConfigScreen(padding = padding, navController = navController, id = it.arguments?.getString("id"), focusRequester = focusRequester)} composable("${Routes.Detail.name}/{id}", enterTransition = { - fadeIn(animationSpec = tween(1000)) + fadeIn(animationSpec = tween(Constants.FADE_IN_ANIMATION_DURATION)) }) { DetailScreen(padding = padding, id = it.arguments?.getString("id")) } } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/config/ConfigViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/config/ConfigViewModel.kt index 25a0c07..6afe299 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/config/ConfigViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/config/ConfigViewModel.kt @@ -9,10 +9,10 @@ import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.toMutableStateList import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao import com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsManager -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -22,8 +22,8 @@ import javax.inject.Inject @HiltViewModel class ConfigViewModel @Inject constructor(private val application : Application, - private val tunnelRepo : Repository, - private val settingsRepo : Repository) : ViewModel() { + private val tunnelRepo : TunnelConfigDao, + private val settingsRepo : SettingsDoa) : ViewModel() { private val _tunnel = MutableStateFlow(null) private val _tunnelName = MutableStateFlow("") @@ -140,14 +140,15 @@ class ConfigViewModel @Inject constructor(private val application : Application, tunnelRepo.save(it) ShortcutsManager.createTunnelShortcuts(application, it) val settings = settingsRepo.getAll() - if(settings != null) { - val setting = settings[0] - if(setting.defaultTunnel != null) { - if(it.id == TunnelConfig.from(setting.defaultTunnel!!).id) { - settingsRepo.save(setting.copy( - defaultTunnel = it.toString() - )) - } + if(settings.isEmpty()) { + return + } + val setting = settings[0] + if(setting.defaultTunnel != null) { + if(it.id == TunnelConfig.from(setting.defaultTunnel!!).id) { + settingsRepo.save(setting.copy( + defaultTunnel = it.toString() + )) } } } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/detail/DetailViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/detail/DetailViewModel.kt index 59c5698..c6f39ac 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/detail/DetailViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/detail/DetailViewModel.kt @@ -2,9 +2,9 @@ package com.zaneschepke.wireguardautotunnel.ui.screens.detail import androidx.lifecycle.ViewModel import com.wireguard.config.Config -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow @@ -12,7 +12,7 @@ import timber.log.Timber import javax.inject.Inject @HiltViewModel -class DetailViewModel @Inject constructor(private val tunnelRepo : Repository, private val vpnService : VpnService +class DetailViewModel @Inject constructor(private val tunnelRepo : TunnelConfigDao, private val vpnService : VpnService ) : ViewModel() { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt index 42f085b..cbca1db 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt @@ -18,7 +18,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.lazy.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FileOpen @@ -73,8 +73,8 @@ import androidx.navigation.NavController import com.wireguard.android.backend.Tunnel import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.ui.Routes import com.zaneschepke.wireguardautotunnel.ui.common.RowListItem import com.zaneschepke.wireguardautotunnel.ui.theme.brickRed @@ -249,7 +249,7 @@ fun MainScreen( .fillMaxSize() .nestedScroll(nestedScrollConnection), ) { - itemsIndexed(tunnels.toList()) { _, tunnel -> + items(tunnels, key = { tunnel -> tunnel.id }) {tunnel -> val focusRequester = FocusRequester(); RowListItem(leadingIcon = Icons.Rounded.Circle, leadingIconColor = if (tunnelName == tunnel.name) when (handshakeStatus) { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt index 8caed38..e82eba2 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainViewModel.kt @@ -9,21 +9,26 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.wireguard.config.BadConfigException import com.wireguard.config.Config +import com.zaneschepke.wireguardautotunnel.Constants import com.zaneschepke.wireguardautotunnel.R -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao import com.zaneschepke.wireguardautotunnel.service.barcode.CodeScanner import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceState import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.service.foreground.WireGuardConnectivityWatcherService import com.zaneschepke.wireguardautotunnel.service.shortcut.ShortcutsManager import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnService -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.Settings +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.ui.ViewState +import com.zaneschepke.wireguardautotunnel.util.NumberUtils import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import timber.log.Timber import javax.inject.Inject @@ -31,15 +36,15 @@ import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor(private val application : Application, - private val tunnelRepo : Repository, - private val settingsRepo : Repository, + private val tunnelRepo : TunnelConfigDao, + private val settingsRepo : SettingsDoa, private val vpnService: VpnService, private val codeScanner: CodeScanner ) : ViewModel() { private val _viewState = MutableStateFlow(ViewState()) val viewState get() = _viewState.asStateFlow() - val tunnels get() = tunnelRepo.itemFlow + val tunnels get() = tunnelRepo.getAllFlow() val state get() = vpnService.state val handshakeStatus get() = vpnService.handshakeStatus @@ -47,14 +52,9 @@ class MainViewModel @Inject constructor(private val application : Application, private val _settings = MutableStateFlow(Settings()) val settings get() = _settings.asStateFlow() - private val defaultConfigName = { - "tunnel${(Math.random() * 100000).toInt()}" - } - - init { - viewModelScope.launch { - settingsRepo.itemFlow.collect { + viewModelScope.launch(Dispatchers.IO) { + settingsRepo.getAllFlow().filter { it.isNotEmpty() }.collect { val settings = it.first() validateWatcherServiceState(settings) _settings.emit(settings) @@ -75,7 +75,7 @@ class MainViewModel @Inject constructor(private val application : Application, if(tunnelRepo.count() == 1L) { ServiceManager.stopWatcherService(application.applicationContext) val settings = settingsRepo.getAll() - if(!settings.isNullOrEmpty()) { + if(settings.isNotEmpty()) { val setting = settings[0] setting.defaultTunnel = null setting.isAutoTunnelEnabled = false @@ -99,7 +99,7 @@ class MainViewModel @Inject constructor(private val application : Application, suspend fun onTunnelQRSelected() { codeScanner.scan().collect { if(!it.isNullOrEmpty() && it.contains(application.resources.getString(R.string.config_validation))) { - val tunnelConfig = TunnelConfig(name = defaultConfigName(), wgQuick = it) + val tunnelConfig = TunnelConfig(name = NumberUtils.generateRandomTunnelName(), wgQuick = it) saveTunnel(tunnelConfig) } else if(!it.isNullOrEmpty() && it.contains(application.resources.getString(R.string.barcode_downloading))) { showSnackBarMessage(application.resources.getString(R.string.barcode_downloading_message)) @@ -110,34 +110,34 @@ class MainViewModel @Inject constructor(private val application : Application, } fun onTunnelFileSelected(uri : Uri) { - try { - val fileName = getFileName(application.applicationContext, uri) - val extension = getFileExtensionFromFileName(fileName) - if(extension != ".conf") { - viewModelScope.launch { - showSnackBarMessage(application.resources.getString(R.string.file_extension_message)) + viewModelScope.launch(Dispatchers.IO) { + try { + val fileName = getFileName(application.applicationContext, uri) + val extension = getFileExtensionFromFileName(fileName) + if (extension != ".conf") { + launch { + showSnackBarMessage(application.resources.getString(R.string.file_extension_message)) + } + return@launch } - return - } - val stream = application.applicationContext.contentResolver.openInputStream(uri) - stream ?: return - val bufferReader = stream.bufferedReader(charset = Charsets.UTF_8) + val stream = application.applicationContext.contentResolver.openInputStream(uri) + stream ?: return@launch + val bufferReader = stream.bufferedReader(charset = Charsets.UTF_8) val config = Config.parse(bufferReader) val tunnelName = getNameFromFileName(fileName) saveTunnel(TunnelConfig(name = tunnelName, wgQuick = config.toWgQuickString())) - stream.close() - } catch(_: BadConfigException) { - viewModelScope.launch { - showSnackBarMessage(application.applicationContext.getString(R.string.bad_config)) + stream.close() + } catch (_: BadConfigException) { + launch { + showSnackBarMessage(application.applicationContext.getString(R.string.bad_config)) + } } } } - private fun saveTunnel(tunnelConfig : TunnelConfig) { - viewModelScope.launch { - tunnelRepo.save(tunnelConfig) - ShortcutsManager.createTunnelShortcuts(application.applicationContext, tunnelConfig) - } + private suspend fun saveTunnel(tunnelConfig : TunnelConfig) { + tunnelRepo.save(tunnelConfig) + ShortcutsManager.createTunnelShortcuts(application.applicationContext, tunnelConfig) } @SuppressLint("Range") @@ -149,14 +149,14 @@ class MainViewModel @Inject constructor(private val application : Application, Timber.d("Exception getting config name") null } - cursor ?: return defaultConfigName() + cursor ?: return NumberUtils.generateRandomTunnelName() cursor.use { if(cursor.moveToFirst()) { return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)) } } } - return defaultConfigName() + return NumberUtils.generateRandomTunnelName() } suspend fun showSnackBarMessage(message : String) { @@ -170,7 +170,7 @@ class MainViewModel @Inject constructor(private val application : Application, } } )) - delay(3000) + delay(Constants.SNACKBAR_DELAY) dismissSnackBar() } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt index 753244e..3275815 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsScreen.kt @@ -69,7 +69,7 @@ import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.ui.Routes import com.zaneschepke.wireguardautotunnel.ui.common.ClickableIconButton import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt index 256fb7d..0a4ecde 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt @@ -6,35 +6,41 @@ import android.location.LocationManager import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.zaneschepke.wireguardautotunnel.R -import com.zaneschepke.wireguardautotunnel.repository.Repository +import com.zaneschepke.wireguardautotunnel.repository.SettingsDoa +import com.zaneschepke.wireguardautotunnel.repository.TunnelConfigDao +import com.zaneschepke.wireguardautotunnel.repository.model.Settings +import com.zaneschepke.wireguardautotunnel.repository.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings -import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig import com.zaneschepke.wireguardautotunnel.ui.ViewState import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.filter import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class SettingsViewModel @Inject constructor(private val application : Application, - private val tunnelRepo : Repository, private val settingsRepo : Repository + private val tunnelRepo : TunnelConfigDao, private val settingsRepo : SettingsDoa ) : ViewModel() { private val _trustedSSIDs = MutableStateFlow(emptyList()) val trustedSSIDs = _trustedSSIDs.asStateFlow() private val _settings = MutableStateFlow(Settings()) val settings get() = _settings.asStateFlow() - val tunnels get() = tunnelRepo.itemFlow + val tunnels get() = tunnelRepo.getAllFlow() private val _viewState = MutableStateFlow(ViewState()) val viewState get() = _viewState.asStateFlow() init { checkLocationServicesEnabled() - viewModelScope.launch { - settingsRepo.itemFlow.collect { + viewModelScope.launch(Dispatchers.IO) { + settingsRepo.getAllFlow().filter { it.isNotEmpty() }.collect { val settings = it.first() _settings.emit(settings) _trustedSSIDs.emit(settings.trustedNetworkSSIDs.toList()) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/NumberUtils.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/NumberUtils.kt index 7cdeddc..dd2a5b8 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/NumberUtils.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/NumberUtils.kt @@ -13,6 +13,10 @@ object NumberUtils { return bytes.toBigDecimal().divide(BYTES_IN_KB.toBigDecimal()) } + fun generateRandomTunnelName() : String { + return "tunnel${(Math.random() * 100000).toInt()}" + } + fun formatDecimalTwoPlaces(bigDecimal: BigDecimal) : String { val df = DecimalFormat("#.##") return df.format(bigDecimal) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7a2536e..8297e67 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -91,4 +91,5 @@ Search Icon Attempting connection.. VPN Starting + wg-tunnel-db \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 95714b7..3ecbf9b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,20 +1,18 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - buildscript { - val objectBoxVersion by extra("3.7.0") - val hiltVersion by extra("2.48") - val accompanistVersion by extra("0.31.2-alpha") - dependencies { - classpath("io.objectbox:objectbox-gradle-plugin:$objectBoxVersion") - classpath("com.google.gms:google-services:4.3.15") - classpath("com.google.firebase:firebase-crashlytics-gradle:2.9.9") + if (BuildHelper.isReleaseBuild(gradle) && BuildHelper.isGeneralFlavor(gradle)) { + classpath(libs.google.services) + classpath(libs.firebase.crashlytics.gradle) + } } } + + plugins { - id("com.android.application") version "8.2.0-beta03" apply false - id("org.jetbrains.kotlin.android") version "1.8.22" apply false - id("com.google.dagger.hilt.android") version "2.48" apply false - kotlin("plugin.serialization") version "1.8.22" apply false + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.hilt.android) apply false + kotlin("plugin.serialization").version(libs.versions.kotlin).apply(false) + alias(libs.plugins.ksp) apply false } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 0000000..37871be --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + `kotlin-dsl` // enable the Kotlin-DSL +} + +repositories { + google() + mavenCentral() +} \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/BuildHelper.kt b/buildSrc/src/main/kotlin/BuildHelper.kt new file mode 100644 index 0000000..13b6bd4 --- /dev/null +++ b/buildSrc/src/main/kotlin/BuildHelper.kt @@ -0,0 +1,29 @@ +import org.gradle.api.invocation.Gradle + +object BuildHelper { + private fun getCurrentFlavor(gradle : Gradle): String { + val taskRequestsStr = gradle.startParameter.taskRequests.toString() + val pattern: java.util.regex.Pattern = if (taskRequestsStr.contains("assemble")) { + java.util.regex.Pattern.compile("assemble(\\w+)(Release|Debug)") + } else { + java.util.regex.Pattern.compile("bundle(\\w+)(Release|Debug)") + } + + val matcher = pattern.matcher(taskRequestsStr) + val flavor = if (matcher.find()) { + matcher.group(1).lowercase() + } else { + print("NO FLAVOR FOUND") + "" + } + return flavor + } + + fun isGeneralFlavor(gradle : Gradle) : Boolean { + return getCurrentFlavor(gradle) == "general" + } + fun isReleaseBuild(gradle: Gradle) : Boolean { + return (gradle.startParameter.taskNames.size > 0 && gradle.startParameter.taskNames[0].contains( + "Release")) + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 1023be8..2cbd6d1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -21,5 +21,3 @@ kotlin.code.style=official # resources declared in the library itself and none from the library's dependencies, # thereby reducing the size of the R class for that library android.nonTransitiveRClass=true -#enable buildconfig values -android.defaults.buildfeatures.buildconfig=true \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..487e750 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,89 @@ +[versions] +accompanist = "0.31.2-alpha" +activityCompose = "1.7.2" +androidx-junit = "1.1.5" +appcompat = "1.6.1" +coreKtx = "1.12.0" +espressoCore = "3.5.1" +firebase-crashlytics-gradle = "2.9.9" +google-services = "4.3.15" +hiltAndroid = "2.48" +hiltNavigationCompose = "1.0.0" +junit = "4.13.2" +kotlinx-serialization-json = "1.5.1" +lifecycle-runtime-compose = "2.6.2" +material-icons-extended = "1.5.1" +material3 = "1.1.1" +navigationCompose = "2.7.2" +playServicesCodeScanner = "16.1.0" +roomVersion = "2.6.0-beta01" +timber = "5.0.1" +tunnel = "1.0.20230706" +androidGradlePlugin = "8.2.0-beta03" +kotlin="1.9.10" +ksp="1.9.10-1.0.13" +composeBom="2023.09.00" +firebaseBom="32.2.3" +compose="1.5.1" +crashlytics="18.4.1" +analytics="21.3.0" +composeCompiler="1.5.3" + + +[libraries] +# accompanist +accompanist-drawablepainter = { module = "com.google.accompanist:accompanist-drawablepainter", version.ref = "accompanist" } +accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" } +accompanist-navigation-animation = { module = "com.google.accompanist:accompanist-navigation-animation", version.ref = "accompanist" } +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } +accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanist" } +#room +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "roomVersion" } +androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "roomVersion" } +androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "roomVersion" } + +#compose +androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref="composeBom" } +androidx-compose-ui-test = { module="androidx.compose.ui:ui-test-junit4", version.ref="compose" } +androidx-compose-ui-tooling = { module="androidx.compose.ui:ui-tooling", version.ref="compose" } +androidx-compose-manifest = { module="androidx.compose.ui:ui-test-manifest", version.ref="compose" } +androidx-compose-ui-graphics = { module="androidx.compose.ui:ui-graphics", version.ref="compose" } +androidx-compose-ui-tooling-preview = { module="androidx.compose.ui:ui-tooling-preview", version.ref="compose" } +androidx-compose-ui = { module="androidx.compose.ui:ui", version.ref="compose" } + +#hilt +hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" } +hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" } + +androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "activityCompose" } +androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } +androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } +androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" } +androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" } +androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" } +androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycle-runtime-compose" } +androidx-material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" } +androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" } + +junit = { module = "junit:junit", version.ref = "junit" } +kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" } +lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "lifecycle-runtime-compose" } +material-icons-extended = { module = "androidx.compose.material:material-icons-extended", version.ref = "material-icons-extended" } +play-services-code-scanner = { module = "com.google.android.gms:play-services-code-scanner", version.ref = "playServicesCodeScanner" } + +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } + +tunnel = { module = "com.wireguard.android:tunnel", version.ref = "tunnel" } + +#firebase +google-firebase-crashlytics-ktx = { module = "com.google.firebase:firebase-crashlytics-ktx", version.ref = "crashlytics" } +google-firebase-analytics-ktx = { module = "com.google.firebase:firebase-analytics-ktx", version.ref = "analytics" } +firebase-crashlytics-gradle = { module = "com.google.firebase:firebase-crashlytics-gradle", version.ref = "firebase-crashlytics-gradle" } +firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBom"} +google-services = { module = "com.google.gms:google-services", version.ref = "google-services" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } +hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hiltAndroid" } +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }