Skip to content

Commit b6f3f58

Browse files
committed
feat: multi select batch actions
1 parent 0db9378 commit b6f3f58

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1998
-612
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import li.songe.gkd.service.updateLauncherAppId
4747
import li.songe.gkd.ui.component.BuildDialog
4848
import li.songe.gkd.ui.component.ShareDataDialog
4949
import li.songe.gkd.ui.component.SubsSheet
50+
import li.songe.gkd.ui.component.UrlDetailDialog
5051
import li.songe.gkd.ui.theme.AppTheme
5152
import li.songe.gkd.util.EditGithubCookieDlg
5253
import li.songe.gkd.util.LocalMainViewModel
@@ -114,6 +115,7 @@ class MainActivity : ComponentActivity() {
114115
ShareDataDialog(mainVm, mainVm.showShareDataIdsFlow)
115116
mainVm.inputSubsLinkOption.ContentDialog()
116117
mainVm.ruleGroupState.Render()
118+
UrlDetailDialog(mainVm.urlFlow)
117119
}
118120
}
119121
}

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

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

3+
import android.webkit.URLUtil
34
import androidx.lifecycle.ViewModel
45
import androidx.lifecycle.viewModelScope
56
import com.blankj.utilcode.util.LogUtils
@@ -27,6 +28,7 @@ import li.songe.gkd.util.clearCache
2728
import li.songe.gkd.util.client
2829
import li.songe.gkd.util.launchTry
2930
import li.songe.gkd.util.map
31+
import li.songe.gkd.util.openUri
3032
import li.songe.gkd.util.storeFlow
3133
import li.songe.gkd.util.subsItemsFlow
3234
import li.songe.gkd.util.toast
@@ -118,6 +120,15 @@ class MainViewModel : ViewModel() {
118120

119121
val ruleGroupState = RuleGroupState(this)
120122

123+
val urlFlow = MutableStateFlow<String?>(null)
124+
fun openUrl(url: String) {
125+
if (URLUtil.isNetworkUrl(url)) {
126+
urlFlow.value = url
127+
} else {
128+
openUri(url)
129+
}
130+
}
131+
121132
init {
122133
viewModelScope.launchTry(Dispatchers.IO) {
123134
val subsItems = DbSet.subsItemDao.queryAll()

app/src/main/kotlin/li/songe/gkd/data/RawSubscription.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,13 @@ data class RawSubscription(
812812
jsonElement.jsonObject,
813813
index
814814
)
815-
} ?: emptyList()).distinctBy { it.id },
815+
} ?: emptyList()).distinctBy { it.id }.run {
816+
if (any { it.groups.isEmpty() }) {
817+
filterNot { it.groups.isEmpty() }
818+
} else {
819+
this
820+
}
821+
},
816822
categories = (rootJson["categories"]?.jsonArray?.mapIndexed { index, jsonElement ->
817823
RawCategory(
818824
key = getInt(jsonElement.jsonObject, "key")

app/src/main/kotlin/li/songe/gkd/data/ResolvedGroup.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ sealed class ResolvedGroup(
77
val config: SubsConfig?,
88
) {
99
val excludeData = ExcludeData.parse(config?.exclude)
10+
11+
abstract val appId: String?
1012
}
1113

1214
class ResolvedAppGroup(
@@ -18,11 +20,17 @@ class ResolvedAppGroup(
1820
val enable: Boolean,
1921
val category: RawSubscription.RawCategory?,
2022
val categoryConfig: CategoryConfig?,
21-
) : ResolvedGroup(group, subscription, subsItem, config)
23+
) : ResolvedGroup(group, subscription, subsItem, config) {
24+
override val appId: String?
25+
get() = app.id
26+
}
2227

2328
class ResolvedGlobalGroup(
2429
override val group: RawSubscription.RawGlobalGroup,
2530
subscription: RawSubscription,
2631
subsItem: SubsItem,
2732
config: SubsConfig?,
28-
) : ResolvedGroup(group, subscription, subsItem, config)
33+
) : ResolvedGroup(group, subscription, subsItem, config) {
34+
override val appId: String?
35+
get() = null
36+
}

app/src/main/kotlin/li/songe/gkd/data/SubsConfig.kt

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,27 @@ import kotlinx.parcelize.Parcelize
1616
import kotlinx.serialization.Serializable
1717

1818

19+
private var lastId = 0L
20+
21+
@Synchronized
22+
private fun buildUniqueTimeMillisId(): Long {
23+
while (true) {
24+
val id = System.currentTimeMillis()
25+
if (id != lastId) {
26+
lastId = id
27+
return id
28+
}
29+
Thread.sleep(1)
30+
}
31+
}
32+
1933
@Serializable
2034
@Entity(
2135
tableName = "subs_config",
2236
)
2337
@Parcelize
2438
data class SubsConfig(
25-
@PrimaryKey @ColumnInfo(name = "id") val id: Long = System.currentTimeMillis(),
39+
@PrimaryKey @ColumnInfo(name = "id") val id: Long = buildUniqueTimeMillisId(),
2640
@ColumnInfo(name = "type") val type: Int,
2741
@ColumnInfo(name = "enable") val enable: Boolean? = null,
2842
@ColumnInfo(name = "subs_item_id") val subsItemId: Long,
@@ -53,6 +67,12 @@ data class SubsConfig(
5367
@Delete
5468
suspend fun delete(vararg users: SubsConfig): Int
5569

70+
@Transaction
71+
suspend fun insertAndDelete(newList: List<SubsConfig>, deleteList: List<SubsConfig>){
72+
insert(*newList.toTypedArray())
73+
delete(*deleteList.toTypedArray())
74+
}
75+
5676
@Query("DELETE FROM subs_config WHERE subs_item_id=:subsItemId")
5777
suspend fun delete(subsItemId: Long): Int
5878

@@ -65,9 +85,20 @@ data class SubsConfig(
6585
@Query("DELETE FROM subs_config WHERE type=${AppGroupType} AND subs_item_id=:subsItemId AND app_id=:appId AND group_key=:groupKey")
6686
suspend fun deleteAppGroupConfig(subsItemId: Long, appId: String, groupKey: Int): Int
6787

88+
89+
@Query("DELETE FROM subs_config WHERE type=${AppGroupType} AND subs_item_id=:subsItemId AND app_id=:appId AND group_key IN (:keyList)")
90+
suspend fun batchDeleteAppGroupConfig(
91+
subsItemId: Long,
92+
appId: String,
93+
keyList: List<Int>
94+
): Int
95+
6896
@Query("DELETE FROM subs_config WHERE type=${GlobalGroupType} AND subs_item_id=:subsItemId AND group_key=:groupKey")
6997
suspend fun deleteGlobalGroupConfig(subsItemId: Long, groupKey: Int): Int
7098

99+
@Query("DELETE FROM subs_config WHERE type=${GlobalGroupType} AND subs_item_id=:subsItemId AND group_key IN (:keyList)")
100+
suspend fun batchDeleteGlobalGroupConfig(subsItemId: Long, keyList: List<Int>): Int
101+
71102
@Query("SELECT * FROM subs_config WHERE subs_item_id IN (SELECT si.id FROM subs_item si WHERE si.enable = 1)")
72103
fun queryUsedList(): Flow<List<SubsConfig>>
73104

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ fun AboutPage() {
243243
Column(
244244
modifier = Modifier
245245
.clickable {
246-
openUri(REPOSITORY_URL)
246+
mainVm.openUrl(REPOSITORY_URL)
247247
}
248248
.fillMaxWidth()
249249
.itemPadding()
@@ -263,7 +263,7 @@ fun AboutPage() {
263263
Column(
264264
modifier = Modifier
265265
.clickable {
266-
openUri(ISSUES_URL)
266+
mainVm.openUrl(ISSUES_URL)
267267
}
268268
.fillMaxWidth()
269269
.itemPadding()
@@ -378,7 +378,7 @@ private fun AnimatedLogoIcon(
378378
val enableDarkTheme by mainVm.enableDarkThemeFlow.collectAsState()
379379
val darkTheme = enableDarkTheme ?: isSystemInDarkTheme()
380380
var atEnd by remember { mutableStateOf(false) }
381-
val animation = AnimatedImageVector.animatedVectorResource(id = SafeR.ic_logo_animation)
381+
val animation = AnimatedImageVector.animatedVectorResource(id = SafeR.ic_anim_logo)
382382
val painter = rememberAnimatedVectorPainter(
383383
animation,
384384
atEnd

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

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ import li.songe.gkd.ui.style.scaffoldPadding
7373
import li.songe.gkd.util.LocalMainViewModel
7474
import li.songe.gkd.util.LocalNavController
7575
import li.songe.gkd.util.ProfileTransitions
76-
import li.songe.gkd.util.appInfoCacheFlow
7776
import li.songe.gkd.util.launchAsFn
7877
import li.songe.gkd.util.map
7978
import li.songe.gkd.util.subsIdToRawFlow
@@ -152,7 +151,6 @@ fun ActionLogPage(
152151
Icon(
153152
imageVector = Icons.Outlined.Delete,
154153
contentDescription = null,
155-
tint = MaterialTheme.colorScheme.error
156154
)
157155
}
158156
}
@@ -331,9 +329,6 @@ private fun ActionLogDialog(
331329
) {
332330
val navController = LocalNavController.current
333331
val scope = rememberCoroutineScope()
334-
val appInfo = remember(actionLog.appId) {
335-
appInfoCacheFlow.map(scope) { it[actionLog.appId] }
336-
}.collectAsState().value
337332
val subsConfig = remember(actionLog) {
338333
(if (actionLog.groupType == SubsConfig.AppGroupType) {
339334
DbSet.subsConfigDao.queryAppGroupTypeConfig(
@@ -386,11 +381,10 @@ private fun ActionLogDialog(
386381
}.collectAsState().value
387382
val group = subs?.globalGroups?.find { g -> g.key == actionLog.groupKey }
388383
val appChecked = if (group != null) {
389-
getChecked(
384+
getGlobalGroupChecked(
390385
oldExclude,
391386
group,
392387
actionLog.appId,
393-
appInfo
394388
)
395389
} else {
396390
null

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ fun ActivityLogPage() {
100100
Icon(
101101
imageVector = Icons.Outlined.Delete,
102102
contentDescription = null,
103-
tint = MaterialTheme.colorScheme.error
104103
)
105104
}
106105
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ fun AdvancedPage() {
246246
color = MaterialTheme.colorScheme.primary,
247247
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
248248
modifier = Modifier.clickable(onClick = throttle {
249-
openUri(localUrl)
249+
mainVm.openUrl(localUrl)
250250
}),
251251
)
252252
Spacer(modifier = Modifier.width(2.dp))
@@ -259,7 +259,7 @@ fun AdvancedPage() {
259259
color = MaterialTheme.colorScheme.primary,
260260
style = LocalTextStyle.current.copy(textDecoration = TextDecoration.Underline),
261261
modifier = Modifier.clickable(onClick = throttle {
262-
openUri(lanUrl)
262+
mainVm.openUrl(lanUrl)
263263
})
264264
)
265265
}
@@ -536,7 +536,7 @@ private fun ShizukuTitleCard() {
536536
Row(
537537
modifier = Modifier
538538
.fillMaxWidth()
539-
.titleItemPadding(),
539+
.titleItemPadding(showTop = false),
540540
horizontalArrangement = Arrangement.SpaceBetween,
541541
) {
542542
Text(

0 commit comments

Comments
 (0)