From 74daa464c617735bad32f0762a5e4a7ceaef244e Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 23 Jul 2024 09:58:54 +0800 Subject: [PATCH 001/144] Update plugin com.gradle.develocity to v3.17.6 (#2217) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 0f44f249fbb..f0ac4ed0e4a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,7 +13,7 @@ pluginManagement { // https://docs.gradle.com/enterprise/gradle-plugin/ plugins { - id("com.gradle.develocity") version "3.17.5" + id("com.gradle.develocity") version "3.17.6" } develocity { From 60fd3df00d4749fd6394b86049788f50427822eb Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Wed, 24 Jul 2024 18:18:57 +0300 Subject: [PATCH 002/144] +35 links (#2220) --- app/assets/appfilter.xml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 4cea8ff60e6..a3b718a7f95 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -792,6 +792,7 @@ + @@ -1825,6 +1826,7 @@ + @@ -2583,6 +2585,8 @@ + + @@ -3065,6 +3069,7 @@ + @@ -3429,6 +3434,7 @@ + @@ -3731,6 +3737,7 @@ + @@ -4027,6 +4034,7 @@ + @@ -4245,6 +4253,7 @@ + @@ -4818,6 +4827,7 @@ + @@ -5522,6 +5532,7 @@ + @@ -6511,6 +6522,7 @@ + @@ -6700,6 +6712,7 @@ + @@ -6756,6 +6769,7 @@ + @@ -7120,6 +7134,7 @@ + @@ -7664,6 +7679,7 @@ + @@ -7824,6 +7840,7 @@ + @@ -8467,6 +8484,7 @@ + @@ -8488,6 +8506,7 @@ + @@ -9363,6 +9382,7 @@ + @@ -9420,6 +9440,7 @@ + @@ -9472,6 +9493,7 @@ + @@ -9723,6 +9745,8 @@ + + @@ -10363,6 +10387,7 @@ + @@ -10961,6 +10986,7 @@ + @@ -11049,6 +11075,7 @@ + @@ -11255,6 +11282,7 @@ + @@ -11442,6 +11470,7 @@ + @@ -11502,6 +11531,7 @@ + @@ -11585,6 +11615,7 @@ + @@ -11655,6 +11686,7 @@ + @@ -12100,6 +12132,7 @@ + @@ -12184,6 +12217,7 @@ + @@ -12224,6 +12258,7 @@ + From ee7a51ec2a26338908b95357f57d17d6ee4055fc Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:52:17 +0800 Subject: [PATCH 003/144] Update dependency androidx.navigation:navigation-compose to v2.8.0-beta06 (#2223) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 58f3a8be7ef..25cbc7ab0d6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -144,7 +144,7 @@ dependencies { implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0-beta04") implementation("androidx.compose.material3:material3-window-size-class") - implementation("androidx.navigation:navigation-compose:2.8.0-beta05") + implementation("androidx.navigation:navigation-compose:2.8.0-beta06") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") From 9191ab0ce7167f8156fd18c7e6624ff84ceced9b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 25 Jul 2024 07:52:40 +0800 Subject: [PATCH 004/144] Update dependency androidx.activity:activity-compose to v1.9.1 (#2221) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 25cbc7ab0d6..c3ef0acb779 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -134,7 +134,7 @@ licensee { dependencies { implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-splashscreen:1.0.1") - implementation("androidx.activity:activity-compose:1.9.0") + implementation("androidx.activity:activity-compose:1.9.1") implementation(platform("androidx.compose:compose-bom:2024.06.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") From 2e35a290c6f708cd8ec92eb93a928d9fc3e7166f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Jul 2024 23:55:18 +0000 Subject: [PATCH 005/144] Update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.4 (#2222) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c3ef0acb779..064d655adc3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -145,7 +145,7 @@ dependencies { implementation("androidx.compose.material3:material3:1.3.0-beta04") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0-beta06") - implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.3") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") From b3cc85a473138d6e24ebec93f8a10f47fbe5b5f7 Mon Sep 17 00:00:00 2001 From: thismoon <107642606+thismoon@users.noreply.github.com> Date: Thu, 25 Jul 2024 20:30:10 +0100 Subject: [PATCH 006/144] update 1 icon (#2219) * update 1 icon * simplify aves icon * fix aves size * Moved the icon to the visual center --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- svgs/aves_gallery.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/svgs/aves_gallery.svg b/svgs/aves_gallery.svg index 4f945f5ac45..32bfe7964e4 100644 --- a/svgs/aves_gallery.svg +++ b/svgs/aves_gallery.svg @@ -1 +1 @@ - \ No newline at end of file + From 49fd86daf621746f5bd7cd23f6c04f8fd1199538 Mon Sep 17 00:00:00 2001 From: GGORG Date: Thu, 25 Jul 2024 21:42:56 +0200 Subject: [PATCH 007/144] +4 icons (#2218) * +4.5 icons * Test PWA in another form * Added blik; tweaked tuszama, czynaczas, port_authority; removed serialusb * tweaked czynaczas and port_authority * Artifacts have been removed * Line spacing and style have been improved --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 4 +++ svgs/blik.svg | 46 +++++++++++++++++++++++++++++ svgs/czynaczas.svg | 1 + svgs/port_authority.svg | 1 + svgs/tuszama.svg | 62 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+) create mode 100644 svgs/blik.svg create mode 100644 svgs/czynaczas.svg create mode 100644 svgs/port_authority.svg create mode 100644 svgs/tuszama.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index a3b718a7f95..13cfd209ca9 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -1099,6 +1099,7 @@ + @@ -2338,6 +2339,7 @@ + @@ -7723,6 +7725,7 @@ + @@ -10687,6 +10690,7 @@ + diff --git a/svgs/blik.svg b/svgs/blik.svg new file mode 100644 index 00000000000..c5654a73bfa --- /dev/null +++ b/svgs/blik.svg @@ -0,0 +1,46 @@ + + + + diff --git a/svgs/czynaczas.svg b/svgs/czynaczas.svg new file mode 100644 index 00000000000..31f42638634 --- /dev/null +++ b/svgs/czynaczas.svg @@ -0,0 +1 @@ + diff --git a/svgs/port_authority.svg b/svgs/port_authority.svg new file mode 100644 index 00000000000..cc3862c8c59 --- /dev/null +++ b/svgs/port_authority.svg @@ -0,0 +1 @@ + diff --git a/svgs/tuszama.svg b/svgs/tuszama.svg new file mode 100644 index 00000000000..57f7be1f383 --- /dev/null +++ b/svgs/tuszama.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + From 9dbb68b4366ccc143c36aa303cff9c9843d003db Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 25 Jul 2024 23:26:06 +0300 Subject: [PATCH 008/144] Fixed the link to the visual balance section (#2226) --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ae30d671815..3b24acddbfe 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ Square icons must fit the `154×154px` content area size. Icons that mostly fit #### Color All shapes must have non-transparent black color `#000000`. #### Stroke widths -The stroke should be kept at `12px` in most cases. If an icon is too minimal or dense, you'll need other widths: `14px` for the most minimal, and `8px` for the densest. For fine details, you can use `6px`. For more clarification, please refer to [the visual balance section](https://github.com/x9136/lawnicons/blob/addate/CONTRIBUTING.md#maintaining-visual-balance) down below. +The stroke should be kept at `12px` in most cases. If an icon is too minimal or dense, you'll need other widths: `14px` for the most minimal, and `8px` for the densest. For fine details, you can use `6px`. For more clarification, please refer to [the visual balance section](https://github.com/LawnchairLauncher/lawnicons/blob/develop/CONTRIBUTING.md#maintaining-visual-balance) down below. #### End caps All shapes must have rounded caps and joins. #### Corner radius From 814a4e19f9ebf5e796cf4b5e1913f091374fdd4c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 26 Jul 2024 07:38:31 +0800 Subject: [PATCH 009/144] Update dependency androidx.compose.material3:material3 to v1.3.0-beta05 (#2225) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 064d655adc3..619a15f5915 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -142,7 +142,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") implementation("androidx.compose.material:material-icons-core-android:1.6.8") - implementation("androidx.compose.material3:material3:1.3.0-beta04") + implementation("androidx.compose.material3:material3:1.3.0-beta05") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0-beta06") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") From f5ce1a297211f706f151c2b9edc8436a673ee0cf Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 26 Jul 2024 21:53:52 +0800 Subject: [PATCH 010/144] Implement bottom navigation for smaller devices --- app/build.gradle.kts | 17 +- .../ui/components/home/HomeBottomBar.kt | 110 +++++++++ .../ui/components/home/HomeTopBar.kt | 143 ++++++++++++ .../ui/components/home/IconPreviewGrid.kt | 7 +- .../ui/components/home/IconRequestFAB.kt | 208 +++++++++++------- .../ui/components/home/search/SearchBar.kt | 16 +- .../lawnicons/ui/destination/Home.kt | 101 +++++---- app/src/main/res/values/strings.xml | 1 + build.gradle.kts | 3 +- 9 files changed, 471 insertions(+), 135 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 619a15f5915..92451330b7b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,6 +1,5 @@ import app.cash.licensee.LicenseeTask import com.android.build.gradle.internal.api.ApkVariantOutputImpl -import com.android.build.gradle.tasks.MergeResources import java.io.FileInputStream import java.util.Locale import java.util.Properties @@ -101,7 +100,7 @@ android { applicationVariants.all { outputs.all { (this as? ApkVariantOutputImpl)?.outputFileName = - "Lawnicons $versionName v${versionCode}_${buildType.name}.apk" + "Lawnicons $versionName v$versionCode ${buildType.name}.apk".replace(" ", ".") } } } @@ -122,9 +121,9 @@ androidComponents.onVariants { variant -> } // Process SVGs before every build. -tasks.withType().configureEach { - dependsOn(projects.svgProcessor.dependencyProject.tasks.named("run")) -} +// tasks.withType().configureEach { +// dependsOn(projects.svgProcessor.dependencyProject.tasks.named("run")) +// } licensee { allow("Apache-2.0") @@ -136,10 +135,10 @@ dependencies { implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.activity:activity-compose:1.9.1") implementation(platform("androidx.compose:compose-bom:2024.06.00")) - implementation("androidx.compose.ui:ui") - implementation("androidx.compose.ui:ui-tooling-preview") - implementation("androidx.compose.ui:ui-util") - debugImplementation("androidx.compose.ui:ui-tooling") + implementation("androidx.compose.ui:ui:1.6.6") + implementation("androidx.compose.ui:ui-tooling-preview:1.6.6") + implementation("androidx.compose.ui:ui-util:1.6.6") + debugImplementation("androidx.compose.ui:ui-tooling:1.6.6") implementation("androidx.compose.animation:animation") implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0-beta05") diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt new file mode 100644 index 00000000000..b425c041c55 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -0,0 +1,110 @@ +package app.lawnchair.lawnicons.ui.components.home + +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.layout.requiredSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Search +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.PlainTooltip +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.model.IconRequestModel +import app.lawnchair.lawnicons.ui.util.Constants + +@Composable +fun HomeBottomBar( + context: Context, + iconRequestModel: IconRequestModel?, + snackbarHostState: SnackbarHostState, + onNavigate: () -> Unit, + onExpandSearch: () -> Unit, + modifier: Modifier = Modifier, +) { + BottomAppBar( + actions = { + SimpleTooltipBox( + label = stringResource(id = R.string.github), + ) { + IconButton( + onClick = { + val webpage = Uri.parse(Constants.GITHUB) + val intent = Intent(Intent.ACTION_VIEW, webpage) + if (intent.resolveActivity(context.packageManager) != null) { + context.startActivity(intent) + } + }, + ) { + Icon( + painter = painterResource(id = R.drawable.github_foreground), + contentDescription = stringResource(id = R.string.github), + modifier = Modifier.requiredSize(24.dp), + ) + } + } + IconRequestIconButton( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + ) + SimpleTooltipBox( + label = stringResource(id = R.string.about), + ) { + IconButton(onClick = onNavigate) { + Icon( + painter = painterResource(id = R.drawable.contacts_foreground), + contentDescription = stringResource(id = R.string.about), + modifier = Modifier.requiredSize(24.dp), + ) + } + } + }, + floatingActionButton = { + SimpleTooltipBox( + label = stringResource(id = R.string.search), + ) { + FloatingActionButton(onClick = onExpandSearch) { + Icon( + imageVector = Icons.Rounded.Search, + contentDescription = stringResource(id = R.string.search), + ) + } + } + }, + modifier = modifier, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun SimpleTooltipBox( + label: String, + modifier: Modifier = Modifier, + content: @Composable (() -> Unit), +) { + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(label) + } + }, + state = rememberTooltipState(), + modifier = modifier, + ) { + content() + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt new file mode 100644 index 00000000000..5bbd8c6a13f --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt @@ -0,0 +1,143 @@ +package app.lawnchair.lawnicons.ui.components.home + +import androidx.compose.animation.AnimatedContent +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.model.IconInfo +import app.lawnchair.lawnicons.model.IconInfoModel +import app.lawnchair.lawnicons.model.SearchMode +import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar +import app.lawnchair.lawnicons.ui.components.home.search.SearchContents + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +fun HomeTopBar( + isSearchExpanded: Boolean, + onFocusChange: () -> Unit, + isExpandedScreen: Boolean, + onClearSearch: () -> Unit, + onChangeMode: (SearchMode) -> Unit, + onSearchIcons: (String) -> Unit, + searchedIconInfoModel: IconInfoModel?, + onNavigate: () -> Unit, + isIconPicker: Boolean, + searchTerm: String, + searchMode: SearchMode, + onSendResult: (IconInfo) -> Unit, + focusRequester: FocusRequester, + scrollBehavior: TopAppBarScrollBehavior, + appIcon: ImageBitmap, + modifier: Modifier = Modifier, +) { + AnimatedContent(targetState = isSearchExpanded || isExpandedScreen, label = "TopAppBar to SearchBar", modifier = modifier) { targetState -> + if (targetState) { + searchedIconInfoModel?.let { + SearchBar( + searchTerm = searchTerm, + onClearSearch = onClearSearch, + onChangeMode = onChangeMode, + onSearchIcons = onSearchIcons, + iconInfoModel = it, + onNavigate = onNavigate, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + searchMode = searchMode, + onSendResult = onSendResult, + onFocusChange = onFocusChange, + inputFieldModifier = Modifier.focusRequester(focusRequester), + ) + } + } else { + CenterAlignedTopAppBar( + scrollBehavior = scrollBehavior, + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + bitmap = appIcon, + contentDescription = stringResource(id = R.string.app_name), + modifier = Modifier.size(36.dp), + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + stringResource(id = R.string.app_name), + ) + } + }, + ) + } + } +} + +@Composable +private fun SearchBar( + onClearSearch: () -> Unit, + onChangeMode: (SearchMode) -> Unit, + onSearchIcons: (String) -> Unit, + searchTerm: String, + iconInfoModel: IconInfoModel, + onNavigate: () -> Unit, + isExpandedScreen: Boolean, + isIconPicker: Boolean, + searchMode: SearchMode, + onSendResult: (IconInfo) -> Unit, + onFocusChange: () -> Unit, + modifier: Modifier = Modifier, + inputFieldModifier: Modifier = Modifier, +) { + Column( + modifier = modifier.fillMaxWidth(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + LawniconsSearchBar( + query = searchTerm, + isQueryEmpty = searchTerm == "", + onClearAndBackClick = { + onClearSearch() + onFocusChange() + }, + onQueryChange = { newValue -> + onSearchIcons(newValue) + }, + iconInfoModel = iconInfoModel, + onNavigate = onNavigate, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + content = { + SearchContents( + searchTerm = searchTerm, + searchMode = searchMode, + onModeChange = { mode -> + onChangeMode(mode) + }, + iconInfo = iconInfoModel.iconInfo, + onSendResult = { + onSendResult(it) + }, + ) + }, + inputFieldModifier = inputFieldModifier, + ) + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 5ca6ad76883..7c7ec33072c 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -16,7 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid @@ -56,9 +56,8 @@ fun IconPreviewGrid( ) { LazyVerticalGridScrollbar( modifier = Modifier - .then( - if (isExpandedScreen) Modifier.width(640.dp) else Modifier, - ) + .widthIn(max = 640.dp) + .fillMaxWidth() .statusBarsPadding() .padding(top = 26.dp), state = gridState, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 3e622eb4f05..70a5162234c 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -14,12 +14,14 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState @@ -46,6 +48,7 @@ import app.lawnchair.lawnicons.model.IconRequestModel import app.lawnchair.lawnicons.ui.components.core.Card import app.lawnchair.lawnicons.ui.util.Constants import app.lawnchair.lawnicons.ui.util.isScrollingUp +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch @@ -57,30 +60,80 @@ fun IconRequestFAB( snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier, ) { - if (iconRequestModel != null) { - if (iconRequestModel.iconCount > 0) { - IconRequestFAB( - iconRequestList = iconRequestModel.list, - lazyGridState = lazyGridState, - snackbarHostState = snackbarHostState, - modifier = modifier, + RequestHandler( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + ) { interactionSource -> + ExtendedFloatingActionButton( + text = { + Text(stringResource(R.string.request_icons)) + }, + icon = { + Icon( + painter = painterResource(id = R.drawable.icon_request_app), + contentDescription = null, + ) + }, + onClick = {}, + expanded = lazyGridState.isScrollingUp(), + interactionSource = interactionSource, + modifier = modifier, + ) + } +} + +@Composable +fun IconRequestIconButton( + iconRequestModel: IconRequestModel?, + snackbarHostState: SnackbarHostState, + modifier: Modifier = Modifier, +) { + RequestHandler( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + ) { interactionSource -> + IconButton( + onClick = {}, + interactionSource = interactionSource, + modifier = modifier, + ) { + Icon( + painter = painterResource(id = R.drawable.icon_request_app), + contentDescription = stringResource(R.string.request_icons), + modifier = Modifier.requiredSize(24.dp), ) } } } +@Composable +fun RequestHandler( + iconRequestModel: IconRequestModel?, + snackbarHostState: SnackbarHostState, + content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), +) { + if (iconRequestModel != null && iconRequestModel.iconCount > 0) { + RequestHandler( + iconRequestList = iconRequestModel.list, + snackbarHostState = snackbarHostState, + ) { + content(it) + } + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable -fun IconRequestFAB( +fun RequestHandler( iconRequestList: List, snackbarHostState: SnackbarHostState, - lazyGridState: LazyGridState, - modifier: Modifier = Modifier, + content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), ) { val context = LocalContext.current + val viewConfiguration = LocalViewConfiguration.current - val list = iconRequestList.joinToString("\n") { "${it.name}\n${it.componentName}" } - val request = buildForm(list.replace("\n", "%20")) + val requestList = formatIconRequestList(iconRequestList) + val encodedRequestList = buildForm(requestList.replace("\n", "%20")) val sheetExpanded = remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState( @@ -89,9 +142,8 @@ fun IconRequestFAB( val coroutineScope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } - val viewConfiguration = LocalViewConfiguration.current - val directLinkEnabled = request.length < Constants.DIRECT_LINK_MAX_LENGTH + val directLinkEnabled = encodedRequestList.length < Constants.DIRECT_LINK_MAX_LENGTH LaunchedEffect(interactionSource) { var isLongClick = false @@ -111,28 +163,9 @@ fun IconRequestFAB( is PressInteraction.Release -> { if (!isLongClick) { if (directLinkEnabled) { - openLink(context, request) + openLink(context, encodedRequestList) } else { - copyTextToClipboard(context, list) - coroutineScope.launch { - val result = snackbarHostState - .showSnackbar( - message = context.getString(R.string.snackbar_request_too_large), - actionLabel = context.getString(R.string.snackbar_use_fallback_link), - withDismissAction = true, - duration = SnackbarDuration.Indefinite, - ) - when (result) { - SnackbarResult.ActionPerformed -> { - /* Handle snackbar action performed */ - openLink(context, Constants.ICON_REQUEST_FORM) - } - - SnackbarResult.Dismissed -> { - snackbarHostState.currentSnackbarData?.dismiss() - } - } - } + openSnackbarContent(context, requestList, coroutineScope, snackbarHostState) } } } @@ -144,56 +177,48 @@ fun IconRequestFAB( } } - ExtendedFloatingActionButton( - text = { - Text(stringResource(R.string.request_icons)) - }, - icon = { - Icon( - painter = painterResource(id = R.drawable.icon_request_app), - contentDescription = null, - ) - }, - onClick = {}, - expanded = lazyGridState.isScrollingUp(), - interactionSource = interactionSource, - modifier = modifier, - ) + content(interactionSource) + AnimatedVisibility(visible = sheetExpanded.value) { ModalBottomSheet( onDismissRequest = { sheetExpanded.value = false }, sheetState = sheetState, ) { + IconRequestSheet(requestList, context) + } + } +} + +@Composable +private fun IconRequestSheet(list: String, context: Context) { + Column( + modifier = Modifier + .padding(16.dp) + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Card { Column( modifier = Modifier - .padding(16.dp) - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, + .verticalScroll(rememberScrollState()) + .padding(16.dp), ) { - Card { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .padding(16.dp), + Text( + text = list, + fontFamily = FontFamily.Monospace, + modifier = Modifier + .horizontalScroll(rememberScrollState()), + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + TextButton( + onClick = { + copyTextToClipboard(context, list) + }, ) { - Text( - text = list, - fontFamily = FontFamily.Monospace, - modifier = Modifier - .horizontalScroll(rememberScrollState()), - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center, - ) { - TextButton( - onClick = { - copyTextToClipboard(context, list) - }, - ) { - Text(stringResource(R.string.copy_to_clipboard)) - } - } + Text(stringResource(R.string.copy_to_clipboard)) } } } @@ -201,12 +226,43 @@ fun IconRequestFAB( } } +private fun formatIconRequestList(iconRequestList: List) = + iconRequestList.joinToString("\n") { "${it.name}\n${it.componentName}" } + private fun copyTextToClipboard(context: Context, text: String) { val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager val clip = ClipData.newPlainText(context.getString(R.string.copied_text), text) clipboard.setPrimaryClip(clip) } +private fun openSnackbarContent( + context: Context, + list: String, + coroutineScope: CoroutineScope, + snackbarHostState: SnackbarHostState, +) { + copyTextToClipboard(context, list) + coroutineScope.launch { + val result = snackbarHostState + .showSnackbar( + message = context.getString(R.string.snackbar_request_too_large), + actionLabel = context.getString(R.string.snackbar_use_fallback_link), + withDismissAction = true, + duration = SnackbarDuration.Indefinite, + ) + when (result) { + SnackbarResult.ActionPerformed -> { + /* Handle snackbar action performed */ + openLink(context, Constants.ICON_REQUEST_FORM) + } + + SnackbarResult.Dismissed -> { + snackbarHostState.currentSnackbarData?.dismiss() + } + } + } +} + private fun openLink(context: Context, link: String) { val website = Uri.parse(link) val intent = Intent(Intent.ACTION_VIEW, website) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt index dd460f4fdbc..6dbb88bd124 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt @@ -58,6 +58,7 @@ fun LawniconsSearchBar( iconInfoModel: IconInfoModel, onNavigate: () -> Unit, modifier: Modifier = Modifier, + inputFieldModifier: Modifier = Modifier, isExpandedScreen: Boolean = false, isIconPicker: Boolean = false, content: @Composable (() -> Unit), @@ -71,6 +72,7 @@ fun LawniconsSearchBar( onNavigate = onNavigate, content = content, modifier = modifier, + inputFieldModifier = inputFieldModifier, isExpandedScreen = isExpandedScreen, isIconPicker = isIconPicker, ) @@ -99,6 +101,7 @@ fun LawniconsSearchBar( iconCount: Int, onNavigate: () -> Unit, modifier: Modifier = Modifier, + inputFieldModifier: Modifier = Modifier, isExpandedScreen: Boolean = false, isIconPicker: Boolean = false, content: @Composable (() -> Unit), @@ -134,7 +137,12 @@ fun LawniconsSearchBar( onQueryChange = onQueryChange, onSearch = { active = false }, active = active, - onActiveChange = { active = it }, + onActiveChange = { + active = it + if (!active) { + onClearAndBackClick() + } + }, placeholder = { Text( stringResource( @@ -166,6 +174,7 @@ fun LawniconsSearchBar( } }, isExpandedScreen = isExpandedScreen, + inputFieldModifier = inputFieldModifier, ) { content() } @@ -184,12 +193,15 @@ private fun ResponsiveSearchBar( leadingIcon: @Composable () -> Unit, trailingIcon: @Composable () -> Unit, isExpandedScreen: Boolean, + modifier: Modifier = Modifier, + inputFieldModifier: Modifier = Modifier, content: @Composable () -> Unit, ) { if (isExpandedScreen) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center, + modifier = modifier, ) { DockedSearchBar( inputField = { @@ -197,6 +209,7 @@ private fun ResponsiveSearchBar( query = query, onQueryChange = onQueryChange, onSearch = onSearch, + modifier = inputFieldModifier, expanded = active, onExpandedChange = onActiveChange, placeholder = placeholder, @@ -218,6 +231,7 @@ private fun ResponsiveSearchBar( query = query, onQueryChange = onQueryChange, onSearch = onSearch, + modifier = inputFieldModifier, expanded = active, onExpandedChange = onActiveChange, placeholder = placeholder, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 700abda7069..bc0d6862876 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -2,24 +2,29 @@ package app.lawnchair.lawnicons.ui.destination import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.SearchMode +import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar +import app.lawnchair.lawnicons.ui.components.home.HomeTopBar import app.lawnchair.lawnicons.ui.components.home.IconPreviewGrid import app.lawnchair.lawnicons.ui.components.home.IconRequestFAB import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar @@ -28,10 +33,11 @@ import app.lawnchair.lawnicons.ui.components.home.search.SearchContents import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData +import app.lawnchair.lawnicons.util.appIcon import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel import kotlinx.collections.immutable.toImmutableList -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun Home( onNavigate: () -> Unit, @@ -48,9 +54,15 @@ fun Home( val searchMode = searchMode val searchTerm = searchTerm + val expandSearch = remember { mutableStateOf(false) } + val context = LocalContext.current + val lazyGridState = rememberLazyGridState() val snackbarHostState = remember { SnackbarHostState() } + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val focusRequester = remember { FocusRequester() } + Crossfade( modifier = modifier, targetState = iconInfoModel != null, @@ -59,52 +71,48 @@ fun Home( if (visible) { Scaffold( topBar = { - searchedIconInfoModel?.let { - Column( - modifier = Modifier.fillMaxWidth(), - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - LawniconsSearchBar( - query = searchTerm, - isQueryEmpty = searchTerm == "", - onClearAndBackClick = { - lawniconsViewModel.clearSearch() - }, - onQueryChange = { newValue -> - lawniconsViewModel.searchIcons(newValue) - }, - iconInfoModel = it, - onNavigate = onNavigate, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, - content = { - SearchContents( - searchTerm = searchTerm, - searchMode = searchMode, - onModeChange = { mode -> - lawniconsViewModel.changeMode(mode) - }, - iconInfo = it.iconInfo, - onSendResult = { - onSendResult(it) - }, - ) - }, - ) - } + HomeTopBar( + isSearchExpanded = expandSearch.value, + onFocusChange = { expandSearch.value = !expandSearch.value }, + isExpandedScreen = isExpandedScreen, + onClearSearch = { clearSearch() }, + onChangeMode = { changeMode(it) }, + onSearchIcons = { searchIcons(it) }, + searchedIconInfoModel = searchedIconInfoModel, + onNavigate = onNavigate, + searchTerm = searchTerm, + searchMode = searchMode, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + focusRequester = focusRequester, + scrollBehavior = scrollBehavior, + appIcon = context.appIcon().asImageBitmap(), + ) + }, + bottomBar = { + if (!isExpandedScreen) { + HomeBottomBar( + context = context, + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + onNavigate = onNavigate, + onExpandSearch = { expandSearch.value = !expandSearch.value }, + ) } }, floatingActionButton = { - IconRequestFAB( - iconRequestModel = iconRequestModel, - snackbarHostState = snackbarHostState, - lazyGridState = lazyGridState, - ) + if (isExpandedScreen) { + IconRequestFAB( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + lazyGridState = lazyGridState, + ) + } }, snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { contentPadding -> iconInfoModel?.let { val padding = contentPadding // Ignore padding value @@ -123,6 +131,11 @@ fun Home( ) } } + LaunchedEffect(expandSearch.value) { + if (expandSearch.value) { + focusRequester.requestFocus() + } + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d00ad51d7a4..91f637a3be9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,4 +75,5 @@ Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Search diff --git a/build.gradle.kts b/build.gradle.kts index ea39f8e1a44..379455588c6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -16,7 +16,8 @@ plugins { allprojects { plugins.withType().configureEach { extensions.configure { - toolchain.languageVersion = JavaLanguageVersion.of(21) + // Downgrade temporarily to make Compose previews work + toolchain.languageVersion = JavaLanguageVersion.of(17) } } From c05a2df6ac573f86050b823c5fe4fddbd64ae920 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 26 Jul 2024 22:35:38 +0800 Subject: [PATCH 011/144] Initial fix on in-app picker Todo: fix icon colors --- .../app/lawnchair/lawnicons/MainActivity.kt | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt index 06e90530536..2ddec052487 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt @@ -2,6 +2,8 @@ package app.lawnchair.lawnicons import android.content.Context import android.content.Intent +import android.content.res.ColorStateList +import android.graphics.drawable.Drawable import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -13,6 +15,7 @@ import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSiz import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.ui.platform.LocalContext import androidx.core.content.res.ResourcesCompat +import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.toBitmap import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import app.lawnchair.lawnicons.model.IconInfo @@ -51,10 +54,22 @@ class MainActivity : ComponentActivity() { ) { val intent = Intent() - val bitmap = ResourcesCompat.getDrawable(context.resources, iconInfo.id, null) - ?.toBitmap() + val primaryForegroundColor = context.getColor(R.color.primaryForeground) + val primaryBackgroundColor = context.getColor(R.color.primaryBackground) + + val drawable: Drawable? = + ResourcesCompat.getDrawable(context.resources, iconInfo.id, theme)?.mutate()?.let { + DrawableCompat.wrap( + it, + ) + } + + if (drawable != null) { + DrawableCompat.setTintList(drawable, ColorStateList.valueOf(primaryForegroundColor)) + DrawableCompat.setTintList(drawable, ColorStateList.valueOf(primaryBackgroundColor)) + + val bitmap = drawable.toBitmap() - if (bitmap != null) { try { intent.putExtra( "icon", @@ -69,6 +84,7 @@ class MainActivity : ComponentActivity() { } intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconInfo.id) setResult(RESULT_OK, intent) + finish() } else { setResult(RESULT_CANCELED, intent) } From 6bc2a9e4ad1422cd5b4e80432565fd2eb6e2d706 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 26 Jul 2024 22:46:33 +0800 Subject: [PATCH 012/144] Revert app module gradle changes --- app/build.gradle.kts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 92451330b7b..619a15f5915 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,6 @@ import app.cash.licensee.LicenseeTask import com.android.build.gradle.internal.api.ApkVariantOutputImpl +import com.android.build.gradle.tasks.MergeResources import java.io.FileInputStream import java.util.Locale import java.util.Properties @@ -100,7 +101,7 @@ android { applicationVariants.all { outputs.all { (this as? ApkVariantOutputImpl)?.outputFileName = - "Lawnicons $versionName v$versionCode ${buildType.name}.apk".replace(" ", ".") + "Lawnicons $versionName v${versionCode}_${buildType.name}.apk" } } } @@ -121,9 +122,9 @@ androidComponents.onVariants { variant -> } // Process SVGs before every build. -// tasks.withType().configureEach { -// dependsOn(projects.svgProcessor.dependencyProject.tasks.named("run")) -// } +tasks.withType().configureEach { + dependsOn(projects.svgProcessor.dependencyProject.tasks.named("run")) +} licensee { allow("Apache-2.0") @@ -135,10 +136,10 @@ dependencies { implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.activity:activity-compose:1.9.1") implementation(platform("androidx.compose:compose-bom:2024.06.00")) - implementation("androidx.compose.ui:ui:1.6.6") - implementation("androidx.compose.ui:ui-tooling-preview:1.6.6") - implementation("androidx.compose.ui:ui-util:1.6.6") - debugImplementation("androidx.compose.ui:ui-tooling:1.6.6") + implementation("androidx.compose.ui:ui") + implementation("androidx.compose.ui:ui-tooling-preview") + implementation("androidx.compose.ui:ui-util") + debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0-beta05") From 443ee5c5cd4636587ead0e31f955454f7d9b71b1 Mon Sep 17 00:00:00 2001 From: Chang Jiaman Date: Sun, 28 Jul 2024 00:35:41 +0800 Subject: [PATCH 013/144] +9 icons, +1 link (#2183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * link hihonor music, legado(play) * add todesk,yunrili * +6,link 1 * +2 icons * link1 * fix icons,+1 icon * fix * Fixed IQIYI → iQIYI * Improved iqiyi.svg quality for small sizes * The visual center of ithome.svg has been clarified * Moved kaadas.svg so that it is located within the boundaries of the content area and reduced the density at the bottom --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 13 +++++++++++++ svgs/feishu.svg | 1 + svgs/huazhuhui.svg | 1 + svgs/iqiyi.svg | 1 + svgs/ithome.svg | 1 + svgs/kaadas.svg | 1 + svgs/tongyi.svg | 1 + svgs/vvex.svg | 1 + svgs/yadea.svg | 1 + svgs/yunrili.svg | 1 + 10 files changed, 22 insertions(+) create mode 100644 svgs/feishu.svg create mode 100644 svgs/huazhuhui.svg create mode 100644 svgs/iqiyi.svg create mode 100644 svgs/ithome.svg create mode 100644 svgs/kaadas.svg create mode 100644 svgs/tongyi.svg create mode 100644 svgs/vvex.svg create mode 100644 svgs/yadea.svg create mode 100644 svgs/yunrili.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 13cfd209ca9..2ebe21a31a0 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -7479,6 +7479,7 @@ + @@ -11150,6 +11151,7 @@ + @@ -12273,6 +12275,17 @@ + + + + + + + + + + + diff --git a/svgs/feishu.svg b/svgs/feishu.svg new file mode 100644 index 00000000000..8749f8e033d --- /dev/null +++ b/svgs/feishu.svg @@ -0,0 +1 @@ + diff --git a/svgs/huazhuhui.svg b/svgs/huazhuhui.svg new file mode 100644 index 00000000000..10e1a74fa11 --- /dev/null +++ b/svgs/huazhuhui.svg @@ -0,0 +1 @@ + diff --git a/svgs/iqiyi.svg b/svgs/iqiyi.svg new file mode 100644 index 00000000000..03afa64e829 --- /dev/null +++ b/svgs/iqiyi.svg @@ -0,0 +1 @@ + diff --git a/svgs/ithome.svg b/svgs/ithome.svg new file mode 100644 index 00000000000..571b53f91dd --- /dev/null +++ b/svgs/ithome.svg @@ -0,0 +1 @@ + diff --git a/svgs/kaadas.svg b/svgs/kaadas.svg new file mode 100644 index 00000000000..cfb420e9c80 --- /dev/null +++ b/svgs/kaadas.svg @@ -0,0 +1 @@ + diff --git a/svgs/tongyi.svg b/svgs/tongyi.svg new file mode 100644 index 00000000000..56d66f276c7 --- /dev/null +++ b/svgs/tongyi.svg @@ -0,0 +1 @@ + diff --git a/svgs/vvex.svg b/svgs/vvex.svg new file mode 100644 index 00000000000..a1e665b3db4 --- /dev/null +++ b/svgs/vvex.svg @@ -0,0 +1 @@ + diff --git a/svgs/yadea.svg b/svgs/yadea.svg new file mode 100644 index 00000000000..245dcec5404 --- /dev/null +++ b/svgs/yadea.svg @@ -0,0 +1 @@ + diff --git a/svgs/yunrili.svg b/svgs/yunrili.svg new file mode 100644 index 00000000000..b9884d6e465 --- /dev/null +++ b/svgs/yunrili.svg @@ -0,0 +1 @@ + From 186a39a45fc1d6f3a99027118ab28414f79c5f43 Mon Sep 17 00:00:00 2001 From: Secozzi <49240133+Secozzi@users.noreply.github.com> Date: Sat, 27 Jul 2024 16:40:16 +0000 Subject: [PATCH 014/144] +1 icon (#2202) * +1 icon * Fixed --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 1 + svgs/fate_grand_order.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 svgs/fate_grand_order.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 2ebe21a31a0..1e7e05eb25b 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -3147,6 +3147,7 @@ + diff --git a/svgs/fate_grand_order.svg b/svgs/fate_grand_order.svg new file mode 100644 index 00000000000..3a2c79127c3 --- /dev/null +++ b/svgs/fate_grand_order.svg @@ -0,0 +1 @@ + From 3db5c42ce0b00a03caef6686b2f85f4ebedaae2c Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:53:43 +0300 Subject: [PATCH 015/144] +14 links (#2229) --- app/assets/appfilter.xml | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 1e7e05eb25b..76065105524 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -792,6 +792,7 @@ + @@ -1316,6 +1317,8 @@ + + @@ -1819,6 +1822,7 @@ + @@ -2544,6 +2548,7 @@ + @@ -3331,6 +3336,7 @@ + @@ -3750,6 +3756,7 @@ + @@ -4634,6 +4641,7 @@ + @@ -5159,6 +5167,7 @@ + @@ -5315,6 +5324,7 @@ + @@ -6726,6 +6736,7 @@ + @@ -7781,6 +7792,7 @@ + @@ -7910,6 +7922,7 @@ + @@ -10392,6 +10405,7 @@ + @@ -11647,6 +11661,7 @@ + @@ -12114,6 +12129,7 @@ + @@ -12124,11 +12140,13 @@ + + @@ -12162,6 +12180,7 @@ + @@ -12199,6 +12218,7 @@ + @@ -12243,6 +12263,8 @@ + + @@ -12255,6 +12277,7 @@ + @@ -12272,21 +12295,12 @@ + + - - - - - - - - - - - From ea89aa083682a6bdcc467d141511f2a32b2641f7 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 27 Jul 2024 20:00:14 +0300 Subject: [PATCH 016/144] Clarified the instructions for finding the visual center of an icon (#2230) --- .github/icon_checklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index 51c1a6568da..b4909874fd6 100644 --- a/.github/icon_checklist.md +++ b/.github/icon_checklist.md @@ -20,7 +20,7 @@ Example: `京东 ~~ JD`. ### Quality 1. Ensure that icons are easily recognizable. -2. Align icons to [the visual center](https://www.google.com/search?sca_esv=1fcec3f5e0b15e20&q=what+is+visual+center+of+an+icon&tbm=isch&source=lnms) as much as possible within the guidelines. +2. Align icons to [the visual center](https://crazybitsstudios.com/another-way-of-aligning-elements-when-creating-icons) as much as possible within the guidelines. The visual center is where your icon looks and feels centered. 3. Avoid noticable black spots by reducing the stroke width or simplifying the icons. 4. Avoid close distances between strokes. The icons on the phone screen will be smaller, so the small distances between the strokes will stick together. 5. Avoid drastic changes in stroke widths. When the strokes next to each other differ in width by 4px or more, the icon will look sloppy. From 8c689221675381c31a8a5b98e72c68f427f5c066 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:56:58 +0800 Subject: [PATCH 017/144] Create initial icon design change issue template --- .github/ISSUE_TEMPLATE/icon_rebrand.yml | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/icon_rebrand.yml diff --git a/.github/ISSUE_TEMPLATE/icon_rebrand.yml b/.github/ISSUE_TEMPLATE/icon_rebrand.yml new file mode 100644 index 00000000000..acf139c33ae --- /dev/null +++ b/.github/ISSUE_TEMPLATE/icon_rebrand.yml @@ -0,0 +1,31 @@ +name: Request icon design change +description: Request changing the design of an existing icon in Lawnicons +title: "[Icon Rebrand] " +labels: ["icon rebrand"] +body: + - type: textarea + id: outdated-icon-list + attributes: + label: List of outdated icons + description: | + Please follow the following format regarding the outdated icons: + + ``` + App Name + (image to new icon) + + App Name + (image to new icon) + ``` + + It is more preferable to link to the outdated icon in [the svgs/ folder](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs) + placeholder: + validations: + required: true + - type: textarea + id: additional-info + attributes: + label: Additional information + description: Place additional context here. + validations: + required: true From 3b05a0f564fb149bf056601542d433ae79eb043e Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:06:51 +0800 Subject: [PATCH 018/144] Move icon picker constants --- app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt | 3 ++- .../main/kotlin/app/lawnchair/lawnicons/ui/util/Constants.kt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt index 2ddec052487..9b9b1829f96 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt @@ -20,6 +20,7 @@ import androidx.core.graphics.drawable.toBitmap import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.ui.Lawnicons +import app.lawnchair.lawnicons.ui.util.Constants import dagger.hilt.android.AndroidEntryPoint @ExperimentalFoundationApi @@ -32,7 +33,7 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) enableEdgeToEdge() - val isIconPicker = intent?.action == "com.novalauncher.THEME" + val isIconPicker = intent?.action == Constants.ICON_PICKER_INTENT_ACTION setContent { val context = LocalContext.current diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Constants.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Constants.kt index d33c4ee6788..871c7701a12 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Constants.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Constants.kt @@ -4,6 +4,8 @@ object Constants { const val ICON_REQUEST_FORM = "https://forms.gle/xt7sJhgWEasuo9TR9" const val GITHUB = "https://github.com/LawnchairLauncher/lawnicons" + const val ICON_PICKER_INTENT_ACTION = "com.novalauncher.THEME" + /** * Maximum length of a direct Google forms link. The limit is around 2300-2400 characters, so we use the lower limit to prevent any issues. */ From 2d3a0c8ee574a3f560e81c96dd04e408ebfca1dc Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:07:40 +0800 Subject: [PATCH 019/144] Open empty icon request form if icon count is 0 --- .../lawnicons/ui/components/home/IconRequestFAB.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 70a5162234c..c51a9d36930 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -112,7 +112,7 @@ fun RequestHandler( snackbarHostState: SnackbarHostState, content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), ) { - if (iconRequestModel != null && iconRequestModel.iconCount > 0) { + if (iconRequestModel != null) { RequestHandler( iconRequestList = iconRequestModel.list, snackbarHostState = snackbarHostState, @@ -162,7 +162,9 @@ fun RequestHandler( is PressInteraction.Release -> { if (!isLongClick) { - if (directLinkEnabled) { + if (iconRequestList.isEmpty()) { + openLink(context, Constants.ICON_REQUEST_FORM) + } else if (directLinkEnabled) { openLink(context, encodedRequestList) } else { openSnackbarContent(context, requestList, coroutineScope, snackbarHostState) From 948851b6d8f26a86631b94051783bad7538da234 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:08:24 +0800 Subject: [PATCH 020/144] Update bottom bar FAB color --- .../lawnicons/ui/components/home/HomeBottomBar.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index b425c041c55..bc218d9f586 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -7,8 +7,10 @@ import androidx.compose.foundation.layout.requiredSize import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Search import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.BottomAppBarDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.PlainTooltip @@ -76,7 +78,11 @@ fun HomeBottomBar( SimpleTooltipBox( label = stringResource(id = R.string.search), ) { - FloatingActionButton(onClick = onExpandSearch) { + FloatingActionButton( + onClick = onExpandSearch, + containerColor = BottomAppBarDefaults.bottomAppBarFabColor, + elevation = FloatingActionButtonDefaults.bottomAppBarFabElevation(), + ) { Icon( imageVector = Icons.Rounded.Search, contentDescription = stringResource(id = R.string.search), From 081edd27ac1d500d8044b35fca195f348e29b45a Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:08:35 +0800 Subject: [PATCH 021/144] Hide top app bar on scroll --- .../main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index bc0d6862876..9838d9b7255 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -60,7 +60,7 @@ fun Home( val lazyGridState = rememberLazyGridState() val snackbarHostState = remember { SnackbarHostState() } - val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val focusRequester = remember { FocusRequester() } Crossfade( From 2d60c924447dbf18d1084d5f78dff042d8a54f77 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 27 Jul 2024 19:56:44 +0800 Subject: [PATCH 022/144] Update app repositories code --- .../lawnicons/di/IconRepositoryModule.kt | 3 +- .../di/OssLibraryRepositoryModule.kt | 5 +- .../lawnicons/model/IconRequestModel.kt | 2 +- .../lawnicons/repository/IconRepository.kt | 157 +++++++++--------- .../repository/OssLibraryRepository.kt | 15 +- .../ui/components/home/IconRequestFAB.kt | 2 +- .../lawnicons/viewmodel/LawniconsViewModel.kt | 2 +- 7 files changed, 94 insertions(+), 92 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/IconRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/IconRepositoryModule.kt index b29d360d930..474f588d244 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/di/IconRepositoryModule.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/IconRepositoryModule.kt @@ -2,6 +2,7 @@ package app.lawnchair.lawnicons.di import android.app.Application import app.lawnchair.lawnicons.repository.IconRepository +import app.lawnchair.lawnicons.repository.IconRepositoryImpl import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -14,5 +15,5 @@ object IconRepositoryModule { @Provides @Singleton - fun provideIconRepository(application: Application) = IconRepository(application) + fun provideIconRepository(application: Application): IconRepository = IconRepositoryImpl(application) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt index c4bd81be934..52942d9f83d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt @@ -2,6 +2,7 @@ package app.lawnchair.lawnicons.di import android.app.Application import app.lawnchair.lawnicons.repository.OssLibraryRepository +import app.lawnchair.lawnicons.repository.OssLibraryRepositoryImpl import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -14,6 +15,6 @@ object OssLibraryRepositoryModule { @Provides @Singleton - fun provideOssLibraryRepository(application: Application) = - OssLibraryRepository(application = application) + fun provideOssLibraryRepository(application: Application) : OssLibraryRepository = + OssLibraryRepositoryImpl(application = application) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt index d81bbe2ae4d..d26f7f76115 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt @@ -3,7 +3,7 @@ package app.lawnchair.lawnicons.model import kotlinx.collections.immutable.ImmutableList data class IconRequest( - val name: String, + val label: String, val componentName: String, ) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt index 7120ce1c78c..c92d5158559 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt @@ -12,113 +12,104 @@ import app.lawnchair.lawnicons.model.getFirstLabelAndComponent import app.lawnchair.lawnicons.util.getIconInfo import app.lawnchair.lawnicons.util.getSystemIconInfoAppfilter import javax.inject.Inject +import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class IconRepository @Inject constructor(application: Application) { +interface IconRepository { + val iconInfoModel: StateFlow + val searchedIconInfoModel: StateFlow + val iconRequestList: MutableStateFlow + + suspend fun search(mode: SearchMode, query: String) + fun clearSearch() +} + +class IconRepositoryImpl @Inject constructor(application: Application) : IconRepository { private val coroutineScope = CoroutineScope(Dispatchers.IO) - private var iconInfo: List = emptyList() - val iconInfoModel = MutableStateFlow(value = null) - val searchedIconInfoModel = MutableStateFlow(value = null) - private var systemPackageList: List? = null - var iconRequestList = MutableStateFlow(value = null) + private val _iconInfoModel = MutableStateFlow(IconInfoModel(persistentListOf(), 0)) + override val iconInfoModel = _iconInfoModel.asStateFlow() - private var iconCount = 0 + private val _searchedIconInfoModel = MutableStateFlow(IconInfoModel(persistentListOf(), 0)) + override val searchedIconInfoModel = _searchedIconInfoModel.asStateFlow() - init { + override val iconRequestList = MutableStateFlow(value = null) + + init{ coroutineScope.launch { - application.getIconInfo() - .also { list -> - iconInfo = list.sortedBy { it.label.lowercase() } - } - .associateBy { it.label }.values - .also { - iconCount = it.size - } + val iconList = application.getIconInfo().sortedBy { it.label.lowercase() } + val groupedIcons = iconList.associateBy { it.label }.values + val iconCount = groupedIcons.size - iconInfoModel.value = IconInfoModel( - iconInfo = iconInfo.toPersistentList(), - iconCount = iconCount, - ) - searchedIconInfoModel.value = IconInfoModel( - iconInfo = iconInfo.toPersistentList(), + _iconInfoModel.value = IconInfoModel( + iconInfo = iconList.toPersistentList(), iconCount = iconCount, ) + _searchedIconInfoModel.value = _iconInfoModel.value - systemPackageList = application.getSystemIconInfoAppfilter() + val systemPackageList = application.getSystemIconInfoAppfilter() .associateBy { it.label }.values .sortedBy { it.label.lowercase() } - - getIconRequestList() + getIconRequestList(systemPackageList) } } - suspend fun search( + override suspend fun search( mode: SearchMode, query: String, ) = withContext(Dispatchers.Default) { - searchedIconInfoModel.value = iconInfo - .let { iconInfo -> - val filtered = iconInfo.mapNotNull { candidate -> - val searchIn = when (mode) { - SearchMode.LABEL -> candidate.componentNames.map { it.label } - SearchMode.COMPONENT -> candidate.componentNames.map { it.componentName } - SearchMode.DRAWABLE -> listOf(candidate.drawableName) - } - val indexOfMatch = searchIn.map { - it.indexOf(string = query, ignoreCase = true) - }.filter { it != -1 }.minOrNull() ?: return@mapNotNull null - val matchAtWordStart = searchIn.any { - it.indexOf(string = query, ignoreCase = true) == 0 || - it.getOrNull(it.indexOf(string = query, ignoreCase = true) - 1) == ' ' - } - SearchInfo( - iconInfo = candidate, - indexOfMatch = indexOfMatch, - matchAtWordStart = matchAtWordStart, - ) - }.sortedWith( - compareBy( - { searchInfo -> !searchInfo.matchAtWordStart }, - { searchInfo -> searchInfo.indexOfMatch }, - ), - ).map { searchInfo -> - searchInfo.iconInfo - }.toPersistentList() - IconInfoModel( - iconCount = iconInfo.size, - iconInfo = filtered, - ) + val filteredIcons = _iconInfoModel.value.iconInfo.mapNotNull { candidate -> + val searchIn = when (mode) { + SearchMode.LABEL -> candidate.componentNames.map { it.label } + SearchMode.COMPONENT -> candidate.componentNames.map { it.componentName } + SearchMode.DRAWABLE -> listOf(candidate.drawableName) + } + val indexOfMatch = searchIn.map { + it.indexOf(string = query, ignoreCase = true) + }.filter { it != -1 }.minOrNull() ?: return@mapNotNull null + val matchAtWordStart = searchIn.any { + it.indexOf(string = query, ignoreCase = true) == 0 || + it.getOrNull(it.indexOf(string = query, ignoreCase = true) - 1) == ' ' } + SearchInfo( + iconInfo = candidate, + indexOfMatch = indexOfMatch, + matchAtWordStart = matchAtWordStart, + ) + }.sortedWith( + compareBy( + { searchInfo -> !searchInfo.matchAtWordStart }, + { searchInfo -> searchInfo.indexOfMatch }, + ), + ).map { searchInfo -> + searchInfo.iconInfo + }.toPersistentList() + + _searchedIconInfoModel.value = IconInfoModel( + iconCount = _iconInfoModel.value.iconCount, + iconInfo = filteredIcons, + ) } - fun clear() { - searchedIconInfoModel.value = iconInfoModel.value?.let { - IconInfoModel( - iconCount = it.iconCount, - iconInfo = IconInfoManager.splitByComponentName(iconInfo).toPersistentList(), - ) - } + override fun clearSearch() { + _searchedIconInfoModel.value = _iconInfoModel.value } - private suspend fun getIconRequestList() = withContext(Dispatchers.Default) { - iconRequestList.value = systemPackageList?.let { packageList -> - val lawniconsData = iconInfo + private suspend fun getIconRequestList(systemPackageList: List) = + withContext(Dispatchers.Default) { + val lawniconsData = _iconInfoModel.value.iconInfo - val systemData = packageList.map { info -> - info.getFirstLabelAndComponent().also { - IconRequest( - it.label, - it.componentName, - ) - } + val systemData = systemPackageList.map { info -> + info.getFirstLabelAndComponent() } val lawniconsComponents = IconInfoManager.splitByComponentName(lawniconsData) @@ -126,17 +117,17 @@ class IconRepository @Inject constructor(application: Application) { .sortedBy { it.lowercase() } .toSet() - val commonItems = systemData.filter { it.componentName !in lawniconsComponents }.map { - IconRequest( - it.label, - it.componentName, - ) - } + val commonItems = systemData.filter { it.componentName !in lawniconsComponents } + .map { + IconRequest( + label = it.label, + componentName = it.componentName, + ) + } - IconRequestModel( + iconRequestList.value = IconRequestModel( list = commonItems.toImmutableList(), iconCount = commonItems.size, ) } - } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/OssLibraryRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/OssLibraryRepository.kt index 5dc0fbd5956..5b35c656528 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/OssLibraryRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/OssLibraryRepository.kt @@ -15,11 +15,20 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -class OssLibraryRepository @Inject constructor(private val application: Application) { +interface OssLibraryRepository { + val ossLibraries: StateFlow> + + fun getNoticeForOssLibrary( + ossLibraryName: String, + annotate: (String) -> AnnotatedString, + ): Flow +} + +class OssLibraryRepositoryImpl @Inject constructor(private val application: Application) : OssLibraryRepository { private val coroutineScope = MainScope() - val ossLibraries: StateFlow> = flow { + override val ossLibraries: StateFlow> = flow { val jsonString = application.resources.assets.open("artifacts.json") .bufferedReader().use { it.readText() } val ossLibraries = kotlinxJson.decodeFromString>(jsonString) @@ -33,7 +42,7 @@ class OssLibraryRepository @Inject constructor(private val application: Applicat .flowOn(Dispatchers.IO) .stateIn(coroutineScope, SharingStarted.Lazily, emptyList()) - fun getNoticeForOssLibrary( + override fun getNoticeForOssLibrary( ossLibraryName: String, annotate: (String) -> AnnotatedString, ): Flow = ossLibraries.map { it -> diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index c51a9d36930..9c76355cf4e 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -229,7 +229,7 @@ private fun IconRequestSheet(list: String, context: Context) { } private fun formatIconRequestList(iconRequestList: List) = - iconRequestList.joinToString("\n") { "${it.name}\n${it.componentName}" } + iconRequestList.joinToString("\n") { "${it.label}\n${it.componentName}" } private fun copyTextToClipboard(context: Context, text: String) { val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt index d443da3c7ae..da3abce5f0d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt @@ -49,7 +49,7 @@ class LawniconsViewModel @Inject constructor(private val iconRepository: IconRep fun clearSearch() { _searchTerm = "" viewModelScope.launch { - iconRepository.clear() + iconRepository.clearSearch() } } } From c2a728c331e0ccc417eceddfa491fe8028e7a778 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:28:00 +0800 Subject: [PATCH 023/144] Simplify HomeTopBar --- .../ui/components/home/HomeTopBar.kt | 33 +++++++++++-------- .../lawnicons/ui/destination/Home.kt | 20 ++++++----- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt index 5bbd8c6a13f..55f98e36d1b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt @@ -14,6 +14,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -28,26 +29,32 @@ import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar import app.lawnchair.lawnicons.ui.components.home.search.SearchContents +data class HomeTopBarUiState( + val isSearchExpanded: Boolean , + val isExpandedScreen: Boolean, + val searchTerm: String, + val searchMode: SearchMode, + val searchedIconInfoModel: IconInfoModel?, + val isIconPicker: Boolean, + val appIcon: ImageBitmap, +) + @Composable @OptIn(ExperimentalMaterial3Api::class) fun HomeTopBar( - isSearchExpanded: Boolean, + uiState: HomeTopBarUiState, onFocusChange: () -> Unit, - isExpandedScreen: Boolean, onClearSearch: () -> Unit, onChangeMode: (SearchMode) -> Unit, onSearchIcons: (String) -> Unit, - searchedIconInfoModel: IconInfoModel?, onNavigate: () -> Unit, - isIconPicker: Boolean, - searchTerm: String, - searchMode: SearchMode, onSendResult: (IconInfo) -> Unit, focusRequester: FocusRequester, scrollBehavior: TopAppBarScrollBehavior, - appIcon: ImageBitmap, modifier: Modifier = Modifier, ) { + val (isSearchExpanded, isExpandedScreen, searchTerm, searchMode, searchedIconInfoModel, isIconPicker, appIcon) = uiState + AnimatedContent(targetState = isSearchExpanded || isExpandedScreen, label = "TopAppBar to SearchBar", modifier = modifier) { targetState -> if (targetState) { searchedIconInfoModel?.let { @@ -55,7 +62,7 @@ fun HomeTopBar( searchTerm = searchTerm, onClearSearch = onClearSearch, onChangeMode = onChangeMode, - onSearchIcons = onSearchIcons, + onSearch = onSearchIcons, iconInfoModel = it, onNavigate = onNavigate, isExpandedScreen = isExpandedScreen, @@ -91,16 +98,16 @@ fun HomeTopBar( @Composable private fun SearchBar( + searchMode: SearchMode, + searchTerm: String, + onSearch: (String) -> Unit, onClearSearch: () -> Unit, onChangeMode: (SearchMode) -> Unit, - onSearchIcons: (String) -> Unit, - searchTerm: String, - iconInfoModel: IconInfoModel, onNavigate: () -> Unit, isExpandedScreen: Boolean, isIconPicker: Boolean, - searchMode: SearchMode, onSendResult: (IconInfo) -> Unit, + iconInfoModel: IconInfoModel, onFocusChange: () -> Unit, modifier: Modifier = Modifier, inputFieldModifier: Modifier = Modifier, @@ -118,7 +125,7 @@ private fun SearchBar( onFocusChange() }, onQueryChange = { newValue -> - onSearchIcons(newValue) + onSearch(newValue) }, iconInfoModel = iconInfoModel, onNavigate = onNavigate, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 9838d9b7255..41f07cd2fa9 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -65,28 +65,30 @@ fun Home( Crossfade( modifier = modifier, - targetState = iconInfoModel != null, + targetState = iconInfoModel.iconCount > 0, label = "", ) { visible -> if (visible) { Scaffold( topBar = { HomeTopBar( - isSearchExpanded = expandSearch.value, + uiState = HomeTopBarUiState( + isSearchExpanded = expandSearch.value, + isExpandedScreen = isExpandedScreen, + searchedIconInfoModel = searchedIconInfoModel, + searchTerm = searchTerm, + searchMode = searchMode, + isIconPicker = isIconPicker, + appIcon = context.appIcon().asImageBitmap(), + ), onFocusChange = { expandSearch.value = !expandSearch.value }, - isExpandedScreen = isExpandedScreen, onClearSearch = { clearSearch() }, onChangeMode = { changeMode(it) }, onSearchIcons = { searchIcons(it) }, - searchedIconInfoModel = searchedIconInfoModel, onNavigate = onNavigate, - searchTerm = searchTerm, - searchMode = searchMode, - isIconPicker = isIconPicker, onSendResult = onSendResult, focusRequester = focusRequester, scrollBehavior = scrollBehavior, - appIcon = context.appIcon().asImageBitmap(), ) }, bottomBar = { @@ -114,7 +116,7 @@ fun Home( }, modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), ) { contentPadding -> - iconInfoModel?.let { + iconInfoModel.let { val padding = contentPadding // Ignore padding value IconPreviewGrid( iconInfo = it.iconInfo, From 06e41c57f4c16f03773b5c7f65b0c2a97e5b249c Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:00:51 +0800 Subject: [PATCH 024/144] Implement basic user tips As of now, only the "icon request" tip will be added. Further tips can be easily expanded upon later. --- .../lawnicons/di/UserTipsRepositoryModule.kt | 23 +++++++++ .../repository/UserTipsRepository.kt | 27 ++++++++++ .../ui/components/home/HomeBottomBar.kt | 51 +++++++++++++++++-- .../ui/components/home/IconRequestFAB.kt | 6 +++ .../lawnicons/ui/destination/Home.kt | 5 ++ .../lawnicons/viewmodel/LawniconsViewModel.kt | 15 +++++- 6 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt new file mode 100644 index 00000000000..4c81717b0d1 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt @@ -0,0 +1,23 @@ +package app.lawnchair.lawnicons.di + +import android.app.Application +import android.content.Context +import app.lawnchair.lawnicons.repository.UserTipsRepository +import app.lawnchair.lawnicons.repository.UserTipsRepositoryImpl +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + + +@Module +@InstallIn(SingletonComponent::class) +object UserTipsRepositoryModule { + + @Provides + @Singleton + fun provideIconRepository(application: Application): UserTipsRepository = UserTipsRepositoryImpl( + application.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) + ) +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt new file mode 100644 index 00000000000..2667e883bb3 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt @@ -0,0 +1,27 @@ +package app.lawnchair.lawnicons.repository + +import android.content.SharedPreferences +import javax.inject.Inject + +// TODO: Add additional tips +interface UserTipsRepository { + fun hasClickedIconRequestButton(): Boolean + fun onIconRequestButtonClicked() + + fun clearTips() +} + +class UserTipsRepositoryImpl @Inject constructor(private val prefs: SharedPreferences) : UserTipsRepository { + + companion object { + const val ICON_REQUEST_BUTTON_CLICKED = "icon_request_button_clicked" + } + + override fun hasClickedIconRequestButton(): Boolean = prefs.get(ICON_REQUEST_BUTTON_CLICKED) + override fun onIconRequestButtonClicked() = prefs.set(ICON_REQUEST_BUTTON_CLICKED, true) + + override fun clearTips() = prefs.edit().clear().apply() +} + +fun SharedPreferences.get(key: String): Boolean = getBoolean(key, false) +fun SharedPreferences.set(key: String, value: Boolean) = edit().putBoolean(key, value).apply() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index bc218d9f586..83d2a435822 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -13,6 +13,7 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PlainTooltip import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text @@ -20,9 +21,12 @@ import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequestModel @@ -35,6 +39,8 @@ fun HomeBottomBar( snackbarHostState: SnackbarHostState, onNavigate: () -> Unit, onExpandSearch: () -> Unit, + isIconRequestClicked: Boolean, + onIconRequestClick: () -> Unit, modifier: Modifier = Modifier, ) { BottomAppBar( @@ -58,10 +64,14 @@ fun HomeBottomBar( ) } } - IconRequestIconButton( - iconRequestModel = iconRequestModel, - snackbarHostState = snackbarHostState, - ) + IconRequestTooltip(isIconRequestClicked) { + IconRequestIconButton( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + onClick = onIconRequestClick, + ) + } + SimpleTooltipBox( label = stringResource(id = R.string.about), ) { @@ -114,3 +124,36 @@ private fun SimpleTooltipBox( content() } } + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun IconRequestTooltip( + isButtonClicked: Boolean, + content: @Composable (() -> Unit), +) { + val state = rememberTooltipState( + initialIsVisible = true, + isPersistent = true, + ) + val hideTooltip = remember { isButtonClicked } + + LaunchedEffect(hideTooltip) { + if (hideTooltip) { state.dismiss() } + } + + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip( + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + caretSize = DpSize(16.dp, 8.dp) + ) { + Text("Request missing icons here") + } + }, + state = state, + ) { + content() + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 9c76355cf4e..dd984afa23b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -86,11 +86,13 @@ fun IconRequestFAB( fun IconRequestIconButton( iconRequestModel: IconRequestModel?, snackbarHostState: SnackbarHostState, + onClick: () -> Unit, modifier: Modifier = Modifier, ) { RequestHandler( iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, + onClick = onClick, ) { interactionSource -> IconButton( onClick = {}, @@ -110,12 +112,14 @@ fun IconRequestIconButton( fun RequestHandler( iconRequestModel: IconRequestModel?, snackbarHostState: SnackbarHostState, + onClick: () -> Unit = {}, content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), ) { if (iconRequestModel != null) { RequestHandler( iconRequestList = iconRequestModel.list, snackbarHostState = snackbarHostState, + onClick = onClick, ) { content(it) } @@ -127,6 +131,7 @@ fun RequestHandler( fun RequestHandler( iconRequestList: List, snackbarHostState: SnackbarHostState, + onClick: () -> Unit, content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), ) { val context = LocalContext.current @@ -151,6 +156,7 @@ fun RequestHandler( interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> { + onClick() isLongClick = false delay(viewConfiguration.longPressTimeoutMillis) isLongClick = true diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 41f07cd2fa9..b6025803b70 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -25,6 +25,7 @@ import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBar +import app.lawnchair.lawnicons.ui.components.home.HomeTopBarUiState import app.lawnchair.lawnicons.ui.components.home.IconPreviewGrid import app.lawnchair.lawnicons.ui.components.home.IconRequestFAB import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar @@ -99,6 +100,10 @@ fun Home( snackbarHostState = snackbarHostState, onNavigate = onNavigate, onExpandSearch = { expandSearch.value = !expandSearch.value }, + isIconRequestClicked = isIconRequestButtonClicked, + onIconRequestClick = { + onIconRequestButtonClicked() + } ) } }, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt index da3abce5f0d..153d44305d4 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt @@ -7,12 +7,16 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.repository.IconRepository +import app.lawnchair.lawnicons.repository.UserTipsRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.launch @HiltViewModel -class LawniconsViewModel @Inject constructor(private val iconRepository: IconRepository) : +class LawniconsViewModel @Inject constructor( + private val iconRepository: IconRepository, + private val userTipsRepository: UserTipsRepository, +) : ViewModel() { @JvmField val iconInfoModel = iconRepository.iconInfoModel @@ -23,6 +27,9 @@ class LawniconsViewModel @Inject constructor(private val iconRepository: IconRep @JvmField val iconRequestModel = iconRepository.iconRequestList + @JvmField + val isIconRequestButtonClicked = userTipsRepository.hasClickedIconRequestButton() + private var _searchMode by mutableStateOf(SearchMode.LABEL) private var _searchTerm by mutableStateOf("") @@ -52,4 +59,10 @@ class LawniconsViewModel @Inject constructor(private val iconRepository: IconRep iconRepository.clearSearch() } } + + fun onIconRequestButtonClicked() { + if (!userTipsRepository.hasClickedIconRequestButton()) { + userTipsRepository.onIconRequestButtonClicked() + } + } } From 6707f41c83cb6a6186888556815fbf8e8e37dc0b Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:07:11 +0800 Subject: [PATCH 025/144] Add new core contributors --- .../GitHubContributorsRepository.kt | 10 ++++-- .../lawnicons/ui/destination/About.kt | 32 ++++++++++++++++++- app/src/main/res/values/strings.xml | 12 +++++-- 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt index c82b4cb4afa..d04b0283dc0 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt @@ -4,9 +4,13 @@ import app.lawnchair.lawnicons.api.GitHubContributorsAPI import javax.inject.Inject val coreContributorIds = listOf( - 8080853, - 29139614, - 56888459, + 29139614, // Remove Patryk from contributors list, as per https://t.me/lawnchairci/1557 + 56888459, // Remove renovate-bot from contributors list, since we don't count botss as contributors + 8080853, // suphon-t + 70206496, // SuperDragonXD + 60105060, // x9136 + 10363352, // Goooler + 49114212, // Grabstertv ) class GitHubContributorsRepository @Inject constructor( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index f72f317583b..203092dae67 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -54,11 +54,40 @@ private val externalLinks = listOf( private val coreContributors = listOf( Contributor( - name = "paphonb", + name = "Suphon T.", username = "paphonb", photoUrl = "https://avatars.githubusercontent.com/u/8080853", socialUrl = "https://x.com/paphonb", + descriptionRes = R.string.contribution_core, ), + Contributor( + name = "SuperDragonXD", + username = "SuperDragonXD", + photoUrl = "https://avatars.githubusercontent.com/u/70206496", + socialUrl = "https://github.com/SuperDragonXD", + descriptionRes = R.string.contribution_core, + ), + Contributor( + name = "Gleb", + username = "x9136", + photoUrl = "https://avatars.githubusercontent.com/u/60105060", + socialUrl = "https://github.com/x9136", + descriptionRes = R.string.contribution_icons, + ), + Contributor( + name = "Grabster", + username = "Grabstertv", + photoUrl = "https://avatars.githubusercontent.com/u/49114212", + socialUrl = "https://x.com/grabstertv", + descriptionRes = R.string.contribution_icons + ), + Contributor( + name = "Zongle Wang", + username = "Goooler", + photoUrl = "https://avatars.githubusercontent.com/u/10363352", + socialUrl = "https://androiddev.social/@Goooler", + descriptionRes = R.string.contribution_deps + ) ) private val specialThanks = listOf( @@ -158,6 +187,7 @@ fun About( photoUrl = it.photoUrl, profileUrl = it.socialUrl, divider = index != coreContributors.lastIndex, + description = it.descriptionRes?.let { stringResource(id = it) }, ) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 91f637a3be9..5633c4de3ee 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,6 +14,9 @@ Pick an icon + + Search + %s not found @@ -39,6 +42,11 @@ Share details + + Core app + Icons + Dependencies + Special thanks @@ -48,7 +56,7 @@ For naming the app - Acknowledgements + Open-source licenses @@ -73,7 +81,7 @@ Copy to clipboard Copied text + Copied icon request details to clipboard. To request them, submit the details into the form. Open form - Search From 4167aa693e85ef3e8bf5c90de4beee071eaf2dd1 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 29 Jul 2024 16:26:16 +0800 Subject: [PATCH 026/144] Apply spotless --- .../di/OssLibraryRepositoryModule.kt | 2 +- .../lawnicons/di/UserTipsRepositoryModule.kt | 3 +-- .../GitHubContributorsRepository.kt | 21 ++++++++++++------- .../lawnicons/repository/IconRepository.kt | 2 +- .../ui/components/home/HomeBottomBar.kt | 6 ++++-- .../ui/components/home/HomeTopBar.kt | 3 +-- .../ui/components/home/IconRequestFAB.kt | 5 ++++- .../lawnicons/ui/destination/About.kt | 6 +++--- .../lawnicons/ui/destination/Home.kt | 2 +- 9 files changed, 30 insertions(+), 20 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt index 52942d9f83d..733a73102ad 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/OssLibraryRepositoryModule.kt @@ -15,6 +15,6 @@ object OssLibraryRepositoryModule { @Provides @Singleton - fun provideOssLibraryRepository(application: Application) : OssLibraryRepository = + fun provideOssLibraryRepository(application: Application): OssLibraryRepository = OssLibraryRepositoryImpl(application = application) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt index 4c81717b0d1..f747c66eb09 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt @@ -10,7 +10,6 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import javax.inject.Singleton - @Module @InstallIn(SingletonComponent::class) object UserTipsRepositoryModule { @@ -18,6 +17,6 @@ object UserTipsRepositoryModule { @Provides @Singleton fun provideIconRepository(application: Application): UserTipsRepository = UserTipsRepositoryImpl( - application.getSharedPreferences("app_prefs", Context.MODE_PRIVATE) + application.getSharedPreferences("app_prefs", Context.MODE_PRIVATE), ) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt index d04b0283dc0..9b5f2bba583 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt @@ -4,13 +4,20 @@ import app.lawnchair.lawnicons.api.GitHubContributorsAPI import javax.inject.Inject val coreContributorIds = listOf( - 29139614, // Remove Patryk from contributors list, as per https://t.me/lawnchairci/1557 - 56888459, // Remove renovate-bot from contributors list, since we don't count botss as contributors - 8080853, // suphon-t - 70206496, // SuperDragonXD - 60105060, // x9136 - 10363352, // Goooler - 49114212, // Grabstertv + // Remove Patryk from contributors list, as per https://t.me/lawnchairci/1557 + 29139614, + // Remove renovate-bot from contributors list, since we don't count bots as contributors + 56888459, + // suphon-t + 8080853, + // SuperDragonXD + 70206496, + // x9136 + 60105060, + // Goooler + 10363352, + // Grabstertv + 49114212, ) class GitHubContributorsRepository @Inject constructor( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt index c92d5158559..dee296b010b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt @@ -44,7 +44,7 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep override val iconRequestList = MutableStateFlow(value = null) - init{ + init { coroutineScope.launch { val iconList = application.getIconInfo().sortedBy { it.label.lowercase() } val groupedIcons = iconList.associateBy { it.label }.values diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 83d2a435822..33272e9024d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -138,7 +138,9 @@ private fun IconRequestTooltip( val hideTooltip = remember { isButtonClicked } LaunchedEffect(hideTooltip) { - if (hideTooltip) { state.dismiss() } + if (hideTooltip) { + state.dismiss() + } } TooltipBox( @@ -147,7 +149,7 @@ private fun IconRequestTooltip( PlainTooltip( containerColor = MaterialTheme.colorScheme.primaryContainer, contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - caretSize = DpSize(16.dp, 8.dp) + caretSize = DpSize(16.dp, 8.dp), ) { Text("Request missing icons here") } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt index 55f98e36d1b..9a5da94b14f 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt @@ -14,7 +14,6 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.runtime.Composable -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -30,7 +29,7 @@ import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar import app.lawnchair.lawnicons.ui.components.home.search.SearchContents data class HomeTopBarUiState( - val isSearchExpanded: Boolean , + val isSearchExpanded: Boolean, val isExpandedScreen: Boolean, val searchTerm: String, val searchMode: SearchMode, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index dd984afa23b..caeb92c2ff6 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -34,6 +34,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -137,6 +138,8 @@ fun RequestHandler( val context = LocalContext.current val viewConfiguration = LocalViewConfiguration.current + val onClickEffect = rememberUpdatedState(onClick) + val requestList = formatIconRequestList(iconRequestList) val encodedRequestList = buildForm(requestList.replace("\n", "%20")) @@ -156,7 +159,7 @@ fun RequestHandler( interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> { - onClick() + onClickEffect.value() isLongClick = false delay(viewConfiguration.longPressTimeoutMillis) isLongClick = true diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index 203092dae67..f1beb644910 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -79,15 +79,15 @@ private val coreContributors = listOf( username = "Grabstertv", photoUrl = "https://avatars.githubusercontent.com/u/49114212", socialUrl = "https://x.com/grabstertv", - descriptionRes = R.string.contribution_icons + descriptionRes = R.string.contribution_icons, ), Contributor( name = "Zongle Wang", username = "Goooler", photoUrl = "https://avatars.githubusercontent.com/u/10363352", socialUrl = "https://androiddev.social/@Goooler", - descriptionRes = R.string.contribution_deps - ) + descriptionRes = R.string.contribution_deps, + ), ) private val specialThanks = listOf( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index b6025803b70..2d3324bc45c 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -103,7 +103,7 @@ fun Home( isIconRequestClicked = isIconRequestButtonClicked, onIconRequestClick = { onIconRequestButtonClicked() - } + }, ) } }, From c7ebe6fc1388c4e3bb8b6beffbe0f348e0fea2f6 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:48:15 +0800 Subject: [PATCH 027/144] Update plugin com.google.devtools.ksp to v2.0.0-1.0.24 (#2234) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 379455588c6..ea457890671 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.jetbrains.kotlin.android") version "2.0.0" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" apply false - id("com.google.devtools.ksp") version "2.0.0-1.0.23" apply false + id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false id("com.google.dagger.hilt.android") version "2.51.1" apply false id("app.cash.licensee") version "1.11.0" apply false id("com.diffplug.spotless") version "6.25.0" apply false From ae994fbc1c87c569ae33766e461c355e5ca4dc7b Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 08:51:39 +0800 Subject: [PATCH 028/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.7 (#2232) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index ea457890671..521af850cec 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.5", + "io.nlopez.compose.rules:ktlint:0.4.7", ), ).editorConfigOverride( mapOf( From dca2288614ccf8e87d9ab5799439a294abb20edb Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:30:33 +0300 Subject: [PATCH 029/144] Clarifying the icon update template (#2233) * Clarifying the icon update template * Eliminating name duplication if it has not changed * Placeholder for the Additional Info * Minor fix * new label name * Minor fix * +example * Minor formatting changes --- .github/ISSUE_TEMPLATE/icon_rebrand.yml | 33 +++++++++++-------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/icon_rebrand.yml b/.github/ISSUE_TEMPLATE/icon_rebrand.yml index acf139c33ae..f10cf719359 100644 --- a/.github/ISSUE_TEMPLATE/icon_rebrand.yml +++ b/.github/ISSUE_TEMPLATE/icon_rebrand.yml @@ -1,31 +1,28 @@ -name: Request icon design change -description: Request changing the design of an existing icon in Lawnicons -title: "[Icon Rebrand] " -labels: ["icon rebrand"] +name: Update an existing icon +description: Request changing an icon if it is outdated or applied incorrectly. +labels: ["icon update"] body: - type: textarea id: outdated-icon-list attributes: - label: List of outdated icons + label: Icons description: | - Please follow the following format regarding the outdated icons: + **Please specify for each icon** + - the current application name in Lawnicons (search in [the appfilter.xml](https://github.com/LawnchairLauncher/lawnicons/blob/develop/app/assets/appfilter.xml)); + - [the link to the icon](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs) in Lawnicons; + - the new application name, if changed; + - the image of the new icon. - ``` - App Name - (image to new icon) + **Example** + Twitter, [twitter.svg](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs/) + ↓ + X, [the X logo](https://commons.wikimedia.org/wiki/File:X_logo_2023_original.svg) - App Name - (image to new icon) - ``` - - It is more preferable to link to the outdated icon in [the svgs/ folder](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs) - placeholder: + placeholder: Tell us what should be changed and how validations: required: true - type: textarea id: additional-info attributes: label: Additional information - description: Place additional context here. - validations: - required: true + placeholder: Specify what else is worth considering. For example, the application has a new activity From 5358225cb212d5085b6850aeb711ba3d4f65c0f1 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Tue, 30 Jul 2024 10:41:21 +0300 Subject: [PATCH 030/144] Additional changes for the icon update template (#2235) * One-line example for the icon update template * Updated the link in the repository description --- .github/ISSUE_TEMPLATE/icon_rebrand.yml | 4 +--- README.md | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/icon_rebrand.yml b/.github/ISSUE_TEMPLATE/icon_rebrand.yml index f10cf719359..9e817d426a5 100644 --- a/.github/ISSUE_TEMPLATE/icon_rebrand.yml +++ b/.github/ISSUE_TEMPLATE/icon_rebrand.yml @@ -14,9 +14,7 @@ body: - the image of the new icon. **Example** - Twitter, [twitter.svg](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs/) - ↓ - X, [the X logo](https://commons.wikimedia.org/wiki/File:X_logo_2023_original.svg) + Twitter, [twitter.svg](https://github.com/LawnchairLauncher/lawnicons/tree/develop/svgs/) → X, [the X logo](https://commons.wikimedia.org/wiki/File:X_logo_2023_original.svg) placeholder: Tell us what should be changed and how validations: diff --git a/README.md b/README.md index fe529414eba..5942602f418 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Need help? [Join us on Discord](https://discord.gg/3x8qNWxgGZ). ## Requesting icons Please use **Lawnicons 2.10+**: `Open Lawnicons → Tap "Request icons" → Submit the response`. -You can also use [the icon request form](https://forms.gle/xt7sJhgWEasuo9TR9). If a previously added icon has a design change, create [an issue](https://github.com/LawnchairLauncher/lawnicons/issues). +You can also use [the icon request form](https://forms.gle/xt7sJhgWEasuo9TR9). If a previously added icon has a design change, create [an issue](https://github.com/LawnchairLauncher/lawnicons/issues/new?assignees=&labels=icon+update&projects=&template=icon_rebrand.yml). From bafd800e8052edfcb7a878e3c760d246065f219a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 30 Jul 2024 23:31:32 +0800 Subject: [PATCH 031/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.8 (#2236) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 521af850cec..e72fb3ed8b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.7", + "io.nlopez.compose.rules:ktlint:0.4.8", ), ).editorConfigOverride( mapOf( From 902c1c21046f38a43d8bbe06a14b28102aafad19 Mon Sep 17 00:00:00 2001 From: Hamish <133548095+Hamster45105@users.noreply.github.com> Date: Sat, 3 Aug 2024 20:56:15 +1000 Subject: [PATCH 032/144] + 1 icon, + 1 update (#2231) * + 1 icon * Update ShizuTools icon Closes #2237 * Apply requested changes [1] --- app/assets/appfilter.xml | 3 ++- svgs/claude_by_anthropic.svg | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 svgs/claude_by_anthropic.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 76065105524..e3e00f2874f 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -1933,6 +1933,7 @@ + @@ -8788,7 +8789,7 @@ - + diff --git a/svgs/claude_by_anthropic.svg b/svgs/claude_by_anthropic.svg new file mode 100644 index 00000000000..2637e7f11fb --- /dev/null +++ b/svgs/claude_by_anthropic.svg @@ -0,0 +1,50 @@ + + From 30279db99c079e6623ffdf8c474f1bdf53dd181e Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 3 Aug 2024 14:01:39 +0300 Subject: [PATCH 033/144] +30 links (#2241) --- app/assets/appfilter.xml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index e3e00f2874f..575ca14e6fb 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -703,6 +703,7 @@ + @@ -792,6 +793,7 @@ + @@ -985,6 +987,7 @@ + @@ -1188,6 +1191,7 @@ + @@ -1254,6 +1258,7 @@ + @@ -1427,6 +1432,7 @@ + @@ -1704,6 +1710,7 @@ + @@ -1804,6 +1811,7 @@ + @@ -3118,6 +3126,7 @@ + @@ -4900,6 +4909,7 @@ + @@ -5914,6 +5924,7 @@ + @@ -6463,6 +6474,7 @@ + @@ -6993,6 +7005,7 @@ + @@ -7125,6 +7138,7 @@ + @@ -7182,6 +7196,7 @@ + @@ -7510,6 +7525,7 @@ + @@ -7762,6 +7778,7 @@ + @@ -7858,6 +7875,7 @@ + @@ -7957,6 +7975,7 @@ + @@ -8207,6 +8226,7 @@ + @@ -9401,6 +9421,7 @@ + @@ -9512,6 +9533,7 @@ + @@ -9818,6 +9840,7 @@ + @@ -9961,6 +9984,7 @@ + @@ -10664,6 +10688,7 @@ + @@ -10995,6 +11020,7 @@ + @@ -11737,6 +11763,7 @@ + @@ -11810,6 +11837,7 @@ + @@ -12277,6 +12305,7 @@ + @@ -12287,6 +12316,7 @@ + From 2370331c22f54e0702ee8df7c99631d555542beb Mon Sep 17 00:00:00 2001 From: Albert Koczy Date: Sat, 3 Aug 2024 13:34:28 +0200 Subject: [PATCH 034/144] +1 icon (#2238) * Add VeloBank icon * VeloBank: resize to 160x160, re-draw letters as stroke * Removed the fill from the E * Minor fix --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 1 + svgs/velobank.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 svgs/velobank.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 575ca14e6fb..31ed5d1851b 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -10949,6 +10949,7 @@ + diff --git a/svgs/velobank.svg b/svgs/velobank.svg new file mode 100644 index 00000000000..fad2dec7047 --- /dev/null +++ b/svgs/velobank.svg @@ -0,0 +1 @@ + From 82f70ec0450e4eccb9c89933d086c44cd120d361 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 4 Aug 2024 01:17:05 +0000 Subject: [PATCH 035/144] Update gradle/actions action to v4 (#2242) * Update gradle/actions action to v4 * Apply suggestions from code review --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Zongle Wang --- .github/workflows/build_debug_apk.yml | 7 ++----- .github/workflows/build_release_apk.yml | 3 +-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build_debug_apk.yml b/.github/workflows/build_debug_apk.yml index 92f5fed7ed4..23f1856941b 100644 --- a/.github/workflows/build_debug_apk.yml +++ b/.github/workflows/build_debug_apk.yml @@ -20,10 +20,9 @@ jobs: with: distribution: 'zulu' java-version: 21 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: Da25KUVSE5jbGds2zXmfXw== - gradle-home-cache-cleanup: true - name: Write sign info if: github.repository_owner == 'LawnchairLauncher' run: | @@ -52,9 +51,7 @@ jobs: with: distribution: 'zulu' java-version: 21 - - uses: gradle/actions/setup-gradle@v3 - with: - gradle-home-cache-cleanup: true + - uses: gradle/actions/setup-gradle@v4 - run: ./gradlew spotlessCheck send-notifications: diff --git a/.github/workflows/build_release_apk.yml b/.github/workflows/build_release_apk.yml index 8534bb6b84e..e20ea88a5e6 100644 --- a/.github/workflows/build_release_apk.yml +++ b/.github/workflows/build_release_apk.yml @@ -19,10 +19,9 @@ jobs: with: distribution: 'zulu' java-version: 21 - - uses: gradle/actions/setup-gradle@v3 + - uses: gradle/actions/setup-gradle@v4 with: cache-encryption-key: Da25KUVSE5jbGds2zXmfXw== - gradle-home-cache-cleanup: true - name: Write sign info if: github.repository_owner == 'LawnchairLauncher' run: | From b2e43540fb8a17b686a9bdb8db14e4467e51dc41 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 6 Aug 2024 06:24:56 +0800 Subject: [PATCH 036/144] Add crowdin support Based on Lawnchair's `crowdin.yml` file --- .github/workflows/crowdin.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/crowdin.yml diff --git a/.github/workflows/crowdin.yml b/.github/workflows/crowdin.yml new file mode 100644 index 00000000000..a6283b59565 --- /dev/null +++ b/.github/workflows/crowdin.yml @@ -0,0 +1,33 @@ +name: Crowdin Synchronization + +on: + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + + synchronize-with-crowdin: + name: Synchronize with Crowdin + if: github.repository_owner == 'LawnchairLauncher' + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Sync Translations + uses: crowdin/github-action@v2 + with: + upload_translations: false + upload_sources: true + download_translations: true + localization_branch_name: i18n + create_pull_request: true + base_url: 'https://lawnchair.crowdin.com' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} From 009da5eef49b906a73e48bd6c873bc4be1699555 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 6 Aug 2024 06:28:24 +0800 Subject: [PATCH 037/144] Add crowdin config --- crowdin.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 crowdin.yml diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000000..d2acf316f21 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,5 @@ +project_id_env: CROWDIN_PROJECT_ID +api_token_env: CROWDIN_PERSONAL_TOKEN +files: + - source: /app/src/main/res/values/strings.xml + translation: /app/src/main/res/values-%android_code%/%original_file_name% From 733dcb0ab29601b966eeb16c52998986b9d1f7c0 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 6 Aug 2024 06:38:59 +0800 Subject: [PATCH 038/144] Add crowdin string upload workflow --- .github/workflows/crowdin_upload.yml | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/crowdin_upload.yml diff --git a/.github/workflows/crowdin_upload.yml b/.github/workflows/crowdin_upload.yml new file mode 100644 index 00000000000..ce663f4d22a --- /dev/null +++ b/.github/workflows/crowdin_upload.yml @@ -0,0 +1,32 @@ +name: Crowdin Upload + +on: + push: + branches: + - 'develop' + workflow_dispatch: + +jobs: + + synchronize-with-crowdin: + name: Upload strings to Crowdin + if: github.repository_owner == 'LawnchairLauncher' + runs-on: ubuntu-latest + steps: + + - name: Checkout + uses: actions/checkout@v4 + + - name: Upload Strings + uses: crowdin/github-action@v2 + with: + upload_translations: false + upload_sources: true + download_translations: false + localization_branch_name: i18n + create_pull_request: false + base_url: 'https://lawnchair.crowdin.com' + env: + GITHUB_TOKEN: ${{ secrets.LAWNCHAIR_BOT_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} From 523fba3ff7347b1f56fb1fd3bc27943d62859f03 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 6 Aug 2024 06:45:01 +0800 Subject: [PATCH 039/144] `crowdin.yml` - upload existing translated files --- .github/workflows/crowdin_upload.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/crowdin_upload.yml b/.github/workflows/crowdin_upload.yml index ce663f4d22a..050047e8e37 100644 --- a/.github/workflows/crowdin_upload.yml +++ b/.github/workflows/crowdin_upload.yml @@ -20,7 +20,7 @@ jobs: - name: Upload Strings uses: crowdin/github-action@v2 with: - upload_translations: false + upload_translations: true upload_sources: true download_translations: false localization_branch_name: i18n From 921aa8ade43b616f1a8650005673f02a61b77ed1 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 6 Aug 2024 07:33:39 +0800 Subject: [PATCH 040/144] Temporarily remove translations --- .github/workflows/crowdin_upload.yml | 2 +- app/src/main/res/values-fil/strings.xml | 18 --------- app/src/main/res/values-fr/strings.xml | 53 ------------------------- app/src/main/res/values-hi/strings.xml | 48 ---------------------- app/src/main/res/values-id/strings.xml | 53 ------------------------- app/src/main/res/values-mr/strings.xml | 50 ----------------------- app/src/main/res/values-pl/strings.xml | 53 ------------------------- 7 files changed, 1 insertion(+), 276 deletions(-) delete mode 100644 app/src/main/res/values-fil/strings.xml delete mode 100644 app/src/main/res/values-fr/strings.xml delete mode 100644 app/src/main/res/values-hi/strings.xml delete mode 100644 app/src/main/res/values-id/strings.xml delete mode 100644 app/src/main/res/values-mr/strings.xml delete mode 100644 app/src/main/res/values-pl/strings.xml diff --git a/.github/workflows/crowdin_upload.yml b/.github/workflows/crowdin_upload.yml index 050047e8e37..ce663f4d22a 100644 --- a/.github/workflows/crowdin_upload.yml +++ b/.github/workflows/crowdin_upload.yml @@ -20,7 +20,7 @@ jobs: - name: Upload Strings uses: crowdin/github-action@v2 with: - upload_translations: true + upload_translations: false upload_sources: true download_translations: false localization_branch_name: i18n diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml deleted file mode 100644 index 5b9c30e0627..00000000000 --- a/app/src/main/res/values-fil/strings.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - Bersyon %s - Hanapin sa %d na icons - Walang nahanap na mga icon - Mga pagkilala - Patungkol - Mga nag-aambag - Mga pangunahing tagapag-ambag - "Tingnan ang lahat ng " - Tingnan sa GitHub - Espesyal na pagsasalamat - Sa pagbibigay-inspirasyon sa icon ng app - Sa pagbigay-pangalan sa app - Maaring iguhit - Pakete - Form sa paghiling ng icons - diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml deleted file mode 100644 index 6651d9021f5..00000000000 --- a/app/src/main/res/values-fr/strings.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - Version %s - - - - - - Rechercher parmi %d icônes - - - Aucune icône trouvée - - - - Mentions légales - - À propos - - - - Formulaire de demande d\'icône - - - - - - Contributeurs - - Contributeurs principaux - - Voir tous les contributeurs - - - Voir sur GitHub - - - - Remerciements spéciaux - - Pour avoir inspiré l\'icône de l\'application. - - Pour avoir donné le nom à l\'application. - - - - - - Élément graphique - Application - diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml deleted file mode 100644 index 0d191b5d28c..00000000000 --- a/app/src/main/res/values-hi/strings.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - संस्करण %s - - - - - %d चिन्ह मे से खोजें - - - कोई चिन्ह नहीं मिला - - - - स्वीकृतियाँ - - ऐप के बारे में - - - - चिन्ह अनुरोध प्रपत्र - - - - योगदानकर्ता - - मुख्य योगदानकर्ता - - सभी योगदानकर्ता देखें - - - गिटहब पर देखें - - - - विशेष धन्यवाद - - ऐप के चिन्ह को प्रेरित करने के लिए। - - ऐप का नामकरण करने के लिए। - - - - ड्रॉएबल - - पैकेज - diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml deleted file mode 100644 index 2fc7a1fa03b..00000000000 --- a/app/src/main/res/values-id/strings.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - Versi %s - - - - - - Telusuri melalui %d Ikon - - - Tidak menemukan ikon - - - - Ucapan terima kasih - - Tentang - - - - Permintaan Ikon Dari - - - - - - Kontributor - - Kontributor Inti - - Liat Semua Kontributor - - - Lihat di Github - - - - Terima kasih Khusus - - Untuk inspirasi ikon aplikasi. - - Untuk memberi nama aplikasi. - - - - - Drawable - - Paket nama - diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml deleted file mode 100644 index 8f9291585e7..00000000000 --- a/app/src/main/res/values-mr/strings.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - आवृत्ती %s - - - - - - %d चिन्हांमधून शोधा - - - कोणतेही चिन्ह आढळले नाही - - - - मंजूरी - - अॅप बद्दल - - - - चिन्ह विनंती फॉर्म - - - - योगदानकर्ता - - मुख्य योगदानकर्ता - - सर्व योगदानकर्ते पहा - - - गिटहब वर पहा - - - - विशेष धन्यवाद - - अॅप चिन्ह प्रेरणा देण्यासाठी. - - अॅपला नाव देण्यासाठी. - - - - - ड्रॉएबल - - पैकेज - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml deleted file mode 100644 index 60e066dacef..00000000000 --- a/app/src/main/res/values-pl/strings.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - Wersja %s - - - - - - Przeszukaj %d Ikon - - - Nie znaleziono ikon - - - - Podziękowanie - - O aplikacji - - - - Formularz Zgłoszeniowy Ikony - - - - - - Współautorzy - - Główni współautorzy - - Zobacz wszystkich Współtwórców - - - Zobacz na GitHub - - - - Specjalne podziękowania - - Za zainspirowanie ikony aplikacji. - - Za nazwanie aplikacji. - - - - - Element graficzny - - Pakiet - From ec5819bd22e80adbd59e4669e723c242d6bdf512 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 14:10:25 +0800 Subject: [PATCH 041/144] Update Hilt to v2.52 (#2244) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 619a15f5915..90ecc89007f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -150,7 +150,7 @@ dependencies { implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") - val hiltVersion = "2.51.1" + val hiltVersion = "2.52" implementation("com.google.dagger:hilt-android:$hiltVersion") ksp("com.google.dagger:hilt-compiler:$hiltVersion") implementation("androidx.hilt:hilt-navigation-compose:1.2.0") diff --git a/build.gradle.kts b/build.gradle.kts index e72fb3ed8b5..f11f1d19bd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -7,7 +7,7 @@ plugins { id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" apply false id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false - id("com.google.dagger.hilt.android") version "2.51.1" apply false + id("com.google.dagger.hilt.android") version "2.52" apply false id("app.cash.licensee") version "1.11.0" apply false id("com.diffplug.spotless") version "6.25.0" apply false id("org.gradle.android.cache-fix") version "3.0.1" apply false From 6253dc0e8247b041e057a55331d354af28c49827 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 12:56:59 +0000 Subject: [PATCH 042/144] Update Kotlin to v2.0.10 (#2247) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index f11f1d19bd1..b05624ea1d3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,9 +3,9 @@ import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep plugins { id("com.android.application") version "8.5.1" apply false - id("org.jetbrains.kotlin.android") version "2.0.0" apply false - id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" - id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" apply false + id("org.jetbrains.kotlin.android") version "2.0.10" apply false + id("org.jetbrains.kotlin.plugin.compose") version "2.0.10" + id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" apply false id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false id("com.google.dagger.hilt.android") version "2.52" apply false id("app.cash.licensee") version "1.11.0" apply false From 9c5d15e3f3b4b59a5a5b8da93c8b852aef476df1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 08:03:30 +0800 Subject: [PATCH 043/144] Update plugin com.google.devtools.ksp to v2.0.10-1.0.24 (#2249) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b05624ea1d3..56cc2f9d5db 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.jetbrains.kotlin.android") version "2.0.10" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.10" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" apply false - id("com.google.devtools.ksp") version "2.0.0-1.0.24" apply false + id("com.google.devtools.ksp") version "2.0.10-1.0.24" apply false id("com.google.dagger.hilt.android") version "2.52" apply false id("app.cash.licensee") version "1.11.0" apply false id("com.diffplug.spotless") version "6.25.0" apply false From 08556622b5e7b4a0afa1a80527bf1cc9307ea1b0 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 08:03:39 +0800 Subject: [PATCH 044/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.9 (#2248) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 56cc2f9d5db..b047cee4d8a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.8", + "io.nlopez.compose.rules:ktlint:0.4.9", ), ).editorConfigOverride( mapOf( From 4b8876d499398db0816e60cfb650cc890bf819ee Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:44:12 +0800 Subject: [PATCH 045/144] Update dependency androidx.navigation:navigation-compose to v2.8.0-beta07 (#2251) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 90ecc89007f..6dc4988273d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -144,7 +144,7 @@ dependencies { implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0-beta05") implementation("androidx.compose.material3:material3-window-size-class") - implementation("androidx.navigation:navigation-compose:2.8.0-beta06") + implementation("androidx.navigation:navigation-compose:2.8.0-beta07") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") From 4044db47ef52de64f5c056d98f09d4cfa3578518 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 09:44:21 +0800 Subject: [PATCH 046/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.10 (#2250) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index b047cee4d8a..4f9f9c5ce6c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.9", + "io.nlopez.compose.rules:ktlint:0.4.10", ), ).editorConfigOverride( mapOf( From c6c37998aafaa9fbe8dc29e50a3660dd6ca528eb Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:59:39 +0800 Subject: [PATCH 047/144] Fix bottom bar icon request behavior --- .../ui/components/home/HomeBottomBar.kt | 51 ++------------ .../ui/components/home/IconRequestFAB.kt | 66 +++++++++++++++---- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 33272e9024d..7e4ad6a7ad6 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -13,7 +13,6 @@ import androidx.compose.material3.FloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PlainTooltip import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text @@ -21,12 +20,9 @@ import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequestModel @@ -64,13 +60,12 @@ fun HomeBottomBar( ) } } - IconRequestTooltip(isIconRequestClicked) { - IconRequestIconButton( - iconRequestModel = iconRequestModel, - snackbarHostState = snackbarHostState, - onClick = onIconRequestClick, - ) - } + IconRequestIconButton( + iconRequestModel = iconRequestModel, + snackbarHostState = snackbarHostState, + isIconRequestClicked = isIconRequestClicked, + onClick = onIconRequestClick, + ) SimpleTooltipBox( label = stringResource(id = R.string.about), @@ -125,37 +120,3 @@ private fun SimpleTooltipBox( } } -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun IconRequestTooltip( - isButtonClicked: Boolean, - content: @Composable (() -> Unit), -) { - val state = rememberTooltipState( - initialIsVisible = true, - isPersistent = true, - ) - val hideTooltip = remember { isButtonClicked } - - LaunchedEffect(hideTooltip) { - if (hideTooltip) { - state.dismiss() - } - } - - TooltipBox( - positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), - tooltip = { - PlainTooltip( - containerColor = MaterialTheme.colorScheme.primaryContainer, - contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - caretSize = DpSize(16.dp, 8.dp), - ) { - Text("Request missing icons here") - } - }, - state = state, - ) { - content() - } -} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index caeb92c2ff6..1e922a6e064 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -22,13 +22,18 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text import androidx.compose.material3.TextButton +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateOf @@ -42,6 +47,7 @@ import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequest @@ -85,8 +91,9 @@ fun IconRequestFAB( @Composable fun IconRequestIconButton( - iconRequestModel: IconRequestModel?, + isIconRequestClicked: Boolean, snackbarHostState: SnackbarHostState, + iconRequestModel: IconRequestModel?, onClick: () -> Unit, modifier: Modifier = Modifier, ) { @@ -95,18 +102,55 @@ fun IconRequestIconButton( snackbarHostState = snackbarHostState, onClick = onClick, ) { interactionSource -> - IconButton( - onClick = {}, - interactionSource = interactionSource, - modifier = modifier, - ) { - Icon( - painter = painterResource(id = R.drawable.icon_request_app), - contentDescription = stringResource(R.string.request_icons), - modifier = Modifier.requiredSize(24.dp), - ) + IconRequestTooltip(isIconRequestClicked) { + IconButton( + onClick = {}, + interactionSource = interactionSource, + modifier = modifier, + ) { + Icon( + painter = painterResource(id = R.drawable.icon_request_app), + contentDescription = stringResource(R.string.request_icons), + modifier = Modifier.requiredSize(24.dp), + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun IconRequestTooltip( + isButtonClicked: Boolean, + content: @Composable (() -> Unit), +) { + val state = rememberTooltipState( + initialIsVisible = true, + isPersistent = true, + ) + val hideTooltip = remember { isButtonClicked } + + LaunchedEffect(hideTooltip) { + if (hideTooltip) { + state.dismiss() } } + + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip( + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + caretSize = DpSize(16.dp, 8.dp), + ) { + Text("Request missing icons here") + } + }, + state = state, + ) { + content() + } } @Composable From e8aec608c493118c13e69bb3114d9e189a8c2727 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:15:22 +0800 Subject: [PATCH 048/144] Bump versionName and code --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6dc4988273d..cf40ff1629a 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,7 +26,7 @@ val ciRunNumber = providers.environmentVariable("GITHUB_RUN_NUMBER").orNull.orEm val isReleaseBuild = ciBuild && ciRef.contains("main") val devReleaseName = if (ciBuild) "(Dev #$ciRunNumber)" else "($buildCommit)" -val version = "2.10.1" +val version = "2.11.0" val versionDisplayName = "$version ${if (isReleaseBuild) "" else devReleaseName}" android { @@ -37,7 +37,7 @@ android { applicationId = "app.lawnchair.lawnicons" minSdk = 26 targetSdk = compileSdk - versionCode = 14 + versionCode = 15 versionName = versionDisplayName vectorDrawables.useSupportLibrary = true } From 7b8183612692cd33a0d10191e3dffa1ce9114b86 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:22:01 +0800 Subject: [PATCH 049/144] Fix style --- .../app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 7e4ad6a7ad6..1e36ca1eee5 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -119,4 +119,3 @@ private fun SimpleTooltipBox( content() } } - From 38ec700cc91ac53526e4b54f89f3dfcc52885435 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Fri, 9 Aug 2024 14:38:05 +0300 Subject: [PATCH 050/144] +21 links, Asphalt icon update (#2253) * +21 links, Asphalt icon update * +new links --- app/assets/appfilter.xml | 25 +++++++++++++++++++++++-- svgs/asphalt_9_legends.svg | 1 - svgs/asphalt_legends_unite.svg | 1 + 3 files changed, 24 insertions(+), 3 deletions(-) delete mode 100644 svgs/asphalt_9_legends.svg create mode 100644 svgs/asphalt_legends_unite.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 31ed5d1851b..a50d84f2db4 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -417,6 +417,7 @@ + @@ -569,6 +570,7 @@ + @@ -679,8 +681,8 @@ - - + + @@ -1303,6 +1305,7 @@ + @@ -1836,6 +1839,7 @@ + @@ -2566,6 +2570,7 @@ + @@ -3887,6 +3892,7 @@ + @@ -5473,6 +5479,7 @@ + @@ -5562,6 +5569,7 @@ + @@ -5968,6 +5976,7 @@ + @@ -6020,6 +6029,7 @@ + @@ -6452,6 +6462,7 @@ + @@ -7447,6 +7458,7 @@ + @@ -7461,6 +7473,7 @@ + @@ -7875,6 +7888,7 @@ + @@ -9418,6 +9432,7 @@ + @@ -9950,6 +9965,7 @@ + @@ -10503,6 +10519,7 @@ + @@ -10549,6 +10566,7 @@ + @@ -11679,6 +11697,7 @@ + @@ -11838,6 +11857,7 @@ + @@ -11991,6 +12011,7 @@ + diff --git a/svgs/asphalt_9_legends.svg b/svgs/asphalt_9_legends.svg deleted file mode 100644 index 1a8a510d3c2..00000000000 --- a/svgs/asphalt_9_legends.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/svgs/asphalt_legends_unite.svg b/svgs/asphalt_legends_unite.svg new file mode 100644 index 00000000000..f7890a3fecc --- /dev/null +++ b/svgs/asphalt_legends_unite.svg @@ -0,0 +1 @@ + \ No newline at end of file From 5d8a91021ade60f308c3289b7c28f73cb99dfa8f Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 9 Aug 2024 21:38:32 +0800 Subject: [PATCH 051/144] Polish UI and UX --- .../GitHubContributorsRepository.kt | 2 + .../ui/components/home/HomeBottomBar.kt | 2 +- .../ui/components/home/HomeTopBar.kt | 88 +++++++------------ .../ui/components/home/IconPreviewGrid.kt | 58 ++++++++++-- .../ui/components/home/search/SearchBar.kt | 59 ++++++++----- .../lawnicons/ui/destination/About.kt | 7 ++ .../lawnicons/ui/destination/Home.kt | 57 +++++------- app/src/main/res/drawable/about_icon.xml | 9 ++ 8 files changed, 163 insertions(+), 119 deletions(-) create mode 100644 app/src/main/res/drawable/about_icon.xml diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt index 9b5f2bba583..4da1d6b3b7b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/GitHubContributorsRepository.kt @@ -12,6 +12,8 @@ val coreContributorIds = listOf( 8080853, // SuperDragonXD 70206496, + // Chefski + 100310118, // x9136 60105060, // Goooler diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 1e36ca1eee5..623dc18e200 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -72,7 +72,7 @@ fun HomeBottomBar( ) { IconButton(onClick = onNavigate) { Icon( - painter = painterResource(id = R.drawable.contacts_foreground), + painter = painterResource(id = R.drawable.about_icon), contentDescription = stringResource(id = R.string.about), modifier = Modifier.requiredSize(24.dp), ) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt index 9a5da94b14f..cd1c1021216 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt @@ -1,27 +1,17 @@ package app.lawnchair.lawnicons.ui.components.home -import androidx.compose.animation.AnimatedContent -import androidx.compose.foundation.Image +import androidx.compose.animation.core.animateDpAsState import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.material3.CenterAlignedTopAppBar -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.foundation.layout.offset import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester -import androidx.compose.ui.graphics.ImageBitmap -import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.IconInfoModel import app.lawnchair.lawnicons.model.SearchMode @@ -35,11 +25,9 @@ data class HomeTopBarUiState( val searchMode: SearchMode, val searchedIconInfoModel: IconInfoModel?, val isIconPicker: Boolean, - val appIcon: ImageBitmap, ) @Composable -@OptIn(ExperimentalMaterial3Api::class) fun HomeTopBar( uiState: HomeTopBarUiState, onFocusChange: () -> Unit, @@ -49,49 +37,39 @@ fun HomeTopBar( onNavigate: () -> Unit, onSendResult: (IconInfo) -> Unit, focusRequester: FocusRequester, - scrollBehavior: TopAppBarScrollBehavior, modifier: Modifier = Modifier, ) { - val (isSearchExpanded, isExpandedScreen, searchTerm, searchMode, searchedIconInfoModel, isIconPicker, appIcon) = uiState + val (isSearchExpanded, isExpandedScreen, searchTerm, searchMode, searchedIconInfoModel, isIconPicker) = uiState - AnimatedContent(targetState = isSearchExpanded || isExpandedScreen, label = "TopAppBar to SearchBar", modifier = modifier) { targetState -> - if (targetState) { - searchedIconInfoModel?.let { - SearchBar( - searchTerm = searchTerm, - onClearSearch = onClearSearch, - onChangeMode = onChangeMode, - onSearch = onSearchIcons, - iconInfoModel = it, - onNavigate = onNavigate, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, - searchMode = searchMode, - onSendResult = onSendResult, - onFocusChange = onFocusChange, - inputFieldModifier = Modifier.focusRequester(focusRequester), - ) - } + val condition = isSearchExpanded || isExpandedScreen + + val offset = animateDpAsState( + targetValue = if (condition) { + 0.dp } else { - CenterAlignedTopAppBar( - scrollBehavior = scrollBehavior, - title = { - Row( - verticalAlignment = Alignment.CenterVertically, - ) { - Image( - bitmap = appIcon, - contentDescription = stringResource(id = R.string.app_name), - modifier = Modifier.size(36.dp), - ) - Spacer(modifier = Modifier.width(8.dp)) - Text( - stringResource(id = R.string.app_name), - ) - } + (-100).dp + }, + label = "move search bar", + ) + searchedIconInfoModel?.let { + SearchBar( + modifier = modifier + .offset { + IntOffset(0, offset.value.roundToPx()) }, - ) - } + searchTerm = searchTerm, + onClearSearch = onClearSearch, + onChangeMode = onChangeMode, + onSearch = onSearchIcons, + iconInfoModel = it, + onNavigate = onNavigate, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + searchMode = searchMode, + onSendResult = onSendResult, + onFocusChange = onFocusChange, + inputFieldModifier = Modifier.focusRequester(focusRequester), + ) } } @@ -119,8 +97,10 @@ private fun SearchBar( LawniconsSearchBar( query = searchTerm, isQueryEmpty = searchTerm == "", - onClearAndBackClick = { + onClear = { onClearSearch() + }, + onBack = { onFocusChange() }, onQueryChange = { newValue -> diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 7c7ec33072c..3f755301961 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -1,38 +1,49 @@ package app.lawnchair.lawnicons.ui.components.home import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandHorizontally import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut -import androidx.compose.animation.shrinkHorizontally import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData import app.lawnchair.lawnicons.ui.util.toPaddingValues +import app.lawnchair.lawnicons.util.appIcon import kotlinx.collections.immutable.ImmutableList import my.nanihadesuka.compose.LazyVerticalGridScrollbar import my.nanihadesuka.compose.ScrollbarSelectionMode @@ -59,7 +70,9 @@ fun IconPreviewGrid( .widthIn(max = 640.dp) .fillMaxWidth() .statusBarsPadding() - .padding(top = 26.dp), + .then( + if (isExpandedScreen) Modifier.padding(top = 26.dp) else Modifier, + ), state = gridState, settings = ScrollbarSettings( alwaysShowScrollbar = true, @@ -70,8 +83,8 @@ fun IconPreviewGrid( indicatorContent = { _, isThumbSelected -> AnimatedVisibility( visible = isThumbSelected, - enter = fadeIn() + expandHorizontally(), - exit = fadeOut() + shrinkHorizontally(), + enter = fadeIn(), + exit = fadeOut(), ) { Box( modifier = Modifier @@ -96,11 +109,20 @@ fun IconPreviewGrid( columns = GridCells.Adaptive(minSize = 80.dp), contentPadding = contentPadding ?: WindowInsets.navigationBars.toPaddingValues( additionalStart = horizontalGridPadding, - additionalTop = 42.dp, + additionalTop = if (isExpandedScreen) 42.dp else 0.dp, additionalEnd = horizontalGridPadding, ), state = gridState, ) { + if (!isExpandedScreen) { + item( + span = { + GridItemSpan(maxLineSpan) + }, + ) { + TopAppBar() + } + } items( items = iconInfo, contentType = { "icon_preview" }, @@ -116,6 +138,30 @@ fun IconPreviewGrid( } } +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun TopAppBar(modifier: Modifier = Modifier) { + val context = LocalContext.current + CenterAlignedTopAppBar( + modifier = modifier, + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Image( + bitmap = context.appIcon().asImageBitmap(), + contentDescription = stringResource(id = R.string.app_name), + modifier = Modifier.size(36.dp), + ) + Spacer(modifier = Modifier.width(8.dp)) + Text( + stringResource(id = R.string.app_name), + ) + } + }, + ) +} + @OptIn(ExperimentalFoundationApi::class) @PreviewLawnicons @Composable diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt index 6dbb88bd124..435cd245b92 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt @@ -53,7 +53,8 @@ import app.lawnchair.lawnicons.ui.util.toPaddingValues fun LawniconsSearchBar( query: String, isQueryEmpty: Boolean, - onClearAndBackClick: () -> Unit, + onClear: () -> Unit, + onBack: () -> Unit, onQueryChange: (String) -> Unit, iconInfoModel: IconInfoModel, onNavigate: () -> Unit, @@ -66,7 +67,8 @@ fun LawniconsSearchBar( LawniconsSearchBar( query = query, isQueryEmpty = isQueryEmpty, - onClearAndBackClick = onClearAndBackClick, + onClear = onClear, + onBack = onBack, onQueryChange = onQueryChange, iconCount = iconInfoModel.iconCount, onNavigate = onNavigate, @@ -83,7 +85,8 @@ fun LawniconsSearchBar( * * @param query The current search query entered by the user. * @param isQueryEmpty A boolean value indicating whether the search query is empty. - * @param onClearAndBackClick A callback function that handles clearing the search query and navigating back. + * @param onClear A callback function that handles clearing the search query. + * @param onBack A callback function that handles navigating back. * @param onQueryChange A callback function that handles changes in the search query. * @param iconCount The number of icons available for selection. * @param onNavigate A callback function that handles navigation to different screens based on the search query. @@ -96,7 +99,8 @@ fun LawniconsSearchBar( fun LawniconsSearchBar( query: String, isQueryEmpty: Boolean, - onClearAndBackClick: () -> Unit, + onClear: () -> Unit, + onBack: () -> Unit, onQueryChange: (String) -> Unit, iconCount: Int, onNavigate: () -> Unit, @@ -112,7 +116,7 @@ fun LawniconsSearchBar( modifier = modifier .animateContentSize() .then( - if (!active || isExpandedScreen) { + if (isExpandedScreen) { Modifier .padding( WindowInsets.navigationBars.toPaddingValues( @@ -140,7 +144,7 @@ fun LawniconsSearchBar( onActiveChange = { active = it if (!active) { - onClearAndBackClick() + onBack() } }, placeholder = { @@ -159,7 +163,7 @@ fun LawniconsSearchBar( SearchIcon( active = active, onButtonClick = { - onClearAndBackClick() + onBack() active = !active }, ) @@ -168,8 +172,23 @@ fun LawniconsSearchBar( if (!isIconPicker) { SearchActionButton( isQueryEmpty = isQueryEmpty, + navigateContent = { + if (isExpandedScreen) { + IconButton( + onClick = it, + ) { + Icon( + imageVector = ImageVector.vectorResource(id = R.drawable.lawnicons_foreground), + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier + .size(24.dp), + ) + } + } + }, onNavigate = onNavigate, - onClearAndBackClick = onClearAndBackClick, + onClear = onClear, ) } }, @@ -267,25 +286,16 @@ internal fun SearchIcon( @Composable internal fun SearchActionButton( isQueryEmpty: Boolean, + navigateContent: @Composable (() -> Unit) -> Unit, onNavigate: () -> Unit, - onClearAndBackClick: () -> Unit, + onClear: () -> Unit, ) { Crossfade(isQueryEmpty, label = "") { if (it) { - IconButton( - onClick = onNavigate, - ) { - Icon( - imageVector = ImageVector.vectorResource(id = R.drawable.lawnicons_foreground), - contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, - modifier = Modifier - .size(24.dp), - ) - } + navigateContent(onNavigate) } else { ClickableIcon( - onClick = onClearAndBackClick, + onClick = onClear, imageVector = Icons.Rounded.Close, ) } @@ -302,7 +312,8 @@ private fun SearchBarPreview() { LawniconsSearchBar( query = searchTerm, isQueryEmpty = false, - onClearAndBackClick = {}, + onClear = {}, + onBack = {}, onQueryChange = { newValue -> searchTerm = newValue }, @@ -337,8 +348,8 @@ private fun SearchIconPreview() { private fun SearchActionButtonPreview() { LawniconsTheme { Column { - SearchActionButton(isQueryEmpty = false, {}, {}) - SearchActionButton(isQueryEmpty = true, {}, {}) + SearchActionButton(isQueryEmpty = false, {}, {}, {}) + SearchActionButton(isQueryEmpty = true, {}, {}, {}) } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index f1beb644910..e5ae792bf97 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -67,6 +67,13 @@ private val coreContributors = listOf( socialUrl = "https://github.com/SuperDragonXD", descriptionRes = R.string.contribution_core, ), + Contributor( + name = "Patryk Radziszewski", + username = "Chefski", + photoUrl = "https://avatars.githubusercontent.com/u/100310118", + socialUrl = "https://github.com/Chefski", + descriptionRes = R.string.contribution_icons, + ), Contributor( name = "Gleb", username = "x9136", diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 2d3324bc45c..111e8127e87 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -1,13 +1,12 @@ package app.lawnchair.lawnicons.ui.destination +import android.annotation.SuppressLint import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.lazy.grid.rememberLazyGridState -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState -import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -16,8 +15,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.graphics.asImageBitmap -import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -34,11 +31,11 @@ import app.lawnchair.lawnicons.ui.components.home.search.SearchContents import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData -import app.lawnchair.lawnicons.util.appIcon import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel import kotlinx.collections.immutable.toImmutableList -@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@OptIn(ExperimentalFoundationApi::class) @Composable fun Home( onNavigate: () -> Unit, @@ -55,13 +52,12 @@ fun Home( val searchMode = searchMode val searchTerm = searchTerm - val expandSearch = remember { mutableStateOf(false) } + var expandSearch by remember { mutableStateOf(false) } val context = LocalContext.current val lazyGridState = rememberLazyGridState() val snackbarHostState = remember { SnackbarHostState() } - val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior() val focusRequester = remember { FocusRequester() } Crossfade( @@ -74,22 +70,20 @@ fun Home( topBar = { HomeTopBar( uiState = HomeTopBarUiState( - isSearchExpanded = expandSearch.value, + isSearchExpanded = expandSearch, isExpandedScreen = isExpandedScreen, searchedIconInfoModel = searchedIconInfoModel, searchTerm = searchTerm, searchMode = searchMode, isIconPicker = isIconPicker, - appIcon = context.appIcon().asImageBitmap(), ), - onFocusChange = { expandSearch.value = !expandSearch.value }, - onClearSearch = { clearSearch() }, - onChangeMode = { changeMode(it) }, - onSearchIcons = { searchIcons(it) }, + onFocusChange = { expandSearch = !expandSearch }, + onClearSearch = ::clearSearch, + onChangeMode = ::changeMode, + onSearchIcons = ::searchIcons, onNavigate = onNavigate, onSendResult = onSendResult, focusRequester = focusRequester, - scrollBehavior = scrollBehavior, ) }, bottomBar = { @@ -99,11 +93,9 @@ fun Home( iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, onNavigate = onNavigate, - onExpandSearch = { expandSearch.value = !expandSearch.value }, + onExpandSearch = { expandSearch = true }, isIconRequestClicked = isIconRequestButtonClicked, - onIconRequestClick = { - onIconRequestButtonClicked() - }, + onIconRequestClick = ::onIconRequestButtonClicked, ) } }, @@ -119,18 +111,14 @@ fun Home( snackbarHost = { SnackbarHost(hostState = snackbarHostState) }, - modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), - ) { contentPadding -> - iconInfoModel.let { - val padding = contentPadding // Ignore padding value - IconPreviewGrid( - iconInfo = it.iconInfo, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, - onSendResult = onSendResult, - gridState = lazyGridState, - ) - } + ) { + IconPreviewGrid( + iconInfo = iconInfoModel.iconInfo, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + gridState = lazyGridState, + ) } } else { PlaceholderSearchBar( @@ -138,8 +126,8 @@ fun Home( ) } } - LaunchedEffect(expandSearch.value) { - if (expandSearch.value) { + LaunchedEffect(expandSearch) { + if (expandSearch) { focusRequester.requestFocus() } } @@ -157,9 +145,10 @@ private fun HomePreview() { LawniconsSearchBar( query = searchTerm, isQueryEmpty = searchTerm == "", - onClearAndBackClick = { + onClear = { searchTerm = "" }, + onBack = {}, onQueryChange = { newValue -> searchTerm = newValue // No actual searching, this is just a preview diff --git a/app/src/main/res/drawable/about_icon.xml b/app/src/main/res/drawable/about_icon.xml new file mode 100644 index 00000000000..e176b71f4d3 --- /dev/null +++ b/app/src/main/res/drawable/about_icon.xml @@ -0,0 +1,9 @@ + + + From 7881a51540c4196dd0c8cd98c82c665c12351bd6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:18:07 +0800 Subject: [PATCH 052/144] New Crowdin translations by GitHub Action (#2255) Co-authored-by: Crowdin Bot --- app/src/main/res/values-af-rZA/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ar-rSA/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ca-rES/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-cs-rCZ/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-da-rDK/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-de-rDE/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-el-rGR/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-en-rUS/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-es-rES/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-fi-rFI/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-fil-rPH/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-fr-rFR/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-hi-rIN/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-hu-rHU/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-in-rID/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-it-rIT/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-iw-rIL/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ja-rJP/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ko-rKR/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-mr-rIN/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-nl-rNL/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-no-rNO/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-pl-rPL/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-pt-rBR/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-pt-rPT/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ro-rRO/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-ru-rRU/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-sv-rSE/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-tr-rTR/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-uk-rUA/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-vi-rVN/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 66 +++++++++++++++++++++ app/src/main/res/values-zh-rTW/strings.xml | 66 +++++++++++++++++++++ 33 files changed, 2178 insertions(+) create mode 100644 app/src/main/res/values-af-rZA/strings.xml create mode 100644 app/src/main/res/values-ar-rSA/strings.xml create mode 100644 app/src/main/res/values-ca-rES/strings.xml create mode 100644 app/src/main/res/values-cs-rCZ/strings.xml create mode 100644 app/src/main/res/values-da-rDK/strings.xml create mode 100644 app/src/main/res/values-de-rDE/strings.xml create mode 100644 app/src/main/res/values-el-rGR/strings.xml create mode 100644 app/src/main/res/values-en-rUS/strings.xml create mode 100644 app/src/main/res/values-es-rES/strings.xml create mode 100644 app/src/main/res/values-fi-rFI/strings.xml create mode 100644 app/src/main/res/values-fil-rPH/strings.xml create mode 100644 app/src/main/res/values-fr-rFR/strings.xml create mode 100644 app/src/main/res/values-hi-rIN/strings.xml create mode 100644 app/src/main/res/values-hu-rHU/strings.xml create mode 100644 app/src/main/res/values-in-rID/strings.xml create mode 100644 app/src/main/res/values-it-rIT/strings.xml create mode 100644 app/src/main/res/values-iw-rIL/strings.xml create mode 100644 app/src/main/res/values-ja-rJP/strings.xml create mode 100644 app/src/main/res/values-ko-rKR/strings.xml create mode 100644 app/src/main/res/values-mr-rIN/strings.xml create mode 100644 app/src/main/res/values-nl-rNL/strings.xml create mode 100644 app/src/main/res/values-no-rNO/strings.xml create mode 100644 app/src/main/res/values-pl-rPL/strings.xml create mode 100644 app/src/main/res/values-pt-rBR/strings.xml create mode 100644 app/src/main/res/values-pt-rPT/strings.xml create mode 100644 app/src/main/res/values-ro-rRO/strings.xml create mode 100644 app/src/main/res/values-ru-rRU/strings.xml create mode 100644 app/src/main/res/values-sv-rSE/strings.xml create mode 100644 app/src/main/res/values-tr-rTR/strings.xml create mode 100644 app/src/main/res/values-uk-rUA/strings.xml create mode 100644 app/src/main/res/values-vi-rVN/strings.xml create mode 100644 app/src/main/res/values-zh-rCN/strings.xml create mode 100644 app/src/main/res/values-zh-rTW/strings.xml diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml new file mode 100644 index 00000000000..680cb8e8e1c --- /dev/null +++ b/app/src/main/res/values-af-rZA/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Soek + + %s not found + + Oor + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Icons + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml new file mode 100644 index 00000000000..e613c59d823 --- /dev/null +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + البحث + + %s not found + + حول التطبيق + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + الأيقونات + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml new file mode 100644 index 00000000000..fda7534543c --- /dev/null +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Cerca + + %s not found + + Quant a + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Icones + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml new file mode 100644 index 00000000000..0e32a08e8e1 --- /dev/null +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Vyhledávání + + %s not found + + O aplikaci + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ikony + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml new file mode 100644 index 00000000000..d8c6f75ccb5 --- /dev/null +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Søg + + %s not found + + Om + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ikoner + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml new file mode 100644 index 00000000000..f2139d339b6 --- /dev/null +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Durchsuche %d Symbole + Symbol auswählen + + Suchen + + %s nicht gefunden + + Über + + + + Symbol-Anfrageformular + + + Mitwirkende + + Hauptbeteiligte Mitwirkende + + Alle Mitwirkenden ansehen + + Auf GitHub ansehen + + Details teilen + + Kern-App + Symbole + Abhängigkeiten + + + Besonderer Dank + + Für die Inspiration des App-Symbols + + Für den App-Namen + + Open-Source-Lizenzen + + + Name + + Drawable + + Name der Komponente + + Zugewiesene Komponenten + + Wenn das Symbol aufgrund eines Neu-Brandings veraltet ist, eröffne ein Issue auf GitHub. + + Inhalte ein-/ausblenden + + Symbole anfragen + In Zwischenablage kopieren + Text kopiert + + Details der Symbolanfrage in die Zwischenablage kopiert. Um sie anzufragen, übertrage die Details in das Formular. + Formular öffnen + diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml new file mode 100644 index 00000000000..bdcfc182cc9 --- /dev/null +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Αναζήτηση + + %s not found + + Πληροφορίες + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Εικονίδια + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 00000000000..7823eaee94c --- /dev/null +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Search + + %s not found + + About + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Icons + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml new file mode 100644 index 00000000000..419742f5126 --- /dev/null +++ b/app/src/main/res/values-es-rES/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Buscar + + %s not found + + Acerca de + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Iconos + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml new file mode 100644 index 00000000000..92ae1aa4582 --- /dev/null +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Hae + + %s not found + + Tietoja + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Kuvakkeet + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-fil-rPH/strings.xml b/app/src/main/res/values-fil-rPH/strings.xml new file mode 100644 index 00000000000..34d46654429 --- /dev/null +++ b/app/src/main/res/values-fil-rPH/strings.xml @@ -0,0 +1,66 @@ + + + + + + Bersyon %s + + + + Hanapin sa %d na icons + Pumili ng icon + + Maghanap + + Walang nahanap na mga icon + + Patungkol + + + + Form sa paghiling ng icons + + + Mga nag-aambag + + Mga pangunahing tagapag-ambag + + Tingnan ang lahat ng tagapag-ambag + + Tingnan sa GitHub + + Ibahagi ang detalye + + Core app + Mga Icon + Dependencies + + + Espesyal na pagsasalamat + + Sa pagbibigay-inspirasyon sa icon ng app + + Sa pagbigay-pangalan sa app + + Mga pagkilala + + + Pangalan + + Maaring iguhit + + Pangalan ng component + + Pakete + + Kung ang icon ay luma na dahil sa rebranding, gumawa ng isyu sa GitHub. + + I-toggle ang bisibilidad ng mga content + + Maghiling ng icons + Kopyahin sa clipboard + Kinopya ang teksto + + Nakopya na ang mga detalye tungkol sa ihihiling na icons sa clipboard. Upang hilingin ang mga ito, isumite ang mga detalye sa form. + Buksan ang form + diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml new file mode 100644 index 00000000000..4418dc73661 --- /dev/null +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Rechercher parmi %d icônes + Pick an icon + + Recherche + + Aucune icône trouvée + + À propos + + + + Formulaire de demande d\'icône + + + Contributeurs + + Contributeurs principaux + + Voir tous les contributeurs + + Voir sur GitHub + + Share details + + Core app + Icônes + Dependencies + + + Remerciements spéciaux + + Pour avoir inspiré l\'icône de l\'application. + + Pour avoir donné le nom à l\'application. + + Mentions légales + + + Name + + Élément graphique + + Component name + + Application + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 00000000000..bdf5ded2ef3 --- /dev/null +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,66 @@ + + + + + + संस्करण %s + + + + %d चिन्ह मे से खोजें + Pick an icon + + खोजें + + कोई चिन्ह नहीं मिला + + ऐप के बारे में + + + + चिन्ह अनुरोध प्रपत्र + + + योगदानकर्ता + + मुख्य योगदानकर्ता + + सभी योगदानकर्ता देखें + + गिटहब पर देखें + + Share details + + Core app + चिह्न + Dependencies + + + विशेष धन्यवाद + + ऐप के चिन्ह को प्रेरित करने के लिए। + + ऐप का नामकरण करने के लिए। + + स्वीकृतियाँ + + + Name + + ड्रॉएबल + + Component name + + पैकेज + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml new file mode 100644 index 00000000000..ea13a9c6a7a --- /dev/null +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Keresés + + %s not found + + Névjegy + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ikonok + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml new file mode 100644 index 00000000000..1a1b8444c89 --- /dev/null +++ b/app/src/main/res/values-in-rID/strings.xml @@ -0,0 +1,66 @@ + + + + + + Versi %s + + + + Telusuri melalui %d Ikon + Pick an icon + + Cari + + Tidak menemukan ikon + + Tentang + + + + Permintaan Ikon Dari + + + Kontributor + + Kontributor Inti + + Liat Semua Kontributor + + Lihat di Github + + Share details + + Core app + Ikon + Dependencies + + + Terima kasih Khusus + + Untuk inspirasi ikon aplikasi. + + Untuk memberi nama aplikasi. + + Ucapan terima kasih + + + Name + + Drawable + + Component name + + Paket nama + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml new file mode 100644 index 00000000000..715511adeea --- /dev/null +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Ricerca + + %s not found + + Informazioni + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Icone + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml new file mode 100644 index 00000000000..79c06deb07b --- /dev/null +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + חיפוש + + %s not found + + אודות + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + סמלים + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml new file mode 100644 index 00000000000..b1f22fed11c --- /dev/null +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + 検索 + + %s not found + + このアプリについて + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + アイコン + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml new file mode 100644 index 00000000000..bf143a3833c --- /dev/null +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -0,0 +1,66 @@ + + + + + + 버전 %s + + + + %d개의 아이콘 중 검색 + 아이콘 선택 + + 검색 + + %s 아이콘을 찾을 수 없습니다. + + 더 보기 + + + + 아이콘 요청 폼 + + + 기여자 + + 주요 기여자 + + 전체 기여자 보기 + + GitHub에서 보기 + + 세부 정보 공유 + + 코어 앱 + 아이콘 + 의존성 라이브러리 + + + Special thanks + + For inspiring the app icon + + For naming the app + + 오픈 소스 라이선스 + + + 이름 + + Drawable + + 컴포넌트 이름 + + Mapped components + + 앱 리브랜딩으로 아이콘이 바뀌었다면 GitHub에 이슈를 등록해 주세요. + + Toggle visibility of contents + + 아이콘 요청 + 클립보드에 복사 + 텍스트를 복사했습니다. + + 아이콘 요청 정보를 클립보드에 복사했습니다. 아이콘을 요청하려면 세부 정보를 폼에 입력하세요. + 폼 열기 + diff --git a/app/src/main/res/values-mr-rIN/strings.xml b/app/src/main/res/values-mr-rIN/strings.xml new file mode 100644 index 00000000000..ddde439db36 --- /dev/null +++ b/app/src/main/res/values-mr-rIN/strings.xml @@ -0,0 +1,66 @@ + + + + + + आवृत्ती %s + + + + %d चिन्हांमधून शोधा + Pick an icon + + Search + + कोणतेही चिन्ह आढळले नाही + + अॅप बद्दल + + + + चिन्ह विनंती फॉर्म + + + योगदानकर्ता + + मुख्य योगदानकर्ता + + सर्व योगदानकर्ते पहा + + गिटहब वर पहा + + Share details + + Core app + चिन्हे + Dependencies + + + विशेष धन्यवाद + + अॅप चिन्ह प्रेरणा देण्यासाठी. + + अॅपला नाव देण्यासाठी. + + मंजूरी + + + Name + + ड्रॉएबल + + Component name + + पैकेज + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml new file mode 100644 index 00000000000..ed7f5e8254d --- /dev/null +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Zoeken + + %s not found + + Over + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Pictogrammen + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml new file mode 100644 index 00000000000..bb49477c568 --- /dev/null +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Search + + %s not found + + Om + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ikoner + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml new file mode 100644 index 00000000000..8c515dfff7a --- /dev/null +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -0,0 +1,66 @@ + + + + + + Wersja %s + + + + Przeszukaj %d Ikon + Pick an icon + + Szukaj + + Nie znaleziono ikon + + O aplikacji + + + + Formularz Zgłoszeniowy Ikony + + + Współautorzy + + Główni współautorzy + + Zobacz wszystkich Współtwórców + + Zobacz na GitHub + + Share details + + Core app + Ikony + Dependencies + + + Specjalne podziękowania + + Za zainspirowanie ikony aplikacji. + + Za nazwanie aplikacji. + + Podziękowanie + + + Name + + Element graficzny + + Component name + + Pakiet + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 00000000000..09a4d4bf363 --- /dev/null +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Pesquisar + + %s not found + + Sobre + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ícones + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml new file mode 100644 index 00000000000..09a4d4bf363 --- /dev/null +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Pesquisar + + %s not found + + Sobre + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ícones + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml new file mode 100644 index 00000000000..6ab1eb1b78c --- /dev/null +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Caută + + %s not found + + Despre + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Pictograme + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml new file mode 100644 index 00000000000..624da4179d8 --- /dev/null +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Поиск + + %s not found + + О программе + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Иконки + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml new file mode 100644 index 00000000000..0be8e30f06b --- /dev/null +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Sök + + %s not found + + Om + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Ikoner + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml new file mode 100644 index 00000000000..b0178be1bf8 --- /dev/null +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Ara + + %s not found + + Hakkında + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Resimleyici + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml new file mode 100644 index 00000000000..de18cdc6fe3 --- /dev/null +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -0,0 +1,66 @@ + + + + + + Версія %s + + + + Шукати за %d значками + Вибрати іконку + + Пошук + + %s не знайдено + + Про додаток + + + + Форма запиту іконок + + + Автори + + Учасники проекту + + Переглянути всіх учасників + + Переглянути на GitHub + + Поділитися подробицями + + Головний додаток + Значки + Залежності + + + Особлива подяка + + Що надихнули іконку застосунка + + За назву застосунку + + Ліцензії ПЗ з відкритим вихідним кодом + + + Ім\'я + + Малюнок + + Назва компонента + + Зіставлені компоненти + + Якщо іконка застаріла через ребрендінг, створіть проблему на GitHub. + + Перемкнути видимість вмісту + + Запит іконок + Скопіювати до буфера обміну + Скопійований текст + + Скопійовано подробиці до буфера обміну. Щоб зробити запит, додайте деталі у форму. + Відкрити форму + diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml new file mode 100644 index 00000000000..d74e329d5a2 --- /dev/null +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + Tìm kiếm + + %s not found + + Giới thiệu + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + Biểu tượng + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 00000000000..5351f587b8b --- /dev/null +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + 搜索 + + %s not found + + 关于 + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + 图标 + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 00000000000..46033a92969 --- /dev/null +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,66 @@ + + + + + + Version %s + + + + Search through %d icons + Pick an icon + + 搜尋 + + %s not found + + 關於 + + + + Icon request form + + + Contributors + + Core contributors + + See all contributors + + View on GitHub + + Share details + + Core app + 圖示 + Dependencies + + + Special thanks + + For inspiring the app icon + + For naming the app + + Open-source licenses + + + Name + + Drawable + + Component name + + Mapped components + + If the icon is outdated due to rebranding, create an issue on GitHub. + + Toggle visibility of contents + + Request icons + Copy to clipboard + Copied text + + Copied icon request details to clipboard. To request them, submit the details into the form. + Open form + From 7b7618e392058a17fb0ae293eb38392165be2781 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 11 Aug 2024 08:13:46 +0800 Subject: [PATCH 053/144] Update AGP (#2252) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- svg-processor/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 4f9f9c5ce6c..8de0294675f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import com.diffplug.gradle.spotless.SpotlessExtension import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep plugins { - id("com.android.application") version "8.5.1" apply false + id("com.android.application") version "8.5.2" apply false id("org.jetbrains.kotlin.android") version "2.0.10" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.10" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" apply false diff --git a/svg-processor/build.gradle.kts b/svg-processor/build.gradle.kts index 737e82427ca..2df983d5b96 100644 --- a/svg-processor/build.gradle.kts +++ b/svg-processor/build.gradle.kts @@ -8,7 +8,7 @@ application { } dependencies { - implementation("com.android.tools:sdk-common:31.5.1") + implementation("com.android.tools:sdk-common:31.5.2") implementation("org.dom4j:dom4j:2.1.4") implementation("commons-io:commons-io:2.16.1") } From 48bad435a4f22b2f32d176b5aa95639da5e4df58 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 08:20:44 +0800 Subject: [PATCH 054/144] Update dependency gradle to v8.10 (#2259) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.jar | Bin 43504 -> 43583 bytes gradle/wrapper/gradle-wrapper.properties | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 2c3521197d7c4586c843d1d3e9090525f1898cde..a4b76b9530d66f5e68d973ea569d8e19de379189 100644 GIT binary patch delta 3990 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 68e8816d71c..2b189974c29 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=d725d707bfabd4dfdc958c624003b3c80accc03f7037b5122c4b1d0ef15cecab -distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From c35b537a5225a3612232cd28cc908391827cf532 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 15 Aug 2024 16:42:44 +0300 Subject: [PATCH 055/144] +39 links and 2 updates (#2260) * +38 links * Updates, renaming * +1 link * Minor fix --- app/assets/appfilter.xml | 45 ++++++++++++++++++++++++++++++--- svgs/bill_payment_organizer.svg | 2 +- svgs/databackup.svg | 2 +- svgs/mi_video.svg | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index a50d84f2db4..6ba531a09bb 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -176,6 +176,7 @@ + @@ -1020,6 +1021,7 @@ + @@ -1149,6 +1151,7 @@ + @@ -1325,6 +1328,8 @@ + + @@ -1926,6 +1931,7 @@ + @@ -2246,7 +2252,6 @@ - @@ -2440,6 +2445,7 @@ + @@ -3090,6 +3096,7 @@ + @@ -3692,6 +3699,7 @@ + @@ -3768,6 +3776,7 @@ + @@ -3914,6 +3923,8 @@ + + @@ -3959,6 +3970,9 @@ + + + @@ -4060,6 +4074,8 @@ + + @@ -4068,6 +4084,7 @@ + @@ -4133,6 +4150,7 @@ + @@ -4308,6 +4326,7 @@ + @@ -4398,6 +4417,7 @@ + @@ -5658,8 +5678,6 @@ - - @@ -6229,6 +6247,7 @@ + @@ -6353,6 +6372,7 @@ + @@ -6377,6 +6397,7 @@ + @@ -6502,6 +6523,7 @@ + @@ -7072,6 +7094,7 @@ + @@ -7754,6 +7777,7 @@ + @@ -7870,6 +7894,7 @@ + @@ -8403,6 +8428,7 @@ + @@ -9436,6 +9462,7 @@ + @@ -9559,6 +9586,7 @@ + @@ -9572,6 +9600,7 @@ + @@ -9701,8 +9730,10 @@ + + @@ -9776,6 +9807,7 @@ + @@ -10049,6 +10081,7 @@ + @@ -10170,6 +10203,7 @@ + @@ -10790,6 +10824,7 @@ + @@ -10817,6 +10852,7 @@ + @@ -11184,6 +11220,7 @@ + @@ -11989,6 +12026,7 @@ + @@ -12117,6 +12155,7 @@ + diff --git a/svgs/bill_payment_organizer.svg b/svgs/bill_payment_organizer.svg index 91956fae8ce..593d919fb73 100644 --- a/svgs/bill_payment_organizer.svg +++ b/svgs/bill_payment_organizer.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/databackup.svg b/svgs/databackup.svg index 532a76cd4a9..f6a6fe1a193 100644 --- a/svgs/databackup.svg +++ b/svgs/databackup.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/mi_video.svg b/svgs/mi_video.svg index d0ba29e3ed5..28301a125e0 100644 --- a/svgs/mi_video.svg +++ b/svgs/mi_video.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From d5712a2f8930e3fce327e0a496980a6f83ecc865 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 16 Aug 2024 07:01:35 -0400 Subject: [PATCH 056/144] Fix edge-to-edge on three-button nav bar (#2261) --- app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt index 9b9b1829f96..e48505dff3d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt @@ -6,6 +6,7 @@ import android.content.res.ColorStateList import android.graphics.drawable.Drawable import android.os.Bundle import android.util.Log +import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge @@ -32,6 +33,9 @@ class MainActivity : ComponentActivity() { installSplashScreen() super.onCreate(savedInstanceState) enableEdgeToEdge() + // Fix for three-button nav not properly going edge-to-edge. + // TODO: https://issuetracker.google.com/issues/298296168 + window.setFlags(FLAG_LAYOUT_NO_LIMITS, FLAG_LAYOUT_NO_LIMITS) val isIconPicker = intent?.action == Constants.ICON_PICKER_INTENT_ACTION From c7513c81d78130aec94190529057be5551bd86d2 Mon Sep 17 00:00:00 2001 From: Ishaan <81937191+5h3r10k@users.noreply.github.com> Date: Fri, 16 Aug 2024 19:31:20 -0400 Subject: [PATCH 057/144] +2 icons and -1 typo (#2239) * typo fix in "contributing.md" * added Marcus logo and appfilter * added NJ Transit logo and appfilter * added ParkMobile logo and appfilter * added Snackpass logo and appfilter * added YI Home logo and appfilter * updated icon sizes i downloaded and tested the debug apk, the icon sizes were too small, fixed that * adjusted stroke and sizes * updated icons and sizes redid marcus and nj_transit icon, modified snackpass, parkmobile, yi_home. Adjusted sizes of all * removed nj transit for now, will rework and re-add at a later time * updated sizes and strokes of icons * fixed snackpass and yi home fixed size of snackpass, fixed accidental fill on yi home * removed icons to troubleshoot --- CONTRIBUTING.md | 2 +- app/assets/appfilter.xml | 2 ++ svgs/marcus.svg | 8 ++++++++ svgs/parkmobile.svg | 4 ++++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 svgs/marcus.svg create mode 100644 svgs/parkmobile.svg diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3b24acddbfe..52513979e45 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -125,7 +125,7 @@ Correct ## Adding an icon to Lawnicons Here's how to add an icon to Lawnicons: -### Prerequesties +### Prerequisites * Your icon in the SVG format, adhering to the [above guidelines](#contributing-icons). The filename must use snake case (e.g. `files_by_google.svg`). * The package and activity name of the app. diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 6ba531a09bb..f103bce295c 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -5449,6 +5449,7 @@ + @@ -7182,6 +7183,7 @@ + diff --git a/svgs/marcus.svg b/svgs/marcus.svg new file mode 100644 index 00000000000..c821d9711a3 --- /dev/null +++ b/svgs/marcus.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/svgs/parkmobile.svg b/svgs/parkmobile.svg new file mode 100644 index 00000000000..2264a6eb30f --- /dev/null +++ b/svgs/parkmobile.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From e61aead7297c38411bb598b5799e8c56eab2ccd7 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 17 Aug 2024 12:56:26 +0300 Subject: [PATCH 058/144] Updating the self-review checklist (#2262) * Updating the self-review checklist * Minor fix --- .github/icon_checklist.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index b4909874fd6..64b8cb378d3 100644 --- a/.github/icon_checklist.md +++ b/.github/icon_checklist.md @@ -6,21 +6,21 @@ While waiting for a review from our team, you can do a self-review to ensure tha 1. Canvas: `192×192px`. 2. Non-square icons: the long side of the icons should be `160px`. 3. Square icons: `154×154px`. - +- [ ] Done ### Color, stroke width and rounding 1. Color: black `#000`. 2. No fill. Base stroke width: `12px`. `14px`, `10px`, `8px` — depending on the shape of the icons. `6px` — for fine details. 3. Rounded ends and joins. 90° corners are rounded by `6-32px`. - +- [ ] Done ### Naming 1. Names should match the official app name and contain no additional text. -2. If the first `3` characters of the app name contain letters not from the English alphabet, then add a localized (or transliterated) name via `~~`. -Example: `京东 ~~ JD`. +2. If the first `3` characters of the app name contain letters not from the English alphabet, then add a localized (or transliterated) name via `~~`. Example: `京东 ~~ JD`. 3. The names of the drawables should repeat the names of the apps if nothing prevents it. - +- [ ] Done ### Quality 1. Ensure that icons are easily recognizable. 2. Align icons to [the visual center](https://crazybitsstudios.com/another-way-of-aligning-elements-when-creating-icons) as much as possible within the guidelines. The visual center is where your icon looks and feels centered. 3. Avoid noticable black spots by reducing the stroke width or simplifying the icons. 4. Avoid close distances between strokes. The icons on the phone screen will be smaller, so the small distances between the strokes will stick together. 5. Avoid drastic changes in stroke widths. When the strokes next to each other differ in width by 4px or more, the icon will look sloppy. +- [ ] Done From c6771a8eff6f04ce4bf19d4d2f7b095ccf0c3496 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:15:16 +0800 Subject: [PATCH 059/144] Fix crash when search results are 0 Fix #2258 --- .../lawnicons/ui/components/home/search/SearchContents.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt index 369dff1632e..702e28652c0 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt @@ -173,7 +173,12 @@ private fun IconInfoListItem(iconInfo: ImmutableList) { .padding(PaddingValues(16.dp)), verticalArrangement = Arrangement.spacedBy(4.dp), ) { - val it = iconInfo[0] + val it = try { + iconInfo[0] + } catch (_: Exception) { + return@IconInfoListItem + } + val isIconInfoAppfilterShown = remember { mutableStateOf(false) } ListItem( From ab5b665a17c64992bb64b8bd7e148a1154cbb2ea Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:25:57 +0800 Subject: [PATCH 060/144] Improve edge-to-edge handling --- .../app/lawnchair/lawnicons/MainActivity.kt | 41 ++++--- .../app/lawnchair/lawnicons/ui/Lawnicons.kt | 101 ++++++++---------- .../ui/components/SetupEdgeToEdge.kt | 31 ++++++ 3 files changed, 105 insertions(+), 68 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/SetupEdgeToEdge.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt index e48505dff3d..a1b47407bd0 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/MainActivity.kt @@ -6,14 +6,16 @@ import android.content.res.ColorStateList import android.graphics.drawable.Drawable import android.os.Bundle import android.util.Log -import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.drawable.DrawableCompat @@ -21,6 +23,8 @@ import androidx.core.graphics.drawable.toBitmap import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.ui.Lawnicons +import app.lawnchair.lawnicons.ui.components.SetupEdgeToEdge +import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.Constants import dagger.hilt.android.AndroidEntryPoint @@ -33,27 +37,37 @@ class MainActivity : ComponentActivity() { installSplashScreen() super.onCreate(savedInstanceState) enableEdgeToEdge() - // Fix for three-button nav not properly going edge-to-edge. - // TODO: https://issuetracker.google.com/issues/298296168 - window.setFlags(FLAG_LAYOUT_NO_LIMITS, FLAG_LAYOUT_NO_LIMITS) val isIconPicker = intent?.action == Constants.ICON_PICKER_INTENT_ACTION setContent { val context = LocalContext.current val windowSizeClass = calculateWindowSizeClass(this) - Lawnicons( - windowSizeClass = windowSizeClass, - onSendResult = { iconInfo -> - setResult(context, iconInfo) - finish() - }, - isIconPicker = isIconPicker, - ) + LawniconsTheme { + val isExpandedScreen = + windowSizeClass.widthSizeClass == WindowWidthSizeClass.Expanded + + val navBarColor = if (isExpandedScreen) { + MaterialTheme.colorScheme.background.copy(alpha = 0.95f) + } else { + MaterialTheme.colorScheme.surfaceContainer + } + + SetupEdgeToEdge(navBarColor.toArgb()) + Lawnicons( + isExpandedScreen = isExpandedScreen, + onSendResult = { iconInfo -> + setIntentResult(context, iconInfo) + finish() + }, + isIconPicker = isIconPicker, + ) + } } } - private fun setResult( + @Suppress("DEPRECATION") + private fun setIntentResult( context: Context, iconInfo: IconInfo, ) { @@ -89,7 +103,6 @@ class MainActivity : ComponentActivity() { } intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, iconInfo.id) setResult(RESULT_OK, intent) - finish() } else { setResult(RESULT_CANCELED, intent) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt index 052f6000522..5fa7cc626f1 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt @@ -4,8 +4,6 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.windowsizeclass.WindowSizeClass -import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection @@ -20,7 +18,6 @@ import app.lawnchair.lawnicons.ui.destination.Acknowledgement import app.lawnchair.lawnicons.ui.destination.Acknowledgements import app.lawnchair.lawnicons.ui.destination.Contributors import app.lawnchair.lawnicons.ui.destination.Home -import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.About import app.lawnchair.lawnicons.ui.util.Acknowledgement import app.lawnchair.lawnicons.ui.util.Acknowledgements @@ -33,7 +30,7 @@ import soup.compose.material.motion.animation.rememberSlideDistance @Composable @ExperimentalFoundationApi fun Lawnicons( - windowSizeClass: WindowSizeClass, + isExpandedScreen: Boolean, onSendResult: (IconInfo) -> Unit, modifier: Modifier = Modifier, isIconPicker: Boolean = false, @@ -41,57 +38,53 @@ fun Lawnicons( val navController = rememberNavController() val isRtl = LocalLayoutDirection.current == LayoutDirection.Rtl val slideDistance = rememberSlideDistance() - val isExpandedScreen = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Expanded - - LawniconsTheme { - Surface( - modifier = modifier.fillMaxSize(), - color = MaterialTheme.colorScheme.background, + Surface( + modifier = modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background, + ) { + NavHost( + navController = navController, + startDestination = Home, + enterTransition = { materialSharedAxisXIn(!isRtl, slideDistance) }, + exitTransition = { materialSharedAxisXOut(!isRtl, slideDistance) }, + popEnterTransition = { materialSharedAxisXIn(isRtl, slideDistance) }, + popExitTransition = { materialSharedAxisXOut(isRtl, slideDistance) }, ) { - NavHost( - navController = navController, - startDestination = Home, - enterTransition = { materialSharedAxisXIn(!isRtl, slideDistance) }, - exitTransition = { materialSharedAxisXOut(!isRtl, slideDistance) }, - popEnterTransition = { materialSharedAxisXIn(isRtl, slideDistance) }, - popExitTransition = { materialSharedAxisXOut(isRtl, slideDistance) }, - ) { - composable { - Home( - onNavigate = { navController.navigate(About) }, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, - onSendResult = onSendResult, - ) - } - composable { - Acknowledgements( - onBack = navController::popBackStack, - onNavigate = { - navController.navigate(Acknowledgement(it)) - }, - isExpandedScreen = isExpandedScreen, - ) - } - composable { backStackEntry -> - val acknowledgement: Acknowledgement = backStackEntry.toRoute() - Acknowledgement( - name = acknowledgement.id, - onBack = navController::popBackStack, - isExpandedScreen = isExpandedScreen, - ) - } - composable { - About( - onBack = navController::popBackStack, - onNavigateToContributors = { navController.navigate(Contributors) }, - onNavigateToAcknowledgements = { navController.navigate(Acknowledgements) }, - isExpandedScreen = isExpandedScreen, - ) - } - composable { - Contributors(onBack = navController::popBackStack, isExpandedScreen = isExpandedScreen) - } + composable { + Home( + onNavigate = { navController.navigate(About) }, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + ) + } + composable { + Acknowledgements( + onBack = navController::popBackStack, + onNavigate = { + navController.navigate(Acknowledgement(it)) + }, + isExpandedScreen = isExpandedScreen, + ) + } + composable { backStackEntry -> + val acknowledgement: Acknowledgement = backStackEntry.toRoute() + Acknowledgement( + name = acknowledgement.id, + onBack = navController::popBackStack, + isExpandedScreen = isExpandedScreen, + ) + } + composable { + About( + onBack = navController::popBackStack, + onNavigateToContributors = { navController.navigate(Contributors) }, + onNavigateToAcknowledgements = { navController.navigate(Acknowledgements) }, + isExpandedScreen = isExpandedScreen, + ) + } + composable { + Contributors(onBack = navController::popBackStack, isExpandedScreen = isExpandedScreen) } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/SetupEdgeToEdge.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/SetupEdgeToEdge.kt new file mode 100644 index 00000000000..f4a7b79854d --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/SetupEdgeToEdge.kt @@ -0,0 +1,31 @@ +package app.lawnchair.lawnicons.ui.components + +import androidx.activity.ComponentActivity +import androidx.activity.SystemBarStyle +import androidx.activity.enableEdgeToEdge +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.graphics.luminance +import androidx.compose.ui.graphics.toArgb + +@Composable +fun ComponentActivity.SetupEdgeToEdge( + scrimColor: Int, +) { + val contentColor = MaterialTheme.colorScheme.onBackground.toArgb() + val isDarkTheme = MaterialTheme.colorScheme.surface.luminance() < 0.5f + + LaunchedEffect(Unit) { + enableEdgeToEdge( + navigationBarStyle = if (isDarkTheme) { + SystemBarStyle.dark(scrimColor) + } else { + SystemBarStyle.light( + scrimColor, + contentColor, + ) + }, + ) + } +} From 83ec23e9c2fce73a582e05f35173d658fac1c186 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sun, 18 Aug 2024 14:26:26 +0800 Subject: [PATCH 061/144] Fix crash when search is expanded and app is in background --- .../app/lawnchair/lawnicons/repository/IconRepository.kt | 2 +- .../kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt | 4 ---- .../app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt | 2 ++ 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt index dee296b010b..1c18cdda2e8 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt @@ -95,7 +95,7 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep }.toPersistentList() _searchedIconInfoModel.value = IconInfoModel( - iconCount = _iconInfoModel.value.iconCount, + iconCount = _searchedIconInfoModel.value.iconCount, iconInfo = filteredIcons, ) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 111e8127e87..3e98e37a917 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -49,10 +49,6 @@ fun Home( val iconInfoModel by iconInfoModel.collectAsStateWithLifecycle() val searchedIconInfoModel by searchedIconInfoModel.collectAsStateWithLifecycle() val iconRequestModel by iconRequestModel.collectAsStateWithLifecycle() - val searchMode = searchMode - val searchTerm = searchTerm - - var expandSearch by remember { mutableStateOf(false) } val context = LocalContext.current val lazyGridState = rememberLazyGridState() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt index 153d44305d4..69fbd2e5f57 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt @@ -30,6 +30,8 @@ class LawniconsViewModel @Inject constructor( @JvmField val isIconRequestButtonClicked = userTipsRepository.hasClickedIconRequestButton() + var expandSearch by mutableStateOf(false) + private var _searchMode by mutableStateOf(SearchMode.LABEL) private var _searchTerm by mutableStateOf("") From 2a2fbf337617a4b78defdc194083430be991575a Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:03:54 +0300 Subject: [PATCH 062/144] +17 links and 5 updates (#2269) * 2 updates * Spotify update * +17 links --- app/assets/appfilter.xml | 17 +++++++++++++++++ svgs/github.svg | 2 +- svgs/spotiflyer.svg | 2 +- svgs/spotify.svg | 2 +- svgs/spotify_artists.svg | 2 +- svgs/spotify_podcasters.svg | 2 +- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index f103bce295c..8be042b3d7f 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -1114,6 +1114,7 @@ + @@ -2120,6 +2121,7 @@ + @@ -3691,6 +3693,7 @@ + @@ -4434,6 +4437,7 @@ + @@ -4726,6 +4730,7 @@ + @@ -5368,6 +5373,7 @@ + @@ -5995,6 +6001,7 @@ + @@ -6398,6 +6405,7 @@ + @@ -7596,6 +7604,7 @@ + @@ -9464,6 +9473,8 @@ + + @@ -9563,6 +9574,7 @@ + @@ -9966,6 +9978,7 @@ + @@ -10808,6 +10821,7 @@ + @@ -11740,6 +11754,7 @@ + @@ -11931,6 +11946,7 @@ + @@ -12282,6 +12298,7 @@ + diff --git a/svgs/github.svg b/svgs/github.svg index 4e7b4223282..6cbd5ff925a 100644 --- a/svgs/github.svg +++ b/svgs/github.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/spotiflyer.svg b/svgs/spotiflyer.svg index d1d5867cc61..da9569a7223 100644 --- a/svgs/spotiflyer.svg +++ b/svgs/spotiflyer.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/spotify.svg b/svgs/spotify.svg index c7181f838fc..28c5a6c41e5 100644 --- a/svgs/spotify.svg +++ b/svgs/spotify.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/spotify_artists.svg b/svgs/spotify_artists.svg index 1af294315e9..6b6f4650261 100644 --- a/svgs/spotify_artists.svg +++ b/svgs/spotify_artists.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/spotify_podcasters.svg b/svgs/spotify_podcasters.svg index 82566e29d12..4f99f8a5ee3 100644 --- a/svgs/spotify_podcasters.svg +++ b/svgs/spotify_podcasters.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From 126f09ef6695c8b67ea50b6a5343f1334bf5d709 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:07:01 +0800 Subject: [PATCH 063/144] Update dependency androidx.compose:compose-bom to v2024.08.00 (#2272) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cf40ff1629a..848bf47d053 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -135,7 +135,7 @@ dependencies { implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.activity:activity-compose:1.9.1") - implementation(platform("androidx.compose:compose-bom:2024.06.00")) + implementation(platform("androidx.compose:compose-bom:2024.08.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.ui:ui-util") From 6e6c39534e6ec1f29362df4b1879e64b76315419 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:07:09 +0800 Subject: [PATCH 064/144] Update dependency androidx.navigation:navigation-compose to v2.8.0-rc01 (#2271) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 848bf47d053..5eac5f76308 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -144,7 +144,7 @@ dependencies { implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0-beta05") implementation("androidx.compose.material3:material3-window-size-class") - implementation("androidx.navigation:navigation-compose:2.8.0-beta07") + implementation("androidx.navigation:navigation-compose:2.8.0-rc01") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") From c86521a65831bbd0f15f4b329bae77822685db2f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:07:17 +0800 Subject: [PATCH 065/144] Update dependency androidx.compose.material3:material3 to v1.3.0-rc01 (#2270) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5eac5f76308..cf9f33d9ef0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -142,7 +142,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") implementation("androidx.compose.material:material-icons-core-android:1.6.8") - implementation("androidx.compose.material3:material3:1.3.0-beta05") + implementation("androidx.compose.material3:material3:1.3.0-rc01") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0-rc01") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") From 43d2105a97b860917122930eb3eb3608a4443382 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:07:25 +0800 Subject: [PATCH 066/144] Update plugin com.gradle.develocity to v3.18 (#2268) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index f0ac4ed0e4a..8ac7d615286 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,7 +13,7 @@ pluginManagement { // https://docs.gradle.com/enterprise/gradle-plugin/ plugins { - id("com.gradle.develocity") version "3.17.6" + id("com.gradle.develocity") version "3.18" } develocity { From f4bf48e57771302e76b7dda91760c7618b520fb6 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:56:15 +0300 Subject: [PATCH 067/144] +6 links (#2274) --- app/assets/appfilter.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 8be042b3d7f..1675e806208 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -796,6 +796,7 @@ + @@ -1754,6 +1755,7 @@ + @@ -2084,6 +2086,7 @@ + @@ -2162,7 +2165,7 @@ - + @@ -5143,6 +5146,7 @@ + @@ -7214,6 +7218,7 @@ + @@ -11969,6 +11974,7 @@ + From 3d38b0ac0736ee4fc4ebe2ba4751c9e4874a589c Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 22 Aug 2024 09:18:14 +0300 Subject: [PATCH 068/144] Minor fix (#2275) --- app/assets/appfilter.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 1675e806208..0f59ec1b1aa 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -2165,7 +2165,6 @@ - @@ -7352,6 +7351,7 @@ + From 5ccd2f935f5dba5732e9ccf56f1ff54a0c21f0fa Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:32:40 +0300 Subject: [PATCH 069/144] +11 links (#2277) --- app/assets/appfilter.xml | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 0f59ec1b1aa..3059e6e48d2 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -1539,6 +1539,7 @@ + @@ -2565,6 +2566,7 @@ + @@ -3701,6 +3703,7 @@ + @@ -4390,6 +4393,7 @@ + @@ -4416,6 +4420,7 @@ + @@ -6131,6 +6136,7 @@ + @@ -6650,6 +6656,7 @@ + @@ -8327,6 +8334,7 @@ + @@ -11174,20 +11182,21 @@ - - - + + + - - - - + + + + + - + - - + + @@ -11851,6 +11860,7 @@ + @@ -12335,6 +12345,7 @@ + From eec3a99cb009b9fda5431d5ae1e4ed2fc2db9639 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 23 Aug 2024 08:27:07 +0800 Subject: [PATCH 070/144] Update Kotlin and KSP (#2276) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 8de0294675f..fa51ad45f0a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,10 +3,10 @@ import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep plugins { id("com.android.application") version "8.5.2" apply false - id("org.jetbrains.kotlin.android") version "2.0.10" apply false - id("org.jetbrains.kotlin.plugin.compose") version "2.0.10" - id("org.jetbrains.kotlin.plugin.serialization") version "2.0.10" apply false - id("com.google.devtools.ksp") version "2.0.10-1.0.24" apply false + id("org.jetbrains.kotlin.android") version "2.0.20" apply false + id("org.jetbrains.kotlin.plugin.compose") version "2.0.20" + id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" apply false + id("com.google.devtools.ksp") version "2.0.20-1.0.24" apply false id("com.google.dagger.hilt.android") version "2.52" apply false id("app.cash.licensee") version "1.11.0" apply false id("com.diffplug.spotless") version "6.25.0" apply false From c542e1253c71bb2fb0f542b0837eeb8adf13f207 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:32:34 +0800 Subject: [PATCH 071/144] Use singleton for handling prefs --- .../lawnicons/di/UserTipsRepositoryModule.kt | 22 ------ .../lawnicons/repository/PreferenceManager.kt | 72 +++++++++++++++++++ .../repository/UserTipsRepository.kt | 27 ------- .../ui/components/home/HomeBottomBar.kt | 4 -- .../ui/components/home/IconRequestFAB.kt | 46 ++++++------ .../lawnicons/ui/destination/Home.kt | 3 +- .../lawnicons/viewmodel/LawniconsViewModel.kt | 11 --- 7 files changed, 98 insertions(+), 87 deletions(-) delete mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt delete mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt deleted file mode 100644 index f747c66eb09..00000000000 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/di/UserTipsRepositoryModule.kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.lawnchair.lawnicons.di - -import android.app.Application -import android.content.Context -import app.lawnchair.lawnicons.repository.UserTipsRepository -import app.lawnchair.lawnicons.repository.UserTipsRepositoryImpl -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object UserTipsRepositoryModule { - - @Provides - @Singleton - fun provideIconRepository(application: Application): UserTipsRepository = UserTipsRepositoryImpl( - application.getSharedPreferences("app_prefs", Context.MODE_PRIVATE), - ) -} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt new file mode 100644 index 00000000000..beb6e77c7ae --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -0,0 +1,72 @@ +package app.lawnchair.lawnicons.repository + +import android.content.Context +import android.content.SharedPreferences +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.produceState +import androidx.compose.ui.platform.LocalContext + +/** + * A class that abstracts the functionality of SharedPreferences + * @param prefs The SharedPreferences instance to use + */ +abstract class BasePreferenceManager( + private val prefs: SharedPreferences, +) { + private val editor = prefs.edit() + + /** + * A class that represents a boolean preference + * @param key The key of the preference + * @param defaultValue The default value of the preference + */ + inner class BoolPref( + val key: String, + private val defaultValue: Boolean, + ) { + fun get() = prefs.getBoolean(key, defaultValue) + fun set(value: Boolean) = editor.putBoolean(key, value).apply() + + @Composable + fun asState(): State { + return produceState(initialValue = get(), this) { + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey -> + if (changedKey == key) { + value = get() // Update the state value when the preference changes + } + } + prefs.registerOnSharedPreferenceChangeListener(listener) + } + } + } +} + +/** + * Provides a class to handle Lawnicons preferences + */ +class PreferenceManager private constructor( + prefs: SharedPreferences, +) : BasePreferenceManager(prefs) { + + val showRequestTooltip = BoolPref("icon_request_button_clicked", true) + + companion object { + @Volatile + private var instance: PreferenceManager? = null + + /** + * Returns a singleton instance of PreferenceManager + */ + fun getInstance(context: Context): PreferenceManager { + return instance ?: synchronized(this) { + instance ?: PreferenceManager( + context.getSharedPreferences("app_prefs", Context.MODE_PRIVATE), + ).also { instance = it } + } + } + } +} + +@Composable +fun preferenceManager(context: Context = LocalContext.current) = PreferenceManager.getInstance(context) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt deleted file mode 100644 index 2667e883bb3..00000000000 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/UserTipsRepository.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.lawnchair.lawnicons.repository - -import android.content.SharedPreferences -import javax.inject.Inject - -// TODO: Add additional tips -interface UserTipsRepository { - fun hasClickedIconRequestButton(): Boolean - fun onIconRequestButtonClicked() - - fun clearTips() -} - -class UserTipsRepositoryImpl @Inject constructor(private val prefs: SharedPreferences) : UserTipsRepository { - - companion object { - const val ICON_REQUEST_BUTTON_CLICKED = "icon_request_button_clicked" - } - - override fun hasClickedIconRequestButton(): Boolean = prefs.get(ICON_REQUEST_BUTTON_CLICKED) - override fun onIconRequestButtonClicked() = prefs.set(ICON_REQUEST_BUTTON_CLICKED, true) - - override fun clearTips() = prefs.edit().clear().apply() -} - -fun SharedPreferences.get(key: String): Boolean = getBoolean(key, false) -fun SharedPreferences.set(key: String, value: Boolean) = edit().putBoolean(key, value).apply() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 623dc18e200..28e7cb023ae 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -35,8 +35,6 @@ fun HomeBottomBar( snackbarHostState: SnackbarHostState, onNavigate: () -> Unit, onExpandSearch: () -> Unit, - isIconRequestClicked: Boolean, - onIconRequestClick: () -> Unit, modifier: Modifier = Modifier, ) { BottomAppBar( @@ -63,8 +61,6 @@ fun HomeBottomBar( IconRequestIconButton( iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, - isIconRequestClicked = isIconRequestClicked, - onClick = onIconRequestClick, ) SimpleTooltipBox( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 1e922a6e064..c7e13efe88b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -52,6 +52,7 @@ import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequest import app.lawnchair.lawnicons.model.IconRequestModel +import app.lawnchair.lawnicons.repository.preferenceManager import app.lawnchair.lawnicons.ui.components.core.Card import app.lawnchair.lawnicons.ui.util.Constants import app.lawnchair.lawnicons.ui.util.isScrollingUp @@ -91,18 +92,18 @@ fun IconRequestFAB( @Composable fun IconRequestIconButton( - isIconRequestClicked: Boolean, snackbarHostState: SnackbarHostState, iconRequestModel: IconRequestModel?, - onClick: () -> Unit, modifier: Modifier = Modifier, ) { + val prefs = preferenceManager() + RequestHandler( iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, - onClick = onClick, + onClick = { prefs.showRequestTooltip.set(false) }, ) { interactionSource -> - IconRequestTooltip(isIconRequestClicked) { + IconRequestTooltip(prefs.showRequestTooltip.asState().value) { IconButton( onClick = {}, interactionSource = interactionSource, @@ -121,34 +122,37 @@ fun IconRequestIconButton( @OptIn(ExperimentalMaterial3Api::class) @Composable private fun IconRequestTooltip( - isButtonClicked: Boolean, + showTooltip: Boolean, content: @Composable (() -> Unit), ) { val state = rememberTooltipState( initialIsVisible = true, isPersistent = true, ) - val hideTooltip = remember { isButtonClicked } - LaunchedEffect(hideTooltip) { - if (hideTooltip) { + LaunchedEffect(showTooltip) { + if (!showTooltip) { state.dismiss() } } - TooltipBox( - positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), - tooltip = { - PlainTooltip( - containerColor = MaterialTheme.colorScheme.primaryContainer, - contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - caretSize = DpSize(16.dp, 8.dp), - ) { - Text("Request missing icons here") - } - }, - state = state, - ) { + if (showTooltip) { + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip( + containerColor = MaterialTheme.colorScheme.primaryContainer, + contentColor = MaterialTheme.colorScheme.onPrimaryContainer, + caretSize = DpSize(16.dp, 8.dp), + ) { + Text("Request missing icons here") + } + }, + state = state, + ) { + content() + } + } else { content() } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 3e98e37a917..017ab6ff09a 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -20,6 +20,7 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.SearchMode +import app.lawnchair.lawnicons.repository.preferenceManager import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBarUiState @@ -90,8 +91,6 @@ fun Home( snackbarHostState = snackbarHostState, onNavigate = onNavigate, onExpandSearch = { expandSearch = true }, - isIconRequestClicked = isIconRequestButtonClicked, - onIconRequestClick = ::onIconRequestButtonClicked, ) } }, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt index 69fbd2e5f57..b6d23e9fefc 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt @@ -7,7 +7,6 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.repository.IconRepository -import app.lawnchair.lawnicons.repository.UserTipsRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.launch @@ -15,7 +14,6 @@ import kotlinx.coroutines.launch @HiltViewModel class LawniconsViewModel @Inject constructor( private val iconRepository: IconRepository, - private val userTipsRepository: UserTipsRepository, ) : ViewModel() { @JvmField @@ -27,9 +25,6 @@ class LawniconsViewModel @Inject constructor( @JvmField val iconRequestModel = iconRepository.iconRequestList - @JvmField - val isIconRequestButtonClicked = userTipsRepository.hasClickedIconRequestButton() - var expandSearch by mutableStateOf(false) private var _searchMode by mutableStateOf(SearchMode.LABEL) @@ -61,10 +56,4 @@ class LawniconsViewModel @Inject constructor( iconRepository.clearSearch() } } - - fun onIconRequestButtonClicked() { - if (!userTipsRepository.hasClickedIconRequestButton()) { - userTipsRepository.onIconRequestButtonClicked() - } - } } From 9353ecaa4248e692851e122c588054a927df2830 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:31:22 +0800 Subject: [PATCH 072/144] Use snackbar instead of tooltip for first launch --- .../lawnicons/repository/PreferenceManager.kt | 5 +- .../ui/components/home/IconRequestFAB.kt | 208 +++++++++--------- app/src/main/res/values/strings.xml | 1 + 3 files changed, 112 insertions(+), 102 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt index beb6e77c7ae..9a9e7a2a448 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -28,6 +28,8 @@ abstract class BasePreferenceManager( fun get() = prefs.getBoolean(key, defaultValue) fun set(value: Boolean) = editor.putBoolean(key, value).apply() + fun onChange() = set(!get()) + @Composable fun asState(): State { return produceState(initialValue = get(), this) { @@ -48,8 +50,7 @@ abstract class BasePreferenceManager( class PreferenceManager private constructor( prefs: SharedPreferences, ) : BasePreferenceManager(prefs) { - - val showRequestTooltip = BoolPref("icon_request_button_clicked", true) + val showFirstLaunchSnackbar = BoolPref("show_first_launch_snackbar", true) companion object { @Volatile diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index c7e13efe88b..3ce7213b7e8 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -22,32 +22,30 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.Icon import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.PlainTooltip +import androidx.compose.material3.SheetState import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text import androidx.compose.material3.TextButton -import androidx.compose.material3.TooltipBox -import androidx.compose.material3.TooltipDefaults import androidx.compose.material3.rememberModalBottomSheetState -import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalViewConfiguration +import androidx.compose.ui.platform.ViewConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequest @@ -68,8 +66,9 @@ fun IconRequestFAB( snackbarHostState: SnackbarHostState, modifier: Modifier = Modifier, ) { + val list = iconRequestModel?.list ?: emptyList() RequestHandler( - iconRequestModel = iconRequestModel, + iconRequestList = list, snackbarHostState = snackbarHostState, ) { interactionSource -> ExtendedFloatingActionButton( @@ -96,81 +95,22 @@ fun IconRequestIconButton( iconRequestModel: IconRequestModel?, modifier: Modifier = Modifier, ) { - val prefs = preferenceManager() + val list = iconRequestModel?.list ?: emptyList() RequestHandler( - iconRequestModel = iconRequestModel, + iconRequestList = list, snackbarHostState = snackbarHostState, - onClick = { prefs.showRequestTooltip.set(false) }, ) { interactionSource -> - IconRequestTooltip(prefs.showRequestTooltip.asState().value) { - IconButton( - onClick = {}, - interactionSource = interactionSource, - modifier = modifier, - ) { - Icon( - painter = painterResource(id = R.drawable.icon_request_app), - contentDescription = stringResource(R.string.request_icons), - modifier = Modifier.requiredSize(24.dp), - ) - } - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun IconRequestTooltip( - showTooltip: Boolean, - content: @Composable (() -> Unit), -) { - val state = rememberTooltipState( - initialIsVisible = true, - isPersistent = true, - ) - - LaunchedEffect(showTooltip) { - if (!showTooltip) { - state.dismiss() - } - } - - if (showTooltip) { - TooltipBox( - positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), - tooltip = { - PlainTooltip( - containerColor = MaterialTheme.colorScheme.primaryContainer, - contentColor = MaterialTheme.colorScheme.onPrimaryContainer, - caretSize = DpSize(16.dp, 8.dp), - ) { - Text("Request missing icons here") - } - }, - state = state, - ) { - content() - } - } else { - content() - } -} - -@Composable -fun RequestHandler( - iconRequestModel: IconRequestModel?, - snackbarHostState: SnackbarHostState, - onClick: () -> Unit = {}, - content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), -) { - if (iconRequestModel != null) { - RequestHandler( - iconRequestList = iconRequestModel.list, - snackbarHostState = snackbarHostState, - onClick = onClick, + IconButton( + onClick = {}, + interactionSource = interactionSource, + modifier = modifier, ) { - content(it) + Icon( + painter = painterResource(id = R.drawable.icon_request_app), + contentDescription = stringResource(R.string.request_icons), + modifier = Modifier.requiredSize(24.dp), + ) } } } @@ -180,39 +120,86 @@ fun RequestHandler( fun RequestHandler( iconRequestList: List, snackbarHostState: SnackbarHostState, - onClick: () -> Unit, content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), ) { + val prefs = preferenceManager() + val showFirstLaunchSnackbar by prefs.showFirstLaunchSnackbar.asState() val context = LocalContext.current - val viewConfiguration = LocalViewConfiguration.current - - val onClickEffect = rememberUpdatedState(onClick) val requestList = formatIconRequestList(iconRequestList) val encodedRequestList = buildForm(requestList.replace("\n", "%20")) + val directLinkEnabled = encodedRequestList.length < Constants.DIRECT_LINK_MAX_LENGTH - val sheetExpanded = remember { mutableStateOf(false) } + var sheetExpanded by remember { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true, ) - val coroutineScope = rememberCoroutineScope() + val scope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } - val directLinkEnabled = encodedRequestList.length < Constants.DIRECT_LINK_MAX_LENGTH + HandleTouchInteractions( + interactionSource = interactionSource, + viewConfiguration = LocalViewConfiguration.current, + context = context, + coroutineScope = scope, + onExpandSheet = { sheetExpanded = it }, + sheetState = sheetState, + iconRequestList = iconRequestList, + directLinkEnabled = directLinkEnabled, + encodedRequestList = encodedRequestList, + requestList = requestList, + snackbarHostState = snackbarHostState, + ) + + content(interactionSource) + + if (showFirstLaunchSnackbar && iconRequestList.isNotEmpty()) { + openSnackbarFirstLaunchContent( + context, + scope, + prefs.showFirstLaunchSnackbar::onChange, + snackbarHostState, + ) + } + AnimatedVisibility(visible = sheetExpanded) { + ModalBottomSheet( + onDismissRequest = { sheetExpanded = false }, + sheetState = sheetState, + ) { + IconRequestSheet(requestList, context) + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun HandleTouchInteractions( + interactionSource: MutableInteractionSource, + viewConfiguration: ViewConfiguration, + context: Context, + coroutineScope: CoroutineScope, + onExpandSheet: (Boolean) -> Unit, + sheetState: SheetState, + iconRequestList: List, + directLinkEnabled: Boolean, + requestList: String, + encodedRequestList: String, + snackbarHostState: SnackbarHostState, +) { + val lastestOnExpandSheet by rememberUpdatedState(newValue = onExpandSheet) LaunchedEffect(interactionSource) { var isLongClick = false interactionSource.interactions.collectLatest { interaction -> when (interaction) { is PressInteraction.Press -> { - onClickEffect.value() isLongClick = false delay(viewConfiguration.longPressTimeoutMillis) isLongClick = true coroutineScope.launch { - sheetExpanded.value = true + lastestOnExpandSheet(true) sheetState.show() } } @@ -224,7 +211,12 @@ fun RequestHandler( } else if (directLinkEnabled) { openLink(context, encodedRequestList) } else { - openSnackbarContent(context, requestList, coroutineScope, snackbarHostState) + openSnackbarWarningContent( + context, + requestList, + coroutineScope, + snackbarHostState, + ) } } } @@ -235,17 +227,6 @@ fun RequestHandler( } } } - - content(interactionSource) - - AnimatedVisibility(visible = sheetExpanded.value) { - ModalBottomSheet( - onDismissRequest = { sheetExpanded.value = false }, - sheetState = sheetState, - ) { - IconRequestSheet(requestList, context) - } - } } @Composable @@ -294,7 +275,35 @@ private fun copyTextToClipboard(context: Context, text: String) { clipboard.setPrimaryClip(clip) } -private fun openSnackbarContent( +private fun openSnackbarFirstLaunchContent( + context: Context, + coroutineScope: CoroutineScope, + onActionPerformed: () -> Unit, + snackbarHostState: SnackbarHostState, +) { + coroutineScope.launch { + val result = snackbarHostState + .showSnackbar( + message = context.getString(R.string.you_have_missing_icons), + actionLabel = context.getString(R.string.request_icons), + withDismissAction = true, + duration = SnackbarDuration.Indefinite, + ) + when (result) { + SnackbarResult.ActionPerformed -> { + onActionPerformed() + openLink(context, Constants.ICON_REQUEST_FORM) + } + + SnackbarResult.Dismissed -> { + onActionPerformed() + snackbarHostState.currentSnackbarData?.dismiss() + } + } + } +} + +private fun openSnackbarWarningContent( context: Context, list: String, coroutineScope: CoroutineScope, @@ -311,7 +320,6 @@ private fun openSnackbarContent( ) when (result) { SnackbarResult.ActionPerformed -> { - /* Handle snackbar action performed */ openLink(context, Constants.ICON_REQUEST_FORM) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5633c4de3ee..d02c191f394 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -84,4 +84,5 @@ Copied icon request details to clipboard. To request them, submit the details into the form. Open form + You have missing icons From b589f24054f06f9fd20d4f4f9a6762058404d016 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:36:48 +0800 Subject: [PATCH 073/144] Update placeholder UI --- .../home/search/PlaceholderSearchBar.kt | 7 ++---- .../lawnicons/ui/destination/Home.kt | 23 +++++++++++++++---- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/PlaceholderSearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/PlaceholderSearchBar.kt index dd2bcfbaf77..e849693d127 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/PlaceholderSearchBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/PlaceholderSearchBar.kt @@ -22,7 +22,6 @@ import app.lawnchair.lawnicons.ui.util.PreviewLawnicons @Composable fun PlaceholderSearchBar( - isExpandedScreen: Boolean, modifier: Modifier = Modifier, ) { Column( @@ -38,9 +37,7 @@ fun PlaceholderSearchBar( content = {}, contentAlignment = Alignment.TopCenter, modifier = Modifier - .then( - if (isExpandedScreen) Modifier.width(360.dp) else Modifier, - ) + .width(360.dp) .zIndex(1f) .statusBarsPadding() .padding(top = 8.dp) @@ -60,6 +57,6 @@ fun PlaceholderSearchBar( @Composable private fun PlaceholderSearchBarPreview() { LawniconsTheme { - PlaceholderSearchBar(false) + PlaceholderSearchBar() } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 017ab6ff09a..7fcf0b211ae 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -3,7 +3,12 @@ package app.lawnchair.lawnicons.ui.destination import android.annotation.SuppressLint import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -13,6 +18,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.platform.LocalContext @@ -20,7 +26,6 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.SearchMode -import app.lawnchair.lawnicons.repository.preferenceManager import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBarUiState @@ -36,7 +41,7 @@ import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel import kotlinx.collections.immutable.toImmutableList @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@OptIn(ExperimentalFoundationApi::class) +@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun Home( onNavigate: () -> Unit, @@ -116,9 +121,17 @@ fun Home( ) } } else { - PlaceholderSearchBar( - isExpandedScreen = isExpandedScreen, - ) + if (isExpandedScreen) { + PlaceholderSearchBar() + } else { + Column( + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + modifier = Modifier.fillMaxSize(), + ) { + CircularProgressIndicator() + } + } } } LaunchedEffect(expandSearch) { From b4d766d9332076783ba560fffc9fc66eb968e9c5 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 12:37:01 +0800 Subject: [PATCH 074/144] Fix padding --- .../lawnicons/ui/components/home/IconPreviewGrid.kt | 2 +- .../lawnicons/ui/components/home/search/SearchContents.kt | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 3f755301961..7418990dbd1 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -71,7 +71,7 @@ fun IconPreviewGrid( .fillMaxWidth() .statusBarsPadding() .then( - if (isExpandedScreen) Modifier.padding(top = 26.dp) else Modifier, + if (isExpandedScreen) Modifier.padding(top = 26.dp) else Modifier.padding(bottom = 80.dp), ), state = gridState, settings = ScrollbarSettings( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt index 702e28652c0..c2f05d47838 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt @@ -123,6 +123,7 @@ fun SearchContents( 1 -> { IconInfoListItem(iconInfo) } + 0 -> { Box( modifier = Modifier @@ -145,7 +146,7 @@ fun SearchContents( ) { iconInfo -> LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 80.dp), - contentPadding = PaddingValues(16.dp), + contentPadding = PaddingValues(16.dp, 16.dp, 16.dp, 80.dp), ) { items( items = iconInfo, @@ -154,7 +155,7 @@ fun SearchContents( IconPreview( iconInfo = it, onSendResult = onSendResult, - iconBackground = MaterialTheme.colorScheme.surfaceVariant, + iconBackground = MaterialTheme.colorScheme.surfaceContainerLow, ) } } From 0bdd5d9bf297c7e7a8b2868caaa3e3ff0467d40f Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:07:10 +0800 Subject: [PATCH 075/144] Simplify IconInfo --- .../app/lawnchair/lawnicons/model/IconInfo.kt | 76 +++++++++---------- .../lawnicons/repository/IconRepository.kt | 5 +- .../lawnchair/lawnicons/util/GetIconInfo.kt | 6 +- 3 files changed, 40 insertions(+), 47 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfo.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfo.kt index 7d3a6351f6b..6661e3118ef 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfo.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfo.kt @@ -21,52 +21,44 @@ data class IconInfo( } /** - * A helper object for processing and manipulating collections of [IconInfo] objects, - * including merging and splitting based on drawable names and component names. + * Merges a list of [IconInfo] objects, grouping them by their `drawableName` and + * combining the `componentNames` of icons with the same drawable name. + * + * @return A new list of [IconInfo] objects with merged component names for icons + * sharing the same drawable name. */ -object IconInfoManager { - /** - * Merges a list of [IconInfo] objects, grouping them by their `drawableName` and - * combining the `componentNames` of icons with the same drawable name. - * - * @param iconInfoList The list of [IconInfo] objects to merge. - * @return A new list of [IconInfo] objects with merged component names for icons - * sharing the same drawable name. - */ - fun mergeByDrawableName(iconInfoList: List): List { - return iconInfoList.groupBy { it.drawableName } - .map { (drawableName, icons) -> - val mergedComponentNames = icons.flatMap { it.componentNames } - IconInfo( - componentNames = mergedComponentNames, - drawableName = drawableName, - id = icons.first().id, - ) - } - } +fun List.mergeByDrawableName(): List { + return groupBy { it.drawableName } + .map { (drawableName, icons) -> + val mergedComponentNames = icons.flatMap { it.componentNames } + IconInfo( + componentNames = mergedComponentNames, + drawableName = drawableName, + id = icons.first().id, + ) + } +} - /** - * Splits [IconInfo] objects with multiple component names into a list where each - * [IconInfo] object has a single component name. - * - * @param iconInfoList The list of [IconInfo] objects to split. - * @return A new list of [IconInfo] objects, each with a single component name. - */ - fun splitByComponentName(iconInfoList: List): List { - val splitList = mutableListOf() - for (iconInfo in iconInfoList) { - for (nameAndComponent in iconInfo.componentNames) { - splitList.add( - IconInfo( - componentNames = listOf(nameAndComponent), - drawableName = iconInfo.drawableName, - id = iconInfo.id, - ), - ) - } +/** + * Splits [IconInfo] objects with multiple component names into a list where each + * [IconInfo] object has a single component name. + * + * @return A new list of [IconInfo] objects, each with a single component name. + */ +fun List.splitByComponentName(): List { + val splitList = mutableListOf() + for (iconInfo in this) { + for (nameAndComponent in iconInfo.componentNames) { + splitList.add( + IconInfo( + componentNames = listOf(nameAndComponent), + drawableName = iconInfo.drawableName, + id = iconInfo.id, + ), + ) } - return splitList } + return splitList } fun IconInfo.getFirstLabelAndComponent(): LabelAndComponent { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt index 1c18cdda2e8..c03ddb1cf28 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt @@ -2,13 +2,13 @@ package app.lawnchair.lawnicons.repository import android.app.Application import app.lawnchair.lawnicons.model.IconInfo -import app.lawnchair.lawnicons.model.IconInfoManager import app.lawnchair.lawnicons.model.IconInfoModel import app.lawnchair.lawnicons.model.IconRequest import app.lawnchair.lawnicons.model.IconRequestModel import app.lawnchair.lawnicons.model.SearchInfo import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.model.getFirstLabelAndComponent +import app.lawnchair.lawnicons.model.splitByComponentName import app.lawnchair.lawnicons.util.getIconInfo import app.lawnchair.lawnicons.util.getSystemIconInfoAppfilter import javax.inject.Inject @@ -112,7 +112,8 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep info.getFirstLabelAndComponent() } - val lawniconsComponents = IconInfoManager.splitByComponentName(lawniconsData) + val lawniconsComponents = lawniconsData + .splitByComponentName() .map { it.getFirstLabelAndComponent().componentName } .sortedBy { it.lowercase() } .toSet() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt index abcd3fac554..7ea59aeb188 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt @@ -4,13 +4,13 @@ import android.annotation.SuppressLint import android.content.Context import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo -import app.lawnchair.lawnicons.model.IconInfoManager import app.lawnchair.lawnicons.model.LabelAndComponent +import app.lawnchair.lawnicons.model.mergeByDrawableName import org.xmlpull.v1.XmlPullParser @SuppressLint("DiscouragedApi") fun Context.getIconInfo(): List { - var iconInfo = mutableListOf() + val iconInfo = mutableListOf() val componentInfoPrefixLength = "ComponentInfo{".length @@ -61,5 +61,5 @@ fun Context.getIconInfo(): List { e.printStackTrace() } - return IconInfoManager.mergeByDrawableName(iconInfo) + return iconInfo.mergeByDrawableName() } From 8522751a23592c383cbd246ec5d9f7902bc01045 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 13:16:09 +0800 Subject: [PATCH 076/144] Fix scrollbar content Fix #2256 --- .../ui/components/home/IconPreviewGrid.kt | 56 ++++++++++++------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 7418990dbd1..92c81d274b2 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -31,6 +32,8 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.asImageBitmap @@ -60,6 +63,9 @@ fun IconPreviewGrid( contentPadding: PaddingValues? = null, gridState: LazyGridState = rememberLazyGridState(), ) { + val indexOfFirstItem = remember { derivedStateOf { gridState.firstVisibleItemIndex } } + val letter = iconInfo[indexOfFirstItem.value].label[0].uppercase() + Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, @@ -81,27 +87,7 @@ fun IconPreviewGrid( selectionMode = ScrollbarSelectionMode.Thumb, ), indicatorContent = { _, isThumbSelected -> - AnimatedVisibility( - visible = isThumbSelected, - enter = fadeIn(), - exit = fadeOut(), - ) { - Box( - modifier = Modifier - .padding(end = 16.dp) - .background( - color = MaterialTheme.colorScheme.primary, - shape = MaterialTheme.shapes.large, - ), - ) { - Text( - modifier = Modifier.padding(16.dp), - text = "#", - style = MaterialTheme.typography.titleMedium, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - } + ScrollbarIndicator(letter, isThumbSelected) }, ) { val horizontalGridPadding = if (isExpandedScreen) 32.dp else 8.dp @@ -138,6 +124,34 @@ fun IconPreviewGrid( } } +@Composable +private fun ColumnScope.ScrollbarIndicator( + label: String, + isThumbSelected: Boolean, +) { + AnimatedVisibility( + visible = isThumbSelected, + enter = fadeIn(), + exit = fadeOut(), + ) { + Box( + modifier = Modifier + .padding(end = 16.dp) + .background( + color = MaterialTheme.colorScheme.primary, + shape = MaterialTheme.shapes.large, + ), + ) { + Text( + modifier = Modifier.padding(16.dp), + text = label, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + } +} + @OptIn(ExperimentalMaterial3Api::class) @Composable fun TopAppBar(modifier: Modifier = Modifier) { From c974fcf8dac9993103e2b891326835f3ec2ab99d Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 23 Aug 2024 14:02:08 +0800 Subject: [PATCH 077/144] Group myself to infra --- .../main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt | 2 +- app/src/main/res/values-af-rZA/strings.xml | 1 - app/src/main/res/values-ar-rSA/strings.xml | 1 - app/src/main/res/values-ca-rES/strings.xml | 1 - app/src/main/res/values-cs-rCZ/strings.xml | 1 - app/src/main/res/values-da-rDK/strings.xml | 1 - app/src/main/res/values-de-rDE/strings.xml | 1 - app/src/main/res/values-el-rGR/strings.xml | 1 - app/src/main/res/values-en-rUS/strings.xml | 1 - app/src/main/res/values-es-rES/strings.xml | 1 - app/src/main/res/values-fi-rFI/strings.xml | 1 - app/src/main/res/values-fil-rPH/strings.xml | 1 - app/src/main/res/values-fr-rFR/strings.xml | 1 - app/src/main/res/values-hi-rIN/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-in-rID/strings.xml | 1 - app/src/main/res/values-it-rIT/strings.xml | 1 - app/src/main/res/values-iw-rIL/strings.xml | 1 - app/src/main/res/values-ja-rJP/strings.xml | 1 - app/src/main/res/values-ko-rKR/strings.xml | 1 - app/src/main/res/values-mr-rIN/strings.xml | 1 - app/src/main/res/values-nl-rNL/strings.xml | 1 - app/src/main/res/values-no-rNO/strings.xml | 1 - app/src/main/res/values-pl-rPL/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-pt-rPT/strings.xml | 1 - app/src/main/res/values-ro-rRO/strings.xml | 1 - app/src/main/res/values-ru-rRU/strings.xml | 1 - app/src/main/res/values-sv-rSE/strings.xml | 1 - app/src/main/res/values-tr-rTR/strings.xml | 1 - app/src/main/res/values-uk-rUA/strings.xml | 1 - app/src/main/res/values-vi-rVN/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values-zh-rTW/strings.xml | 1 - app/src/main/res/values/strings.xml | 2 +- 35 files changed, 2 insertions(+), 35 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index e5ae792bf97..68a70354255 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -93,7 +93,7 @@ private val coreContributors = listOf( username = "Goooler", photoUrl = "https://avatars.githubusercontent.com/u/10363352", socialUrl = "https://androiddev.social/@Goooler", - descriptionRes = R.string.contribution_deps, + descriptionRes = R.string.contribution_infra, ), ) diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml index 680cb8e8e1c..2c96f6ec44c 100644 --- a/app/src/main/res/values-af-rZA/strings.xml +++ b/app/src/main/res/values-af-rZA/strings.xml @@ -33,7 +33,6 @@ Core app Icons - Dependencies Special thanks diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index e613c59d823..ef89bd8810e 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -33,7 +33,6 @@ Core app الأيقونات - Dependencies Special thanks diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index fda7534543c..21ae600a6da 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -33,7 +33,6 @@ Core app Icones - Dependencies Special thanks diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 0e32a08e8e1..f236fefd641 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -33,7 +33,6 @@ Core app Ikony - Dependencies Special thanks diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index d8c6f75ccb5..a07187d65d6 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -33,7 +33,6 @@ Core app Ikoner - Dependencies Special thanks diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index f2139d339b6..c6ed397c757 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -33,7 +33,6 @@ Kern-App Symbole - Abhängigkeiten Besonderer Dank diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index bdcfc182cc9..3041ae315d7 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -33,7 +33,6 @@ Core app Εικονίδια - Dependencies Special thanks diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 7823eaee94c..17cf6c8d98f 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -33,7 +33,6 @@ Core app Icons - Dependencies Special thanks diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 419742f5126..a29653b6654 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -33,7 +33,6 @@ Core app Iconos - Dependencies Special thanks diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index 92ae1aa4582..c9fef536a95 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -33,7 +33,6 @@ Core app Kuvakkeet - Dependencies Special thanks diff --git a/app/src/main/res/values-fil-rPH/strings.xml b/app/src/main/res/values-fil-rPH/strings.xml index 34d46654429..c8a453a8f0f 100644 --- a/app/src/main/res/values-fil-rPH/strings.xml +++ b/app/src/main/res/values-fil-rPH/strings.xml @@ -33,7 +33,6 @@ Core app Mga Icon - Dependencies Espesyal na pagsasalamat diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 4418dc73661..76fc6e5f4fb 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -33,7 +33,6 @@ Core app Icônes - Dependencies Remerciements spéciaux diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index bdf5ded2ef3..3184fce8814 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -33,7 +33,6 @@ Core app चिह्न - Dependencies विशेष धन्यवाद diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index ea13a9c6a7a..ba7af2b819a 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -33,7 +33,6 @@ Core app Ikonok - Dependencies Special thanks diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index 1a1b8444c89..3f09b2b5753 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -33,7 +33,6 @@ Core app Ikon - Dependencies Terima kasih Khusus diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 715511adeea..cb0f69037e7 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -33,7 +33,6 @@ Core app Icone - Dependencies Special thanks diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml index 79c06deb07b..3181c5bbb22 100644 --- a/app/src/main/res/values-iw-rIL/strings.xml +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -33,7 +33,6 @@ Core app סמלים - Dependencies Special thanks diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index b1f22fed11c..f8340bc15e1 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -33,7 +33,6 @@ Core app アイコン - Dependencies Special thanks diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index bf143a3833c..89abc4a41de 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -33,7 +33,6 @@ 코어 앱 아이콘 - 의존성 라이브러리 Special thanks diff --git a/app/src/main/res/values-mr-rIN/strings.xml b/app/src/main/res/values-mr-rIN/strings.xml index ddde439db36..f35f9398a2e 100644 --- a/app/src/main/res/values-mr-rIN/strings.xml +++ b/app/src/main/res/values-mr-rIN/strings.xml @@ -33,7 +33,6 @@ Core app चिन्हे - Dependencies विशेष धन्यवाद diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index ed7f5e8254d..67620cfd5dd 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -33,7 +33,6 @@ Core app Pictogrammen - Dependencies Special thanks diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml index bb49477c568..bd33741642e 100644 --- a/app/src/main/res/values-no-rNO/strings.xml +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -33,7 +33,6 @@ Core app Ikoner - Dependencies Special thanks diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 8c515dfff7a..d5fe76ffd3f 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -33,7 +33,6 @@ Core app Ikony - Dependencies Specjalne podziękowania diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 09a4d4bf363..fb2e7ac9e09 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -33,7 +33,6 @@ Core app Ícones - Dependencies Special thanks diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index 09a4d4bf363..fb2e7ac9e09 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -33,7 +33,6 @@ Core app Ícones - Dependencies Special thanks diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 6ab1eb1b78c..3b950f5c352 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -33,7 +33,6 @@ Core app Pictograme - Dependencies Special thanks diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 624da4179d8..038759f7b9a 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -33,7 +33,6 @@ Core app Иконки - Dependencies Special thanks diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 0be8e30f06b..69e728926d2 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -33,7 +33,6 @@ Core app Ikoner - Dependencies Special thanks diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index b0178be1bf8..1f3cb6fa825 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -33,7 +33,6 @@ Core app Resimleyici - Dependencies Special thanks diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index de18cdc6fe3..10ee5b370e2 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -33,7 +33,6 @@ Головний додаток Значки - Залежності Особлива подяка diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index d74e329d5a2..d72618aabcc 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -33,7 +33,6 @@ Core app Biểu tượng - Dependencies Special thanks diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5351f587b8b..cd45165288a 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -33,7 +33,6 @@ Core app 图标 - Dependencies Special thanks diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 46033a92969..49ef20d6629 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -33,7 +33,6 @@ Core app 圖示 - Dependencies Special thanks diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d02c191f394..19bdf595c38 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -45,7 +45,7 @@ Core app Icons - Dependencies + Infrastructure From fc2f199608372dbe31758e618bdaa6996a3e421e Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:44:06 +0800 Subject: [PATCH 078/144] Improve snackbar behavior --- .../ui/components/home/IconRequestFAB.kt | 66 +++++++++++-------- app/src/main/res/values/strings.xml | 3 +- 2 files changed, 42 insertions(+), 27 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 3ce7213b7e8..06d88d6c2cd 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -188,6 +188,7 @@ private fun HandleTouchInteractions( encodedRequestList: String, snackbarHostState: SnackbarHostState, ) { + val prefs = preferenceManager() val lastestOnExpandSheet by rememberUpdatedState(newValue = onExpandSheet) LaunchedEffect(interactionSource) { var isLongClick = false @@ -206,18 +207,16 @@ private fun HandleTouchInteractions( is PressInteraction.Release -> { if (!isLongClick) { - if (iconRequestList.isEmpty()) { - openLink(context, Constants.ICON_REQUEST_FORM) - } else if (directLinkEnabled) { - openLink(context, encodedRequestList) - } else { - openSnackbarWarningContent( - context, - requestList, - coroutineScope, - snackbarHostState, - ) - } + prefs.showFirstLaunchSnackbar.set(false) + handleRequestClick( + iconRequestList, + context, + directLinkEnabled, + encodedRequestList, + requestList, + coroutineScope, + snackbarHostState, + ) } } @@ -275,6 +274,30 @@ private fun copyTextToClipboard(context: Context, text: String) { clipboard.setPrimaryClip(clip) } + +private fun handleRequestClick( + iconRequestList: List, + context: Context, + directLinkEnabled: Boolean, + encodedRequestList: String, + requestList: String, + coroutineScope: CoroutineScope, + snackbarHostState: SnackbarHostState, +) { + if (iconRequestList.isEmpty()) { + openLink(context, Constants.ICON_REQUEST_FORM) + } else if (directLinkEnabled) { + openLink(context, encodedRequestList) + } else { + openSnackbarWarningContent( + context, + requestList, + coroutineScope, + snackbarHostState, + ) + } +} + private fun openSnackbarFirstLaunchContent( context: Context, coroutineScope: CoroutineScope, @@ -284,21 +307,12 @@ private fun openSnackbarFirstLaunchContent( coroutineScope.launch { val result = snackbarHostState .showSnackbar( - message = context.getString(R.string.you_have_missing_icons), - actionLabel = context.getString(R.string.request_icons), - withDismissAction = true, - duration = SnackbarDuration.Indefinite, + message = context.getString(R.string.snackbar_request_icons_hint), + duration = SnackbarDuration.Long, ) - when (result) { - SnackbarResult.ActionPerformed -> { - onActionPerformed() - openLink(context, Constants.ICON_REQUEST_FORM) - } - - SnackbarResult.Dismissed -> { - onActionPerformed() - snackbarHostState.currentSnackbarData?.dismiss() - } + if (result == SnackbarResult.Dismissed) { + onActionPerformed() + snackbarHostState.currentSnackbarData?.dismiss() } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 19bdf595c38..3f3ff0e25c4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -82,7 +82,8 @@ Copied text + Request missing icons from the bottom bar + Copied icon request details to clipboard. To request them, submit the details into the form. Open form - You have missing icons From 83df10f0ec90334f71d0619cb03c2f68ff80ef46 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Fri, 23 Aug 2024 14:48:53 +0800 Subject: [PATCH 079/144] Fix style --- .../app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 06d88d6c2cd..8e3cdee83b1 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -274,7 +274,6 @@ private fun copyTextToClipboard(context: Context, text: String) { clipboard.setPrimaryClip(clip) } - private fun handleRequestClick( iconRequestList: List, context: Context, From 3ded652477c6aaee11a4b96ac8ce7032bc538507 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:40:07 +0300 Subject: [PATCH 080/144] Clarified the process of adding and linking icons (#2282) * Clarified the process of adding and linking icons * Update CONTRIBUTING.md --- CONTRIBUTING.md | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52513979e45..06c3dc6cfa1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -123,31 +123,35 @@ Correct ``` ## Adding an icon to Lawnicons -Here's how to add an icon to Lawnicons: - ### Prerequisites -* Your icon in the SVG format, adhering to the [above guidelines](#contributing-icons). The filename must use snake case (e.g. `files_by_google.svg`). -* The package and activity name of the app. +* A fork of the Lawnicons repository; +* Your icon in the SVG format, adhering to the [above guidelines](#contributing-icons). The filename must use snake case (e.g. `spck_editor.svg`). +* The package and activity name of the app; ### Via `icontool.py` -Please check the [icon tool guide](/docs/icontool_guide.md) for more information. +Please check [the icon tool guide](/docs/icontool_guide.md) for more information. ### Via manual process -1. Add the ready SVG to the `svgs` directory. +1. Add the ready SVG to the `svgs` directory. If you want to add a link to an existing SVG, you will need its name. -1. Add a new line to `app/assets/appfilter.xml` (in alphabetical order, by the `name` attribute), and map the new icon to a package name and app's activity. For example: +2. Add a new line to `app/assets/appfilter.xml` (in alphabetical order, by the `name` attribute), and map the new icon to a package name and app's activity. + **Example** + - the app name: `Spck Editor`; + - the svg (drawable) name: `spck_editor`; + - the package and activity of the app: `io.spck/io.spck.EditorActivity`. + + **The new line** ```xml - + ``` - A general template is as follows: - + **General template** ```xml ``` -1. Done! You're ready to open a pull request. Please set `develop` as the base branch. +4. Done! You're ready to open a pull request. Please set `develop` as the base branch. ## Finding the package and activity name of an app @@ -158,8 +162,8 @@ Please check the [icon tool guide](/docs/icontool_guide.md) for more information ### Using `adb` 1. Connect your Android device or emulator to your laptop/desktop PC that has `adb` installed (see [this tutorial](https://www.xda-developers.com/install-adb-windows-macos-linux/) for more information) and open the app whose details you want to inspect, e.g. Telegram. -1. Open a new Command Prompt or Terminal window and input `adb devices`. -1. Finally, type the below-given command to get the information about the currently open application. +2. Open a new Command Prompt or Terminal window and input `adb devices`. +3. Finally, type the below-given command to get the information about the currently open application. **For Mac or Linux**: From be66330b688912215143409a75d4d9a9ba571b6d Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Tue, 27 Aug 2024 16:06:36 +0300 Subject: [PATCH 081/144] Updating the self-review checklist 2 (#2286) --- .github/icon_checklist.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index 64b8cb378d3..8059999f6d6 100644 --- a/.github/icon_checklist.md +++ b/.github/icon_checklist.md @@ -6,21 +6,21 @@ While waiting for a review from our team, you can do a self-review to ensure tha 1. Canvas: `192×192px`. 2. Non-square icons: the long side of the icons should be `160px`. 3. Square icons: `154×154px`. -- [ ] Done +- [ ] Approved by the Lawnicons reviewer ### Color, stroke width and rounding -1. Color: black `#000`. +1. Color: non-transparent black `#000`. 2. No fill. Base stroke width: `12px`. `14px`, `10px`, `8px` — depending on the shape of the icons. `6px` — for fine details. 3. Rounded ends and joins. 90° corners are rounded by `6-32px`. -- [ ] Done +- [ ] Approved by the Lawnicons reviewer ### Naming 1. Names should match the official app name and contain no additional text. 2. If the first `3` characters of the app name contain letters not from the English alphabet, then add a localized (or transliterated) name via `~~`. Example: `京东 ~~ JD`. 3. The names of the drawables should repeat the names of the apps if nothing prevents it. -- [ ] Done +- [ ] Approved by the Lawnicons reviewer ### Quality 1. Ensure that icons are easily recognizable. 2. Align icons to [the visual center](https://crazybitsstudios.com/another-way-of-aligning-elements-when-creating-icons) as much as possible within the guidelines. The visual center is where your icon looks and feels centered. 3. Avoid noticable black spots by reducing the stroke width or simplifying the icons. 4. Avoid close distances between strokes. The icons on the phone screen will be smaller, so the small distances between the strokes will stick together. 5. Avoid drastic changes in stroke widths. When the strokes next to each other differ in width by 4px or more, the icon will look sloppy. -- [ ] Done +- [ ] Approved by the Lawnicons reviewer From b9c4f8ab4cf0c5372cb62f4a63c2776368353fd6 Mon Sep 17 00:00:00 2001 From: 92 <169070113+I21b@users.noreply.github.com> Date: Wed, 28 Aug 2024 03:49:45 +0900 Subject: [PATCH 082/144] +3 icons (#2279) * +3 icons * minor fix custom_uploader svg --- app/assets/appfilter.xml | 3 +++ svgs/cuberite.svg | 3 +++ svgs/custom_uploader.svg | 3 +++ svgs/look4sat.svg | 3 +++ 4 files changed, 12 insertions(+) create mode 100644 svgs/cuberite.svg create mode 100644 svgs/custom_uploader.svg create mode 100644 svgs/look4sat.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 3059e6e48d2..f440cf61c45 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -2348,6 +2348,7 @@ + @@ -2357,6 +2358,7 @@ + @@ -5322,6 +5324,7 @@ + diff --git a/svgs/cuberite.svg b/svgs/cuberite.svg new file mode 100644 index 00000000000..eb91ad479df --- /dev/null +++ b/svgs/cuberite.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/custom_uploader.svg b/svgs/custom_uploader.svg new file mode 100644 index 00000000000..885def8995c --- /dev/null +++ b/svgs/custom_uploader.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/look4sat.svg b/svgs/look4sat.svg new file mode 100644 index 00000000000..5942dcf582e --- /dev/null +++ b/svgs/look4sat.svg @@ -0,0 +1,3 @@ + + + From 35581a1ee6426b9920af50f1fedabae810f88545 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Aug 2024 09:18:55 +0800 Subject: [PATCH 083/144] Update dependency org.jetbrains.kotlinx:kotlinx-serialization-json to v1.7.2 (#2287) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cf9f33d9ef0..934e4849cf6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -147,7 +147,7 @@ dependencies { implementation("androidx.navigation:navigation-compose:2.8.0-rc01") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") val hiltVersion = "2.52" From 7a95b69165b66e29e2d41d790c32043daf22d1d2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 09:45:23 +0800 Subject: [PATCH 084/144] Update AGP (#2288) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- svg-processor/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index fa51ad45f0a..74f2bec6281 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import com.diffplug.gradle.spotless.SpotlessExtension import com.diffplug.spotless.extra.wtp.EclipseWtpFormatterStep plugins { - id("com.android.application") version "8.5.2" apply false + id("com.android.application") version "8.6.0" apply false id("org.jetbrains.kotlin.android") version "2.0.20" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.20" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" apply false diff --git a/svg-processor/build.gradle.kts b/svg-processor/build.gradle.kts index 2df983d5b96..83eaaf8b79a 100644 --- a/svg-processor/build.gradle.kts +++ b/svg-processor/build.gradle.kts @@ -8,7 +8,7 @@ application { } dependencies { - implementation("com.android.tools:sdk-common:31.5.2") + implementation("com.android.tools:sdk-common:31.6.0") implementation("org.dom4j:dom4j:2.1.4") implementation("commons-io:commons-io:2.16.1") } From 758d919a322e9ffcebf00b82c66fe317b76eaedf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 19:31:40 +0800 Subject: [PATCH 085/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.11 (#2289) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 74f2bec6281..5bb8a8f1fd1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.10", + "io.nlopez.compose.rules:ktlint:0.4.11", ), ).editorConfigOverride( mapOf( From 81f2c9b6848077b84c25cb694508abbd917ec0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B5=81=E5=85=89?= <45266046+DreamVoid@users.noreply.github.com> Date: Sat, 31 Aug 2024 23:59:35 +0800 Subject: [PATCH 086/144] Link Raileay 12306 (#2290) --- app/assets/appfilter.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index f440cf61c45..aea60f676fd 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -12415,6 +12415,7 @@ + From 5ae99dba3fd1c5914d475d806907712be3b8f85e Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 31 Aug 2024 19:20:39 +0300 Subject: [PATCH 087/144] +37 links (#2291) --- app/assets/appfilter.xml | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index aea60f676fd..9e783d289bd 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -512,6 +512,7 @@ + @@ -681,6 +682,7 @@ + @@ -796,6 +798,7 @@ + @@ -956,6 +959,7 @@ + @@ -988,9 +992,11 @@ + + @@ -1115,6 +1121,7 @@ + @@ -1330,6 +1337,7 @@ + @@ -2620,6 +2628,7 @@ + @@ -4003,6 +4012,7 @@ + @@ -4278,6 +4288,8 @@ + + @@ -4361,6 +4373,7 @@ + @@ -4395,6 +4408,7 @@ + @@ -4830,6 +4844,7 @@ + @@ -5116,11 +5131,11 @@ - + @@ -5138,6 +5153,8 @@ + + @@ -5537,6 +5554,7 @@ + @@ -5804,6 +5822,8 @@ + + @@ -5902,6 +5922,7 @@ + @@ -6113,6 +6134,7 @@ + @@ -6267,6 +6289,8 @@ + + @@ -8245,6 +8269,7 @@ + @@ -8887,6 +8912,7 @@ + @@ -9489,6 +9515,7 @@ + @@ -9685,6 +9712,7 @@ + @@ -9816,6 +9844,7 @@ + @@ -10108,6 +10137,7 @@ + @@ -11076,6 +11106,7 @@ + @@ -11363,6 +11394,7 @@ + @@ -11371,6 +11403,7 @@ + @@ -11759,6 +11792,7 @@ + @@ -12024,6 +12058,7 @@ + @@ -12265,6 +12300,7 @@ + @@ -12329,6 +12365,7 @@ + From d8376706c8b16e3f8cab8b384fa79d91b9025a3e Mon Sep 17 00:00:00 2001 From: Chang Jiaman Date: Sun, 1 Sep 2024 14:43:44 +0800 Subject: [PATCH 088/144] +1 icon (#2292) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * link hihonor music, legado(play) * add todesk,yunrili * +6,link 1 * +2 icons * link1 * fix icons,+1 icon * fix * Fixed IQIYI → iQIYI * Improved iqiyi.svg quality for small sizes * The visual center of ithome.svg has been clarified * Moved kaadas.svg so that it is located within the boundaries of the content area and reduced the density at the bottom * +1 icon * Rename hkbank.svg to hankou_bank.svg * Unnecessary additions have been removed --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 1 + svgs/hankou_bank.svg | 1 + 2 files changed, 2 insertions(+) create mode 100644 svgs/hankou_bank.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 9e783d289bd..b5742e7a647 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -12470,6 +12470,7 @@ + diff --git a/svgs/hankou_bank.svg b/svgs/hankou_bank.svg new file mode 100644 index 00000000000..86e16c2a997 --- /dev/null +++ b/svgs/hankou_bank.svg @@ -0,0 +1 @@ + From af69fb035ae3b6ebdb1e8a47e187b1a16b6b0995 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:28:02 +0800 Subject: [PATCH 089/144] Implement build variant for play store --- app/build.gradle.kts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 934e4849cf6..00692471e8e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,6 +69,11 @@ android { isMinifyEnabled = true proguardFiles("proguard-rules.pro") } + create("play") { + applicationIdSuffix = ".play" + isMinifyEnabled = true + proguardFiles("proguard-rules.pro") + } } flavorDimensions += "product" From 725bf6cf117b8209e977314ad71f626fa87781c8 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Wed, 4 Sep 2024 20:55:44 +0800 Subject: [PATCH 090/144] Use rememberSaveable for certain parts of the UI Should fix some of the crashes from invalid state --- .../lawnicons/ui/components/home/IconInfoSheet.kt | 5 +++-- .../lawnicons/ui/components/home/IconRequestFAB.kt | 7 ++++--- .../lawnicons/ui/components/home/search/SearchContents.kt | 3 ++- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconInfoSheet.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconInfoSheet.kt index e48e807a60d..c79a5685d7d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconInfoSheet.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconInfoSheet.kt @@ -29,6 +29,7 @@ import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode @@ -58,7 +59,7 @@ fun IconInfoSheet( skipPartiallyExpanded = true, ) - val groupedComponents = remember { + val groupedComponents = rememberSaveable { iconInfo.componentNames .groupBy { it.label } .map { (label, components) -> @@ -71,7 +72,7 @@ fun IconInfoSheet( newValue = "", ) - val shareContents = remember { getShareContents(githubName, groupedComponents) } + val shareContents = rememberSaveable { getShareContents(githubName, groupedComponents) } ModalBottomSheet( onDismissRequest = { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 8e3cdee83b1..20b6d652999 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -37,6 +37,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -130,13 +131,13 @@ fun RequestHandler( val encodedRequestList = buildForm(requestList.replace("\n", "%20")) val directLinkEnabled = encodedRequestList.length < Constants.DIRECT_LINK_MAX_LENGTH - var sheetExpanded by remember { mutableStateOf(false) } + var sheetExpanded by rememberSaveable { mutableStateOf(false) } val sheetState = rememberModalBottomSheetState( skipPartiallyExpanded = true, ) val scope = rememberCoroutineScope() - val interactionSource = remember { MutableInteractionSource() } + val interactionSource = rememberSaveable { MutableInteractionSource() } HandleTouchInteractions( interactionSource = interactionSource, @@ -307,7 +308,7 @@ private fun openSnackbarFirstLaunchContent( val result = snackbarHostState .showSnackbar( message = context.getString(R.string.snackbar_request_icons_hint), - duration = SnackbarDuration.Long, + duration = SnackbarDuration.Short, ) if (result == SnackbarResult.Dismissed) { onActionPerformed() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt index c2f05d47838..70e482f2fae 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt @@ -30,6 +30,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -180,7 +181,7 @@ private fun IconInfoListItem(iconInfo: ImmutableList) { return@IconInfoListItem } - val isIconInfoAppfilterShown = remember { mutableStateOf(false) } + val isIconInfoAppfilterShown = rememberSaveable { mutableStateOf(false) } ListItem( headlineContent = { Text(it.getFirstLabelAndComponent().label) }, From b9281485081029ac4c2f792282b12378558e5cd9 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Wed, 4 Sep 2024 22:56:30 +0800 Subject: [PATCH 091/144] Simplify code --- .../ui/components/home/HomeTopBar.kt | 28 +++----- .../ui/components/home/IconRequestFAB.kt | 2 +- .../ui/components/home/OverflowMenu.kt | 58 --------------- .../ui/components/home/search/SearchBar.kt | 70 ++++++++----------- .../components/home/search/SearchContents.kt | 1 - 5 files changed, 39 insertions(+), 120 deletions(-) delete mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/OverflowMenu.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt index cd1c1021216..9c2b6afae38 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeTopBar.kt @@ -41,10 +41,8 @@ fun HomeTopBar( ) { val (isSearchExpanded, isExpandedScreen, searchTerm, searchMode, searchedIconInfoModel, isIconPicker) = uiState - val condition = isSearchExpanded || isExpandedScreen - val offset = animateDpAsState( - targetValue = if (condition) { + targetValue = if (isSearchExpanded || isExpandedScreen) { 0.dp } else { (-100).dp @@ -59,7 +57,7 @@ fun HomeTopBar( }, searchTerm = searchTerm, onClearSearch = onClearSearch, - onChangeMode = onChangeMode, + onModeChange = onChangeMode, onSearch = onSearchIcons, iconInfoModel = it, onNavigate = onNavigate, @@ -79,7 +77,7 @@ private fun SearchBar( searchTerm: String, onSearch: (String) -> Unit, onClearSearch: () -> Unit, - onChangeMode: (SearchMode) -> Unit, + onModeChange: (SearchMode) -> Unit, onNavigate: () -> Unit, isExpandedScreen: Boolean, isIconPicker: Boolean, @@ -97,15 +95,9 @@ private fun SearchBar( LawniconsSearchBar( query = searchTerm, isQueryEmpty = searchTerm == "", - onClear = { - onClearSearch() - }, - onBack = { - onFocusChange() - }, - onQueryChange = { newValue -> - onSearch(newValue) - }, + onClear = onClearSearch, + onBack = onFocusChange, + onQueryChange = onSearch, iconInfoModel = iconInfoModel, onNavigate = onNavigate, isExpandedScreen = isExpandedScreen, @@ -114,13 +106,9 @@ private fun SearchBar( SearchContents( searchTerm = searchTerm, searchMode = searchMode, - onModeChange = { mode -> - onChangeMode(mode) - }, + onModeChange = onModeChange, iconInfo = iconInfoModel.iconInfo, - onSendResult = { - onSendResult(it) - }, + onSendResult = onSendResult, ) }, inputFieldModifier = inputFieldModifier, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 20b6d652999..2106ec0cd94 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -137,7 +137,7 @@ fun RequestHandler( ) val scope = rememberCoroutineScope() - val interactionSource = rememberSaveable { MutableInteractionSource() } + val interactionSource = remember { MutableInteractionSource() } HandleTouchInteractions( interactionSource = interactionSource, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/OverflowMenu.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/OverflowMenu.kt deleted file mode 100644 index 99caf61734b..00000000000 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/OverflowMenu.kt +++ /dev/null @@ -1,58 +0,0 @@ -package app.lawnchair.lawnicons.ui.components.home - -import androidx.compose.foundation.layout.Box -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.MoreVert -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.LocalContentColor -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.dp - -@Composable -fun OverflowMenu( - modifier: Modifier = Modifier, - block: @Composable OverflowMenuScope.() -> Unit, -) { - val showMenu = remember { mutableStateOf(false) } - val overflowMenuScope = remember { OverflowMenuScopeImpl(showMenu) } - - Box( - modifier = modifier, - ) { - ClickableIcon( - imageVector = Icons.Rounded.MoreVert, - size = 52.dp, - onClick = { showMenu.value = true }, - ) - DropdownMenu( - expanded = showMenu.value, - onDismissRequest = { showMenu.value = false }, - offset = DpOffset(x = 16.dp, y = (-36).dp), - ) { - CompositionLocalProvider( - LocalContentColor - provides MaterialTheme.colorScheme.onSurface, - ) { - block(overflowMenuScope) - } - } - } -} - -interface OverflowMenuScope { - fun hideMenu() -} - -private class OverflowMenuScopeImpl(private val showState: MutableState) : - OverflowMenuScope { - override fun hideMenu() { - showState.value = false - } -} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt index 435cd245b92..c2e1d4ac3d5 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt @@ -5,6 +5,7 @@ import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize @@ -214,8 +215,23 @@ private fun ResponsiveSearchBar( isExpandedScreen: Boolean, modifier: Modifier = Modifier, inputFieldModifier: Modifier = Modifier, - content: @Composable () -> Unit, + content: @Composable ColumnScope.() -> Unit, ) { + val inputField = + @Composable { + SearchBarDefaults.InputField( + query = query, + onQueryChange = onQueryChange, + onSearch = onSearch, + modifier = inputFieldModifier, + expanded = active, + onExpandedChange = onActiveChange, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIcon = trailingIcon, + ) + } + if (isExpandedScreen) { Row( verticalAlignment = Alignment.CenterVertically, @@ -223,47 +239,19 @@ private fun ResponsiveSearchBar( modifier = modifier, ) { DockedSearchBar( - inputField = { - SearchBarDefaults.InputField( - query = query, - onQueryChange = onQueryChange, - onSearch = onSearch, - modifier = inputFieldModifier, - expanded = active, - onExpandedChange = onActiveChange, - placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon, - ) - }, + inputField = inputField, expanded = active, onExpandedChange = onActiveChange, - content = { - content() - }, + content = content, ) } } else { SearchBar( - inputField = { - SearchBarDefaults.InputField( - query = query, - onQueryChange = onQueryChange, - onSearch = onSearch, - modifier = inputFieldModifier, - expanded = active, - onExpandedChange = onActiveChange, - placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIcon = trailingIcon, - ) - }, + inputField = inputField, expanded = active, onExpandedChange = onActiveChange, modifier = Modifier.fillMaxWidth(), - content = { - content() - }, + content = content, ) } } @@ -273,13 +261,15 @@ internal fun SearchIcon( active: Boolean, onButtonClick: () -> Unit, ) { - if (active) { - ClickableIcon( - imageVector = Icons.AutoMirrored.Rounded.ArrowBack, - onClick = onButtonClick, - ) - } else { - Icon(Icons.Rounded.Search, contentDescription = null) + Crossfade(active, label = "") { + if (it) { + ClickableIcon( + imageVector = Icons.AutoMirrored.Rounded.ArrowBack, + onClick = onButtonClick, + ) + } else { + Icon(Icons.Rounded.Search, contentDescription = null) + } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt index 70e482f2fae..bd919f75d08 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt @@ -29,7 +29,6 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier From 1292415090e193e6c1dbda37db5d684815234dbd Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 5 Sep 2024 00:10:42 +0800 Subject: [PATCH 092/144] Add background to scrollbar, highlight icons on scrollbar click When selecting the scrollbar, the icons with the same letter will now be scaled (110%) to highlight that they are the same category. Further improvements can be made after discussion. --- .../ui/components/home/IconPreview.kt | 13 +-- .../ui/components/home/IconPreviewGrid.kt | 102 ++++++++++++------ 2 files changed, 79 insertions(+), 36 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreview.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreview.kt index 213ae98691b..8847e7801de 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreview.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreview.kt @@ -33,11 +33,12 @@ import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData import kotlin.math.ln -private fun ColorScheme.iconColor(): Color { - val elevation = 3.dp - val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f - return primary.copy(alpha = alpha).compositeOver(surface) -} +val ColorScheme.iconColor: Color + get() { + val elevation = 3.dp + val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f + return primary.copy(alpha = alpha).compositeOver(surface) + } @Composable fun IconPreview( @@ -68,7 +69,7 @@ fun IconPreview( color = iconBackground ?: if (isIconInfoShown.value) { MaterialTheme.colorScheme.surfaceVariant } else { - MaterialTheme.colorScheme.iconColor() + MaterialTheme.colorScheme.iconColor }, ), ) { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 92c81d274b2..8dd5edfc33e 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -1,6 +1,7 @@ package app.lawnchair.lawnicons.ui.components.home import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.foundation.ExperimentalFoundationApi @@ -9,13 +10,14 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBarsPadding @@ -27,15 +29,21 @@ import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.rememberLazyGridState +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -48,7 +56,7 @@ import app.lawnchair.lawnicons.ui.util.SampleData import app.lawnchair.lawnicons.ui.util.toPaddingValues import app.lawnchair.lawnicons.util.appIcon import kotlinx.collections.immutable.ImmutableList -import my.nanihadesuka.compose.LazyVerticalGridScrollbar +import my.nanihadesuka.compose.InternalLazyVerticalGridScrollbar import my.nanihadesuka.compose.ScrollbarSelectionMode import my.nanihadesuka.compose.ScrollbarSettings @@ -63,34 +71,31 @@ fun IconPreviewGrid( contentPadding: PaddingValues? = null, gridState: LazyGridState = rememberLazyGridState(), ) { - val indexOfFirstItem = remember { derivedStateOf { gridState.firstVisibleItemIndex } } - val letter = iconInfo[indexOfFirstItem.value].label[0].uppercase() + val indexOfFirstItem by remember { derivedStateOf { gridState.firstVisibleItemIndex } } + val letter = iconInfo[indexOfFirstItem].label[0].uppercase() + var thumbSelected by remember { mutableStateOf(false) } Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth(), ) { - LazyVerticalGridScrollbar( + val horizontalGridPadding = if (isExpandedScreen) 32.dp else 8.dp + Box( modifier = Modifier .widthIn(max = 640.dp) .fillMaxWidth() .statusBarsPadding() .then( - if (isExpandedScreen) Modifier.padding(top = 26.dp) else Modifier.padding(bottom = 80.dp), + if (isExpandedScreen) { + Modifier.padding(top = 26.dp) + } else { + Modifier.padding( + bottom = 80.dp, + ) + }, ), - state = gridState, - settings = ScrollbarSettings( - alwaysShowScrollbar = true, - thumbUnselectedColor = MaterialTheme.colorScheme.primaryContainer, - thumbSelectedColor = MaterialTheme.colorScheme.primary, - selectionMode = ScrollbarSelectionMode.Thumb, - ), - indicatorContent = { _, isThumbSelected -> - ScrollbarIndicator(letter, isThumbSelected) - }, ) { - val horizontalGridPadding = if (isExpandedScreen) 32.dp else 8.dp LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 80.dp), contentPadding = contentPadding ?: WindowInsets.navigationBars.toPaddingValues( @@ -106,26 +111,63 @@ fun IconPreviewGrid( GridItemSpan(maxLineSpan) }, ) { - TopAppBar() + AppBarListItem() + } + items( + items = iconInfo, + contentType = { "icon_preview" }, + ) { iconInfo -> + val scale by animateFloatAsState( + if (thumbSelected && iconInfo.label.first() + .toString() == letter + ) { + 1.1f + } else { + 1f + }, + label = "", + ) + IconPreview( + modifier = Modifier + .scale(scale), + iconInfo = iconInfo, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + ) } } - items( - items = iconInfo, - contentType = { "icon_preview" }, - ) { iconInfo -> - IconPreview( - iconInfo = iconInfo, - isIconPicker = isIconPicker, - onSendResult = onSendResult, - ) - } + } + Box( + contentAlignment = Alignment.CenterEnd, + ) { + Spacer( + Modifier + .fillMaxHeight() + .width(8.dp) + .background(MaterialTheme.colorScheme.surfaceContainer) + .clip(CircleShape), + ) + InternalLazyVerticalGridScrollbar( + modifier = Modifier.offset(7.dp), + state = gridState, + settings = ScrollbarSettings( + alwaysShowScrollbar = true, + thumbUnselectedColor = MaterialTheme.colorScheme.primary, + thumbSelectedColor = MaterialTheme.colorScheme.primary, + selectionMode = ScrollbarSelectionMode.Thumb, + ), + indicatorContent = { _, isThumbSelected -> + thumbSelected = isThumbSelected + ScrollbarIndicator(letter, isThumbSelected) + }, + ) } } } } @Composable -private fun ColumnScope.ScrollbarIndicator( +private fun ScrollbarIndicator( label: String, isThumbSelected: Boolean, ) { @@ -154,7 +196,7 @@ private fun ColumnScope.ScrollbarIndicator( @OptIn(ExperimentalMaterial3Api::class) @Composable -fun TopAppBar(modifier: Modifier = Modifier) { +private fun AppBarListItem(modifier: Modifier = Modifier) { val context = LocalContext.current CenterAlignedTopAppBar( modifier = modifier, From 65462534f7fd1a3a251dfabcbc8ec82e50be33f3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:10:16 +0800 Subject: [PATCH 093/144] Update dependency androidx.compose.material3:material3 to v1.3.0 (#2301) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 00692471e8e..aa7b138b548 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -147,7 +147,7 @@ dependencies { debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") implementation("androidx.compose.material:material-icons-core-android:1.6.8") - implementation("androidx.compose.material3:material3:1.3.0-rc01") + implementation("androidx.compose.material3:material3:1.3.0") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0-rc01") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") From b74ea4dc965fab0cfb77ac680c289423132a87f2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:10:27 +0800 Subject: [PATCH 094/144] Update dependency androidx.activity:activity-compose to v1.9.2 (#2300) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index aa7b138b548..593c59e1b60 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -139,7 +139,7 @@ licensee { dependencies { implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-splashscreen:1.0.1") - implementation("androidx.activity:activity-compose:1.9.1") + implementation("androidx.activity:activity-compose:1.9.2") implementation(platform("androidx.compose:compose-bom:2024.08.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") From adbc56b285913960d74993bea5c2704d482a0b9d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:19:05 +0800 Subject: [PATCH 095/144] Update dependency androidx.navigation:navigation-compose to v2.8.0 (#2303) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 593c59e1b60..031ab6089dc 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -149,7 +149,7 @@ dependencies { implementation("androidx.compose.material:material-icons-core-android:1.6.8") implementation("androidx.compose.material3:material3:1.3.0") implementation("androidx.compose.material3:material3-window-size-class") - implementation("androidx.navigation:navigation-compose:2.8.0-rc01") + implementation("androidx.navigation:navigation-compose:2.8.0") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") From 0db2a48bb7dba4ee9dca638a97d0180eb4976ee1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:19:58 +0800 Subject: [PATCH 096/144] Update dependency androidx.lifecycle:lifecycle-viewmodel-compose to v2.8.5 (#2302) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 031ab6089dc..3d622851d5b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -150,7 +150,7 @@ dependencies { implementation("androidx.compose.material3:material3:1.3.0") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0") - implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4") + implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") From 00fe17ce7f175180b46e6d14df1307f8d89f29cf Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:26:45 +0800 Subject: [PATCH 097/144] Update dependency androidx.compose.material:material-icons-core-android to v1.7.0 (#2304) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3d622851d5b..9fd5328e8e4 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -146,7 +146,7 @@ dependencies { implementation("androidx.compose.ui:ui-util") debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") - implementation("androidx.compose.material:material-icons-core-android:1.6.8") + implementation("androidx.compose.material:material-icons-core-android:1.7.0") implementation("androidx.compose.material3:material3:1.3.0") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0") From bf13365326c7fc6f4e375842e90a470c142a1277 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 5 Sep 2024 09:27:57 +0800 Subject: [PATCH 098/144] Update dependency androidx.compose:compose-bom to v2024.09.00 (#2305) * Update dependency androidx.compose:compose-bom to v2024.09.00 * Tweaks --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Goooler --- app/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9fd5328e8e4..e720ad5decd 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -140,14 +140,14 @@ dependencies { implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.activity:activity-compose:1.9.2") - implementation(platform("androidx.compose:compose-bom:2024.08.00")) + implementation(platform("androidx.compose:compose-bom:2024.09.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.ui:ui-util") debugImplementation("androidx.compose.ui:ui-tooling") implementation("androidx.compose.animation:animation") - implementation("androidx.compose.material:material-icons-core-android:1.7.0") - implementation("androidx.compose.material3:material3:1.3.0") + implementation("androidx.compose.material:material-icons-core-android") + implementation("androidx.compose.material3:material3") implementation("androidx.compose.material3:material3-window-size-class") implementation("androidx.navigation:navigation-compose:2.8.0") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") From 569ab75b984265fde71dbd0ad18b87fa4a47a54e Mon Sep 17 00:00:00 2001 From: "M." Date: Thu, 5 Sep 2024 11:11:02 +0330 Subject: [PATCH 099/144] +1 icon (#2294) * added Beanconqueror * updated svg * Fix * Minor fix --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 3 ++- svgs/beanconqueror.svg | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 svgs/beanconqueror.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index b5742e7a647..7d396578232 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -954,6 +954,7 @@ + @@ -12377,6 +12378,7 @@ + @@ -12470,7 +12472,6 @@ - diff --git a/svgs/beanconqueror.svg b/svgs/beanconqueror.svg new file mode 100644 index 00000000000..8a743ef6a8c --- /dev/null +++ b/svgs/beanconqueror.svg @@ -0,0 +1 @@ + From 33db100912bbf4b77c218442bf5159ba12dd07d7 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 5 Sep 2024 11:06:32 +0300 Subject: [PATCH 100/144] Lawnicons update, +14 links (#2306) --- app/assets/appfilter.xml | 52 ++++++++++++------- svgs/{gta_sa.svg => gta_san_andreas.svg} | 0 svgs/{gta_vc.svg => gta_vice_city.svg} | 0 svgs/lawnicons.svg | 2 +- ...off_invest.svg => tinkoff_investments.svg} | 0 ...craft.svg => toolbox_for_minecraft_pe.svg} | 0 6 files changed, 34 insertions(+), 20 deletions(-) rename svgs/{gta_sa.svg => gta_san_andreas.svg} (100%) rename svgs/{gta_vc.svg => gta_vice_city.svg} (100%) rename svgs/{tinkoff_invest.svg => tinkoff_investments.svg} (100%) rename svgs/{toolbox_for_minecraft.svg => toolbox_for_minecraft_pe.svg} (100%) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 7d396578232..d58db01649e 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -319,6 +319,7 @@ + @@ -389,6 +390,7 @@ + @@ -4079,6 +4081,7 @@ + @@ -4155,21 +4158,22 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + @@ -4814,6 +4818,7 @@ + @@ -5121,6 +5126,7 @@ + @@ -7219,6 +7225,7 @@ + @@ -7534,6 +7541,7 @@ + @@ -10646,8 +10654,9 @@ - - + + + @@ -10662,6 +10671,7 @@ + @@ -11793,6 +11803,8 @@ + + @@ -11893,6 +11905,7 @@ + @@ -12171,8 +12184,9 @@ - - + + + diff --git a/svgs/gta_sa.svg b/svgs/gta_san_andreas.svg similarity index 100% rename from svgs/gta_sa.svg rename to svgs/gta_san_andreas.svg diff --git a/svgs/gta_vc.svg b/svgs/gta_vice_city.svg similarity index 100% rename from svgs/gta_vc.svg rename to svgs/gta_vice_city.svg diff --git a/svgs/lawnicons.svg b/svgs/lawnicons.svg index 7f48dd1e280..1a5943746ba 100644 --- a/svgs/lawnicons.svg +++ b/svgs/lawnicons.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/tinkoff_invest.svg b/svgs/tinkoff_investments.svg similarity index 100% rename from svgs/tinkoff_invest.svg rename to svgs/tinkoff_investments.svg diff --git a/svgs/toolbox_for_minecraft.svg b/svgs/toolbox_for_minecraft_pe.svg similarity index 100% rename from svgs/toolbox_for_minecraft.svg rename to svgs/toolbox_for_minecraft_pe.svg From 43080ffd28417853354a9435f99c22d044314cee Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:18:26 +0800 Subject: [PATCH 101/144] Fix grid not showing on expanded devices --- .../ui/components/home/IconPreviewGrid.kt | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 8dd5edfc33e..98284cb58a6 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -33,6 +33,7 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.derivedStateOf @@ -46,6 +47,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R @@ -113,28 +115,28 @@ fun IconPreviewGrid( ) { AppBarListItem() } - items( - items = iconInfo, - contentType = { "icon_preview" }, - ) { iconInfo -> - val scale by animateFloatAsState( - if (thumbSelected && iconInfo.label.first() - .toString() == letter - ) { - 1.1f - } else { - 1f - }, - label = "", - ) - IconPreview( - modifier = Modifier - .scale(scale), - iconInfo = iconInfo, - isIconPicker = isIconPicker, - onSendResult = onSendResult, - ) - } + } + items( + items = iconInfo, + contentType = { "icon_preview" }, + ) { iconInfo -> + val scale by animateFloatAsState( + if (thumbSelected && iconInfo.label.first() + .toString() == letter + ) { + 1.1f + } else { + 1f + }, + label = "", + ) + IconPreview( + modifier = Modifier + .scale(scale), + iconInfo = iconInfo, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + ) } } Box( @@ -204,11 +206,13 @@ private fun AppBarListItem(modifier: Modifier = Modifier) { Row( verticalAlignment = Alignment.CenterVertically, ) { - Image( - bitmap = context.appIcon().asImageBitmap(), - contentDescription = stringResource(id = R.string.app_name), - modifier = Modifier.size(36.dp), - ) + if (!LocalInspectionMode.current) { + Image( + bitmap = context.appIcon().asImageBitmap(), + contentDescription = stringResource(id = R.string.app_name), + modifier = Modifier.size(36.dp), + ) + } Spacer(modifier = Modifier.width(8.dp)) Text( stringResource(id = R.string.app_name), @@ -223,12 +227,31 @@ private fun AppBarListItem(modifier: Modifier = Modifier) { @Composable private fun IconGridPreview() { LawniconsTheme { - IconPreviewGrid( - SampleData.iconInfoList, - true, - {}, - Modifier, - false, - ) + Surface { + IconPreviewGrid( + iconInfo = SampleData.iconInfoList, + isExpandedScreen = false, + onSendResult = {}, + modifier = Modifier, + isIconPicker = false, + ) + } + } +} + +@OptIn(ExperimentalFoundationApi::class) +@PreviewLawnicons +@Composable +private fun IconGridExpandedPreview() { + LawniconsTheme { + Surface { + IconPreviewGrid( + iconInfo = SampleData.iconInfoList, + isExpandedScreen = true, + onSendResult = {}, + modifier = Modifier, + isIconPicker = false, + ) + } } } From 9ec06e57e745cf4bd8fa5ec9cd663eb5163ec883 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:27:57 +0800 Subject: [PATCH 102/144] Rename `onChange` to `toggle` --- .../app/lawnchair/lawnicons/repository/PreferenceManager.kt | 5 ++++- .../lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt index 9a9e7a2a448..b641936f866 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -28,7 +28,7 @@ abstract class BasePreferenceManager( fun get() = prefs.getBoolean(key, defaultValue) fun set(value: Boolean) = editor.putBoolean(key, value).apply() - fun onChange() = set(!get()) + fun toggle() = set(!get()) @Composable fun asState(): State { @@ -39,6 +39,9 @@ abstract class BasePreferenceManager( } } prefs.registerOnSharedPreferenceChangeListener(listener) + awaitDispose { + prefs.unregisterOnSharedPreferenceChangeListener(listener) + } } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 2106ec0cd94..53dfd79868d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -159,7 +159,7 @@ fun RequestHandler( openSnackbarFirstLaunchContent( context, scope, - prefs.showFirstLaunchSnackbar::onChange, + prefs.showFirstLaunchSnackbar::toggle, snackbarHostState, ) } From 5155f127830fa02bbbb8dbe9a09472fb64c6ab5a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 08:23:44 +0800 Subject: [PATCH 103/144] Update Kotlin and KSP (#2307) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e720ad5decd..1fb5382ed6d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -153,7 +153,7 @@ dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") - implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7") + implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8") val hiltVersion = "2.52" implementation("com.google.dagger:hilt-android:$hiltVersion") diff --git a/build.gradle.kts b/build.gradle.kts index 5bb8a8f1fd1..85c2d418d08 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { id("org.jetbrains.kotlin.android") version "2.0.20" apply false id("org.jetbrains.kotlin.plugin.compose") version "2.0.20" id("org.jetbrains.kotlin.plugin.serialization") version "2.0.20" apply false - id("com.google.devtools.ksp") version "2.0.20-1.0.24" apply false + id("com.google.devtools.ksp") version "2.0.20-1.0.25" apply false id("com.google.dagger.hilt.android") version "2.52" apply false id("app.cash.licensee") version "1.11.0" apply false id("com.diffplug.spotless") version "6.25.0" apply false From f401a40db060eb759f96e2b03030158abc319973 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 6 Sep 2024 06:16:04 -0400 Subject: [PATCH 104/144] Rearrange nav destinations (#2284) --- .../app/lawnchair/lawnicons/ui/Lawnicons.kt | 79 ++++----- .../lawnicons/ui/destination/About.kt | 166 ++++++++++-------- .../ui/destination/Acknowledgement.kt | 26 ++- .../ui/destination/Acknowledgements.kt | 22 ++- .../lawnicons/ui/destination/Contributors.kt | 25 ++- .../lawnicons/ui/destination/Home.kt | 24 ++- .../lawnicons/ui/util/Destinations.kt | 18 -- 7 files changed, 217 insertions(+), 143 deletions(-) delete mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Destinations.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt index 5fa7cc626f1..5562654a521 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt @@ -9,20 +9,18 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.unit.LayoutDirection import androidx.navigation.compose.NavHost -import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import androidx.navigation.toRoute import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.ui.destination.About import app.lawnchair.lawnicons.ui.destination.Acknowledgement import app.lawnchair.lawnicons.ui.destination.Acknowledgements import app.lawnchair.lawnicons.ui.destination.Contributors import app.lawnchair.lawnicons.ui.destination.Home -import app.lawnchair.lawnicons.ui.util.About -import app.lawnchair.lawnicons.ui.util.Acknowledgement -import app.lawnchair.lawnicons.ui.util.Acknowledgements -import app.lawnchair.lawnicons.ui.util.Contributors -import app.lawnchair.lawnicons.ui.util.Home +import app.lawnchair.lawnicons.ui.destination.aboutDestination +import app.lawnchair.lawnicons.ui.destination.acknowledgementDestination +import app.lawnchair.lawnicons.ui.destination.acknowledgementsDestination +import app.lawnchair.lawnicons.ui.destination.contributorsDestination +import app.lawnchair.lawnicons.ui.destination.homeDestination import soup.compose.material.motion.animation.materialSharedAxisXIn import soup.compose.material.motion.animation.materialSharedAxisXOut import soup.compose.material.motion.animation.rememberSlideDistance @@ -50,42 +48,37 @@ fun Lawnicons( popEnterTransition = { materialSharedAxisXIn(isRtl, slideDistance) }, popExitTransition = { materialSharedAxisXOut(isRtl, slideDistance) }, ) { - composable { - Home( - onNavigate = { navController.navigate(About) }, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, - onSendResult = onSendResult, - ) - } - composable { - Acknowledgements( - onBack = navController::popBackStack, - onNavigate = { - navController.navigate(Acknowledgement(it)) - }, - isExpandedScreen = isExpandedScreen, - ) - } - composable { backStackEntry -> - val acknowledgement: Acknowledgement = backStackEntry.toRoute() - Acknowledgement( - name = acknowledgement.id, - onBack = navController::popBackStack, - isExpandedScreen = isExpandedScreen, - ) - } - composable { - About( - onBack = navController::popBackStack, - onNavigateToContributors = { navController.navigate(Contributors) }, - onNavigateToAcknowledgements = { navController.navigate(Acknowledgements) }, - isExpandedScreen = isExpandedScreen, - ) - } - composable { - Contributors(onBack = navController::popBackStack, isExpandedScreen = isExpandedScreen) - } + homeDestination( + onNavigate = { navController.navigate(About) }, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + ) + acknowledgementsDestination( + onBack = navController::popBackStack, + onNavigate = { + navController.navigate(Acknowledgement(it)) + }, + isExpandedScreen = isExpandedScreen, + ) + acknowledgementDestination( + onBack = navController::popBackStack, + isExpandedScreen = isExpandedScreen, + ) + aboutDestination( + onBack = navController::popBackStack, + onNavigateToContributors = { + navController.navigate(Contributors) + }, + onNavigateToAcknowledgements = { + navController.navigate(Acknowledgements) + }, + isExpandedScreen = isExpandedScreen, + ) + contributorsDestination( + onBack = navController::popBackStack, + isExpandedScreen = isExpandedScreen, + ) } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index 68a70354255..8f94c65b0e0 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -25,6 +25,8 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable import app.lawnchair.lawnicons.BuildConfig import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.ui.components.ContributorRow @@ -38,82 +40,29 @@ import app.lawnchair.lawnicons.ui.util.Contributor import app.lawnchair.lawnicons.ui.util.ExternalLink import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.util.appIcon +import kotlinx.serialization.Serializable -private val externalLinks = listOf( - ExternalLink( - iconResId = R.drawable.github_foreground, - name = R.string.github, - url = Constants.GITHUB, - ), - ExternalLink( - iconResId = R.drawable.icon_request_app, - name = R.string.request_form, - url = Constants.ICON_REQUEST_FORM, - ), -) +@Serializable +data object About -private val coreContributors = listOf( - Contributor( - name = "Suphon T.", - username = "paphonb", - photoUrl = "https://avatars.githubusercontent.com/u/8080853", - socialUrl = "https://x.com/paphonb", - descriptionRes = R.string.contribution_core, - ), - Contributor( - name = "SuperDragonXD", - username = "SuperDragonXD", - photoUrl = "https://avatars.githubusercontent.com/u/70206496", - socialUrl = "https://github.com/SuperDragonXD", - descriptionRes = R.string.contribution_core, - ), - Contributor( - name = "Patryk Radziszewski", - username = "Chefski", - photoUrl = "https://avatars.githubusercontent.com/u/100310118", - socialUrl = "https://github.com/Chefski", - descriptionRes = R.string.contribution_icons, - ), - Contributor( - name = "Gleb", - username = "x9136", - photoUrl = "https://avatars.githubusercontent.com/u/60105060", - socialUrl = "https://github.com/x9136", - descriptionRes = R.string.contribution_icons, - ), - Contributor( - name = "Grabster", - username = "Grabstertv", - photoUrl = "https://avatars.githubusercontent.com/u/49114212", - socialUrl = "https://x.com/grabstertv", - descriptionRes = R.string.contribution_icons, - ), - Contributor( - name = "Zongle Wang", - username = "Goooler", - photoUrl = "https://avatars.githubusercontent.com/u/10363352", - socialUrl = "https://androiddev.social/@Goooler", - descriptionRes = R.string.contribution_infra, - ), -) - -private val specialThanks = listOf( - Contributor( - name = "Eatos", - photoUrl = "https://avatars.githubusercontent.com/u/52837599", - socialUrl = "https://x.com/eatosapps", - descriptionRes = R.string.special_thanks_icon, - ), - Contributor( - name = "Rik Koedoot", - photoUrl = "https://avatars.githubusercontent.com/u/29402532", - username = "rikkoedoot", - descriptionRes = R.string.special_thanks_name, - ), -) +fun NavGraphBuilder.aboutDestination( + onBack: () -> Unit, + onNavigateToContributors: () -> Unit, + onNavigateToAcknowledgements: () -> Unit, + isExpandedScreen: Boolean, +) { + composable { + About( + onBack = onBack, + onNavigateToContributors = onNavigateToContributors, + onNavigateToAcknowledgements = onNavigateToAcknowledgements, + isExpandedScreen = isExpandedScreen, + ) + } +} @Composable -fun About( +private fun About( onBack: () -> Unit, onNavigateToContributors: () -> Unit, onNavigateToAcknowledgements: () -> Unit, @@ -238,6 +187,79 @@ fun About( } } +private val externalLinks = listOf( + ExternalLink( + iconResId = R.drawable.github_foreground, + name = R.string.github, + url = Constants.GITHUB, + ), + ExternalLink( + iconResId = R.drawable.icon_request_app, + name = R.string.request_form, + url = Constants.ICON_REQUEST_FORM, + ), +) + +private val coreContributors = listOf( + Contributor( + name = "Suphon T.", + username = "paphonb", + photoUrl = "https://avatars.githubusercontent.com/u/8080853", + socialUrl = "https://x.com/paphonb", + descriptionRes = R.string.contribution_core, + ), + Contributor( + name = "SuperDragonXD", + username = "SuperDragonXD", + photoUrl = "https://avatars.githubusercontent.com/u/70206496", + socialUrl = "https://github.com/SuperDragonXD", + descriptionRes = R.string.contribution_core, + ), + Contributor( + name = "Patryk Radziszewski", + username = "Chefski", + photoUrl = "https://avatars.githubusercontent.com/u/100310118", + socialUrl = "https://github.com/Chefski", + descriptionRes = R.string.contribution_icons, + ), + Contributor( + name = "Gleb", + username = "x9136", + photoUrl = "https://avatars.githubusercontent.com/u/60105060", + socialUrl = "https://github.com/x9136", + descriptionRes = R.string.contribution_icons, + ), + Contributor( + name = "Grabster", + username = "Grabstertv", + photoUrl = "https://avatars.githubusercontent.com/u/49114212", + socialUrl = "https://x.com/grabstertv", + descriptionRes = R.string.contribution_icons, + ), + Contributor( + name = "Zongle Wang", + username = "Goooler", + photoUrl = "https://avatars.githubusercontent.com/u/10363352", + socialUrl = "https://androiddev.social/@Goooler", + descriptionRes = R.string.contribution_infra, + ), +) + +private val specialThanks = listOf( + Contributor( + name = "Eatos", + photoUrl = "https://avatars.githubusercontent.com/u/52837599", + socialUrl = "https://x.com/eatosapps", + descriptionRes = R.string.special_thanks_icon, + ), + Contributor( + name = "Rik Koedoot", + photoUrl = "https://avatars.githubusercontent.com/u/29402532", + username = "rikkoedoot", + descriptionRes = R.string.special_thanks_name, + ), +) + @PreviewLawnicons @Composable private fun AboutPreview() { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgement.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgement.kt index 3e3f492eab2..23347bf7207 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgement.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgement.kt @@ -28,22 +28,40 @@ import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import androidx.navigation.toRoute import app.lawnchair.lawnicons.ui.components.core.LawniconsScaffold import app.lawnchair.lawnicons.ui.components.core.placeholder.PlaceholderHighlight import app.lawnchair.lawnicons.ui.components.core.placeholder.fade import app.lawnchair.lawnicons.ui.components.core.placeholder.placeholder import app.lawnchair.lawnicons.viewmodel.AcknowledgementViewModel +import kotlinx.serialization.Serializable + +@Serializable +data class Acknowledgement(val id: String) + +fun NavGraphBuilder.acknowledgementDestination( + isExpandedScreen: Boolean, + onBack: () -> Unit, +) { + composable { backStackEntry -> + Acknowledgement( + name = backStackEntry.toRoute().id, + onBack = onBack, + isExpandedScreen = isExpandedScreen, + ) + } +} @Composable -fun Acknowledgement( - name: String?, +private fun Acknowledgement( + name: String, onBack: () -> Unit, isExpandedScreen: Boolean, modifier: Modifier = Modifier, acknowledgementViewModel: AcknowledgementViewModel = hiltViewModel(), ) { - requireNotNull(name) - val notice by acknowledgementViewModel.getNoticeForOssLibrary( ossLibraryName = name, linkStyle = SpanStyle( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgements.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgements.kt index 215dade5260..7667df30df2 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgements.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Acknowledgements.kt @@ -14,13 +14,33 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.ui.components.core.LawniconsScaffold import app.lawnchair.lawnicons.ui.components.core.SimpleListRow import app.lawnchair.lawnicons.viewmodel.AcknowledgementViewModel +import kotlinx.serialization.Serializable + +@Serializable +data object Acknowledgements + +fun NavGraphBuilder.acknowledgementsDestination( + isExpandedScreen: Boolean, + onBack: () -> Unit, + onNavigate: (String) -> Unit, +) { + composable { + Acknowledgements( + onBack = onBack, + onNavigate = onNavigate, + isExpandedScreen = isExpandedScreen, + ) + } +} @Composable -fun Acknowledgements( +private fun Acknowledgements( onBack: () -> Unit, onNavigate: (String) -> Unit, isExpandedScreen: Boolean, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt index 76c0990c29a..9d97ab59b16 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt @@ -20,6 +20,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.GitHubContributor import app.lawnchair.lawnicons.ui.components.ContributorRow @@ -33,11 +35,25 @@ import app.lawnchair.lawnicons.viewmodel.ContributorsUiState import app.lawnchair.lawnicons.viewmodel.ContributorsViewModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf +import kotlinx.serialization.Serializable -const val CONTRIBUTOR_URL = "${Constants.GITHUB}/graphs/contributors" +@Serializable +data object Contributors + +fun NavGraphBuilder.contributorsDestination( + onBack: () -> Unit, + isExpandedScreen: Boolean, +) { + composable { + Contributors( + onBack = onBack, + isExpandedScreen = isExpandedScreen, + ) + } +} @Composable -fun Contributors( +private fun Contributors( onBack: () -> Unit, isExpandedScreen: Boolean, modifier: Modifier = Modifier, @@ -158,13 +174,14 @@ private fun ContributorListError( SideEffect { onBack() // we might be rate-limited, open the web ui instead - val website = - Uri.parse(CONTRIBUTOR_URL) + val website = Uri.parse(CONTRIBUTOR_URL) val intent = Intent(Intent.ACTION_VIEW, website) context.startActivity(intent) } } +private const val CONTRIBUTOR_URL = "${Constants.GITHUB}/graphs/contributors" + @PreviewLawnicons @Composable private fun ContributorsScreenPreview() { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 7fcf0b211ae..e4af608c7db 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -24,6 +24,8 @@ import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.platform.LocalContext import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar @@ -39,11 +41,31 @@ import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel import kotlinx.collections.immutable.toImmutableList +import kotlinx.serialization.Serializable + +@Serializable +data object Home + +fun NavGraphBuilder.homeDestination( + isExpandedScreen: Boolean, + isIconPicker: Boolean, + onNavigate: () -> Unit, + onSendResult: (IconInfo) -> Unit, +) { + composable { + Home( + onNavigate = onNavigate, + isExpandedScreen = isExpandedScreen, + isIconPicker = isIconPicker, + onSendResult = onSendResult, + ) + } +} @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable -fun Home( +private fun Home( onNavigate: () -> Unit, onSendResult: (IconInfo) -> Unit, isExpandedScreen: Boolean, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Destinations.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Destinations.kt deleted file mode 100644 index bcc6846dac0..00000000000 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Destinations.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.lawnchair.lawnicons.ui.util - -import kotlinx.serialization.Serializable - -@Serializable -object Home - -@Serializable -object About - -@Serializable -object Acknowledgements - -@Serializable -object Contributors - -@Serializable -data class Acknowledgement(val id: String) From a966f8502aab0507d40eeb3d20a2a7eb2d7a3b89 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 6 Sep 2024 06:40:47 -0400 Subject: [PATCH 105/144] Mark stable classes and enable Compose Compiler reports (#2280) * Remove org.jetbrains.kotlinx:kotlinx-collections-immutable * Enable stabilityConfigurationFile and reportsDestination https://developer.android.com/develop/ui/compose/performance/stability/fix#configuration-file --- app/build.gradle.kts | 6 +++++- app/compose_compiler_config.conf | 7 +++++++ .../app/lawnchair/lawnicons/model/IconInfoModel.kt | 6 ++---- .../lawnchair/lawnicons/model/IconRequestModel.kt | 4 +--- .../lawnicons/repository/IconRepository.kt | 13 +++++-------- .../lawnicons/ui/components/home/IconPreviewGrid.kt | 3 +-- .../ui/components/home/search/SearchContents.kt | 5 ++--- .../lawnicons/ui/destination/Contributors.kt | 8 +++----- .../app/lawnchair/lawnicons/ui/destination/Home.kt | 3 +-- .../app/lawnchair/lawnicons/ui/util/PreviewUtils.kt | 3 +-- .../lawnicons/viewmodel/ContributorsViewModel.kt | 8 +++----- 11 files changed, 31 insertions(+), 35 deletions(-) create mode 100644 app/compose_compiler_config.conf diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1fb5382ed6d..ca1b7c15666 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -131,6 +131,11 @@ tasks.withType().configureEach { dependsOn(projects.svgProcessor.dependencyProject.tasks.named("run")) } +composeCompiler { + stabilityConfigurationFile = layout.projectDirectory.file("compose_compiler_config.conf") + reportsDestination = layout.buildDirectory.dir("compose_build_reports") +} + licensee { allow("Apache-2.0") allow("MIT") @@ -153,7 +158,6 @@ dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") - implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8") val hiltVersion = "2.52" implementation("com.google.dagger:hilt-android:$hiltVersion") diff --git a/app/compose_compiler_config.conf b/app/compose_compiler_config.conf new file mode 100644 index 00000000000..ac70d690a9f --- /dev/null +++ b/app/compose_compiler_config.conf @@ -0,0 +1,7 @@ +kotlin.collections.* +kotlin.time.Duration + +kotlinx.coroutines.CoroutineScope + +// All models should be stable. +app.lawnchair.lawnicons.model.* diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfoModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfoModel.kt index 716402f815f..1d918d14b3b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfoModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconInfoModel.kt @@ -1,7 +1,5 @@ package app.lawnchair.lawnicons.model -import kotlinx.collections.immutable.ImmutableList - /** * Data class to hold information about icons. * @@ -9,6 +7,6 @@ import kotlinx.collections.immutable.ImmutableList * @property iconCount The total number of icons. */ data class IconInfoModel( - val iconInfo: ImmutableList, - val iconCount: Int, + val iconInfo: List = emptyList(), + val iconCount: Int = 0, ) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt index d26f7f76115..4de30e1ef5b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/model/IconRequestModel.kt @@ -1,13 +1,11 @@ package app.lawnchair.lawnicons.model -import kotlinx.collections.immutable.ImmutableList - data class IconRequest( val label: String, val componentName: String, ) data class IconRequestModel( - val list: ImmutableList, + val list: List, val iconCount: Int, ) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt index c03ddb1cf28..1de7e4e4ee8 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/IconRepository.kt @@ -12,9 +12,6 @@ import app.lawnchair.lawnicons.model.splitByComponentName import app.lawnchair.lawnicons.util.getIconInfo import app.lawnchair.lawnicons.util.getSystemIconInfoAppfilter import javax.inject.Inject -import kotlinx.collections.immutable.persistentListOf -import kotlinx.collections.immutable.toImmutableList -import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -36,10 +33,10 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep private val coroutineScope = CoroutineScope(Dispatchers.IO) - private val _iconInfoModel = MutableStateFlow(IconInfoModel(persistentListOf(), 0)) + private val _iconInfoModel = MutableStateFlow(IconInfoModel()) override val iconInfoModel = _iconInfoModel.asStateFlow() - private val _searchedIconInfoModel = MutableStateFlow(IconInfoModel(persistentListOf(), 0)) + private val _searchedIconInfoModel = MutableStateFlow(IconInfoModel()) override val searchedIconInfoModel = _searchedIconInfoModel.asStateFlow() override val iconRequestList = MutableStateFlow(value = null) @@ -51,7 +48,7 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep val iconCount = groupedIcons.size _iconInfoModel.value = IconInfoModel( - iconInfo = iconList.toPersistentList(), + iconInfo = iconList, iconCount = iconCount, ) _searchedIconInfoModel.value = _iconInfoModel.value @@ -92,7 +89,7 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep ), ).map { searchInfo -> searchInfo.iconInfo - }.toPersistentList() + } _searchedIconInfoModel.value = IconInfoModel( iconCount = _searchedIconInfoModel.value.iconCount, @@ -127,7 +124,7 @@ class IconRepositoryImpl @Inject constructor(application: Application) : IconRep } iconRequestList.value = IconRequestModel( - list = commonItems.toImmutableList(), + list = commonItems, iconCount = commonItems.size, ) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 98284cb58a6..3821e3e60fb 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -57,7 +57,6 @@ import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData import app.lawnchair.lawnicons.ui.util.toPaddingValues import app.lawnchair.lawnicons.util.appIcon -import kotlinx.collections.immutable.ImmutableList import my.nanihadesuka.compose.InternalLazyVerticalGridScrollbar import my.nanihadesuka.compose.ScrollbarSelectionMode import my.nanihadesuka.compose.ScrollbarSettings @@ -65,7 +64,7 @@ import my.nanihadesuka.compose.ScrollbarSettings @Composable @ExperimentalFoundationApi fun IconPreviewGrid( - iconInfo: ImmutableList, + iconInfo: List, isExpandedScreen: Boolean, onSendResult: (IconInfo) -> Unit, modifier: Modifier = Modifier, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt index bd919f75d08..62b18cf9e61 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchContents.kt @@ -43,14 +43,13 @@ import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.model.getFirstLabelAndComponent import app.lawnchair.lawnicons.ui.components.home.IconInfoSheet import app.lawnchair.lawnicons.ui.components.home.IconPreview -import kotlinx.collections.immutable.ImmutableList @Composable fun SearchContents( searchTerm: String, searchMode: SearchMode, onModeChange: (SearchMode) -> Unit, - iconInfo: ImmutableList, + iconInfo: List, modifier: Modifier = Modifier, onSendResult: (IconInfo) -> Unit = {}, ) { @@ -167,7 +166,7 @@ fun SearchContents( } @Composable -private fun IconInfoListItem(iconInfo: ImmutableList) { +private fun IconInfoListItem(iconInfo: List) { Column( modifier = Modifier .fillMaxWidth() diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt index 9d97ab59b16..124c0c8b5a1 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt @@ -33,8 +33,6 @@ import app.lawnchair.lawnicons.ui.util.Constants import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.viewmodel.ContributorsUiState import app.lawnchair.lawnicons.viewmodel.ContributorsViewModel -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.persistentListOf import kotlinx.serialization.Serializable @Serializable @@ -111,7 +109,7 @@ fun Contributors( @Composable private fun ContributorList( - contributors: ImmutableList, + contributors: List, modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(), ) { @@ -185,7 +183,7 @@ private const val CONTRIBUTOR_URL = "${Constants.GITHUB}/graphs/contributors" @PreviewLawnicons @Composable private fun ContributorsScreenPreview() { - val contributors = persistentListOf( + val contributors = listOf( GitHubContributor( id = 1, login = "Example", @@ -219,7 +217,7 @@ private fun ContributorsScreenLoadingPreview() { @PreviewLawnicons @Composable private fun ContributorListPreview() { - val contributors = persistentListOf( + val contributors = listOf( GitHubContributor( id = 1, login = "Example", diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index e4af608c7db..a257463e19f 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -40,7 +40,6 @@ import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel -import kotlinx.collections.immutable.toImmutableList import kotlinx.serialization.Serializable @Serializable @@ -196,7 +195,7 @@ private fun HomePreview() { }, ) IconPreviewGrid( - iconInfo = iconInfo.toImmutableList(), + iconInfo = iconInfo, isExpandedScreen = false, {}, Modifier, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/PreviewUtils.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/PreviewUtils.kt index 1e7543669b7..88f2c55b70b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/PreviewUtils.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/PreviewUtils.kt @@ -5,7 +5,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Wallpapers import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.LabelAndComponent -import kotlinx.collections.immutable.persistentListOf @Preview( name = "Normal", @@ -39,7 +38,7 @@ object SampleData { ), id = 1, ) - val iconInfoList = persistentListOf( + val iconInfoList = listOf( IconInfo( drawableName = "@drawable/email", componentNames = listOf( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/ContributorsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/ContributorsViewModel.kt index f5dd2d57a52..c17cc568c0b 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/ContributorsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/ContributorsViewModel.kt @@ -7,8 +7,6 @@ import app.lawnchair.lawnicons.model.GitHubContributor import app.lawnchair.lawnicons.repository.GitHubContributorsRepository import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toPersistentList import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map @@ -19,7 +17,7 @@ import kotlinx.coroutines.launch sealed interface ContributorsUiState { data class Success( - val contributors: ImmutableList, + val contributors: List, ) : ContributorsUiState data object Loading : ContributorsUiState @@ -28,7 +26,7 @@ sealed interface ContributorsUiState { private data class ContributorsViewModelState( val isRefreshing: Boolean, - val contributors: ImmutableList? = null, + val contributors: List? = null, val hasError: Boolean = false, ) { fun toUiState(): ContributorsUiState = when { @@ -63,7 +61,7 @@ class ContributorsViewModel @Inject constructor( when { result.isSuccess -> it.copy( isRefreshing = false, - contributors = result.getOrThrow().toPersistentList(), + contributors = result.getOrThrow(), hasError = false, ) From c53cc4a2770b2327c249953db9728eb53c21a6d5 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:38:55 +0300 Subject: [PATCH 106/144] New issue: Add a link to an existing icon (#2283) * New issue: Add a link to an existing icon * Update .github/ISSUE_TEMPLATE/config.yml * Update .github/ISSUE_TEMPLATE/config.yml Co-authored-by: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> --------- Co-authored-by: Zongle Wang Co-authored-by: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/config.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 637761d9d26..214528c627e 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: Link apps to existing icons + url: https://github.com/LawnchairLauncher/lawnicons/blob/develop/CONTRIBUTING.md#adding-an-icon-to-lawnicons + about: Learn more about linking an app to an existing icon and making a PR to contribute to Lawnicons. - name: Icon Request url: https://forms.gle/xt7sJhgWEasuo9TR9 about: Please request your icons in this form. From dbd28e324991693b7c73bffc2b641c057cf66c35 Mon Sep 17 00:00:00 2001 From: juman-y <80329028+juman-y@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:52:27 +0000 Subject: [PATCH 107/144] Add Infinity for Reddit link (#2309) --- app/assets/appfilter.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index d58db01649e..14c6fee4060 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -4573,6 +4573,7 @@ + From 0e5ce9c3d90e431a6c04304cc7852017c1a26502 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sun, 8 Sep 2024 02:22:58 +0300 Subject: [PATCH 108/144] [Barter 5] +100 icons: Bybit, My Huawei, Wa Enhancer (#2310) --- app/assets/appfilter.xml | 103 +++++++++++++++++++++++++ svgs/_1weather.svg | 1 + svgs/adda247.svg | 1 + svgs/adidas.svg | 2 +- svgs/adidas_running.svg | 1 + svgs/agc_toolkit.svg | 1 + svgs/ai_wallpapers.svg | 1 + svgs/ar_art_projector.svg | 1 + svgs/blackmagic_camera.svg | 1 + svgs/block_blast.svg | 1 + svgs/brilliant.svg | 1 + svgs/bybit.svg | 1 + svgs/calculator_you.svg | 1 + svgs/capturesposed.svg | 1 + svgs/chalo.svg | 1 + svgs/clearscore.svg | 1 + svgs/click_to_chat.svg | 1 + svgs/crayon_icons.svg | 1 + svgs/day_one_journal.svg | 1 + svgs/dr_web.svg | 1 + svgs/evernote.svg | 1 + svgs/flow_free.svg | 1 + svgs/folax.svg | 1 + svgs/fold.svg | 1 + svgs/g_cpu.svg | 1 + svgs/geometry_dash_meltdown.svg | 1 + svgs/giphy.svg | 1 + svgs/glassdoor.svg | 1 + svgs/healthy_battery_charging.svg | 1 + svgs/huawei_appassistant.svg | 1 + svgs/huawei_optimizer.svg | 1 + svgs/huawei_themes.svg | 1 + svgs/huawei_weather.svg | 1 + svgs/hyperos_downloader.svg | 1 + svgs/hypic.svg | 1 + svgs/iliad_visual_voicemail.svg | 1 + svgs/intel_unison.svg | 1 + svgs/iyps.svg | 1 + svgs/jetpack_joyride.svg | 1 + svgs/jumia.svg | 1 + svgs/koda_for_kustom.svg | 1 + svgs/livescore.svg | 1 + svgs/mach.svg | 1 + svgs/magisk_module_repo_loader.svg | 1 + svgs/mail_ru.svg | 1 + svgs/mcpedl_for_minecraft.svg | 1 + svgs/mi_mover.svg | 1 + svgs/mi_personal_flow.svg | 1 + svgs/mobile_data_consumption.svg | 1 + svgs/mobile_jkn.svg | 1 + svgs/modern_warships.svg | 1 + svgs/modo.svg | 1 + svgs/moto_unplugged.svg | 1 + svgs/musclewiki.svg | 1 + svgs/muslim_pro.svg | 1 + svgs/my_apps_time.svg | 1 + svgs/my_huawei.svg | 1 + svgs/my_zong.svg | 1 + svgs/national_train_enquiry_system.svg | 1 + svgs/native_alpha_plus.svg | 1 + svgs/nays.svg | 1 + svgs/nothing_icons.svg | 1 + svgs/octohide_vpn.svg | 1 + svgs/offline_games.svg | 1 + svgs/onecard.svg | 1 + svgs/onescore.svg | 1 + svgs/overmorrow_weather.svg | 1 + svgs/pixel_launcher.svg | 1 + svgs/plato.svg | 1 + svgs/playhub.svg | 1 + svgs/qanda.svg | 1 + svgs/qralarm.svg | 1 + svgs/quikshort.svg | 1 + svgs/rappi.svg | 1 + svgs/regain.svg | 1 + svgs/ring.svg | 1 + svgs/round_sync.svg | 1 + svgs/screen_orientation_control.svg | 1 + svgs/sd_maid.svg | 2 +- svgs/sd_maid_1_pro.svg | 1 + svgs/shelf.svg | 1 + svgs/simosa.svg | 1 + svgs/spin_the_wheel.svg | 1 + svgs/storage_saver.svg | 1 + svgs/super_money.svg | 1 + svgs/supreme_duelist.svg | 1 + svgs/syphon.svg | 1 + svgs/t_mobile_visual_voicemail.svg | 1 + svgs/tecno_spot.svg | 1 + svgs/ten_ten.svg | 1 + svgs/thunder_vpn.svg | 1 + svgs/ts_news_plus.svg | 1 + svgs/update_me.svg | 1 + svgs/v_appstore.svg | 1 + svgs/vivo_feedback.svg | 1 + svgs/wa_enhancer.svg | 1 + svgs/wear_installer_2.svg | 1 + svgs/welife.svg | 1 + svgs/work_log.svg | 1 + svgs/x_vpn.svg | 1 + svgs/yearly_progress.svg | 1 + svgs/youtube_adaway.svg | 1 + svgs/zenless_zone_zero.svg | 1 + 103 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 svgs/_1weather.svg create mode 100644 svgs/adda247.svg create mode 100644 svgs/adidas_running.svg create mode 100644 svgs/agc_toolkit.svg create mode 100644 svgs/ai_wallpapers.svg create mode 100644 svgs/ar_art_projector.svg create mode 100644 svgs/blackmagic_camera.svg create mode 100644 svgs/block_blast.svg create mode 100644 svgs/brilliant.svg create mode 100644 svgs/bybit.svg create mode 100644 svgs/calculator_you.svg create mode 100644 svgs/capturesposed.svg create mode 100644 svgs/chalo.svg create mode 100644 svgs/clearscore.svg create mode 100644 svgs/click_to_chat.svg create mode 100644 svgs/crayon_icons.svg create mode 100644 svgs/day_one_journal.svg create mode 100644 svgs/dr_web.svg create mode 100644 svgs/evernote.svg create mode 100644 svgs/flow_free.svg create mode 100644 svgs/folax.svg create mode 100644 svgs/fold.svg create mode 100644 svgs/g_cpu.svg create mode 100644 svgs/geometry_dash_meltdown.svg create mode 100644 svgs/giphy.svg create mode 100644 svgs/glassdoor.svg create mode 100644 svgs/healthy_battery_charging.svg create mode 100644 svgs/huawei_appassistant.svg create mode 100644 svgs/huawei_optimizer.svg create mode 100644 svgs/huawei_themes.svg create mode 100644 svgs/huawei_weather.svg create mode 100644 svgs/hyperos_downloader.svg create mode 100644 svgs/hypic.svg create mode 100644 svgs/iliad_visual_voicemail.svg create mode 100644 svgs/intel_unison.svg create mode 100644 svgs/iyps.svg create mode 100644 svgs/jetpack_joyride.svg create mode 100644 svgs/jumia.svg create mode 100644 svgs/koda_for_kustom.svg create mode 100644 svgs/livescore.svg create mode 100644 svgs/mach.svg create mode 100644 svgs/magisk_module_repo_loader.svg create mode 100644 svgs/mail_ru.svg create mode 100644 svgs/mcpedl_for_minecraft.svg create mode 100644 svgs/mi_mover.svg create mode 100644 svgs/mi_personal_flow.svg create mode 100644 svgs/mobile_data_consumption.svg create mode 100644 svgs/mobile_jkn.svg create mode 100644 svgs/modern_warships.svg create mode 100644 svgs/modo.svg create mode 100644 svgs/moto_unplugged.svg create mode 100644 svgs/musclewiki.svg create mode 100644 svgs/muslim_pro.svg create mode 100644 svgs/my_apps_time.svg create mode 100644 svgs/my_huawei.svg create mode 100644 svgs/my_zong.svg create mode 100644 svgs/national_train_enquiry_system.svg create mode 100644 svgs/native_alpha_plus.svg create mode 100644 svgs/nays.svg create mode 100644 svgs/nothing_icons.svg create mode 100644 svgs/octohide_vpn.svg create mode 100644 svgs/offline_games.svg create mode 100644 svgs/onecard.svg create mode 100644 svgs/onescore.svg create mode 100644 svgs/overmorrow_weather.svg create mode 100644 svgs/pixel_launcher.svg create mode 100644 svgs/plato.svg create mode 100644 svgs/playhub.svg create mode 100644 svgs/qanda.svg create mode 100644 svgs/qralarm.svg create mode 100644 svgs/quikshort.svg create mode 100644 svgs/rappi.svg create mode 100644 svgs/regain.svg create mode 100644 svgs/ring.svg create mode 100644 svgs/round_sync.svg create mode 100644 svgs/screen_orientation_control.svg create mode 100644 svgs/sd_maid_1_pro.svg create mode 100644 svgs/shelf.svg create mode 100644 svgs/simosa.svg create mode 100644 svgs/spin_the_wheel.svg create mode 100644 svgs/storage_saver.svg create mode 100644 svgs/super_money.svg create mode 100644 svgs/supreme_duelist.svg create mode 100644 svgs/syphon.svg create mode 100644 svgs/t_mobile_visual_voicemail.svg create mode 100644 svgs/tecno_spot.svg create mode 100644 svgs/ten_ten.svg create mode 100644 svgs/thunder_vpn.svg create mode 100644 svgs/ts_news_plus.svg create mode 100644 svgs/update_me.svg create mode 100644 svgs/v_appstore.svg create mode 100644 svgs/vivo_feedback.svg create mode 100644 svgs/wa_enhancer.svg create mode 100644 svgs/wear_installer_2.svg create mode 100644 svgs/welife.svg create mode 100644 svgs/work_log.svg create mode 100644 svgs/x_vpn.svg create mode 100644 svgs/yearly_progress.svg create mode 100644 svgs/youtube_adaway.svg create mode 100644 svgs/zenless_zone_zero.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 14c6fee4060..578bdb4be14 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -61,6 +61,7 @@ + @@ -175,6 +176,7 @@ + @@ -191,6 +193,7 @@ + @@ -233,6 +236,7 @@ + @@ -246,6 +250,7 @@ + @@ -649,6 +654,7 @@ + @@ -1111,6 +1117,7 @@ + @@ -1137,6 +1144,7 @@ + @@ -1295,6 +1303,7 @@ + @@ -1434,6 +1443,7 @@ + @@ -1507,6 +1517,7 @@ + @@ -1760,6 +1771,7 @@ + @@ -1837,6 +1849,7 @@ + @@ -1974,9 +1987,11 @@ + + @@ -2327,6 +2342,7 @@ + @@ -2431,6 +2447,7 @@ + @@ -2791,6 +2808,7 @@ + @@ -3087,6 +3105,7 @@ + @@ -3443,6 +3462,7 @@ + @@ -3491,6 +3511,8 @@ + + @@ -3636,6 +3658,7 @@ + @@ -3796,6 +3819,7 @@ + @@ -3833,6 +3857,7 @@ + @@ -3841,6 +3866,7 @@ + @@ -4244,6 +4270,7 @@ + @@ -4376,6 +4403,7 @@ + @@ -4386,11 +4414,14 @@ + + + @@ -4408,6 +4439,8 @@ + + @@ -4495,6 +4528,7 @@ + @@ -4642,6 +4676,7 @@ + @@ -4717,6 +4752,7 @@ + @@ -4749,6 +4785,7 @@ + @@ -4792,6 +4829,7 @@ + @@ -5036,6 +5074,7 @@ + @@ -5322,6 +5361,7 @@ + @@ -5400,6 +5440,7 @@ + @@ -5440,6 +5481,7 @@ + @@ -5455,6 +5497,7 @@ + @@ -5589,6 +5632,7 @@ + @@ -5803,6 +5847,7 @@ + @@ -5811,6 +5856,7 @@ + @@ -6014,8 +6060,10 @@ + + @@ -6031,6 +6079,8 @@ + + @@ -6123,6 +6173,7 @@ + @@ -6168,6 +6219,7 @@ + @@ -6211,6 +6263,7 @@ + @@ -6245,6 +6298,7 @@ + @@ -6267,6 +6321,7 @@ + @@ -6343,6 +6398,7 @@ + @@ -6480,8 +6536,10 @@ + + @@ -6495,6 +6553,7 @@ + @@ -6721,6 +6780,7 @@ + @@ -6859,6 +6919,7 @@ + @@ -6877,6 +6938,7 @@ + @@ -6979,6 +7041,7 @@ + @@ -7014,6 +7077,7 @@ + @@ -7157,6 +7221,7 @@ + @@ -7643,6 +7708,9 @@ + + + @@ -7731,11 +7799,13 @@ + + @@ -8007,6 +8077,7 @@ + @@ -8069,6 +8140,7 @@ + @@ -8096,6 +8168,7 @@ + @@ -8181,6 +8254,7 @@ + @@ -8308,6 +8382,7 @@ + @@ -8409,6 +8484,7 @@ + @@ -8456,6 +8532,7 @@ + @@ -8714,6 +8791,7 @@ + @@ -8733,6 +8811,7 @@ + @@ -8905,6 +8984,7 @@ + @@ -9022,6 +9102,7 @@ + @@ -9704,6 +9785,7 @@ + @@ -9860,6 +9942,7 @@ + @@ -9938,6 +10021,7 @@ + @@ -9952,6 +10036,7 @@ + @@ -10025,6 +10110,7 @@ + @@ -10038,6 +10124,7 @@ + @@ -10141,6 +10228,7 @@ + @@ -10229,6 +10317,7 @@ + @@ -10541,6 +10630,7 @@ + @@ -10805,6 +10895,7 @@ + @@ -11000,6 +11091,7 @@ + @@ -11046,6 +11138,7 @@ + @@ -11234,6 +11327,7 @@ + @@ -11335,6 +11429,8 @@ + + @@ -11411,6 +11507,7 @@ + @@ -11456,6 +11553,7 @@ + @@ -11703,6 +11801,7 @@ + @@ -11758,6 +11857,7 @@ + @@ -11848,6 +11948,7 @@ + @@ -11900,6 +12001,7 @@ + @@ -12006,6 +12108,7 @@ + diff --git a/svgs/_1weather.svg b/svgs/_1weather.svg new file mode 100644 index 00000000000..73f5c225423 --- /dev/null +++ b/svgs/_1weather.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/adda247.svg b/svgs/adda247.svg new file mode 100644 index 00000000000..9d79a897481 --- /dev/null +++ b/svgs/adda247.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/adidas.svg b/svgs/adidas.svg index 146895ce61f..7eba9ca5bc1 100644 --- a/svgs/adidas.svg +++ b/svgs/adidas.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/adidas_running.svg b/svgs/adidas_running.svg new file mode 100644 index 00000000000..09ba227fed1 --- /dev/null +++ b/svgs/adidas_running.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/agc_toolkit.svg b/svgs/agc_toolkit.svg new file mode 100644 index 00000000000..f45f4cfa5b1 --- /dev/null +++ b/svgs/agc_toolkit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ai_wallpapers.svg b/svgs/ai_wallpapers.svg new file mode 100644 index 00000000000..b104047f117 --- /dev/null +++ b/svgs/ai_wallpapers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ar_art_projector.svg b/svgs/ar_art_projector.svg new file mode 100644 index 00000000000..df06137d7a6 --- /dev/null +++ b/svgs/ar_art_projector.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/blackmagic_camera.svg b/svgs/blackmagic_camera.svg new file mode 100644 index 00000000000..0bcfc9d03be --- /dev/null +++ b/svgs/blackmagic_camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/block_blast.svg b/svgs/block_blast.svg new file mode 100644 index 00000000000..10c50a35835 --- /dev/null +++ b/svgs/block_blast.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/brilliant.svg b/svgs/brilliant.svg new file mode 100644 index 00000000000..f89db8c850f --- /dev/null +++ b/svgs/brilliant.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/bybit.svg b/svgs/bybit.svg new file mode 100644 index 00000000000..526e9b2f431 --- /dev/null +++ b/svgs/bybit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/calculator_you.svg b/svgs/calculator_you.svg new file mode 100644 index 00000000000..2eb4ba38010 --- /dev/null +++ b/svgs/calculator_you.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/capturesposed.svg b/svgs/capturesposed.svg new file mode 100644 index 00000000000..1c7547377a9 --- /dev/null +++ b/svgs/capturesposed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/chalo.svg b/svgs/chalo.svg new file mode 100644 index 00000000000..e35e3f322a3 --- /dev/null +++ b/svgs/chalo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/clearscore.svg b/svgs/clearscore.svg new file mode 100644 index 00000000000..734ca2aa2fa --- /dev/null +++ b/svgs/clearscore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/click_to_chat.svg b/svgs/click_to_chat.svg new file mode 100644 index 00000000000..89aa36ab70e --- /dev/null +++ b/svgs/click_to_chat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/crayon_icons.svg b/svgs/crayon_icons.svg new file mode 100644 index 00000000000..56fe80a324e --- /dev/null +++ b/svgs/crayon_icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/day_one_journal.svg b/svgs/day_one_journal.svg new file mode 100644 index 00000000000..2c28b98e7f1 --- /dev/null +++ b/svgs/day_one_journal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/dr_web.svg b/svgs/dr_web.svg new file mode 100644 index 00000000000..5e164359114 --- /dev/null +++ b/svgs/dr_web.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/evernote.svg b/svgs/evernote.svg new file mode 100644 index 00000000000..75204bfac9c --- /dev/null +++ b/svgs/evernote.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/flow_free.svg b/svgs/flow_free.svg new file mode 100644 index 00000000000..2c519da16e8 --- /dev/null +++ b/svgs/flow_free.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/folax.svg b/svgs/folax.svg new file mode 100644 index 00000000000..740fb019012 --- /dev/null +++ b/svgs/folax.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/fold.svg b/svgs/fold.svg new file mode 100644 index 00000000000..6b0a11eea67 --- /dev/null +++ b/svgs/fold.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/g_cpu.svg b/svgs/g_cpu.svg new file mode 100644 index 00000000000..d836f349f28 --- /dev/null +++ b/svgs/g_cpu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/geometry_dash_meltdown.svg b/svgs/geometry_dash_meltdown.svg new file mode 100644 index 00000000000..b4643f72b98 --- /dev/null +++ b/svgs/geometry_dash_meltdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/giphy.svg b/svgs/giphy.svg new file mode 100644 index 00000000000..95c743c2634 --- /dev/null +++ b/svgs/giphy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/glassdoor.svg b/svgs/glassdoor.svg new file mode 100644 index 00000000000..49a9b3e724f --- /dev/null +++ b/svgs/glassdoor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/healthy_battery_charging.svg b/svgs/healthy_battery_charging.svg new file mode 100644 index 00000000000..c3e06eb71f4 --- /dev/null +++ b/svgs/healthy_battery_charging.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/huawei_appassistant.svg b/svgs/huawei_appassistant.svg new file mode 100644 index 00000000000..87f4af3432d --- /dev/null +++ b/svgs/huawei_appassistant.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/huawei_optimizer.svg b/svgs/huawei_optimizer.svg new file mode 100644 index 00000000000..6249a3a8539 --- /dev/null +++ b/svgs/huawei_optimizer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/huawei_themes.svg b/svgs/huawei_themes.svg new file mode 100644 index 00000000000..f6961a51619 --- /dev/null +++ b/svgs/huawei_themes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/huawei_weather.svg b/svgs/huawei_weather.svg new file mode 100644 index 00000000000..86f059003c3 --- /dev/null +++ b/svgs/huawei_weather.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/hyperos_downloader.svg b/svgs/hyperos_downloader.svg new file mode 100644 index 00000000000..511689e6893 --- /dev/null +++ b/svgs/hyperos_downloader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/hypic.svg b/svgs/hypic.svg new file mode 100644 index 00000000000..20637a423bc --- /dev/null +++ b/svgs/hypic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/iliad_visual_voicemail.svg b/svgs/iliad_visual_voicemail.svg new file mode 100644 index 00000000000..bd6b0f456b6 --- /dev/null +++ b/svgs/iliad_visual_voicemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/intel_unison.svg b/svgs/intel_unison.svg new file mode 100644 index 00000000000..0355df5d09e --- /dev/null +++ b/svgs/intel_unison.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/iyps.svg b/svgs/iyps.svg new file mode 100644 index 00000000000..be6b77db263 --- /dev/null +++ b/svgs/iyps.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/jetpack_joyride.svg b/svgs/jetpack_joyride.svg new file mode 100644 index 00000000000..799be1c440e --- /dev/null +++ b/svgs/jetpack_joyride.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/jumia.svg b/svgs/jumia.svg new file mode 100644 index 00000000000..26e266afe84 --- /dev/null +++ b/svgs/jumia.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/koda_for_kustom.svg b/svgs/koda_for_kustom.svg new file mode 100644 index 00000000000..da0d5f4c4f1 --- /dev/null +++ b/svgs/koda_for_kustom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/livescore.svg b/svgs/livescore.svg new file mode 100644 index 00000000000..b21a4b3057a --- /dev/null +++ b/svgs/livescore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mach.svg b/svgs/mach.svg new file mode 100644 index 00000000000..c23dcddc2b5 --- /dev/null +++ b/svgs/mach.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/magisk_module_repo_loader.svg b/svgs/magisk_module_repo_loader.svg new file mode 100644 index 00000000000..48fb05f52a1 --- /dev/null +++ b/svgs/magisk_module_repo_loader.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mail_ru.svg b/svgs/mail_ru.svg new file mode 100644 index 00000000000..a4d6180d7c0 --- /dev/null +++ b/svgs/mail_ru.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mcpedl_for_minecraft.svg b/svgs/mcpedl_for_minecraft.svg new file mode 100644 index 00000000000..543c03ce8b7 --- /dev/null +++ b/svgs/mcpedl_for_minecraft.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mi_mover.svg b/svgs/mi_mover.svg new file mode 100644 index 00000000000..098a152db11 --- /dev/null +++ b/svgs/mi_mover.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mi_personal_flow.svg b/svgs/mi_personal_flow.svg new file mode 100644 index 00000000000..08073074d65 --- /dev/null +++ b/svgs/mi_personal_flow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mobile_data_consumption.svg b/svgs/mobile_data_consumption.svg new file mode 100644 index 00000000000..1919c9fb5d0 --- /dev/null +++ b/svgs/mobile_data_consumption.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mobile_jkn.svg b/svgs/mobile_jkn.svg new file mode 100644 index 00000000000..8a07922960d --- /dev/null +++ b/svgs/mobile_jkn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/modern_warships.svg b/svgs/modern_warships.svg new file mode 100644 index 00000000000..dc4a51d4fa1 --- /dev/null +++ b/svgs/modern_warships.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/modo.svg b/svgs/modo.svg new file mode 100644 index 00000000000..a6e04f5af64 --- /dev/null +++ b/svgs/modo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/moto_unplugged.svg b/svgs/moto_unplugged.svg new file mode 100644 index 00000000000..067ab7e7a95 --- /dev/null +++ b/svgs/moto_unplugged.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/musclewiki.svg b/svgs/musclewiki.svg new file mode 100644 index 00000000000..f6724970573 --- /dev/null +++ b/svgs/musclewiki.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/muslim_pro.svg b/svgs/muslim_pro.svg new file mode 100644 index 00000000000..0e05d5b7ecb --- /dev/null +++ b/svgs/muslim_pro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/my_apps_time.svg b/svgs/my_apps_time.svg new file mode 100644 index 00000000000..45293beaed2 --- /dev/null +++ b/svgs/my_apps_time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/my_huawei.svg b/svgs/my_huawei.svg new file mode 100644 index 00000000000..5b3a4381fe4 --- /dev/null +++ b/svgs/my_huawei.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/my_zong.svg b/svgs/my_zong.svg new file mode 100644 index 00000000000..89247d037ce --- /dev/null +++ b/svgs/my_zong.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/national_train_enquiry_system.svg b/svgs/national_train_enquiry_system.svg new file mode 100644 index 00000000000..a66beeaf857 --- /dev/null +++ b/svgs/national_train_enquiry_system.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/native_alpha_plus.svg b/svgs/native_alpha_plus.svg new file mode 100644 index 00000000000..07e6eec6834 --- /dev/null +++ b/svgs/native_alpha_plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/nays.svg b/svgs/nays.svg new file mode 100644 index 00000000000..f7839384e16 --- /dev/null +++ b/svgs/nays.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/nothing_icons.svg b/svgs/nothing_icons.svg new file mode 100644 index 00000000000..0f0a7e2ddc2 --- /dev/null +++ b/svgs/nothing_icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/octohide_vpn.svg b/svgs/octohide_vpn.svg new file mode 100644 index 00000000000..a80cd0ab3af --- /dev/null +++ b/svgs/octohide_vpn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/offline_games.svg b/svgs/offline_games.svg new file mode 100644 index 00000000000..14571dd09c0 --- /dev/null +++ b/svgs/offline_games.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/onecard.svg b/svgs/onecard.svg new file mode 100644 index 00000000000..a45de2db222 --- /dev/null +++ b/svgs/onecard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/onescore.svg b/svgs/onescore.svg new file mode 100644 index 00000000000..f2dffb169c9 --- /dev/null +++ b/svgs/onescore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/overmorrow_weather.svg b/svgs/overmorrow_weather.svg new file mode 100644 index 00000000000..e1d8307591d --- /dev/null +++ b/svgs/overmorrow_weather.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pixel_launcher.svg b/svgs/pixel_launcher.svg new file mode 100644 index 00000000000..bdde114429e --- /dev/null +++ b/svgs/pixel_launcher.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/plato.svg b/svgs/plato.svg new file mode 100644 index 00000000000..3fdbc9170e9 --- /dev/null +++ b/svgs/plato.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/playhub.svg b/svgs/playhub.svg new file mode 100644 index 00000000000..c8cf49e12c7 --- /dev/null +++ b/svgs/playhub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/qanda.svg b/svgs/qanda.svg new file mode 100644 index 00000000000..bbba90dd6a9 --- /dev/null +++ b/svgs/qanda.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/qralarm.svg b/svgs/qralarm.svg new file mode 100644 index 00000000000..5173d85eb75 --- /dev/null +++ b/svgs/qralarm.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/quikshort.svg b/svgs/quikshort.svg new file mode 100644 index 00000000000..8282914ad38 --- /dev/null +++ b/svgs/quikshort.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/rappi.svg b/svgs/rappi.svg new file mode 100644 index 00000000000..0e81de883c4 --- /dev/null +++ b/svgs/rappi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/regain.svg b/svgs/regain.svg new file mode 100644 index 00000000000..62a01881c4f --- /dev/null +++ b/svgs/regain.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ring.svg b/svgs/ring.svg new file mode 100644 index 00000000000..73352365b6d --- /dev/null +++ b/svgs/ring.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/round_sync.svg b/svgs/round_sync.svg new file mode 100644 index 00000000000..137be208ee7 --- /dev/null +++ b/svgs/round_sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/screen_orientation_control.svg b/svgs/screen_orientation_control.svg new file mode 100644 index 00000000000..98237f66cdc --- /dev/null +++ b/svgs/screen_orientation_control.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/sd_maid.svg b/svgs/sd_maid.svg index ec63ca45e7e..0330bdad76c 100644 --- a/svgs/sd_maid.svg +++ b/svgs/sd_maid.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/sd_maid_1_pro.svg b/svgs/sd_maid_1_pro.svg new file mode 100644 index 00000000000..25f964a155b --- /dev/null +++ b/svgs/sd_maid_1_pro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/shelf.svg b/svgs/shelf.svg new file mode 100644 index 00000000000..91d8773159a --- /dev/null +++ b/svgs/shelf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/simosa.svg b/svgs/simosa.svg new file mode 100644 index 00000000000..8b3db5d882e --- /dev/null +++ b/svgs/simosa.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/spin_the_wheel.svg b/svgs/spin_the_wheel.svg new file mode 100644 index 00000000000..0216c9173b4 --- /dev/null +++ b/svgs/spin_the_wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/storage_saver.svg b/svgs/storage_saver.svg new file mode 100644 index 00000000000..c3abd78d929 --- /dev/null +++ b/svgs/storage_saver.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/super_money.svg b/svgs/super_money.svg new file mode 100644 index 00000000000..70d9b16ead6 --- /dev/null +++ b/svgs/super_money.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/supreme_duelist.svg b/svgs/supreme_duelist.svg new file mode 100644 index 00000000000..e9b064b3031 --- /dev/null +++ b/svgs/supreme_duelist.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/syphon.svg b/svgs/syphon.svg new file mode 100644 index 00000000000..70e0cf85683 --- /dev/null +++ b/svgs/syphon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/t_mobile_visual_voicemail.svg b/svgs/t_mobile_visual_voicemail.svg new file mode 100644 index 00000000000..372e3256ff9 --- /dev/null +++ b/svgs/t_mobile_visual_voicemail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/tecno_spot.svg b/svgs/tecno_spot.svg new file mode 100644 index 00000000000..92d0a14547f --- /dev/null +++ b/svgs/tecno_spot.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ten_ten.svg b/svgs/ten_ten.svg new file mode 100644 index 00000000000..ed449405a3a --- /dev/null +++ b/svgs/ten_ten.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/thunder_vpn.svg b/svgs/thunder_vpn.svg new file mode 100644 index 00000000000..32b3e43780b --- /dev/null +++ b/svgs/thunder_vpn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ts_news_plus.svg b/svgs/ts_news_plus.svg new file mode 100644 index 00000000000..4129d038433 --- /dev/null +++ b/svgs/ts_news_plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/update_me.svg b/svgs/update_me.svg new file mode 100644 index 00000000000..b3976388a60 --- /dev/null +++ b/svgs/update_me.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/v_appstore.svg b/svgs/v_appstore.svg new file mode 100644 index 00000000000..a929bcafef8 --- /dev/null +++ b/svgs/v_appstore.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/vivo_feedback.svg b/svgs/vivo_feedback.svg new file mode 100644 index 00000000000..dffc9762f75 --- /dev/null +++ b/svgs/vivo_feedback.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/wa_enhancer.svg b/svgs/wa_enhancer.svg new file mode 100644 index 00000000000..6a56ff7e16c --- /dev/null +++ b/svgs/wa_enhancer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/wear_installer_2.svg b/svgs/wear_installer_2.svg new file mode 100644 index 00000000000..b548064c5b5 --- /dev/null +++ b/svgs/wear_installer_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/welife.svg b/svgs/welife.svg new file mode 100644 index 00000000000..3fac32af04c --- /dev/null +++ b/svgs/welife.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/work_log.svg b/svgs/work_log.svg new file mode 100644 index 00000000000..f1128a11233 --- /dev/null +++ b/svgs/work_log.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/x_vpn.svg b/svgs/x_vpn.svg new file mode 100644 index 00000000000..45a16d594a5 --- /dev/null +++ b/svgs/x_vpn.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/yearly_progress.svg b/svgs/yearly_progress.svg new file mode 100644 index 00000000000..a36aa65a5e1 --- /dev/null +++ b/svgs/yearly_progress.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/youtube_adaway.svg b/svgs/youtube_adaway.svg new file mode 100644 index 00000000000..e1482086706 --- /dev/null +++ b/svgs/youtube_adaway.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/zenless_zone_zero.svg b/svgs/zenless_zone_zero.svg new file mode 100644 index 00000000000..8a55dfc7174 --- /dev/null +++ b/svgs/zenless_zone_zero.svg @@ -0,0 +1 @@ + \ No newline at end of file From ad7bb25b7c95f6ab8e802407eddf973d1ff22a77 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sun, 8 Sep 2024 10:02:32 +0300 Subject: [PATCH 109/144] +44 links (#2311) * +44 links * Minor fix --- app/assets/appfilter.xml | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 578bdb4be14..27867659cda 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -61,6 +61,7 @@ + @@ -1303,6 +1304,7 @@ + @@ -1561,6 +1563,8 @@ + + @@ -1766,6 +1770,7 @@ + @@ -2977,6 +2982,7 @@ + @@ -3122,6 +3128,7 @@ + @@ -3135,6 +3142,7 @@ + @@ -3254,6 +3262,7 @@ + @@ -3512,6 +3521,8 @@ + + @@ -3650,6 +3661,7 @@ + @@ -4360,8 +4372,11 @@ + + + @@ -4406,6 +4421,7 @@ + @@ -4420,6 +4436,8 @@ + + @@ -4531,6 +4549,7 @@ + @@ -5117,6 +5136,7 @@ + @@ -5223,6 +5243,7 @@ + @@ -5377,6 +5398,7 @@ + @@ -5497,6 +5519,7 @@ + @@ -5633,6 +5656,7 @@ + @@ -5682,6 +5706,7 @@ + @@ -6006,6 +6031,7 @@ + @@ -6321,6 +6347,7 @@ + @@ -6333,6 +6360,7 @@ + @@ -6553,6 +6581,7 @@ + @@ -7361,6 +7390,7 @@ + @@ -7384,6 +7414,7 @@ + @@ -7708,6 +7739,7 @@ + @@ -8166,6 +8198,7 @@ + @@ -9102,6 +9135,7 @@ + @@ -9808,6 +9842,7 @@ + @@ -10238,6 +10273,7 @@ + @@ -11138,6 +11174,8 @@ + + @@ -11328,6 +11366,7 @@ + @@ -11429,6 +11468,7 @@ + @@ -11857,6 +11897,7 @@ + @@ -12051,6 +12092,7 @@ + @@ -12108,6 +12150,8 @@ + + From ae9d0d037c8b2e452aff60ba9185b2e551e68838 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Mon, 9 Sep 2024 01:32:50 +0300 Subject: [PATCH 110/144] +14 links (#2313) --- app/assets/appfilter.xml | 14 ++++++++++++++ svgs/castro.svg | 2 +- svgs/lawnchair.svg | 2 +- svgs/pi_network.svg | 2 +- svgs/superimage.svg | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 27867659cda..5185b285a08 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -172,6 +172,7 @@ + @@ -194,6 +195,7 @@ + @@ -603,6 +605,7 @@ + @@ -2617,6 +2620,7 @@ + @@ -4355,6 +4359,7 @@ + @@ -4713,6 +4718,7 @@ + @@ -5656,6 +5662,10 @@ + + + + @@ -7390,6 +7400,7 @@ + @@ -7414,6 +7425,7 @@ + @@ -7837,6 +7849,7 @@ + @@ -11366,6 +11379,7 @@ + diff --git a/svgs/castro.svg b/svgs/castro.svg index 7b226b18acd..179fe77c760 100644 --- a/svgs/castro.svg +++ b/svgs/castro.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/lawnchair.svg b/svgs/lawnchair.svg index 0a6c5487e74..ec900f5f3cf 100644 --- a/svgs/lawnchair.svg +++ b/svgs/lawnchair.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/pi_network.svg b/svgs/pi_network.svg index 92a24c36dc9..c5d1e33049b 100644 --- a/svgs/pi_network.svg +++ b/svgs/pi_network.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/superimage.svg b/svgs/superimage.svg index e227f5cf92a..2a7f6b6fea0 100644 --- a/svgs/superimage.svg +++ b/svgs/superimage.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From ca2473ad47d743dcb2cd650e774709db61339215 Mon Sep 17 00:00:00 2001 From: Pun Butrach Date: Mon, 9 Sep 2024 21:10:31 +0700 Subject: [PATCH 111/144] Link Lawnchair Google Play Store package name (#2316) * Link Lawnchair Google Play Store package name * github is dumb --- app/assets/appfilter.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 5185b285a08..087ba214fb5 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -5189,6 +5189,7 @@ + From 1ce102e5706d110e4f910c848b7d403b762215be Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 9 Sep 2024 20:43:14 +0800 Subject: [PATCH 112/144] Implement new icons UI --- app/src/main/AndroidManifest.xml | 4 +- .../lawnicons/di/NewIconsRepositoryModule.kt | 34 ++++ .../repository/NewIconsRepository.kt | 61 ++++++++ .../lawnicons/repository/PreferenceManager.kt | 93 ++++++++++- .../app/lawnchair/lawnicons/ui/Lawnicons.kt | 9 +- .../lawnicons/ui/components/core/Card.kt | 23 ++- .../ui/components/core/LawniconsScaffold.kt | 6 +- .../ui/components/home/IconPreviewGrid.kt | 147 +++++++++++------- .../ui/components/home/NewIconsCard.kt | 112 +++++++++++++ .../ui/components/home/search/SearchBar.kt | 16 +- .../lawnicons/ui/destination/Home.kt | 89 +++++------ .../lawnicons/ui/destination/NewIcons.kt | 77 +++++++++ .../lawnchair/lawnicons/util/GetIconInfo.kt | 6 +- .../lawnicons/viewmodel/LawniconsViewModel.kt | 73 +++++++-- .../lawnicons/viewmodel/NewIconsViewModel.kt | 31 ++++ app/src/main/res/drawable/new_releases.xml | 21 +++ app/src/main/res/values/strings.xml | 3 + .../lawnicons/helper/AppfilterDiffCreator.kt | 81 ++++++++++ .../lawnchair/lawnicons/helper/Application.kt | 21 ++- .../lawnicons/helper/ConfigProcessor.kt | 19 +++ .../lawnicons/helper/SvgFilesProcessor.kt | 16 ++ .../app/lawnchair/lawnicons/helper/XmlUtil.kt | 16 ++ 22 files changed, 801 insertions(+), 157 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/di/NewIconsRepositoryModule.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/repository/NewIconsRepository.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/NewIcons.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/NewIconsViewModel.kt create mode 100644 app/src/main/res/drawable/new_releases.xml create mode 100644 svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b32bcae0c12..b40f1576d1f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,12 +18,12 @@ - + - + diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/di/NewIconsRepositoryModule.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/di/NewIconsRepositoryModule.kt new file mode 100644 index 00000000000..cef43aedc7a --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/di/NewIconsRepositoryModule.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.di + +import android.app.Application +import app.lawnchair.lawnicons.repository.NewIconsRepository +import app.lawnchair.lawnicons.repository.NewIconsRepositoryImpl +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +object NewIconsRepositoryModule { + @Provides + @Singleton + fun provideNewIconsRepository(application: Application): NewIconsRepository = NewIconsRepositoryImpl(application) +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/NewIconsRepository.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/NewIconsRepository.kt new file mode 100644 index 00000000000..1866e8621b3 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/NewIconsRepository.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.repository + +import android.app.Application +import app.lawnchair.lawnicons.BuildConfig +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.model.IconInfoModel +import app.lawnchair.lawnicons.util.getIconInfo +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +interface NewIconsRepository { + val newIconsInfoModel: StateFlow +} + +class NewIconsRepositoryImpl @Inject constructor(application: Application) : NewIconsRepository { + + private val coroutineScope = CoroutineScope(Dispatchers.IO) + private val prefs = PreferenceManager.getInstance(application) + + private val _newIconsInfoModel = MutableStateFlow(IconInfoModel()) + override val newIconsInfoModel = _newIconsInfoModel.asStateFlow() + + init { + val currentVersionCode = prefs.currentLawniconsVersion.get() + val newVersionCode = BuildConfig.VERSION_CODE + + if (currentVersionCode != newVersionCode) { + prefs.currentLawniconsVersion.set(newVersionCode) + prefs.showNewIconsCard.set(true) + } + + coroutineScope.launch { + val iconInfo = application.getIconInfo(R.xml.appfilter_diff).sortedBy { it.label.lowercase() } + _newIconsInfoModel.value = IconInfoModel( + iconInfo, + iconInfo.size, + ) + } + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt index b641936f866..75773b25ff5 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -6,6 +6,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.runtime.produceState import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalInspectionMode +import app.lawnchair.lawnicons.BuildConfig /** * A class that abstracts the functionality of SharedPreferences @@ -45,22 +47,55 @@ abstract class BasePreferenceManager( } } } + + /** + * A class that represents a integer preference + * @param key The key of the preference + * @param defaultValue The default value of the preference + */ + inner class IntPref( + val key: String, + private val defaultValue: Int, + ) { + fun get() = prefs.getInt(key, defaultValue) + fun set(value: Int) = editor.putInt(key, value).apply() + + @Composable + fun asState(): State { + return produceState(initialValue = get(), this) { + val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, changedKey -> + if (changedKey == key) { + value = get() // Update the state value when the preference changes + } + } + prefs.registerOnSharedPreferenceChangeListener(listener) + awaitDispose { + prefs.unregisterOnSharedPreferenceChangeListener(listener) + } + } + } + } } /** * Provides a class to handle Lawnicons preferences + * + * Use [PreferenceManager.getInstance] to get the instance for use thoughout the app. + * @see preferenceManager */ class PreferenceManager private constructor( prefs: SharedPreferences, ) : BasePreferenceManager(prefs) { val showFirstLaunchSnackbar = BoolPref("show_first_launch_snackbar", true) + val showNewIconsCard = BoolPref("show_new_icons_card", true) + val currentLawniconsVersion = IntPref("current_lawnicons_version", BuildConfig.VERSION_CODE) companion object { @Volatile private var instance: PreferenceManager? = null /** - * Returns a singleton instance of PreferenceManager + * Returns a singleton instance of [PreferenceManager] */ fun getInstance(context: Context): PreferenceManager { return instance ?: synchronized(this) { @@ -69,8 +104,62 @@ class PreferenceManager private constructor( ).also { instance = it } } } + + /** + * Get dummy instance of [PreferenceManager] for testing and Compose previews + */ + fun getDummyInstance(): PreferenceManager { + return PreferenceManager(DummySharedPreferences()) + } } } +/** + * Returns a singleton instance of [PreferenceManager] for use in Composable UIs. + * + * In [LocalInspectionMode], the dummy instance is returned instead. + * + * @param context the context to use for getting the shared preferences + * @return a singleton instance of [PreferenceManager] + */ @Composable -fun preferenceManager(context: Context = LocalContext.current) = PreferenceManager.getInstance(context) +fun preferenceManager(context: Context = LocalContext.current) = if (LocalInspectionMode.current) { + PreferenceManager.getDummyInstance() +} else { + PreferenceManager.getInstance(context) +} + +/** + * Dummy implementation of [SharedPreferences] for Compose previews, with mock default values + */ +class DummySharedPreferences : SharedPreferences { + override fun getAll() = mutableMapOf>() + override fun getBoolean(key: String?, defValue: Boolean) = true + override fun getString(key: String?, defValue: String?) = "" + override fun getStringSet(key: String?, defValues: MutableSet?) = mutableSetOf() + override fun getLong(key: String?, defValue: Long) = 0L + override fun getFloat(key: String?, defValue: Float) = 0.0f + override fun getInt(key: String?, defValue: Int) = 0 + override fun contains(key: String?) = true + override fun edit() = DummyEditor() + override fun registerOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {} + override fun unregisterOnSharedPreferenceChangeListener(listener: SharedPreferences.OnSharedPreferenceChangeListener?) {} + + /** + * Dummy implementation of [SharedPreferences.Editor] for Compose previews + */ + class DummyEditor() : SharedPreferences.Editor { + override fun putString(key: String?, value: String?) = DummyEditor() + override fun putStringSet(key: String?, values: MutableSet?) = DummyEditor() + + override fun putInt(key: String?, value: Int) = DummyEditor() + override fun putLong(key: String?, value: Long) = DummyEditor() + override fun putFloat(key: String?, value: Float) = DummyEditor() + override fun putBoolean(key: String?, value: Boolean) = DummyEditor() + override fun remove(key: String?) = DummyEditor() + override fun clear() = DummyEditor() + + override fun commit() = true + override fun apply() {} + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt index 5562654a521..5ffd551ae9a 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/Lawnicons.kt @@ -16,11 +16,13 @@ import app.lawnchair.lawnicons.ui.destination.Acknowledgement import app.lawnchair.lawnicons.ui.destination.Acknowledgements import app.lawnchair.lawnicons.ui.destination.Contributors import app.lawnchair.lawnicons.ui.destination.Home +import app.lawnchair.lawnicons.ui.destination.NewIcons import app.lawnchair.lawnicons.ui.destination.aboutDestination import app.lawnchair.lawnicons.ui.destination.acknowledgementDestination import app.lawnchair.lawnicons.ui.destination.acknowledgementsDestination import app.lawnchair.lawnicons.ui.destination.contributorsDestination import app.lawnchair.lawnicons.ui.destination.homeDestination +import app.lawnchair.lawnicons.ui.destination.newIconsDestination import soup.compose.material.motion.animation.materialSharedAxisXIn import soup.compose.material.motion.animation.materialSharedAxisXOut import soup.compose.material.motion.animation.rememberSlideDistance @@ -49,7 +51,8 @@ fun Lawnicons( popExitTransition = { materialSharedAxisXOut(isRtl, slideDistance) }, ) { homeDestination( - onNavigate = { navController.navigate(About) }, + onNavigateToAbout = { navController.navigate(About) }, + onNavigateToNewIcons = { navController.navigate(NewIcons) }, isExpandedScreen = isExpandedScreen, isIconPicker = isIconPicker, onSendResult = onSendResult, @@ -79,6 +82,10 @@ fun Lawnicons( onBack = navController::popBackStack, isExpandedScreen = isExpandedScreen, ) + newIconsDestination( + onBack = navController::popBackStack, + isExpandedScreen = isExpandedScreen, + ) } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/Card.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/Card.kt index 94855617e6b..41421916eb9 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/Card.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/Card.kt @@ -1,6 +1,7 @@ package app.lawnchair.lawnicons.ui.components.core import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.shape.RoundedCornerShape @@ -16,22 +17,18 @@ import app.lawnchair.lawnicons.ui.util.PreviewLawnicons @Composable fun Card( modifier: Modifier = Modifier, + contentModifier: Modifier = Modifier, label: String? = null, - content: @Composable () -> Unit, + content: @Composable ColumnScope.() -> Unit, ) { Column(modifier = modifier) { if (label != null) { - Text( - text = label, - style = MaterialTheme.typography.titleSmall, - color = MaterialTheme.colorScheme.primary, - modifier = Modifier.padding(start = 32.dp, bottom = 6.dp), - ) + CardHeader(label) } Surface( color = MaterialTheme.colorScheme.surfaceContainer, shape = RoundedCornerShape(size = 16.dp), - modifier = Modifier + modifier = contentModifier .padding(horizontal = 16.dp) .fillMaxWidth(), ) { @@ -42,6 +39,16 @@ fun Card( } } +@Composable +fun CardHeader(label: String, modifier: Modifier = Modifier) { + Text( + text = label, + style = MaterialTheme.typography.titleSmall, + color = MaterialTheme.colorScheme.primary, + modifier = modifier.padding(start = 32.dp, bottom = 6.dp), + ) +} + @PreviewLawnicons @Composable private fun CardPreview() { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/LawniconsScaffold.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/LawniconsScaffold.kt index fef3a4c2e6e..4bd3d20a073 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/LawniconsScaffold.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/core/LawniconsScaffold.kt @@ -29,10 +29,8 @@ fun LawniconsScaffold( modifier: Modifier = Modifier, content: @Composable (PaddingValues) -> Unit, ) { - var scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() - if (isExpandedScreen) { - scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() - } + val scrollBehavior = + if (isExpandedScreen) TopAppBarDefaults.pinnedScrollBehavior() else TopAppBarDefaults.exitUntilCollapsedScrollBehavior() Scaffold( modifier = modifier.nestedScroll(scrollBehavior.nestedScrollConnection), diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 3821e3e60fb..8e0dd7864be 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -10,7 +10,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -25,6 +24,7 @@ import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyGridItemScope import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -49,6 +49,7 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo @@ -61,16 +62,39 @@ import my.nanihadesuka.compose.InternalLazyVerticalGridScrollbar import my.nanihadesuka.compose.ScrollbarSelectionMode import my.nanihadesuka.compose.ScrollbarSettings +data class IconPreviewGridPadding( + val topPadding: Dp, + val bottomPadding: Dp, + val horizontalPadding: Dp, +) { + + companion object { + val Defaults = IconPreviewGridPadding( + topPadding = 0.dp, + bottomPadding = 80.dp, + horizontalPadding = 8.dp, + ) + + val ExpandedSize = IconPreviewGridPadding( + topPadding = 72.dp, + bottomPadding = 0.dp, + horizontalPadding = 32.dp, + ) + } +} + @Composable @ExperimentalFoundationApi fun IconPreviewGrid( iconInfo: List, - isExpandedScreen: Boolean, onSendResult: (IconInfo) -> Unit, modifier: Modifier = Modifier, + containerModifier: Modifier = Modifier + .applyGridInsets(), + contentPadding: IconPreviewGridPadding = IconPreviewGridPadding.Defaults, isIconPicker: Boolean = false, - contentPadding: PaddingValues? = null, gridState: LazyGridState = rememberLazyGridState(), + otherContent: @Composable (LazyGridItemScope.() -> Unit) = {}, ) { val indexOfFirstItem by remember { derivedStateOf { gridState.firstVisibleItemIndex } } val letter = iconInfo[indexOfFirstItem].label[0].uppercase() @@ -81,48 +105,30 @@ fun IconPreviewGrid( verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxWidth(), ) { - val horizontalGridPadding = if (isExpandedScreen) 32.dp else 8.dp Box( - modifier = Modifier - .widthIn(max = 640.dp) - .fillMaxWidth() - .statusBarsPadding() - .then( - if (isExpandedScreen) { - Modifier.padding(top = 26.dp) - } else { - Modifier.padding( - bottom = 80.dp, - ) - }, - ), + modifier = containerModifier + .padding(bottom = contentPadding.bottomPadding), ) { LazyVerticalGrid( columns = GridCells.Adaptive(minSize = 80.dp), - contentPadding = contentPadding ?: WindowInsets.navigationBars.toPaddingValues( - additionalStart = horizontalGridPadding, - additionalTop = if (isExpandedScreen) 42.dp else 0.dp, - additionalEnd = horizontalGridPadding, + contentPadding = WindowInsets.navigationBars.toPaddingValues( + additionalStart = contentPadding.horizontalPadding, + additionalTop = contentPadding.topPadding, + additionalEnd = contentPadding.horizontalPadding, ), state = gridState, ) { - if (!isExpandedScreen) { - item( - span = { - GridItemSpan(maxLineSpan) - }, - ) { - AppBarListItem() - } + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + otherContent() } items( items = iconInfo, contentType = { "icon_preview" }, ) { iconInfo -> val scale by animateFloatAsState( - if (thumbSelected && iconInfo.label.first() - .toString() == letter - ) { + if (thumbSelected && iconInfo.label.first().toString() == letter) { 1.1f } else { 1f @@ -138,35 +144,56 @@ fun IconPreviewGrid( ) } } - Box( - contentAlignment = Alignment.CenterEnd, - ) { - Spacer( - Modifier - .fillMaxHeight() - .width(8.dp) - .background(MaterialTheme.colorScheme.surfaceContainer) - .clip(CircleShape), - ) - InternalLazyVerticalGridScrollbar( - modifier = Modifier.offset(7.dp), - state = gridState, - settings = ScrollbarSettings( - alwaysShowScrollbar = true, - thumbUnselectedColor = MaterialTheme.colorScheme.primary, - thumbSelectedColor = MaterialTheme.colorScheme.primary, - selectionMode = ScrollbarSelectionMode.Thumb, - ), - indicatorContent = { _, isThumbSelected -> - thumbSelected = isThumbSelected - ScrollbarIndicator(letter, isThumbSelected) - }, - ) - } + ScrollbarLayout( + gridState, + { thumbSelected = it }, + letter, + contentPadding.topPadding, + ) } } } +private fun Modifier.applyGridInsets() = this + .widthIn(max = 640.dp) + .fillMaxWidth() + .statusBarsPadding() + +@Composable +private fun ScrollbarLayout( + gridState: LazyGridState, + onSelectedChange: (Boolean) -> Unit, + currentLetter: String, + topPadding: Dp = 0.dp, +) { + Box( + contentAlignment = Alignment.CenterEnd, + modifier = Modifier.padding(top = topPadding), + ) { + Spacer( + Modifier + .fillMaxHeight() + .width(8.dp) + .background(MaterialTheme.colorScheme.surfaceContainer) + .clip(CircleShape), + ) + InternalLazyVerticalGridScrollbar( + modifier = Modifier.offset(7.dp), + state = gridState, + settings = ScrollbarSettings( + alwaysShowScrollbar = true, + thumbUnselectedColor = MaterialTheme.colorScheme.primary, + thumbSelectedColor = MaterialTheme.colorScheme.primary, + selectionMode = ScrollbarSelectionMode.Thumb, + ), + indicatorContent = { _, isThumbSelected -> + onSelectedChange(isThumbSelected) + ScrollbarIndicator(currentLetter, isThumbSelected) + }, + ) + } +} + @Composable private fun ScrollbarIndicator( label: String, @@ -197,7 +224,7 @@ private fun ScrollbarIndicator( @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun AppBarListItem(modifier: Modifier = Modifier) { +fun AppBarListItem(modifier: Modifier = Modifier) { val context = LocalContext.current CenterAlignedTopAppBar( modifier = modifier, @@ -229,9 +256,9 @@ private fun IconGridPreview() { Surface { IconPreviewGrid( iconInfo = SampleData.iconInfoList, - isExpandedScreen = false, onSendResult = {}, modifier = Modifier, + contentPadding = IconPreviewGridPadding.Defaults, isIconPicker = false, ) } @@ -246,9 +273,9 @@ private fun IconGridExpandedPreview() { Surface { IconPreviewGrid( iconInfo = SampleData.iconInfoList, - isExpandedScreen = true, onSendResult = {}, modifier = Modifier, + contentPadding = IconPreviewGridPadding.ExpandedSize, isIconPicker = false, ) } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt new file mode 100644 index 00000000000..adef79bb553 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt @@ -0,0 +1,112 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.ui.components.home + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Clear +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.BuildConfig +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.repository.preferenceManager +import app.lawnchair.lawnicons.ui.components.core.Card +import app.lawnchair.lawnicons.ui.theme.LawniconsTheme +import app.lawnchair.lawnicons.ui.util.PreviewLawnicons + +@Composable +fun NewIconsCard( + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + val prefs = preferenceManager() + val cardState = prefs.showNewIconsCard.asState() + NewIconsCard( + onClick = onClick, + visible = cardState.value, + onVisibilityChange = { + prefs.showNewIconsCard.set(false) + }, + modifier = modifier, + ) +} + +@Composable +fun NewIconsCard( + onClick: () -> Unit, + visible: Boolean, + onVisibilityChange: () -> Unit, + modifier: Modifier = Modifier, +) { + AnimatedVisibility(visible) { + Card( + modifier = modifier, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier + .clickable { onClick() } + .padding(start = 12.dp), + ) { + Row { + Icon( + painterResource(R.drawable.new_releases), + contentDescription = null, + ) + Spacer(Modifier.width(8.dp)) + Text( + text = stringResource( + R.string.new_icons_in_version, + BuildConfig.VERSION_NAME, + ), + style = MaterialTheme.typography.titleSmall, + ) + } + Spacer(Modifier.weight(1f)) + IconButton( + onClick = onVisibilityChange, + ) { + Icon(Icons.Rounded.Clear, contentDescription = stringResource(R.string.clear)) + } + } + } + } +} + +@PreviewLawnicons +@Composable +private fun NewIconsCardPreview() { + LawniconsTheme { + Surface { + NewIconsCard({}) + } + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt index c2e1d4ac3d5..00bf7162860 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt @@ -261,15 +261,13 @@ internal fun SearchIcon( active: Boolean, onButtonClick: () -> Unit, ) { - Crossfade(active, label = "") { - if (it) { - ClickableIcon( - imageVector = Icons.AutoMirrored.Rounded.ArrowBack, - onClick = onButtonClick, - ) - } else { - Icon(Icons.Rounded.Search, contentDescription = null) - } + if (active) { + ClickableIcon( + imageVector = Icons.AutoMirrored.Rounded.ArrowBack, + onClick = onButtonClick, + ) + } else { + Icon(Icons.Rounded.Search, contentDescription = null) } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index a257463e19f..52ada0381f2 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -8,16 +8,14 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -27,19 +25,20 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import app.lawnchair.lawnicons.model.IconInfo -import app.lawnchair.lawnicons.model.SearchMode +import app.lawnchair.lawnicons.ui.components.home.AppBarListItem import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBarUiState import app.lawnchair.lawnicons.ui.components.home.IconPreviewGrid +import app.lawnchair.lawnicons.ui.components.home.IconPreviewGridPadding import app.lawnchair.lawnicons.ui.components.home.IconRequestFAB -import app.lawnchair.lawnicons.ui.components.home.search.LawniconsSearchBar +import app.lawnchair.lawnicons.ui.components.home.NewIconsCard import app.lawnchair.lawnicons.ui.components.home.search.PlaceholderSearchBar -import app.lawnchair.lawnicons.ui.components.home.search.SearchContents import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons -import app.lawnchair.lawnicons.ui.util.SampleData +import app.lawnchair.lawnicons.viewmodel.DummyLawniconsViewModel import app.lawnchair.lawnicons.viewmodel.LawniconsViewModel +import app.lawnchair.lawnicons.viewmodel.LawniconsViewModelImpl import kotlinx.serialization.Serializable @Serializable @@ -48,12 +47,14 @@ data object Home fun NavGraphBuilder.homeDestination( isExpandedScreen: Boolean, isIconPicker: Boolean, - onNavigate: () -> Unit, + onNavigateToAbout: () -> Unit, + onNavigateToNewIcons: () -> Unit, onSendResult: (IconInfo) -> Unit, ) { composable { Home( - onNavigate = onNavigate, + onNavigateToAbout = onNavigateToAbout, + onNavigateToNewIcons = onNavigateToNewIcons, isExpandedScreen = isExpandedScreen, isIconPicker = isIconPicker, onSendResult = onSendResult, @@ -62,20 +63,22 @@ fun NavGraphBuilder.homeDestination( } @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") -@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) +@OptIn(ExperimentalFoundationApi::class) @Composable private fun Home( - onNavigate: () -> Unit, + onNavigateToAbout: () -> Unit, + onNavigateToNewIcons: () -> Unit, onSendResult: (IconInfo) -> Unit, isExpandedScreen: Boolean, modifier: Modifier = Modifier, isIconPicker: Boolean = false, - lawniconsViewModel: LawniconsViewModel = hiltViewModel(), + lawniconsViewModel: LawniconsViewModel = hiltViewModel(), ) { with(lawniconsViewModel) { val iconInfoModel by iconInfoModel.collectAsStateWithLifecycle() val searchedIconInfoModel by searchedIconInfoModel.collectAsStateWithLifecycle() val iconRequestModel by iconRequestModel.collectAsStateWithLifecycle() + val newIconsInfoModel by newIconsInfoModel.collectAsStateWithLifecycle() val context = LocalContext.current val lazyGridState = rememberLazyGridState() @@ -104,7 +107,7 @@ private fun Home( onClearSearch = ::clearSearch, onChangeMode = ::changeMode, onSearchIcons = ::searchIcons, - onNavigate = onNavigate, + onNavigate = onNavigateToAbout, onSendResult = onSendResult, focusRequester = focusRequester, ) @@ -115,7 +118,7 @@ private fun Home( context = context, iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, - onNavigate = onNavigate, + onNavigate = onNavigateToAbout, onExpandSearch = { expandSearch = true }, ) } @@ -135,11 +138,20 @@ private fun Home( ) { IconPreviewGrid( iconInfo = iconInfoModel.iconInfo, - isExpandedScreen = isExpandedScreen, - isIconPicker = isIconPicker, onSendResult = onSendResult, + contentPadding = if (isExpandedScreen) IconPreviewGridPadding.ExpandedSize else IconPreviewGridPadding.Defaults, + isIconPicker = isIconPicker, gridState = lazyGridState, - ) + ) { + Column { + if (!isExpandedScreen) { + AppBarListItem() + } + if (newIconsInfoModel.iconCount != 0) { + NewIconsCard(onNavigateToNewIcons) + } + } + } } } else { if (isExpandedScreen) { @@ -163,43 +175,18 @@ private fun Home( } } -@OptIn(ExperimentalFoundationApi::class) @PreviewLawnicons @Composable private fun HomePreview() { - var searchTerm by remember { mutableStateOf(value = "") } - val iconInfo = SampleData.iconInfoList - LawniconsTheme { - LawniconsSearchBar( - query = searchTerm, - isQueryEmpty = searchTerm == "", - onClear = { - searchTerm = "" - }, - onBack = {}, - onQueryChange = { newValue -> - searchTerm = newValue - // No actual searching, this is just a preview - }, - iconCount = 3, - onNavigate = {}, - isExpandedScreen = true, - content = { - SearchContents( - "", - SearchMode.LABEL, - {}, - iconInfo = iconInfo, - ) - }, - ) - IconPreviewGrid( - iconInfo = iconInfo, - isExpandedScreen = false, - {}, - Modifier, - false, - ) + Surface(Modifier.fillMaxSize()) { + Home( + onNavigateToAbout = {}, + onNavigateToNewIcons = {}, + isExpandedScreen = true, + onSendResult = {}, + lawniconsViewModel = DummyLawniconsViewModel(), + ) + } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/NewIcons.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/NewIcons.kt new file mode 100644 index 00000000000..50ecbed8c97 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/NewIcons.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.ui.destination + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.ui.components.core.LawniconsScaffold +import app.lawnchair.lawnicons.ui.components.home.IconPreviewGrid +import app.lawnchair.lawnicons.ui.components.home.IconPreviewGridPadding +import app.lawnchair.lawnicons.viewmodel.NewIconsViewModel +import kotlinx.serialization.Serializable + +@Serializable +data object NewIcons + +fun NavGraphBuilder.newIconsDestination( + isExpandedScreen: Boolean, + onBack: () -> Unit, +) { + composable { + NewIcons( + onBack = onBack, + isExpandedScreen = isExpandedScreen, + ) + } +} + +@OptIn(ExperimentalFoundationApi::class) +@Composable +private fun NewIcons( + onBack: () -> Unit, + isExpandedScreen: Boolean, + modifier: Modifier = Modifier, + newIconsViewModel: NewIconsViewModel = hiltViewModel(), +) { + val iconInfoModel by newIconsViewModel.newIconsInfoModel.collectAsStateWithLifecycle() + + LawniconsScaffold( + modifier = modifier, + title = stringResource(R.string.new_icons, iconInfoModel.iconCount), + onBack = onBack, + isExpandedScreen = isExpandedScreen, + ) { paddingValues -> + IconPreviewGrid( + iconInfo = iconInfoModel.iconInfo, + onSendResult = {}, + contentPadding = IconPreviewGridPadding( + topPadding = paddingValues.calculateTopPadding() - 24.dp, + bottomPadding = paddingValues.calculateBottomPadding(), + horizontalPadding = if (isExpandedScreen) IconPreviewGridPadding.ExpandedSize.horizontalPadding else IconPreviewGridPadding.Defaults.horizontalPadding, + ), + ) + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt index 7ea59aeb188..d162a0a68e6 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/GetIconInfo.kt @@ -2,6 +2,7 @@ package app.lawnchair.lawnicons.util import android.annotation.SuppressLint import android.content.Context +import androidx.annotation.XmlRes import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo import app.lawnchair.lawnicons.model.LabelAndComponent @@ -9,13 +10,14 @@ import app.lawnchair.lawnicons.model.mergeByDrawableName import org.xmlpull.v1.XmlPullParser @SuppressLint("DiscouragedApi") -fun Context.getIconInfo(): List { +fun Context.getIconInfo( + @XmlRes xmlId: Int = R.xml.appfilter, +): List { val iconInfo = mutableListOf() val componentInfoPrefixLength = "ComponentInfo{".length try { - val xmlId = R.xml.appfilter if (xmlId != 0) { val parser = resources.getXml(xmlId) val depth = parser.depth diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt index b6d23e9fefc..c5510c80bdb 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/LawniconsViewModel.kt @@ -5,55 +5,94 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import app.lawnchair.lawnicons.model.IconInfoModel +import app.lawnchair.lawnicons.model.IconRequestModel import app.lawnchair.lawnicons.model.SearchMode import app.lawnchair.lawnicons.repository.IconRepository +import app.lawnchair.lawnicons.repository.NewIconsRepository +import app.lawnchair.lawnicons.ui.util.SampleData import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -@HiltViewModel -class LawniconsViewModel @Inject constructor( - private val iconRepository: IconRepository, -) : - ViewModel() { - @JvmField - val iconInfoModel = iconRepository.iconInfoModel +interface LawniconsViewModel { + val iconInfoModel: StateFlow + val searchedIconInfoModel: StateFlow + val iconRequestModel: StateFlow + val newIconsInfoModel: StateFlow + + var expandSearch: Boolean + + val searchMode: SearchMode + val searchTerm: String - @JvmField - val searchedIconInfoModel = iconRepository.searchedIconInfoModel + fun searchIcons(query: String) + fun changeMode(mode: SearchMode) + fun clearSearch() +} - @JvmField - val iconRequestModel = iconRepository.iconRequestList +@HiltViewModel +class LawniconsViewModelImpl @Inject constructor( + private val iconRepository: IconRepository, + private val newIconsRepository: NewIconsRepository, +) : LawniconsViewModel, ViewModel() { + override val iconInfoModel = iconRepository.iconInfoModel + override val searchedIconInfoModel = iconRepository.searchedIconInfoModel + override val iconRequestModel = iconRepository.iconRequestList + override val newIconsInfoModel = newIconsRepository.newIconsInfoModel - var expandSearch by mutableStateOf(false) + override var expandSearch by mutableStateOf(false) private var _searchMode by mutableStateOf(SearchMode.LABEL) private var _searchTerm by mutableStateOf("") - val searchMode: SearchMode + override val searchMode: SearchMode get() = _searchMode - val searchTerm: String + override val searchTerm: String get() = _searchTerm - fun searchIcons(query: String) { + override fun searchIcons(query: String) { _searchTerm = query viewModelScope.launch { iconRepository.search(searchMode, searchTerm) } } - fun changeMode(mode: SearchMode) { + override fun changeMode(mode: SearchMode) { _searchMode = mode viewModelScope.launch { iconRepository.search(searchMode, searchTerm) } } - fun clearSearch() { + override fun clearSearch() { _searchTerm = "" viewModelScope.launch { iconRepository.clearSearch() } } } + +class DummyLawniconsViewModel : LawniconsViewModel { + private val list = SampleData.iconInfoList + + override val iconInfoModel = MutableStateFlow(IconInfoModel(iconInfo = list, iconCount = list.size)).asStateFlow() + override val searchedIconInfoModel = MutableStateFlow(IconInfoModel(iconInfo = list, iconCount = list.size)).asStateFlow() + override val iconRequestModel = MutableStateFlow(IconRequestModel(list = listOf(), iconCount = 0)).asStateFlow() + override val newIconsInfoModel = MutableStateFlow(IconInfoModel(iconInfo = list, iconCount = list.size)).asStateFlow() + + override var expandSearch by mutableStateOf(false) + + override val searchMode = SearchMode.LABEL + override val searchTerm = "" + + override fun searchIcons(query: String) {} + + override fun changeMode(mode: SearchMode) {} + + override fun clearSearch() {} +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/NewIconsViewModel.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/NewIconsViewModel.kt new file mode 100644 index 00000000000..8b7136527c7 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/viewmodel/NewIconsViewModel.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.viewmodel + +import androidx.lifecycle.ViewModel +import app.lawnchair.lawnicons.repository.NewIconsRepository +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +@HiltViewModel +class NewIconsViewModel @Inject constructor( + private val newIconsRepository: NewIconsRepository, +) : ViewModel() { + + @JvmField + val newIconsInfoModel = newIconsRepository.newIconsInfoModel +} diff --git a/app/src/main/res/drawable/new_releases.xml b/app/src/main/res/drawable/new_releases.xml new file mode 100644 index 00000000000..9eec8a7b8eb --- /dev/null +++ b/app/src/main/res/drawable/new_releases.xml @@ -0,0 +1,21 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f3ff0e25c4..976cffe6bc0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -86,4 +86,7 @@ Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt new file mode 100644 index 00000000000..3988d9319b4 --- /dev/null +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.helper + +import java.io.File + +object AppfilterDiffCreator { + private const val OUTPUT_FILE = "/xml/appfilter_diff.xml" + + private fun getBranchContents( + branch: String, + appFilterFile: String, + ): List { + val command = listOf("git", "show", "$branch:$appFilterFile") + val process = ProcessBuilder(command) + .redirectErrorStream(true) + .start() + + val result = process.inputStream.bufferedReader().readLines() + if (process.waitFor() != 0) { + throw RuntimeException("Failed to execute command: $command") + } + return result + } + + private fun getLineDiff( + mainLines: List, + developLines: List, + ): List { + return developLines.filterNot { it in mainLines } + } + + private fun writeDiffToFile( + diff: List, + resDir: String, + ) { + val outputFile = File(resDir + OUTPUT_FILE) + val schema = "" + + if (diff.isEmpty()) { + outputFile.writeText("$schema\n") + return + } + + val xmlContent = buildString { + appendLine(schema) + appendLine("") + diff.forEach { line -> + appendLine(" $line") + } + appendLine("") + } + + outputFile.writeText(xmlContent) + } + + fun createAppfilterDiff( + resDir: String, + appFilterFile: String, + ) { + val mainLines = getBranchContents("main", appFilterFile) + val developLines = getBranchContents("develop", appFilterFile) + val diff = getLineDiff(mainLines, developLines) + + writeDiffToFile(diff, resDir) + } +} diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/Application.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/Application.kt index a016e388349..e97ded9b314 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/Application.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/Application.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package app.lawnchair.lawnicons.helper fun main() { @@ -8,9 +24,12 @@ fun main() { // Convert svg to drawable in runtime SvgFilesProcessor.process(sourceDir, "$resDir/drawable") + println("SvgToVectorDrawable task completed") // Read appfilter xml and create icon, drawable xml file. ConfigProcessor.loadAndCreateConfigs(appFilterFile, resDir) + println("ConfigProcessor task completed") - println("SvgToVector task completed") + AppfilterDiffCreator.createAppfilterDiff(resDir, appFilterFile) + println("Appfilter diff task completed") } diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/ConfigProcessor.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/ConfigProcessor.kt index 33b16af250e..3bc95143baf 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/ConfigProcessor.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/ConfigProcessor.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package app.lawnchair.lawnicons.helper import java.util.Locale @@ -25,10 +41,13 @@ object ConfigProcessor { resDirs.forEach { // Create Drawable files writeDrawableToFile(sortedDrawableMap, "$it/xml/drawable.xml") + println("Written drawables to $it/xml/drawable.xml") // Create Icon Map files writeIconMapToFile(sortedDrawableMap, iconMap, "$it/xml/grayscale_icon_map.xml") + println("Created grayscale_icon_map.xml") // Write AppFilter to resource directory XmlUtil.writeDocumentToFile(appFilterDocument, "$it/xml/appfilter.xml") + println("Created appfilter.xml") } } diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/SvgFilesProcessor.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/SvgFilesProcessor.kt index a0b8c3099f8..93bd91a34ae 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/SvgFilesProcessor.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/SvgFilesProcessor.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package app.lawnchair.lawnicons.helper import com.android.ide.common.vectordrawable.Svg2Vector diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/XmlUtil.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/XmlUtil.kt index bfe417d87f8..45db04313fb 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/XmlUtil.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/XmlUtil.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package app.lawnchair.lawnicons.helper import java.io.File From 7708507ad6963c900179a70e75363015b3434dee Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 9 Sep 2024 21:19:28 +0800 Subject: [PATCH 113/144] Improve UX for icon request disabling --- .../lawnicons/repository/PreferenceManager.kt | 12 +-- .../ui/components/home/IconRequestFAB.kt | 89 +++++++++++-------- 2 files changed, 58 insertions(+), 43 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt index 75773b25ff5..50e03618da7 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -77,12 +77,6 @@ abstract class BasePreferenceManager( } } -/** - * Provides a class to handle Lawnicons preferences - * - * Use [PreferenceManager.getInstance] to get the instance for use thoughout the app. - * @see preferenceManager - */ class PreferenceManager private constructor( prefs: SharedPreferences, ) : BasePreferenceManager(prefs) { @@ -90,6 +84,12 @@ class PreferenceManager private constructor( val showNewIconsCard = BoolPref("show_new_icons_card", true) val currentLawniconsVersion = IntPref("current_lawnicons_version", BuildConfig.VERSION_CODE) + /** + * Provides a class to handle Lawnicons preferences. + * + * Use [PreferenceManager.getInstance] to get the instance for use thoughout the app. + * @see preferenceManager + */ companion object { @Volatile private var instance: PreferenceManager? = null diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 53dfd79868d..83ce44a0e6d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -20,8 +20,10 @@ import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton +import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.SheetState import androidx.compose.material3.SnackbarDuration @@ -68,7 +70,10 @@ fun IconRequestFAB( modifier: Modifier = Modifier, ) { val list = iconRequestModel?.list ?: emptyList() + val enabled = iconRequestModel != null + RequestHandler( + enabled = enabled, iconRequestList = list, snackbarHostState = snackbarHostState, ) { interactionSource -> @@ -84,7 +89,8 @@ fun IconRequestFAB( }, onClick = {}, expanded = lazyGridState.isScrollingUp(), - interactionSource = interactionSource, + interactionSource = if (enabled) interactionSource else null, + containerColor = if (!enabled) MaterialTheme.colorScheme.surfaceVariant else FloatingActionButtonDefaults.containerColor, modifier = modifier, ) } @@ -97,14 +103,17 @@ fun IconRequestIconButton( modifier: Modifier = Modifier, ) { val list = iconRequestModel?.list ?: emptyList() + val enabled = iconRequestModel != null RequestHandler( + enabled = enabled, iconRequestList = list, snackbarHostState = snackbarHostState, ) { interactionSource -> IconButton( onClick = {}, - interactionSource = interactionSource, + enabled = enabled, + interactionSource = if (enabled) interactionSource else null, modifier = modifier, ) { Icon( @@ -119,6 +128,7 @@ fun IconRequestIconButton( @OptIn(ExperimentalMaterial3Api::class) @Composable fun RequestHandler( + enabled: Boolean, iconRequestList: List, snackbarHostState: SnackbarHostState, content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), @@ -140,6 +150,7 @@ fun RequestHandler( val interactionSource = remember { MutableInteractionSource() } HandleTouchInteractions( + enabled = enabled, interactionSource = interactionSource, viewConfiguration = LocalViewConfiguration.current, context = context, @@ -155,13 +166,15 @@ fun RequestHandler( content(interactionSource) - if (showFirstLaunchSnackbar && iconRequestList.isNotEmpty()) { - openSnackbarFirstLaunchContent( - context, - scope, - prefs.showFirstLaunchSnackbar::toggle, - snackbarHostState, - ) + LaunchedEffect(iconRequestList.isNotEmpty()) { + if (showFirstLaunchSnackbar) { + openSnackbarFirstLaunchContent( + context, + scope, + { prefs.showFirstLaunchSnackbar.set(false) }, + snackbarHostState, + ) + } } AnimatedVisibility(visible = sheetExpanded) { @@ -177,6 +190,7 @@ fun RequestHandler( @OptIn(ExperimentalMaterial3Api::class) @Composable private fun HandleTouchInteractions( + enabled: Boolean, interactionSource: MutableInteractionSource, viewConfiguration: ViewConfiguration, context: Context, @@ -189,40 +203,41 @@ private fun HandleTouchInteractions( encodedRequestList: String, snackbarHostState: SnackbarHostState, ) { - val prefs = preferenceManager() val lastestOnExpandSheet by rememberUpdatedState(newValue = onExpandSheet) - LaunchedEffect(interactionSource) { - var isLongClick = false - interactionSource.interactions.collectLatest { interaction -> - when (interaction) { - is PressInteraction.Press -> { - isLongClick = false - delay(viewConfiguration.longPressTimeoutMillis) - isLongClick = true - coroutineScope.launch { - lastestOnExpandSheet(true) - sheetState.show() + if (enabled) { + LaunchedEffect(interactionSource) { + var isLongClick = false + + interactionSource.interactions.collectLatest { interaction -> + when (interaction) { + is PressInteraction.Press -> { + isLongClick = false + delay(viewConfiguration.longPressTimeoutMillis) + isLongClick = true + coroutineScope.launch { + lastestOnExpandSheet(true) + sheetState.show() + } } - } - is PressInteraction.Release -> { - if (!isLongClick) { - prefs.showFirstLaunchSnackbar.set(false) - handleRequestClick( - iconRequestList, - context, - directLinkEnabled, - encodedRequestList, - requestList, - coroutineScope, - snackbarHostState, - ) + is PressInteraction.Release -> { + if (!isLongClick) { + handleRequestClick( + iconRequestList, + context, + directLinkEnabled, + encodedRequestList, + requestList, + coroutineScope, + snackbarHostState, + ) + } } - } - is PressInteraction.Cancel -> { - isLongClick = false + is PressInteraction.Cancel -> { + isLongClick = false + } } } } From 26300ccafe491aa65b52430bf6af92a384a4b065 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 9 Sep 2024 22:23:47 +0800 Subject: [PATCH 114/144] Add debug menu --- .../lawnicons/repository/PreferenceManager.kt | 1 + .../lawnicons/ui/components/home/DebugMenu.kt | 172 ++++++++++++++++++ .../ui/components/home/HomeBottomBar.kt | 3 +- .../ui/components/home/IconPreviewGrid.kt | 14 +- .../ui/components/home/IconRequestFAB.kt | 142 +++++---------- .../lawnicons/ui/destination/Home.kt | 12 +- .../lawnchair/lawnicons/ui/util/Clipboard.kt | 28 +++ 7 files changed, 268 insertions(+), 104 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/DebugMenu.kt create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Clipboard.kt diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt index 50e03618da7..700a06057cd 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/repository/PreferenceManager.kt @@ -82,6 +82,7 @@ class PreferenceManager private constructor( ) : BasePreferenceManager(prefs) { val showFirstLaunchSnackbar = BoolPref("show_first_launch_snackbar", true) val showNewIconsCard = BoolPref("show_new_icons_card", true) + val showDebugMenu = BoolPref("debug_menu", false) val currentLawniconsVersion = IntPref("current_lawnicons_version", BuildConfig.VERSION_CODE) /** diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/DebugMenu.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/DebugMenu.kt new file mode 100644 index 00000000000..e78673b78a0 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/DebugMenu.kt @@ -0,0 +1,172 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.ui.components.home + +import android.content.Context +import androidx.compose.foundation.horizontalScroll +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.Switch +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.BuildConfig +import app.lawnchair.lawnicons.R +import app.lawnchair.lawnicons.model.IconInfoModel +import app.lawnchair.lawnicons.model.IconRequestModel +import app.lawnchair.lawnicons.model.splitByComponentName +import app.lawnchair.lawnicons.repository.BasePreferenceManager +import app.lawnchair.lawnicons.repository.PreferenceManager +import app.lawnchair.lawnicons.repository.preferenceManager +import app.lawnchair.lawnicons.ui.components.core.Card +import app.lawnchair.lawnicons.ui.components.core.SimpleListRow +import app.lawnchair.lawnicons.ui.util.copyTextToClipboard + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DebugMenu( + iconInfoModel: IconInfoModel, + iconRequestModel: IconRequestModel?, + newIconsInfoModel: IconInfoModel, +) { + val context = LocalContext.current + val prefs = preferenceManager() + val sheetState = rememberModalBottomSheetState( + skipPartiallyExpanded = true, + ) + + ModalBottomSheet( + onDismissRequest = { prefs.showDebugMenu.set(false) }, + sheetState = sheetState, + ) { + SheetContent( + iconInfoCount = iconInfoModel.iconInfo.size, + componentCount = iconInfoModel.iconInfo.splitByComponentName().size, + newIconInfoList = newIconsInfoModel.toString(), + newIconInfoCount = newIconsInfoModel.iconInfo.size, + iconRequestList = iconRequestModel?.list?.joinToString("\n") { "${it.label}\n${it.componentName}" } + ?: "null", + iconRequestCount = iconRequestModel?.iconCount ?: 0, + context, + prefs, + ) + } +} + +@Composable +private fun SheetContent( + iconInfoCount: Int, + componentCount: Int, + newIconInfoList: String, + newIconInfoCount: Int, + iconRequestList: String, + iconRequestCount: Int, + context: Context, + prefs: PreferenceManager, +) { + Column( + modifier = Modifier + .padding(16.dp) + .verticalScroll(rememberScrollState()) + .fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + SimpleListRow("Icon count: $iconInfoCount") + SimpleListRow("Component count: $componentCount") + SimpleListRow("New icon count: $newIconInfoCount") + SimpleListRow("Icon request count: $iconRequestCount") + + SwitchPref(prefs.showDebugMenu) + SwitchPref(prefs.showNewIconsCard) + SwitchPref(prefs.showFirstLaunchSnackbar) + + SimpleListRow( + "Current version", + description = prefs.currentLawniconsVersion.asState().value.toString(), + ) + SimpleListRow( + "Actual version", + description = BuildConfig.VERSION_CODE.toString(), + ) + Button({ prefs.currentLawniconsVersion.set(0) }) { Text("Reset version code") } + + CopyableList(iconRequestList, context) + CopyableList(newIconInfoList, context) + } +} + +@Composable +private fun CopyableList(string: String, context: Context) { + Card { + Column( + modifier = Modifier + .padding(16.dp), + ) { + Text( + text = string, + fontFamily = FontFamily.Monospace, + modifier = Modifier + .horizontalScroll(rememberScrollState()), + ) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + ) { + TextButton( + onClick = { + copyTextToClipboard(context, string) + }, + ) { + Text(stringResource(R.string.copy_to_clipboard)) + } + } + } + } +} + +@Composable +private fun SwitchPref( + pref: BasePreferenceManager.BoolPref, + modifier: Modifier = Modifier, +) { + SimpleListRow( + pref.key, + endIcon = { + Switch( + checked = pref.asState().value, + onCheckedChange = { pref.set(it) }, + ) + }, + modifier = modifier, + ) +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt index 28e7cb023ae..d355b29cebf 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/HomeBottomBar.kt @@ -58,9 +58,10 @@ fun HomeBottomBar( ) } } + IconRequestIconButton( - iconRequestModel = iconRequestModel, snackbarHostState = snackbarHostState, + iconRequestModel = iconRequestModel, ) SimpleTooltipBox( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 8e0dd7864be..1962770c55d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -7,6 +7,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -53,6 +54,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconInfo +import app.lawnchair.lawnicons.repository.preferenceManager import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons import app.lawnchair.lawnicons.ui.util.SampleData @@ -222,10 +224,11 @@ private fun ScrollbarIndicator( } } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable fun AppBarListItem(modifier: Modifier = Modifier) { val context = LocalContext.current + val prefs = preferenceManager(context) CenterAlignedTopAppBar( modifier = modifier, title = { @@ -236,7 +239,14 @@ fun AppBarListItem(modifier: Modifier = Modifier) { Image( bitmap = context.appIcon().asImageBitmap(), contentDescription = stringResource(id = R.string.app_name), - modifier = Modifier.size(36.dp), + modifier = Modifier + .size(36.dp) + .combinedClickable( + onClick = {}, + onLongClick = { + prefs.showDebugMenu.toggle() + }, + ), ) } Spacer(modifier = Modifier.width(8.dp)) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 83ce44a0e6d..997f02570d2 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -1,61 +1,45 @@ package app.lawnchair.lawnicons.ui.components.home -import android.content.ClipData -import android.content.ClipboardManager import android.content.Context import android.content.Intent import android.net.Uri -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.foundation.horizontalScroll import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.PressInteraction -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.lazy.grid.LazyGridState -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExtendedFloatingActionButton import androidx.compose.material3.FloatingActionButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.SheetState +import androidx.compose.material3.PlainTooltip import androidx.compose.material3.SnackbarDuration import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarResult import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.material3.TooltipBox +import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberUpdatedState -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalViewConfiguration import androidx.compose.ui.platform.ViewConfiguration import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.model.IconRequest import app.lawnchair.lawnicons.model.IconRequestModel import app.lawnchair.lawnicons.repository.preferenceManager -import app.lawnchair.lawnicons.ui.components.core.Card import app.lawnchair.lawnicons.ui.util.Constants +import app.lawnchair.lawnicons.ui.util.copyTextToClipboard import app.lawnchair.lawnicons.ui.util.isScrollingUp import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay @@ -76,6 +60,7 @@ fun IconRequestFAB( enabled = enabled, iconRequestList = list, snackbarHostState = snackbarHostState, + onLongClick = {}, ) { interactionSource -> ExtendedFloatingActionButton( text = { @@ -96,6 +81,7 @@ fun IconRequestFAB( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun IconRequestIconButton( snackbarHostState: SnackbarHostState, @@ -105,33 +91,52 @@ fun IconRequestIconButton( val list = iconRequestModel?.list ?: emptyList() val enabled = iconRequestModel != null + val tooltipState = rememberTooltipState() + val scope = rememberCoroutineScope() + RequestHandler( enabled = enabled, iconRequestList = list, snackbarHostState = snackbarHostState, + onLongClick = { + scope.launch { + tooltipState.show() + } + }, ) { interactionSource -> - IconButton( - onClick = {}, - enabled = enabled, - interactionSource = if (enabled) interactionSource else null, + TooltipBox( + positionProvider = TooltipDefaults.rememberPlainTooltipPositionProvider(), + tooltip = { + PlainTooltip { + Text(stringResource(R.string.request_icons)) + } + }, + state = tooltipState, modifier = modifier, + enableUserInput = false, ) { - Icon( - painter = painterResource(id = R.drawable.icon_request_app), - contentDescription = stringResource(R.string.request_icons), - modifier = Modifier.requiredSize(24.dp), - ) + IconButton( + onClick = {}, + enabled = enabled, + interactionSource = if (enabled) interactionSource else null, + ) { + Icon( + painter = painterResource(id = R.drawable.icon_request_app), + contentDescription = stringResource(R.string.request_icons), + modifier = Modifier.requiredSize(24.dp), + ) + } } } } -@OptIn(ExperimentalMaterial3Api::class) @Composable fun RequestHandler( enabled: Boolean, iconRequestList: List, snackbarHostState: SnackbarHostState, - content: @Composable ((interactionSource: MutableInteractionSource) -> Unit), + onLongClick: () -> Unit, + content: @Composable (interactionSource: MutableInteractionSource) -> Unit, ) { val prefs = preferenceManager() val showFirstLaunchSnackbar by prefs.showFirstLaunchSnackbar.asState() @@ -141,11 +146,6 @@ fun RequestHandler( val encodedRequestList = buildForm(requestList.replace("\n", "%20")) val directLinkEnabled = encodedRequestList.length < Constants.DIRECT_LINK_MAX_LENGTH - var sheetExpanded by rememberSaveable { mutableStateOf(false) } - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true, - ) - val scope = rememberCoroutineScope() val interactionSource = remember { MutableInteractionSource() } @@ -155,12 +155,11 @@ fun RequestHandler( viewConfiguration = LocalViewConfiguration.current, context = context, coroutineScope = scope, - onExpandSheet = { sheetExpanded = it }, - sheetState = sheetState, + onLongClick = onLongClick, iconRequestList = iconRequestList, directLinkEnabled = directLinkEnabled, - encodedRequestList = encodedRequestList, requestList = requestList, + encodedRequestList = encodedRequestList, snackbarHostState = snackbarHostState, ) @@ -176,18 +175,8 @@ fun RequestHandler( ) } } - - AnimatedVisibility(visible = sheetExpanded) { - ModalBottomSheet( - onDismissRequest = { sheetExpanded = false }, - sheetState = sheetState, - ) { - IconRequestSheet(requestList, context) - } - } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun HandleTouchInteractions( enabled: Boolean, @@ -195,15 +184,14 @@ private fun HandleTouchInteractions( viewConfiguration: ViewConfiguration, context: Context, coroutineScope: CoroutineScope, - onExpandSheet: (Boolean) -> Unit, - sheetState: SheetState, + onLongClick: () -> Unit, iconRequestList: List, directLinkEnabled: Boolean, requestList: String, encodedRequestList: String, snackbarHostState: SnackbarHostState, ) { - val lastestOnExpandSheet by rememberUpdatedState(newValue = onExpandSheet) + val latestOnClick by rememberUpdatedState(newValue = onLongClick) if (enabled) { LaunchedEffect(interactionSource) { @@ -215,10 +203,7 @@ private fun HandleTouchInteractions( isLongClick = false delay(viewConfiguration.longPressTimeoutMillis) isLongClick = true - coroutineScope.launch { - lastestOnExpandSheet(true) - sheetState.show() - } + latestOnClick() } is PressInteraction.Release -> { @@ -244,52 +229,9 @@ private fun HandleTouchInteractions( } } -@Composable -private fun IconRequestSheet(list: String, context: Context) { - Column( - modifier = Modifier - .padding(16.dp) - .fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Card { - Column( - modifier = Modifier - .verticalScroll(rememberScrollState()) - .padding(16.dp), - ) { - Text( - text = list, - fontFamily = FontFamily.Monospace, - modifier = Modifier - .horizontalScroll(rememberScrollState()), - ) - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center, - ) { - TextButton( - onClick = { - copyTextToClipboard(context, list) - }, - ) { - Text(stringResource(R.string.copy_to_clipboard)) - } - } - } - } - } -} - private fun formatIconRequestList(iconRequestList: List) = iconRequestList.joinToString("\n") { "${it.label}\n${it.componentName}" } -private fun copyTextToClipboard(context: Context, text: String) { - val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - val clip = ClipData.newPlainText(context.getString(R.string.copied_text), text) - clipboard.setPrimaryClip(clip) -} - private fun handleRequestClick( iconRequestList: List, context: Context, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 52ada0381f2..447e22ae4f7 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -25,7 +25,9 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.composable import app.lawnchair.lawnicons.model.IconInfo +import app.lawnchair.lawnicons.repository.preferenceManager import app.lawnchair.lawnicons.ui.components.home.AppBarListItem +import app.lawnchair.lawnicons.ui.components.home.DebugMenu import app.lawnchair.lawnicons.ui.components.home.HomeBottomBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBar import app.lawnchair.lawnicons.ui.components.home.HomeTopBarUiState @@ -127,8 +129,8 @@ private fun Home( if (isExpandedScreen) { IconRequestFAB( iconRequestModel = iconRequestModel, - snackbarHostState = snackbarHostState, lazyGridState = lazyGridState, + snackbarHostState = snackbarHostState, ) } }, @@ -172,6 +174,14 @@ private fun Home( focusRequester.requestFocus() } } + val prefs = preferenceManager(context) + if (prefs.showDebugMenu.asState().value) { + DebugMenu( + iconInfoModel, + iconRequestModel, + newIconsInfoModel, + ) + } } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Clipboard.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Clipboard.kt new file mode 100644 index 00000000000..05c98b9ac5c --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Clipboard.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.ui.util + +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import app.lawnchair.lawnicons.R + +fun copyTextToClipboard(context: Context, text: String) { + val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager + val clip = ClipData.newPlainText(context.getString(R.string.copied_text), text) + clipboard.setPrimaryClip(clip) +} From f8853ac1573631d43a1d62e205072046f8531fd5 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Mon, 9 Sep 2024 23:09:17 +0800 Subject: [PATCH 115/144] Fix workflow --- .github/workflows/build_debug_apk.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_debug_apk.yml b/.github/workflows/build_debug_apk.yml index 23f1856941b..2cb49104ead 100644 --- a/.github/workflows/build_debug_apk.yml +++ b/.github/workflows/build_debug_apk.yml @@ -16,6 +16,8 @@ jobs: uses: actions/checkout@v4 with: submodules: true + - name: Fetch main branch + run: git fetch origin main:main - uses: actions/setup-java@v4 with: distribution: 'zulu' From 2dbb2fcabcba838aa0a0594bd37a120e8d5cd657 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 08:30:35 +0800 Subject: [PATCH 116/144] Update dependency gradle to v8.10.1 (#2317) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2b189974c29..8e876e1c557 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=5b9c5eb3f9fc2c94abaea57d90bd78747ca117ddbbf96c859d3741181a12bf2a -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip +distributionSha256Sum=1541fa36599e12857140465f3c91a97409b4512501c26f9631fb113e392c5bd1 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From 15ef5c3ee348a08b820c355cdb223089c97c2f0a Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 10 Sep 2024 18:56:41 +0800 Subject: [PATCH 117/144] Update app icon --- app/src/main/ic_launcher-playstore.png | Bin 197681 -> 23303 bytes .../drawable-v24/ic_launcher_foreground.xml | 30 --- .../res/drawable/ic_launcher_background.xml | 197 +++--------------- .../res/drawable/ic_launcher_foreground.xml | 15 ++ .../res/drawable/ic_launcher_monochrome.xml | 27 +-- .../res/mipmap-anydpi-v26/ic_launcher.xml | 7 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 7 +- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 5562 -> 3057 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 7567 -> 5058 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 3324 -> 2266 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 4351 -> 3193 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 8685 -> 4158 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 11813 -> 7191 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 16344 -> 6443 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 22027 -> 11279 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 26957 -> 8455 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 35179 -> 15862 bytes 17 files changed, 61 insertions(+), 222 deletions(-) delete mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_foreground.xml diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index a0c46279ed9d90e7668d9621b280f121213f07b1..a41561910c88a7af95c02c1c56d1107a6f8fd499 100644 GIT binary patch literal 23303 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

3iAbTs|8G!oW|Vjw_chYL zqWX&aUS@{9xu>I40$8&IVR%;*2=si1Pht`3mA+bBUquhyNVWD^6y@UvPZP)f>;w3h zpz=>ltABPPMXfJ>H0IqfgWW-|UbXEwQ0zxgY{~UQ=`}2d1L!5631#gxuDVx8+|3;Z z?V0RKax>!x0Gob@ptF9op z`sc!ie*_1zea}+wEVlAm8Rjb^%i-4MlQ13agyb?VAU^3evuB5Z_SE;H= z(F8E08!Bnt$vO?2^9uGoEh+2MJ@`l=2CPh)84-1Dl z!-ka;q2RJA1qEB}3ef+Q_uz?YC5aH0Xg%tQ;kPO)QC7&7a60`*M^bYhY0UTa+@Bws zZ5oNl5QF7)WQH;sV~Mz=^D;ukiF_;yF6}XX2M#Jb!;cG|4>uLD2Hw)rHJ

S}<+| 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

uKZ-v%xd4w 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%0D?#mzvS=iG~V+FI}nh@Prdoj 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 diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d11462..00000000000 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 07d5da9cbf1..8b5801641b9 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,170 +1,39 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 00000000000..68858dffd32 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml index 613857327cc..09b1121b01f 100644 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -1,23 +1,10 @@ + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> - - + android:pathData="M25.52,25.53a15.28,15.28 0,0 1,21.72 0c6,6.04 6,15.83 0,21.87a15.28,15.28 0,0 1,-21.72 0c-6,-6.04 -6,-15.83 0,-21.87ZM42.35,30.46a8.4,8.4 0,0 0,-11.93 0c-3.3,3.32 -3.3,8.7 0,12.01a8.4,8.4 0,0 0,11.93 0c3.3,-3.32 3.3,-8.7 0,-12.01ZM65.8,28.84c-0.96,0 -1.73,0.78 -1.73,1.74v11.76c0,0.96 0.77,1.74 1.73,1.74h11.68c0.95,0 1.73,-0.78 1.73,-1.74L79.21,30.58c0,-0.96 -0.77,-1.74 -1.73,-1.74L65.8,28.84ZM57.15,30.58c0,-4.81 3.87,-8.71 8.65,-8.71h11.68c4.78,0 8.65,3.9 8.65,8.71v11.76c0,4.81 -3.87,8.71 -8.65,8.71L65.8,51.06c-4.78,0 -8.65,-3.9 -8.65,-8.71L57.15,30.58ZM37.89,64.13a0.86,0.86 0,0 0,-1.5 0l-8.34,14.54a0.87,0.87 0,0 0,0.75 1.31h16.67a0.87,0.87 0,0 0,0.75 -1.31l-8.34,-14.54ZM30.39,60.64c3,-5.23 10.49,-5.23 13.49,0l8.34,14.54c3,5.23 -0.75,11.76 -6.74,11.76L28.8,86.94c-5.99,0 -9.74,-6.53 -6.74,-11.76l8.34,-14.54ZM63.57,60.67c1.64,-2.75 4.64,-4.6 8.07,-4.6 3.43,0 6.43,1.85 8.07,4.6 0.62,1.04 1.68,2.11 2.72,2.74A9.48,9.48 0,0 1,87 71.54a9.48,9.48 0,0 1,-4.57 8.13c-1.03,0.63 -2.1,1.7 -2.72,2.74 -1.64,2.75 -4.64,4.6 -8.07,4.6 -3.43,0 -6.43,-1.85 -8.07,-4.6 -0.62,-1.04 -1.68,-2.11 -2.72,-2.74a9.49,9.49 0,0 1,-4.57 -8.13,9.48 9.48,0 0,1 4.57,-8.13c1.03,-0.63 2.1,-1.7 2.72,-2.74ZM69.5,64.26c-1.21,2.02 -3.08,3.91 -5.09,5.12a2.51,2.51 0,0 0,-1.21 2.15c0,0.91 0.48,1.71 1.21,2.15 2.01,1.21 3.88,3.1 5.09,5.12a2.48,2.48 0,0 0,4.27 0c1.21,-2.02 3.08,-3.91 5.09,-5.12a2.51,2.51 0,0 0,1.21 -2.15c0,-0.91 -0.48,-1.71 -1.21,-2.15 -2.01,-1.21 -3.88,-3.1 -5.09,-5.13a2.48,2.48 0,0 0,-4.27 0Z" + android:fillColor="#000" + android:fillType="evenOdd"/> diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 5c65feb13a4..bbd3e021239 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,6 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 9f66525319f..bbd3e021239 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,6 +1,5 @@ - - - - + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 2b56a86cecc5fb718192957ac9976d939ad49cb9..215c29420c3b89a34fe23cef48c28fa0e2d800b9 100644 GIT binary patch delta 3052 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 literal 7567 zcmV;A9dP1_P)^ETe+dAwBQYf4%6uUeF+uHH6#1ARAY14T!@POpMZk?ZMWPzgFL z>+A#Ob@ma7we|t5V;fb1kHIF(T3QmdmZC#(4fQqu)@=ORizG$W4Q5x+ZPvB)taTl| z6Sa<7qt@CfQbKfMQR+1^>SZT(3G-TNwXC7HO}J(luI;=r?&r^_hyle4ZTE2R7hS>u#qT`LM!hY-ktBu^@kAwDoch_Y;!F_nv=xg4^} zMMjckf-F-7{Ry(HzS{J)70wtXYa%O1|NXVJO%j8yz#>=*YCA7SRk&awo>ci>trC92$= zNDm|lWmiX%!?lWt)eyB>5V!^uQAWez<@BPjw*EgU$_*bVqZ^~w*xzF@R+dmE*xZEp z5aUaZBuJ64S{AX|5xkomPjHM$O)2D*2sTO5YCE$FZM{+5=C8acH$v9j6J0?y(dhry z)q*V=V}qv%CuQzL`alw+f`j+9&5crr6om+x@KRBfMDco=y(YY9WSY9|Us+KGzUWfh zoak~Ijz*uimI^kjhX5~DyNL9GrwEBsZ&-*L(<)gG*D?`miXjPgc!@Y1p4&fH9mAJi zoSCy)cnoroH6lf$-?JQE_LAZu#wn;&C5M+e_^XI<%2_3&7UV%hi3*leEC>)p#v*}? zIo&@|$MU5W<$~WYu{{)BrjoN-mUAUay-~zC1$nZ{8>bu@Q;Bcf1eLHLSyHhbl58|H zt8KnIrhm97DQPVoxhHxx4OkT8yNfc%!H32P(W~q=fTCAH4hMS~0aqfj#2Zf$62;!I5H+SESqj%O z5k8RQ6e>VcAtdDv)J|J^;$}yX|G+#+5o9e9-eWn|A`Hj~R1)M#iH~JfEeR?1s6EB_ z5`+NFj4wfjml0Gb<0eO@K(KK=E3@Kqh3FDl4jQi@1wU3;hz~ro zL@h;)BuEX5@qtr}rxZ6qAYZf@^F}BnsqPhZtYa?9hdpcFkj`3SA7mlXC88*aDIOcq z$ebrOi4^k(kv4oL(#{hiZ8>ScXC*_WxvqNI4&gwB~?F zvAac@k9n2}K}UEXiI6cCh<4|CKGyR^F}#2%EURyD`jVq}sAC>eQ4WqS7PdxX^p8UJ zID;>`I&%i6n|H1VN;hUXga47U{?QwT6cfOMyFPh6SO1>J5?3wK}fB z*BZsOcb}FeA@B$lEW(K_Mj}rpSFjm#1!Pgn4umRw)9InXcTv(UGJh!2T1*_U-BZAo z;2;jxx=XnnP2D0beb=`bH$h+lKJXrI^u7km+J4M&%w+|6$^k~M^T{5%a**zO?bIA~ z>{l$xz#Nrtd*6x?--?kx3IU9Txp=c3f*hOtgp~lg2W-^ZJxZN@Hm{7TL6$wYMHZ6p zjhV?4XwAn04UM{AS6S{J6zNxQ$yt==KrO?SHSQpT1S9H@q~;I(#xh_lX=ceC47C;_ zd(dcLm+LDM4M8RQ+=K5M5@_e=z4Yr1ZS;6iGyS}*g^J(5M9r5*U4ep6t3;YzERY33 zs4+7L;L!?!dInwBWzip>ACS&fw(Y+t(nBQzMc{bGQ-(y2J7GDZXv`%F&FH6TFCU3i zJMdYY-79x^jWr+HQ-JJIi^%sDBW(jutQV-N-CfSotsNAe+(Mx#ofMXG33V5RCbiPS z(pEa#Fzh_mhOByJryymDQ%#uL!sz2rTAZ!P$Mdi|s(> zM5MG!Vmt{=>Y!IQce-W3j-vua=6VPMFa2JiO9QUs8oNemeoiZeB(~G5TRNl%q3k<_ zG3v)6W0LH;z709t<+i2$zS0Jt3HhOY3OX-1}K8nZ~AQRx) zh;?IXFNG#wq7!wlZg#RkpodqDk~v$JgzKj75olo8l|9_0tZ8i!#F8#al73O%PA#f2 zjR)*U%LR8CS>71kz+jE~{^iwwfCC?2`pZA2nflTv6Oj$gQdZ=md*!eIPazH>m1R6F zOV%j;?o(GIJNpEBZbLssr1eA05ScSa$ecAI)e%_d?cpiCRNG;5o^zzuM)M1C%t{-X zFec2!*mJ(cC1+q*px4kXXC`#ftfU?Y?t!Fk3PX2&bAPY%IA-fX0c{mrLNYz@5EPb) zZk9zfBfhOw`)J-|wG*i*#!QLL(NQ_*UO9MkDRNXqs%j?)$b!IA-y3wk-g&?*-#d)$ zkOO&^EF8nfp*ClZQbhU?J+;RDEwtwZj)y!G_M5T<%KN~5VBUSSpDZaIlAN%VehNz+ zKv(UTB+boiqoyv`1M2D*>G?NpkRf=>kuj>t;F|2SlKbg`t-$)KRW0)3}^|`&iTe<~Wv|)szSPU}4f@39c{G;ef`_8$t zhvzi$J9^O_kzE-hw4h{^PS(2w4PxwhqPU%AB_LxEgfVp($BsbK5QOz%dlwb#zC^>L zu5)%AhMWvR3O?KeNr+5XI%*J>Aqt_XBQ$OCu{fx3{~@HDLD!m6dpAizuY@3}z8c)U zASiv9tQo!Z&LP);$((P&+wH#vNv!wBP258ai!|1-F^h+G`OFV#Q*ALM%Yx^m2dpC9Uxujn}_vD8Y zj^I6EAqo&=XGvjc0t5+k-^*vWvJ2NZF%6lNCOUDGBd>GKg2K}5bpLBL2jJpcE-%Vpq_bXU$r!o7ftxc0(ILPG=(83X zX*t6oC_H6=!q5d?c)g9PT86zu_=4pWp=%i9F<(mJfqR%Dkme8K^U;T=U6a7S74B-Q zKEODYJdAE=vl|sTK9J<3iZm-l5W~_iP%mw&^qX|ocxUn`lcM0KHr{H<5L#scBG+mx z8NP``KR2gi;7u7MV`4AOis_)A7Pip-GXv;GzO#VGoH}%?mmo7Nrj^3tF(pVIfFRC9 zJoTgjdMvMlj@JyieXbh|BapN8<6ioHDo;ouC}k95mUu&!r7eH$ zp-;~Z(lN|o4qY6iU5EQ<#pZU3PH3c=%Q5iAVc<>d!@0B;;i zTC%Z~lD4%|`i>6JN$EQsr13JgrEc$_xGin;!rB&Ekl8>X%UWn=Y#)Ut3?YjkCZhq3sO(QQ<5*x&&{dGqU0em zCiGEQTn{n{6FCS7S=vmNxF(vN)I?G7O*Ct16U|uGhK6*~tXRm2#|%4h&><&yn%# z2cbzAtWzXGgAjDDm!P|T`u1JOph1?xg3OAbv5?AwFc#ryMd0Zh;~kPhAs`f@JYji~ zoH)#?6EMS0;>@u@kWH$?Ik5Nv9D~Uqj-9#U5;q*eRY=<|(F`olSjHl|q-B=F*)uC{ z5E;bX6@xU(@qtQ?Lr^kzF$nr$&V62j?tJo11A^?eAO+2-=whiH_}DSCBm`(mf+S=> zI06id>!q+*MU(=sV|zRXWpn|SV}e){p0X(!pQD&Wbc+Osq)-kvhQ~I@T7j_&*PD%x zFmo`iu%>XP_CN|)&inZ|WDd)T$N34!o(M4z?K940~kY3i&reinj=98!)A!8_LVdab^Vh5ava{!8|4Hol(l&JwmyE7zRU>yKBf% zOY0+)_1-8g**r=Q=izlM%Q4}pG7(8OSrRe;fg0n7Xl~XZ<~qal$73UOxN4M6;G@ZB z7e{H^rz5m@!w^}JxuLNj4&x5a3riUFmXj#sDJKDMF&30ac+I!9-ERC(og~QZH9u+6 zcvIrg1u6JsL39g#jQr0c5g$O^zfrszbsZwTx&?A&ITGj=OhlrMqA)Hk+d4}1or2r9 zh-!G!`N?^Ko~b~_uoxwC6d@j{%`Zk8)WGXOD|0blb8I1?pCPA9Oi*-c{Wu(kq)GCP9|LwFhCB zAv6v%>3BQcyZHQPa4|vU#raX=JH}5D&@UimJdl+2H zS}3HvnL<#{T-8QP-x>6h!y+mNJLqs<1GSFyc}++gAo~Z|Dk<^qg!v#e4#Wz=tT=(D zK6m){?BemqRbP3?AI!cL^5WSTOOoA7kU7z}97#|j?-%Il)i&x;1+%l`Bt3Fw6D>Hi z(I>IB@4E%Itmk72Xj@1A?d!?EV?Ev5xtXd)yPf+-1sm<@I!h0o#xX}S$^U331s%Un&DlH(Jd+Dh^Rjb2mljlSaSJN88-iNaK+;+YXkSY&_UuJ= zxMt#eI?qz*=~D8?x&G(!X)^FXmq!6#E(<;;o| zAPTSe*Lq0vaOwYI7gnq4>khfET|4>yC$*-Sp(b+z2QG?SUkwvp(=%5!&|@E*rruH4 z*B$xo5OltP0?+4D&;`^ASZ5a0ZgmqBcWFNbG?zhA1!-H?($2vP&VAgC9yqg(0wCBQ z=Q5LJSP~1*Y}iX9g5%RX59YB48fkh-qx3clgM`b0%)!(^5NE}Z{k|9LTE-jZ-^nf@ z#r;nnEvCTgB3jV!mb;+NeH748LIF*sG^2R~ z9U5|tD@XbpAqUx01vxcEYRW!G0i@Tt%&q!MfG1wP`pq=nK0$b3u z%|p;$3am$#A*iVh<+OjG*14~3v>&n|q83OJS4sFY^^jCkNKZEHq)WCz=Q(*@pW@hJ z$1yETDNSaYR+H|?PMZ4WX$naiu+LhK`OgZ>e-<}%+;qo-{EJoNytfV<7N**pOO|&nWboOT#y1w!tp*TAqyVy67&%T)fPA;)#TI9YPLzQ zc4hym;WnDz_7(*}iX^AiAxV!6{&nXbxAE_6e+xxal~X`%KE|~oNJY17W>FqA72EwA z(YB8^(Jepx^tI^bR3d0mEATd@mS`*{ZCwF9)Uc7- zM_u1ZA0BF=!tT$hpcnKVqTTZ73 z+$U^fg)`-`y3G)jM;ZhbRFjJUSJDs9tf317ZEnYoh&F1s4N$YKk1h#A&Tge#=Pz9s z=&qBQ6mW4R1YyqAfN4cz0i<})SYQumhNLs;G~wm>PjSqCWzYEW+)KRM@oFEBLYSd3QDa2i{VenjB0Save1S)SODAXU@Dy zwS%2r=lEh@=Xr`cj*K~*j<;48-k3QUw=hp?WJ%oJ6!MTgc{cyL9GbM_xBSyoe>vtc zmbV_~v1t7GM?%cnvzfg*7}quyh+MNUsRnv1>+yticv8B`m1H=cLix2H(&@e?>KN|B z#BmS|`CyPPjSf)NKs#-1K1kumIb$**CfgwhfoX6(&AAK;I+08vhcjslj%yscIQ{br-Oh_T9It$}j4hDVBB9_FpgMj)RF`zk*Zu>m0_qsV#qd8W; z1nZT@9?zmnkc{4b>-t3ry6Tk>k}v3C-V5ANhk$f=VmdszJB}n%#G#e+;E_U_cN}lG z<0UljLkXi3~Fz!TpaUP|&F)3ObvLi73R@u%K)RLKZbZRD+`q ztj}gyg8$hxx;g)ebdJ&QrSR`~#y^&Fjh{*S@rNPsPfPabYO^6E$Hqe3z!TD=A^Iu^ zI-gFuFH%W&GMRM86G^LZf=QCW@-Z1+XE|uBwlWi<@gVA15d%NRSdP*6yyvRLk#;wa3%Kb%&1bQd20Q^nLpCJk5QAkh;Kq71M30o#;mPUn1a$~V zcN&sTF-fZBWK8{&obYz-SqQq2M!IU8i=cG%ED0bOZ8fs$VmfINwB`#4f&>lD(?AHr zVl<}`9orQ-mFeiJ5R3CQ^~j=nmc%vWG-TR>8nWp2k6x}CH|fR@j?M46kTDL-mnr_w zgf7o+}H^V!c);BNIinppGze@0@s~|lrxus_npHr7a+6> znTMeCb+|@7O9EKd;+iZ@TZs%i&zT0HXCUJXCecyzI<{*rAj@!^rW%53aSqPcs0gad z6f_N)H2IUIeb+xSeF4Yh=ZNheFB9j5O+XcR%hGwzXip}Hh6d>gLsAyx$RHR4f;6Ck z20TUmMTokX>V-~5T1PBGPXpjMo z2xibQ1A;N2p%T?D^s3rP4a0Ky8mQ}764wwSBdymuj@4DCI;cu(gz) zXuPys>!=M<4W#W3BwRAs14LiVJJ zhT0S{7!6}Mc+XnFbKM;TF2ORCWgpbIFS8(NTTQaGtgT5Fb+yT&wla|>@A+-jO$+XM zgxf5){VS8Blxru1Pvxhe^_y`0tbpymd|!VmmL-8?o1r?z9*jl?qp^-!Syo6v1|@q_ z>%ENw*4HGdmL2PERJ)dSRY`VzZK6$&YiUoepxZY;^MT)l?}Tz&T{$3lX7JrV1P?)4SWS0zGB0>nVl zMa+vn{;%%a(jU%1+xU-p1LU@T>0{2-$~Ar={@43yC-E;m-Z{ZCWsd(FPrs)>@)}8^ zYNe+u7^)M*DF}iIR@GkAcy3ET@K;7(6))jhNejW%@nUdQyd5>6hAamx zV+xSA%lq7FdD&1IYd2KIiTbKIA-E=9G}J)Ug;>(!UX!=~eBZ=p!k^_fa9iXy{cWGG zzQW?jCjAZkzp)s=z2ALe)=&M{Klzq+-wQ2{|CI|?25eloJ?Py<2Xr6&>b!3M;wJs4FLvq=zSJXe;KfeeUl%v=K0YSk zjfLB9&sngN&*f|QIkJVXsgdr1dr9~F7cAHMP4WBojngo}baX%d-M?UPH@IiqxN-M` zSse5YAwdsKFlpy8yv*CMZzdnZ$I9pMxq*Bw>6*BM|oe+1ul ztKTg*-0sKU1v|v?Ag`6-W!^TKkKtqa94S-y8vjO8u2iHScl%lKrU~&I=QnT4xBaZT l>m+!YxA8uQjIV9L{lBnmlHsd_mbm}`002ovPDHLkV1g6RLl^)6 diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 4f6519bc3e1609e769b636c86eccfbece311e004..9339572a47c6520de9dabf60d1fbce20663f1c6e 100644 GIT binary patch delta 2255 zcmV;=2r&2j8QKw$BYy~?NklI6 zW^B{6(>kW(q)FPzq@7OkM~665otO#=2rOT_AfSv9F}2hvDu^*gMU!fb#ZN3?6cH6z zmi=PoYuUY=KKI^T_I>vSVUw8kkKCDO4twu8?|FWE?|lbl%zv0K$3r|;?V+*pi8L;h z;vNEhjXVA>D9)|KZ^zbIcY^87L3aB79f4~%1 zz^tJZ_n<3a1>BR;r-1p_KFh0KL;O|CQYflwMUs1(1UsFrYXW z#fYJl^Zv#mT`rM1KsWqz5m+3&8;7pg0@Fh$Bgd zMnB_cmNy+@{j*4V06=;$09gRY=C3XkBMzsha7MFFFgkFV(aGzGml&lU1&mRfyA;Ra z?*|$E^Bkjn7yT-$VYK1!&^3M!07(0s0aou|)L>%7m{#X*F$<&66J<-7~AS0Ud# zS5lR>m-GOD&A|ZZ0g#DeJ&F+nm2=$RH1!C+IeuOR|K- z?A&srU%xJ7bgx&gm;G1UOL_o6YOnx$6lb6qQGY2N9$IlpHavX;runz5SbrM3bHTe4 z2QSGvA3(E}(Qk{?`OA^-?2+sH&a2n_9)bnP06+$c(@~75R6MrzM1yQtdPcqG)A4$_ z{-5jevkIV4ox40Y03hI5(gOfeJ|_Sjbnv2V`0-5%q+DNtZ}iF?xqje+7r=Yuh6KoY z5Ptya07yr18j2AEmGPcz$j`dr7^7tz0`pJ9%=QoE`R{i#+E^*)eE@B^1AoLF_=Ul* zl>qAU-GPs_y`%>KBnJTyo94F1rZL=n{8oql5FxQ`fw}0ez$g03-q6_oD?!20$u`Q&5aJoR(sX^>|fQ zgx=4dUWltXepFqcETxgSUFeXWuY$@Rb*zXt#$J^+9(LZ1#`697_BoQz_`k$?1h z8KZ60jIyvB&*W&=m0E>=9=>yqQ7zt7m3T|NSgg%aN_q$uU?TvMQM?Joi1$L7;<$oeBZ8}Dm>`swu_w>?xea&R@bcxTmE%+6qNc()h z2LQYo3_v0PHljEQ#fUyF%Iu<;k~{Q7t~1n!&*BT{#PK?ETRfll@%5A*0DrJP7=R4` zNJ4RFI;{8k%R@CFY|5w;m8??4Eqi|0vQ@fRGd)T|ISTy{fm7qByj&*R{QD{_&3}Mt^5?0P_;6qUWAHYM<5i7R~I~ z%4S-&QJ`MzJTiC*6YrfyqvFA}g|^+)p?~zQb2JCW_C=` z{T7-FGl4m4ou|Y)Ki_fKop{^7sTDiL=lYq4Qo248&q;7ri#y@lv0vKDHO~?rEJYO2 zoadNW__743uGRvKp?^d#KtgncDc>GpE})3^Elfm(W}COt!QM|q({rv?GIrHyw6nX` zYt~J_vF{gkI_qw#K|Y`7_oNKR#^i-+?6=bj+g_Me_Zsxjfp{xt5WweEJyZZjdqjIa zMVRuKhyhCIJU)1Y?x(9Rv#L&Kc^hvi`6~5E+!gCyO^-ow4}WIFrmWEeOgH7)r?(qv zy2-#q4A3k*_;trIdZ)XN4)H~>Ns%!W^7V$73GcpE4sVZoJq|PE;@I&&j$AO|@Lvy3 zy0XqTxqf};q`Eg8Jbsb#^_*0@&NiX)FBRisX7b}R_Wl5T$b?6sIpcKE%N|+%q4{{e$i{*NlqiP-=E002ovPDHLkV1hy(aI^pb delta 3321 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 DamiSw diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png index b58f8b2ed674ea89f7c313d5d3969437e98e4808..a1a963963eb4f2f9dc1cc2b5e5eea1af5fd7b26e 100644 GIT binary patch delta 3189 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 bdztco8L7y?)!Nd_00000NkvXXu0mjfh>|zx literal 4351 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 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index dc55538d344a30f5e649040f0b3394c1ec6ff985..0c68fcff9ad2d8feb66c69c08b37b678ad8ff8ac 100644 GIT binary patch literal 4158 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 IM6N<$f{tbU`2YX_ literal 8685 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 literal 11813 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 Tw7JMG00000NkvXXu0mjf5_ZO6 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 3c105a690cec3a6aafc2681cedbd23b6529a284f..57897b26990e240ab94e9243a9337596d20d993d 100644 GIT binary patch literal 6443 zcmaKRcQjmI)OKVTj8P)$5F(=22}7c1v>=%1y+$X9-c9s6!cUthqt_^5L>E0o?|2oQ2;9wQ8z;Eu znToD=zM00vlqYncRn$jr_Q^KU!DUko=1;tsg;OM6v{Is^oxT`dsWN5j$+&LoIDF!u z%TXN-J^3lJNz-^|2&1}s-*?9_OuL+OOi2V)oH_a-jU;)8HBGhOtf*p)h`FpE_4xlL~TBLPE8c9pw? zA8hruVK=|d(|(SM*{QeH#ZM2(__WoYrq$3mJ>x>YuDl@RxJf8yd~+kKklo_@J4MCk zQ?XfQ1W>_w?E+UW*}t<5Ix;9k-c70bRumO6`-;mUrp|r;D~w5U@rj{eE>u! z_BEn{A&QVWN3>KS(z-@mqe zCz|w&ItiHE7%rOB!*SIu7b83-%3u!xi;~Bv+>IP_5Jo%#)3A|0ZXzs1?vM~uj_7Po zYtlgKRP)?_)1p5a=K08Audj=2K;)|T)*w$N(y5wJFGXxqoBfCA!r#??jnq!LxqP`RaKdqrs8_xUT=NUr72jM^d6KGf(t0ClHOpw+l{R%M6#am{<%U7gL~8%Cb6-%r=7 zGX#Q%=q|m8oeN`_gqi%t6v!v!GzC0=ELC;ZjVCd#Vws^pr-MmFM} zHHMAhza;=de%t{cKkSjtgHH%q7sLwz7?v%Wy5S52} zD$p9^GsCU3UT7iMFLv$W9A$2hKh{0BK-u-gL#Uzqw1oS(gS+|1OYO}Mxh}xT{)H4I z$De_7D+-9_^RHRdP!0Ca^|nqoLDwtF;EVPhKbMG%xQer=e`3po$8;F%d8s`_PPrtj z#V5#U{jcvwTpT6#Vki?XEy{a7f@o9Yg68T1I~Xbs_hAjIdaT_w1G%R0hOtCXqP=>o zh0iUCMHcg=t>P=fH6s3Dx~JD7&qh2%FKhhFE?&e}Bm`5PwqZf3&kSZ7NBeQnwL>kr zu{fuLnEcHepn^5c{$D9R6175v3fos_r`wt38FHLtKEUP_eh8+ zr~`6k;&A--Fwo(lc)dAT^e!+q3~6PFF<{`P!?Qi40O>8yP^{nt@P;Zf&zh@Na&LkQ zxg`|ExjQ}-+$OKmrO$$Veb`3}x38x7}$67J3P06*2h(=eCO~?UN zng=VsF^71iImaHI@z+TYb3Nf)8>+0*FXu=Mqw=yzH&!OBA2IKxiL1Nw=HQ{8>ykB#bUAZXF+jtMW5+1M34JzHaz6l ze)C-Kk#lmZZk~vrRaTA%5lC7_eyFp(`iRIXt51=?VzK6X)9M;+Nta|!oFVrU> z?0&Bk1S-7Tz&COFlk^FQ*54{EBTVvu5}+Q5w6ef3FmMB7{4)BroO_Gw_QhsttFrZW z_3cSM^so4152u*>6{{szW_esIzwB7!v*DOH5Qqi?+9pH6JyP-O&cn}*JIh&*FTP-V zTOWXyz6sHhSFOdrKg!;x5~96%d)ratM}nL0T3Oh`bV8!HqR=ZRDB6XilwEqRO(Hji z;4&B7QM#X1$BE5>Xhd;{<>g^sEbpPw3DO6B1+wX#g?&rwJoz3If@cXt69UxVAvxKg zLX(s}o3gSxn+4Jh7o~+)v&O+@+l?#hxwMk#JOppU5&Qg8U{KRt9Mm=wpT~8%x5yT~ zwp9n|A~>s+-EU&xl!sc5V;x+ZlBB>`hZW$bD8;~FqPp(5ee?Yiq*z&1HZa30O4s}MPVgsZ zw|4ROz$X}4(3W^jTW-wKF#Qj{`rQn8oX;Z2!7Iv|YK@eo51TBu$RhR!@Z81jE2W^2 z-n`k@;8y*-jsr=-Fke@E<%x|%=38L68Mr|)=h1H9uY7T|5@&UXqZ4&*C2yS<*8|S? z#5cQ5uK<2mNoJQqmNi^0b7CUoE5wn&Aiw1HSHcKU@Ub319KkRoA~XCqLa zqWv%{X4%X#pzC8t6}zvJ>e9RU6xIXA<1L;-q~nTYPKZdPS;oQ&Bd=fG9I8SJDxb&9 z_2YLLd9Z+pd%|1^*L&dIuo7O+p3eR0GIF||^K+|^bdXS`JPK2RWL1=I^|*6-2D1`gO4Qn@OM>?w1s{9_Qe2NA$=kb z&bQ9z1dgs2RLW9j&Bzf0)$sOX8Xa?;Q7o#h$c^;D6C4P)UDlNd^=^Y-ONla_FUxgX zU|ulTKLU&11EQmQzV}Fz7I~f~i+J`g?3Ydsz^0%<&#}eBJ&h~Icd``2zu6#wy^$l zkKbT3iHcvvp`af5YJ zjKJys`MUDeLMl5=nIYkuE|z9mkyM!mu^YYS%)}35;q5!m-Ut@vD1Hk!2=JBi!-M2% zoc5&8$LG&}No>Dwfx)l9JFdRV1##*lsxzN?F6u9CZsh7|Ee76v*`NK8qo~GHa`8^M z5z@*mrT0lAda|+ZfL$UqJ5xp@%r22$^)rb(`0;}5M1wo;4HE^Tq`>K*bEAbYPW*KB zo~6a^ITb9*g{s##AsrvAix&kOf!hQHTWc8y`Lx1ryOdy7e)nAu@BY1^@jp_ku+I#* zc#ZyP(+zFBn9O2x-1G1PwK`5Vg@hmI$LQSWm&lDCn5gq3e#0r^DBNMH$ zFQV$dO~Y9LK|-Fpbv`_2p%l97B-f6uCe6ChO*#f8ZycgN261MV%^I*mN__$|&;P1l zmYViGa{6%9^o#T+23g@Pe0ddWgR6SS0XK1}@4qA1eik-{lCG%P6_54M0R(BMD&|Fe z3vX;5BN877v zD-261Sz^Xfc<0oL|HghP`LX-RO7MeWP8);r8c6OYPJ z)EkaZ&ZzGBD55rw+aR_PMwiaBPfPHSzdIF!J$_PSw+R95ukY(}+x|2O7_1l;ZMibu zj$cZ;Y4%s@c2111tR)mFmZ47{h_G!uHx3f-r9PfvFGs$-*WG4;nHK|?QUaF#lU)RF z7PrppeNq1Gu6*-oNCw*>!dq2^i9(ESu5Awv8zgIFIE8Sy-&67}_r0#Rdeb@dso+nR zTNO)Ht=1r=7MF>9h$*=l`u86yC_QW*)1?{i`)@`fkJ5FY6an=>JB*?582@8YGN2af zjkWKgQB*bmMtX?yt~=M(+IIKXRdNcl?XRDz!!z;}D|q^~E|0hq{%rF?jGNV??SQmZ z7=B{SKG@lj2Zf97cyF-DBYHILPRj!|b z8;blkO>{UlN+uT)Z`Z%IY#FKE`p=eipE&Oru18HBoy_`>1zTcTGi^g(+ZqwDF7YN*`2ZbL#k;>txB{^w*_K3so=l@O zA)Me!;J!h-()$)7#d<#H3MsWB3Kj~%FHg!wzvT$}9XYJ`u2J|Pz)bJdLk6D@7j=65 z`0@^=`~GCsgYVfGe+Vb`snkF^P&ERn^&Y_sE@WBiD~PDbYCr$`SgP)-#4{=>J;$5M zf4;W>epPf}s!QP&!E-WuK=SWjAebh|4^k=}{&UM*_UrOHAHN_F9hu*BU+_@$h0Hb} zq|=$omL;fzr5guClLFR@GmLS?4>M`_Rtk*$8a73uB%zw0YOZRMQ0#kQXNhU@$_IAL z`pw##lLfEkMZRANP$(Os_satMSFCMX_2V37zz{(b^=^=! zR{Hn(t`n1@fISne>xh@hmN&$-Rb{x%b@@><&j&>s>sBQ?(eB|NSBo*^{c_aecjhYi`nuVgp>ULBLo?a@r&OB#varn>tBDG zDtL_e8gBbcMjYP+;wB*F_#(Icikka1T%?jkMhxGCp+SYOT0T7CCZ&0jXQ+WMlFRr& ze1G4y9U8#9lmVLto&BFzQbZw=BT>M?NIdM5>3^`Hwg%GgD9@+HUQeDzf*3%OD-(X8nZE9yFq8DU8=b8FJS%` zZNApCJMZ>vOwLd^DeYzCKP_8h;EH~7;-J@<;=0?nK5;_>bfMv#-T$khP#&+LlX$sS z)X&=OsnhlYfFihYutx-OmEzMSwLT$7pqhY0?*{y~N=YaFYoo4S;Q!~>%1^PtGuHzg ztfQscs4!Aq-kD9}7g7mX@nhlR~tUw_=d5qgO*A7-WpFmwzLO3IY5@NwdEh_7if!>2#x~E&ftyVW=4_Y{;Z1Kr1a1(oEz6hUHA0VPZ?3@=VOGF3ATao0#kZ zp0g=mje4W?z`}_glS189;u<YNQsVGHIUT)&9qQ%v>%KRFxG?p{VbM`AhctRoP{o`Qx!PX&7y$`=>$5rOgZ>7_a6j;T$ zV55>+^^~kpoq)9%u0fPYyotPjPakVPL9DiLT&$+V;@G@Vl!f_tTS>AY-7K;BZJaKK za_+>)YwWK+A3FF#OJlN^of4MFkW83xmZ^CP88(`+-^8weYp=C#%4lc#uA?3A)pD_2 zv47Xcd{V}D1xx82u-e?e@4wxw+@cmp(08-Iwv_W)0HdNg6A3FH-!6vi8pv0V$QW7o zms8TJHz*i=fWSb|rMborTg^X~ksUu?S#!pqECqDb4VY%4v7a3J7HT8Sa)at^UGsm0 zZG@8jPJB^cS9a*ylJPF7zQ?Bqm;hNSceI*}gjszIe8ck5fpeAKy+dR^d9AB5VxXa~ zp&V%{bjY&MSO=^ma+;WWJsFMtLw01JaDP0$hlsJd;>tcNWxZquOz%X!pO+wsZ}Qi0 zRwmdocR*1=lhkYZ@jqX4v@1_`yC!HGPg19y(fz+q7(B|ZWqC?Au)Zm}+xSC}J1UAA K3RQ56cmD%;w{!pi literal 16344 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 qIrf~{J$|ofqyLwozH(U`icZUZG=k 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 FV1kiD9;N^Q literal 22027 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 L>8VyITZR4~z-+ky literal 26957 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 Rb%69dxcB&Og$5$}{{ZZMZ~6cL diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png index c5ef8799841d60ccdad75ad985d732264205be83..c3b529cc279d84219bf7c68a9697d7324b95f660 100644 GIT binary patch literal 15862 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 CF(tYH literal 35179 zcmZ5nWmHt(+r7ik43bhqDT2}^T>~O0jX}rIAPv$rfP_j4(v2Ygq`PP6ERV180Xuk#LWPl$W{I9JVLJiDrs%IH-8GzSlP`_ zg|@)v%PuWE1(+lukzInx({Y=<7MmNi^KQ%V{Q8`5AE`Qa=*B-VyJckID#Ooa@2qZe zW_>{oAF>gImAhoQiM>_6%fB1D`+uL_s$_X=`0xJ2uNVIa3RU6W42WQpAw$R6pWIK{ zZ-@X(I0G^Q zWCDI1Fi2Kl86ZQNX)hzo z@?}<{czUGAus$H{M0}gsC}Gx3nqVX|Y`xPx!ZcPEM?dd=v#-vy`%vcxpO_1{H$uD6 z<2Ljgch>KPqLBYi@xt8+>WE}HoL(C|j4An&q0cT>>)^}#m*b+jUYuCK!#NwngJIE{{b=|bDepXznj1#b?<`=Lye9VnKNl~Y;N$9+|H2+lINq0R{ zf9Jgw?Y?5UJ7W%<-;u6gyFIA4|AjE)x48++T^Qn(M;KkPcvy)7s=g4p=K7KJQFK-`bkZv>xHlJFsD zzyJ)|0LIw=4yfV-n)ylUQPH<=z%7XV>Lu4j!rYn}8{x=D#7Vw~A?zkN9MAMV3~HgQ z;WC3g$>zelw;GoN`9T%RDrxJ_yt+j`;=e$KY+o_ac*^xB^9XC31be-Qu<7Ll2#bf% zU$?R;+6>`P&hw&(Yfr%luz3&lUPUR%$d!_w`O2vepGp11Ht(lLNesezyOzSmy{0NQ z_4KT(XOnm5>%Q<8+;;P_t?eiLqE*H3X?)2XISmp;2N*XpZTWZqyu*A2PUO3BePN~zIXVv-{6OL!E|c#DJY8o<;8}k zb^Z}6yd%f2uQ76gN*C4XhfY!QIy-#S{CuwZ!XhsCuVrX~4gxKLdeg&d9YARW&18y{ z38r$SbFy*F=?t#O5R^bGUdoapL@n_%LI)AWm^R!C+vHLAFx8F6qU}$yXH%vOEohd; z_$o60SC(x-saB6~-L#|Z{Su#WqP`|6MTM=r*nh<)i-C;%lCR!RN2##J+CKbXyswbC zpVA$%$gFG?>Oyl+GxaP;&@`e-;g*sNKQ1b+?vu%|shXUZoXhqi50Zd|G83!5RO_vO zEgf^9nQZ>T9{0cx6bM*CyWZyXRK)1pKJ=H7Wwc8qvqTVb?tB15f@hT{9%R#sMmSSa zEwM%CU?SL+^dM}nIAHpn=-i*jNq@ZN7hUgeF)as#FK>hgy&P@{H&h{5h)&lK#D?XK+s@_!H&Z3^^FS91i@UePIvpkZ|ylz70$86c9Y0S zi3iZ&DtShFkae$^(z(U$W3I_XuOQKL0$HO2xw;JeXhRJWJ(+*sDCBe+2T5>B0`L|@ zJ`GE?OQXWC57}wVr3%+jDI_h-SM3sJyq*RC5o$N3WaRDS7otG}aBJ3f6w%zqtd1GF z)fqAB%AAu7Va3l0c{%r`Ib{g9Iox*&mxTD-i}}RlKBR6cKif*?`5cs;yQtL|Wy|<= zRzjC54ATdbg6QX9U;6CHkvg_wH;18!ht8qR6c0?N zYliECVj8l7rIz&`BXfj&pN& z9`@*38nsLkuxa%(!cvlkunAt!ODc2W*kL5loIJ?WE^)foW?{VB; zA?7pDB7EhKNt(lS09s+aXCBcpeUjClCRc6_>(|G-6-r)V`nhN7OHsLhc>oj%O<})S z$ivBX38iOxYG1Kcp{UG;+n#j4`ps%fZJx4^L^4kg+$U_no!z{LK%wpjjL4WY-QR=& zunR^U&&Aj|wuTI0wP5$YlnAIK37B92xb1nHY2b);&N-*w-3O!<&+I5c)B04RaU^x8 z#v6DJj_>Q8=mMKK900-KNcHkabvV{&A!GQu=&bzCm5xj-I>s>LoHKN>d(@9(D*?fU zfznfn_i)A;{vz@h=BafGzv{2w{@tdO)&x8Qn%g%9IWc@i1ffvgs3mJ$ zl2YB?9Qh^p{2y^w6fE%V=9UNVMiX&OCZ{au-PcBKdS%db!9G$+=#{P`8aEET4ef>I zh13k3Ctz$k>rljP-jOx4c$yhY z43rAjF(cS;V`Pv^%!4d3$mjAK*!GMn^@d3Rwc{U5m%L&FHh2edeBM$9W{y|9;)SF= zc9wsfG{Vtqh|!*$8eI7*suWB8A4(UJ`sU< z1HeUnkfnyWxyrsUITnu=a2<&s>@-7~q`sEepZfe!emTVyuDW7_dy|;uq|->Z-`rhp z>XnO=dyFBqRDx=jF+?U=e8RA@Gogqjy!K-}mUN{s+u?=Fz=db2o;+E$MGsJlrRC^h z1^ACW=kR1+(kM|3*El9V`e*`7)*yyKMzLmuUW0hEa-yTYwkLWh-A(aJlE(Rxi~10#F^ zEO59NTlnsz=e}l5bY=0zGJWP8l$7Z9^)e zOE0d3yYEa@;m)B=u=*4gj9c_W8$^kWy_^dC%ap{6^tYoN7sq)OH5ccZEIX?GzHv`oFR- z7<&O?e^U#<#1M=;m06%d;m#ZDN6#Xo&u;G=ILbxtDA>O)n^K(9s;K|g?B?mRGlwRS!w7g$V4D=LI3Yh19- zWB7HFWG!#C7WW(;&15-fP8LEQbL&){TtSWnQ4LlJrLuOf#wE-Au5wp%JQiz1-8Dp4 zkllq$iHEnAP#^FUx9tO&l&iFb?ev^sMk6)KtRRck1A_)rSnZYkuBQGYouay46bx=ReU7x?2}NeM*^F}PG>!%b z<;J)3-4LFLWaX9HrG*5LloiLfelMgC$%Vk&+`8RZy{XvERtVFcYqfVnmVV zxIqgll`lFgOt;{JD#8eR95mepf|@lzcbF6tXu~&X0-z33qqnIY>@(la;n|c**M4PzzJ|%z!7JO?C8a60_QKvK>g_U|SX3&A_;rI(R;RDk`(;m=5g`+)CHJ zJ(LOkS!{QOj?Fk||Ha34=SJ4@SAS~4jT(%^KX6~!XR=w+ZP1>_Gi9q*fQB2OUq-Qq z9Y1)%w_`?S`_7Y8tJuQUQ4R>~tia*7pwZC>Ymt_BlOHps&^}=cG_?lmJxl1_5gN)L zJ_%rned|w1b9dzv_tW6a>F@{XIj(1m-Pc?37REZaR?NP?6Ihg8GK087HUH7L4K1#u zy8Y~HkEwkP7onIrwc6oTflxDhsVyn&)zazqdN3kX7wtfg4Ojw|am=4p+W#)U>KXO_ zeIQbeo0k1al2t1FRcX)6SzGw8oy!oPN1KwcFEuneAetPhp1cDFDeI+E2uAd1L|rQ; zW~iop&ZxLR@3h#7!4P@#z`7H4$AA1(?^|7c3>;G^aE_2`Q>YeYj}6uauvZVt1L$Gu z?)4$`6XZ^x$cpvJap%ICJ8PF*IRkbMbE$y^=C7|AQv#>}73fJ9E}d>;mwPpqlZU?Ve7d5&`skPKVIe4g74;@oVQBwU;?XS1>_%umi5eO zt_+=c%ekPS#!N!hrR*A;A@8VuDBj`?*YEyJ>12fV zcDPdy#gSH50IrCqt0sn2{4)BZ$`M&X3ooAaFxbn6#JZ zJ^{liBb~>Idl-B@dlI)XzVDaO)!`qGeY?`DhPm8@HxoBB;=zHzpiveQoHX3&VpSzS zzbs_8F)h1IG+CobPt1uGFijx-?;FuhMrpz`=iK)$9dMGl<4liw&kaTy%^4r1U|HDs zn;zyXw{D<;L4HtR1hJ>UA{vHp&YcuhA+AgVhiieSW)?$1d1^Tnrnm>|Pt=3|HA|TA zcal%J7$nL_+5ShE&^2Zp!K2Xrk+Jnn4@8DN=h1 zdmYY(VaBl(oAj?n@D^AIHfRrT}on z+Xw&yN=_d6TOs_!ED_W|kkcC+$;(_3gpQ#IxWi865qH=uK?B)&M>)v~#J)9pf%vu! zgN`n9@ZP-$#4j&NRB`}xLWDt9qC2_q|4h#x>8Wf74fyj*V@aF}-kv_-G{!jA;zu^X z@DbVjbnV4NHn>5VEYlt(CgZyir3Dtm749V{k9IAB%j4n<4?xEt?D=z=XC7;Ybn}8F z1;a1f_E<*LYd-*%xV_mOCz+EW*~K?w!>`*}l1Q56tRK-z*aL#y?E(?%S={3H8R$Whn`)iflF{`pgX_y>~H-EB% zFZ!pq$%q%vwNa@zW!QWqS;MFlecQwxanWoL)MKq3H^4_fq_9+F^rq~|Mpy~ahlT8% z$x_^tPRhhrbTuANZM_UbCU-SP|3N9M&1(cZ_0O-(0!INeGqRjGrQp2|r>jy>JL;>Q z!$pWiOeN(-{wI%fV~xhA@?_0PImvZTZAtDN3=Ju(?VLlhW)gF@vxTft9&l$5m7ip_aQ`UK)R-UE z{62VQ5(+9mBt_AF!4}N41GOIO1uL#2XjkZJfk;iGz8Jqp2{%IOVgXmCIc8~3B_y!k zH!L^p>{ZBc%K~R8^>Q3_ARYr^t3HNFjc>|q3Y^AfztMxVsVdbB7&7xX;jkUESo6w* zHN~@F8aN0ClDIit&e-LSwk3bgjYaOK0YW`S#6vr|72l!g=<~7N7j091mDG|w*B4*e zRM)z!llU+jNW^l%u?)BXPXgi%3uycOZ^?&IYHJ+#_{p-L?&9~Hr=lrE%;8HzgsJ9i z$`c&n8&LF*knPF!rG{syuWO%%BeXyI$B@-Wi1HZD`pFrl=A8IZQpb9?Xm4%39-Zf3 z4*2{w7~E`n3LoSe`TR$GQZ2^<6uDa;HT1exNQ`^BUp(fXP`vTs&K$9#vJ|NuO(81d z!?C#hsk0zV#v4FvS~<}N#a7qY&9h$PM}Ej`kCl3#Ln)PYRcvgS{5w1~3PBe98#r;t$k?Qu(%ny_ z*s97oY0%S&X^Z~65ni=+N3ry7avBGg6};~ICJ3~w=H z>of<|N~)wZ&}>PlEXjgc5DYd>FsEj@UXhU9A@)Dz2@IU&5dMTt7bzKnifsOs6SAjt zS)_uR8(y*KKhHl-$3fDej^%mY!>({-C9*&HICVC&Axw8rd=|rp^%t&<%Q502`>IGr zZ>fnk*7;j$HFB~AkQ$SJd!D_H#jKsb9mc+u3tej>tHYHrkDa&4IL zWj%$5Jo5ZOjuU=dGb{y@qFsI|Rk0sGyJ zmZ{H5?({C}8`Bz`OMLUgUm!2y%NaIuaqRTrnm}{fe{;XB32OZ_cS?e6+b;yhMKn7v zY%pr5xGx~;j|7%sQasT|w)Bc4EL8LdB-ULLv)wIzCSQ<_`VaJ1XvNa)!I%C>QZ77C z7^4|JzV24g5Ty`4s$nSA4$Zyt;9N2(zeFT7LwGztYK!Ula^+KgkYC4${>8o--{SWO zrMo3snRD&%edm8_7gQu2skINR@ohD>Qpj2zk=4Bu*Uq%$&M&7v>dx~+-{G?;y~5$M zcDXbYeqyHC9|aXB!5b8}X*@S<%!C#wqq{aqnt%3Y(?18nWl}&!6052zpQ-MlT@zwE zBc@?nUG!l28(uf^^iTQS2XSJ^?TbC)i?JZ3p0LR4UVz8 z85m?d7uh3Q$EtzUr_%I!G5+_`SO$wyW%@YJR#Lse&s)9I2L5<8?uf-+@`djV8G9M3 zhO{j8xAkm-p~x(AiD;(hTU*I@o`amGB7VVM!X#6g%P~A@GpFh(vWu}hautxQKVyOH zB*viG?s(W5#cY@ym>45W$nUV1cV}FY;Kl`9af}sxPHz^ZQYVSds*hLt=Z!PseuuPn zD1b7{z%u7I<#bh*L-<<5NCgH6S4mcsF9_*J8=ku@W!vGNBS)$8ORnB#bE_a)ch=^g zmzJhx%};$7VqvG-zWm$#Na-SC4z20 zXVyHAj-p(co0VY5nl68t6W*QVTrjwmnP^;S{l$v5MqbyIIu(4|8ls%;NpiH>IMdSL&C%q7{^uM&$zmaF`EKurpb>Ml72Eal z3=`x0cqoxR#zw5G*y4ft#$BiNEd}ZiH67?GYf4!4#Brh|3C@B?t|eM~Z)U!Q*+W*I0w-Hbivm>>uCHRx-_Q2ov4Y;PZQ0w2EP z%{rGn>E}Lwu;L{5M)+A)+kQ`^s;(&k$KqkY{blJVm@xLUI&r0{nrt%i+aa_R_f@+d z%tbtfjqLJ7g3NQa_B6>N=Lvi_Z3gO8S4K(~z(p+r2c?xDX#){(nX>7-s@SR?(SA6U z^sRw%zx&J0FkYg|>ub7)uGIV)ASzq^e~8%D=-bC6a%hanqinIw7_75j>HMU+4chrs zDcSL7)PFL0g75uWmUNwu`gQkI^cRy&=Cg8y*DFDV9Y8m3oHGu=%0WdMYZp+vA3~N> zf)fCWLOFNSGM?Jsn_G*#}S+!zWo_aXmwLi!7$Q}{IoiTIz7JB28PyI=P zw;m7v`(SPdj@6Xm=UcuZ$Ys7AAK0YF4F5FbY;vHoa$O)u6}b{EpX0Db4?SU zhH{K2Qqr7LKrX*2VvC;rao##qm)wJENtXj?u~CVmnpR^OegO6t8N%l_0T#Mj9{Har zf9|XqSNhPNb4P=OeqV@aF34Z3LN}eEl5dBGD|JHKGJN~BV>UsDqu=4jOtX+#!|c&3RqO6O?o3|%$d@5IF-(wC z{TQEg&&+%f=<(tL<-Ggy)HjlH=fVzPRyh(Fk5%*;Rd+Bj>`S2%F)|l!V0MYS7Sl4 zFfTZ5y~kkY+uome`TiI>dlv`8MLOYUN&09NHh#Z7dF$gB?Hf{uCxp?r5?1L#-s65b zmZEub&Vj~oV=a)UZ872WV{>(HX@h%y=F=3w7~dM?$Wu}#Q#`w%{%@=H%>!i=d__|s z+t3SiH8M75CmEv5mcZ?&_>i+9r`k7Lwxki(E^J1K7bcl4^=K z9Sq(WL1iKzE2W?QFyU9>z0YeGM~;j)>Acv;+ZdvHrnjwMyJHq%XL9H?x4=Y~(51TH z|Bf1u3%g#L|Bu7^FQjzTB074F6TjTNTt+ZN=JZkBH^>t6RY`Jh7Q?ZUrXJe!PpnQ7 zV$7=$A_R>(d#K^aGIFoY6v{5~r_u|Gl8nt(112gzBSp-FHzdqyNP_wxbUDelXLW+p zMPZBO<+oUW=)=i9NE^}=F;XH2^Z8Tz#svIgadc}{q*}Xl_sY6RhBe$};IU;e4P?og3R!D6MZkyHKAdr_2lCBi<(T}xvfXBh zcMXp;{AS*iJ!E&lB1K#DF~dbOw7=A<9S~!yO%flRut{Yz$!?jg*wJms?K@G_J35dX zOxN3Sf-G5zxVG$<&TvXPo`3Jp@P6h@_ihQ2&dRMByYqq(Ss(0c2^NCiNz--fxvQFi z(@=e*)9S>*RwUoBb3BH0Ix$2-kT#fpRxIF9HozcHTini4#j+! zxZ&+9;y-}aA44S}*U`38CDn^>bM%YyOU4x}pZRY*uldjZgg-!2JBf zA5X5*xmUBN1!sPp5s|ca3v{fp-=%o>Qop@IoGqQ0d9j}LJoF{0;PNlFh`be0@*aK& zeH=ee_fz{Hx;Egl37rknS)3H=4Lm<-ZSS5O0LhV{!eQ#BW(V*0{B!WGp9K|z$Ztq~ zo{U;?k2htvT$_dK=E-gOlLWSeIKLAp`1+T(KYM2Pp_<4|Gp8|gRNU;;=Bnt&l%rRq zaCMhc><#A#eF3u60*sNkm;K(V(`aGFaC{eWrM)AWa*QZzo`g?zijtw@Qz43DPwVF)W{)g?l5EMl05wufCbM+HI$RA0d zahR;|2~HC$b~puyd@OwAJo{r=itv9sFVe0!Ty$KXEpN(rF@Rkz50+7|UMbw~XYwR2QrHdDxOMo3&Y(haY|04It!Vb9D|#ex}$fnBxXl z_k>Q+3CJ^NCmSw0^*^!?AxSEzOKrYtU>2o@I(+HFiA#YS2p#2{qAvSG=wxb^M&+QN zdgolOm?dwvtT~+lZ=Dm+!jC#Vrkueva8~tuf=)t<-&2guPHNLmT+bF2f1?Y%45>%n z`|(5I>IgN!mK4MBCf`|}CWYzz=J256A$U*O4^1e!mn>IWh=Ng%6g!?MnH*8KGMMe- zw~$)JCCTY0mq^67%|&hOGr%6*)1Rm97EY!p+VU6e4Z_6|)-Il-mC9khsoU$15ginl zA@-7X$_(lC>tbhrQpf484Z>JzWFH45!<;Y#ag)GXKN-PLVH3c1n&%Boo3wvshJi)M ze^TS2>)ps@e|rRHi;|JjGwc*Lj~8Cgu&3!91eQ58AV?NE|Iou%daOPnhA+^+hE6pe z?+@V4O4vc+(-~HbKwUkmy!vXSiiD#zYjSI(sIcETL{Zd{q(B%v={C`l+wDrH0il~) z*YntqG?R=Du;2=s`)VVG{nN{BGVQsHwvNHAa#p4Pv8t)jb?W?Z1hz|70b)df9J5i% z#bd1~z8vM0wq&qes2S$o{e~SX^z;q5${k?!&%WC}R@?m6GbUA5(ZLNr7g?s&XcIBx zX_b9^^iI)=TRI!{Wn*X>0K`6~ZBNu_o4w$kKc34q1-}cTJ*5Aj{_n2~Uh_+x8yZ3SqCGhOWSMh6g?Sjad-*5N`k^->~1 zbSyjDS+&74F%FMLmYOQR9gv+X1u5igr}er5`-ECHU|+u|*&oNxe6DMBrlUVAYUC@Q zi|+Ty)!+2MPfLQt2p3DaOBC_X&)UOJl~ATa36y5_V7UFXkPOki?v7cd!`O5G8-E*( zG4*Q{gjFa7DO!udHWPJxH@;)@_P;1M-Te89$oDqO=X7_G31fDQx1`68bz5aD+VX{Z zkIxiwY?#OSn4+`-{IsPUXA%|&R2EH}O$QSeQS`9Vu2gGcr)Y+A5OtQ{B-pjI@9hW~ zN%r|dLwIl&Vgs3;e-X$(aKEH~_`<-i{hW+OjXf`4TlX!=PI7Zx%Mca5i2gIb{BGy` zGEIAps}8}rRE5++eO3aG`si-rYLYrK9}BK)uJ9=WLyQxIp#x7&n*R#HS(rayS z`Km5?Snm0Bb5q1{T4Stw?{t2yR4ND#JVYk(4@Hl0&;I#(>t|^3aWA9fx$m-QxOa90 zX(?xb+RDf;k%RR~uL}L9da??7Z|UFRRq`I(HVCjazgBAx)Mr(xarHCU?ye*CWf~rX zHvS=pPXD9Ny(V-{g37iKYpo0XF;`egxNY@;7{i7;!(a*n;OGff+vpOupJ`q~`fs^f zpXRrh5@DS8%(m~&qFXlF66hv}1b|RG2z=?`c__x0uA_N2oHQ;5YlI>qRMkoY6j9@& ztE=urZVMqYoX%>A!3-O|Jbx5Txvt!PgX6r)V96 z%CZCm}J0`xKZ++25$WYUc3Et<{e;zc{Wxw}9CCM^g*t;YXYqMBo`|wrA z3Ch!!ZQloYPcnVhgn^tv;svtA{epO1r#$_$A7_6b%;l9dlHf-QCc0YSCMoPF?1k(x zN05@UqcW|coXt-?O@0 zTC^oq=f=IdK=qIBO*)sDXfuS}ekFKJaCy8rDUlo5r} zQL&O(>d;fU&@Azkhsx^Csu`X#UhXkq59}cUU}#R8hywXXQ<}+p&nYgr!gMbsavzoT zHv7|p2q@8*>{#1;u+wp&k9NV3z>~Mb*_;L8S5#2&ELb+h6y2J!q)bG`|K?Q(2O+(} zRi&)7&AQ;z(WmG}cbdR)n#U@$M?cHk1c7~U>uC9R(LEJ@#~0@b>?ABvH0=WDOpFU(t#me z&ZFVA!{sTm%+rL3gCJsmExN$B*#s#G3toeqcr5=SuZrm4lIS}c9ojicS{D*ez*m=I z?Xys@b;RZJC|?VHfKXpY7V99QIDmX?Y#izlH!6tg zRe`*o*K3&G6ZZTXF1%Se{3DtISfVtyppd;l=7NOjR}mv}Dezuy=eaJ5ho)VktFQT- zHI6?-gWR@#rBe|3Rn=kzc8IfYaKt|EOP$S!;2cH;nsV(~5|jzc{jdB&Pn;Isq`jE^ zTeFta9E^%$l0*pHg=vV(%yIDFGR8ZCS^R|7=n{0YC zr_#yWRiW#gH&`h%2~2@8FP=khpm1E#;6z24=j$Vz$*%hkcO}VxR@p2&B?y8#)>kLf zdB_D2V5FiOlNUq%SZNRK=_xX zey&B;{IZ!9^%e`Vdz7t7y=Yew*b;hQvZ+~cIQ(>&%UX%HcB&Zy>ZL4lY0q~LN6H*k zulUuQb+Mf@PPfyN-kM__TdPB2$@2I3>!__R?$Rm_T+1&bit!_^!QsP)=@k7F{Oz!7 zktwkzf=ja@yx4ML1NZKg5I&sG>6jt>4U$bUZ2cz`&az5|!Y;*zh|x8KZqHeG&B>J6 zsvJqi_(-Ggi6*s8HjUDnI}1auM@ zJOL!~jnDzvuTelH=W2_ZSmtzjcGhCb0`L6Umn~=Kr5n;aBatb+e>R^5qnha-y5a*^ zomL_RM^m>p8nD2e{s+K)Cmj|Y8~{L3P+>D@z?z>ICOwzM|1G}w=2zq;P{-0=wjg(( zVqL!2^s|uIEG5E4UDn$zwErRIcMXNT-R3zb-wAY5^9AoPrQ~&|pvYW^wUi=3GbJFs z@4QCNVsH04qd)%Z;Ekx^3~ah*vLymYqMQBMtkf3Nr?1mGfxnLC2&1{&UoR)b4(vq{ zM3r0*M$4S1j>&xHos~wMHu9>ry|g_&emVogI1u)Zkt1OMQA=)b8T&0{FZsEzL-5Fd z?s>?Vh(zOo0$mw)A&%X`w}IY^LIMu@veIBkZ!d}&!*)^Qh~!OEf&8Q;Ly*|=7L{HL z-kTDnQ)$bY&L8^D(jGudfS`Oq`CJj0S<5^j+T)EZ6tQ&VHVsU#5=bX1EfD3d_0$O=h26P3kin|iOo{Ku6sGfZ0s|UBd*3#kF=8i3hc7ZNj@}OC;g6WmD=FPb>R=AEx3!a|$CsJ12Asd|_HR5(iLQ8Ikt3Pp?=I zrdKt;P!Zpa+3+K65}6KUuf`+x@jH@MI|NV?>zFG!@y-0O6XPJhER}boy-+x8n+~P8 z@njUI<~=2x;Db%Hl*!ZvmI-W&tfw$%d)`?*Xu_JE+qYhn)`MBmar><81FM8_GzCpO zgxU>$huU68Oa1a0k!osC>}f&u*L2|_vQ;@_m=2SD%@Z(a+N`=^Q>N&a~4v0;4g>#{+C+s`XkyyJGV zJ7O>bMvvvE#9Mw@LimwSNindU4yPCyEZCjP*dm%j;57@^D~3*Cd@ZUJ9xVjvk0f~n z#EM*bF2hZvQ7-jsv_58g|b5L{TREJe&(lS+I5h; zUl*UfRHW!*-OmDhFy(G9ag=XTx;aU+cHrhM{P|ePWNat%{a-ciJ74dh$g}xTs8r+T z7SwC3*VOrkw(kCq!6VNF@JF}P5F%d(nn)jk;Na{5RuV_Lqh}y<^nJeto-`0Ng{v=} zZM@Acba9e#iqvct$K+>Ul9^qUJB2ZT{oxzyT==eihbm*#qOcdzAo7klu0i7JS*2(e zl>nItvLKmc`4a(HnIKI4=RAQ6J?<2_D~RPqN*4!Rz(U z!#gp3?nDN&ZFVHfG;T@NK+d(x1^%>oESJUd2JDjBjadKtBp(@R7EIp>6y-~(!ezG5 z6v@tc6&Y=THU0$i$7;X*|FqQA=(d(Z-eR%^9v?Sn7EqRk*(;nU#MY;WH@!I@pg4y) z-?sQ|eyvF_=!E)o(J)9|Ab#S*G18X72+$L%10^~EuqDZH?uxQ6iJy4;)lC{EgR6=o zzW2Yq0t%$J^?ZfJhy)Q2OAIKc{7hZWWm$|iAUuD!u$^<|p&P!7ypq0~7Ccj=Q6t7R z@Wq=qYv*yt72o}`HlM2IC>HJboXBj-2A=v)!+wdjQ*j-_=Ukq-CpjDp{MGm_t>}Hj|)4z z?}U8VGCdEW*lATg+OnS%$hAK>~Sy4o@QzeMA`b-}GH zbS@m>r)5vc_COn(aylei?Wh$kC+1rLYd9xPd-9DLk8L7cEIL3t}r6F4DAtst?(u(k0??i1*1%PMc*5{8w|aCR z5j$z!1XAyVxA6@`<$B9fR7T%!))K$q$uHTkbuQtOp`h9Q$JN$ic}Q${UcJ zN|grHO~AP$wru<42#(uFn1QGDLieM${;H#i4qj+ix~d>Zt|x`4>A>G1oY%-NA9vbP ztqm1hj#1@iJ+^OtPSkYz@bq1u#BIaR>Fqwoblc9=q3h=BtHuuzV%FDApRX-0)`wF3 z5kmckB8d;G2#R(z1c5z#kQ1~9O%9ZC=8%|(OsU(1DwzNpl&bGPC=L*6;qrK{gYK;LwNl4bbbzwwtXP%!n<$xiS~t2 zc=YoT(}wQ@- z9Q(XY`NZr8j7P}3)dvo*ML+3h&4}H$(&(Nqrs=~q$3c*)E81gd*&;c=9Ybowlq%6mfD(Um!5?v(QBb#q4HHStL-oy9ScyyZwQZWeZ4@$;!zzH`o zu!#JSf>3`Gwm*RaGX0}1X<+(c>!TZ)xM*vfYAW(ndQUvY9x4}yp-1cD9IjEU@rw$w zp3jSZa{*=&5zTXa6mB3`9awH zDW3OuS}zMD2_1Z*pzMtK>_YzzFNq+a;HU#G)#qMzR>#e2zqjk-~0RXp|wo6Qnc_nmncYC zt+?+6){<()T=+8&qKVte0Y`E6wJ22%BPD{JBn)B(0ob0f1=-F&0Sk5e7yT9Zr!M8& z9>^C|EWt6QQ##fj;4n;oUFmsy!F&DCyJZS>Rvz4NZFcVd`yV8)4=_6bm123TIdcr_ z^B)I#ezz0;O&2)p)i%=Z^9T&Ny?%}c>~5M6Y>q_O_$9ge-*LjQr$R7!reqjU&PVht zC$W|fx6wF1AUO3sV+H;{$+fgT7P68ApI{b?55N#kH!i-kD5&+v`}hwbjEa+e9F^@5 z%4zx!bdP`0Sl|RdIJRyHVpd`1^m9??^8w`09X{WIMWsLrBu7yM8XO+~sHZRxX@NhBw%Bd57(S=NpQl5Jv{mmla4a9Yt2->s z+##M?#YSJtpGSi#x&7FW@^2$RYS=n@6lk8n)G(9m1kZ`U4GXIOd{F2Sy<`*2Wq~OE zaO6!kDzZXyVu~|Ri>opMcpfTi+_bSA(N&+CC&D~3Ks>!pB%eVF7NzY1S1@Ix9wuG) z29DRm_B4@(U_f9P_nFAY@ji<8d4i#wh@{y7P+l$I0AamvInc6F7g{FVNv+YdL5*

9Aifqj!);GJ^}2AE`@iFZHTHHb7RW+5(F67~qn4!8{K?Dh`?_5e2V*`8 z2g3UjW*Er75YZL>A4y-~(B%8Q{VW(Y8tIgegn*3h5(R0nC>4-yl#(7GAWDa%fFdQS zbPrHUx?#kS?$Kk^Z{PR*3%2___c`~8>$=WIJt~@vydQk({8hH@a7!J_ehcdhF&Ngg zB}=T-4*S=V-|P^$)KZ|bZl5X=spv(S7h$K~7L=$i+5*vUR{ED|?`v@rS|=sRYODOK zl_Cfmny{WbFEZ2aYyX$V^W^q1$k{-V8B(33BiO-0E)lkCsW+5xgy37>$dIBMw$pJu z1C(-y__vSguS?%9RFmV1vD)WhLevrSfTIo#3nNYqd0~Pgt85As4)5suu>v>fh2bUy zg~LAaEmu6`%m&4ZTzySe;S07JDf*UyJMHlMD1q!K&i|xr#Omy&J1r5iJpo(Chbjw6 z0&Pka1{UIpzd9$U&Y#&PrN_lMYaB5wa%|7Xe&bi}4; z`$TZa1w)LzeHri?`Tej#={dy0g#-BU`sklr$|OlZpeUq|V$Nmhu+vC()>{+?H#C^h zvy-m%Uzhgsqww(@`54)_*=py%@pH;=v!e8w$jNA#{)xd@PSfU(Ou0=barvU^+Lu~o zLLtpz6yr;(kJml`%~ALnn|Bm1_7J$4)t<*Ku%N6I}Ya5-Io_zRRx<$Dq zGOytJ-KuetWWCG2J;zGoYT?z779MrR#bIsp92=B|gb|kJYSjzm7xd*E5#r#&fG`31 z=vn~Qpcy(Guf;Pip0rXFCSCEqtc3*rg%xAW%}eR|)`HZGv$TDZ@U}jh{PJw5VwI9Q zIp@aLeMv9o>9X(539Z6jKtTA+4jxnTyZ*)L(|q--7b*_A@rCLikQWv(VBFQ5D-v{f z*EpZOu8b*HOphn%dgrs1`m1=*XR5ydL=S&kiR7XOCA!XTWITWMHbD|;wg&xf5Wy8A z7TRWR&^hgELM6i{PBb~atm6G9o9a${^8IE$88^$U&&u?6O#Q)+=Vx55KRju)_%3+K z^RcPg|q>6Fkt?Ibv?LP2t9%Ri{A$B)5HDoR z;T|9m>X!klykUy)at^ZT-co_NfAxd|=Lu+#6#QP>Cb-`JOF&vj18fp!lfwQFK{U92)OpK%!oMl+F}rRqO2PyZC-mB_|sH(|RDT$D9=MJ#-JU$B$OIJL=2Vcp({N zuOI`%mRXA!Bw&Bd{nQdk5N$}(Yr!TkrY*I19AcMnL1;^6ATz@1u#fVxp(vI*pB98= z=OX$?Qu)%jbJ>#pZEL~4B$LR}l*Ga3ItJ23Jy3t-D@}Li&;7vp#EAN^5D0tp4nkVY zUEho)j7peW#i~;GjFW=Wk8Eqa+_L)IB>e@Vj#IqjZdXPU)$5j6IB{0u1Le!D$f}$Y z0i5?eoBmKr>@7de>yI*-9iQxUob#Rp;}|c)(yYR5Iz3Hcs6v~4R`(tEORssWL*D&! z3OLFwjS1k=qF=A=33(hV$s(A=15c5ZgHa{iFEC$fU_1ZqIKJn?)e6UD!V#9rUjh~s zeL^h%ie1NOo8~}2fv}8A^;f~NMlR{Eo@&F>Q{zW}hiLW}Za$m_{#gV{2u)XEJ6 zS3=fF%Tg$KxBI)GiVadH6agYdHR7tN3-(%UA)JPbphZb2h7mGdL;VXB8(cZPczX_>|WpxZ-qM}znKnsfTC%0;bE-#t!u{$FL;_`L8L6- zSg@JPn$m4PS~>iRr>3DF4cADfVXnw~SR<2%)=*f#+R9DuVKDr%+|^`&)&CO07*yu_ ztllbo6197pw*q;&#OAaJ-h~8Hi<97H!2!U~Ha9wz&=pW!*!U|oM!Hx}8O(LIk*BAy zPG>RuE3hY$2{XO4&gH@;iRX*^;wBCNI-()Tf)nir9ggH4UL(~CF08jH2AnvE81~i zYq<16cw-U(^$6kzff;^tz@fo}hlUeVazDPXCk9`t<57krO@yfwKk&p?O!{^QzS$FL z$BGsP++xOH;n?D_p{|#?`q{@ZPFgav94ZVJ7+R%Ddl&QDwM0+5@4P0EgBv}v2TLsH zBw@!ZlJid7c*yNEix(}$pE}*9{Wa?!`W;YQW;DFuw{R!>(Z5Z+Q4Ru9PHC<_o!hl6 zZ~9cMDJNrZ1TXEQ2$S5J&&sXT6QDaPM)iM_tXNL+qXm567+{aJ6(d`;O2XizdGMp98KiSi$HJRuWooMN1y zUZ{Wnz@G61(HLmrFsb(}eF_qKj;R_Sx4hY@1WSb83FUy2Pe!qv$_=YYIp?(3ida4vyl=Qd^}7wA5XLudOd)_nv3eom6;EYX7zG$?#*TZ;XY7 zpU^+mFH{l_8@#&EJuYmiFf>wVxq(AMxihc(P5PvflB(||@Patn6N;iPfO12Cx&1C# z&;!4=p{dd3{$Dbz{|k%uc~4qz3MKpZ5S`cqhhUNdDxuG91V&P{NZ1=?=uLaMJ6iaoa87Me>u><9k@H3*D>jEj-CNFvp}yQx9Ll3OL0Rxb+s9|S(q;y}5T z4_S2qR^`(V`2yE#%~0hwGP_jm$02|AmA8Jwvo1NUf=~XXJe=qOIC3SZ<+--s67 zuvSt9xG+%o1;&od%1R9PMGq9HR`h=l8Pfe4;|5S_ z4R;@f`Z|J{RCFyaLN@lVz1E(p8(D}Sr+K91h zY8}o!J5V=V`E0U+;i<3U!)F{^x;Pk+mBO%v=%K_ei82O!5h+r@`PxF53oj4Th#@N} zXMX3aik{D3`URi5KSRS@Ydjo2Ojy9~U#Q`C%nlm94PW|ZQhfpCZW2!pV|Ed! z$5P--u4K{&GPWL<`hOwg9LmQ-;lI|IV=tM5Gp#Th?{6-ISb8cvDm#WcevUXNFfU)5 zP6~?Kb7k7{r)spB`ViN2k6vt#SGdMJ(TovArlE{z-&Mm4x<}+l1Jikk1Dd4lVgAua zFNekX_~Pbe_dKrjn?XUvKJE?^L>7csz{8-c@QN9!^c(1=Or1X(QF|K{M#&eKM&!0W`x{?ymNKbnuym{?BSXBpJ6pkC8U( z*B3AE3#@B6nE8+gUjNB|d(!dfiik(_WYMp`?a{W@ z+4;J}sI(ApT)fyv+|eQ z)3{I@5Yzt6Wc0?hkvVr&fTh`s#xCT}H||Mjn2#9B-V*Gpzvu;V*-`Wqp#9YC;CB=z z0Zq7BWmdw1NHIMmu^{NR$#cD%{TH-XWg%qQU-T=g3+v9ijQ)C@xAa&-R2p7Gt-vVZ z^xS^i_hRB}EUIFV+1|l=9-_HObDO~gDJ$AeDu_<(Q5GYo|7wujYSS4;UZtDan|O)R zV75->#PWZK#)2+5V<`F?S5CS*?koJD1rR$!*3k zN<9dEO;F%rK{jJnRs_dVS zaPIzR1@M0oSMg?^x?z+aBQkfZ8H=s~zmWz*x`1x}~Xb;%scUsmm+nHB+mboQGh*j*}bFVKF-ka)jyCE7I@26b9eMNsB z9v1$zQ8n=QenMf@NoC=iUB6A#=vU!{sAfbmQ^tievO^18OB^T}kw-8{Z3aWL>m zvIa?lkVX`$O@X2>ClWaV1bvjWyA{PBItC>rI42X2BVX0%Nuy*YCwrvBm{9f@?J@p~ znTGLMbjo3tWy@$)=3Aeu2-u!+e_P?=aBr|*vbr$((M-)3LxgtO9t(Fjl8uxw8B9-t zUj{~1soZu-T#vatFF8=Po4f+|2L(LhfV)roAdk6yLSvOQrD(c2|u4~?o6^ro@ei@y#4T}F_#rPy82-=EX2?1-rs77O}}es8O^0LDt}mDXfRijSgKIL z&e+V~Y_s&G^q5M}{OwD&Orzlgkva9kg+J+*dwP8xH)f?Ytd)FUQ(9wXBe3X7>Vtgc z-c9sDzve3is{qC?-tBn<8iDvvL>8w53!u?R=l8_$e=J*8oEO1!oEd@VwaQG8|HP4k z$O^27lMYRmez``Q7-@6KT(OJ9*5}lX70I))H)ck|l`pj&m{LhPy_s;4Z=ny5IlEN8 zOg2jpTtATsr5-@HOMy{atTa`Qi>R!AM)4|6Rtm-X{Oy7>h;m9^WL_70%{K#(+gDnH zCcSrv$4S%?U45rUPYABS_^Kg7d{_r^51ox8el2_@>Q0v`$XoimIIDat!=J zjD-yABTU*clnY$Yq5Jj!s`5!*h0{QjBC4i&oQBn5n3}9(|qeQX!u!Z6?PPe_aV&9?EYY>(2w0lUamT_(prUW3UNGbqDatU$54eELS=nQ z!JbZHu{v`kc93oSG6OQ^j9TunvTTbH?M`tA?c;- zo7}kTb*4)-rT}ojG^<76hB|Ih+4s_Zjubz%JoH0gAZNU$q%u*u)8;^i>v?Wx1WB?A zfqud4ZYJ)dB^dLncjP*~X%jav#f&jg^T~J)#r*-`%3)&B+Z$iuqXw}>g)XL9hg}aG zo?XCLx{z=>tO+ZVBj6y(By3JK#rDe~Ax@ zZkdI|R*=%g-LQMuAu()KaY9)D4%GZH$HSn?*R{G;pfYxf>VZ`J+a4y1VJC5We5@KP zAm=m1F5$inwj#&|T7xI`q`?10AZApxzDxRyVHaB-n0Vnz=tPGI-Tg{`6FL`jv}VEe zP}Z<^;nhZQOLz2nuTlFJpOPr8zfsxEVloID9|)vA!6^W-a!T7%=<5|i&KIH;yIX%c zzY!%28gjctL|8C!MFMx=HFpHqAWt1K*{x7e_z<-yh}FW$&&S1fCk!;L0AI0C$gu@Q zsN>E0x9jTyUHTdf`~0i~QZ11=Ctc1@7Tlk5mX5r#uygtO`Vp~HPB*c(x=I8hf5bu{ zsxl;7ApLFcf?BG|{J|^yo>K3Ed`};c z*9)ehLX;hlGG{Hgw7+Mg0_zJWGU9lL&L4=2g6-hIv_KRR#EIVs&W1wZ?14*GbVqND z3Ock`Qs4Y%gc9Bf5jESQPo8PWaP2d$p19aiE0LKscly?Nf3R3=T7OIC5djF3^Od~4AyO%r{2Y;4&BVx)=8T|T|Hjr)GY!oN zvf`MZ$D8(fMATH&g|#-j14%BCq{i}G3#>R>#HdyE?VWI`^4uhjOY)c()xCc^ za!kgH+*BCVKFF35upW~n1VHRrWb>GasWzcbZ}&vtN8-pzaPV#2sT=%oAc}ZLaY9v% ztUGlrW`EkmKrh*dLBAe`wG<(bU5a}`h#-#&OIzc%FSdy`5G#S9LkY|E?CRhfDHO>& z*-&wV&M^s8SP!s00UX`=rv2TBz=^Mnxc@j)O?R|AjWGSKgjJegnq4++k=?5etIcb^ zuK_CrxpEx0pY)E-zLfoPcDK%ERZwjRX961x<3x%-QKIUq4UCP;m{DjX5@H>bqEc`OL`d%;Tm67$#M*ossBmb8oe%?-g6dz}H|o~V&} z_K!Dj_TQIkOV61Ye9mn?e9r^~P66jhx(oo$s={2GPuZUs;tV40CzJgq2XQrpG?Oc@ z!7u05r4MCLy~A*;cd_VbT6>N!wQnr@Sn2Kvgc#J4T=J6f^l5t%Zy*@O;M%!oW=_BW z3@|z+nr0f3heH(Fw+}9Rz=-yMB%)eO4Hv$X&117eLfP2A)JmLUvGP%FI0$xh9+ugO zWu3MJdrXnKi1FZTXrdtym)`~Nqyn9`g$0Hf^9#`#4*gwsF6RRF7+SlYr&+Y#T=LQx zZ(Nne)1#Szl;^a$W5htN*;I+-iE$ z22S`dkzdLKPa<^G9_`X@TD6S#dL0iw@6sXhu-h8h;EXItmgdzenVtFsia5-qz(jog zPP0+Aa{ex9x9#~@s+DAzbqLYhR)M^=(Q`E6UM+MtIE%p$745d6w&+OFcdhojj~!#! z@oM}5CVQc~J}mZMHaL--D4t(1>+V0$MroAojCBIt^td$VJK5FqZ=Tx=jQ0F?(e3Z9 z*S?efNA6q)9)1lQi=^qWW!flBaprQW)Hl)MD{cLxe$O{d>~GT@a%+9W49b=$0QZn5 z7%xV_E?ow94qBOBx*>foT;(Q>=APU(0_(Yb6qOkn43OEAA9rLsWEwUT}+8nyX0ckjJc(hlB3+ zSLOGi9DCD`x|d@qzqOf%+K;=@Vj_2}r+sFh$611f!%IQ&suoBOpE-4TfAr&QL9JBh z=CCsg@oB)hW1v(xE2PgIw$zdp2Hb9tn}J`pTCYEQ&sY?LZHZzHD=p z*;D^5Mo-agB7!RLE)TIYC2raxS=nv#)NZ`i z6yb&4Hk1NcSOYWq_6+fGi(DUFe&(e(jSsm?feg&<7RfAN7V+$Z)hmT1fmQU;KAHJ0ovMw(F}4f6F+`O zZC8j_n%XCEMRpHwr42S&73_Zsem4bl)?!Xq735+=n7i6=ORNmvn`I3TDJo4U2zuM* zjIeluVi@N?LSY5`dOst`1%ao?OGO%ibr&y;U;&@4%edJ@Be}N35%zD`9|Vh{8kvtL zjLN?TD((tQeHgtq<_ip-`f_*#U+AjP{+q+z1tknCDB2Y!xlP4OJL~S{v!Y+=Y?ln< zfSuZxLt}45q((6(;=Y_6Hp6Q(uaWJEL~Fg0#4cf^p|q8C0vJt-Xr`nC;BK*8(m*;TOQj#t%5Fv5$6eUS^uLp2?rl9EmE)`FiAPTZ)7^JlJwGjwq5vI{S*mB zxqP;&q#+tmgrjC#!S|@$>bhr7zplt40CWG$sA~iu25bd0VX7r4um;^QIi+|I!y_2A zCJe#SI7ZXu?8{4dC*zY6o1h$9sT}KrL zB2Y*~LFR&L`o?86Im_nWk$>C1|H6+a6O5`nA2p|r0&+aI#*0^<2e$6}5;FI(yXqLP zYAbnWl=%~v>~}6hLA0Qn=Cj6zts3P@5FmkqVc0gm?&{4OuGxg#d`R7wqH3*aZ>}T8 zs#QEWR<2kp4de` z3p8+xVNdAg{j=Q&S$*U~OIqh3Pq*O2PgjqHCJOBzA*0k0_G=qQzbKB-fuZ5ZJraH& zx_ZL}j?bn>UN1E=mM2%4Sgw8wTR;p}3b`lUKs|LVZ8Wg@m~X3lH;UUI*~`|jpE*q+ zLM!~`Fw8m8msDMgC5>K;8Sc)@`^S+WYs$w90Zk3p!8g;ZFEm@GTE}$G7avCK-FoO3 z+MIq{5uW>&LPgfg_R8}pNAfIv>eQVcxlo{a5VsgG!q#*Zq$exWq1J@t4D91?VZGY2 zvYluW**9DwQ5rB8BY~CL7Ed%7 zE&Vl>(Sm*hN&4{yQJXj9W!?rB+Ebq9gh>hKaXR4hv~l^yTSy3kc`#nx`m?TY#MglH zSZ~-wA0ML{nKxU|gLk{@dvp~V+n#KV4hW=%v~=#*NxlyOU|Z|X``4+4y^+b|+wzN| ze|@UcA4_Ag@M1ttHcC_unN zW5f}5S6M33wXHkaZ&&mvlih2r=1UV5M>#fbUBj(@==+qO_$GdaH%wL~FBbfWkX)Hr z0$SU^8t)}2lIzj3x(@!`JKH}7Q2rvm*-Q!_Op-aBgZ?uQ+I1ui zW__@Q_W#XwIkS0*31@t`RKd;(FsnC^)Xd22ddK(2m>EM`&0nr)B zXKQIG9=d;HryAMZ^pDjqnrvs9T-Ms_occqh%@H1pFD!$wlb_ZO*iQ=fTBv+nWIyR1fKY{wOzs<~Kat(}^VLZ6=x_9WzOpmWwOS z)LqQfZ>513^by}?YD!vcc?}3HS*Ni@nt!m>B+gIOGu;}C83KxyRs@Ym*x4GHks_L$GhdxZtwLb3Ks)9V2i{jh1o9f*M zjs8aZKSVYL0X9;r`U}f)#K(CVVwY@oBTh~FJ3u_IrRXUc8|#<{uZcsOashL zNF7#E9@O)YOl~R-XyE{vid}~{xx#J5S_jU(v%qNZuG*AQdWdp^wd7A9g!pt}+$HI8 z3)7X?8{W?1pq9U|4#4KmQL9(Dk$jW5g*&68gQ__{;KZtS?+#?&`Di|#)a#( zCXlUE@MtvO9w_qyJFTdT^81iXz@2SE5K$1E9rFX#nI> z(I{JkVfGnsz`W>XZJ@dCaC(7XZ<4h4Y0KvKpB5r1oJi%MaJQhd*%j%A4eR;N?woI=I`rLN_Q$`*;9xJrS63RB@04Gx$IwU)1!55jZPS+(hsT?V56q36?kLHUH6N>I$_7#B zdXw5OiUQw)KHn~2Qc(wnSWtyM8Tllc^Aerb4)q%2iuRjNkIccCV3SYw6b`)=SpfG^$X&ELRJ(sT)7yuPZJk`ovSsI zx2E49^L*M>w_W>a+BMv&9dLQXx<=6ShJ#k0R3A@0%M>Zia>+h#8+gg_kFQwTr`4)! ze9o;o-Wve_tWU#bn1`rH|8wod;6Z)kn8g#Zs1siJJmGi-lp^QA#@G93$C&xQ4W zB(2Y~-X9De{ZyBEoYR%rf0U$St5(zNTq?C`Di1~hF%qUDc8?*}+!2eC$nsCnx5;{$ z^TY!5vqV9gowKJ`v0ptYAa3&eXBIK(NgMmE_{(W{Zjz-BJ-<9=P9#{d>c?w;6&jS= zg;E??mMD$lO-X6@f0cabPOn)J;sX*cSPzX50vQch0}rOw`7%3=o~GNqDw*d~2Y;tX zbq+w`{_?)1Kck*VSdi%B$1ICulq{hJ5DCj{l|T}qICY@nIU%^Apeei;bI@hs)<0Rz zc<-u1kpX{~S4hn>aE4FxcSF9T!Z*AF*e6?0)bd6O99h2XkPH)k_+O)$#s7*O9oDBL zd-XJlWOYu#Bo4Q}1z+iiuOtYX?*?uq*oD?SI9}XNT3q?pO1pZaU79*2qQ4q)=f-O@ zKmie2m&9B41u)51?@4G1GqAr1nl3cBQK)@l-9v)_#Q_MQJ&pzmr=}KaZ@jzwBw4}n zVNLqtak6hZa9JONOkRpP^G^G7W27N_G|vlEmK4zTjLDWQUABUFfT-KNxvIxL6qsTV z0!(esv5GcfvQWFF`%zGbA;MH)At2}vT)b?lu3)ch_fn)Paq7_W{o+~L(_ zA}O!#dT%pg#(GlU3Supt2y(Op8ngYhhI#-Krd$(sWT~WzR2Ff6m5P}fwvpw5?!Vez zzu8kY&2LfrmxKQbyE8x&i>Sp5SwzZiWRBvp@PE_j?FuEIntG3rpkmdQgBBH&AHgF_ z`TC2OuaS{0Ue|+c^8k>8=0$Zc#ns)pzy{rIltrlMX#m-f{;xC^pP4L{;dG_N5=y$` z;E##sFKbXw-Oj(951iH%tPQw0e^5N{!iA9(_v9=Fb~^KtfUf4twEKOeF2~{KVo}^D z0&nq>6JRmWE>9cbQb(iVxC!X(>H}}^-;!san@ND2jtFmX%xXX;bXPL_^$yluqXs zUwYCH-#mF29}5oS%?=8wb3F71J(L1BsHxPcyVEms%`$|x4M;*C1~#UH=8ctjLlX07 zP=)rzupYz4c%Db0lDE3@5>SPaObYS~$s*bIl>c#QC`tce(^13QeNOmnWc(~6%&@!& z5m{RF{nselp+d@#HoCo5Sg5#SOZ@L$nTM!1R4>G4;Dtw+fQ71Mrl5VI&>Z9mAo4OZ z?gM2dDO2q6B%lOZRz;|a_lFpQ^Zp3UM8Yv3g^#Vy0P2x}EognztcPTInuO=Go)lkM z>p;I-P@j;W3ti@QijTQny{H(-Gn&4l?X1?}d(`exg>*)wxru}8+@-b$|9m8MfZQuv z*%&dA5&J3-cC5kiKfIj)o-mzG21^=4hEHrWdZEG|IFI+dm0Wh{@8x~Neo(osgkkA9 zJ*-{r;O?U_*^it}Yb{EtIY?!1FAFWE&brpU%pCpSfbr`^^7x1X{BGou!^&`uc@XE@ z#ax$H#BW~$Lb*eAw){f7Q~6Z?&)M{`P^h5_A*Arj`f-5>CJvD0dIauEmBrsC8-ot! z5eu@2xF92Lv#FEc%V8bLx6>~5$b80tehu~nbHrwPtB*@I8-yZ^V&&f{vZ|xN@=wD z(yfdJrOeG+hO=5vBa>t2tp-hkywjs`dyEQw$sKyF_f2nctaR|)dQoAB_wH~n_!wt|HZ^r%^dCYWOM z3mJLagPR?gm@!2RIMaT-INxJgPUehHoDjh_s;td=N`+8VxjaQL#UB-;AAUGY5cqZ_ zURFhOg^nyscaE5oxAlnoO3X%4@c7DqiE81WkG;jNmH+=Y&2Kuko%Tun5)8h z=+4KeeMF@MZM^+`@}l)W$%`!J`X866ufYP#XQrEt)ltPeN;fp z8!GAd-Q$}!itqV7!`NFbqI(PTQ#rS;ue2~qzCGs-t_m7l`+StM_o}c8^b4VKB*Xwm zsRO8TwxXKBVY4?G%jI>wZ;ISBG6tUfpV|3VTL$eJUE_uX#Qy{ z=LzR$mN_423Ncm7`nPZ;iW2%&3*;d68d%HKBPOAc9|T#EB?<-cUxk2xTMzRsstQym zCZWh@$f23XQ@0kfLUpLv$Ot`QWp zJUFQg{6MXF9uu&cG{jp(ri;o0G#sL#;7Yrg_?OZt+u&NJhxvhjBx0-CF-grCWJ*++ zGpS|CdjuFoWFb~M3iKZy64bc&ydOfpF++L>ZOuNSG*TyymTI!vpp#BheYRN73OD(T z^{}g~F$z97w@kf9_genNQU?|5>9k~UM;I2pR=d6#who9#eYFL>^-;W6y$(`l1$a=- zPC(xc=?}IzF#Q#2BJ%dLN<)nh2j0lXA+;#2`Og4hV#Z5?{^lk5sD4j9$cYxU?1sF1 zN4Gfth*qJVSD!*s|-#Y`gCN5%iE~fq)N{vqMg2j&#MjvnGU-Ze6S!#kX4c*zG3PSp!NnDTMr$= zt((>~p(|y?nGAZ5%N{}k^!zv8)qEeY4wZWxc&kw96_11(#;x|YeV`LSqYeSR(2|TC z?>sSP$3D@-rj~zs9dWtxt?Yt5N11uYI0CEB-af8GVC7GM?HY>>HiPm5slFd#+UfLL zgsQA}V%Ze?Uu^GCK2T!dnvx@pFX`}NQrUI{qJc+uNaESr!7vP)-8c z%b-t){H}v zOB3=oBVugHJLvr_9_$b`wr1QA#Z21aXRM_Rd-eA@njqlw%cV+A%(^yFcpG6W~+hsT+>1@PeKEX`7X`-Y8ql*c5IGzkMcznqTV3<^$+)S(9GL zBz2^hzKssfKr-}EtS&G6LT;!+G_psBDvik43Hl=K_A8$|yLX+>=A{%l zRP)vod(7{QWFRR>I5@tNFoi6#B2~mQnhjS_=A3?~o(J&V!b#;z29S!~HK=#4Sbz$Wb3{VCL_3kBar*zInnOB=}qT#nucR z=f-fNf42gr4FRHRNJ2(Hoi%_~EWUIY5FyW4v}GZ(~s@k0ipC$=v$)R-L3C zb#L2H@m^?KQmq%I|Dm6_{iJj-sd`$6Y zOi9F;|0t%TE6OEKYmazB6|6W2;W}?7R0%nQQ$!y?;^utn$TZMX@iONxgasf)0ip4_ zz)#X24`h74NP@Y_%cxxvd$NUEOo2G14Jxc=bz2?LW1MEp#BI3>eHxbaIE)W`_(yz` zd-v3c@{Ib{v8kOW-2c?y7TYnR{UK&ZjORe4St)_D>8k8gCfSlU`DNMZ=(t5X)iI@3 ztme(XU(edNG~Z!%ksx;u&AWn7#oDC4YO48uG4KO8A}ob(`Vd)8!;7*va5;pMLB&@9 zdt(p;lGun+{<7qAOWSL>OMQ6Pkzoo7AmpSnOKDK*>Q8yzoq)aV;pm9O3+`FL z~*6V1e^R0i%7IWipI!ONCB{IQxALDHyC7OF&<;-&deiFW zw(T)$i7Ro9{QjQwG8z^gaQEo?rSM*W%FXY_#VTtQ_frlz?2brwito-xm+M(g`c1o? zXcX~uQFp$JW5h620jwi!qZ>bd5P~I;Gi38OjWpvnl0af%k@!e@UjU=02<1dM^>&AY zoaaT6z`bqL!w;w_#u~=NDbp75s<&AJ4QHW7l(@BobtLHZk^#bU2H?p!+aIe?IP)BN z`lyW)^&4jH40Q|ztp^y0)#I&x&i)*&Fcs5XR0YDU9_0Q_c=kCv3zt|}^(G1G*Hp}Q z$ZG&{No}iP@Ai!*q)z_hi3g@mMZ+Q9#R)Wgpro`LCY8dZs{L5o%O93-vv5?$={`xb zzBFTo3wtWD>9u$kyp`8>Z|}Qt+kc(JgC|0pJUs0iR_ghjE#D^0B{`_lbr3C2kPIlE znGc+wYvZf{DUc$UXjrmMEwtX|n2_X6zU(IX$I`w_$K06#AgfjsdK*`+-U@@I`yRdi zSd>#+1roA`%gxROb}p9yyVb*RGC#`uP3nH-+R6*r2w26@Pqy%QzB{(Sac__ke9~H5 zRE-a#FVYru`^Fb7aag!Av+TuZJS@_rRFkwYFC4xAUn16%WhJ8A4(|I}SjgGvS=AOG z#PO6Egf7N3Qg`#T)Rugc3Q;aED%%RYDEg)(m1s4e!L=x)wMWN{`iz|4V+~8SET;{3 z|0}1G*hn;Yns5rfsNzqQCO<~L)ZwZ2zzMYGaiCYxKFB9w2d1E)UXBmOPdpV+gWGnllDt&mj`z%#%b4qKQ?yb<%vQv7MzCk37BcvL{q!>L3&AZF{HaTJFZCtDl1~`?QaNasuIw zL#;BC@IY*b4=nCtD?mX_LHj~Sa{VSU(meG$spo69@AzW{nTaaCOp9Sjz8C31*l)JM zy%Z86MH@nSn$LWbh|EJ=!5{8AsO4CjHCHrc&)v)YgJ$2zTxA;NdleCQ%;XHWlh38R zc=r3$P{6v^du9!_SsICMP~p38J31vl2mz|0Omv#oRRa=rSr z4L9w?9OM^qDYW{mQ14ySlF#Rr-^S(%_~NTm`AUs9BTJqSPoqI>t*Gk&7Vd%HjJPeB!igo=$wKGZmt zG1aBB!TSz6HN)n#ZMvA)b^x76ZP@4aho z`E2g&JK3Acze@(Gn(BFn-J%bgs4ppc4#xpsH7MP&@(nrT=LMf@zy014-B#OB0k`65 zP4$icn2nsFz@Lapm)O^Vbh}H9L}D-z)p+Mmy))&3pwDPttp4h96QZv*93wouR=e+b zK|GpVd5=cPlnPy|vsRSjmfa{mEiqz!?H(@BVD(hD%|j`eG@BwjA@Dg)Q#_kJ`)g1q zn&QTlK{Djpn?(6z$0Bm&CN}DA?+_ud-mcpjX*wJEBR+`JJT*$)Bl#RSlt8X*|GrI(4W2iXa5k9+q4h ztWFfXecQ13WTo~kx#L^bI>|p%CZv_*75Y(iw+x{EPrHNO^t@rSYiTbRpEFc6Aw;%g zrsLVq_QaRI-{oVH!Eb=K;Vw->!9GlJIHyqL39)As+GgWAPMr4`?Kzl)g12BRM8 zVp_R7pkxi-zds1{Ba>g=j>! z5r0$@>^7*++kJc4_K>DOsmWQ8pV4B{T2uw@SgqNlH8k?jjCVvSiS$xnS9KSf^wP72 z*?YgC0^V?5Qa7fkJR607_orBZDw`%d<)WaF^_r>yQ?LZvY6g^3CX)Fz$QEh2X-^be zFUJ!b?5@QwK7Cp^OnqV3C#9cUT@@YT+THgCMK*QQ~`XueVo^mey)N(@qBg!rJgZ}n{$5h5~7-RFZ7lB(=fpLQJ ziqUw_{R8;U$T%ev0Fd%(K2UvHHJnU5^yuhnPg;?)Ju!>X!uU^FNUS|h>Zmh(UUdLtLPXq1hV6Amx8b=DF- zEeK}&uT@>C2VcwA*9F9FzIx)UQ65(mXNR;4u?w{u`?9|uekYxFv*fXl1XBWwfv540 z4}`jq3HQaSg5A5jXw~}tm+M3)-I)T?Ns^>LB*&;*uZU9fz3Tpp63x0E^j4uSF>BcE zUB0!&`h$Fh2G#T#%{OB{?e|ap*TnnS@cQBY}HuPfTrbC3VuW)&x z0CxO)TXzNTIzDBTH81dg0R;&9_s?El)Cd?}-O)hj24yrFjO4jNQ4vglQQ;^y!osuu zlzI4~cl@WXHf0;e5zLc1*$CDQ!wHPx4RJU{j!Ba67Z3o8?&JB`buUMn!_2jMhQvPG`PmoXI|OwJCjg%sa*N&s;oEz&}dUom78PPyVYOW%gd< zp1V=M`xWQMv=kZ*kayxAQseCdzI8-ebTHmbaIPv3@yLGX9)0o9*{Ai^*i zlY8+-Q%)cZCkP+{u2V(@kr*O^7ADyhxP=t;e}9!V07k8gxSjx4>e4qVwXOp2(Yi!> zssnhGTPAi=pAHtS=T_fnvQJ!LN`HF(YeQz9@<07XA9;z5_>$-M=X3`@Wk9-vdy9LF zdyRYE9rZt<1vlEA8{k!&zA3^NFBqDG6uyb1Ts3KgzF!$}M)8!BepGtrw>D*eeMyJE z_`5tRa0I6`fXWVnw{tkmU?n4j1GQ}nL1*L8q?@4PlI4Q#t|#kOdW>+ph1LaJ*PZr) z{UAWk;7?%a^NkbR>GK&xd;hub8v5+*!+tcXcF4r9-P!k_%g%^{kDoDco{w*HaW8RC zac}hvPxAF!BP#)lIkeM0=&T_Y1*k zJ!DcV;NvqR;urB-9lXoe9N&%jy8^!({(X4aoe_}7Vj_q4*ZCA)>0y#r#BVyfn4wpu z{|N&|A8}dn_9c;-rzUwOUBucuLB^Ed$=#%LrHGy=>C zlsZLXShws#^;S+_DFt?WOi7LE#uMygO^(j(FTTonf4J17e=+8b^gW~NhR!?v$syxU zyuIJ3BQEci?*A|PITU()M*ggl=HPWE?g8!v?g{QqH~4=i%dU)oJQnY*@g@Ub;Anaz zqXNJvvMEyZ<(eAes9r<+pV0sGLoYy7Etz)m&xYN4#~18Ub%G3XKZ* z1taob0HPxUzWBk!@F41a2t(ChQVEW(`-kAUrcfd02Bb&-(|}&b6&+Okwf&DQJ*Cf= z^55w5^Woh1Spw1;TobMh*NAJCYsR(X zGvKq}GvTx0GZu>W?pvL1@c+&iHG(@T;JtRz42Y6Q5il`Co*bkiL&yk$l&NRxQ2v=f ze~!MN+kaTU&uQwBFvtfJ_O+=PACrzPpyS`#;y;q$JYFNb3p}nB*Nkh&XGlVi&+10| z?zcMspi7}q!8HTE@Ii`zFMp6Ht0C}bJ&;P^tw}B=;337pq!KV90t3v0IUB9MK$kJC228;@CI`&V_U0+_(l@3$96l$F<^`aqajFN$9(yefQF3*_9cP zBIuk!4WT0heh7xN0^lLVK-2|{h`<0dNC~8P)1oF(A!567x1lfg!M;ICj)i05*f&NExCV{z3cTj@xb|-7yO$5VxMnD12pu5+8qx~9HUxl(x|moZ0s~A$V?c^8;{dE0 zMTMvhxoz4H`(R%j1INNKacrCe=fXL0Zd`*#_(H&UL*KppO^d>lG(;g&AnF1}H3yz| xuy-%}#NtA@D{~~JFc*S4spN6Hf&Yk>{}0|lR~(qLx?KPO002ovPDHLkV1h!TP;LMK From 975f46310cfdc24c66af7bf24fe189b62621823c Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 10 Sep 2024 19:30:35 +0800 Subject: [PATCH 118/144] Minor UI tweaks --- .../ui/components/home/IconPreviewGrid.kt | 12 ++---- .../ui/components/home/NewIconsCard.kt | 11 ++++-- .../lawnicons/ui/destination/About.kt | 6 ++- .../lawnicons/ui/destination/Home.kt | 13 +++++-- .../lawnicons/util/ContextExtensions.kt | 4 +- app/src/main/res/drawable/new_releases.xml | 37 +++++++++---------- 6 files changed, 47 insertions(+), 36 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt index 1962770c55d..71579804566 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconPreviewGrid.kt @@ -24,8 +24,7 @@ import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.GridItemSpan -import androidx.compose.foundation.lazy.grid.LazyGridItemScope +import androidx.compose.foundation.lazy.grid.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -96,7 +95,7 @@ fun IconPreviewGrid( contentPadding: IconPreviewGridPadding = IconPreviewGridPadding.Defaults, isIconPicker: Boolean = false, gridState: LazyGridState = rememberLazyGridState(), - otherContent: @Composable (LazyGridItemScope.() -> Unit) = {}, + otherContent: (LazyGridScope.() -> Unit) = {}, ) { val indexOfFirstItem by remember { derivedStateOf { gridState.firstVisibleItemIndex } } val letter = iconInfo[indexOfFirstItem].label[0].uppercase() @@ -120,11 +119,7 @@ fun IconPreviewGrid( ), state = gridState, ) { - item( - span = { GridItemSpan(maxLineSpan) }, - ) { - otherContent() - } + otherContent() items( items = iconInfo, contentType = { "icon_preview" }, @@ -241,6 +236,7 @@ fun AppBarListItem(modifier: Modifier = Modifier) { contentDescription = stringResource(id = R.string.app_name), modifier = Modifier .size(36.dp) + .clip(CircleShape) .combinedClickable( onClick = {}, onLongClick = { diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt index adef79bb553..894729a12da 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt @@ -20,6 +20,7 @@ import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons @@ -38,7 +39,6 @@ import androidx.compose.ui.unit.dp import app.lawnchair.lawnicons.BuildConfig import app.lawnchair.lawnicons.R import app.lawnchair.lawnicons.repository.preferenceManager -import app.lawnchair.lawnicons.ui.components.core.Card import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons @@ -67,8 +67,13 @@ fun NewIconsCard( modifier: Modifier = Modifier, ) { AnimatedVisibility(visible) { - Card( - modifier = modifier, + Surface( + color = MaterialTheme.colorScheme.surfaceContainer, + shape = MaterialTheme.shapes.extraLarge, + modifier = modifier + .padding(horizontal = 8.dp) + .padding(bottom = 12.dp) + .fillMaxWidth(), ) { Row( verticalAlignment = Alignment.CenterVertically, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index 8f94c65b0e0..331f4bec9b9 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Star import androidx.compose.material3.Icon @@ -19,6 +20,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalInspectionMode @@ -103,7 +105,9 @@ private fun About( Image( bitmap = context.appIcon().asImageBitmap(), contentDescription = stringResource(id = R.string.app_name), - modifier = Modifier.size(72.dp), + modifier = Modifier + .size(72.dp) + .clip(CircleShape), ) } Text( diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 447e22ae4f7..6db59cfbf7d 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -6,6 +6,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.rememberLazyGridState import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Scaffold @@ -145,11 +146,17 @@ private fun Home( isIconPicker = isIconPicker, gridState = lazyGridState, ) { - Column { - if (!isExpandedScreen) { + if (!isExpandedScreen) { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { AppBarListItem() } - if (newIconsInfoModel.iconCount != 0) { + } + if (newIconsInfoModel.iconCount != 0) { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { NewIconsCard(onNavigateToNewIcons) } } diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt index 508d2b6eaac..bd119f8858c 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt @@ -4,4 +4,6 @@ import android.content.Context import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap -fun Context.appIcon(): Bitmap = packageManager.getApplicationIcon(packageName).toBitmap() +fun Context.appIcon(): Bitmap = packageManager + .getApplicationIcon(packageName) + .toBitmap() diff --git a/app/src/main/res/drawable/new_releases.xml b/app/src/main/res/drawable/new_releases.xml index 9eec8a7b8eb..c1dc3184df1 100644 --- a/app/src/main/res/drawable/new_releases.xml +++ b/app/src/main/res/drawable/new_releases.xml @@ -1,21 +1,18 @@ - - - - - - + + + + From 86c1bbb2197e17ac3d57a16859e9ed15bea7dd3e Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:22:08 +0800 Subject: [PATCH 119/144] Release workflow tweaks --- .github/workflows/build_release_apk.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build_release_apk.yml b/.github/workflows/build_release_apk.yml index e20ea88a5e6..dad54cb5bad 100644 --- a/.github/workflows/build_release_apk.yml +++ b/.github/workflows/build_release_apk.yml @@ -1,10 +1,8 @@ +# TODO: Add signing key and build app bundle name: Build release APK on: workflow_dispatch: - push: - branches: - - main jobs: build-release-apk: From 6763e5e360ec13e64205383c4828746a92e61a7c Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:49:08 +0800 Subject: [PATCH 120/144] Fix workflow error on PRs --- .github/workflows/build_debug_apk.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_debug_apk.yml b/.github/workflows/build_debug_apk.yml index 2cb49104ead..c83c617e15e 100644 --- a/.github/workflows/build_debug_apk.yml +++ b/.github/workflows/build_debug_apk.yml @@ -16,8 +16,9 @@ jobs: uses: actions/checkout@v4 with: submodules: true - - name: Fetch main branch - run: git fetch origin main:main + - name: Fetch all needed branches + run: git fetch origin main:main && git fetch origin develop:develop + continue-on-error: true - uses: actions/setup-java@v4 with: distribution: 'zulu' From dce842b7709b7afa30ff6bfeb09fce8c7a2617a2 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 13:40:11 +0000 Subject: [PATCH 121/144] New Crowdin translations by GitHub Action (#2319) Co-authored-by: Crowdin Bot --- app/src/main/res/values-af-rZA/strings.xml | 5 ++ app/src/main/res/values-ar-rSA/strings.xml | 5 ++ app/src/main/res/values-ca-rES/strings.xml | 5 ++ app/src/main/res/values-cs-rCZ/strings.xml | 5 ++ app/src/main/res/values-da-rDK/strings.xml | 5 ++ app/src/main/res/values-de-rDE/strings.xml | 5 ++ app/src/main/res/values-el-rGR/strings.xml | 57 +++++++++++---------- app/src/main/res/values-en-rUS/strings.xml | 7 ++- app/src/main/res/values-es-rES/strings.xml | 57 +++++++++++---------- app/src/main/res/values-fi-rFI/strings.xml | 5 ++ app/src/main/res/values-fil-rPH/strings.xml | 5 ++ app/src/main/res/values-fr-rFR/strings.xml | 29 ++++++----- app/src/main/res/values-hi-rIN/strings.xml | 5 ++ app/src/main/res/values-hu-rHU/strings.xml | 57 +++++++++++---------- app/src/main/res/values-in-rID/strings.xml | 5 ++ app/src/main/res/values-it-rIT/strings.xml | 5 ++ app/src/main/res/values-iw-rIL/strings.xml | 5 ++ app/src/main/res/values-ja-rJP/strings.xml | 23 +++++---- app/src/main/res/values-ko-rKR/strings.xml | 7 ++- app/src/main/res/values-mr-rIN/strings.xml | 5 ++ app/src/main/res/values-nl-rNL/strings.xml | 5 ++ app/src/main/res/values-no-rNO/strings.xml | 5 ++ app/src/main/res/values-pl-rPL/strings.xml | 29 ++++++----- app/src/main/res/values-pt-rBR/strings.xml | 5 ++ app/src/main/res/values-pt-rPT/strings.xml | 5 ++ app/src/main/res/values-ro-rRO/strings.xml | 5 ++ app/src/main/res/values-ru-rRU/strings.xml | 57 +++++++++++---------- app/src/main/res/values-sv-rSE/strings.xml | 5 ++ app/src/main/res/values-tr-rTR/strings.xml | 39 ++++++++------ app/src/main/res/values-uk-rUA/strings.xml | 21 +++++--- app/src/main/res/values-vi-rVN/strings.xml | 5 ++ app/src/main/res/values-zh-rCN/strings.xml | 55 +++++++++++--------- app/src/main/res/values-zh-rTW/strings.xml | 5 ++ 33 files changed, 354 insertions(+), 189 deletions(-) diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml index 2c96f6ec44c..90b7bb59143 100644 --- a/app/src/main/res/values-af-rZA/strings.xml +++ b/app/src/main/res/values-af-rZA/strings.xml @@ -33,6 +33,7 @@ Core app Icons + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ar-rSA/strings.xml b/app/src/main/res/values-ar-rSA/strings.xml index ef89bd8810e..5e5a5e3c238 100644 --- a/app/src/main/res/values-ar-rSA/strings.xml +++ b/app/src/main/res/values-ar-rSA/strings.xml @@ -33,6 +33,7 @@ Core app الأيقونات + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + مسح + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ca-rES/strings.xml b/app/src/main/res/values-ca-rES/strings.xml index 21ae600a6da..866302f2fa1 100644 --- a/app/src/main/res/values-ca-rES/strings.xml +++ b/app/src/main/res/values-ca-rES/strings.xml @@ -33,6 +33,7 @@ Core app Icones + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Netejar + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index f236fefd641..4801f551e89 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -33,6 +33,7 @@ Core app Ikony + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-da-rDK/strings.xml b/app/src/main/res/values-da-rDK/strings.xml index a07187d65d6..f027ffb954f 100644 --- a/app/src/main/res/values-da-rDK/strings.xml +++ b/app/src/main/res/values-da-rDK/strings.xml @@ -33,6 +33,7 @@ Core app Ikoner + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index c6ed397c757..029a7e0da26 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -33,6 +33,7 @@ Kern-App Symbole + Infrastructure Besonderer Dank @@ -60,6 +61,10 @@ In Zwischenablage kopieren Text kopiert + Request missing icons from the bottom bar Details der Symbolanfrage in die Zwischenablage kopiert. Um sie anzufragen, übertrage die Details in das Formular. Formular öffnen + Leeren + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 3041ae315d7..43469a3e3b7 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -3,63 +3,68 @@ - Version %s + Έκδοση %s - Search through %d icons - Pick an icon + Αναζήτηση μέσω %d εικονιδίων + Επιλέξτε ένα εικονίδιο Αναζήτηση - %s not found + %s δεν βρέθηκε Πληροφορίες - Icon request form + Φόρμα αιτήματος εικονιδίων - Contributors + Συντελεστές - Core contributors + Βασικοί συντελεστές - See all contributors + Προβολή όλων των συνεισφερόντων - View on GitHub + Προβολή στο GitHub - Share details + Κοινή χρήση λεπτομερειών - Core app + Πυρήνας εφαρμογής Εικονίδια + Infrastructure - Special thanks + Ιδιαίτερες ευχαριστίες - For inspiring the app icon + Για να εμπνευστείτε το εικονίδιο της εφαρμογής - For naming the app + Για να ονομάσετε την εφαρμογή - Open-source licenses + Άδειες λογισμικού ανοικτού κώδικα - Name + Όνομα - Drawable + Σχέδιο - Component name + Όνομα στοιχείου - Mapped components + Αντιστοιχισμένα στοιχεία - If the icon is outdated due to rebranding, create an issue on GitHub. + Αν το εικονίδιο είναι ξεπερασμένο λόγω επανασχεδιασμού από τον προγραμματιστή του, δημιουργήστε ένα νέο ζήτημα στο GitHub. - Toggle visibility of contents + Εναλλαγή ορατότητας των περιεχομένων - Request icons - Copy to clipboard - Copied text + Αίτηση εικονιδίων + Αντιγραφή στο πρόχειρο + Αντιγραμμένο κείμενο - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + Request missing icons from the bottom bar + Αντιγράφηκαν λεπτομέρειες αιτήματος εικονιδίου στο πρόχειρο. Για να τα ζητήσετε, υποβάλετε τα στοιχεία στη φόρμα. + Άνοιγμα φόρμας + Εκκαθάριση + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml index 17cf6c8d98f..72a16c0059c 100644 --- a/app/src/main/res/values-en-rUS/strings.xml +++ b/app/src/main/res/values-en-rUS/strings.xml @@ -7,7 +7,7 @@ - Search through %d icons + Pick an icon Search @@ -33,6 +33,7 @@ Core app Icons + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index a29653b6654..d51cfff663e 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -3,63 +3,68 @@ - Version %s + Versión %s - Search through %d icons - Pick an icon + Buscar a través de %d iconos + Escoge un icono Buscar - %s not found + No se ha encontrado %s Acerca de - Icon request form + Formulario de solicitud de iconos - Contributors + Contribuyentes - Core contributors + Colaboradores principales - See all contributors + Ver a todos los contribuyentes - View on GitHub + Ver en GitHub - Share details + Compartir los detalles - Core app + App principal Iconos + Infraestructura - Special thanks + Agradecimiento especial - For inspiring the app icon + Por inspirar el icono de la aplicación - For naming the app + Por nombrar la aplicación - Open-source licenses + Licencias de código abierto - Name + Nombre - Drawable + Elemento gráfico - Component name + Nombre del componente - Mapped components + Componentes asignados - If the icon is outdated due to rebranding, create an issue on GitHub. + Si el icono está obsoleto debido a un cambio significativo, cree un problema en GitHub. - Toggle visibility of contents + Cambiar visibilidad de los contenidos - Request icons - Copy to clipboard - Copied text + Solicitar iconos + Copiar al portapapeles + Texto copiado - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + Solicitar iconos que faltan en la barra inferior + Solicitar detalles del icono copiado al portapapeles. Para solicitarlos, envíe los detalles al formulario. + Abrir formulario + Borrar + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-fi-rFI/strings.xml b/app/src/main/res/values-fi-rFI/strings.xml index c9fef536a95..c340555cff2 100644 --- a/app/src/main/res/values-fi-rFI/strings.xml +++ b/app/src/main/res/values-fi-rFI/strings.xml @@ -33,6 +33,7 @@ Core app Kuvakkeet + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-fil-rPH/strings.xml b/app/src/main/res/values-fil-rPH/strings.xml index c8a453a8f0f..d2cbd1f50f0 100644 --- a/app/src/main/res/values-fil-rPH/strings.xml +++ b/app/src/main/res/values-fil-rPH/strings.xml @@ -33,6 +33,7 @@ Core app Mga Icon + Infrastructure Espesyal na pagsasalamat @@ -60,6 +61,10 @@ Kopyahin sa clipboard Kinopya ang teksto + Request missing icons from the bottom bar Nakopya na ang mga detalye tungkol sa ihihiling na icons sa clipboard. Upang hilingin ang mga ito, isumite ang mga detalye sa form. Buksan ang form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 76fc6e5f4fb..b0b4132be25 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -8,7 +8,7 @@ Rechercher parmi %d icônes - Pick an icon + Sélectionner une icône Recherche @@ -29,10 +29,11 @@ Voir sur GitHub - Share details + Partager les détails - Core app + Application principale Icônes + Infrastructure Remerciements spéciaux @@ -44,22 +45,26 @@ Mentions légales - Name + Nom Élément graphique - Component name + Nom du composant Application - If the icon is outdated due to rebranding, create an issue on GitHub. + Si l\'icône est obsolète en raison d\'un changement de marque, veuillez nous aviser sur GitHub. - Toggle visibility of contents + Activer/désactiver la visibilité des contenus - Request icons - Copy to clipboard - Copied text + Demander des icônes + Copier dans le presse-papier + Texte copié - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + Request missing icons from the bottom bar + Détails de la demande d\'icône copiés dans le presse-papiers. Pour les demander, entrez les détails dans le formulaire. + Ouvrir le formulaire + Effacer + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 3184fce8814..41ca1446644 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -33,6 +33,7 @@ Core app चिह्न + Infrastructure विशेष धन्यवाद @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + साफ करें + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index ba7af2b819a..df795c61ba7 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -3,63 +3,68 @@ - Version %s + %s-verzió - Search through %d icons - Pick an icon + Keresés %d ikon között + Bökjön egy ikonra Keresés - %s not found + %s nem található Névjegy - Icon request form + Ikonigénylő lap - Contributors + Közreműködők - Core contributors + Alapvető közreműködők - See all contributors + Az összes közreműködő megtekintése - View on GitHub + Lesse meg a GitHub-on - Share details + Részletek megosztása - Core app + A mag-alkalmazás Ikonok + Infrastruktúra - Special thanks + Speciális köszönet - For inspiring the app icon + Inspiráció az alkalmazásikonhoz - For naming the app + Az alkalmazás elnevezéséhez - Open-source licenses + Nyílt-forráskódú licencek - Name + Név - Drawable + Rajzolható - Component name + A részegység neve - Mapped components + Feltérképezett részek - If the icon is outdated due to rebranding, create an issue on GitHub. + Ha az ikon a márkaváltás miatt elavult, hozzon létre egy bejelentést a GitHubon. - Toggle visibility of contents + A tartalom láthatóságának kapcsolója - Request icons - Copy to clipboard - Copied text + Ikonrendelés + Másolás a vágólapra + Másolt szöveg - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + A hiányzó ikonokat az alsó sávról kérje + Az ikonkérelem részletei a vágólapra másolva. Kéréséhez adja meg a részleteket az űrlapon. + Az űrlap megnyitása + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index 3f09b2b5753..387ebbd0a95 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -33,6 +33,7 @@ Core app Ikon + Infrastructure Terima kasih Khusus @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Bersihkan + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index cb0f69037e7..b7370a30508 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -33,6 +33,7 @@ Core app Icone + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-iw-rIL/strings.xml b/app/src/main/res/values-iw-rIL/strings.xml index 3181c5bbb22..56a09f300e4 100644 --- a/app/src/main/res/values-iw-rIL/strings.xml +++ b/app/src/main/res/values-iw-rIL/strings.xml @@ -33,6 +33,7 @@ Core app סמלים + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + ניקוי + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index f8340bc15e1..b8704ac8c30 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -8,7 +8,7 @@ Search through %d icons - Pick an icon + アイコンを選択する 検索 @@ -18,21 +18,22 @@ - Icon request form + アイコンリクエストフォーム - Contributors + 寄付者 - Core contributors + 主要な寄付者 - See all contributors + 全ての寄付者を見る - View on GitHub + Githubで見る Share details Core app アイコン + Infrastructure Special thanks @@ -56,10 +57,14 @@ Toggle visibility of contents - Request icons - Copy to clipboard - Copied text + アイコンをリクエストする + クリップボードにコピーする + テキストをコピーしました + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + 消去 + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 89abc4a41de..38a40bd9196 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -33,6 +33,7 @@ 코어 앱 아이콘 + Infrastructure Special thanks @@ -50,7 +51,7 @@ 컴포넌트 이름 - Mapped components + 매핑된 컴포넌트 앱 리브랜딩으로 아이콘이 바뀌었다면 GitHub에 이슈를 등록해 주세요. @@ -60,6 +61,10 @@ 클립보드에 복사 텍스트를 복사했습니다. + Request missing icons from the bottom bar 아이콘 요청 정보를 클립보드에 복사했습니다. 아이콘을 요청하려면 세부 정보를 폼에 입력하세요. 폼 열기 + 기록 삭제 + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-mr-rIN/strings.xml b/app/src/main/res/values-mr-rIN/strings.xml index f35f9398a2e..4d277adfa95 100644 --- a/app/src/main/res/values-mr-rIN/strings.xml +++ b/app/src/main/res/values-mr-rIN/strings.xml @@ -33,6 +33,7 @@ Core app चिन्हे + Infrastructure विशेष धन्यवाद @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index 67620cfd5dd..f0222e80719 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -33,6 +33,7 @@ Core app Pictogrammen + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Verwijderen + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-no-rNO/strings.xml b/app/src/main/res/values-no-rNO/strings.xml index bd33741642e..ad88da4dbcc 100644 --- a/app/src/main/res/values-no-rNO/strings.xml +++ b/app/src/main/res/values-no-rNO/strings.xml @@ -33,6 +33,7 @@ Core app Ikoner + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index d5fe76ffd3f..0d6c05e5f33 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -8,7 +8,7 @@ Przeszukaj %d Ikon - Pick an icon + Wybierz ikonkę Szukaj @@ -29,10 +29,11 @@ Zobacz na GitHub - Share details + Udostępnij szczegóły - Core app + Aplikacja bazowa Ikony + Infrastructure Specjalne podziękowania @@ -44,22 +45,26 @@ Podziękowanie - Name + Nazwa Element graficzny - Component name + Nazwa komponentu Pakiet - If the icon is outdated due to rebranding, create an issue on GitHub. + Jeśli ikona jest przestarzała z powodu rebrandingu, utwórz problem na GitHub. - Toggle visibility of contents + Przełącz widoczność treści - Request icons - Copy to clipboard - Copied text + Zażądaj ikon + Skopiuj do schowka + Skopiowany tekst - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + Request missing icons from the bottom bar + Skopiowano szczegóły żądania ikon do schowka. Aby je poprosić, prześlij szczegóły do formularza. + Otwórz formularz + Wyczyść + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index fb2e7ac9e09..0ceff6c8c85 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -33,6 +33,7 @@ Core app Ícones + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Limpar + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index fb2e7ac9e09..0ceff6c8c85 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -33,6 +33,7 @@ Core app Ícones + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Limpar + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 3b950f5c352..05f6e003b5a 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -33,6 +33,7 @@ Core app Pictograme + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Clear + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 038759f7b9a..d3a83b8628a 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -3,63 +3,68 @@ - Version %s + Версия %s - Search through %d icons - Pick an icon + Поиск среди %d иконок + Выберите иконку Поиск - %s not found + Иконки %s не найдено О программе - Icon request form + Форма запроса иконки - Contributors + Участники - Core contributors + Основные участники - See all contributors + Посмотреть всех участников - View on GitHub + Посмотреть на GitHub - Share details + Поделиться - Core app + Основное приложение Иконки + Инфраструктура - Special thanks + Особая благодарность - For inspiring the app icon + За вдохновение для создания иконки приложения - For naming the app + За название для приложения - Open-source licenses + Лицензии проектов с открытым исходным кодом - Name + Имя - Drawable + Изображение - Component name + Название компонента - Mapped components + Связанные компоненты - If the icon is outdated due to rebranding, create an issue on GitHub. + Если иконка устарела из-за проведенного ребрендинга, создайте проблему на GitHub. - Toggle visibility of contents + Переключить видимость контента - Request icons - Copy to clipboard - Copied text + Запросить иконки + Скопировать в буфер обмена + Текст скопирован - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + Запросите недостающие иконки в нижней панели + Подробности запроса иконки были скопированы в буфер обмена. Для отправки запроса, отправьте данные через форму. + Открыть форму + Очистить + Новые иконки в v%1$s + Новые иконки (%1$s) diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index 69e728926d2..a90e0a502e2 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -33,6 +33,7 @@ Core app Ikoner + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Rensa + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 1f3cb6fa825..6f06403f4e3 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -3,50 +3,51 @@ - Version %s + Sürüm %s - Search through %d icons - Pick an icon + %d simgeler arasına arayın + Bir simge seçin Ara - %s not found + %s bulunamadı Hakkında - Icon request form + Simge istek formu - Contributors + Katkıda bulunanlar - Core contributors + Katkıda bulunanlar - See all contributors + Bürün katkıda bulunanları gör - View on GitHub + GitHub\'da görüntüle - Share details + Detayları paylaş - Core app + Çekirdek uygulama Resimleyici + Infrastructure - Special thanks + Teşekkürler - For inspiring the app icon + Uygulama simgesinden esinlenen - For naming the app + Uygulamaya isim veren - Open-source licenses + Açık kaynak kütüphaneleri - Name + İsim - Drawable + Çizilebilir Component name @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Geçmişi temizle + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index 10ee5b370e2..d6216d78f0c 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -7,8 +7,8 @@ - Шукати за %d значками - Вибрати іконку + Шукати серед %d значків + Вибрати значок Пошук @@ -18,12 +18,12 @@ - Форма запиту іконок + Форма запиту значків Автори - Учасники проекту + Ключові учасники проекту Переглянути всіх учасників @@ -33,11 +33,12 @@ Головний додаток Значки + Infrastructure Особлива подяка - Що надихнули іконку застосунка + За натхнення значка застосунку За назву застосунку @@ -52,14 +53,18 @@ Зіставлені компоненти - Якщо іконка застаріла через ребрендінг, створіть проблему на GitHub. + Якщо значок застарів через ребрендинг, створіть проблему на GitHub. Перемкнути видимість вмісту - Запит іконок + Запит значків Скопіювати до буфера обміну Скопійований текст - Скопійовано подробиці до буфера обміну. Щоб зробити запит, додайте деталі у форму. + Запросіть відсутні значки з нижньої панелі + Скопійовано подробиці до буферу обміну. Щоб зробити запит, додайте деталі у форму. Відкрити форму + Очистити + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index d72618aabcc..14b69603e28 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -33,6 +33,7 @@ Core app Biểu tượng + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + Xóa + New icons in v%1$s + New icons (%1$s) diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cd45165288a..13724a3e451 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -3,63 +3,68 @@ - Version %s + 版本:%s - Search through %d icons - Pick an icon + 搜索 %d 个图标 + 选择图标 搜索 - %s not found + 未找到 %s 关于 - Icon request form + 图标申请表 - Contributors + 贡献者 - Core contributors + 核心贡献者 - See all contributors + 查看所有贡献者 - View on GitHub + 在 GitHub 中查看 - Share details + 分享详细信息 - Core app + 核心功能开发 图标 + 基础架构 - Special thanks + 特别感谢 - For inspiring the app icon + 为应用图标设计提供灵感 - For naming the app + 为此应用程序命名 - Open-source licenses + 开源许可 - Name + 名称 Drawable - Component name + 组件名称 - Mapped components + 映射的组件 - If the icon is outdated due to rebranding, create an issue on GitHub. + 如果图标过时,请在 GitHub 上提交 issue - Toggle visibility of contents + 切换内容可见性 - Request icons - Copy to clipboard - Copied text + 请求图标 + 复制到剪贴板 + 已复制文本 - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form + 从底栏请求缺失的图标 + 图标申请详情已复制到剪贴板,请将这些详情填写到申请表单中以完成申请。 + 打开表单 + 清除 + v%1$s 中的新图标 + 新图标 (%1$s) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 49ef20d6629..f00bd94c3ea 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -33,6 +33,7 @@ Core app 圖示 + Infrastructure Special thanks @@ -60,6 +61,10 @@ Copy to clipboard Copied text + Request missing icons from the bottom bar Copied icon request details to clipboard. To request them, submit the details into the form. Open form + 清除 + New icons in v%1$s + New icons (%1$s) From 4dc5202177ea242c4a1f67b59369727b19956cd5 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:42:22 +0300 Subject: [PATCH 122/144] +10 links (#2321) --- app/assets/appfilter.xml | 10 ++++++++++ svgs/kinnu.svg | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 087ba214fb5..97ab0d8294f 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -2167,6 +2167,7 @@ + @@ -3146,6 +3147,7 @@ + @@ -4756,6 +4758,7 @@ + @@ -5060,6 +5063,7 @@ + @@ -7991,6 +7995,7 @@ + @@ -8219,6 +8224,7 @@ + @@ -9010,6 +9016,7 @@ + @@ -9689,6 +9696,7 @@ + @@ -10790,6 +10798,7 @@ + @@ -12034,6 +12043,7 @@ + diff --git a/svgs/kinnu.svg b/svgs/kinnu.svg index 3618bec4fe1..c48b2412bcd 100644 --- a/svgs/kinnu.svg +++ b/svgs/kinnu.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file From d40f835058bbdb66d1fe3a4a6044963513347728 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:43:27 +0800 Subject: [PATCH 123/144] `send_notifications.py` - don't fail on invalid rev-list --- send_notifications.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/send_notifications.py b/send_notifications.py index 4bc8d00ce80..fc9fb535974 100644 --- a/send_notifications.py +++ b/send_notifications.py @@ -4,6 +4,8 @@ import sys import requests +# TODO: Lessen repetition + github_event_before = os.getenv('GITHUB_EVENT_BEFORE') github_sha = os.getenv('GITHUB_SHA') github_repository = os.getenv('GITHUB_REPOSITORY') @@ -46,15 +48,18 @@ def send_document_to_ci_channel(document): def telegram_commit_message(commits, commits_range): overview_link = f'{github_link()}compare/{commits_range}' - overview_link_tag = f'''{len(commits)} new commit{'s' if len(commits) > 1 else ''}''' + overview_link_tag = f'''{len(commits)} new commit{'s' if len(commits) > 1 else 'New changes'}''' message = f'''🔨 {overview_link_tag} to lawnicons:{github_ref}:\n''' - for commit in reversed(commits): - commit_message = commit.message.split('\n')[0] - commit_link = f'{github_link()}commit/{commit.hexsha}' - commit_link_tag = f'{repository.git.rev_parse(commit.hexsha, short=7)}' - encoded_message = html.escape(commit_message) - message += f'\n• {commit_link_tag}: {encoded_message}' + try: + for commit in reversed(commits): + commit_message = commit.message.split('\n')[0] + commit_link = f'{github_link()}commit/{commit.hexsha}' + commit_link_tag = f'{repository.git.rev_parse(commit.hexsha, short=7)}' + encoded_message = html.escape(commit_message) + message += f'\n• {commit_link_tag}: {encoded_message}' + except: + message += '\n• Failed to get commit information (likely due to force-push).' return message # Discord @@ -81,15 +86,18 @@ def send_document_to_builds_channel(document): def discord_commit_message(commits, commits_range): overview_link = f'{github_link()}compare/{commits_range}>' - overview_link_tag = f'''[{len(commits)} new commit{'s' if len(commits) > 1 else ''}]({overview_link})''' + overview_link_tag = f'''[{len(commits)} new commit{'s' if len(commits) > 1 else 'New changes'}]({overview_link})''' message = f'''**🔨 {overview_link_tag} to `lawnicons:{github_ref}`:**\n''' - for commit in reversed(commits): - commit_message = commit.message.split('\n')[0] - commit_link = f'{github_link()}commit/{commit.hexsha}>' - commit_link_tag = f'[{repository.git.rev_parse(commit.hexsha, short=7)}]({commit_link})' - encoded_message = html.escape(commit_message) - message += f'\n* {commit_link_tag}: {encoded_message}' + try: + for commit in reversed(commits): + commit_message = commit.message.split('\n')[0] + commit_link = f'{github_link()}commit/{commit.hexsha}>' + commit_link_tag = f'[{repository.git.rev_parse(commit.hexsha, short=7)}]({commit_link})' + encoded_message = html.escape(commit_message) + message += f'\n* {commit_link_tag}: {encoded_message}' + except: + message += '\n• _Failed to get commit information (likely due to force-push)._' return message repository = git.Repo('.') From 7a7aa1845a7d4f156747e29727fbc44896810ced Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:05:03 +0800 Subject: [PATCH 124/144] Update dependency androidx.compose:compose-bom to v2024.09.01 (#2322) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- app/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ca1b7c15666..cddee9531d8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -145,7 +145,7 @@ dependencies { implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.activity:activity-compose:1.9.2") - implementation(platform("androidx.compose:compose-bom:2024.09.00")) + implementation(platform("androidx.compose:compose-bom:2024.09.01")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.ui:ui-util") From 566217bfa8d66ff69291313f6919fd17c3c93d0d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:05:13 +0800 Subject: [PATCH 125/144] Update plugin com.gradle.develocity to v3.18.1 (#2320) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- settings.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ac7d615286..5db0dbe5893 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -13,7 +13,7 @@ pluginManagement { // https://docs.gradle.com/enterprise/gradle-plugin/ plugins { - id("com.gradle.develocity") version "3.18" + id("com.gradle.develocity") version "3.18.1" } develocity { From 89a5c3e422791607670192db0970e461952468e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:09:58 +0800 Subject: [PATCH 126/144] Update dependency io.nlopez.compose.rules:ktlint to v0.4.12 (#2318) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 85c2d418d08..6522fc06524 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,7 +31,7 @@ allprojects { target("src/**/*.kt") ktlint().customRuleSets( listOf( - "io.nlopez.compose.rules:ktlint:0.4.11", + "io.nlopez.compose.rules:ktlint:0.4.12", ), ).editorConfigOverride( mapOf( From ae64961414ea172c755a3502e1a2aa8151977c1a Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Wed, 11 Sep 2024 22:34:14 +0800 Subject: [PATCH 127/144] Update icons * Fix and re-add monochrome icon * Update splashscreen icon * Fix clipping of app icon on certain devices --- .../lawnicons/util/ContextExtensions.kt | 5 +- .../res/drawable/ic_launcher_monochrome.xml | 14 ++- app/src/main/res/drawable/splashscreen.xml | 112 +++++++----------- .../res/mipmap-anydpi-v26/ic_launcher.xml | 3 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 3 +- 5 files changed, 58 insertions(+), 79 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt index bd119f8858c..51973048fe3 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt @@ -3,7 +3,8 @@ package app.lawnchair.lawnicons.util import android.content.Context import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap +import app.lawnchair.lawnicons.R -fun Context.appIcon(): Bitmap = packageManager - .getApplicationIcon(packageName) +fun Context.appIcon(): Bitmap = (this.resources.getDrawable(R.mipmap.ic_launcher, this.theme) + ?: packageManager.getApplicationIcon(packageName)) .toBitmap() diff --git a/app/src/main/res/drawable/ic_launcher_monochrome.xml b/app/src/main/res/drawable/ic_launcher_monochrome.xml index 09b1121b01f..73a1df000ed 100644 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -3,8 +3,14 @@ android:height="108dp" android:viewportWidth="108" android:viewportHeight="108"> - + + + diff --git a/app/src/main/res/drawable/splashscreen.xml b/app/src/main/res/drawable/splashscreen.xml index c6fbe0b706d..14294fe5807 100644 --- a/app/src/main/res/drawable/splashscreen.xml +++ b/app/src/main/res/drawable/splashscreen.xml @@ -4,75 +4,45 @@ android:height="240dp" android:viewportWidth="240" android:viewportHeight="240"> - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index bbd3e021239..e628350bb06 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index bbd3e021239..e628350bb06 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -2,4 +2,5 @@ - \ No newline at end of file + + From f028993e8ddf93b396f328af2d284e8aed17abbc Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 12 Sep 2024 05:08:03 +0800 Subject: [PATCH 128/144] Fix style --- .../app/lawnchair/lawnicons/util/ContextExtensions.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt index 51973048fe3..4de2ff69773 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt @@ -5,6 +5,8 @@ import android.graphics.Bitmap import androidx.core.graphics.drawable.toBitmap import app.lawnchair.lawnicons.R -fun Context.appIcon(): Bitmap = (this.resources.getDrawable(R.mipmap.ic_launcher, this.theme) - ?: packageManager.getApplicationIcon(packageName)) +fun Context.appIcon(): Bitmap = ( + this.resources.getDrawable(R.mipmap.ic_launcher, this.theme) + ?: packageManager.getApplicationIcon(packageName) + ) .toBitmap() From 2422ab5d6791dbe140aa8f50f2056c3ee9b3655e Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Thu, 12 Sep 2024 05:39:35 +0800 Subject: [PATCH 129/144] `send_notifications.py` - remove unnecessary text --- send_notifications.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/send_notifications.py b/send_notifications.py index fc9fb535974..2072aaa0c18 100644 --- a/send_notifications.py +++ b/send_notifications.py @@ -48,7 +48,7 @@ def send_document_to_ci_channel(document): def telegram_commit_message(commits, commits_range): overview_link = f'{github_link()}compare/{commits_range}' - overview_link_tag = f'''{len(commits)} new commit{'s' if len(commits) > 1 else 'New changes'}''' + overview_link_tag = f'''{len(commits)} new commit{'s' if len(commits) > 1 else ''}''' message = f'''🔨 {overview_link_tag} to lawnicons:{github_ref}:\n''' try: @@ -86,7 +86,7 @@ def send_document_to_builds_channel(document): def discord_commit_message(commits, commits_range): overview_link = f'{github_link()}compare/{commits_range}>' - overview_link_tag = f'''[{len(commits)} new commit{'s' if len(commits) > 1 else 'New changes'}]({overview_link})''' + overview_link_tag = f'''[{len(commits)} new commit{'s' if len(commits) > 1 else ''}]({overview_link})''' message = f'''**🔨 {overview_link_tag} to `lawnicons:{github_ref}`:**\n''' try: @@ -107,7 +107,7 @@ def discord_commit_message(commits, commits_range): commits = list(repository.iter_commits(commits_range)) except git.exc.GitCommandError as error: print(f"Error fetching commits: {error}") - exit(1) + exit() telegram_message = telegram_commit_message(commits, commits_range) discord_message = discord_commit_message(commits, commits_range) From c15f860fa49e9c84f740ee1574022f6a9b50a64d Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 12 Sep 2024 01:27:24 +0300 Subject: [PATCH 130/144] [Barter 6] +100 icons: Birbank, My Galaxy, Wuthering Waves (#2323) --- app/assets/appfilter.xml | 104 +++++++++++++++++++++++++- svgs/_365scores.svg | 1 + svgs/act_fibernet.svg | 1 + svgs/action.svg | 1 + svgs/adobe_creative_cloud.svg | 1 + svgs/agricultural_bank_of_china.svg | 1 + svgs/ampereflow.svg | 1 + svgs/anacity_in.svg | 1 + svgs/asus_tips.svg | 1 + svgs/birbank.svg | 1 + svgs/brother_print_service_plugin.svg | 1 + svgs/buy_me_a_coffee.svg | 1 + svgs/bz_reminder.svg | 1 + svgs/bz_reminder_pro.svg | 1 + svgs/call_of_duty_warzone.svg | 1 + svgs/calorie_counter.svg | 1 + svgs/cara.svg | 1 + svgs/castro_premium.svg | 1 + svgs/comatose.svg | 1 + svgs/cpu_monitor.svg | 1 + svgs/darker.svg | 1 + svgs/delhivery.svg | 1 + svgs/dicio_assistant.svg | 1 + svgs/disky.svg | 1 + svgs/exnova.svg | 1 + svgs/federal_bank.svg | 1 + svgs/finshell_pay.svg | 1 + svgs/focus_video.svg | 1 + svgs/formulia.svg | 1 + svgs/freecodecamp.svg | 1 + svgs/freetube.svg | 1 + svgs/fuhrerschein.svg | 1 + svgs/goodmoney.svg | 1 + svgs/groovifi.svg | 1 + svgs/huawei_video.svg | 1 + svgs/iaca_laboratorios.svg | 1 + svgs/ilovepdf.svg | 1 + svgs/incognito_browser.svg | 1 + svgs/infomaniak_kdrive.svg | 1 + svgs/jiofinance.svg | 1 + svgs/jupiter.svg | 1 + svgs/kate_mobile.svg | 1 + svgs/kaufland.svg | 1 + svgs/koshelek.svg | 1 + svgs/manga_dogs.svg | 1 + svgs/meeye_icons.svg | 1 + svgs/mi_community.svg | 1 + svgs/mods_maps_for_minecraft_pe.svg | 1 + svgs/mostaza.svg | 1 + svgs/motohub.svg | 1 + svgs/my_app_list.svg | 1 + svgs/my_galaxy.svg | 1 + svgs/naranja_x.svg | 1 + svgs/neostumbler.svg | 1 + svgs/nfcgate.svg | 1 + svgs/notes_notepad.svg | 1 + svgs/nulls_brawl.svg | 1 + svgs/orgzly_revived.svg | 1 + svgs/oss_card_wallet.svg | 1 + svgs/packmate.svg | 1 + svgs/pascals_wager.svg | 1 + svgs/payoneer.svg | 1 + svgs/pi_browser.svg | 1 + svgs/pikmin_bloom.svg | 1 + svgs/pixelcut.svg | 1 + svgs/plants_vs_zombies_2.svg | 1 + svgs/plugin_voicegpt.svg | 1 + svgs/postparty.svg | 1 + svgs/prequel.svg | 1 + svgs/proton_wallet.svg | 1 + svgs/raven.svg | 1 + svgs/remote_for_android_tv.svg | 1 + svgs/ridmik_keyboard.svg | 1 + svgs/rise_up_balloon_game.svg | 1 + svgs/robinhood.svg | 1 + svgs/root_checker.svg | 1 + svgs/rush.svg | 1 + svgs/safetynet.svg | 1 + svgs/schoology.svg | 1 + svgs/skroutz.svg | 1 + svgs/solar_smash.svg | 1 + svgs/spamblocker.svg | 1 + svgs/squad_busters.svg | 1 + svgs/standoff_2.svg | 1 + svgs/superimage_pro.svg | 1 + svgs/tipatch.svg | 1 + svgs/tubi.svg | 1 + svgs/unit_converter.svg | 1 + svgs/velociraptor.svg | 1 + svgs/vitune.svg | 1 + svgs/voice_access.svg | 1 + svgs/vpn_fast_proxy_secure.svg | 1 + svgs/vrchat.svg | 1 + svgs/vtb.svg | 1 + svgs/wanderlog.svg | 1 + svgs/whicons.svg | 1 + svgs/world_tv.svg | 1 + svgs/wuthering_waves.svg | 1 + svgs/xapk_installer.svg | 1 + svgs/yandex_with_alice.svg | 1 + svgs/zipxtract_fd.svg | 1 + 101 files changed, 202 insertions(+), 2 deletions(-) create mode 100644 svgs/_365scores.svg create mode 100644 svgs/act_fibernet.svg create mode 100644 svgs/action.svg create mode 100644 svgs/adobe_creative_cloud.svg create mode 100644 svgs/agricultural_bank_of_china.svg create mode 100644 svgs/ampereflow.svg create mode 100644 svgs/anacity_in.svg create mode 100644 svgs/asus_tips.svg create mode 100644 svgs/birbank.svg create mode 100644 svgs/brother_print_service_plugin.svg create mode 100644 svgs/buy_me_a_coffee.svg create mode 100644 svgs/bz_reminder.svg create mode 100644 svgs/bz_reminder_pro.svg create mode 100644 svgs/call_of_duty_warzone.svg create mode 100644 svgs/calorie_counter.svg create mode 100644 svgs/cara.svg create mode 100644 svgs/castro_premium.svg create mode 100644 svgs/comatose.svg create mode 100644 svgs/cpu_monitor.svg create mode 100644 svgs/darker.svg create mode 100644 svgs/delhivery.svg create mode 100644 svgs/dicio_assistant.svg create mode 100644 svgs/disky.svg create mode 100644 svgs/exnova.svg create mode 100644 svgs/federal_bank.svg create mode 100644 svgs/finshell_pay.svg create mode 100644 svgs/focus_video.svg create mode 100644 svgs/formulia.svg create mode 100644 svgs/freecodecamp.svg create mode 100644 svgs/freetube.svg create mode 100644 svgs/fuhrerschein.svg create mode 100644 svgs/goodmoney.svg create mode 100644 svgs/groovifi.svg create mode 100644 svgs/huawei_video.svg create mode 100644 svgs/iaca_laboratorios.svg create mode 100644 svgs/ilovepdf.svg create mode 100644 svgs/incognito_browser.svg create mode 100644 svgs/infomaniak_kdrive.svg create mode 100644 svgs/jiofinance.svg create mode 100644 svgs/jupiter.svg create mode 100644 svgs/kate_mobile.svg create mode 100644 svgs/kaufland.svg create mode 100644 svgs/koshelek.svg create mode 100644 svgs/manga_dogs.svg create mode 100644 svgs/meeye_icons.svg create mode 100644 svgs/mi_community.svg create mode 100644 svgs/mods_maps_for_minecraft_pe.svg create mode 100644 svgs/mostaza.svg create mode 100644 svgs/motohub.svg create mode 100644 svgs/my_app_list.svg create mode 100644 svgs/my_galaxy.svg create mode 100644 svgs/naranja_x.svg create mode 100644 svgs/neostumbler.svg create mode 100644 svgs/nfcgate.svg create mode 100644 svgs/notes_notepad.svg create mode 100644 svgs/nulls_brawl.svg create mode 100644 svgs/orgzly_revived.svg create mode 100644 svgs/oss_card_wallet.svg create mode 100644 svgs/packmate.svg create mode 100644 svgs/pascals_wager.svg create mode 100644 svgs/payoneer.svg create mode 100644 svgs/pi_browser.svg create mode 100644 svgs/pikmin_bloom.svg create mode 100644 svgs/pixelcut.svg create mode 100644 svgs/plants_vs_zombies_2.svg create mode 100644 svgs/plugin_voicegpt.svg create mode 100644 svgs/postparty.svg create mode 100644 svgs/prequel.svg create mode 100644 svgs/proton_wallet.svg create mode 100644 svgs/raven.svg create mode 100644 svgs/remote_for_android_tv.svg create mode 100644 svgs/ridmik_keyboard.svg create mode 100644 svgs/rise_up_balloon_game.svg create mode 100644 svgs/robinhood.svg create mode 100644 svgs/root_checker.svg create mode 100644 svgs/rush.svg create mode 100644 svgs/safetynet.svg create mode 100644 svgs/schoology.svg create mode 100644 svgs/skroutz.svg create mode 100644 svgs/solar_smash.svg create mode 100644 svgs/spamblocker.svg create mode 100644 svgs/squad_busters.svg create mode 100644 svgs/standoff_2.svg create mode 100644 svgs/superimage_pro.svg create mode 100644 svgs/tipatch.svg create mode 100644 svgs/tubi.svg create mode 100644 svgs/unit_converter.svg create mode 100644 svgs/velociraptor.svg create mode 100644 svgs/vitune.svg create mode 100644 svgs/voice_access.svg create mode 100644 svgs/vpn_fast_proxy_secure.svg create mode 100644 svgs/vrchat.svg create mode 100644 svgs/vtb.svg create mode 100644 svgs/wanderlog.svg create mode 100644 svgs/whicons.svg create mode 100644 svgs/world_tv.svg create mode 100644 svgs/wuthering_waves.svg create mode 100644 svgs/xapk_installer.svg create mode 100644 svgs/yandex_with_alice.svg create mode 100644 svgs/zipxtract_fd.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 97ab0d8294f..a2b1c69fe9b 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -86,6 +86,7 @@ + @@ -154,6 +155,8 @@ + + @@ -202,6 +205,7 @@ + @@ -449,7 +453,9 @@ + + @@ -709,6 +715,7 @@ + @@ -1070,6 +1077,7 @@ + @@ -1320,6 +1328,7 @@ + @@ -1443,12 +1452,15 @@ + + + @@ -1561,8 +1573,10 @@ + + @@ -1784,6 +1798,7 @@ + @@ -1821,6 +1836,7 @@ + @@ -2156,6 +2172,7 @@ + @@ -2345,6 +2362,7 @@ + @@ -2434,6 +2452,7 @@ + @@ -2505,6 +2524,7 @@ + @@ -2581,6 +2601,7 @@ + @@ -2688,6 +2709,7 @@ + @@ -3135,6 +3157,7 @@ + @@ -3233,6 +3256,7 @@ + @@ -3360,6 +3384,7 @@ + @@ -3525,6 +3550,7 @@ + @@ -3579,6 +3605,7 @@ + @@ -3622,6 +3649,7 @@ + @@ -3634,6 +3662,7 @@ + @@ -3676,6 +3705,7 @@ + @@ -3933,6 +3963,7 @@ + @@ -4184,6 +4215,7 @@ + @@ -4446,6 +4478,7 @@ + @@ -4477,6 +4510,7 @@ + @@ -4555,6 +4589,7 @@ + @@ -4616,6 +4651,7 @@ + @@ -4636,6 +4672,7 @@ + @@ -4829,6 +4866,7 @@ + @@ -4862,6 +4900,7 @@ + @@ -4927,7 +4966,9 @@ + + @@ -5551,6 +5592,7 @@ + @@ -5721,6 +5763,7 @@ + @@ -5874,6 +5917,7 @@ + @@ -6122,6 +6166,7 @@ + @@ -6195,6 +6240,7 @@ + @@ -6216,6 +6262,7 @@ + @@ -6339,6 +6386,7 @@ + @@ -6359,6 +6407,7 @@ + @@ -6574,6 +6623,7 @@ + @@ -6651,6 +6701,7 @@ + @@ -6732,6 +6783,7 @@ + @@ -6819,6 +6871,7 @@ + @@ -6908,6 +6961,7 @@ + @@ -7230,6 +7284,7 @@ + @@ -7242,6 +7297,7 @@ + @@ -7300,6 +7356,7 @@ + @@ -7351,6 +7408,7 @@ + @@ -7377,6 +7435,7 @@ + @@ -7691,6 +7750,7 @@ + @@ -7709,6 +7769,7 @@ + @@ -7770,6 +7831,7 @@ + @@ -7846,6 +7908,7 @@ + @@ -7873,6 +7936,7 @@ + @@ -7990,6 +8054,7 @@ + @@ -8043,6 +8108,7 @@ + @@ -8098,6 +8164,7 @@ + @@ -8311,6 +8378,7 @@ + @@ -8461,6 +8529,7 @@ + @@ -8524,6 +8593,7 @@ + @@ -8544,11 +8614,13 @@ + + @@ -8569,6 +8641,7 @@ + @@ -8599,6 +8672,7 @@ + @@ -8628,6 +8702,7 @@ + @@ -8831,6 +8906,7 @@ + @@ -9563,6 +9639,7 @@ + @@ -9727,6 +9804,7 @@ + @@ -9816,6 +9894,7 @@ + @@ -9870,6 +9949,7 @@ + @@ -9893,6 +9973,7 @@ + @@ -10083,6 +10164,7 @@ + @@ -10754,6 +10836,7 @@ + @@ -10961,6 +11044,7 @@ + @@ -11115,6 +11199,7 @@ + @@ -11232,6 +11317,7 @@ + @@ -11377,6 +11463,7 @@ + @@ -11421,6 +11508,7 @@ + @@ -11446,6 +11534,7 @@ + @@ -11459,6 +11548,7 @@ + @@ -11541,6 +11631,7 @@ + @@ -11773,6 +11864,7 @@ + @@ -11872,6 +11964,7 @@ + @@ -11896,6 +11989,7 @@ + @@ -11926,6 +12020,7 @@ + @@ -12204,6 +12299,7 @@ + @@ -12238,8 +12334,8 @@ - - + + @@ -12285,6 +12381,7 @@ + @@ -12317,6 +12414,7 @@ + @@ -12400,6 +12498,7 @@ + @@ -12491,6 +12590,7 @@ + diff --git a/svgs/_365scores.svg b/svgs/_365scores.svg new file mode 100644 index 00000000000..6cd7c394986 --- /dev/null +++ b/svgs/_365scores.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/act_fibernet.svg b/svgs/act_fibernet.svg new file mode 100644 index 00000000000..0b421da8200 --- /dev/null +++ b/svgs/act_fibernet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/action.svg b/svgs/action.svg new file mode 100644 index 00000000000..dd604a8d6fd --- /dev/null +++ b/svgs/action.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/adobe_creative_cloud.svg b/svgs/adobe_creative_cloud.svg new file mode 100644 index 00000000000..2a800183655 --- /dev/null +++ b/svgs/adobe_creative_cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/agricultural_bank_of_china.svg b/svgs/agricultural_bank_of_china.svg new file mode 100644 index 00000000000..67e0c2e7377 --- /dev/null +++ b/svgs/agricultural_bank_of_china.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ampereflow.svg b/svgs/ampereflow.svg new file mode 100644 index 00000000000..dca6379a68b --- /dev/null +++ b/svgs/ampereflow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/anacity_in.svg b/svgs/anacity_in.svg new file mode 100644 index 00000000000..72defb9ab2b --- /dev/null +++ b/svgs/anacity_in.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/asus_tips.svg b/svgs/asus_tips.svg new file mode 100644 index 00000000000..465546e532d --- /dev/null +++ b/svgs/asus_tips.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/birbank.svg b/svgs/birbank.svg new file mode 100644 index 00000000000..0c533187a0c --- /dev/null +++ b/svgs/birbank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/brother_print_service_plugin.svg b/svgs/brother_print_service_plugin.svg new file mode 100644 index 00000000000..d16d8d21cb8 --- /dev/null +++ b/svgs/brother_print_service_plugin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/buy_me_a_coffee.svg b/svgs/buy_me_a_coffee.svg new file mode 100644 index 00000000000..4c8b846e3f8 --- /dev/null +++ b/svgs/buy_me_a_coffee.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/bz_reminder.svg b/svgs/bz_reminder.svg new file mode 100644 index 00000000000..eeca29df0a3 --- /dev/null +++ b/svgs/bz_reminder.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/bz_reminder_pro.svg b/svgs/bz_reminder_pro.svg new file mode 100644 index 00000000000..81a3a02e496 --- /dev/null +++ b/svgs/bz_reminder_pro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/call_of_duty_warzone.svg b/svgs/call_of_duty_warzone.svg new file mode 100644 index 00000000000..e2eb91afc98 --- /dev/null +++ b/svgs/call_of_duty_warzone.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/calorie_counter.svg b/svgs/calorie_counter.svg new file mode 100644 index 00000000000..868e722fe10 --- /dev/null +++ b/svgs/calorie_counter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/cara.svg b/svgs/cara.svg new file mode 100644 index 00000000000..707ff2bb503 --- /dev/null +++ b/svgs/cara.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/castro_premium.svg b/svgs/castro_premium.svg new file mode 100644 index 00000000000..bc55ff1b81a --- /dev/null +++ b/svgs/castro_premium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/comatose.svg b/svgs/comatose.svg new file mode 100644 index 00000000000..c070be21da7 --- /dev/null +++ b/svgs/comatose.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/cpu_monitor.svg b/svgs/cpu_monitor.svg new file mode 100644 index 00000000000..34e7fc15f7f --- /dev/null +++ b/svgs/cpu_monitor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/darker.svg b/svgs/darker.svg new file mode 100644 index 00000000000..be2214ecaee --- /dev/null +++ b/svgs/darker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/delhivery.svg b/svgs/delhivery.svg new file mode 100644 index 00000000000..e3c69c88058 --- /dev/null +++ b/svgs/delhivery.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/dicio_assistant.svg b/svgs/dicio_assistant.svg new file mode 100644 index 00000000000..20d8f066cf3 --- /dev/null +++ b/svgs/dicio_assistant.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/disky.svg b/svgs/disky.svg new file mode 100644 index 00000000000..81c27b9a974 --- /dev/null +++ b/svgs/disky.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/exnova.svg b/svgs/exnova.svg new file mode 100644 index 00000000000..6796fdcf932 --- /dev/null +++ b/svgs/exnova.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/federal_bank.svg b/svgs/federal_bank.svg new file mode 100644 index 00000000000..a8d576e6e1a --- /dev/null +++ b/svgs/federal_bank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/finshell_pay.svg b/svgs/finshell_pay.svg new file mode 100644 index 00000000000..52c50ce71ae --- /dev/null +++ b/svgs/finshell_pay.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/focus_video.svg b/svgs/focus_video.svg new file mode 100644 index 00000000000..c0081d56bfe --- /dev/null +++ b/svgs/focus_video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/formulia.svg b/svgs/formulia.svg new file mode 100644 index 00000000000..934bc391372 --- /dev/null +++ b/svgs/formulia.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/freecodecamp.svg b/svgs/freecodecamp.svg new file mode 100644 index 00000000000..5da25c7df09 --- /dev/null +++ b/svgs/freecodecamp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/freetube.svg b/svgs/freetube.svg new file mode 100644 index 00000000000..7f26e7084dc --- /dev/null +++ b/svgs/freetube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/fuhrerschein.svg b/svgs/fuhrerschein.svg new file mode 100644 index 00000000000..5945bf34068 --- /dev/null +++ b/svgs/fuhrerschein.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/goodmoney.svg b/svgs/goodmoney.svg new file mode 100644 index 00000000000..dcbdc1e4708 --- /dev/null +++ b/svgs/goodmoney.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/groovifi.svg b/svgs/groovifi.svg new file mode 100644 index 00000000000..a7e3855ed95 --- /dev/null +++ b/svgs/groovifi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/huawei_video.svg b/svgs/huawei_video.svg new file mode 100644 index 00000000000..f8c473998db --- /dev/null +++ b/svgs/huawei_video.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/iaca_laboratorios.svg b/svgs/iaca_laboratorios.svg new file mode 100644 index 00000000000..c06f0608877 --- /dev/null +++ b/svgs/iaca_laboratorios.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ilovepdf.svg b/svgs/ilovepdf.svg new file mode 100644 index 00000000000..2cbf05b1982 --- /dev/null +++ b/svgs/ilovepdf.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/incognito_browser.svg b/svgs/incognito_browser.svg new file mode 100644 index 00000000000..ec26aaead83 --- /dev/null +++ b/svgs/incognito_browser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/infomaniak_kdrive.svg b/svgs/infomaniak_kdrive.svg new file mode 100644 index 00000000000..41150a007cc --- /dev/null +++ b/svgs/infomaniak_kdrive.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/jiofinance.svg b/svgs/jiofinance.svg new file mode 100644 index 00000000000..4b63d32692f --- /dev/null +++ b/svgs/jiofinance.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/jupiter.svg b/svgs/jupiter.svg new file mode 100644 index 00000000000..8b3bb7b22ec --- /dev/null +++ b/svgs/jupiter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/kate_mobile.svg b/svgs/kate_mobile.svg new file mode 100644 index 00000000000..cfe5e65b23f --- /dev/null +++ b/svgs/kate_mobile.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/kaufland.svg b/svgs/kaufland.svg new file mode 100644 index 00000000000..dd75ad80f7a --- /dev/null +++ b/svgs/kaufland.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/koshelek.svg b/svgs/koshelek.svg new file mode 100644 index 00000000000..47d4b35d036 --- /dev/null +++ b/svgs/koshelek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/manga_dogs.svg b/svgs/manga_dogs.svg new file mode 100644 index 00000000000..b1880a01ebf --- /dev/null +++ b/svgs/manga_dogs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/meeye_icons.svg b/svgs/meeye_icons.svg new file mode 100644 index 00000000000..2ef64fe2ed7 --- /dev/null +++ b/svgs/meeye_icons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mi_community.svg b/svgs/mi_community.svg new file mode 100644 index 00000000000..ca0117a9aaa --- /dev/null +++ b/svgs/mi_community.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mods_maps_for_minecraft_pe.svg b/svgs/mods_maps_for_minecraft_pe.svg new file mode 100644 index 00000000000..98b3b69319d --- /dev/null +++ b/svgs/mods_maps_for_minecraft_pe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mostaza.svg b/svgs/mostaza.svg new file mode 100644 index 00000000000..470f3d0ca14 --- /dev/null +++ b/svgs/mostaza.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/motohub.svg b/svgs/motohub.svg new file mode 100644 index 00000000000..05ebc3c73db --- /dev/null +++ b/svgs/motohub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/my_app_list.svg b/svgs/my_app_list.svg new file mode 100644 index 00000000000..288b08064c0 --- /dev/null +++ b/svgs/my_app_list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/my_galaxy.svg b/svgs/my_galaxy.svg new file mode 100644 index 00000000000..c0969ab4af2 --- /dev/null +++ b/svgs/my_galaxy.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/naranja_x.svg b/svgs/naranja_x.svg new file mode 100644 index 00000000000..095ceed6d9d --- /dev/null +++ b/svgs/naranja_x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/neostumbler.svg b/svgs/neostumbler.svg new file mode 100644 index 00000000000..775016828f9 --- /dev/null +++ b/svgs/neostumbler.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/nfcgate.svg b/svgs/nfcgate.svg new file mode 100644 index 00000000000..e6588fa4a39 --- /dev/null +++ b/svgs/nfcgate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/notes_notepad.svg b/svgs/notes_notepad.svg new file mode 100644 index 00000000000..38987cdcc5a --- /dev/null +++ b/svgs/notes_notepad.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/nulls_brawl.svg b/svgs/nulls_brawl.svg new file mode 100644 index 00000000000..34105370d4d --- /dev/null +++ b/svgs/nulls_brawl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/orgzly_revived.svg b/svgs/orgzly_revived.svg new file mode 100644 index 00000000000..cf3c9e80f2c --- /dev/null +++ b/svgs/orgzly_revived.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/oss_card_wallet.svg b/svgs/oss_card_wallet.svg new file mode 100644 index 00000000000..d8f485e87ce --- /dev/null +++ b/svgs/oss_card_wallet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/packmate.svg b/svgs/packmate.svg new file mode 100644 index 00000000000..6921e9ae27d --- /dev/null +++ b/svgs/packmate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pascals_wager.svg b/svgs/pascals_wager.svg new file mode 100644 index 00000000000..b2cbcf69923 --- /dev/null +++ b/svgs/pascals_wager.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/payoneer.svg b/svgs/payoneer.svg new file mode 100644 index 00000000000..6aff0835806 --- /dev/null +++ b/svgs/payoneer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pi_browser.svg b/svgs/pi_browser.svg new file mode 100644 index 00000000000..95cc4cf222c --- /dev/null +++ b/svgs/pi_browser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pikmin_bloom.svg b/svgs/pikmin_bloom.svg new file mode 100644 index 00000000000..b87ac9141f9 --- /dev/null +++ b/svgs/pikmin_bloom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pixelcut.svg b/svgs/pixelcut.svg new file mode 100644 index 00000000000..296367f2925 --- /dev/null +++ b/svgs/pixelcut.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/plants_vs_zombies_2.svg b/svgs/plants_vs_zombies_2.svg new file mode 100644 index 00000000000..dee85f29830 --- /dev/null +++ b/svgs/plants_vs_zombies_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/plugin_voicegpt.svg b/svgs/plugin_voicegpt.svg new file mode 100644 index 00000000000..b4385d67bd1 --- /dev/null +++ b/svgs/plugin_voicegpt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/postparty.svg b/svgs/postparty.svg new file mode 100644 index 00000000000..2b364a757e9 --- /dev/null +++ b/svgs/postparty.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/prequel.svg b/svgs/prequel.svg new file mode 100644 index 00000000000..3d9412930a4 --- /dev/null +++ b/svgs/prequel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/proton_wallet.svg b/svgs/proton_wallet.svg new file mode 100644 index 00000000000..fea1781c71a --- /dev/null +++ b/svgs/proton_wallet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/raven.svg b/svgs/raven.svg new file mode 100644 index 00000000000..a062b6672d4 --- /dev/null +++ b/svgs/raven.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/remote_for_android_tv.svg b/svgs/remote_for_android_tv.svg new file mode 100644 index 00000000000..feeaf932cbc --- /dev/null +++ b/svgs/remote_for_android_tv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/ridmik_keyboard.svg b/svgs/ridmik_keyboard.svg new file mode 100644 index 00000000000..ceabb19ba53 --- /dev/null +++ b/svgs/ridmik_keyboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/rise_up_balloon_game.svg b/svgs/rise_up_balloon_game.svg new file mode 100644 index 00000000000..1543286f06b --- /dev/null +++ b/svgs/rise_up_balloon_game.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/robinhood.svg b/svgs/robinhood.svg new file mode 100644 index 00000000000..f11c2244748 --- /dev/null +++ b/svgs/robinhood.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/root_checker.svg b/svgs/root_checker.svg new file mode 100644 index 00000000000..5f00c70b5a8 --- /dev/null +++ b/svgs/root_checker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/rush.svg b/svgs/rush.svg new file mode 100644 index 00000000000..529e2f62c3a --- /dev/null +++ b/svgs/rush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/safetynet.svg b/svgs/safetynet.svg new file mode 100644 index 00000000000..9e5f188fc73 --- /dev/null +++ b/svgs/safetynet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/schoology.svg b/svgs/schoology.svg new file mode 100644 index 00000000000..b4aa3fa1aae --- /dev/null +++ b/svgs/schoology.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/skroutz.svg b/svgs/skroutz.svg new file mode 100644 index 00000000000..9e4957942e7 --- /dev/null +++ b/svgs/skroutz.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/solar_smash.svg b/svgs/solar_smash.svg new file mode 100644 index 00000000000..0635c23abc0 --- /dev/null +++ b/svgs/solar_smash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/spamblocker.svg b/svgs/spamblocker.svg new file mode 100644 index 00000000000..734983e5c69 --- /dev/null +++ b/svgs/spamblocker.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/squad_busters.svg b/svgs/squad_busters.svg new file mode 100644 index 00000000000..a806f05429f --- /dev/null +++ b/svgs/squad_busters.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/standoff_2.svg b/svgs/standoff_2.svg new file mode 100644 index 00000000000..8659cf2e0e0 --- /dev/null +++ b/svgs/standoff_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/superimage_pro.svg b/svgs/superimage_pro.svg new file mode 100644 index 00000000000..981dbbdc6ad --- /dev/null +++ b/svgs/superimage_pro.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/tipatch.svg b/svgs/tipatch.svg new file mode 100644 index 00000000000..b5bb55c1b15 --- /dev/null +++ b/svgs/tipatch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/tubi.svg b/svgs/tubi.svg new file mode 100644 index 00000000000..712b7eb6282 --- /dev/null +++ b/svgs/tubi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/unit_converter.svg b/svgs/unit_converter.svg new file mode 100644 index 00000000000..fb5fab97f80 --- /dev/null +++ b/svgs/unit_converter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/velociraptor.svg b/svgs/velociraptor.svg new file mode 100644 index 00000000000..514ce6194c5 --- /dev/null +++ b/svgs/velociraptor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/vitune.svg b/svgs/vitune.svg new file mode 100644 index 00000000000..e78a1ad4d19 --- /dev/null +++ b/svgs/vitune.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/voice_access.svg b/svgs/voice_access.svg new file mode 100644 index 00000000000..095aae6a06c --- /dev/null +++ b/svgs/voice_access.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/vpn_fast_proxy_secure.svg b/svgs/vpn_fast_proxy_secure.svg new file mode 100644 index 00000000000..503bf4515cb --- /dev/null +++ b/svgs/vpn_fast_proxy_secure.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/vrchat.svg b/svgs/vrchat.svg new file mode 100644 index 00000000000..168abedfcd5 --- /dev/null +++ b/svgs/vrchat.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/vtb.svg b/svgs/vtb.svg new file mode 100644 index 00000000000..f933f80f689 --- /dev/null +++ b/svgs/vtb.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/wanderlog.svg b/svgs/wanderlog.svg new file mode 100644 index 00000000000..067e651d603 --- /dev/null +++ b/svgs/wanderlog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/whicons.svg b/svgs/whicons.svg new file mode 100644 index 00000000000..d8ebb11cf02 --- /dev/null +++ b/svgs/whicons.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/world_tv.svg b/svgs/world_tv.svg new file mode 100644 index 00000000000..b09d9a116c4 --- /dev/null +++ b/svgs/world_tv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/wuthering_waves.svg b/svgs/wuthering_waves.svg new file mode 100644 index 00000000000..6723a9a51ab --- /dev/null +++ b/svgs/wuthering_waves.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/xapk_installer.svg b/svgs/xapk_installer.svg new file mode 100644 index 00000000000..49e1d799b2d --- /dev/null +++ b/svgs/xapk_installer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/yandex_with_alice.svg b/svgs/yandex_with_alice.svg new file mode 100644 index 00000000000..4b7f67a6d0d --- /dev/null +++ b/svgs/yandex_with_alice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/zipxtract_fd.svg b/svgs/zipxtract_fd.svg new file mode 100644 index 00000000000..6f1385cc3b7 --- /dev/null +++ b/svgs/zipxtract_fd.svg @@ -0,0 +1 @@ + \ No newline at end of file From 23d5862d200c55cc8703fcd82207da16cd0bfedc Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 12 Sep 2024 02:14:47 +0300 Subject: [PATCH 131/144] +67 links (#2324) * +67 links * Minor fix --- app/assets/appfilter.xml | 67 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index a2b1c69fe9b..119bcfe42ac 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -323,6 +323,7 @@ + @@ -1888,6 +1889,7 @@ + @@ -2141,6 +2143,7 @@ + @@ -2508,6 +2511,7 @@ + @@ -2990,6 +2994,7 @@ + @@ -3152,6 +3157,7 @@ + @@ -3384,6 +3390,10 @@ + + + + @@ -3662,6 +3672,7 @@ + @@ -4001,6 +4012,7 @@ + @@ -4042,6 +4054,7 @@ + @@ -4064,12 +4077,14 @@ + + @@ -4084,6 +4099,7 @@ + @@ -4099,16 +4115,19 @@ + + + @@ -4375,6 +4394,7 @@ + @@ -4552,11 +4572,13 @@ + + @@ -4712,6 +4734,7 @@ + @@ -4900,6 +4923,7 @@ + @@ -4936,6 +4960,7 @@ + @@ -4966,6 +4991,7 @@ + @@ -5109,6 +5135,7 @@ + @@ -5119,6 +5146,7 @@ + @@ -5281,6 +5309,7 @@ + @@ -5311,6 +5340,7 @@ + @@ -5656,6 +5686,7 @@ + @@ -5750,6 +5781,7 @@ + @@ -5884,6 +5916,7 @@ + @@ -5929,6 +5962,7 @@ + @@ -5979,6 +6013,7 @@ + @@ -6030,6 +6065,7 @@ + @@ -6348,6 +6384,7 @@ + @@ -6944,6 +6981,7 @@ + @@ -7128,6 +7166,7 @@ + @@ -7457,6 +7496,7 @@ + @@ -7744,6 +7784,7 @@ + @@ -7906,6 +7947,7 @@ + @@ -8100,6 +8142,7 @@ + @@ -8312,6 +8355,7 @@ + @@ -8666,6 +8710,7 @@ + @@ -9597,6 +9642,7 @@ + @@ -9771,6 +9817,7 @@ + @@ -9875,6 +9922,7 @@ + @@ -9918,6 +9966,7 @@ + @@ -10147,6 +10196,7 @@ + @@ -10188,6 +10238,7 @@ + @@ -10199,6 +10250,7 @@ + @@ -10467,6 +10519,7 @@ + @@ -10890,6 +10943,7 @@ + @@ -10987,6 +11041,7 @@ + @@ -10998,6 +11053,7 @@ + @@ -11113,6 +11169,7 @@ + @@ -11294,6 +11351,7 @@ + @@ -11468,6 +11526,7 @@ + @@ -11508,6 +11567,8 @@ + + @@ -11616,6 +11677,7 @@ + @@ -11927,6 +11989,7 @@ + @@ -11989,6 +12052,7 @@ + @@ -12197,6 +12261,7 @@ + @@ -12340,6 +12405,7 @@ + @@ -12381,6 +12447,7 @@ + From ed6393e50b9f9c37abc6ca9c80fba36e4a1d64ef Mon Sep 17 00:00:00 2001 From: 92 <169070113+I21b@users.noreply.github.com> Date: Fri, 13 Sep 2024 03:28:38 +0900 Subject: [PATCH 132/144] +12 icons, +3 link (#2315) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * +12 icons, +3 link > Icons: `BBLL`, `BiliYou`, `BUFF`, `СберИнвестиции ~~ SberInvestments`, `Купер ~~ Kuper`, `Magical Search`, `magicplan`, `Moscow Wi-Fi autologin`, `О'КЕЙ ~~ O'KEY`, `РЖД Пассажирам билеты на поезд ~~ Russian Railways`, `Перекресток ~~ Perekrestok`, `乐速通 ~~ BJETC` > Links: `Avee Player Lite`, `BUFF`, `TorrServe MatriX` Co-Authored-By: Daniil <68991727+fishaffair@users.noreply.github.com> Co-Authored-By: astolfogit <35395586+astolfogit@users.noreply.github.com> Co-Authored-By: OWQW <180897579+owqw@users.noreply.github.com> Co-Authored-By: 92 <169070113+i21b@users.noreply.github.com> * small fix * Update buff.svg * Update okey.svg * Update torrserve_matrix.svg --------- Co-authored-by: Daniil <68991727+fishaffair@users.noreply.github.com> Co-authored-by: astolfogit <35395586+astolfogit@users.noreply.github.com> Co-authored-by: OWQW <180897579+owqw@users.noreply.github.com> Co-authored-by: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 15 +++++++++++++++ svgs/bbll.svg | 3 +++ svgs/biliyou.svg | 3 +++ svgs/bjetc.svg | 3 +++ svgs/buff.svg | 1 + svgs/kuper.svg | 3 +++ svgs/magical_search.svg | 3 +++ svgs/magicplan.svg | 3 +++ svgs/moscow_wifi_autologin.svg | 3 +++ svgs/okey.svg | 1 + svgs/perekrestok.svg | 6 ++++++ svgs/russian_railways.svg | 3 +++ svgs/sberinvestments.svg | 3 +++ svgs/torrserve_matrix.svg | 1 + 14 files changed, 51 insertions(+) create mode 100644 svgs/bbll.svg create mode 100644 svgs/biliyou.svg create mode 100644 svgs/bjetc.svg create mode 100644 svgs/buff.svg create mode 100644 svgs/kuper.svg create mode 100644 svgs/magical_search.svg create mode 100644 svgs/magicplan.svg create mode 100644 svgs/moscow_wifi_autologin.svg create mode 100644 svgs/okey.svg create mode 100644 svgs/perekrestok.svg create mode 100644 svgs/russian_railways.svg create mode 100644 svgs/sberinvestments.svg create mode 100644 svgs/torrserve_matrix.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 119bcfe42ac..bc0c17997d9 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -799,6 +799,7 @@ + @@ -947,6 +948,7 @@ + @@ -1049,6 +1051,7 @@ + @@ -1349,6 +1352,8 @@ + + @@ -1469,6 +1474,7 @@ + @@ -5225,6 +5231,7 @@ + @@ -5566,9 +5573,11 @@ + + @@ -6275,6 +6284,7 @@ + @@ -7041,6 +7051,7 @@ + @@ -7389,6 +7400,7 @@ + @@ -10954,6 +10966,7 @@ + @@ -12506,6 +12519,7 @@ + @@ -12821,6 +12835,7 @@ + diff --git a/svgs/bbll.svg b/svgs/bbll.svg new file mode 100644 index 00000000000..0c569c0bc60 --- /dev/null +++ b/svgs/bbll.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/biliyou.svg b/svgs/biliyou.svg new file mode 100644 index 00000000000..7d634c17145 --- /dev/null +++ b/svgs/biliyou.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/bjetc.svg b/svgs/bjetc.svg new file mode 100644 index 00000000000..753d8a0e1bd --- /dev/null +++ b/svgs/bjetc.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/buff.svg b/svgs/buff.svg new file mode 100644 index 00000000000..b84dcfaa90d --- /dev/null +++ b/svgs/buff.svg @@ -0,0 +1 @@ + diff --git a/svgs/kuper.svg b/svgs/kuper.svg new file mode 100644 index 00000000000..589417942ca --- /dev/null +++ b/svgs/kuper.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/magical_search.svg b/svgs/magical_search.svg new file mode 100644 index 00000000000..f1ca03d5554 --- /dev/null +++ b/svgs/magical_search.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/magicplan.svg b/svgs/magicplan.svg new file mode 100644 index 00000000000..bcfa8c85f3b --- /dev/null +++ b/svgs/magicplan.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/moscow_wifi_autologin.svg b/svgs/moscow_wifi_autologin.svg new file mode 100644 index 00000000000..e367ba251f5 --- /dev/null +++ b/svgs/moscow_wifi_autologin.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/okey.svg b/svgs/okey.svg new file mode 100644 index 00000000000..1a6355a554b --- /dev/null +++ b/svgs/okey.svg @@ -0,0 +1 @@ + diff --git a/svgs/perekrestok.svg b/svgs/perekrestok.svg new file mode 100644 index 00000000000..91efd9d454d --- /dev/null +++ b/svgs/perekrestok.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/svgs/russian_railways.svg b/svgs/russian_railways.svg new file mode 100644 index 00000000000..3e77546923e --- /dev/null +++ b/svgs/russian_railways.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/sberinvestments.svg b/svgs/sberinvestments.svg new file mode 100644 index 00000000000..818b9d5a703 --- /dev/null +++ b/svgs/sberinvestments.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/torrserve_matrix.svg b/svgs/torrserve_matrix.svg new file mode 100644 index 00000000000..e531573306d --- /dev/null +++ b/svgs/torrserve_matrix.svg @@ -0,0 +1 @@ + From 4b8cc3a278e199b3696ed96fd9ccf1ab85038e03 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Thu, 12 Sep 2024 22:19:00 +0300 Subject: [PATCH 133/144] +17 links (#2327) --- app/assets/appfilter.xml | 176 ++++++++++-------- svgs/{dominos.svg => dominos_pizza.svg} | 0 ...ytopia.svg => the_battle_of_polytopia.svg} | 0 svgs/{tune_in_radio.svg => tunein_radio.svg} | 0 svgs/{tuya.svg => tuya_smart.svg} | 0 5 files changed, 96 insertions(+), 80 deletions(-) rename svgs/{dominos.svg => dominos_pizza.svg} (100%) rename svgs/{polytopia.svg => the_battle_of_polytopia.svg} (100%) rename svgs/{tune_in_radio.svg => tunein_radio.svg} (100%) rename svgs/{tuya.svg => tuya_smart.svg} (100%) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index bc0c17997d9..9cd9467ece9 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -1054,6 +1054,7 @@ + @@ -1352,6 +1353,8 @@ + + @@ -1474,7 +1477,6 @@ - @@ -2764,57 +2766,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3918,6 +3921,7 @@ + @@ -5231,7 +5235,6 @@ - @@ -6016,8 +6019,9 @@ - - + + + @@ -6325,7 +6329,7 @@ - + @@ -6401,6 +6405,7 @@ + @@ -7051,7 +7056,6 @@ - @@ -7400,7 +7404,6 @@ - @@ -8431,6 +8434,7 @@ + @@ -10327,6 +10331,7 @@ + @@ -10375,6 +10380,7 @@ + @@ -10789,7 +10795,8 @@ - + + @@ -11128,20 +11135,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -11164,8 +11172,9 @@ - - + + + @@ -11339,6 +11348,7 @@ + @@ -11465,6 +11475,7 @@ + @@ -11998,6 +12009,7 @@ + @@ -12495,6 +12507,7 @@ + @@ -12510,19 +12523,21 @@ + + - + @@ -12530,6 +12545,7 @@ + @@ -12581,7 +12597,7 @@ - + @@ -12603,8 +12619,8 @@ - - + + @@ -12658,6 +12674,7 @@ + @@ -12835,7 +12852,6 @@ - diff --git a/svgs/dominos.svg b/svgs/dominos_pizza.svg similarity index 100% rename from svgs/dominos.svg rename to svgs/dominos_pizza.svg diff --git a/svgs/polytopia.svg b/svgs/the_battle_of_polytopia.svg similarity index 100% rename from svgs/polytopia.svg rename to svgs/the_battle_of_polytopia.svg diff --git a/svgs/tune_in_radio.svg b/svgs/tunein_radio.svg similarity index 100% rename from svgs/tune_in_radio.svg rename to svgs/tunein_radio.svg diff --git a/svgs/tuya.svg b/svgs/tuya_smart.svg similarity index 100% rename from svgs/tuya.svg rename to svgs/tuya_smart.svg From bfb63815a53a55c5292045b9f85bb4dec73b79c6 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Fri, 13 Sep 2024 17:11:09 +0300 Subject: [PATCH 134/144] Small refinements of the Lawnicons docs (#2328) * Small refinements of the GitHub docs * Update icon_checklist.md * Update icon_checklist.md * Update icon_checklist.md --- .github/icon_checklist.md | 6 +----- CONTRIBUTING.md | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index 8059999f6d6..1c7013045c2 100644 --- a/.github/icon_checklist.md +++ b/.github/icon_checklist.md @@ -1,26 +1,22 @@ Thanks for your contribution! -While waiting for a review from our team, you can do a self-review to ensure that your icons are suitable for Lawnicons. +We try to do the review within 7 days. While waiting for a review from our team, you can do a self-review to ensure that your icons are suitable for Lawnicons. ### Canvas and sizes 1. Canvas: `192×192px`. 2. Non-square icons: the long side of the icons should be `160px`. 3. Square icons: `154×154px`. -- [ ] Approved by the Lawnicons reviewer ### Color, stroke width and rounding 1. Color: non-transparent black `#000`. 2. No fill. Base stroke width: `12px`. `14px`, `10px`, `8px` — depending on the shape of the icons. `6px` — for fine details. 3. Rounded ends and joins. 90° corners are rounded by `6-32px`. -- [ ] Approved by the Lawnicons reviewer ### Naming 1. Names should match the official app name and contain no additional text. 2. If the first `3` characters of the app name contain letters not from the English alphabet, then add a localized (or transliterated) name via `~~`. Example: `京东 ~~ JD`. 3. The names of the drawables should repeat the names of the apps if nothing prevents it. -- [ ] Approved by the Lawnicons reviewer ### Quality 1. Ensure that icons are easily recognizable. 2. Align icons to [the visual center](https://crazybitsstudios.com/another-way-of-aligning-elements-when-creating-icons) as much as possible within the guidelines. The visual center is where your icon looks and feels centered. 3. Avoid noticable black spots by reducing the stroke width or simplifying the icons. 4. Avoid close distances between strokes. The icons on the phone screen will be smaller, so the small distances between the strokes will stick together. 5. Avoid drastic changes in stroke widths. When the strokes next to each other differ in width by 4px or more, the icon will look sloppy. -- [ ] Approved by the Lawnicons reviewer diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06c3dc6cfa1..82dceff8ba8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,6 +11,10 @@ For additional information on designing icons and samples, see [the Lawnicons Fi Need help? [Join Lawnchair on Discord](https://discord.com/invite/3x8qNWxgGZ). ### TL;DR on icon design + +> [!NOTE] +> Upload no more than 10 icons at a time, because reviewers only have time for small pull requests. + The canvas is `192×192px`. The content area for most icons is `160×160px`, meaning the long side of an icon should be `160px`. Square icons should be `154×154px`. No fill, the stroke width is `12px`. All shapes should be black `#000` with rounded ends and joins. Round 90° angles by `6-32px`. Avoid noticable black spots, close distances between strokes, and drastic changes in stroke widths. Simplify details, but don't lose recognizability. Provide original and localized names, so the icons can be found. To avoid rework, save time and understand the limitations of the guidelines, it is worth reading reviews (e.g., [+8 icons, +1 link, +4 updates](https://github.com/LawnchairLauncher/lawnicons/pull/1865)) and creating 5-10 icons in the first contribution. From bd0a23bafbcadc11b59b582607f51e059b1435aa Mon Sep 17 00:00:00 2001 From: "M." Date: Fri, 13 Sep 2024 22:30:31 +0330 Subject: [PATCH 135/144] +3 icons (#2326) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added 'Mead Mate', 'Nobitex' and 'بانک مهر' * fixed 'Nobitex' * fixed 'بانک مهر' * Minor fixes * fixed 'بانک مهر' in appfilter * fixed 'بانک مهر' * updated 'Mead Mate' * Sixe fix mead_mate.svg --------- Co-authored-by: Gleb <60105060+x9136@users.noreply.github.com> --- app/assets/appfilter.xml | 3 +++ svgs/bank_mehr.svg | 3 +++ svgs/mead_mate.svg | 1 + svgs/nobitex.svg | 4 ++++ 4 files changed, 11 insertions(+) create mode 100644 svgs/bank_mehr.svg create mode 100644 svgs/mead_mate.svg create mode 100644 svgs/nobitex.svg diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 9cd9467ece9..29ff5cda89f 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -882,6 +882,7 @@ + @@ -5779,6 +5780,7 @@ + @@ -6872,6 +6874,7 @@ + diff --git a/svgs/bank_mehr.svg b/svgs/bank_mehr.svg new file mode 100644 index 00000000000..f46180b3b07 --- /dev/null +++ b/svgs/bank_mehr.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/mead_mate.svg b/svgs/mead_mate.svg new file mode 100644 index 00000000000..5a9999b9eeb --- /dev/null +++ b/svgs/mead_mate.svg @@ -0,0 +1 @@ + diff --git a/svgs/nobitex.svg b/svgs/nobitex.svg new file mode 100644 index 00000000000..92e92ffb02f --- /dev/null +++ b/svgs/nobitex.svg @@ -0,0 +1,4 @@ + + + + From c80d861e229dfcb12320d09240940671dc9a1222 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Sat, 14 Sep 2024 09:52:51 +0800 Subject: [PATCH 136/144] Create vcs.xml --- .idea/vcs.xml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .idea/vcs.xml diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000000..14f965d36f5 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,20 @@ + + + + + + + + + From 00b42dff3dd33ec64087b2492ddcf3856b17746c Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:02:03 +0300 Subject: [PATCH 137/144] +15 links (#2329) --- app/assets/appfilter.xml | 21 ++++++++++++++++++--- svgs/{athena.svg => zorin_connect.svg} | 0 2 files changed, 18 insertions(+), 3 deletions(-) rename svgs/{athena.svg => zorin_connect.svg} (100%) diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 29ff5cda89f..5923fea3693 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -244,12 +244,14 @@ + + @@ -672,6 +674,7 @@ + @@ -719,9 +722,9 @@ - + - + @@ -882,7 +885,6 @@ - @@ -2196,6 +2198,7 @@ + @@ -2995,6 +2998,7 @@ + @@ -3218,6 +3222,7 @@ + @@ -3858,6 +3863,7 @@ + @@ -6021,6 +6027,7 @@ + @@ -6279,6 +6286,7 @@ + @@ -6564,6 +6572,7 @@ + @@ -7094,6 +7103,7 @@ + @@ -7555,6 +7565,7 @@ + @@ -7880,6 +7891,7 @@ + @@ -8033,6 +8045,7 @@ + @@ -12437,6 +12450,7 @@ + @@ -12609,6 +12623,7 @@ + diff --git a/svgs/athena.svg b/svgs/zorin_connect.svg similarity index 100% rename from svgs/athena.svg rename to svgs/zorin_connect.svg From 263eaf01db19e4dd2120470267479b066d3052e3 Mon Sep 17 00:00:00 2001 From: Gleb <60105060+x9136@users.noreply.github.com> Date: Sat, 14 Sep 2024 12:12:57 +0300 Subject: [PATCH 138/144] Minor fix to the self-review list (#2330) --- .github/icon_checklist.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index 1c7013045c2..2162f28c151 100644 --- a/.github/icon_checklist.md +++ b/.github/icon_checklist.md @@ -1,6 +1,6 @@ Thanks for your contribution! -We try to do the review within 7 days. While waiting for a review from our team, you can do a self-review to ensure that your icons are suitable for Lawnicons. +While waiting for a review from our team, you can do a self-review to ensure that your icons are suitable for Lawnicons. We try to do the review within 7 days. ### Canvas and sizes 1. Canvas: `192×192px`. From 5638e36f8065306506a93a16200021f37ced93e1 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:32:19 +0800 Subject: [PATCH 139/144] Update new icons build process --- .github/workflows/build_debug_apk.yml | 3 -- .../lawnicons/helper/AppfilterDiffCreator.kt | 42 ++++++++++++++----- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build_debug_apk.yml b/.github/workflows/build_debug_apk.yml index c83c617e15e..23f1856941b 100644 --- a/.github/workflows/build_debug_apk.yml +++ b/.github/workflows/build_debug_apk.yml @@ -16,9 +16,6 @@ jobs: uses: actions/checkout@v4 with: submodules: true - - name: Fetch all needed branches - run: git fetch origin main:main && git fetch origin develop:develop - continue-on-error: true - uses: actions/setup-java@v4 with: distribution: 'zulu' diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt index 3988d9319b4..ed8f7bb3c5c 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -21,20 +21,42 @@ import java.io.File object AppfilterDiffCreator { private const val OUTPUT_FILE = "/xml/appfilter_diff.xml" - private fun getBranchContents( - branch: String, + private fun getPreviousReleaseLines( appFilterFile: String, ): List { - val command = listOf("git", "show", "$branch:$appFilterFile") - val process = ProcessBuilder(command) + val fetchCommand = listOf("git", "fetch", "--tags") + val fetchProcess = ProcessBuilder(fetchCommand) .redirectErrorStream(true) .start() + val output = fetchProcess.inputStream.bufferedReader().readText() + if (fetchProcess.waitFor() != 0) { + throw RuntimeException("Failed to execute $fetchCommand: $output") + } else { + val describeCommand = listOf("git", "describe", "--tags", "--abbrev=0") + val describeProcess = ProcessBuilder(describeCommand) + .redirectErrorStream(true) + .start() - val result = process.inputStream.bufferedReader().readLines() - if (process.waitFor() != 0) { - throw RuntimeException("Failed to execute command: $command") + val latestTag = describeProcess.inputStream.bufferedReader().readLine() + if (describeProcess.waitFor() != 0) { + throw RuntimeException("Failed to get latest tag: $latestTag") + } + + val showCommand = listOf("git", "show", "$latestTag:$appFilterFile") + val process = ProcessBuilder(showCommand) + .redirectErrorStream(true) + .start() + + val result = process.inputStream.bufferedReader().readLines() + if (process.waitFor() != 0) { + throw RuntimeException("Failed to execute $showCommand: $result") + } + return result } - return result + } + + private fun readFileContents(filePath: String): List { + return File(filePath).readLines() } private fun getLineDiff( @@ -72,8 +94,8 @@ object AppfilterDiffCreator { resDir: String, appFilterFile: String, ) { - val mainLines = getBranchContents("main", appFilterFile) - val developLines = getBranchContents("develop", appFilterFile) + val mainLines = getPreviousReleaseLines(appFilterFile) + val developLines = readFileContents(appFilterFile) val diff = getLineDiff(mainLines, developLines) writeDiffToFile(diff, resDir) From ed06a0218b8caa91908f18d4807544c92494470f Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:32:34 +0800 Subject: [PATCH 140/144] Fix snackbar showing twice --- .../lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 997f02570d2..45bc7d3b97c 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt @@ -165,8 +165,8 @@ fun RequestHandler( content(interactionSource) - LaunchedEffect(iconRequestList.isNotEmpty()) { - if (showFirstLaunchSnackbar) { + LaunchedEffect(enabled) { + if (showFirstLaunchSnackbar && enabled) { openSnackbarFirstLaunchContent( context, scope, From 550917afb667ee754e4809f1a3967fa20694846f Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:33:46 +0800 Subject: [PATCH 141/144] Bump version name and code --- app/build.gradle.kts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index cddee9531d8..4485db657eb 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -26,8 +26,8 @@ val ciRunNumber = providers.environmentVariable("GITHUB_RUN_NUMBER").orNull.orEm val isReleaseBuild = ciBuild && ciRef.contains("main") val devReleaseName = if (ciBuild) "(Dev #$ciRunNumber)" else "($buildCommit)" -val version = "2.11.0" -val versionDisplayName = "$version ${if (isReleaseBuild) "" else devReleaseName}" +val version = "2.12.0" +val versionDisplayName = version + if (!isReleaseBuild) " $devReleaseName" else "" android { compileSdk = 35 @@ -37,7 +37,7 @@ android { applicationId = "app.lawnchair.lawnicons" minSdk = 26 targetSdk = compileSdk - versionCode = 15 + versionCode = 16 versionName = versionDisplayName vectorDrawables.useSupportLibrary = true } From 6dab19a6988443381e8c4427e901db2b0589cc9c Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 18:53:33 +0800 Subject: [PATCH 142/144] Fix build error --- .../lawnicons/helper/AppfilterDiffCreator.kt | 53 ++++++++++--------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt index ed8f7bb3c5c..66b1089230a 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -24,34 +24,39 @@ object AppfilterDiffCreator { private fun getPreviousReleaseLines( appFilterFile: String, ): List { - val fetchCommand = listOf("git", "fetch", "--tags") - val fetchProcess = ProcessBuilder(fetchCommand) - .redirectErrorStream(true) - .start() - val output = fetchProcess.inputStream.bufferedReader().readText() - if (fetchProcess.waitFor() != 0) { - throw RuntimeException("Failed to execute $fetchCommand: $output") - } else { - val describeCommand = listOf("git", "describe", "--tags", "--abbrev=0") - val describeProcess = ProcessBuilder(describeCommand) + return try { + val fetchCommand = listOf("git", "fetch", "--tags") + val fetchProcess = ProcessBuilder(fetchCommand) .redirectErrorStream(true) .start() + val output = fetchProcess.inputStream.bufferedReader().readText() + if (fetchProcess.waitFor() != 0) { + throw RuntimeException("Failed to execute $fetchCommand: $output") + } else { + val describeCommand = listOf("git", "describe", "--tags", "--abbrev=0") + val describeProcess = ProcessBuilder(describeCommand) + .redirectErrorStream(true) + .start() - val latestTag = describeProcess.inputStream.bufferedReader().readLine() - if (describeProcess.waitFor() != 0) { - throw RuntimeException("Failed to get latest tag: $latestTag") - } + val latestTag = describeProcess.inputStream.bufferedReader().readLine() + if (describeProcess.waitFor() != 0) { + throw RuntimeException("Failed to get latest tag: $latestTag") + } - val showCommand = listOf("git", "show", "$latestTag:$appFilterFile") - val process = ProcessBuilder(showCommand) - .redirectErrorStream(true) - .start() + val showCommand = listOf("git", "show", "$latestTag:$appFilterFile") + val process = ProcessBuilder(showCommand) + .redirectErrorStream(true) + .start() - val result = process.inputStream.bufferedReader().readLines() - if (process.waitFor() != 0) { - throw RuntimeException("Failed to execute $showCommand: $result") + val result = process.inputStream.bufferedReader().readLines() + if (process.waitFor() != 0) { + throw RuntimeException("Failed to execute $showCommand: $result") + } + result } - return result + } catch (e: Exception) { + println(e) + listOf() } } @@ -94,8 +99,8 @@ object AppfilterDiffCreator { resDir: String, appFilterFile: String, ) { - val mainLines = getPreviousReleaseLines(appFilterFile) - val developLines = readFileContents(appFilterFile) + val mainLines = readFileContents(appFilterFile) + val developLines = getPreviousReleaseLines(appFilterFile) val diff = getLineDiff(mainLines, developLines) writeDiffToFile(diff, resDir) From 93342555610e704701d37ab0800d7eb913304100 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:14:57 +0800 Subject: [PATCH 143/144] Update placeholder UI --- .../ui/components/home/PlaceholderUI.kt | 155 ++++++++++++++++++ .../lawnicons/ui/destination/Contributors.kt | 11 ++ .../lawnicons/ui/destination/Home.kt | 13 +- app/src/main/res/values-en-rUS/strings.xml | 70 -------- .../lawnicons/helper/AppfilterDiffCreator.kt | 10 +- 5 files changed, 174 insertions(+), 85 deletions(-) create mode 100644 app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/PlaceholderUI.kt delete mode 100644 app/src/main/res/values-en-rUS/strings.xml diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/PlaceholderUI.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/PlaceholderUI.kt new file mode 100644 index 00000000000..36301c012f5 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/PlaceholderUI.kt @@ -0,0 +1,155 @@ +/* + * Copyright 2024 Lawnchair Launcher + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package app.lawnchair.lawnicons.ui.components.home + +import android.annotation.SuppressLint +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.GridItemSpan +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.BottomAppBar +import androidx.compose.material3.BottomAppBarDefaults +import androidx.compose.material3.CenterAlignedTopAppBar +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.unit.dp +import app.lawnchair.lawnicons.ui.components.core.placeholder.PlaceholderHighlight +import app.lawnchair.lawnicons.ui.components.core.placeholder.fade +import app.lawnchair.lawnicons.ui.components.core.placeholder.placeholder +import app.lawnchair.lawnicons.ui.components.core.placeholder.shimmer +import app.lawnchair.lawnicons.ui.util.toPaddingValues + +@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun PlaceholderUI( + showDummyCard: Boolean, + modifier: Modifier = Modifier, +) { + val contentPadding = IconPreviewGridPadding.Defaults + Scaffold( + modifier = modifier, + bottomBar = { + BottomAppBar( + modifier = Modifier.placeholder( + visible = true, + color = BottomAppBarDefaults.containerColor, + highlight = PlaceholderHighlight.shimmer( + MaterialTheme.colorScheme.surfaceContainer, + ), + ), + ) {} + }, + ) { + LazyVerticalGrid( + columns = GridCells.Adaptive(80.dp), + userScrollEnabled = false, + contentPadding = WindowInsets.navigationBars.toPaddingValues( + additionalStart = contentPadding.horizontalPadding, + additionalTop = contentPadding.topPadding, + additionalEnd = contentPadding.horizontalPadding, + ), + ) { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + CenterAlignedTopAppBar( + title = { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Box( + modifier = Modifier + .size(36.dp) + .clip(CircleShape) + .placeholder( + visible = true, + color = MaterialTheme.colorScheme.surfaceContainer, + highlight = PlaceholderHighlight.fade(), + ), + ) + Spacer(modifier = Modifier.width(8.dp)) + Box( + modifier = Modifier + .width(96.dp) + .height(16.dp) + .clip(MaterialTheme.shapes.small) + .placeholder( + visible = true, + color = MaterialTheme.colorScheme.surfaceContainer, + highlight = PlaceholderHighlight.fade(), + ), + ) + } + }, + ) + } + if (showDummyCard) { + item(span = { GridItemSpan(maxLineSpan) }) { + Box( + modifier = Modifier + .padding(horizontal = 8.dp) + .padding(bottom = 12.dp) + .height(48.dp) + .fillMaxWidth() + .clip(CircleShape) + .placeholder( + visible = true, + color = MaterialTheme.colorScheme.surfaceContainer, + highlight = PlaceholderHighlight.shimmer( + MaterialTheme.colorScheme.surfaceContainerHigh, + ), + ), + ) {} + } + } + + items(100) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .padding(all = 8.dp) + .aspectRatio(ratio = 1F) + .clip(shape = CircleShape) + .placeholder( + visible = true, + color = MaterialTheme.colorScheme.iconColor, + highlight = PlaceholderHighlight.shimmer( + MaterialTheme.colorScheme.surfaceContainer, + ), + ), + ) {} + } + } + } +} diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt index 124c0c8b5a1..1a677077f2e 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt @@ -153,7 +153,18 @@ private fun ContributorListPlaceholder( LazyColumn( modifier = modifier, contentPadding = contentPadding, + userScrollEnabled = false, ) { + item { + ContributorRowPlaceholder( + first = true, + last = true, + divider = false, + ) + } + item { + Spacer(modifier = Modifier.height(16.dp)) + } items(itemCount) { ContributorRowPlaceholder( first = it == 0, diff --git a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt index 6db59cfbf7d..8a4981aae31 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Home.kt @@ -3,12 +3,9 @@ package app.lawnchair.lawnicons.ui.destination import android.annotation.SuppressLint import androidx.compose.animation.Crossfade import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.rememberLazyGridState -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -17,7 +14,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.platform.LocalContext @@ -36,6 +32,7 @@ import app.lawnchair.lawnicons.ui.components.home.IconPreviewGrid import app.lawnchair.lawnicons.ui.components.home.IconPreviewGridPadding import app.lawnchair.lawnicons.ui.components.home.IconRequestFAB import app.lawnchair.lawnicons.ui.components.home.NewIconsCard +import app.lawnchair.lawnicons.ui.components.home.PlaceholderUI import app.lawnchair.lawnicons.ui.components.home.search.PlaceholderSearchBar import app.lawnchair.lawnicons.ui.theme.LawniconsTheme import app.lawnchair.lawnicons.ui.util.PreviewLawnicons @@ -166,13 +163,7 @@ private fun Home( if (isExpandedScreen) { PlaceholderSearchBar() } else { - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize(), - ) { - CircularProgressIndicator() - } + PlaceholderUI(newIconsInfoModel.iconCount != 0) } } } diff --git a/app/src/main/res/values-en-rUS/strings.xml b/app/src/main/res/values-en-rUS/strings.xml deleted file mode 100644 index 72a16c0059c..00000000000 --- a/app/src/main/res/values-en-rUS/strings.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - Version %s - - - - - Pick an icon - - Search - - %s not found - - About - - - - Icon request form - - - Contributors - - Core contributors - - See all contributors - - View on GitHub - - Share details - - Core app - Icons - Infrastructure - - - Special thanks - - For inspiring the app icon - - For naming the app - - Open-source licenses - - - Name - - Drawable - - Component name - - Mapped components - - If the icon is outdated due to rebranding, create an issue on GitHub. - - Toggle visibility of contents - - Request icons - Copy to clipboard - Copied text - - Request missing icons from the bottom bar - Copied icon request details to clipboard. To request them, submit the details into the form. - Open form - Clear - New icons in v%1$s - New icons (%1$s) - diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt index 66b1089230a..d51108c8950 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -33,7 +33,8 @@ object AppfilterDiffCreator { if (fetchProcess.waitFor() != 0) { throw RuntimeException("Failed to execute $fetchCommand: $output") } else { - val describeCommand = listOf("git", "describe", "--tags", "--abbrev=0") + val describeCommand = + listOf("git", "describe", "--tags", "--abbrev=0", "--start=main") val describeProcess = ProcessBuilder(describeCommand) .redirectErrorStream(true) .start() @@ -99,9 +100,10 @@ object AppfilterDiffCreator { resDir: String, appFilterFile: String, ) { - val mainLines = readFileContents(appFilterFile) - val developLines = getPreviousReleaseLines(appFilterFile) - val diff = getLineDiff(mainLines, developLines) + val diff = getLineDiff( + getPreviousReleaseLines(appFilterFile), + readFileContents(appFilterFile), + ) writeDiffToFile(diff, resDir) } From c4864d7d10913a9d76ca1f433396ab6b6393eb73 Mon Sep 17 00:00:00 2001 From: SuperDragonXD <70206496+SuperDragonXD@users.noreply.github.com> Date: Sat, 14 Sep 2024 20:56:32 +0800 Subject: [PATCH 144/144] Fix build --- .../lawnicons/helper/AppfilterDiffCreator.kt | 61 +++++++++++-------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt index d51108c8950..1e49e4d3a24 100644 --- a/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -25,36 +25,43 @@ object AppfilterDiffCreator { appFilterFile: String, ): List { return try { - val fetchCommand = listOf("git", "fetch", "--tags") - val fetchProcess = ProcessBuilder(fetchCommand) + runGitCommand(listOf("fetch", "--tags")) + + val tagCommand = + listOf("/usr/bin/bash", "-c", "git tag --sort=-creatordate | head -n 1") + val tagProcess = ProcessBuilder(tagCommand) .redirectErrorStream(true) .start() - val output = fetchProcess.inputStream.bufferedReader().readText() - if (fetchProcess.waitFor() != 0) { - throw RuntimeException("Failed to execute $fetchCommand: $output") - } else { - val describeCommand = - listOf("git", "describe", "--tags", "--abbrev=0", "--start=main") - val describeProcess = ProcessBuilder(describeCommand) - .redirectErrorStream(true) - .start() - - val latestTag = describeProcess.inputStream.bufferedReader().readLine() - if (describeProcess.waitFor() != 0) { - throw RuntimeException("Failed to get latest tag: $latestTag") - } - - val showCommand = listOf("git", "show", "$latestTag:$appFilterFile") - val process = ProcessBuilder(showCommand) - .redirectErrorStream(true) - .start() - - val result = process.inputStream.bufferedReader().readLines() - if (process.waitFor() != 0) { - throw RuntimeException("Failed to execute $showCommand: $result") - } - result + + val latestTag = tagProcess.inputStream.bufferedReader().readLine() + if (tagProcess.waitFor() != 0) { + throw RuntimeException("Failed to get latest tag") } + + runGitCommand(listOf("show", "$latestTag:$appFilterFile")) + } catch (e: Exception) { + println(e) + listOf() + } + } + + private fun runGitCommand( + args: List, + ): List { + return try { + val command = listOf("git") + args + + val process = ProcessBuilder(command) + .redirectErrorStream(true) + .start() + + val result = process.inputStream.bufferedReader().readLines() + if (process.waitFor() != 0) { + throw RuntimeException("Failed to execute $command: $result") + } + println("task git $args completed") + + result } catch (e: Exception) { println(e) listOf()