From 7ef4b7d1cfe77d22e2125b541d08d97dd61fc266 Mon Sep 17 00:00:00 2001 From: lamtruong28 Date: Fri, 26 Jun 2026 22:03:24 +0700 Subject: [PATCH] Add app info in setting --- .../app/torquevaultkmp/Platform.android.kt | 2 -- .../app/torquevaultkmp/di/PlatformModules.kt | 3 +++ .../app/torquevaultkmp/utils/AppInfo.android.kt | 15 +++++++++++++++ .../screens/settings/SettingScreen.kt | 17 ++++++++++++++++- .../app/torquevaultkmp/utils/AppInfo.kt | 5 +++++ .../app/torquevaultkmp/di/PlatformModules.kt | 3 +++ .../app/torquevaultkmp/utils/AppInfo.ios.kt | 12 ++++++++++++ iosApp/iosApp.xcodeproj/project.pbxproj | 4 ++++ 8 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.android.kt create mode 100644 composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.kt create mode 100644 composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.ios.kt diff --git a/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/Platform.android.kt b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/Platform.android.kt index 65c48c5..a78c1d2 100644 --- a/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/Platform.android.kt +++ b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/Platform.android.kt @@ -1,7 +1,5 @@ package com.digitoolsolutions.app.torquevaultkmp -import android.os.Build - class AndroidPlatform : Platform { override val name: String = "Android" } diff --git a/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt index a061f28..016b129 100644 --- a/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt +++ b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt @@ -5,8 +5,10 @@ import app.cash.sqldelight.driver.android.AndroidSqliteDriver import com.digitoolsolutions.app.torquevaultkmp.AppStoragePlatform import com.digitoolsolutions.app.torquevaultkmp.data.storage.AppStorage import com.digitoolsolutions.app.torquevaultkmp.data.storage.db.AppDatabase +import com.digitoolsolutions.app.torquevaultkmp.utils.AndroidAppInfo import com.digitoolsolutions.app.torquevaultkmp.utils.AndroidBluetoothManager import com.digitoolsolutions.app.torquevaultkmp.utils.AndroidNetworkMonitor +import com.digitoolsolutions.app.torquevaultkmp.utils.AppInfo import com.digitoolsolutions.app.torquevaultkmp.utils.BluetoothManager import com.digitoolsolutions.app.torquevaultkmp.utils.NetworkMonitor import com.digitoolsolutions.app.torquevaultkmp.utils.PermissionHandler @@ -26,4 +28,5 @@ actual val platformModule = module { ) } single { AndroidNetworkMonitor(androidContext()) } + single { AndroidAppInfo(androidContext()) } } diff --git a/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.android.kt b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.android.kt new file mode 100644 index 0000000..67a859b --- /dev/null +++ b/composeApp/src/androidMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.android.kt @@ -0,0 +1,15 @@ +package com.digitoolsolutions.app.torquevaultkmp.utils + +import android.content.Context +import android.os.Build +import androidx.annotation.RequiresApi + +class AndroidAppInfo(private val context: Context): AppInfo { + override val version: String? + @RequiresApi(Build.VERSION_CODES.P) + get() { + val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0) + val versionName = packageInfo.versionName + return versionName + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/screens/settings/SettingScreen.kt b/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/screens/settings/SettingScreen.kt index 9d9328d..88925cc 100644 --- a/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/screens/settings/SettingScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/screens/settings/SettingScreen.kt @@ -13,6 +13,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost @@ -29,17 +30,21 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.digitoolsolutions.app.torquevaultkmp.components.AppBar import com.digitoolsolutions.app.torquevaultkmp.screens.auth.AuthDestination +import com.digitoolsolutions.app.torquevaultkmp.utils.AppInfo import kotlinx.coroutines.launch import org.koin.compose.viewmodel.koinViewModel import org.jetbrains.compose.resources.stringResource +import org.koin.compose.koinInject import torquevaultkmp.composeapp.generated.resources.Res import torquevaultkmp.composeapp.generated.resources.auto_connect import torquevaultkmp.composeapp.generated.resources.dark_theme @@ -101,6 +106,7 @@ fun SettingContent( val focusManager = LocalFocusManager.current val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() + val appVersion: String? = koinInject().version // remember the initial serverUrl to check if it has changed when saving val oldUrl by remember { mutableStateOf(serverUrl) } var showRestartDialog by remember { mutableStateOf(false) } @@ -133,7 +139,7 @@ fun SettingContent( .fillMaxSize() .imePadding() .padding(padding) - .padding(16.dp) + .padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 0.dp) .pointerInput(Unit) { detectTapGestures(onTap = { focusManager.clearFocus() @@ -208,6 +214,15 @@ fun SettingContent( ) { Text(stringResource(Res.string.logout)) } + + Spacer(modifier = Modifier.weight(1f)) + Text( + text="Digitool Solutions Team" + if(appVersion != null) " - App version: $appVersion" else "", + style = MaterialTheme.typography.bodySmall, + color = Color.Gray, + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) } } } diff --git a/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.kt b/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.kt new file mode 100644 index 0000000..897b0a7 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.kt @@ -0,0 +1,5 @@ +package com.digitoolsolutions.app.torquevaultkmp.utils + +interface AppInfo { + val version: String? +} \ No newline at end of file diff --git a/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt b/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt index f21a59c..7f6ab40 100644 --- a/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt +++ b/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/di/PlatformModules.kt @@ -5,7 +5,9 @@ import app.cash.sqldelight.driver.native.NativeSqliteDriver import com.digitoolsolutions.app.torquevaultkmp.AppStoragePlatform import com.digitoolsolutions.app.torquevaultkmp.data.storage.AppStorage import com.digitoolsolutions.app.torquevaultkmp.data.storage.db.AppDatabase +import com.digitoolsolutions.app.torquevaultkmp.utils.AppInfo import com.digitoolsolutions.app.torquevaultkmp.utils.BluetoothManager +import com.digitoolsolutions.app.torquevaultkmp.utils.IOSAppInfo import com.digitoolsolutions.app.torquevaultkmp.utils.IOSNetworkMonitor import com.digitoolsolutions.app.torquevaultkmp.utils.IosBluetoothManager import com.digitoolsolutions.app.torquevaultkmp.utils.NetworkMonitor @@ -24,4 +26,5 @@ actual val platformModule = module { ) } single { IOSNetworkMonitor() } + single { IOSAppInfo() } } diff --git a/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.ios.kt b/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.ios.kt new file mode 100644 index 0000000..e9128e1 --- /dev/null +++ b/composeApp/src/iosMain/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/AppInfo.ios.kt @@ -0,0 +1,12 @@ +package com.digitoolsolutions.app.torquevaultkmp.utils + +import platform.Foundation.NSBundle + +class IOSAppInfo: AppInfo { + override val version: String? + get() { + val infoDict = NSBundle.mainBundle.infoDictionary + val version = infoDict?.get("CFBundleShortVersionString") as? String + return version + } +} \ No newline at end of file diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj index 86e0a5a..8b3c5f0 100644 --- a/iosApp/iosApp.xcodeproj/project.pbxproj +++ b/iosApp/iosApp.xcodeproj/project.pbxproj @@ -302,6 +302,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; DEVELOPMENT_TEAM = ZCFJN5LS8B; ENABLE_PREVIEWS = YES; @@ -319,6 +320,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.2; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -333,6 +335,7 @@ ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; DEVELOPMENT_TEAM = ZCFJN5LS8B; ENABLE_PREVIEWS = YES; @@ -350,6 +353,7 @@ "$(inherited)", "@executable_path/Frameworks", ); + MARKETING_VERSION = 1.0.2; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2";