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.
This commit is contained in:
parent
991d1224ab
commit
3c5aff31aa
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -114,8 +114,5 @@
|
|||
<meta-data
|
||||
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||
android:value="barcode_ui"/>
|
||||
<meta-data
|
||||
android:name="firebase_crashlytics_collection_enabled"
|
||||
android:value="true" />
|
||||
</application>
|
||||
</manifest>
|
|
@ -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
|
||||
}
|
|
@ -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<Settings>
|
||||
|
||||
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 {
|
||||
|
|
|
@ -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<Settings> {
|
||||
return store.boxFor(Settings::class.java)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBoxForTunnels(store : BoxStore) : Box<TunnelConfig> {
|
||||
return store.boxFor(TunnelConfig::class.java)
|
||||
}
|
||||
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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<Settings>
|
||||
@Provides
|
||||
fun provideSettingsRepository(appDatabase: AppDatabase) : SettingsDoa {
|
||||
return appDatabase.settingDao()
|
||||
}
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
abstract fun provideTunnelRepository(tunnelBox: TunnelBox) : Repository<TunnelConfig>
|
||||
@Provides
|
||||
fun provideTunnelConfigRepository(appDatabase: AppDatabase) : TunnelConfigDao {
|
||||
return appDatabase.tunnelConfigDoa()
|
||||
}
|
||||
}
|
|
@ -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<Settings>
|
||||
lateinit var settingsRepo : SettingsDoa
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == Intent.ACTION_BOOT_COMPLETED) {
|
||||
|
|
|
@ -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<Settings>
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.zaneschepke.wireguardautotunnel.repository
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
|
||||
class DatabaseListConverters {
|
||||
@TypeConverter
|
||||
fun listToString(value: MutableList<String>): String {
|
||||
return value.joinToString()
|
||||
}
|
||||
@TypeConverter
|
||||
fun <T> stringToList(value: String): MutableList<String> {
|
||||
if(value.isEmpty()) return mutableListOf()
|
||||
return value.split(",").toMutableList()
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package com.zaneschepke.wireguardautotunnel.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface Repository<T> {
|
||||
suspend fun save(t : T)
|
||||
suspend fun saveAll(t : List<T>)
|
||||
suspend fun getById(id : Long) : T?
|
||||
suspend fun getAll() : List<T>?
|
||||
suspend fun delete(t : T) : Boolean?
|
||||
suspend fun count() : Long?
|
||||
|
||||
val itemFlow : Flow<MutableList<T>>
|
||||
|
||||
fun init()
|
||||
}
|
|
@ -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<Settings>, private val boxStore : BoxStore) : Repository<Settings> {
|
||||
|
||||
@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<Settings>) {
|
||||
boxStore.awaitCallInTx {
|
||||
box.put(t)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getById(id: Long): Settings? {
|
||||
return boxStore.awaitCallInTx {
|
||||
box[id]
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAll(): List<Settings>? {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<Settings>)
|
||||
|
||||
@Query("SELECT * FROM settings WHERE id=:id")
|
||||
suspend fun getById(id: Long): Settings?
|
||||
|
||||
@Query("SELECT * FROM settings")
|
||||
suspend fun getAll(): List<Settings>
|
||||
|
||||
@Query("SELECT * FROM settings")
|
||||
fun getAllFlow(): Flow<MutableList<Settings>>
|
||||
|
||||
@Delete
|
||||
suspend fun delete(t: Settings)
|
||||
|
||||
@Query("SELECT COUNT('id') FROM settings")
|
||||
suspend fun count(): Long
|
||||
}
|
|
@ -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<TunnelConfig>,private val boxStore : BoxStore) : Repository<TunnelConfig> {
|
||||
|
||||
@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<TunnelConfig>) {
|
||||
boxStore.awaitCallInTx {
|
||||
box.put(t)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getById(id: Long): TunnelConfig? {
|
||||
return boxStore.awaitCallInTx {
|
||||
box[id]
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getAll(): List<TunnelConfig>? {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<TunnelConfig>)
|
||||
|
||||
@Query("SELECT * FROM TunnelConfig WHERE id=:id")
|
||||
suspend fun getById(id: Long): TunnelConfig?
|
||||
|
||||
@Query("SELECT * FROM TunnelConfig")
|
||||
suspend fun getAll(): List<TunnelConfig>
|
||||
|
||||
@Delete
|
||||
suspend fun delete(t: TunnelConfig)
|
||||
|
||||
@Query("SELECT COUNT('id') FROM TunnelConfig")
|
||||
suspend fun count(): Long
|
||||
|
||||
@Query("SELECT * FROM tunnelconfig")
|
||||
fun getAllFlow(): Flow<MutableList<TunnelConfig>>
|
||||
}
|
|
@ -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<String> = mutableListOf(),
|
||||
@ColumnInfo(name = "default_tunnel") var defaultTunnel : String? = null,
|
||||
@ColumnInfo(name = "is_always_on_vpn_enabled") var isAlwaysOnVpnEnabled : Boolean = false,
|
||||
)
|
|
@ -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)
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<MobileDataService>
|
||||
|
||||
@Inject
|
||||
lateinit var settingsRepo: Repository<Settings>
|
||||
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 {
|
||||
|
|
|
@ -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<Settings>
|
||||
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!!)
|
||||
|
|
|
@ -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<Settings>
|
||||
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)
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
|
|
@ -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<Settings>
|
||||
lateinit var settingsRepo : SettingsDoa
|
||||
|
||||
@Inject
|
||||
lateinit var configRepo : Repository<TunnelConfig>
|
||||
lateinit var configRepo : TunnelConfigDao
|
||||
|
||||
@Inject
|
||||
lateinit var vpnService : VpnService
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<String> = mutableListOf(),
|
||||
var defaultTunnel : String? = null,
|
||||
var isAlwaysOnVpnEnabled : Boolean = false,
|
||||
)
|
|
@ -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")) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TunnelConfig>,
|
||||
private val settingsRepo : Repository<Settings>) : ViewModel() {
|
||||
private val tunnelRepo : TunnelConfigDao,
|
||||
private val settingsRepo : SettingsDoa) : ViewModel() {
|
||||
|
||||
private val _tunnel = MutableStateFlow<TunnelConfig?>(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()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TunnelConfig>, private val vpnService : VpnService
|
||||
class DetailViewModel @Inject constructor(private val tunnelRepo : TunnelConfigDao, private val vpnService : VpnService
|
||||
|
||||
) : ViewModel() {
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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<TunnelConfig>,
|
||||
private val settingsRepo : Repository<Settings>,
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<TunnelConfig>, private val settingsRepo : Repository<Settings>
|
||||
private val tunnelRepo : TunnelConfigDao, private val settingsRepo : SettingsDoa
|
||||
) : ViewModel() {
|
||||
|
||||
private val _trustedSSIDs = MutableStateFlow(emptyList<String>())
|
||||
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())
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -91,4 +91,5 @@
|
|||
<string name="search_icon">Search Icon</string>
|
||||
<string name="attempt_connection">Attempting connection..</string>
|
||||
<string name="vpn_starting">VPN Starting</string>
|
||||
<string name="db_name">wg-tunnel-db</string>
|
||||
</resources>
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
plugins {
|
||||
`kotlin-dsl` // enable the Kotlin-DSL
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
|
@ -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"))
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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" }
|
Loading…
Reference in New Issue