Skip to content

Commit 1c3cadf

Browse files
committed
perf: TooltipIconButtonBox
1 parent 4633393 commit 1c3cadf

17 files changed

+274
-155
lines changed

app/src/main/kotlin/li/songe/gkd/App.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ import android.content.Intent
1111
import android.content.pm.ApplicationInfo
1212
import android.content.pm.PackageInfo
1313
import android.content.pm.PackageManager
14+
import android.database.ContentObserver
15+
import android.net.Uri
1416
import android.os.PowerManager
1517
import android.provider.Settings
1618
import android.view.WindowManager
19+
import android.view.accessibility.AccessibilityManager
1720
import android.view.inputmethod.InputMethodManager
1821
import com.blankj.utilcode.util.LogUtils
1922
import com.blankj.utilcode.util.Utils
@@ -78,6 +81,10 @@ data class AppMeta(
7881

7982
val META by lazy { AppMeta() }
8083

84+
fun contentObserver(listener: () -> Unit) = object : ContentObserver(null) {
85+
override fun onChange(selfChange: Boolean) = listener()
86+
}
87+
8188
class App : Application() {
8289
companion object {
8390
const val START_WAIT_TIME = 3000L
@@ -94,6 +101,17 @@ class App : Application() {
94101
}
95102
}
96103

104+
fun registerObserver(
105+
uri: Uri,
106+
observer: ContentObserver
107+
) {
108+
contentResolver.registerContentObserver(uri, false, observer)
109+
}
110+
111+
fun unregisterObserver(observer: ContentObserver) {
112+
contentResolver.unregisterContentObserver(observer)
113+
}
114+
97115
fun getSecureString(name: String): String? = Settings.Secure.getString(contentResolver, name)
98116
fun putSecureString(name: String, value: String?): Boolean {
99117
return Settings.Secure.putString(contentResolver, name, value)
@@ -152,6 +170,7 @@ class App : Application() {
152170
val keyguardManager by lazy { app.getSystemService(KEYGUARD_SERVICE) as KeyguardManager }
153171
val clipboardManager by lazy { app.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager }
154172
val powerManager by lazy { getSystemService(POWER_SERVICE) as PowerManager }
173+
val a11yManager by lazy { getSystemService(ACCESSIBILITY_SERVICE) as AccessibilityManager }
155174

156175
override fun onCreate() {
157176
super.onCreate()

app/src/main/kotlin/li/songe/gkd/a11y/A11yExt.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import android.accessibilityservice.AccessibilityService
44
import android.accessibilityservice.AccessibilityService.ScreenshotResult
55
import android.accessibilityservice.AccessibilityService.TakeScreenshotCallback
66
import android.content.ComponentName
7-
import android.database.ContentObserver
87
import android.graphics.Bitmap
98
import android.provider.Settings
109
import android.view.Display
@@ -13,6 +12,7 @@ import android.view.accessibility.AccessibilityNodeInfo
1312
import kotlinx.coroutines.flow.MutableStateFlow
1413
import kotlinx.coroutines.flow.StateFlow
1514
import li.songe.gkd.app
15+
import li.songe.gkd.contentObserver
1616
import li.songe.gkd.service.A11yService
1717
import li.songe.gkd.util.AndroidTarget
1818
import li.songe.gkd.util.OnSimpleLife
@@ -25,18 +25,15 @@ import kotlin.coroutines.suspendCoroutine
2525
context(context: OnSimpleLife)
2626
fun useEnabledA11yServicesFlow(): StateFlow<Set<ComponentName>> {
2727
val stateFlow = MutableStateFlow(app.getSecureA11yServices())
28-
val contextObserver = object : ContentObserver(null) {
29-
override fun onChange(selfChange: Boolean) {
30-
stateFlow.value = app.getSecureA11yServices()
31-
}
28+
val contextObserver = contentObserver {
29+
stateFlow.value = app.getSecureA11yServices()
3230
}
33-
app.contentResolver.registerContentObserver(
31+
app.registerObserver(
3432
Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES),
35-
false,
3633
contextObserver
3734
)
3835
context.onDestroyed {
39-
app.contentResolver.unregisterContentObserver(contextObserver)
36+
app.unregisterObserver(contextObserver)
4037
}
4138
return stateFlow
4239
}

app/src/main/kotlin/li/songe/gkd/ui/AdvancedPage.kt

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ import li.songe.gkd.shizuku.shizukuContextFlow
6868
import li.songe.gkd.shizuku.updateBinderMutex
6969
import li.songe.gkd.store.storeFlow
7070
import li.songe.gkd.ui.component.AuthCard
71-
import li.songe.gkd.ui.component.CustomIconButton
7271
import li.songe.gkd.ui.component.CustomOutlinedTextField
72+
import li.songe.gkd.ui.component.PerfCustomIconButton
7373
import li.songe.gkd.ui.component.PerfIcon
7474
import li.songe.gkd.ui.component.PerfIconButton
7575
import li.songe.gkd.ui.component.PerfSwitch
@@ -523,19 +523,16 @@ fun AdvancedPage() {
523523
subtitle = "截屏时保存快照",
524524
checked = store.captureScreenshot,
525525
suffixIcon = {
526-
CustomIconButton(
526+
PerfCustomIconButton(
527527
size = 32.dp,
528+
iconSize = 20.dp,
528529
onClickLabel = "打开配置截屏快照弹窗",
529530
onClick = throttle {
530531
showCaptureScreenshotDlg = true
531532
},
532-
) {
533-
PerfIcon(
534-
modifier = Modifier.size(20.dp),
535-
id = SafeR.ic_page_info,
536-
contentDescription = "截屏快照设置",
537-
)
538-
}
533+
id = SafeR.ic_page_info,
534+
contentDescription = "截屏快照设置",
535+
)
539536
},
540537
onCheckedChange = {
541538
storeFlow.value = store.copy(

app/src/main/kotlin/li/songe/gkd/ui/BlockA11yAppListPage.kt

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import li.songe.gkd.service.fixRestartService
4949
import li.songe.gkd.store.blockA11yAppListFlow
5050
import li.songe.gkd.store.storeFlow
5151
import li.songe.gkd.ui.component.AnimatedBooleanContent
52-
import li.songe.gkd.ui.component.AnimatedIcon
52+
import li.songe.gkd.ui.component.AnimatedIconButton
5353
import li.songe.gkd.ui.component.AnimationFloatingActionButton
5454
import li.songe.gkd.ui.component.AppBarTextField
5555
import li.songe.gkd.ui.component.AppIcon
@@ -199,22 +199,21 @@ fun BlockA11yAppListPage() {
199199
var expanded by remember { mutableStateOf(false) }
200200
AnimatedVisibility(!store.blockA11yAppListFollowMatch) {
201201
Row {
202-
IconButton(onClick = throttle {
203-
if (showSearchBar) {
204-
if (vm.searchStrFlow.value.isEmpty()) {
205-
showSearchBar = false
202+
AnimatedIconButton(
203+
onClick = throttle {
204+
if (showSearchBar) {
205+
if (vm.searchStrFlow.value.isEmpty()) {
206+
showSearchBar = false
207+
} else {
208+
vm.searchStrFlow.value = ""
209+
}
206210
} else {
207-
vm.searchStrFlow.value = ""
211+
showSearchBar = true
208212
}
209-
} else {
210-
showSearchBar = true
211-
}
212-
}) {
213-
AnimatedIcon(
214-
id = SafeR.ic_anim_search_close,
215-
atEnd = showSearchBar,
216-
)
217-
}
213+
},
214+
id = SafeR.ic_anim_search_close,
215+
atEnd = showSearchBar,
216+
)
218217
PerfIconButton(imageVector = PerfIcon.Sort, onClick = {
219218
expanded = true
220219
})

app/src/main/kotlin/li/songe/gkd/ui/SubsAppListPage.kt

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import androidx.compose.material3.Checkbox
1212
import androidx.compose.material3.DropdownMenu
1313
import androidx.compose.material3.DropdownMenuItem
1414
import androidx.compose.material3.FloatingActionButton
15-
import androidx.compose.material3.IconButton
1615
import androidx.compose.material3.MaterialTheme
1716
import androidx.compose.material3.RadioButton
1817
import androidx.compose.material3.Scaffold
@@ -39,7 +38,7 @@ import li.songe.gkd.MainActivity
3938
import li.songe.gkd.data.AppConfig
4039
import li.songe.gkd.db.DbSet
4140
import li.songe.gkd.store.storeFlow
42-
import li.songe.gkd.ui.component.AnimatedIcon
41+
import li.songe.gkd.ui.component.AnimatedIconButton
4342
import li.songe.gkd.ui.component.AppBarTextField
4443
import li.songe.gkd.ui.component.EmptyText
4544
import li.songe.gkd.ui.component.PerfIcon
@@ -124,22 +123,21 @@ fun SubsAppListPage(
124123
)
125124
}
126125
}, actions = {
127-
IconButton(onClick = {
128-
if (showSearchBar) {
129-
if (vm.searchStrFlow.value.isEmpty()) {
130-
showSearchBar = false
126+
AnimatedIconButton(
127+
onClick = {
128+
if (showSearchBar) {
129+
if (vm.searchStrFlow.value.isEmpty()) {
130+
showSearchBar = false
131+
} else {
132+
vm.searchStrFlow.value = ""
133+
}
131134
} else {
132-
vm.searchStrFlow.value = ""
135+
showSearchBar = true
133136
}
134-
} else {
135-
showSearchBar = true
136-
}
137-
}) {
138-
AnimatedIcon(
139-
id = SafeR.ic_anim_search_close,
140-
atEnd = showSearchBar,
141-
)
142-
}
137+
},
138+
id = SafeR.ic_anim_search_close,
139+
atEnd = showSearchBar,
140+
)
143141
PerfIconButton(
144142
imageVector = PerfIcon.Sort,
145143
onClick = {

app/src/main/kotlin/li/songe/gkd/ui/SubsGlobalGroupExcludePage.kt

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import li.songe.gkd.data.SubsConfig
4444
import li.songe.gkd.db.DbSet
4545
import li.songe.gkd.store.blockMatchAppListFlow
4646
import li.songe.gkd.ui.component.AnimatedBooleanContent
47-
import li.songe.gkd.ui.component.AnimatedIcon
47+
import li.songe.gkd.ui.component.AnimatedIconButton
4848
import li.songe.gkd.ui.component.AnimationFloatingActionButton
4949
import li.songe.gkd.ui.component.AppBarTextField
5050
import li.songe.gkd.ui.component.AppIcon
@@ -193,22 +193,21 @@ fun SubsGlobalGroupExcludePage(subsItemId: Long, groupKey: Int) {
193193
},
194194
contentFalse = {
195195
Row {
196-
IconButton(onClick = {
197-
if (showSearchBar) {
198-
if (searchStr.isEmpty()) {
199-
showSearchBar = false
196+
AnimatedIconButton(
197+
onClick = {
198+
if (showSearchBar) {
199+
if (searchStr.isEmpty()) {
200+
showSearchBar = false
201+
} else {
202+
searchStr = ""
203+
}
200204
} else {
201-
searchStr = ""
205+
showSearchBar = true
202206
}
203-
} else {
204-
showSearchBar = true
205-
}
206-
}) {
207-
AnimatedIcon(
208-
id = SafeR.ic_anim_search_close,
209-
atEnd = showSearchBar,
210-
)
211-
}
207+
},
208+
id = SafeR.ic_anim_search_close,
209+
atEnd = showSearchBar,
210+
)
212211
var expanded by remember { mutableStateOf(false) }
213212
PerfIconButton(
214213
imageVector = PerfIcon.Sort,

app/src/main/kotlin/li/songe/gkd/ui/component/AnimatedIcon.kt

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,54 @@ import androidx.compose.animation.graphics.res.animatedVectorResource
55
import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
66
import androidx.compose.animation.graphics.vector.AnimatedImageVector
77
import androidx.compose.material3.Icon
8+
import androidx.compose.material3.IconButton
89
import androidx.compose.material3.LocalContentColor
910
import androidx.compose.runtime.Composable
1011
import androidx.compose.ui.Modifier
1112
import androidx.compose.ui.graphics.Color
1213
import li.songe.gkd.util.SafeR
1314

1415
@Composable
15-
fun AnimatedIcon(
16-
modifier: Modifier = Modifier,
16+
private fun AnimatedIcon(
17+
modifier: Modifier,
1718
@DrawableRes id: Int,
18-
atEnd: Boolean = false,
19-
tint: Color = LocalContentColor.current,
20-
contentDescription: String? = getIconDesc(id, atEnd),
19+
atEnd: Boolean,
20+
tint: Color,
21+
contentDescription: String?,
2122
) {
2223
val animation = AnimatedImageVector.animatedVectorResource(id)
2324
val painter = rememberAnimatedVectorPainter(
2425
animation,
2526
atEnd,
2627
)
27-
PerfTooltipBox(
28-
tooltipText = contentDescription,
28+
Icon(
29+
modifier = modifier,
30+
painter = painter,
31+
contentDescription = contentDescription,
32+
tint = tint,
33+
)
34+
}
35+
36+
@Composable
37+
fun AnimatedIconButton(
38+
onClick: () -> Unit,
39+
@DrawableRes id: Int,
40+
modifier: Modifier = Modifier,
41+
atEnd: Boolean = false,
42+
tint: Color = LocalContentColor.current,
43+
contentDescription: String? = getIconDesc(id, atEnd),
44+
) = TooltipIconButtonBox(
45+
contentDescription = contentDescription,
46+
) {
47+
IconButton(
48+
onClick = onClick,
2949
) {
30-
Icon(
50+
AnimatedIcon(
51+
id = id,
52+
atEnd = atEnd,
3153
modifier = modifier,
32-
painter = painter,
33-
contentDescription = contentDescription,
3454
tint = tint,
55+
contentDescription = contentDescription,
3556
)
3657
}
3758
}

app/src/main/kotlin/li/songe/gkd/ui/component/AnimationFloatingActionButton.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fun AnimationFloatingActionButton(
6464
}
6565
}
6666
if (innerVisible) {
67-
PerfTooltipBox(contentDescription) {
67+
TooltipIconButtonBox(contentDescription) {
6868
FloatingActionButton(
6969
modifier = modifier
7070
.graphicsLayer(

app/src/main/kotlin/li/songe/gkd/ui/component/CustomIconButton.kt

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package li.songe.gkd.ui.component
22

3+
import androidx.annotation.DrawableRes
34
import androidx.compose.foundation.background
45
import androidx.compose.foundation.clickable
56
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -20,7 +21,7 @@ import androidx.compose.ui.unit.Dp
2021
import androidx.compose.ui.unit.dp
2122

2223
@Composable
23-
fun CustomIconButton(
24+
private fun CustomIconButton(
2425
onClick: () -> Unit,
2526
modifier: Modifier = Modifier,
2627
onClickLabel: String? = null,
@@ -50,3 +51,27 @@ fun CustomIconButton(
5051
CompositionLocalProvider(LocalContentColor provides contentColor, content = content)
5152
}
5253
}
54+
55+
@Composable
56+
fun PerfCustomIconButton(
57+
onClick: () -> Unit,
58+
size: Dp,
59+
iconSize: Dp,
60+
onClickLabel: String? = null,
61+
@DrawableRes id: Int,
62+
contentDescription: String? = null,
63+
) = TooltipIconButtonBox(
64+
contentDescription = contentDescription,
65+
) {
66+
CustomIconButton(
67+
size = size,
68+
onClickLabel = onClickLabel,
69+
onClick = onClick,
70+
) {
71+
PerfIcon(
72+
modifier = Modifier.size(iconSize),
73+
id = id,
74+
contentDescription = contentDescription,
75+
)
76+
}
77+
}

0 commit comments

Comments
 (0)