diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 214528c62..854b48d3a 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,8 +1,8 @@ blank_issues_enabled: false contact_links: - - name: Link apps to existing icons + - name: Link apps to identical 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. + about: Learn more about linking an app to an existing icon via a pull request. - name: Icon Request url: https://forms.gle/xt7sJhgWEasuo9TR9 about: Please request your icons in this form. diff --git a/.github/icon_checklist.md b/.github/icon_checklist.md index 8059999f6..2162f28c1 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. +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`. 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/.github/workflows/build_release_apk.yml b/.github/workflows/build_release_apk.yml index e20ea88a5..dad54cb5b 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: diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..14f965d36 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 06c3dc6cf..82dceff8b 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. diff --git a/app/assets/appfilter.xml b/app/assets/appfilter.xml index 578bdb4be..632add8d0 100644 --- a/app/assets/appfilter.xml +++ b/app/assets/appfilter.xml @@ -61,6 +61,7 @@ + @@ -85,6 +86,7 @@ + @@ -153,6 +155,8 @@ + + @@ -171,6 +175,7 @@ + @@ -193,12 +198,14 @@ + + @@ -237,12 +244,14 @@ + + @@ -316,6 +325,7 @@ + @@ -446,7 +456,9 @@ + + @@ -602,6 +614,7 @@ + @@ -661,6 +674,8 @@ + + @@ -705,11 +720,12 @@ + - + - + @@ -787,6 +803,7 @@ + @@ -935,6 +952,7 @@ + @@ -1037,8 +1055,10 @@ + + @@ -1066,6 +1086,7 @@ + @@ -1303,6 +1324,7 @@ + @@ -1315,6 +1337,7 @@ + @@ -1334,6 +1357,10 @@ + + + + @@ -1438,12 +1465,15 @@ + + + @@ -1556,11 +1586,15 @@ + + + + @@ -1766,6 +1800,7 @@ + @@ -1776,6 +1811,7 @@ + @@ -1813,6 +1849,7 @@ + @@ -1864,6 +1901,7 @@ + @@ -2117,6 +2155,7 @@ + @@ -2148,6 +2187,7 @@ + @@ -2159,6 +2199,8 @@ + + @@ -2336,6 +2378,7 @@ + @@ -2425,6 +2468,7 @@ + @@ -2480,6 +2524,7 @@ + @@ -2496,6 +2541,7 @@ + @@ -2572,6 +2618,7 @@ + @@ -2612,6 +2659,7 @@ + @@ -2678,6 +2726,7 @@ + @@ -2722,57 +2771,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2949,6 +2999,7 @@ + @@ -2958,6 +3009,7 @@ + @@ -2977,6 +3029,7 @@ + @@ -3119,10 +3172,13 @@ + + + @@ -3135,6 +3191,8 @@ + + @@ -3165,6 +3223,7 @@ + @@ -3219,6 +3278,7 @@ + @@ -3254,6 +3314,7 @@ + @@ -3345,6 +3406,11 @@ + + + + + @@ -3510,8 +3576,11 @@ + + + @@ -3562,6 +3631,7 @@ + @@ -3605,6 +3675,7 @@ + @@ -3617,6 +3688,8 @@ + + @@ -3650,6 +3723,7 @@ + @@ -3658,6 +3732,7 @@ + @@ -3789,6 +3864,7 @@ + @@ -3853,6 +3929,7 @@ + @@ -3915,6 +3992,7 @@ + @@ -3952,6 +4030,7 @@ + @@ -3993,6 +4072,7 @@ + @@ -4015,12 +4095,14 @@ + + @@ -4035,6 +4117,7 @@ + @@ -4050,16 +4133,19 @@ + + + @@ -4166,6 +4252,7 @@ + @@ -4325,6 +4412,7 @@ + @@ -4343,6 +4431,7 @@ + @@ -4360,8 +4449,11 @@ + + + @@ -4406,6 +4498,7 @@ + @@ -4420,7 +4513,10 @@ + + + @@ -4452,6 +4548,7 @@ + @@ -4493,11 +4590,13 @@ + + @@ -4530,7 +4629,9 @@ + + @@ -4590,6 +4691,7 @@ + @@ -4610,6 +4712,7 @@ + @@ -4649,6 +4752,7 @@ + @@ -4694,6 +4798,7 @@ + @@ -4731,6 +4836,7 @@ + @@ -4801,6 +4907,7 @@ + @@ -4834,6 +4941,8 @@ + + @@ -4869,6 +4978,7 @@ + @@ -4899,7 +5009,10 @@ + + + @@ -5035,10 +5148,12 @@ + + @@ -5049,6 +5164,7 @@ + @@ -5117,6 +5233,7 @@ + @@ -5163,6 +5280,7 @@ + @@ -5209,6 +5327,7 @@ + @@ -5223,6 +5342,7 @@ + @@ -5238,6 +5358,7 @@ + @@ -5377,6 +5498,7 @@ + @@ -5462,9 +5584,11 @@ + + @@ -5497,6 +5621,7 @@ + @@ -5517,6 +5642,7 @@ + @@ -5580,6 +5706,7 @@ + @@ -5633,6 +5760,11 @@ + + + + + @@ -5655,6 +5787,7 @@ + @@ -5669,6 +5802,7 @@ + @@ -5682,6 +5816,8 @@ + + @@ -5801,6 +5937,7 @@ + @@ -5834,6 +5971,7 @@ + @@ -5845,6 +5983,7 @@ + @@ -5889,12 +6028,15 @@ - - + + + + + @@ -5946,6 +6088,7 @@ + @@ -6006,6 +6149,7 @@ + @@ -6072,6 +6216,7 @@ + @@ -6081,6 +6226,7 @@ + @@ -6142,6 +6288,7 @@ + @@ -6153,7 +6300,9 @@ + + @@ -6175,6 +6324,7 @@ + @@ -6191,7 +6341,7 @@ - + @@ -6260,12 +6410,14 @@ + + @@ -6298,6 +6450,7 @@ + @@ -6318,9 +6471,11 @@ + + @@ -6333,6 +6488,7 @@ + @@ -6418,6 +6574,7 @@ + @@ -6531,6 +6688,7 @@ + @@ -6553,6 +6711,7 @@ + @@ -6607,6 +6766,7 @@ + @@ -6688,6 +6848,7 @@ + @@ -6724,6 +6885,7 @@ + @@ -6775,6 +6937,7 @@ + @@ -6847,6 +7010,7 @@ + @@ -6864,6 +7028,7 @@ + @@ -6940,6 +7105,7 @@ + @@ -7030,6 +7196,7 @@ + @@ -7186,6 +7353,7 @@ + @@ -7198,6 +7366,7 @@ + @@ -7256,6 +7425,7 @@ + @@ -7307,6 +7477,7 @@ + @@ -7333,6 +7504,7 @@ + @@ -7354,6 +7526,7 @@ + @@ -7361,6 +7534,8 @@ + + @@ -7384,12 +7559,15 @@ + + + @@ -7637,12 +7815,14 @@ + + @@ -7661,6 +7841,7 @@ + @@ -7708,9 +7889,12 @@ + + + @@ -7721,6 +7905,7 @@ + @@ -7795,8 +7980,10 @@ + + @@ -7805,6 +7992,7 @@ + @@ -7823,6 +8011,7 @@ + @@ -7859,6 +8048,7 @@ + @@ -7940,11 +8130,13 @@ + + @@ -7984,6 +8176,7 @@ + @@ -7992,6 +8185,7 @@ + @@ -8047,6 +8241,7 @@ + @@ -8166,12 +8361,14 @@ + + @@ -8192,6 +8389,7 @@ + @@ -8255,9 +8453,11 @@ + + @@ -8408,6 +8608,7 @@ + @@ -8471,6 +8672,7 @@ + @@ -8491,11 +8693,13 @@ + + @@ -8516,6 +8720,7 @@ + @@ -8540,12 +8745,14 @@ + + @@ -8575,7 +8782,9 @@ + + @@ -8778,6 +8987,7 @@ + @@ -8963,6 +9173,7 @@ + @@ -9102,6 +9313,7 @@ + @@ -9466,6 +9678,7 @@ + @@ -9508,6 +9721,7 @@ + @@ -9639,8 +9853,10 @@ + + @@ -9671,6 +9887,7 @@ + @@ -9741,6 +9958,7 @@ + @@ -9760,6 +9978,7 @@ + @@ -9783,6 +10002,7 @@ + @@ -9808,11 +10028,13 @@ + + @@ -9836,6 +10058,7 @@ + @@ -10009,6 +10232,7 @@ + @@ -10026,6 +10250,7 @@ + @@ -10049,6 +10274,7 @@ + @@ -10060,6 +10286,7 @@ + @@ -10124,6 +10351,7 @@ + @@ -10172,6 +10400,7 @@ + @@ -10238,6 +10467,7 @@ + @@ -10327,6 +10557,7 @@ + @@ -10584,7 +10815,8 @@ - + + @@ -10696,6 +10928,7 @@ + @@ -10740,6 +10973,7 @@ + @@ -10748,6 +10982,7 @@ + @@ -10758,6 +10993,7 @@ + @@ -10845,6 +11081,7 @@ + @@ -10856,6 +11093,7 @@ + @@ -10864,7 +11102,7 @@ - + @@ -10902,6 +11140,7 @@ + @@ -10916,20 +11155,21 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -10952,8 +11192,9 @@ - - + + + @@ -10970,6 +11211,7 @@ + @@ -11056,6 +11298,7 @@ + @@ -11125,6 +11368,7 @@ + @@ -11138,6 +11382,8 @@ + + @@ -11148,6 +11394,7 @@ + @@ -11171,6 +11418,7 @@ + @@ -11247,6 +11495,7 @@ + @@ -11316,10 +11565,12 @@ + + @@ -11328,6 +11579,8 @@ + + @@ -11358,6 +11611,9 @@ + + + @@ -11383,6 +11639,7 @@ + @@ -11396,6 +11653,7 @@ + @@ -11429,6 +11687,7 @@ + @@ -11462,6 +11721,7 @@ + @@ -11477,6 +11737,7 @@ + @@ -11709,6 +11970,7 @@ + @@ -11767,10 +12029,12 @@ + + @@ -11808,6 +12072,7 @@ + @@ -11832,6 +12097,8 @@ + + @@ -11857,10 +12124,12 @@ + + @@ -11978,6 +12247,7 @@ + @@ -12036,6 +12306,7 @@ + @@ -12051,6 +12322,7 @@ + @@ -12108,6 +12380,8 @@ + + @@ -12135,6 +12409,7 @@ + @@ -12169,15 +12444,17 @@ - - + + + + @@ -12216,6 +12493,8 @@ + + @@ -12248,6 +12527,8 @@ + + @@ -12263,10 +12544,12 @@ + + @@ -12275,6 +12558,7 @@ + @@ -12282,6 +12566,7 @@ + @@ -12331,8 +12616,9 @@ + - + @@ -12341,6 +12627,7 @@ + @@ -12354,8 +12641,8 @@ - - + + @@ -12409,6 +12696,7 @@ + @@ -12422,6 +12710,7 @@ + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ca1b7c156..4485db657 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 } @@ -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") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b32bcae0c..b40f1576d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,12 +18,12 @@ - + - + diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png index a0c46279e..a41561910 100644 Binary files a/app/src/main/ic_launcher-playstore.png and b/app/src/main/ic_launcher-playstore.png differ 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 000000000..cef43aedc --- /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 000000000..1866e8621 --- /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 b641936f8..700a06057 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,56 @@ 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 - */ 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 showDebugMenu = BoolPref("debug_menu", false) + 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 /** - * Returns a singleton instance of PreferenceManager + * Returns a singleton instance of [PreferenceManager] */ fun getInstance(context: Context): PreferenceManager { return instance ?: synchronized(this) { @@ -69,8 +105,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 5562654a5..5ffd551ae 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 94855617e..41421916e 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 fef3a4c2e..4bd3d20a0 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/DebugMenu.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/DebugMenu.kt new file mode 100644 index 000000000..e78673b78 --- /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 28e7cb023..d355b29ce 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 3821e3e60..715798045 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,10 +7,10 @@ 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 -import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets @@ -24,7 +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.LazyGridScope import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items @@ -49,9 +49,11 @@ 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 +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 @@ -61,16 +63,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: (LazyGridScope.() -> Unit) = {}, ) { val indexOfFirstItem by remember { derivedStateOf { gridState.firstVisibleItemIndex } } val letter = iconInfo[indexOfFirstItem].label[0].uppercase() @@ -81,48 +106,26 @@ 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() - } - } + 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 +141,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, @@ -195,10 +219,11 @@ private fun ScrollbarIndicator( } } -@OptIn(ExperimentalMaterial3Api::class) +@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class) @Composable -private fun AppBarListItem(modifier: Modifier = Modifier) { +fun AppBarListItem(modifier: Modifier = Modifier) { val context = LocalContext.current + val prefs = preferenceManager(context) CenterAlignedTopAppBar( modifier = modifier, title = { @@ -209,7 +234,15 @@ private 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) + .clip(CircleShape) + .combinedClickable( + onClick = {}, + onLongClick = { + prefs.showDebugMenu.toggle() + }, + ), ) } Spacer(modifier = Modifier.width(8.dp)) @@ -229,9 +262,9 @@ private fun IconGridPreview() { Surface { IconPreviewGrid( iconInfo = SampleData.iconInfoList, - isExpandedScreen = false, onSendResult = {}, modifier = Modifier, + contentPadding = IconPreviewGridPadding.Defaults, isIconPicker = false, ) } @@ -246,9 +279,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/IconRequestFAB.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/IconRequestFAB.kt index 53dfd7986..45bc7d3b9 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,59 +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.ModalBottomSheet -import androidx.compose.material3.SheetState +import androidx.compose.material3.MaterialTheme +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 @@ -68,9 +54,13 @@ fun IconRequestFAB( modifier: Modifier = Modifier, ) { val list = iconRequestModel?.list ?: emptyList() + val enabled = iconRequestModel != null + RequestHandler( + enabled = enabled, iconRequestList = list, snackbarHostState = snackbarHostState, + onLongClick = {}, ) { interactionSource -> ExtendedFloatingActionButton( text = { @@ -84,12 +74,14 @@ 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, ) } } +@OptIn(ExperimentalMaterial3Api::class) @Composable fun IconRequestIconButton( snackbarHostState: SnackbarHostState, @@ -97,31 +89,54 @@ fun IconRequestIconButton( modifier: Modifier = Modifier, ) { 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 = {}, - interactionSource = interactionSource, + 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() @@ -131,134 +146,82 @@ 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() } HandleTouchInteractions( + enabled = enabled, interactionSource = interactionSource, 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, ) content(interactionSource) - if (showFirstLaunchSnackbar && iconRequestList.isNotEmpty()) { - openSnackbarFirstLaunchContent( - context, - scope, - prefs.showFirstLaunchSnackbar::toggle, - snackbarHostState, - ) - } - - AnimatedVisibility(visible = sheetExpanded) { - ModalBottomSheet( - onDismissRequest = { sheetExpanded = false }, - sheetState = sheetState, - ) { - IconRequestSheet(requestList, context) + LaunchedEffect(enabled) { + if (showFirstLaunchSnackbar && enabled) { + openSnackbarFirstLaunchContent( + context, + scope, + { prefs.showFirstLaunchSnackbar.set(false) }, + snackbarHostState, + ) } } } -@OptIn(ExperimentalMaterial3Api::class) @Composable private fun HandleTouchInteractions( + enabled: Boolean, interactionSource: MutableInteractionSource, viewConfiguration: ViewConfiguration, context: Context, coroutineScope: CoroutineScope, - onExpandSheet: (Boolean) -> Unit, - sheetState: SheetState, + onLongClick: () -> Unit, iconRequestList: List, directLinkEnabled: Boolean, requestList: String, encodedRequestList: String, snackbarHostState: SnackbarHostState, ) { - val prefs = preferenceManager() - val lastestOnExpandSheet by rememberUpdatedState(newValue = onExpandSheet) - LaunchedEffect(interactionSource) { - var isLongClick = false + val latestOnClick by rememberUpdatedState(newValue = onLongClick) - 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 - is PressInteraction.Release -> { - if (!isLongClick) { - prefs.showFirstLaunchSnackbar.set(false) - handleRequestClick( - iconRequestList, - context, - directLinkEnabled, - encodedRequestList, - requestList, - coroutineScope, - snackbarHostState, - ) + interactionSource.interactions.collectLatest { interaction -> + when (interaction) { + is PressInteraction.Press -> { + isLongClick = false + delay(viewConfiguration.longPressTimeoutMillis) + isLongClick = true + latestOnClick() } - } - is PressInteraction.Cancel -> { - isLongClick = false - } - } - } - } -} + is PressInteraction.Release -> { + if (!isLongClick) { + handleRequestClick( + iconRequestList, + context, + directLinkEnabled, + encodedRequestList, + requestList, + coroutineScope, + snackbarHostState, + ) + } + } -@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)) + is PressInteraction.Cancel -> { + isLongClick = false } } } @@ -269,12 +232,6 @@ private fun IconRequestSheet(list: String, context: Context) { 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/components/home/NewIconsCard.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt new file mode 100644 index 000000000..894729a12 --- /dev/null +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/NewIconsCard.kt @@ -0,0 +1,117 @@ +/* + * 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.fillMaxWidth +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.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) { + Surface( + color = MaterialTheme.colorScheme.surfaceContainer, + shape = MaterialTheme.shapes.extraLarge, + modifier = modifier + .padding(horizontal = 8.dp) + .padding(bottom = 12.dp) + .fillMaxWidth(), + ) { + 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/PlaceholderUI.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/PlaceholderUI.kt new file mode 100644 index 000000000..36301c012 --- /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/components/home/search/SearchBar.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/components/home/search/SearchBar.kt index c2e1d4ac3..00bf71628 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/About.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/About.kt index 8f94c65b0..331f4bec9 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/Contributors.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/destination/Contributors.kt index 124c0c8b5..1a677077f 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 a257463e1..8a4981aae 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,22 +3,17 @@ 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.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 import androidx.compose.ui.platform.LocalContext @@ -27,19 +22,23 @@ 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.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 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.PlaceholderUI 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 }, ) } @@ -124,8 +127,8 @@ private fun Home( if (isExpandedScreen) { IconRequestFAB( iconRequestModel = iconRequestModel, - snackbarHostState = snackbarHostState, lazyGridState = lazyGridState, + snackbarHostState = snackbarHostState, ) } }, @@ -135,23 +138,32 @@ 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, - ) + ) { + if (!isExpandedScreen) { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + AppBarListItem() + } + } + if (newIconsInfoModel.iconCount != 0) { + item( + span = { GridItemSpan(maxLineSpan) }, + ) { + NewIconsCard(onNavigateToNewIcons) + } + } + } } } else { if (isExpandedScreen) { PlaceholderSearchBar() } else { - Column( - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.fillMaxSize(), - ) { - CircularProgressIndicator() - } + PlaceholderUI(newIconsInfoModel.iconCount != 0) } } } @@ -160,46 +172,29 @@ private fun Home( focusRequester.requestFocus() } } + val prefs = preferenceManager(context) + if (prefs.showDebugMenu.asState().value) { + DebugMenu( + iconInfoModel, + iconRequestModel, + newIconsInfoModel, + ) + } } } -@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 000000000..50ecbed8c --- /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/ui/util/Clipboard.kt b/app/src/main/kotlin/app/lawnchair/lawnicons/ui/util/Clipboard.kt new file mode 100644 index 000000000..05c98b9ac --- /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) +} 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 508d2b6ea..4de2ff697 100644 --- a/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt +++ b/app/src/main/kotlin/app/lawnchair/lawnicons/util/ContextExtensions.kt @@ -3,5 +3,10 @@ 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).toBitmap() +fun Context.appIcon(): Bitmap = ( + this.resources.getDrawable(R.mipmap.ic_launcher, this.theme) + ?: packageManager.getApplicationIcon(packageName) + ) + .toBitmap() 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 7ea59aeb1..d162a0a68 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 b6d23e9fe..c5510c80b 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 000000000..8b7136527 --- /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-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml deleted file mode 100644 index 2b068d114..000000000 --- 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 07d5da9cb..8b5801641 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 000000000..68858dffd --- /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 613857327..73a1df000 100644 --- a/app/src/main/res/drawable/ic_launcher_monochrome.xml +++ b/app/src/main/res/drawable/ic_launcher_monochrome.xml @@ -1,23 +1,16 @@ - - - + android:width="108dp" + android:height="108dp" + android:viewportWidth="108" + android:viewportHeight="108"> + + + 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 000000000..c1dc3184d --- /dev/null +++ b/app/src/main/res/drawable/new_releases.xml @@ -0,0 +1,18 @@ + + + + + diff --git a/app/src/main/res/drawable/splashscreen.xml b/app/src/main/res/drawable/splashscreen.xml index c6fbe0b70..14294fe58 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 5c65feb13..e628350bb 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,6 @@ - - + + 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 9f6652531..e628350bb 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,6 @@ - - - + + + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png index 2b56a86ce..215c29420 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png index 0d19dcfaa..89905a06e 100644 Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png index 4f6519bc3..9339572a4 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ 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 b58f8b2ed..a1a963963 100644 Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png index dc55538d3..0c68fcff9 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png index 7bd24d482..45c8bf29d 100644 Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index 3c105a690..57897b269 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png index 62f7fb52e..01a17e459 100644 Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 3f8383ec7..91de5c331 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ 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 c5ef87998..c3b529cc2 100644 Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values-af-rZA/strings.xml b/app/src/main/res/values-af-rZA/strings.xml index 2c96f6ec4..90b7bb591 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 ef89bd881..5e5a5e3c2 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 21ae600a6..866302f2f 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 f236fefd6..4801f551e 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 a07187d65..f027ffb95 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 c6ed397c7..029a7e0da 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 3041ae315..43469a3e3 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 deleted file mode 100644 index 17cf6c8d9..000000000 --- a/app/src/main/res/values-en-rUS/strings.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - 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 - - - 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 index a29653b66..d51cfff66 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 c9fef536a..c340555cf 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 c8a453a8f..d2cbd1f50 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 76fc6e5f4..b0b4132be 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 3184fce88..41ca14466 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 ba7af2b81..df795c61b 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 3f09b2b57..387ebbd0a 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 cb0f69037..b7370a305 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 3181c5bbb..56a09f300 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 f8340bc15..b8704ac8c 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 89abc4a41..38a40bd91 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 f35f9398a..4d277adfa 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 67620cfd5..f0222e807 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 bd3374164..ad88da4db 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 d5fe76ffd..0d6c05e5f 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 fb2e7ac9e..0ceff6c8c 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 fb2e7ac9e..0ceff6c8c 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 3b950f5c3..05f6e003b 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 038759f7b..d3a83b862 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 69e728926..a90e0a502 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 1f3cb6fa8..6f06403f4 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 10ee5b370..d6216d78f 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 d72618aab..14b69603e 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 cd4516528..13724a3e4 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 49ef20d66..f00bd94c3 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) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3f3ff0e25..976cffe6b 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/build.gradle.kts b/build.gradle.kts index 85c2d418d..6522fc065 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( diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2b189974c..8e876e1c5 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 diff --git a/send_notifications.py b/send_notifications.py index 4bc8d00ce..2072aaa0c 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') @@ -49,12 +51,15 @@ def telegram_commit_message(commits, commits_range): overview_link_tag = f'''{len(commits)} new commit{'s' if len(commits) > 1 else ''}''' 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 @@ -84,12 +89,15 @@ def discord_commit_message(commits, commits_range): 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''' - 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('.') @@ -99,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) diff --git a/settings.gradle.kts b/settings.gradle.kts index 8ac7d6152..5db0dbe58 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 { 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 000000000..1e49e4d3a --- /dev/null +++ b/svg-processor/src/main/kotlin/app/lawnchair/lawnicons/helper/AppfilterDiffCreator.kt @@ -0,0 +1,117 @@ +/* + * 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 getPreviousReleaseLines( + appFilterFile: String, + ): List { + return try { + 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 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() + } + } + + private fun readFileContents(filePath: String): List { + return File(filePath).readLines() + } + + 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 diff = getLineDiff( + getPreviousReleaseLines(appFilterFile), + readFileContents(appFilterFile), + ) + + 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 a016e3883..e97ded9b3 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 33b16af25..3bc95143b 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 a0b8c3099..93bd91a34 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 bfe417d87..45db04313 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 diff --git a/svgs/_365scores.svg b/svgs/_365scores.svg new file mode 100644 index 000000000..6cd7c3949 --- /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 000000000..0b421da82 --- /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 000000000..dd604a8d6 --- /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 000000000..2a8001836 --- /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 000000000..67e0c2e73 --- /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 000000000..dca6379a6 --- /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 000000000..72defb9ab --- /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 000000000..465546e53 --- /dev/null +++ b/svgs/asus_tips.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/bank_mehr.svg b/svgs/bank_mehr.svg new file mode 100644 index 000000000..f46180b3b --- /dev/null +++ b/svgs/bank_mehr.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/bbll.svg b/svgs/bbll.svg new file mode 100644 index 000000000..0c569c0bc --- /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 000000000..7d634c171 --- /dev/null +++ b/svgs/biliyou.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/birbank.svg b/svgs/birbank.svg new file mode 100644 index 000000000..0c533187a --- /dev/null +++ b/svgs/birbank.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/bjetc.svg b/svgs/bjetc.svg new file mode 100644 index 000000000..753d8a0e1 --- /dev/null +++ b/svgs/bjetc.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/brother_print_service_plugin.svg b/svgs/brother_print_service_plugin.svg new file mode 100644 index 000000000..d16d8d21c --- /dev/null +++ b/svgs/brother_print_service_plugin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/buff.svg b/svgs/buff.svg new file mode 100644 index 000000000..b84dcfaa9 --- /dev/null +++ b/svgs/buff.svg @@ -0,0 +1 @@ + diff --git a/svgs/buy_me_a_coffee.svg b/svgs/buy_me_a_coffee.svg new file mode 100644 index 000000000..4c8b846e3 --- /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 000000000..eeca29df0 --- /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 000000000..81a3a02e4 --- /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 000000000..e2eb91afc --- /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 000000000..868e722fe --- /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 000000000..707ff2bb5 --- /dev/null +++ b/svgs/cara.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/castro.svg b/svgs/castro.svg index 7b226b18a..179fe77c7 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/castro_premium.svg b/svgs/castro_premium.svg new file mode 100644 index 000000000..bc55ff1b8 --- /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 000000000..c070be21d --- /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 000000000..34e7fc15f --- /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 000000000..be2214eca --- /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 000000000..e3c69c880 --- /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 000000000..20d8f066c --- /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 000000000..81c27b9a9 --- /dev/null +++ b/svgs/disky.svg @@ -0,0 +1 @@ + \ No newline at end of file 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/exnova.svg b/svgs/exnova.svg new file mode 100644 index 000000000..6796fdcf9 --- /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 000000000..a8d576e6e --- /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 000000000..52c50ce71 --- /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 000000000..c0081d56b --- /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 000000000..934bc3913 --- /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 000000000..5da25c7df --- /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 000000000..7f26e7084 --- /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 000000000..5945bf340 --- /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 000000000..dcbdc1e47 --- /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 000000000..a7e3855ed --- /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 000000000..f8c473998 --- /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 000000000..c06f06088 --- /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 000000000..2cbf05b19 --- /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 000000000..ec26aaead --- /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 000000000..41150a007 --- /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 000000000..4b63d3269 --- /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 000000000..8b3bb7b22 --- /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 000000000..cfe5e65b2 --- /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 000000000..dd75ad80f --- /dev/null +++ b/svgs/kaufland.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/kinnu.svg b/svgs/kinnu.svg index 3618bec4f..c48b2412b 100644 --- a/svgs/kinnu.svg +++ b/svgs/kinnu.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/koshelek.svg b/svgs/koshelek.svg new file mode 100644 index 000000000..47d4b35d0 --- /dev/null +++ b/svgs/koshelek.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/kuper.svg b/svgs/kuper.svg new file mode 100644 index 000000000..589417942 --- /dev/null +++ b/svgs/kuper.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/lawnchair.svg b/svgs/lawnchair.svg index 0a6c5487e..ec900f5f3 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/lawnicons.svg b/svgs/lawnicons.svg index 1a5943746..9724db462 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/magical_search.svg b/svgs/magical_search.svg new file mode 100644 index 000000000..f1ca03d55 --- /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 000000000..bcfa8c85f --- /dev/null +++ b/svgs/magicplan.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/manga_dogs.svg b/svgs/manga_dogs.svg new file mode 100644 index 000000000..b1880a01e --- /dev/null +++ b/svgs/manga_dogs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/mead_mate.svg b/svgs/mead_mate.svg new file mode 100644 index 000000000..5a9999b9e --- /dev/null +++ b/svgs/mead_mate.svg @@ -0,0 +1 @@ + diff --git a/svgs/meeye_icons.svg b/svgs/meeye_icons.svg new file mode 100644 index 000000000..2ef64fe2e --- /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 000000000..ca0117a9a --- /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 000000000..98b3b6931 --- /dev/null +++ b/svgs/mods_maps_for_minecraft_pe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/moscow_wifi_autologin.svg b/svgs/moscow_wifi_autologin.svg new file mode 100644 index 000000000..e367ba251 --- /dev/null +++ b/svgs/moscow_wifi_autologin.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/mostaza.svg b/svgs/mostaza.svg new file mode 100644 index 000000000..470f3d0ca --- /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 000000000..05ebc3c73 --- /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 000000000..288b08064 --- /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 000000000..c0969ab4a --- /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 000000000..095ceed6d --- /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 000000000..775016828 --- /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 000000000..e6588fa4a --- /dev/null +++ b/svgs/nfcgate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/nobitex.svg b/svgs/nobitex.svg new file mode 100644 index 000000000..92e92ffb0 --- /dev/null +++ b/svgs/nobitex.svg @@ -0,0 +1,4 @@ + + + + diff --git a/svgs/notes_notepad.svg b/svgs/notes_notepad.svg new file mode 100644 index 000000000..38987cdcc --- /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 000000000..34105370d --- /dev/null +++ b/svgs/nulls_brawl.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/okey.svg b/svgs/okey.svg new file mode 100644 index 000000000..1a6355a55 --- /dev/null +++ b/svgs/okey.svg @@ -0,0 +1 @@ + diff --git a/svgs/orgzly_revived.svg b/svgs/orgzly_revived.svg new file mode 100644 index 000000000..cf3c9e80f --- /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 000000000..d8f485e87 --- /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 000000000..6921e9ae2 --- /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 000000000..b2cbcf699 --- /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 000000000..6aff08358 --- /dev/null +++ b/svgs/payoneer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/perekrestok.svg b/svgs/perekrestok.svg new file mode 100644 index 000000000..91efd9d45 --- /dev/null +++ b/svgs/perekrestok.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/svgs/pi_browser.svg b/svgs/pi_browser.svg new file mode 100644 index 000000000..95cc4cf22 --- /dev/null +++ b/svgs/pi_browser.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/pi_network.svg b/svgs/pi_network.svg index 92a24c36d..c5d1e3304 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/pikmin_bloom.svg b/svgs/pikmin_bloom.svg new file mode 100644 index 000000000..b87ac9141 --- /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 000000000..296367f29 --- /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 000000000..dee85f298 --- /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 000000000..b4385d67b --- /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 000000000..2b364a757 --- /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 000000000..3d9412930 --- /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 000000000..fea1781c7 --- /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 000000000..a062b6672 --- /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 000000000..feeaf932c --- /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 000000000..ceabb19ba --- /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 000000000..1543286f0 --- /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 000000000..f11c22447 --- /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 000000000..5f00c70b5 --- /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 000000000..529e2f62c --- /dev/null +++ b/svgs/rush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/russian_railways.svg b/svgs/russian_railways.svg new file mode 100644 index 000000000..3e7754692 --- /dev/null +++ b/svgs/russian_railways.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/safetynet.svg b/svgs/safetynet.svg new file mode 100644 index 000000000..9e5f188fc --- /dev/null +++ b/svgs/safetynet.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/sberinvestments.svg b/svgs/sberinvestments.svg new file mode 100644 index 000000000..818b9d5a7 --- /dev/null +++ b/svgs/sberinvestments.svg @@ -0,0 +1,3 @@ + + + diff --git a/svgs/schoology.svg b/svgs/schoology.svg new file mode 100644 index 000000000..b4aa3fa1a --- /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 000000000..9e4957942 --- /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 000000000..0635c23ab --- /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 000000000..734983e5c --- /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 000000000..a806f0542 --- /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 000000000..8659cf2e0 --- /dev/null +++ b/svgs/standoff_2.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/superimage.svg b/svgs/superimage.svg index e227f5cf9..2a7f6b6fe 100644 --- a/svgs/superimage.svg +++ b/svgs/superimage.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/superimage_pro.svg b/svgs/superimage_pro.svg new file mode 100644 index 000000000..981dbbdc6 --- /dev/null +++ b/svgs/superimage_pro.svg @@ -0,0 +1 @@ + \ No newline at end of file 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/tipatch.svg b/svgs/tipatch.svg new file mode 100644 index 000000000..b5bb55c1b --- /dev/null +++ b/svgs/tipatch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/torrserve_matrix.svg b/svgs/torrserve_matrix.svg new file mode 100644 index 000000000..e53157330 --- /dev/null +++ b/svgs/torrserve_matrix.svg @@ -0,0 +1 @@ + diff --git a/svgs/triple_j.svg b/svgs/triple_j.svg new file mode 100644 index 000000000..f626dbdb2 --- /dev/null +++ b/svgs/triple_j.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/triplej.svg b/svgs/triplej.svg deleted file mode 100644 index 8339e1490..000000000 --- a/svgs/triplej.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/svgs/tubi.svg b/svgs/tubi.svg new file mode 100644 index 000000000..712b7eb62 --- /dev/null +++ b/svgs/tubi.svg @@ -0,0 +1 @@ + \ No newline at end of file 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 diff --git a/svgs/unit_converter.svg b/svgs/unit_converter.svg new file mode 100644 index 000000000..fb5fab97f --- /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 000000000..514ce6194 --- /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 000000000..e78a1ad4d --- /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 000000000..095aae6a0 --- /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 000000000..503bf4515 --- /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 000000000..168abedfc --- /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 000000000..f933f80f6 --- /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 000000000..067e651d6 --- /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 000000000..d8ebb11cf --- /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 000000000..b09d9a116 --- /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 000000000..6723a9a51 --- /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 000000000..49e1d799b --- /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 000000000..4b7f67a6d --- /dev/null +++ b/svgs/yandex_with_alice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svgs/youtube_revanced.svg b/svgs/youtube_revanced.svg index 9b1d1a3c9..43d1694ae 100644 --- a/svgs/youtube_revanced.svg +++ b/svgs/youtube_revanced.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/svgs/zipxtract_fd.svg b/svgs/zipxtract_fd.svg new file mode 100644 index 000000000..6f1385cc3 --- /dev/null +++ b/svgs/zipxtract_fd.svg @@ -0,0 +1 @@ + \ No newline at end of file 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