Skip to content

Commit c8af8b2

Browse files
rosuHCopilot
andauthored
fix(UI): Compatibility issues(systemBars, photo permissions) (#367)
Co-authored-by: rosuH <hi@rosuh.me> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
1 parent 7e4aad2 commit c8af8b2

11 files changed

Lines changed: 252 additions & 126 deletions

File tree

.github/workflows/pr_pre_check.yml

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,58 @@
1-
name: Basic Check
2-
3-
env:
4-
GRADLE_OPTS: -Dorg.gradle.jvmargs="-Xmx3072m -Dfile.encoding=UTF-8 -XX:+HeapDumpOnOutOfMemoryError -XX:MaxMetaspaceSize=1g" -Dkotlin.daemon.jvm.options="-Xmx2560m" -Dkotlin.incremental=false
5-
CI_GRADLE_ARG_PROPERTIES: --stacktrace -PpreDexEnable=false --max-workers 2 --no-daemon
1+
name: PR Checks
62

73
on:
84
pull_request:
9-
types: [opened,reopened,synchronize]
5+
types: [opened, reopened, synchronize]
106
branches:
117
- master
8+
paths-ignore:
9+
- '**/*.md'
10+
- 'fastlane/**'
11+
- 'static/**'
12+
- 'captures/**'
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: read
17+
18+
concurrency:
19+
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
20+
cancel-in-progress: true
21+
1222
jobs:
13-
check:
14-
name: Check
23+
build:
24+
name: Compile (app:assembleDebug)
1525
runs-on: ubuntu-latest
26+
timeout-minutes: 30
27+
if: ${{ github.event_name != 'pull_request' || !github.event.pull_request.draft }}
1628
steps:
17-
- uses: actions/checkout@v4
18-
- name: Skip duplicate actions
19-
uses: fkirc/skip-duplicate-actions@v5
20-
with:
21-
cancel_others: true
22-
- uses: actions/setup-java@v4
29+
- name: Checkout
30+
uses: actions/checkout@v4
2331
with:
24-
distribution: 'zulu'
25-
java-version: 17
26-
cache: 'gradle'
27-
- uses: gradle/actions/setup-gradle@v4
28-
with:
29-
gradle-version: wrapper
30-
gradle-home-cache-cleanup: true
31-
# - run: ./gradlew spotlessCheck
32-
simple_compile:
33-
runs-on: ubuntu-latest
34-
steps:
35-
- uses: actions/checkout@v4
36-
with:
37-
fetch-depth: 0
38-
- uses: actions/setup-java@v4
32+
fetch-depth: 1
33+
persist-credentials: false
34+
35+
- name: Validate Gradle Wrapper
36+
uses: gradle/wrapper-validation-action@v2
37+
38+
- name: Set up JDK 17
39+
uses: actions/setup-java@v4
3940
with:
40-
distribution: 'zulu'
41-
java-version: 17
42-
cache: 'gradle'
43-
- uses: gradle/actions/setup-gradle@v4
41+
distribution: 'temurin'
42+
java-version: '17'
43+
44+
- name: Set up Android SDK
45+
uses: android-actions/setup-android@v3
46+
47+
- name: Set up Gradle
48+
uses: gradle/actions/setup-gradle@v4
4449
with:
4550
gradle-version: wrapper
51+
cache-read-only: ${{ github.event_name == 'pull_request' }}
4652
gradle-home-cache-cleanup: true
47-
- name: Build apk with Gradle
48-
run: ./gradlew :app:assembleDebug
53+
54+
- name: Make gradlew executable
55+
run: chmod +x ./gradlew
56+
57+
- name: Build debug APK (skip lint/tests)
58+
run: ./gradlew :app:assembleDebug -x lint -x test --stacktrace

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ android {
1616
applicationId = "me.rosuh.easywatermark"
1717
minSdk = (Apps.minSdk)
1818
targetSdk = (Apps.targetSdk)
19-
versionCode = 20906
20-
versionName = "2.9.6"
19+
versionCode = 21000
20+
versionName = "2.10.0"
2121
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
2222
}
2323

app/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,17 @@
88
<uses-permission
99
android:name="android.permission.READ_EXTERNAL_STORAGE"
1010
android:maxSdkVersion="32" />
11+
12+
<!-- Devices running Android 12L (API level 32) or lower -->
13+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
14+
15+
<!-- Devices running Android 13 (API level 33) or higher -->
1116
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
1217

18+
<!-- To handle the reselection within the app on devices running Android 14
19+
or higher if your app targets Android 14 (API level 34) or higher. -->
20+
<uses-permission android:name="android.permission.READ_MEDIA_VISUAL_USER_SELECTED" />
21+
1322
<application
1423
android:name=".MyApp"
1524
android:allowBackup="true"

app/src/main/java/me/rosuh/easywatermark/ui/MainActivity.kt

Lines changed: 74 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ import android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
2020
import android.widget.Button
2121
import android.widget.TextView
2222
import android.widget.Toast
23-
import androidx.activity.result.ActivityResultCallback
2423
import androidx.activity.result.ActivityResultLauncher
24+
import androidx.activity.result.PickVisualMediaRequest
2525
import androidx.activity.result.contract.ActivityResultContracts
2626
import androidx.activity.viewModels
2727
import androidx.appcompat.app.AppCompatActivity
2828
import androidx.core.content.ContextCompat
2929
import androidx.core.content.edit
30+
import androidx.core.view.ViewCompat
31+
import androidx.core.view.WindowCompat
3032
import androidx.core.view.forEach
3133
import androidx.fragment.app.commit
3234
import androidx.lifecycle.Lifecycle
@@ -52,7 +54,6 @@ import me.rosuh.easywatermark.ui.panel.*
5254
import me.rosuh.easywatermark.ui.widget.CenterLayoutManager
5355
import me.rosuh.easywatermark.ui.widget.LaunchView
5456
import me.rosuh.easywatermark.utils.FileUtils
55-
import me.rosuh.easywatermark.utils.PickImageContract
5657
import me.rosuh.easywatermark.utils.VibrateHelper
5758
import me.rosuh.easywatermark.utils.ktx.*
5859
import me.rosuh.easywatermark.utils.onItemClick
@@ -61,14 +62,22 @@ import me.rosuh.easywatermark.utils.onItemClick
6162
@AndroidEntryPoint
6263
class MainActivity : AppCompatActivity() {
6364

64-
private lateinit var pickIconLauncher: ActivityResultLauncher<String>
65+
private lateinit var pickIconPhotoPickerLauncher: ActivityResultLauncher<PickVisualMediaRequest>
66+
private lateinit var pickMultiplePhotoPickerLauncher: ActivityResultLauncher<PickVisualMediaRequest>
67+
private lateinit var pickIconLegacyLauncher: ActivityResultLauncher<String>
6568
private val viewModel: MainViewModel by viewModels()
6669

6770
private val currentBgColor: Int
6871
get() = ((launchView.parent as? View?)?.background as? ColorDrawable)?.color ?: colorSurface
6972

7073
private lateinit var requestPermissionLauncher: ActivityResultLauncher<String>
7174

75+
private var pendingPermissionAction: (() -> Unit)? = null
76+
77+
private val isSystemPhotoPickerAvailable by lazy {
78+
ActivityResultContracts.PickVisualMedia.isPhotoPickerAvailable(this)
79+
}
80+
7281
private val contentFunList: List<FuncTitleModel> by lazy {
7382
listOf(
7483
FuncTitleModel(
@@ -227,19 +236,32 @@ class MainActivity : AppCompatActivity() {
227236
}
228237

229238
private fun registerResultCallback() {
230-
pickIconLauncher =
231-
registerForActivityResult(PickImageContract()) { uri: Uri? ->
232-
handleActivityResult(REQ_PICK_ICON, listOf(uri))
239+
pickMultiplePhotoPickerLauncher =
240+
registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia()) { uris ->
241+
handlePickedMedia(REQ_CODE_PICK_IMAGE, uris)
242+
}
243+
pickIconPhotoPickerLauncher =
244+
registerForActivityResult(ActivityResultContracts.PickVisualMedia()) { uri ->
245+
val result = uri?.let(::listOf) ?: emptyList()
246+
handlePickedMedia(REQ_PICK_ICON, result)
247+
}
248+
pickIconLegacyLauncher =
249+
registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
250+
val result = uri?.let(::listOf) ?: emptyList()
251+
handlePickedMedia(REQ_PICK_ICON, result)
233252
}
234253
requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
235254
if (isGranted) {
255+
pendingPermissionAction?.invoke()
256+
pendingPermissionAction = null
236257
return@registerForActivityResult
237258
}
238259
Toast.makeText(
239260
this,
240261
getString(R.string.request_permission_failed),
241262
Toast.LENGTH_SHORT
242263
).show()
264+
pendingPermissionAction = null
243265
}
244266
}
245267

@@ -441,9 +463,7 @@ class MainActivity : AppCompatActivity() {
441463
}
442464
// pick image button
443465
launchView.ivSelectedPhotoTips.setOnClickListener {
444-
checkReadingPermission(requestPermissionLauncher) {
445-
performFileSearch(REQ_CODE_PICK_IMAGE)
446-
}
466+
performFileSearch(REQ_CODE_PICK_IMAGE)
447467
}
448468
// setting bg
449469
launchView.ivPhoto.apply {
@@ -595,9 +615,7 @@ class MainActivity : AppCompatActivity() {
595615
TextContentDisplayFragment.replaceShow(this, launchView.fcFunctionDetail.id)
596616
}
597617
FuncTitleModel.FuncType.Icon -> {
598-
checkReadingPermission(requestPermissionLauncher) {
599-
performFileSearch(REQ_PICK_ICON)
600-
}
618+
performFileSearch(REQ_PICK_ICON)
601619
}
602620
FuncTitleModel.FuncType.Color -> {
603621
ColorFragment.replaceShow(this, launchView.fcFunctionDetail.id)
@@ -664,9 +682,7 @@ class MainActivity : AppCompatActivity() {
664682
}
665683

666684
R.id.action_pick -> {
667-
checkReadingPermission(requestPermissionLauncher) {
668-
performFileSearch(REQ_CODE_PICK_IMAGE)
669-
}
685+
performFileSearch(REQ_CODE_PICK_IMAGE)
670686
true
671687
}
672688

@@ -683,33 +699,44 @@ class MainActivity : AppCompatActivity() {
683699
* Fires an intent to spin up the "file chooser" UI and select an image.
684700
*/
685701
private fun performFileSearch(requestCode: Int) {
686-
if (requestCode == REQ_PICK_ICON) {
687-
val mime = "image/*"
688-
val result = kotlin.runCatching {
689-
when (requestCode) {
690-
REQ_PICK_ICON -> {
691-
pickIconLauncher.launch(mime)
692-
}
693-
}
694-
}
702+
val request = PickVisualMediaRequest.Builder()
703+
.setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly)
704+
.build()
695705

696-
if (result.isFailure) {
697-
Toast.makeText(
698-
this,
699-
getString(R.string.tips_not_app_can_open_images),
700-
Toast.LENGTH_LONG
701-
).show()
702-
Log.i("performFileSearch", result.exceptionOrNull()?.message ?: "No msg provided")
706+
if (isSystemPhotoPickerAvailable) {
707+
launchView.logoView.stop()
708+
when (requestCode) {
709+
REQ_PICK_ICON -> pickIconPhotoPickerLauncher.launch(request)
710+
else -> pickMultiplePhotoPickerLauncher.launch(request)
703711
}
704-
} else {
705-
GalleryFragment().apply {
712+
return
713+
}
714+
715+
val launchLegacyPicker = {
716+
if (requestCode == REQ_PICK_ICON) {
706717
launchView.logoView.stop()
707-
doOnDismiss {
708-
launchView.logoView.start()
709-
}
710-
show(supportFragmentManager, "GalleryFragment")
718+
pickIconLegacyLauncher.launch("image/*")
719+
} else {
720+
openLegacyGallery()
711721
}
712722
}
723+
724+
pendingPermissionAction = launchLegacyPicker
725+
checkReadingPermission(requestPermissionLauncher, grant = {
726+
val action = pendingPermissionAction
727+
pendingPermissionAction = null
728+
action?.invoke()
729+
})
730+
}
731+
732+
private fun openLegacyGallery() {
733+
GalleryFragment().apply {
734+
launchView.logoView.stop()
735+
doOnDismiss {
736+
launchView.logoView.start()
737+
}
738+
show(supportFragmentManager, "GalleryFragment")
739+
}
713740
}
714741

715742
private fun dealWithImage(uri: List<Uri>) {
@@ -724,10 +751,11 @@ class MainActivity : AppCompatActivity() {
724751
}
725752
}
726753

727-
private fun handleActivityResult(requestCode: Int, list: List<Uri?>?) {
728-
val finalList = list?.filterNotNull()?.filter {
754+
private fun handlePickedMedia(requestCode: Int, list: List<Uri>) {
755+
launchView.logoView.start()
756+
val finalList = list.filter {
729757
FileUtils.isImage(this.contentResolver, it)
730-
} ?: emptyList()
758+
}
731759
if (finalList.isEmpty()) {
732760
Toast.makeText(
733761
this,
@@ -823,7 +851,12 @@ class MainActivity : AppCompatActivity() {
823851
}
824852

825853
fun requestPermission(block: () -> Unit) {
826-
checkWritingPermission(requestPermissionLauncher, grant = block)
854+
pendingPermissionAction = block
855+
checkWritingPermission(requestPermissionLauncher, grant = {
856+
val action = pendingPermissionAction
857+
pendingPermissionAction = null
858+
action?.invoke()
859+
})
827860
}
828861

829862
companion object {

0 commit comments

Comments
 (0)