From e8be0ef93ffbdc0551eabcf07aba293ab31d907e Mon Sep 17 00:00:00 2001 From: xiaji Date: Sat, 28 Feb 2026 17:12:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=9B=B8=E6=9C=BA=E6=8B=8D?= =?UTF-8?q?=E7=85=A7=E9=97=AE=E9=A2=98=EF=BC=8C=E4=BC=98=E5=8C=96=E6=B0=B4?= =?UTF-8?q?=E5=8D=B0=E5=92=8C=E5=90=88=E6=88=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复 ImageCapture 未绑定相机导致的拍照失败问题 - 添加标题/内容文字样式配置支持 - 使用用户配置的水印样式和图片质量 - 修复 Compose API 兼容性问题 (HorizontalDivider, entries) - 修复 Kotlin 版本兼容性问题 - 添加必要的依赖 (accompanist-permissions, coroutines-play-services) --- .idea/.gitignore | 3 +++ .idea/AndroidProjectSystem.xml | 6 +++++ .idea/gradle.xml | 12 +++++++++ .idea/markdown.xml | 8 ++++++ .idea/migrations.xml | 10 +++++++ .idea/misc.xml | 10 +++++++ .idea/runConfigurations.xml | 17 ++++++++++++ .idea/vcs.xml | 6 +++++ app/build.gradle.kts | 4 +++ .../camera/data/models/WatermarkModels.kt | 1 - .../camera/ui/camera/CameraScreen.kt | 20 +++++++------- .../inspection/camera/ui/merge/MergeScreen.kt | 8 ++++-- .../camera/ui/settings/SettingsScreen.kt | 26 +++++++++---------- .../inspection/camera/util/ImageProcessor.kt | 6 ----- gradle/wrapper/gradle-wrapper.properties | 4 +-- 15 files changed, 107 insertions(+), 34 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/AndroidProjectSystem.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/markdown.xml create mode 100644 .idea/migrations.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml new file mode 100644 index 0000000..4a53bee --- /dev/null +++ b/.idea/AndroidProjectSystem.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..b838237 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/markdown.xml b/.idea/markdown.xml new file mode 100644 index 0000000..c61ea33 --- /dev/null +++ b/.idea/markdown.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/.idea/migrations.xml b/.idea/migrations.xml new file mode 100644 index 0000000..f8051a6 --- /dev/null +++ b/.idea/migrations.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..3040d03 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..16660f1 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index afe8509..bc463ab 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -78,6 +78,7 @@ dependencies { // Location implementation("com.google.android.gms:play-services-location:21.0.1") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.7.3") // DataStore for preferences implementation("androidx.datastore:datastore-preferences:1.0.0") @@ -85,6 +86,9 @@ dependencies { // Coil for image loading implementation("io.coil-kt:coil-compose:2.5.0") + // Accompanist permissions + implementation("com.google.accompanist:accompanist-permissions:0.32.0") + // Testing testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") diff --git a/app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt b/app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt index bc4ee97..9816589 100644 --- a/app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt +++ b/app/src/main/java/com/inspection/camera/data/models/WatermarkModels.kt @@ -1,7 +1,6 @@ package com.inspection.camera.data.models import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.alpha import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp diff --git a/app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt b/app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt index 318becd..1951b27 100644 --- a/app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt +++ b/app/src/main/java/com/inspection/camera/ui/camera/CameraScreen.kt @@ -43,6 +43,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf @@ -145,12 +146,13 @@ fun CameraScreen( CameraContent( flashMode = flashMode, onFlashModeChange = { flashMode = it }, - onCapture = { + onCapture = { imageCapture -> if (!isCapturing) { isCapturing = true scope.launch { capturePhoto( context = context, + imageCapture = imageCapture, flashMode = flashMode, watermarkStyle = currentWatermarkStyle, imageQuality = currentImageQuality, @@ -183,7 +185,7 @@ fun CameraScreen( private fun CameraContent( flashMode: Int, onFlashModeChange: (Int) -> Unit, - onCapture: () -> Unit, + onCapture: (ImageCapture) -> Unit, onSettingsClick: () -> Unit, onGalleryClick: () -> Unit, onMergeClick: () -> Unit, @@ -203,7 +205,7 @@ private fun CameraContent( val cameraProvider = cameraProviderFuture.get() val preview = Preview.Builder().build().also { - it.surfaceProvider = previewView?.surfaceProvider + it.setSurfaceProvider(previewView?.surfaceProvider) } imageCapture = ImageCapture.Builder() @@ -254,6 +256,7 @@ private fun CameraContent( // 底部控制栏 BottomControls( capturedCount = capturedCount, + imageCapture = imageCapture, onCapture = onCapture, onGalleryClick = onGalleryClick, onMergeClick = onMergeClick, @@ -303,7 +306,8 @@ private fun TopControls( @Composable private fun BottomControls( capturedCount: Int, - onCapture: () -> Unit, + imageCapture: ImageCapture?, + onCapture: (ImageCapture) -> Unit, onGalleryClick: () -> Unit, onMergeClick: () -> Unit, isCapturing: Boolean, @@ -333,7 +337,7 @@ private fun BottomControls( } FloatingActionButton( - onClick = onCapture, + onClick = { imageCapture?.let { onCapture(it) } }, modifier = Modifier.size(72.dp), containerColor = Color.White, shape = CircleShape @@ -402,17 +406,13 @@ private fun PermissionRequest( private fun capturePhoto( context: Context, + imageCapture: ImageCapture, flashMode: Int, watermarkStyle: WatermarkStyle, imageQuality: ImageQuality, locationText: String, onComplete: (Uri) -> Unit ) { - val imageCapture = ImageCapture.Builder() - .setFlashMode(flashMode) - .setCaptureMode(ImageCapture.CAPTURE_MODE_MAXIMIZE_QUALITY) - .build() - val photoFile = File( context.cacheDir, "photo_${System.currentTimeMillis()}.jpg" diff --git a/app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt b/app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt index 93562a8..ebd7844 100644 --- a/app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt +++ b/app/src/main/java/com/inspection/camera/ui/merge/MergeScreen.kt @@ -39,6 +39,7 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf @@ -56,6 +57,7 @@ import androidx.compose.ui.unit.dp import coil.compose.AsyncImage import coil.request.ImageRequest import com.inspection.camera.data.PreferencesManager +import com.inspection.camera.data.models.ImageItem import com.inspection.camera.data.models.ImageQuality import com.inspection.camera.data.models.MergeLayoutType import com.inspection.camera.data.models.WatermarkStyle @@ -222,8 +224,9 @@ fun MergeScreen( onClick = { scope.launch { previewBitmap = withContext(Dispatchers.Default) { + val imageItems = images.map { ImageItem(uri = it, path = it.toString()) } ImageProcessor.mergeImages( - images.toList(), + imageItems, layoutType, imageQuality ).let { bitmap -> @@ -289,8 +292,9 @@ fun MergeScreen( TextButton(onClick = { scope.launch { val bitmap = withContext(Dispatchers.Default) { + val imageItems = images.map { ImageItem(uri = it, path = it.toString()) } ImageProcessor.mergeImages( - images.toList(), + imageItems, layoutType, imageQuality ).let { mergedBitmap -> diff --git a/app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt b/app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt index 3e4a1f0..b2ad077 100644 --- a/app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/inspection/camera/ui/settings/SettingsScreen.kt @@ -15,8 +15,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Divider import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -117,7 +117,7 @@ fun SettingsScreen( // 水印设置 SettingsSection(title = "水印设置") { SettingsItem(title = "水印样式") { - WatermarkStyle.entries.forEach { style -> + listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style -> Row( modifier = Modifier .fillMaxWidth() @@ -135,10 +135,10 @@ fun SettingsScreen( } } - HorizontalDivider() + Divider() SettingsItem(title = "地点获取方式") { - LocationMode.entries.forEach { mode -> + LocationMode.values().forEach { mode -> Row( modifier = Modifier .fillMaxWidth() @@ -161,7 +161,7 @@ fun SettingsScreen( } } - HorizontalDivider() + Divider() SettingsItem(title = "手动输入地址") { OutlinedTextField( @@ -180,7 +180,7 @@ fun SettingsScreen( // 合成设置 SettingsSection(title = "合成设置") { SettingsItem(title = "默认合成布局") { - MergeLayoutType.entries.forEach { layout -> + MergeLayoutType.values().forEach { layout -> Row( modifier = Modifier .fillMaxWidth() @@ -198,10 +198,10 @@ fun SettingsScreen( } } - HorizontalDivider() + Divider() SettingsItem(title = "合成图片质量") { - ImageQuality.entries.forEach { quality -> + ImageQuality.values().forEach { quality -> Row( modifier = Modifier .fillMaxWidth() @@ -219,10 +219,10 @@ fun SettingsScreen( } } - HorizontalDivider() + Divider() SettingsItem(title = "默认标题样式") { - WatermarkStyle.entries.forEach { style -> + listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style -> Row( modifier = Modifier .fillMaxWidth() @@ -240,10 +240,10 @@ fun SettingsScreen( } } - HorizontalDivider() + Divider() SettingsItem(title = "默认内容样式") { - WatermarkStyle.entries.forEach { style -> + listOf(WatermarkStyle.Default, WatermarkStyle.Simple, WatermarkStyle.Bold).forEach { style -> Row( modifier = Modifier .fillMaxWidth() @@ -277,7 +277,7 @@ fun SettingsScreen( ) } - HorizontalDivider() + Divider() SettingsItem(title = "巡检员信息") { OutlinedTextField( diff --git a/app/src/main/java/com/inspection/camera/util/ImageProcessor.kt b/app/src/main/java/com/inspection/camera/util/ImageProcessor.kt index c26d431..b027841 100644 --- a/app/src/main/java/com/inspection/camera/util/ImageProcessor.kt +++ b/app/src/main/java/com/inspection/camera/util/ImageProcessor.kt @@ -137,12 +137,6 @@ object ImageProcessor { val top = row * cellHeight try { - val inputStream = imageItem.uri.path?.let { path -> - imageItem.uri.let { uri -> - inputStream - } - } - val sourceBitmap = BitmapFactory.decodeFile(imageItem.path) ?: return@forEachIndexed diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 62f495d..bd595ea 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip -networkTimeout=10000 +distributionUrl=https\://repo.huaweicloud.com/gradle/gradle-8.2-bin.zip +networkTimeout=120000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists