From add0014304aef3b3ebb47d4ee89e867683a1b134 Mon Sep 17 00:00:00 2001 From: tateisu Date: Wed, 20 Mar 2024 04:36:09 +0900 Subject: [PATCH] =?UTF-8?q?=E8=A8=80=E8=AA=9E=E3=83=95=E3=82=A3=E3=83=AB?= =?UTF-8?q?=E3=82=BF=E7=94=BB=E9=9D=A2=E3=81=AE=E3=83=AA=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=AF=E3=82=BF=E3=80=82=20/api/v1/instance/languages=20?= =?UTF-8?q?=E3=81=A7=E8=A8=80=E8=AA=9E=E3=83=AA=E3=82=B9=E3=83=88=E3=82=92?= =?UTF-8?q?=E8=AA=AD=E3=82=80=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 + app/src/fcm/res/raw/dep_list.json | 2 +- app/src/main/AndroidManifest.xml | 2 +- .../juggler/subwaytooter/ActLanguageFilter.kt | 478 ------------------ .../java/jp/juggler/subwaytooter/ActMain.kt | 10 +- .../ColumnViewHolderActions.kt | 15 +- .../juggler/subwaytooter/dialog/DlgConfirm.kt | 61 +-- .../languageFilter/LanguageFilterActivity.kt | 452 +++++++++++++++++ .../LanguageFilterEditDialog.kt | 99 ++++ .../ui/languageFilter/LanguageFilterItem.kt | 18 + .../languageFilter/LanguageFilterViewModel.kt | 258 ++++++++++ .../ui/languageFilter/LanguageInfo.kt | 142 ++++++ .../ui/languageFilter/StringResAndArgs.kt | 20 + .../juggler/subwaytooter/util/ComposeUtils.kt | 41 +- .../main/res/layout/act_language_filter.xml | 80 --- .../main/res/layout/dlg_language_filter.xml | 2 + .../main/res/layout/lv_language_filter.xml | 10 - app/src/main/res/raw/languages_fallback.json | 1 + app/src/main/res/values-ja/strings.xml | 3 + app/src/main/res/values/strings.xml | 3 + app/src/noFcm/res/raw/dep_list.json | 2 +- base/build.gradle.kts | 4 + base/src/main/java/jp/juggler/util/Compat.kt | 7 + .../jp/juggler/util/coroutine/EmptyScope.kt | 20 + .../java/jp/juggler/util/data/StorageUtils.kt | 5 +- .../juggler/util/ui/ActivityResultHandler.kt | 10 +- buildSrc/src/main/java/Vers.kt | 1 + 27 files changed, 1097 insertions(+), 650 deletions(-) delete mode 100644 app/src/main/java/jp/juggler/subwaytooter/ActLanguageFilter.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterActivity.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterEditDialog.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterItem.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterViewModel.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageInfo.kt create mode 100644 app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/StringResAndArgs.kt delete mode 100644 app/src/main/res/layout/act_language_filter.xml delete mode 100644 app/src/main/res/layout/lv_language_filter.xml create mode 100644 app/src/main/res/raw/languages_fallback.json diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 5a075876..ea0d9882 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -169,6 +169,7 @@ dependencies { implementation("androidx.appcompat:appcompat:${Vers.androidxAppcompat}") implementation("androidx.browser:browser:1.8.0") implementation("androidx.compose.material3:material3:1.2.1") + implementation("androidx.compose.material:material-icons-extended-android:${Vers.androidxComposeMaterialIcons}") implementation("androidx.compose.runtime:runtime-livedata:${Vers.androidxComposeRuntime}") implementation("androidx.compose.ui:ui-tooling-preview:${Vers.androidxComposeUi}") implementation("androidx.compose.ui:ui:${Vers.androidxComposeUi}") diff --git a/app/src/fcm/res/raw/dep_list.json b/app/src/fcm/res/raw/dep_list.json index 2a8a7e3c..65b9370d 100644 --- a/app/src/fcm/res/raw/dep_list.json +++ b/app/src/fcm/res/raw/dep_list.json @@ -1 +1 @@ -{"licenses":[{"shortName":"Amazon Software License","urls":["https://aws.amazon.com/asl/","http://aws.amazon.com/asl/"],"name":"Amazon Software License"},{"name":"Android Software Development Kit License","urls":["https://developer.android.com/studio/terms.html"],"shortName":"Android Software Development Kit License"},{"shortName":"Apache-2.0","name":"The Apache Software License, Version 2.0","urls":["https://www.apache.org/licenses/LICENSE-2.0","https://www.apache.org/licenses/LICENSE-2.0.txt","http://www.apache.org/licenses/LICENSE-2.0","http://www.apache.org/licenses/LICENSE-2.0.txt","https://api.github.com/licenses/apache-2.0","https://github.com/elye/loaderviewlibrary/blob/master/LICENSE"]},{"shortName":"BSD-2-Clause","name":"The 2-Clause BSD License","urls":["https://opensource.org/license/bsd-2-clause/","http://www.opensource.org/licenses/bsd-license"]},{"urls":["https://www.bouncycastle.org/licence.html"],"name":"Bouncy Castle Licence","shortName":"Bouncy Castle Licence"},{"name":"MIT License","urls":["https://opensource.org/license/mit/","https://opensource.org/licenses/MIT","https://github.com/lisawray/groupie/blob/master/LICENSE.md","https://github.com/omadahealth/SwipyRefreshLayoutblob/master/LICENSE"],"shortName":"MIT"},{"urls":["http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web"],"name":"SIL Open Font License, Version 1.1","shortName":"SIL Open Font License, Version 1.1"},{"shortName":"Unicode License","name":"Unicode, Inc. License","urls":["https://www.unicode.org/copyright.html#License","http://www.unicode.org/copyright.html#License"]}],"libs":[{"licenses":["MIT"],"website":"https://github.com/iamcal/emoji-data","developers":[{"name":"Cal Henderson"}],"description":"Easy to parse data and spritesheets for emoji","name":"iamcal/emoji-data"},{"description":"A simple library that provides standard Unicode emoji support across all platforms.","developers":[{"name":"X (fka Twitter)"}],"website":"https://github.com/twitter/twemoji","licenses":["MIT"],"name":"Twitter Emoji (Twemoji)"},{"name":"Color Picker","licenses":["Apache-2.0"],"website":"https://github.com/jrummyapps/colorpicker","description":"Yet another open source color picker for Android.","developers":[{"name":"Jared Rummler"}]},{"name":"Kotlin/anko (Anko Layouts)","website":"https://github.com/Kotlin/anko","licenses":["Apache-2.0"],"description":"a fast and type-safe way to write dynamic Android layouts"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","artifactVersion":"1.8.2","description":"Compose integration with Activity","licenses":["Apache-2.0"],"name":"Activity Compose","id":"androidx.activity:activity-compose:1.8.2"},{"artifactVersion":"1.8.2","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Kotlin extensions for 'activity' artifact","name":"Activity Kotlin Extensions","id":"androidx.activity:activity-ktx:1.8.2"},{"licenses":["Apache-2.0"],"description":"Provides the base Activity subclass and the relevant hooks to build a composable structure on top.","name":"Activity","id":"androidx.activity:activity:1.8.2","artifactVersion":"1.8.2","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","developers":[{"name":"The Android Open Source Project"}]},{"id":"androidx.annotation:annotation-experimental:1.4.0","name":"Experimental annotation","description":"Java annotation for use on unstable Android API surfaces. When used in conjunction with the Experimental annotation lint checks, this annotation provides functional parity with Kotlin's Experimental annotation.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.4.0","artifactVersion":"1.4.0"},{"licenses":["Apache-2.0"],"description":"Provides source annotations for tooling and readability.","id":"androidx.annotation:annotation-jvm:1.7.1","name":"Annotation","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.7.1","artifactVersion":"1.7.1","developers":[{"name":"The Android Open Source Project"}]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.7.1","artifactVersion":"1.7.1","id":"androidx.annotation:annotation:1.7.1","name":"Annotation","description":"Provides source annotations for tooling and readability.","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1","artifactVersion":"1.6.1","description":"The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"name":"Android Resources Library","id":"androidx.appcompat:appcompat-resources:1.6.1"},{"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"id":"androidx.appcompat:appcompat:1.6.1","name":"Android AppCompat Library","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.1","website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/arch-core#2.2.0","artifactVersion":"2.2.0","id":"androidx.arch.core:core-common:2.2.0","name":"Android Arch-Common","description":"Android Arch-Common","licenses":["Apache-2.0"]},{"name":"Android Arch-Runtime","id":"androidx.arch.core:core-runtime:2.2.0","licenses":["Apache-2.0"],"description":"Android Arch-Runtime","website":"https://developer.android.com/jetpack/androidx/releases/arch-core#2.2.0","artifactVersion":"2.2.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"AndroidX Autofill","id":"androidx.autofill:autofill:1.0.0","description":"AndroidX Autofill","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","website":"https://developer.android.com/jetpack/androidx"},{"artifactVersion":"1.8.0","website":"https://developer.android.com/jetpack/androidx/releases/browser#1.8.0","developers":[{"name":"The Android Open Source Project"}],"name":"Browser","id":"androidx.browser:browser:1.8.0","licenses":["Apache-2.0"],"description":"Provides support for embedding Custom Tabs in an app."},{"artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Android Support CardView v7","id":"androidx.cardview:cardview:1.0.0","name":"Android Support CardView v7"},{"website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0","artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Standalone efficient collections.","id":"androidx.collection:collection-jvm:1.4.0","name":"collections"},{"licenses":["Apache-2.0"],"description":"Kotlin extensions for 'collection' artifact","name":"Collections Kotlin Extensions","id":"androidx.collection:collection-ktx:1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0","artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"description":"Standalone efficient collections.","name":"collections","id":"androidx.collection:collection:1.4.0","artifactVersion":"1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Compose animation library","licenses":["Apache-2.0"],"name":"Compose Animation","id":"androidx.compose.animation:animation-android:1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0"},{"licenses":["Apache-2.0"],"description":"Animation engine and animation primitives that are the building blocks of the Compose animation library","id":"androidx.compose.animation:animation-core-android:1.6.0","name":"Compose Animation Core","artifactVersion":"1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Animation engine and animation primitives that are the building blocks of the Compose animation library","name":"Compose Animation Core","id":"androidx.compose.animation:animation-core:1.6.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","description":"Compose animation library","licenses":["Apache-2.0"],"id":"androidx.compose.animation:animation:1.6.0","name":"Compose Animation"},{"description":"Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers","licenses":["Apache-2.0"],"name":"Compose Foundation","id":"androidx.compose.foundation:foundation-android:1.6.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","artifactVersion":"1.6.0"},{"name":"Compose Layouts","id":"androidx.compose.foundation:foundation-layout-android:1.6.0","licenses":["Apache-2.0"],"description":"Compose layout implementations","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}]},{"id":"androidx.compose.foundation:foundation-layout:1.6.0","name":"Compose Layouts","licenses":["Apache-2.0"],"description":"Compose layout implementations","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers","licenses":["Apache-2.0"],"id":"androidx.compose.foundation:foundation:1.6.0","name":"Compose Foundation","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","artifactVersion":"1.6.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-material3#1.2.1","artifactVersion":"1.2.1","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Compose Material You Design Components library","id":"androidx.compose.material3:material3-android:1.2.1","name":"Compose Material3 Components"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-material3#1.2.1","artifactVersion":"1.2.1","developers":[{"name":"The Android Open Source Project"}],"name":"Compose Material3 Components","id":"androidx.compose.material3:material3:1.2.1","licenses":["Apache-2.0"],"description":"Compose Material You Design Components library"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","description":"Compose Material Design core icons. This module contains the most commonly used set of Material icons.","licenses":["Apache-2.0"],"id":"androidx.compose.material:material-icons-core-android:1.6.0","name":"Compose Material Icons Core"},{"licenses":["Apache-2.0"],"description":"Compose Material Design core icons. This module contains the most commonly used set of Material icons.","name":"Compose Material Icons Core","id":"androidx.compose.material:material-icons-core:1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Material ripple used to build interactive components","licenses":["Apache-2.0"],"name":"Compose Material Ripple","id":"androidx.compose.material:material-ripple-android:1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Material ripple used to build interactive components","name":"Compose Material Ripple","id":"androidx.compose.material:material-ripple:1.6.0"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","artifactVersion":"1.6.3","description":"Tree composition support for code generated by the Compose compiler plugin and corresponding public API","licenses":["Apache-2.0"],"id":"androidx.compose.runtime:runtime-android:1.6.3","name":"Compose Runtime"},{"id":"androidx.compose.runtime:runtime-livedata:1.6.3","name":"Compose LiveData integration","description":"Compose integration with LiveData","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3"},{"name":"Compose Saveable","id":"androidx.compose.runtime:runtime-saveable-android:1.6.3","description":"Compose components that allow saving and restoring the local ui state","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","artifactVersion":"1.6.3"},{"licenses":["Apache-2.0"],"description":"Compose components that allow saving and restoring the local ui state","id":"androidx.compose.runtime:runtime-saveable:1.6.3","name":"Compose Saveable","website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Tree composition support for code generated by the Compose compiler plugin and corresponding public API","id":"androidx.compose.runtime:runtime:1.6.3","name":"Compose Runtime"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","id":"androidx.compose.ui:ui-android:1.6.3","name":"Compose UI","description":"Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.","licenses":["Apache-2.0"]},{"name":"Compose Geometry","id":"androidx.compose.ui:ui-geometry-android:1.6.3","licenses":["Apache-2.0"],"description":"Compose classes related to dimensions without units","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"description":"Compose classes related to dimensions without units","licenses":["Apache-2.0"],"name":"Compose Geometry","id":"androidx.compose.ui:ui-geometry:1.6.3","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3"},{"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Compose graphics","name":"Compose Graphics","id":"androidx.compose.ui:ui-graphics-android:1.6.3"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","id":"androidx.compose.ui:ui-graphics:1.6.3","name":"Compose Graphics","description":"Compose graphics","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","name":"Compose UI Text","id":"androidx.compose.ui:ui-text-android:1.6.3","description":"Compose Text primitives and utilities","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","id":"androidx.compose.ui:ui-text:1.6.3","name":"Compose UI Text","description":"Compose Text primitives and utilities","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","description":"Compose tooling library API. This library provides the API required to declare @Preview composables in user apps.","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-tooling-preview-android:1.6.3","name":"Compose UI Preview Tooling"},{"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Compose tooling library API. This library provides the API required to declare @Preview composables in user apps.","id":"androidx.compose.ui:ui-tooling-preview:1.6.3","name":"Compose UI Preview Tooling"},{"licenses":["Apache-2.0"],"description":"Compose classes for simple units","name":"Compose Unit","id":"androidx.compose.ui:ui-unit-android:1.6.3","artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"description":"Compose classes for simple units","name":"Compose Unit","id":"androidx.compose.ui:ui-unit:1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"name":"Compose Util","id":"androidx.compose.ui:ui-util-android:1.6.3","licenses":["Apache-2.0"],"description":"Internal Compose utilities used by other modules"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","id":"androidx.compose.ui:ui-util:1.6.3","name":"Compose Util","description":"Internal Compose utilities used by other modules","licenses":["Apache-2.0"]},{"id":"androidx.compose.ui:ui:1.6.3","name":"Compose UI","description":"Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3"},{"id":"androidx.concurrent:concurrent-futures:1.1.0","name":"AndroidX Futures","licenses":["Apache-2.0"],"description":"Androidx implementation of Guava's ListenableFuture","website":"https://developer.android.com/topic/libraries/architecture/index.html","artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Solver for ConstraintLayout","licenses":["Apache-2.0"],"id":"androidx.constraintlayout:constraintlayout-solver:2.0.1","name":"Android ConstraintLayout Solver","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.0.1","website":"http://tools.android.com"},{"website":"http://tools.android.com","artifactVersion":"2.0.1","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"ConstraintLayout for Android","id":"androidx.constraintlayout:constraintlayout:2.0.1","name":"Android ConstraintLayout"},{"licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","id":"androidx.coordinatorlayout:coordinatorlayout:1.1.0","name":"Android Support Library Coordinator Layout","artifactVersion":"1.1.0","website":"https://developer.android.com/jetpack/androidx","developers":[{"name":"The Android Open Source Project"}]},{"description":"Kotlin extensions for 'core' artifact","licenses":["Apache-2.0"],"id":"androidx.core:core-ktx:1.12.0","name":"Core Kotlin Extensions","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/core#1.12.0","artifactVersion":"1.12.0"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/core#1.0.1","artifactVersion":"1.0.1","name":"SplashScreen","id":"androidx.core:core-splashscreen:1.0.1","description":"This library provides the compatibility APIs for SplashScreen and helper method to enable a splashscreen on devices prior Android 12","licenses":["Apache-2.0"]},{"artifactVersion":"1.12.0","website":"https://developer.android.com/jetpack/androidx/releases/core#1.12.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.core:core:1.12.0","name":"Core","licenses":["Apache-2.0"],"description":"Provides backward-compatible implementations of Android platform APIs and features."},{"website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.cursoradapter:cursoradapter:1.0.0","name":"Android Support Library Cursor Adapter","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/customview#1.0.0","artifactVersion":"1.0.0","id":"androidx.customview:customview-poolingcontainer:1.0.0","name":"androidx.customview:poolingcontainer","description":"Utilities for listening to the lifecycle of containers that manage their child Views' lifecycle, such as RecyclerView","licenses":["Apache-2.0"]},{"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"name":"Android Support Library Custom View","id":"androidx.customview:customview:1.1.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.1.0","website":"https://developer.android.com/jetpack/androidx"},{"id":"androidx.databinding:viewbinding:8.3.0","licenses":["Apache-2.0"],"website":"","artifactVersion":"8.3.0","developers":[]},{"name":"Android Support Library Document File","id":"androidx.documentfile:documentfile:1.0.0","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html"},{"id":"androidx.drawerlayout:drawerlayout:1.2.0","name":"Android Support Library Drawer Layout","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","artifactVersion":"1.2.0","website":"https://developer.android.com/jetpack/androidx/releases/drawerlayout#1.2.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations.","licenses":["Apache-2.0"],"name":"Android Support DynamicAnimation","id":"androidx.dynamicanimation:dynamicanimation:1.0.0","developers":[{"name":"The Android Open Source Project"}],"website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.emoji2:emoji2-bundled:1.4.0","name":"Emoji2 Bundled","licenses":["Apache-2.0","SIL Open Font License, Version 1.1","Unicode License"],"description":"Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters."},{"name":"Emoji2 Views Helper","id":"androidx.emoji2:emoji2-views-helper:1.4.0","description":"Provide helper classes for Emoji2 views.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","artifactVersion":"1.4.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","description":"Support for using emoji2 directly with Android Views, for use in apps without appcompat","licenses":["Apache-2.0"],"name":"Emoji2 Views","id":"androidx.emoji2:emoji2-views:1.4.0"},{"licenses":["Apache-2.0"],"description":"Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.","name":"Emoji2","id":"androidx.emoji2:emoji2:1.4.0","artifactVersion":"1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"Android Support ExifInterface","id":"androidx.exifinterface:exifinterface:1.3.7","description":"Android Support ExifInterface","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/exifinterface#1.3.7","artifactVersion":"1.3.7"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/fragment#1.6.1","artifactVersion":"1.6.1","description":"Kotlin extensions for 'fragment' artifact","licenses":["Apache-2.0"],"name":"Fragment Kotlin Extensions","id":"androidx.fragment:fragment-ktx:1.6.1"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/fragment#1.6.1","artifactVersion":"1.6.1","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"id":"androidx.fragment:fragment:1.6.1","name":"Android Support Library fragment"},{"id":"androidx.interpolator:interpolator:1.0.0","name":"Android Support Library Interpolators","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","licenses":["Apache-2.0"],"id":"androidx.legacy:legacy-support-core-utils:1.0.0","name":"Android Support Library core utils"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","id":"androidx.lifecycle:lifecycle-common-java8:2.7.0","name":"Lifecycle-Common for Java 8","description":"Android Lifecycle-Common for Java 8 Language","licenses":["Apache-2.0"]},{"id":"androidx.lifecycle:lifecycle-common:2.7.0","name":"Lifecycle-Common","licenses":["Apache-2.0"],"description":"Android Lifecycle-Common","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"LiveData Core Kotlin Extensions","id":"androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0","description":"Kotlin extensions for 'livedata-core' artifact","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","id":"androidx.lifecycle:lifecycle-livedata-core:2.7.0","name":"Lifecycle LiveData Core","description":"Android Lifecycle LiveData Core","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"description":"Android Lifecycle LiveData","id":"androidx.lifecycle:lifecycle-livedata:2.7.0","name":"Lifecycle LiveData","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","name":"Lifecycle Process","id":"androidx.lifecycle:lifecycle-process:2.7.0","description":"Android Lifecycle Process","licenses":["Apache-2.0"]},{"artifactVersion":"2.7.0","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Compose integration with Lifecycle","id":"androidx.lifecycle:lifecycle-runtime-compose:2.7.0","name":"Lifecycle Runtime Compose"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Kotlin extensions for 'lifecycle' artifact","id":"androidx.lifecycle:lifecycle-runtime-ktx:2.7.0","name":"Lifecycle Kotlin Extensions"},{"description":"Android Lifecycle Runtime","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-runtime:2.7.0","name":"Lifecycle Runtime","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0"},{"id":"androidx.lifecycle:lifecycle-service:2.7.0","name":"Lifecycle Service","licenses":["Apache-2.0"],"description":"Android Lifecycle Service","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Compose integration with Lifecycle ViewModel","name":"Lifecycle ViewModel Compose","id":"androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","description":"Kotlin extensions for 'viewmodel' artifact","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0","name":"Lifecycle ViewModel Kotlin Extensions"},{"id":"androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0","name":"Lifecycle ViewModel with SavedState","description":"Android Lifecycle ViewModel","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.lifecycle:lifecycle-viewmodel:2.7.0","name":"Lifecycle ViewModel","licenses":["Apache-2.0"],"description":"Android Lifecycle ViewModel"},{"id":"androidx.loader:loader:1.0.0","name":"Android Support Library loader","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}]},{"id":"androidx.localbroadcastmanager:localbroadcastmanager:1.0.0","name":"Android Support Library Local Broadcast Manager","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"description":"Media3 common module","name":"Media3 common module","id":"androidx.media3:media3-common:1.3.0","artifactVersion":"1.3.0","website":"https://github.com/androidx/media","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Media3 Container module","name":"Media3 Container module","id":"androidx.media3:media3-container:1.3.0"},{"name":"Media3 database module","id":"androidx.media3:media3-database:1.3.0","description":"Media3 database module","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","artifactVersion":"1.3.0"},{"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"name":"Media3 DataSource module","id":"androidx.media3:media3-datasource:1.3.0","licenses":["Apache-2.0"],"description":"Media3 DataSource module"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","description":"Media3 decoder module","licenses":["Apache-2.0"],"id":"androidx.media3:media3-decoder:1.3.0","name":"Media3 decoder module"},{"id":"androidx.media3:media3-effect:1.3.0","name":"Media3 Effect module","description":"Media3 Effect module","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","artifactVersion":"1.3.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://github.com/androidx/media","name":"Media3 ExoPlayer module","id":"androidx.media3:media3-exoplayer:1.3.0","description":"Media3 ExoPlayer module","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","name":"Media3 Extractor module","id":"androidx.media3:media3-extractor:1.3.0","description":"Media3 Extractor module","licenses":["Apache-2.0"]},{"description":"Media3 Muxer module","licenses":["Apache-2.0"],"id":"androidx.media3:media3-muxer:1.3.0","name":"Media3 Muxer module","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://github.com/androidx/media"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","name":"Media3 Session module","id":"androidx.media3:media3-session:1.3.0","description":"Media3 Session module","licenses":["Apache-2.0"]},{"website":"https://github.com/androidx/media","artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.media3:media3-transformer:1.3.0","name":"Media3 Transformer module","licenses":["Apache-2.0"],"description":"Media3 Transformer module"},{"name":"Media3 UI module","id":"androidx.media3:media3-ui:1.3.0","description":"Media3 UI module","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://github.com/androidx/media"},{"name":"Media","id":"androidx.media:media:1.7.0","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"https://developer.android.com/jetpack/androidx/releases/media#1.7.0","artifactVersion":"1.7.0","developers":[{"name":"The Android Open Source Project"}]},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","website":"https://developer.android.com/jetpack/androidx/releases/preference#1.2.1","description":"Kotlin extensions for preferences","licenses":["Apache-2.0"],"id":"androidx.preference:preference-ktx:1.2.1","name":"Android Preferences KTX"},{"website":"https://developer.android.com/jetpack/androidx/releases/preference#1.2.1","artifactVersion":"1.2.1","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"AndroidX Preference","name":"AndroidX Preference","id":"androidx.preference:preference:1.2.1"},{"website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.print:print:1.0.0","name":"Android Support Library Print","licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."},{"licenses":["Apache-2.0"],"description":"Allows libraries to prepopulate ahead of time compilation traces to be read by ART","name":"androidx.profileinstaller:profileinstaller","id":"androidx.profileinstaller:profileinstaller:1.3.0","artifactVersion":"1.3.0","website":"https://developer.android.com/jetpack/androidx/releases/profileinstaller#1.3.0","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/recyclerview#1.3.2","artifactVersion":"1.3.2","developers":[{"name":"The Android Open Source Project"}],"name":"Android Support RecyclerView","id":"androidx.recyclerview:recyclerview:1.3.2","licenses":["Apache-2.0"],"description":"Android Support RecyclerView"},{"licenses":["Apache-2.0"],"description":"Annotation processors for Android resource and layout inspection","name":"Android Resource Inspection - Annotations","id":"androidx.resourceinspection:resourceinspection-annotation:1.0.1","website":"https://developer.android.com/jetpack/androidx/releases/resourceinspection#1.0.1","artifactVersion":"1.0.1","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0","artifactVersion":"2.5.0","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Android Room-Common","id":"androidx.room:room-common:2.5.0","name":"Android Room-Common"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.5.0","website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0","id":"androidx.room:room-ktx:2.5.0","name":"Android Room Kotlin Extensions","description":"Android Room Kotlin Extensions","licenses":["Apache-2.0"]},{"name":"Android Room-Runtime","id":"androidx.room:room-runtime:2.5.0","licenses":["Apache-2.0"],"description":"Android Room-Runtime","website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0","artifactVersion":"2.5.0","developers":[{"name":"The Android Open Source Project"}]},{"description":"Kotlin extensions for 'savedstate' artifact","licenses":["Apache-2.0"],"id":"androidx.savedstate:savedstate-ktx:1.2.1","name":"SavedState Kotlin Extensions","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","website":"https://developer.android.com/jetpack/androidx/releases/savedstate#1.2.1"},{"website":"https://developer.android.com/jetpack/androidx/releases/savedstate#1.2.1","artifactVersion":"1.2.1","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.savedstate:savedstate:1.2.1","name":"Saved State","licenses":["Apache-2.0"],"description":"Android Lifecycle Saved State"},{"id":"androidx.slidingpanelayout:slidingpanelayout:1.2.0","name":"Android Support Library Sliding Pane Layout","licenses":["Apache-2.0"],"description":"SlidingPaneLayout offers a responsive, two pane layout that automatically switches between overlapping panes on smaller devices to a side by side view on larger devices.","artifactVersion":"1.2.0","website":"https://developer.android.com/jetpack/androidx/releases/slidingpanelayout#1.2.0","developers":[{"name":"The Android Open Source Project"}]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/sqlite#2.3.0","artifactVersion":"2.3.0","id":"androidx.sqlite:sqlite-framework:2.3.0","name":"Android Support SQLite - Framework Implementation","description":"The implementation of Support SQLite library using the framework code.","licenses":["Apache-2.0"]},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/sqlite#2.3.0","artifactVersion":"2.3.0","id":"androidx.sqlite:sqlite:2.3.0","name":"Android DB","description":"Android DB","licenses":["Apache-2.0"]},{"description":"Android App Startup Runtime","licenses":["Apache-2.0"],"name":"Android App Startup Runtime","id":"androidx.startup:startup-runtime:1.1.1","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/startup#1.1.1","artifactVersion":"1.1.1"},{"name":"Android Tracing","id":"androidx.tracing:tracing:1.0.0","description":"Android Tracing","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0","artifactVersion":"1.0.0"},{"id":"androidx.transition:transition:1.4.1","name":"Android Transition Support Library","description":"Android Transition Support Library","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/transition#1.4.1","artifactVersion":"1.4.1"},{"website":"https://developer.android.com/jetpack/androidx","artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.vectordrawable:vectordrawable-animated:1.1.0","name":"Android Support AnimatedVectorDrawable","licenses":["Apache-2.0"],"description":"Android Support AnimatedVectorDrawable"},{"licenses":["Apache-2.0"],"description":"Android Support VectorDrawable","id":"androidx.vectordrawable:vectordrawable:1.1.0","name":"Android Support VectorDrawable","artifactVersion":"1.1.0","website":"https://developer.android.com/jetpack/androidx","developers":[{"name":"The Android Open Source Project"}]},{"artifactVersion":"1.1.1","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}],"licenses":["Apache-2.0"],"description":"Provides a stable but relatively compact binary serialization format that can be passed across processes or persisted safely.","name":"VersionedParcelable","id":"androidx.versionedparcelable:versionedparcelable:1.1.1"},{"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-beta02","artifactVersion":"1.1.0-beta02","name":"ViewPager2","id":"androidx.viewpager2:viewpager2:1.1.0-beta02","description":"AndroidX Widget ViewPager2","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","id":"androidx.viewpager:viewpager:1.0.0","name":"Android Support Library View Pager","website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"Jetpack WindowManager Library","id":"androidx.window:window:1.0.0","description":"WindowManager Jetpack library. Currently only provides additional functionality on foldable devices.","licenses":["Apache-2.0"],"developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/window#1.0.0","artifactVersion":"1.0.0"},{"licenses":["Apache-2.0"],"description":"Android WorkManager Kotlin Extensions","id":"androidx.work:work-runtime-ktx:2.9.0","name":"WorkManager Kotlin Extensions","artifactVersion":"2.9.0","website":"https://developer.android.com/jetpack/androidx/releases/work#2.9.0","developers":[{"name":"The Android Open Source Project"}]},{"website":"https://developer.android.com/jetpack/androidx/releases/work#2.9.0","artifactVersion":"2.9.0","developers":[{"name":"The Android Open Source Project"}],"name":"WorkManager Runtime","id":"androidx.work:work-runtime:2.9.0","licenses":["Apache-2.0"],"description":"Android WorkManager runtime library"},{"developers":[{"name":"Paul LeBeau"}],"website":"https://github.com/BigBadaboom/androidsvg","artifactVersion":"1.4","description":"SVG rendering library for Android.","licenses":["Apache-2.0"],"name":"AndroidSVG","id":"com.caverock:androidsvg-aar:1.4"},{"licenses":["Apache-2.0"],"description":"UnifiedPush connector library","name":"UnifiedPush/android-connector","id":"com.github.UnifiedPush:android-connector:2.1.1","website":"https://github.com/UnifiedPush/android-connector","artifactVersion":"2.1.1","developers":[{"name":"UnifiedPush"}]},{"website":"","licenses":[],"artifactVersion":"1.6.2","developers":[],"id":"com.github.alexzhirkevich:custom-qr-generator:1.6.2"},{"developers":[{"name":"Sam Judd"}],"artifactVersion":"4.15.1","website":"https://github.com/bumptech/glide","name":"Glide Annotations","id":"com.github.bumptech.glide:annotations:4.15.1","description":"A set of annotations for configuring Glide.","licenses":["BSD-2-Clause","Apache-2.0"]},{"developers":[{"name":"Sam Judd"}],"website":"https://github.com/bumptech/glide","artifactVersion":"4.15.1","name":"Glide Disk LRU Cache Library","id":"com.github.bumptech.glide:disklrucache:4.15.1","description":"A cache that uses a bounded amount of space on a filesystem. Based on Jake Wharton's tailored for Glide.","licenses":["BSD-2-Clause","Apache-2.0"]},{"licenses":["BSD-2-Clause","Apache-2.0"],"description":"Implementation of GifDecoder that is more memory efficient to animate for Android devices.","id":"com.github.bumptech.glide:gifdecoder:4.15.1","name":"Glide GIF Decoder Library","website":"https://github.com/bumptech/glide","artifactVersion":"4.15.1","developers":[{"name":"Sam Judd"}]},{"developers":[{"name":"Sam Judd"}],"artifactVersion":"4.15.1","website":"https://github.com/bumptech/glide","description":"A fast and efficient image loading library for Android focused on smooth scrolling.","licenses":["BSD-2-Clause","Apache-2.0"],"id":"com.github.bumptech.glide:glide:4.15.1","name":"Glide"},{"website":"https://github.com/bumptech/glide","artifactVersion":"4.15.1","developers":[{"name":"Sam Judd"}],"id":"com.github.bumptech.glide:okhttp3-integration:4.15.1","name":"Glide OkHttp 3.x Integration","licenses":["BSD-2-Clause","Apache-2.0"],"description":"An integration library to use OkHttp 3.x to fetch data over http/https in Glide"},{"artifactVersion":"1.2.3","website":"https://github.com/omadahealth/SwipyRefreshLayout","developers":[{"name":"Olivier Goutay & Stoyan Dimitrov"}],"name":"SwipyRefreshLayout Library","id":"com.github.omadahealth:swipy:1.2.3","licenses":["MIT"],"description":"A SwipeRefreshLayout extension that allows to swipe in both direction"},{"developers":[],"website":"","artifactVersion":"2.25.0","description":"aaae94bea343a992c053f76bba3373a437e0f34a","licenses":[],"id":"com.github.penfeizhou.android.animation:apng:2.25.0"},{"licenses":[],"description":"aaae94bea343a992c053f76bba3373a437e0f34a","id":"com.github.penfeizhou.android.animation:frameanimation:2.25.0","website":"","artifactVersion":"2.25.0","developers":[]},{"name":"draglistview","id":"com.github.woxthebox:draglistview:1.7.3","licenses":["Apache-2.0"],"description":"Drag and drop to re-order items in a list, grid or board.","website":"https://github.com/woxthebox/DragListView","artifactVersion":"1.7.3","developers":[{"name":"Magnus Woxblom"}]},{"developers":[{"name":"zjupure"}],"artifactVersion":"2.6.4.15.1","website":"https://github.com/zjupure/GlideWebpDecoder","id":"com.github.zjupure:webpdecoder:2.6.4.15.1","name":"Glide WebpDecoder Integration","description":"An integration library to decode and show animated webp for Glide","licenses":["Apache-2.0"]},{"id":"com.google.android.datatransport:transport-api:3.1.0","developers":[],"artifactVersion":"3.1.0","licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk"},{"developers":[],"website":"","artifactVersion":"3.1.8","name":"transport-backend-cct","id":"com.google.android.datatransport:transport-backend-cct:3.1.8","licenses":["Apache-2.0"]},{"artifactVersion":"3.1.8","website":"","developers":[],"name":"transport-runtime","id":"com.google.android.datatransport:transport-runtime:3.1.8","licenses":["Apache-2.0"]},{"developers":[{"name":"Google"}],"artifactVersion":"3.0.0","website":"https://github.com/google/flexbox-layout","description":"Flexbox for Android","licenses":["Apache-2.0"],"name":"flexbox-layout","id":"com.google.android.flexbox:flexbox:3.0.0"},{"id":"com.google.android.gms:play-services-base:18.0.1","name":"play-services-base","licenses":["Android Software Development Kit License"],"developers":[],"artifactVersion":"18.0.1","website":""},{"developers":[],"artifactVersion":"18.1.0","website":"","licenses":["Android Software Development Kit License"],"name":"play-services-basement","id":"com.google.android.gms:play-services-basement:18.1.0"},{"licenses":["Android Software Development Kit License"],"name":"play-services-cloud-messaging","id":"com.google.android.gms:play-services-cloud-messaging:17.1.0","developers":[],"website":"","artifactVersion":"17.1.0"},{"licenses":["Android Software Development Kit License"],"id":"com.google.android.gms:play-services-stats:17.0.2","name":"play-services-stats","developers":[],"website":"","artifactVersion":"17.0.2"},{"developers":[],"website":"","artifactVersion":"18.0.2","licenses":["Android Software Development Kit License"],"name":"play-services-tasks","id":"com.google.android.gms:play-services-tasks:18.0.2"},{"artifactVersion":"1.11.0","website":"https://github.com/material-components/material-components-android","developers":[{"name":"The Android Open Source Project"}],"name":"Material Components for Android","id":"com.google.android.material:material:1.11.0","licenses":["Apache-2.0"],"description":"Material Components for Android is a static library that you can add to your Android application in order to use APIs that provide implementations of the Material Design specification. Compatible on devices running API 14 or later."},{"id":"com.google.errorprone:error_prone_annotations:2.15.0","name":"error-prone annotations","licenses":["Apache-2.0"],"developers":[],"website":"","artifactVersion":"2.15.0"},{"developers":[],"artifactVersion":"16.2.0","website":"","id":"com.google.firebase:firebase-annotations:16.2.0","name":"firebase-annotations","licenses":["Apache-2.0"]},{"id":"com.google.firebase:firebase-common-ktx:20.4.2","licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk","artifactVersion":"20.4.2","developers":[]},{"developers":[],"website":"https://github.com/firebase/firebase-android-sdk","licenses":["Apache-2.0"],"artifactVersion":"20.4.2","id":"com.google.firebase:firebase-common:20.4.2"},{"artifactVersion":"17.1.5","licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk","developers":[],"id":"com.google.firebase:firebase-components:17.1.5"},{"name":"firebase-datatransport","id":"com.google.firebase:firebase-datatransport:18.1.7","licenses":["Apache-2.0"],"website":"","artifactVersion":"18.1.7","developers":[]},{"licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-encoders-json:18.0.0","name":"firebase-encoders-json","developers":[],"website":"","artifactVersion":"18.0.0"},{"licenses":["Apache-2.0"],"name":"firebase-encoders-proto","id":"com.google.firebase:firebase-encoders-proto:16.0.0","developers":[],"website":"","artifactVersion":"16.0.0"},{"developers":[],"artifactVersion":"17.0.0","website":"","licenses":["Apache-2.0"],"name":"firebase-encoders","id":"com.google.firebase:firebase-encoders:17.0.0"},{"artifactVersion":"17.1.0","website":"","developers":[],"licenses":["Android Software Development Kit License"],"id":"com.google.firebase:firebase-iid-interop:17.1.0","name":"firebase-iid-interop"},{"id":"com.google.firebase:firebase-installations-interop:17.1.1","developers":[],"licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk","artifactVersion":"17.1.1"},{"developers":[],"licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk","artifactVersion":"17.2.0","id":"com.google.firebase:firebase-installations:17.2.0"},{"developers":[],"artifactVersion":"19.0.0","website":"","licenses":["Android Software Development Kit License"],"name":"firebase-measurement-connector","id":"com.google.firebase:firebase-measurement-connector:19.0.0"},{"id":"com.google.firebase:firebase-messaging:23.4.1","licenses":["Apache-2.0"],"website":"https://github.com/firebase/firebase-android-sdk","artifactVersion":"23.4.1","developers":[]},{"licenses":[],"description":"Contains\n com.google.common.util.concurrent.internal.InternalFutureFailureAccess and\n InternalFutures. Most users will never need to use this artifact. Its\n classes is conceptually a part of Guava, but they're in this separate\n artifact so that Android libraries can use them without pulling in all of\n Guava (just as they can use ListenableFuture by depending on the\n listenablefuture artifact).","name":"Guava InternalFutureFailureAccess and InternalFutures","id":"com.google.guava:failureaccess:1.0.1","artifactVersion":"1.0.1","website":"","developers":[]},{"description":"Guava is a suite of core and expanded libraries that include\n utility classes, Google's collections, I/O classes, and\n much more.","licenses":[],"id":"com.google.guava:guava:32.1.3-android","name":"Guava: Google Core Libraries for Java","developers":[],"website":"https://github.com/google/guava","artifactVersion":"32.1.3-android"},{"developers":[],"artifactVersion":"9999.0-empty-to-avoid-conflict-with-guava","website":"","description":"An empty artifact that Guava depends on to signal that it is providing\n ListenableFuture -- but is also available in a second \"version\" that\n contains com.google.common.util.concurrent.ListenableFuture class, without\n any other Guava classes. The idea is:\n\n - If users want only ListenableFuture, they depend on listenablefuture-1.0.\n\n - If users want all of Guava, they depend on guava, which, as of Guava\n 27.0, depends on\n listenablefuture-9999.0-empty-to-avoid-conflict-with-guava. The 9999.0-...\n version number is enough for some build systems (notably, Gradle) to select\n that empty artifact over the \"real\" listenablefuture-1.0 -- avoiding a\n conflict with the copy of ListenableFuture in guava itself. If users are\n using an older version of Guava or a build system other than Gradle, they\n may see class conflicts. If so, they can solve them by manually excluding\n the listenablefuture artifact or manually forcing their build systems to\n use 9999.0-....","licenses":[],"name":"Guava ListenableFuture only","id":"com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava"},{"developers":[],"website":"","artifactVersion":"3.5.1","name":"ZXing Core","id":"com.google.zxing:core:3.5.1","description":"Core barcode encoding/decoding library","licenses":[]},{"artifactVersion":"0.6.1","website":"https://github.com/natario1/Egloo","developers":[{"name":"natario1"}],"id":"com.otaliastudios.opengl:egloo:0.6.1","name":"Egloo","licenses":["MIT"],"description":"Egloo"},{"website":"https://github.com/natario1/Transcoder","artifactVersion":"0.10.5","developers":[{"name":"natario1"}],"id":"com.otaliastudios:transcoder:0.10.5","name":"Transcoder","licenses":["Apache-2.0"],"description":"Transcoder"},{"licenses":["Apache-2.0"],"description":"Square’s meticulous HTTP client for Java and Kotlin.","name":"okhttp-java-net-cookiejar","id":"com.squareup.okhttp3:okhttp-java-net-cookiejar:5.0.0-alpha.12","artifactVersion":"5.0.0-alpha.12","website":"https://square.github.io/okhttp/","developers":[{"name":"Square, Inc."}]},{"name":"okhttp","id":"com.squareup.okhttp3:okhttp-jvm:5.0.0-alpha.12","description":"Square’s meticulous HTTP client for Java and Kotlin.","licenses":["Apache-2.0"],"developers":[{"name":"Square, Inc."}],"website":"https://square.github.io/okhttp/","artifactVersion":"5.0.0-alpha.12"},{"name":"okhttp-urlconnection","id":"com.squareup.okhttp3:okhttp-urlconnection:5.0.0-alpha.12","licenses":["Apache-2.0"],"description":"Square’s meticulous HTTP client for Java and Kotlin.","artifactVersion":"5.0.0-alpha.12","website":"https://square.github.io/okhttp/","developers":[{"name":"Square, Inc."}]},{"description":"Square’s meticulous HTTP client for Java and Kotlin.","licenses":["Apache-2.0"],"id":"com.squareup.okhttp3:okhttp:5.0.0-alpha.12","name":"okhttp","developers":[{"name":"Square, Inc."}],"artifactVersion":"5.0.0-alpha.12","website":"https://square.github.io/okhttp/"},{"licenses":["Apache-2.0"],"description":"A modern I/O library for Android, Java, and Kotlin Multiplatform.","id":"com.squareup.okio:okio-jvm:3.7.0","name":"okio","artifactVersion":"3.7.0","website":"https://github.com/square/okio/","developers":[{"name":"Square, Inc."}]},{"description":"A modern I/O library for Android, Java, and Kotlin Multiplatform.","licenses":["Apache-2.0"],"id":"com.squareup.okio:okio:3.7.0","name":"okio","developers":[{"name":"Square, Inc."}],"artifactVersion":"3.7.0","website":"https://github.com/square/okio/"},{"website":"https://insert-koin.io/","artifactVersion":"3.5.0","developers":[{"name":"Arnaud Giuliani"}],"licenses":["Apache-2.0"],"description":"KOIN - Kotlin simple Dependency Injection Framework","name":"koin-android-compat","id":"io.insert-koin:koin-android-compat:3.5.0"},{"name":"koin-android","id":"io.insert-koin:koin-android:3.5.0","description":"KOIN - Kotlin simple Dependency Injection Framework","licenses":["Apache-2.0"],"developers":[{"name":"Arnaud Giuliani"}],"website":"https://insert-koin.io/","artifactVersion":"3.5.0"},{"developers":[{"name":"Arnaud Giuliani"}],"website":"https://insert-koin.io/","artifactVersion":"3.5.0","description":"KOIN - Kotlin simple Dependency Injection Framework","licenses":["Apache-2.0"],"id":"io.insert-koin:koin-androidx-workmanager:3.5.0","name":"koin-androidx-workmanager"},{"name":"koin-core","id":"io.insert-koin:koin-core-jvm:3.5.0","description":"KOIN - Kotlin simple Dependency Injection Framework","licenses":["Apache-2.0"],"developers":[{"name":"Arnaud Giuliani"}],"website":"https://insert-koin.io/","artifactVersion":"3.5.0"},{"description":"KOIN - Kotlin simple Dependency Injection Framework","licenses":["Apache-2.0"],"name":"koin-core","id":"io.insert-koin:koin-core:3.5.0","developers":[{"name":"Arnaud Giuliani"}],"artifactVersion":"3.5.0","website":"https://insert-koin.io/"},{"artifactVersion":"1","website":"http://code.google.com/p/atinject/","developers":[],"id":"javax.inject:javax.inject:1","name":"javax.inject","licenses":["Apache-2.0"],"description":"The javax.inject API"},{"id":"org.bouncycastle:bcprov-jdk15on:1.70","name":"Bouncy Castle Provider","licenses":["Bouncy Castle Licence"],"description":"The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 and up.","artifactVersion":"1.70","website":"https://www.bouncycastle.org/java.html","developers":[{"name":"The Legion of the Bouncy Castle Inc."}]},{"artifactVersion":"2.5.2","website":"https://conscrypt.org/","developers":[{"name":"Conscrypt Contributors"}],"licenses":["Apache-2.0"],"description":"Conscrypt: Android","id":"org.conscrypt:conscrypt-android:2.5.2","name":"org.conscrypt:conscrypt-android"},{"artifactVersion":"1.8.22","website":"https://kotlinlang.org/","developers":[{"name":"JetBrains Team"}],"name":"Kotlin Libraries bill-of-materials","id":"org.jetbrains.kotlin:kotlin-bom:1.8.22","licenses":["Apache-2.0"],"description":"Kotlin is a statically typed programming language that compiles to JVM byte codes and JavaScript"},{"developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.22","website":"https://kotlinlang.org/","id":"org.jetbrains.kotlin:kotlin-reflect:1.9.22","name":"Kotlin Reflect","description":"Kotlin Full Reflection Library","licenses":["Apache-2.0"]},{"website":"https://kotlinlang.org/","artifactVersion":"1.9.22","developers":[{"name":"Kotlin Team"}],"name":"Kotlin Stdlib Common","id":"org.jetbrains.kotlin:kotlin-stdlib-common:1.9.22","licenses":["Apache-2.0"],"description":"Kotlin Common Standard Library (legacy, use kotlin-stdlib instead)"},{"developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.0","website":"https://kotlinlang.org/","description":"Kotlin Standard Library JDK 7 extension","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0","name":"Kotlin Stdlib Jdk7"},{"developers":[{"name":"Kotlin Team"}],"website":"https://kotlinlang.org/","artifactVersion":"1.9.0","description":"Kotlin Standard Library JDK 8 extension","licenses":["Apache-2.0"],"name":"Kotlin Stdlib Jdk8","id":"org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0"},{"description":"Kotlin Standard Library","licenses":["Apache-2.0"],"name":"Kotlin Stdlib","id":"org.jetbrains.kotlin:kotlin-stdlib:1.9.22","developers":[{"name":"Kotlin Team"}],"website":"https://kotlinlang.org/","artifactVersion":"1.9.22"},{"description":"Coroutines support libraries for Kotlin","licenses":["Apache-2.0"],"name":"kotlinx-coroutines-android","id":"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","website":"https://github.com/Kotlin/kotlinx.coroutines"},{"developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","website":"https://github.com/Kotlin/kotlinx.coroutines","description":"Coroutines support libraries for Kotlin","licenses":["Apache-2.0"],"name":"kotlinx-coroutines-bom","id":"org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0"},{"developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.coroutines","artifactVersion":"1.8.0","description":"Coroutines support libraries for Kotlin","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0","name":"kotlinx-coroutines-core"},{"licenses":["Apache-2.0"],"description":"Coroutines support libraries for Kotlin","id":"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0","name":"kotlinx-coroutines-core","artifactVersion":"1.8.0","website":"https://github.com/Kotlin/kotlinx.coroutines","developers":[{"name":"JetBrains Team"}]},{"name":"kotlinx-coroutines-play-services","id":"org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.0","description":"Coroutines support libraries for Kotlin","licenses":["Apache-2.0"],"developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.coroutines","artifactVersion":"1.8.0"},{"website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}],"licenses":["Apache-2.0"],"description":"Kotlin multiplatform serialization runtime library","id":"org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3","name":"kotlinx-serialization-bom"},{"description":"Kotlin multiplatform serialization runtime library","licenses":["Apache-2.0"],"name":"kotlinx-serialization-core","id":"org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.6.3","developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3"},{"licenses":["Apache-2.0"],"description":"Kotlin multiplatform serialization runtime library","name":"kotlinx-serialization-core","id":"org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3","website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}]},{"developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3","description":"Kotlin multiplatform serialization runtime library","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.3","name":"kotlinx-serialization-json"},{"id":"org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3","name":"kotlinx-serialization-json","description":"Kotlin multiplatform serialization runtime library","licenses":["Apache-2.0"],"developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3"},{"licenses":["Apache-2.0"],"description":"A set of annotations used for code inspection support and code documentation.","name":"JetBrains Java Annotations","id":"org.jetbrains:annotations:23.0.0","website":"https://github.com/JetBrains/java-annotations","artifactVersion":"23.0.0","developers":[{"name":"JetBrains Team"}]},{"developers":[{"name":"Andrey Mischenko"}],"artifactVersion":"1.0","website":"https://github.com/gildor/kotlin-coroutines-okhttp","description":"Coroutine adapter for OkHttp Call","licenses":["Apache-2.0"],"id":"ru.gildor.coroutines:kotlin-coroutines-okhttp:1.0","name":"kotlin-coroutines-okhttp"}]} \ No newline at end of file +{"libs":[{"licenses":["MIT"],"name":"iamcal/emoji-data","description":"Easy to parse data and spritesheets for emoji","website":"https://github.com/iamcal/emoji-data","developers":[{"name":"Cal Henderson"}]},{"name":"Twitter Emoji (Twemoji)","licenses":["MIT"],"developers":[{"name":"X (fka Twitter)"}],"website":"https://github.com/twitter/twemoji","description":"A simple library that provides standard Unicode emoji support across all platforms."},{"developers":[{"name":"Jared Rummler"}],"website":"https://github.com/jrummyapps/colorpicker","description":"Yet another open source color picker for Android.","name":"Color Picker","licenses":["Apache-2.0"]},{"website":"https://github.com/Kotlin/anko","description":"a fast and type-safe way to write dynamic Android layouts","licenses":["Apache-2.0"],"name":"Kotlin/anko (Anko Layouts)"},{"name":"Activity Compose","licenses":["Apache-2.0"],"id":"androidx.activity:activity-compose:1.8.2","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.8.2","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","description":"Compose integration with Activity"},{"artifactVersion":"1.8.2","developers":[{"name":"The Android Open Source Project"}],"description":"Kotlin extensions for 'activity' artifact","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","name":"Activity Kotlin Extensions","id":"androidx.activity:activity-ktx:1.8.2","licenses":["Apache-2.0"]},{"name":"Activity","licenses":["Apache-2.0"],"id":"androidx.activity:activity:1.8.2","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.8.2","website":"https://developer.android.com/jetpack/androidx/releases/activity#1.8.2","description":"Provides the base Activity subclass and the relevant hooks to build a composable structure on top."},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.4.0","description":"Java annotation for use on unstable Android API surfaces. When used in conjunction with the Experimental annotation lint checks, this annotation provides functional parity with Kotlin's Experimental annotation.","name":"Experimental annotation","licenses":["Apache-2.0"],"id":"androidx.annotation:annotation-experimental:1.4.0"},{"id":"androidx.annotation:annotation-jvm:1.7.1","licenses":["Apache-2.0"],"name":"Annotation","description":"Provides source annotations for tooling and readability.","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.7.1","artifactVersion":"1.7.1","developers":[{"name":"The Android Open Source Project"}]},{"artifactVersion":"1.7.1","developers":[{"name":"The Android Open Source Project"}],"description":"Provides source annotations for tooling and readability.","website":"https://developer.android.com/jetpack/androidx/releases/annotation#1.7.1","name":"Annotation","id":"androidx.annotation:annotation:1.7.1","licenses":["Apache-2.0"]},{"name":"Android Resources Library","licenses":["Apache-2.0"],"id":"androidx.appcompat:appcompat-resources:1.6.1","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.1","description":"The Resources Library is a static library that you can add to your Android application in order to use resource APIs that backport the latest APIs to older versions of the platform. Compatible on devices running API 14 or later.","website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1"},{"name":"Android AppCompat Library","licenses":["Apache-2.0"],"id":"androidx.appcompat:appcompat:1.6.1","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.1","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"https://developer.android.com/jetpack/androidx/releases/appcompat#1.6.1"},{"name":"Android Arch-Common","id":"androidx.arch.core:core-common:2.2.0","licenses":["Apache-2.0"],"artifactVersion":"2.2.0","developers":[{"name":"The Android Open Source Project"}],"description":"Android Arch-Common","website":"https://developer.android.com/jetpack/androidx/releases/arch-core#2.2.0"},{"licenses":["Apache-2.0"],"id":"androidx.arch.core:core-runtime:2.2.0","name":"Android Arch-Runtime","website":"https://developer.android.com/jetpack/androidx/releases/arch-core#2.2.0","description":"Android Arch-Runtime","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.2.0"},{"id":"androidx.autofill:autofill:1.0.0","licenses":["Apache-2.0"],"name":"AndroidX Autofill","website":"https://developer.android.com/jetpack/androidx","description":"AndroidX Autofill","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"Browser","licenses":["Apache-2.0"],"id":"androidx.browser:browser:1.8.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.8.0","description":"Provides support for embedding Custom Tabs in an app.","website":"https://developer.android.com/jetpack/androidx/releases/browser#1.8.0"},{"name":"Android Support CardView v7","licenses":["Apache-2.0"],"id":"androidx.cardview:cardview:1.0.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","website":"http://developer.android.com/tools/extras/support-library.html","description":"Android Support CardView v7"},{"name":"collections","id":"androidx.collection:collection-jvm:1.4.0","licenses":["Apache-2.0"],"artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"description":"Standalone efficient collections.","website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0"},{"artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0","description":"Kotlin extensions for 'collection' artifact","name":"Collections Kotlin Extensions","id":"androidx.collection:collection-ktx:1.4.0","licenses":["Apache-2.0"]},{"website":"https://developer.android.com/jetpack/androidx/releases/collection#1.4.0","description":"Standalone efficient collections.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.4.0","licenses":["Apache-2.0"],"id":"androidx.collection:collection:1.4.0","name":"collections"},{"name":"Compose Animation","id":"androidx.compose.animation:animation-android:1.6.0","licenses":["Apache-2.0"],"artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"description":"Compose animation library","website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","description":"Animation engine and animation primitives that are the building blocks of the Compose animation library","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.animation:animation-core-android:1.6.0","licenses":["Apache-2.0"],"name":"Compose Animation Core"},{"artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"description":"Animation engine and animation primitives that are the building blocks of the Compose animation library","website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","name":"Compose Animation Core","id":"androidx.compose.animation:animation-core:1.6.0","licenses":["Apache-2.0"]},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-animation#1.6.0","description":"Compose animation library","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.animation:animation:1.6.0","licenses":["Apache-2.0"],"name":"Compose Animation"},{"description":"Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","licenses":["Apache-2.0"],"id":"androidx.compose.foundation:foundation-android:1.6.0","name":"Compose Foundation"},{"licenses":["Apache-2.0"],"id":"androidx.compose.foundation:foundation-layout-android:1.6.0","name":"Compose Layouts","description":"Compose layout implementations","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0"},{"artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"description":"Compose layout implementations","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","name":"Compose Layouts","id":"androidx.compose.foundation:foundation-layout:1.6.0","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"id":"androidx.compose.foundation:foundation:1.6.0","name":"Compose Foundation","description":"Higher level abstractions of the Compose UI primitives. This library is design system agnostic, providing the high-level building blocks for both application and design-system developers","website":"https://developer.android.com/jetpack/androidx/releases/compose-foundation#1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","website":"https://developer.android.com/jetpack/androidx/releases/compose-material3#1.2.1","description":"Compose Material You Design Components library","name":"Compose Material3 Components","licenses":["Apache-2.0"],"id":"androidx.compose.material3:material3-android:1.2.1"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","description":"Compose Material You Design Components library","website":"https://developer.android.com/jetpack/androidx/releases/compose-material3#1.2.1","name":"Compose Material3 Components","licenses":["Apache-2.0"],"id":"androidx.compose.material3:material3:1.2.1"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","description":"Compose Material Design core icons. This module contains the most commonly used set of Material icons.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0","licenses":["Apache-2.0"],"id":"androidx.compose.material:material-icons-core-android:1.6.0","name":"Compose Material Icons Core"},{"artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","description":"Compose Material Design core icons. This module contains the most commonly used set of Material icons.","name":"Compose Material Icons Core","id":"androidx.compose.material:material-icons-core:1.6.0","licenses":["Apache-2.0"]},{"id":"androidx.compose.material:material-ripple-android:1.6.0","licenses":["Apache-2.0"],"name":"Compose Material Ripple","description":"Material ripple used to build interactive components","website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","artifactVersion":"1.6.0","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"id":"androidx.compose.material:material-ripple:1.6.0","name":"Compose Material Ripple","description":"Material ripple used to build interactive components","website":"https://developer.android.com/jetpack/androidx/releases/compose-material#1.6.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.0"},{"id":"androidx.compose.runtime:runtime-android:1.6.3","licenses":["Apache-2.0"],"name":"Compose Runtime","description":"Tree composition support for code generated by the Compose compiler plugin and corresponding public API","website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"name":"Compose LiveData integration","id":"androidx.compose.runtime:runtime-livedata:1.6.3","licenses":["Apache-2.0"],"artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","description":"Compose integration with LiveData"},{"licenses":["Apache-2.0"],"id":"androidx.compose.runtime:runtime-saveable-android:1.6.3","name":"Compose Saveable","website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","description":"Compose components that allow saving and restoring the local ui state","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3"},{"name":"Compose Saveable","licenses":["Apache-2.0"],"id":"androidx.compose.runtime:runtime-saveable:1.6.3","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","description":"Compose components that allow saving and restoring the local ui state","website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-runtime#1.6.3","description":"Tree composition support for code generated by the Compose compiler plugin and corresponding public API","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.runtime:runtime:1.6.3","licenses":["Apache-2.0"],"name":"Compose Runtime"},{"id":"androidx.compose.ui:ui-android:1.6.3","licenses":["Apache-2.0"],"name":"Compose UI","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"name":"Compose Geometry","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-geometry-android:1.6.3","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","description":"Compose classes related to dimensions without units","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3"},{"id":"androidx.compose.ui:ui-geometry:1.6.3","licenses":["Apache-2.0"],"name":"Compose Geometry","description":"Compose classes related to dimensions without units","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","description":"Compose graphics","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","name":"Compose Graphics","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-graphics-android:1.6.3"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Compose graphics","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-graphics:1.6.3","name":"Compose Graphics"},{"description":"Compose Text primitives and utilities","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.ui:ui-text-android:1.6.3","licenses":["Apache-2.0"],"name":"Compose UI Text"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Compose Text primitives and utilities","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.ui:ui-text:1.6.3","licenses":["Apache-2.0"],"name":"Compose UI Text"},{"name":"Compose UI Preview Tooling","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-tooling-preview-android:1.6.3","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Compose tooling library API. This library provides the API required to declare @Preview composables in user apps."},{"id":"androidx.compose.ui:ui-tooling-preview:1.6.3","licenses":["Apache-2.0"],"name":"Compose UI Preview Tooling","description":"Compose tooling library API. This library provides the API required to declare @Preview composables in user apps.","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-unit-android:1.6.3","name":"Compose Unit","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Compose classes for simple units","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3"},{"name":"Compose Unit","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-unit:1.6.3","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","description":"Compose classes for simple units","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3"},{"website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Internal Compose utilities used by other modules","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.ui:ui-util-android:1.6.3","licenses":["Apache-2.0"],"name":"Compose Util"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.6.3","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","description":"Internal Compose utilities used by other modules","name":"Compose Util","licenses":["Apache-2.0"],"id":"androidx.compose.ui:ui-util:1.6.3"},{"description":"Compose UI primitives. This library contains the primitives that form the Compose UI Toolkit, such as drawing, measurement and layout.","website":"https://developer.android.com/jetpack/androidx/releases/compose-ui#1.6.3","artifactVersion":"1.6.3","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.compose.ui:ui:1.6.3","licenses":["Apache-2.0"],"name":"Compose UI"},{"id":"androidx.concurrent:concurrent-futures:1.1.0","licenses":["Apache-2.0"],"name":"AndroidX Futures","website":"https://developer.android.com/topic/libraries/architecture/index.html","description":"Androidx implementation of Guava's ListenableFuture","artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}]},{"id":"androidx.constraintlayout:constraintlayout-solver:2.0.1","licenses":["Apache-2.0"],"name":"Android ConstraintLayout Solver","website":"http://tools.android.com","description":"Solver for ConstraintLayout","artifactVersion":"2.0.1","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"id":"androidx.constraintlayout:constraintlayout:2.0.1","name":"Android ConstraintLayout","description":"ConstraintLayout for Android","website":"http://tools.android.com","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.0.1"},{"name":"Android Support Library Coordinator Layout","id":"androidx.coordinatorlayout:coordinatorlayout:1.1.0","licenses":["Apache-2.0"],"artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}],"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"https://developer.android.com/jetpack/androidx"},{"licenses":["Apache-2.0"],"id":"androidx.core:core-ktx:1.12.0","name":"Core Kotlin Extensions","website":"https://developer.android.com/jetpack/androidx/releases/core#1.12.0","description":"Kotlin extensions for 'core' artifact","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.12.0"},{"name":"SplashScreen","licenses":["Apache-2.0"],"id":"androidx.core:core-splashscreen:1.0.1","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.1","website":"https://developer.android.com/jetpack/androidx/releases/core#1.0.1","description":"This library provides the compatibility APIs for SplashScreen and helper method to enable a splashscreen on devices prior Android 12"},{"id":"androidx.core:core:1.12.0","licenses":["Apache-2.0"],"name":"Core","website":"https://developer.android.com/jetpack/androidx/releases/core#1.12.0","description":"Provides backward-compatible implementations of Android platform APIs and features.","artifactVersion":"1.12.0","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"id":"androidx.cursoradapter:cursoradapter:1.0.0","name":"Android Support Library Cursor Adapter","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0"},{"licenses":["Apache-2.0"],"id":"androidx.customview:customview-poolingcontainer:1.0.0","name":"androidx.customview:poolingcontainer","website":"https://developer.android.com/jetpack/androidx/releases/customview#1.0.0","description":"Utilities for listening to the lifecycle of containers that manage their child Views' lifecycle, such as RecyclerView","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0"},{"id":"androidx.customview:customview:1.1.0","licenses":["Apache-2.0"],"name":"Android Support Library Custom View","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"https://developer.android.com/jetpack/androidx","artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}]},{"licenses":["Apache-2.0"],"id":"androidx.databinding:viewbinding:8.3.0","website":"","developers":[],"artifactVersion":"8.3.0"},{"name":"Android Support Library Document File","id":"androidx.documentfile:documentfile:1.0.0","licenses":["Apache-2.0"],"artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}],"website":"http://developer.android.com/tools/extras/support-library.html","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."},{"name":"Android Support Library Drawer Layout","licenses":["Apache-2.0"],"id":"androidx.drawerlayout:drawerlayout:1.2.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.0","website":"https://developer.android.com/jetpack/androidx/releases/drawerlayout#1.2.0","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later."},{"website":"http://developer.android.com/tools/extras/support-library.html","description":"Physics-based animation in support library, where the animations are driven by physics force. You can use this Animation library to create smooth and realistic animations.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","licenses":["Apache-2.0"],"id":"androidx.dynamicanimation:dynamicanimation:1.0.0","name":"Android Support DynamicAnimation"},{"id":"androidx.emoji2:emoji2-bundled:1.4.0","licenses":["Apache-2.0","SIL Open Font License, Version 1.1","Unicode License"],"name":"Emoji2 Bundled","website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","description":"Library bundled with assets to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.","artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}]},{"artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","description":"Provide helper classes for Emoji2 views.","name":"Emoji2 Views Helper","id":"androidx.emoji2:emoji2-views-helper:1.4.0","licenses":["Apache-2.0"]},{"name":"Emoji2 Views","id":"androidx.emoji2:emoji2-views:1.4.0","licenses":["Apache-2.0"],"artifactVersion":"1.4.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","description":"Support for using emoji2 directly with Android Views, for use in apps without appcompat"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.4.0","website":"https://developer.android.com/jetpack/androidx/releases/emoji2#1.4.0","description":"Core library to enable emoji compatibility in Kitkat and newer devices to avoid the empty emoji characters.","name":"Emoji2","licenses":["Apache-2.0"],"id":"androidx.emoji2:emoji2:1.4.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.7","website":"https://developer.android.com/jetpack/androidx/releases/exifinterface#1.3.7","description":"Android Support ExifInterface","name":"Android Support ExifInterface","licenses":["Apache-2.0"],"id":"androidx.exifinterface:exifinterface:1.3.7"},{"name":"Fragment Kotlin Extensions","id":"androidx.fragment:fragment-ktx:1.6.1","licenses":["Apache-2.0"],"artifactVersion":"1.6.1","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/fragment#1.6.1","description":"Kotlin extensions for 'fragment' artifact"},{"id":"androidx.fragment:fragment:1.6.1","licenses":["Apache-2.0"],"name":"Android Support Library fragment","website":"https://developer.android.com/jetpack/androidx/releases/fragment#1.6.1","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","artifactVersion":"1.6.1","developers":[{"name":"The Android Open Source Project"}]},{"website":"http://developer.android.com/tools/extras/support-library.html","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","licenses":["Apache-2.0"],"id":"androidx.interpolator:interpolator:1.0.0","name":"Android Support Library Interpolators"},{"licenses":["Apache-2.0"],"id":"androidx.legacy:legacy-support-core-utils:1.0.0","name":"Android Support Library core utils","website":"http://developer.android.com/tools/extras/support-library.html","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0"},{"name":"Lifecycle-Common for Java 8","id":"androidx.lifecycle:lifecycle-common-java8:2.7.0","licenses":["Apache-2.0"],"artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Android Lifecycle-Common for Java 8 Language"},{"name":"Lifecycle-Common","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-common:2.7.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","description":"Android Lifecycle-Common","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Kotlin extensions for 'livedata-core' artifact","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-livedata-core-ktx:2.7.0","name":"LiveData Core Kotlin Extensions"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","description":"Android Lifecycle LiveData Core","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","name":"Lifecycle LiveData Core","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-livedata-core:2.7.0"},{"description":"Android Lifecycle LiveData","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.lifecycle:lifecycle-livedata:2.7.0","licenses":["Apache-2.0"],"name":"Lifecycle LiveData"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Android Lifecycle Process","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.lifecycle:lifecycle-process:2.7.0","licenses":["Apache-2.0"],"name":"Lifecycle Process"},{"name":"Lifecycle Runtime Compose","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-runtime-compose:2.7.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","description":"Compose integration with Lifecycle","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Kotlin extensions for 'lifecycle' artifact","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.lifecycle:lifecycle-runtime-ktx:2.7.0","licenses":["Apache-2.0"],"name":"Lifecycle Kotlin Extensions"},{"id":"androidx.lifecycle:lifecycle-runtime:2.7.0","licenses":["Apache-2.0"],"name":"Lifecycle Runtime","description":"Android Lifecycle Runtime","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}]},{"name":"Lifecycle Service","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-service:2.7.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Android Lifecycle Service"},{"website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Compose integration with Lifecycle ViewModel","artifactVersion":"2.7.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.lifecycle:lifecycle-viewmodel-compose:2.7.0","licenses":["Apache-2.0"],"name":"Lifecycle ViewModel Compose"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","description":"Kotlin extensions for 'viewmodel' artifact","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","name":"Lifecycle ViewModel Kotlin Extensions","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","description":"Android Lifecycle ViewModel","name":"Lifecycle ViewModel with SavedState","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-viewmodel-savedstate:2.7.0"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.7.0","description":"Android Lifecycle ViewModel","website":"https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0","name":"Lifecycle ViewModel","licenses":["Apache-2.0"],"id":"androidx.lifecycle:lifecycle-viewmodel:2.7.0"},{"name":"Android Support Library loader","licenses":["Apache-2.0"],"id":"androidx.loader:loader:1.0.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"http://developer.android.com/tools/extras/support-library.html"},{"licenses":["Apache-2.0"],"id":"androidx.localbroadcastmanager:localbroadcastmanager:1.0.0","name":"Android Support Library Local Broadcast Manager","website":"http://developer.android.com/tools/extras/support-library.html","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0"},{"licenses":["Apache-2.0"],"id":"androidx.media3:media3-common:1.3.0","name":"Media3 common module","website":"https://github.com/androidx/media","description":"Media3 common module","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0"},{"artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","description":"Media3 Container module","name":"Media3 Container module","id":"androidx.media3:media3-container:1.3.0","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"id":"androidx.media3:media3-database:1.3.0","name":"Media3 database module","website":"https://github.com/androidx/media","description":"Media3 database module","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0"},{"description":"Media3 DataSource module","website":"https://github.com/androidx/media","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","licenses":["Apache-2.0"],"id":"androidx.media3:media3-datasource:1.3.0","name":"Media3 DataSource module"},{"name":"Media3 decoder module","licenses":["Apache-2.0"],"id":"androidx.media3:media3-decoder:1.3.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://github.com/androidx/media","description":"Media3 decoder module"},{"website":"https://github.com/androidx/media","description":"Media3 Effect module","artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.media3:media3-effect:1.3.0","licenses":["Apache-2.0"],"name":"Media3 Effect module"},{"name":"Media3 ExoPlayer module","id":"androidx.media3:media3-exoplayer:1.3.0","licenses":["Apache-2.0"],"artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"description":"Media3 ExoPlayer module","website":"https://github.com/androidx/media"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://github.com/androidx/media","description":"Media3 Extractor module","name":"Media3 Extractor module","licenses":["Apache-2.0"],"id":"androidx.media3:media3-extractor:1.3.0"},{"artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://github.com/androidx/media","description":"Media3 Muxer module","name":"Media3 Muxer module","id":"androidx.media3:media3-muxer:1.3.0","licenses":["Apache-2.0"]},{"artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"description":"Media3 Session module","website":"https://github.com/androidx/media","name":"Media3 Session module","id":"androidx.media3:media3-session:1.3.0","licenses":["Apache-2.0"]},{"artifactVersion":"1.3.0","developers":[{"name":"The Android Open Source Project"}],"description":"Media3 Transformer module","website":"https://github.com/androidx/media","name":"Media3 Transformer module","id":"androidx.media3:media3-transformer:1.3.0","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"id":"androidx.media3:media3-ui:1.3.0","name":"Media3 UI module","description":"Media3 UI module","website":"https://github.com/androidx/media","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/media#1.7.0","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.7.0","licenses":["Apache-2.0"],"id":"androidx.media:media:1.7.0","name":"Media"},{"name":"Android Preferences KTX","id":"androidx.preference:preference-ktx:1.2.1","licenses":["Apache-2.0"],"artifactVersion":"1.2.1","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/preference#1.2.1","description":"Kotlin extensions for preferences"},{"website":"https://developer.android.com/jetpack/androidx/releases/preference#1.2.1","description":"AndroidX Preference","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","licenses":["Apache-2.0"],"id":"androidx.preference:preference:1.2.1","name":"AndroidX Preference"},{"description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"http://developer.android.com/tools/extras/support-library.html","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.0","licenses":["Apache-2.0"],"id":"androidx.print:print:1.0.0","name":"Android Support Library Print"},{"name":"androidx.profileinstaller:profileinstaller","licenses":["Apache-2.0"],"id":"androidx.profileinstaller:profileinstaller:1.3.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.3.0","website":"https://developer.android.com/jetpack/androidx/releases/profileinstaller#1.3.0","description":"Allows libraries to prepopulate ahead of time compilation traces to be read by ART"},{"name":"Android Support RecyclerView","id":"androidx.recyclerview:recyclerview:1.3.2","licenses":["Apache-2.0"],"artifactVersion":"1.3.2","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/recyclerview#1.3.2","description":"Android Support RecyclerView"},{"website":"https://developer.android.com/jetpack/androidx/releases/resourceinspection#1.0.1","description":"Annotation processors for Android resource and layout inspection","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.0.1","licenses":["Apache-2.0"],"id":"androidx.resourceinspection:resourceinspection-annotation:1.0.1","name":"Android Resource Inspection - Annotations"},{"name":"Android Room-Common","licenses":["Apache-2.0"],"id":"androidx.room:room-common:2.5.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.5.0","description":"Android Room-Common","website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0"},{"licenses":["Apache-2.0"],"id":"androidx.room:room-ktx:2.5.0","name":"Android Room Kotlin Extensions","website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0","description":"Android Room Kotlin Extensions","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.5.0"},{"name":"Android Room-Runtime","licenses":["Apache-2.0"],"id":"androidx.room:room-runtime:2.5.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.5.0","website":"https://developer.android.com/jetpack/androidx/releases/room#2.5.0","description":"Android Room-Runtime"},{"licenses":["Apache-2.0"],"id":"androidx.savedstate:savedstate-ktx:1.2.1","name":"SavedState Kotlin Extensions","description":"Kotlin extensions for 'savedstate' artifact","website":"https://developer.android.com/jetpack/androidx/releases/savedstate#1.2.1","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1"},{"name":"Saved State","licenses":["Apache-2.0"],"id":"androidx.savedstate:savedstate:1.2.1","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.1","description":"Android Lifecycle Saved State","website":"https://developer.android.com/jetpack/androidx/releases/savedstate#1.2.1"},{"developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.2.0","description":"SlidingPaneLayout offers a responsive, two pane layout that automatically switches between overlapping panes on smaller devices to a side by side view on larger devices.","website":"https://developer.android.com/jetpack/androidx/releases/slidingpanelayout#1.2.0","name":"Android Support Library Sliding Pane Layout","licenses":["Apache-2.0"],"id":"androidx.slidingpanelayout:slidingpanelayout:1.2.0"},{"name":"Android Support SQLite - Framework Implementation","licenses":["Apache-2.0"],"id":"androidx.sqlite:sqlite-framework:2.3.0","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.3.0","website":"https://developer.android.com/jetpack/androidx/releases/sqlite#2.3.0","description":"The implementation of Support SQLite library using the framework code."},{"licenses":["Apache-2.0"],"id":"androidx.sqlite:sqlite:2.3.0","name":"Android DB","website":"https://developer.android.com/jetpack/androidx/releases/sqlite#2.3.0","description":"Android DB","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"2.3.0"},{"website":"https://developer.android.com/jetpack/androidx/releases/startup#1.1.1","description":"Android App Startup Runtime","artifactVersion":"1.1.1","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.startup:startup-runtime:1.1.1","licenses":["Apache-2.0"],"name":"Android App Startup Runtime"},{"description":"Android Tracing","website":"https://developer.android.com/jetpack/androidx/releases/tracing#1.0.0","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}],"id":"androidx.tracing:tracing:1.0.0","licenses":["Apache-2.0"],"name":"Android Tracing"},{"id":"androidx.transition:transition:1.4.1","licenses":["Apache-2.0"],"name":"Android Transition Support Library","description":"Android Transition Support Library","website":"https://developer.android.com/jetpack/androidx/releases/transition#1.4.1","artifactVersion":"1.4.1","developers":[{"name":"The Android Open Source Project"}]},{"artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx","description":"Android Support AnimatedVectorDrawable","name":"Android Support AnimatedVectorDrawable","id":"androidx.vectordrawable:vectordrawable-animated:1.1.0","licenses":["Apache-2.0"]},{"name":"Android Support VectorDrawable","id":"androidx.vectordrawable:vectordrawable:1.1.0","licenses":["Apache-2.0"],"artifactVersion":"1.1.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx","description":"Android Support VectorDrawable"},{"name":"VersionedParcelable","id":"androidx.versionedparcelable:versionedparcelable:1.1.1","licenses":["Apache-2.0"],"artifactVersion":"1.1.1","developers":[{"name":"The Android Open Source Project"}],"website":"http://developer.android.com/tools/extras/support-library.html","description":"Provides a stable but relatively compact binary serialization format that can be passed across processes or persisted safely."},{"artifactVersion":"1.1.0-beta02","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-beta02","description":"AndroidX Widget ViewPager2","name":"ViewPager2","id":"androidx.viewpager2:viewpager2:1.1.0-beta02","licenses":["Apache-2.0"]},{"id":"androidx.viewpager:viewpager:1.0.0","licenses":["Apache-2.0"],"name":"Android Support Library View Pager","description":"The Support Library is a static library that you can add to your Android application in order to use APIs that are either not available for older platform versions or utility APIs that aren't a part of the framework APIs. Compatible on devices running API 14 or later.","website":"http://developer.android.com/tools/extras/support-library.html","artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}]},{"artifactVersion":"1.0.0","developers":[{"name":"The Android Open Source Project"}],"website":"https://developer.android.com/jetpack/androidx/releases/window#1.0.0","description":"WindowManager Jetpack library. Currently only provides additional functionality on foldable devices.","name":"Jetpack WindowManager Library","id":"androidx.window:window:1.0.0","licenses":["Apache-2.0"]},{"artifactVersion":"2.9.0","developers":[{"name":"The Android Open Source Project"}],"description":"Android WorkManager Kotlin Extensions","website":"https://developer.android.com/jetpack/androidx/releases/work#2.9.0","name":"WorkManager Kotlin Extensions","id":"androidx.work:work-runtime-ktx:2.9.0","licenses":["Apache-2.0"]},{"name":"WorkManager Runtime","id":"androidx.work:work-runtime:2.9.0","licenses":["Apache-2.0"],"artifactVersion":"2.9.0","developers":[{"name":"The Android Open Source Project"}],"description":"Android WorkManager runtime library","website":"https://developer.android.com/jetpack/androidx/releases/work#2.9.0"},{"artifactVersion":"1.4","developers":[{"name":"Paul LeBeau"}],"description":"SVG rendering library for Android.","website":"https://github.com/BigBadaboom/androidsvg","name":"AndroidSVG","id":"com.caverock:androidsvg-aar:1.4","licenses":["Apache-2.0"]},{"name":"UnifiedPush/android-connector","licenses":["Apache-2.0"],"id":"com.github.UnifiedPush:android-connector:2.1.1","developers":[{"name":"UnifiedPush"}],"artifactVersion":"2.1.1","website":"https://github.com/UnifiedPush/android-connector","description":"UnifiedPush connector library"},{"developers":[],"artifactVersion":"1.6.2","website":"","licenses":[],"id":"com.github.alexzhirkevich:custom-qr-generator:1.6.2"},{"description":"A set of annotations for configuring Glide.","website":"https://github.com/bumptech/glide","artifactVersion":"4.15.1","developers":[{"name":"Sam Judd"}],"id":"com.github.bumptech.glide:annotations:4.15.1","licenses":["BSD-2-Clause","Apache-2.0"],"name":"Glide Annotations"},{"description":"A cache that uses a bounded amount of space on a filesystem. Based on Jake Wharton's tailored for Glide.","website":"https://github.com/bumptech/glide","artifactVersion":"4.15.1","developers":[{"name":"Sam Judd"}],"id":"com.github.bumptech.glide:disklrucache:4.15.1","licenses":["BSD-2-Clause","Apache-2.0"],"name":"Glide Disk LRU Cache Library"},{"licenses":["BSD-2-Clause","Apache-2.0"],"id":"com.github.bumptech.glide:gifdecoder:4.15.1","name":"Glide GIF Decoder Library","description":"Implementation of GifDecoder that is more memory efficient to animate for Android devices.","website":"https://github.com/bumptech/glide","developers":[{"name":"Sam Judd"}],"artifactVersion":"4.15.1"},{"website":"https://github.com/bumptech/glide","description":"A fast and efficient image loading library for Android focused on smooth scrolling.","developers":[{"name":"Sam Judd"}],"artifactVersion":"4.15.1","licenses":["BSD-2-Clause","Apache-2.0"],"id":"com.github.bumptech.glide:glide:4.15.1","name":"Glide"},{"licenses":["BSD-2-Clause","Apache-2.0"],"id":"com.github.bumptech.glide:okhttp3-integration:4.15.1","name":"Glide OkHttp 3.x Integration","description":"An integration library to use OkHttp 3.x to fetch data over http/https in Glide","website":"https://github.com/bumptech/glide","developers":[{"name":"Sam Judd"}],"artifactVersion":"4.15.1"},{"artifactVersion":"1.2.3","developers":[{"name":"Olivier Goutay & Stoyan Dimitrov"}],"description":"A SwipeRefreshLayout extension that allows to swipe in both direction","website":"https://github.com/omadahealth/SwipyRefreshLayout","name":"SwipyRefreshLayout Library","id":"com.github.omadahealth:swipy:1.2.3","licenses":["MIT"]},{"id":"com.github.penfeizhou.android.animation:apng:2.25.0","licenses":[],"website":"","description":"aaae94bea343a992c053f76bba3373a437e0f34a","artifactVersion":"2.25.0","developers":[]},{"developers":[],"artifactVersion":"2.25.0","website":"","description":"aaae94bea343a992c053f76bba3373a437e0f34a","licenses":[],"id":"com.github.penfeizhou.android.animation:frameanimation:2.25.0"},{"name":"draglistview","id":"com.github.woxthebox:draglistview:1.7.3","licenses":["Apache-2.0"],"artifactVersion":"1.7.3","developers":[{"name":"Magnus Woxblom"}],"description":"Drag and drop to re-order items in a list, grid or board.","website":"https://github.com/woxthebox/DragListView"},{"name":"Glide WebpDecoder Integration","licenses":["Apache-2.0"],"id":"com.github.zjupure:webpdecoder:2.6.4.15.1","developers":[{"name":"zjupure"}],"artifactVersion":"2.6.4.15.1","description":"An integration library to decode and show animated webp for Glide","website":"https://github.com/zjupure/GlideWebpDecoder"},{"website":"https://github.com/firebase/firebase-android-sdk","developers":[],"artifactVersion":"3.1.0","licenses":["Apache-2.0"],"id":"com.google.android.datatransport:transport-api:3.1.0"},{"name":"transport-backend-cct","licenses":["Apache-2.0"],"id":"com.google.android.datatransport:transport-backend-cct:3.1.8","developers":[],"artifactVersion":"3.1.8","website":""},{"developers":[],"artifactVersion":"3.1.8","website":"","name":"transport-runtime","licenses":["Apache-2.0"],"id":"com.google.android.datatransport:transport-runtime:3.1.8"},{"description":"Flexbox for Android","website":"https://github.com/google/flexbox-layout","artifactVersion":"3.0.0","developers":[{"name":"Google"}],"id":"com.google.android.flexbox:flexbox:3.0.0","licenses":["Apache-2.0"],"name":"flexbox-layout"},{"developers":[],"artifactVersion":"18.0.1","website":"","name":"play-services-base","licenses":["Android Software Development Kit License"],"id":"com.google.android.gms:play-services-base:18.0.1"},{"developers":[],"artifactVersion":"18.1.0","website":"","name":"play-services-basement","licenses":["Android Software Development Kit License"],"id":"com.google.android.gms:play-services-basement:18.1.0"},{"name":"play-services-cloud-messaging","id":"com.google.android.gms:play-services-cloud-messaging:17.1.0","licenses":["Android Software Development Kit License"],"artifactVersion":"17.1.0","developers":[],"website":""},{"name":"play-services-stats","id":"com.google.android.gms:play-services-stats:17.0.2","licenses":["Android Software Development Kit License"],"artifactVersion":"17.0.2","developers":[],"website":""},{"licenses":["Android Software Development Kit License"],"id":"com.google.android.gms:play-services-tasks:18.0.2","name":"play-services-tasks","website":"","developers":[],"artifactVersion":"18.0.2"},{"website":"https://github.com/material-components/material-components-android","description":"Material Components for Android is a static library that you can add to your Android application in order to use APIs that provide implementations of the Material Design specification. Compatible on devices running API 14 or later.","developers":[{"name":"The Android Open Source Project"}],"artifactVersion":"1.11.0","licenses":["Apache-2.0"],"id":"com.google.android.material:material:1.11.0","name":"Material Components for Android"},{"name":"error-prone annotations","licenses":["Apache-2.0"],"id":"com.google.errorprone:error_prone_annotations:2.15.0","developers":[],"artifactVersion":"2.15.0","website":""},{"artifactVersion":"16.2.0","developers":[],"website":"","name":"firebase-annotations","id":"com.google.firebase:firebase-annotations:16.2.0","licenses":["Apache-2.0"]},{"licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-common-ktx:20.4.2","developers":[],"artifactVersion":"20.4.2","website":"https://github.com/firebase/firebase-android-sdk"},{"id":"com.google.firebase:firebase-common:20.4.2","licenses":["Apache-2.0"],"artifactVersion":"20.4.2","developers":[],"website":"https://github.com/firebase/firebase-android-sdk"},{"developers":[],"artifactVersion":"17.1.5","website":"https://github.com/firebase/firebase-android-sdk","licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-components:17.1.5"},{"developers":[],"artifactVersion":"18.1.7","website":"","name":"firebase-datatransport","licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-datatransport:18.1.7"},{"website":"","artifactVersion":"18.0.0","developers":[],"id":"com.google.firebase:firebase-encoders-json:18.0.0","licenses":["Apache-2.0"],"name":"firebase-encoders-json"},{"website":"","artifactVersion":"16.0.0","developers":[],"id":"com.google.firebase:firebase-encoders-proto:16.0.0","licenses":["Apache-2.0"],"name":"firebase-encoders-proto"},{"name":"firebase-encoders","id":"com.google.firebase:firebase-encoders:17.0.0","licenses":["Apache-2.0"],"artifactVersion":"17.0.0","developers":[],"website":""},{"id":"com.google.firebase:firebase-iid-interop:17.1.0","licenses":["Android Software Development Kit License"],"name":"firebase-iid-interop","website":"","artifactVersion":"17.1.0","developers":[]},{"licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-installations-interop:17.1.1","website":"https://github.com/firebase/firebase-android-sdk","developers":[],"artifactVersion":"17.1.1"},{"artifactVersion":"17.2.0","developers":[],"website":"https://github.com/firebase/firebase-android-sdk","id":"com.google.firebase:firebase-installations:17.2.0","licenses":["Apache-2.0"]},{"developers":[],"artifactVersion":"19.0.0","website":"","name":"firebase-measurement-connector","licenses":["Android Software Development Kit License"],"id":"com.google.firebase:firebase-measurement-connector:19.0.0"},{"developers":[],"artifactVersion":"23.4.1","website":"https://github.com/firebase/firebase-android-sdk","licenses":["Apache-2.0"],"id":"com.google.firebase:firebase-messaging:23.4.1"},{"description":"Contains\n com.google.common.util.concurrent.internal.InternalFutureFailureAccess and\n InternalFutures. Most users will never need to use this artifact. Its\n classes is conceptually a part of Guava, but they're in this separate\n artifact so that Android libraries can use them without pulling in all of\n Guava (just as they can use ListenableFuture by depending on the\n listenablefuture artifact).","website":"","developers":[],"artifactVersion":"1.0.1","licenses":[],"id":"com.google.guava:failureaccess:1.0.1","name":"Guava InternalFutureFailureAccess and InternalFutures"},{"description":"Guava is a suite of core and expanded libraries that include\n utility classes, Google's collections, I/O classes, and\n much more.","website":"https://github.com/google/guava","artifactVersion":"32.1.3-android","developers":[],"id":"com.google.guava:guava:32.1.3-android","licenses":[],"name":"Guava: Google Core Libraries for Java"},{"website":"","description":"An empty artifact that Guava depends on to signal that it is providing\n ListenableFuture -- but is also available in a second \"version\" that\n contains com.google.common.util.concurrent.ListenableFuture class, without\n any other Guava classes. The idea is:\n\n - If users want only ListenableFuture, they depend on listenablefuture-1.0.\n\n - If users want all of Guava, they depend on guava, which, as of Guava\n 27.0, depends on\n listenablefuture-9999.0-empty-to-avoid-conflict-with-guava. The 9999.0-...\n version number is enough for some build systems (notably, Gradle) to select\n that empty artifact over the \"real\" listenablefuture-1.0 -- avoiding a\n conflict with the copy of ListenableFuture in guava itself. If users are\n using an older version of Guava or a build system other than Gradle, they\n may see class conflicts. If so, they can solve them by manually excluding\n the listenablefuture artifact or manually forcing their build systems to\n use 9999.0-....","artifactVersion":"9999.0-empty-to-avoid-conflict-with-guava","developers":[],"id":"com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava","licenses":[],"name":"Guava ListenableFuture only"},{"description":"Core barcode encoding/decoding library","website":"","developers":[],"artifactVersion":"3.5.1","licenses":[],"id":"com.google.zxing:core:3.5.1","name":"ZXing Core"},{"developers":[{"name":"natario1"}],"artifactVersion":"0.6.1","description":"Egloo","website":"https://github.com/natario1/Egloo","name":"Egloo","licenses":["MIT"],"id":"com.otaliastudios.opengl:egloo:0.6.1"},{"licenses":["Apache-2.0"],"id":"com.otaliastudios:transcoder:0.10.5","name":"Transcoder","description":"Transcoder","website":"https://github.com/natario1/Transcoder","developers":[{"name":"natario1"}],"artifactVersion":"0.10.5"},{"developers":[{"name":"Square, Inc."}],"artifactVersion":"5.0.0-alpha.12","website":"https://square.github.io/okhttp/","description":"Square’s meticulous HTTP client for Java and Kotlin.","name":"okhttp-java-net-cookiejar","licenses":["Apache-2.0"],"id":"com.squareup.okhttp3:okhttp-java-net-cookiejar:5.0.0-alpha.12"},{"id":"com.squareup.okhttp3:okhttp-jvm:5.0.0-alpha.12","licenses":["Apache-2.0"],"name":"okhttp","website":"https://square.github.io/okhttp/","description":"Square’s meticulous HTTP client for Java and Kotlin.","artifactVersion":"5.0.0-alpha.12","developers":[{"name":"Square, Inc."}]},{"website":"https://square.github.io/okhttp/","description":"Square’s meticulous HTTP client for Java and Kotlin.","developers":[{"name":"Square, Inc."}],"artifactVersion":"5.0.0-alpha.12","licenses":["Apache-2.0"],"id":"com.squareup.okhttp3:okhttp-urlconnection:5.0.0-alpha.12","name":"okhttp-urlconnection"},{"id":"com.squareup.okhttp3:okhttp:5.0.0-alpha.12","licenses":["Apache-2.0"],"name":"okhttp","website":"https://square.github.io/okhttp/","description":"Square’s meticulous HTTP client for Java and Kotlin.","artifactVersion":"5.0.0-alpha.12","developers":[{"name":"Square, Inc."}]},{"artifactVersion":"3.7.0","developers":[{"name":"Square, Inc."}],"website":"https://github.com/square/okio/","description":"A modern I/O library for Android, Java, and Kotlin Multiplatform.","name":"okio","id":"com.squareup.okio:okio-jvm:3.7.0","licenses":["Apache-2.0"]},{"name":"okio","licenses":["Apache-2.0"],"id":"com.squareup.okio:okio:3.7.0","developers":[{"name":"Square, Inc."}],"artifactVersion":"3.7.0","description":"A modern I/O library for Android, Java, and Kotlin Multiplatform.","website":"https://github.com/square/okio/"},{"id":"io.insert-koin:koin-android-compat:3.5.0","licenses":["Apache-2.0"],"name":"koin-android-compat","website":"https://insert-koin.io/","description":"KOIN - Kotlin simple Dependency Injection Framework","artifactVersion":"3.5.0","developers":[{"name":"Arnaud Giuliani"}]},{"website":"https://insert-koin.io/","description":"KOIN - Kotlin simple Dependency Injection Framework","developers":[{"name":"Arnaud Giuliani"}],"artifactVersion":"3.5.0","licenses":["Apache-2.0"],"id":"io.insert-koin:koin-android:3.5.0","name":"koin-android"},{"artifactVersion":"3.5.0","developers":[{"name":"Arnaud Giuliani"}],"website":"https://insert-koin.io/","description":"KOIN - Kotlin simple Dependency Injection Framework","name":"koin-androidx-workmanager","id":"io.insert-koin:koin-androidx-workmanager:3.5.0","licenses":["Apache-2.0"]},{"name":"koin-core","licenses":["Apache-2.0"],"id":"io.insert-koin:koin-core-jvm:3.5.0","developers":[{"name":"Arnaud Giuliani"}],"artifactVersion":"3.5.0","website":"https://insert-koin.io/","description":"KOIN - Kotlin simple Dependency Injection Framework"},{"id":"io.insert-koin:koin-core:3.5.0","licenses":["Apache-2.0"],"name":"koin-core","website":"https://insert-koin.io/","description":"KOIN - Kotlin simple Dependency Injection Framework","artifactVersion":"3.5.0","developers":[{"name":"Arnaud Giuliani"}]},{"artifactVersion":"1","developers":[],"website":"http://code.google.com/p/atinject/","description":"The javax.inject API","name":"javax.inject","id":"javax.inject:javax.inject:1","licenses":["Apache-2.0"]},{"name":"Bouncy Castle Provider","id":"org.bouncycastle:bcprov-jdk15on:1.70","licenses":["Bouncy Castle Licence"],"artifactVersion":"1.70","developers":[{"name":"The Legion of the Bouncy Castle Inc."}],"description":"The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. This jar contains JCE provider and lightweight API for the Bouncy Castle Cryptography APIs for JDK 1.5 and up.","website":"https://www.bouncycastle.org/java.html"},{"developers":[{"name":"Conscrypt Contributors"}],"artifactVersion":"2.5.2","description":"Conscrypt: Android","website":"https://conscrypt.org/","name":"org.conscrypt:conscrypt-android","licenses":["Apache-2.0"],"id":"org.conscrypt:conscrypt-android:2.5.2"},{"name":"Kotlin Libraries bill-of-materials","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-bom:1.8.22","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.22","description":"Kotlin is a statically typed programming language that compiles to JVM byte codes and JavaScript","website":"https://kotlinlang.org/"},{"licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-reflect:1.9.22","name":"Kotlin Reflect","website":"https://kotlinlang.org/","description":"Kotlin Full Reflection Library","developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.22"},{"name":"Kotlin Stdlib Common","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-stdlib-common:1.9.22","developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.22","website":"https://kotlinlang.org/","description":"Kotlin Common Standard Library (legacy, use kotlin-stdlib instead)"},{"developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.0","website":"https://kotlinlang.org/","description":"Kotlin Standard Library JDK 7 extension","name":"Kotlin Stdlib Jdk7","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0"},{"website":"https://kotlinlang.org/","description":"Kotlin Standard Library JDK 8 extension","developers":[{"name":"Kotlin Team"}],"artifactVersion":"1.9.0","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0","name":"Kotlin Stdlib Jdk8"},{"name":"Kotlin Stdlib","id":"org.jetbrains.kotlin:kotlin-stdlib:1.9.22","licenses":["Apache-2.0"],"artifactVersion":"1.9.22","developers":[{"name":"Kotlin Team"}],"website":"https://kotlinlang.org/","description":"Kotlin Standard Library"},{"name":"kotlinx-coroutines-android","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","description":"Coroutines support libraries for Kotlin","website":"https://github.com/Kotlin/kotlinx.coroutines"},{"artifactVersion":"1.8.0","developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.coroutines","description":"Coroutines support libraries for Kotlin","name":"kotlinx-coroutines-bom","id":"org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0","licenses":["Apache-2.0"]},{"website":"https://github.com/Kotlin/kotlinx.coroutines","description":"Coroutines support libraries for Kotlin","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0","name":"kotlinx-coroutines-core"},{"name":"kotlinx-coroutines-core","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","description":"Coroutines support libraries for Kotlin","website":"https://github.com/Kotlin/kotlinx.coroutines"},{"name":"kotlinx-coroutines-play-services","licenses":["Apache-2.0"],"id":"org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.0","developers":[{"name":"JetBrains Team"}],"artifactVersion":"1.8.0","description":"Coroutines support libraries for Kotlin","website":"https://github.com/Kotlin/kotlinx.coroutines"},{"name":"kotlinx-serialization-bom","id":"org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3","licenses":["Apache-2.0"],"artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}],"description":"Kotlin multiplatform serialization runtime library","website":"https://github.com/Kotlin/kotlinx.serialization"},{"artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}],"website":"https://github.com/Kotlin/kotlinx.serialization","description":"Kotlin multiplatform serialization runtime library","name":"kotlinx-serialization-core","id":"org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.6.3","licenses":["Apache-2.0"]},{"website":"https://github.com/Kotlin/kotlinx.serialization","description":"Kotlin multiplatform serialization runtime library","artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}],"id":"org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3","licenses":["Apache-2.0"],"name":"kotlinx-serialization-core"},{"id":"org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.3","licenses":["Apache-2.0"],"name":"kotlinx-serialization-json","description":"Kotlin multiplatform serialization runtime library","website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}]},{"description":"Kotlin multiplatform serialization runtime library","website":"https://github.com/Kotlin/kotlinx.serialization","artifactVersion":"1.6.3","developers":[{"name":"JetBrains Team"}],"id":"org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3","licenses":["Apache-2.0"],"name":"kotlinx-serialization-json"},{"name":"JetBrains Java Annotations","licenses":["Apache-2.0"],"id":"org.jetbrains:annotations:23.0.0","developers":[{"name":"JetBrains Team"}],"artifactVersion":"23.0.0","description":"A set of annotations used for code inspection support and code documentation.","website":"https://github.com/JetBrains/java-annotations"},{"artifactVersion":"1.0","developers":[{"name":"Andrey Mischenko"}],"website":"https://github.com/gildor/kotlin-coroutines-okhttp","description":"Coroutine adapter for OkHttp Call","name":"kotlin-coroutines-okhttp","id":"ru.gildor.coroutines:kotlin-coroutines-okhttp:1.0","licenses":["Apache-2.0"]}],"licenses":[{"shortName":"Amazon Software License","urls":["https://aws.amazon.com/asl/","http://aws.amazon.com/asl/"],"name":"Amazon Software License"},{"shortName":"Android Software Development Kit License","urls":["https://developer.android.com/studio/terms.html"],"name":"Android Software Development Kit License"},{"urls":["https://www.apache.org/licenses/LICENSE-2.0","https://www.apache.org/licenses/LICENSE-2.0.txt","http://www.apache.org/licenses/LICENSE-2.0","http://www.apache.org/licenses/LICENSE-2.0.txt","https://api.github.com/licenses/apache-2.0","https://github.com/elye/loaderviewlibrary/blob/master/LICENSE"],"shortName":"Apache-2.0","name":"The Apache Software License, Version 2.0"},{"name":"The 2-Clause BSD License","urls":["https://opensource.org/license/bsd-2-clause/","http://www.opensource.org/licenses/bsd-license"],"shortName":"BSD-2-Clause"},{"name":"Bouncy Castle Licence","shortName":"Bouncy Castle Licence","urls":["https://www.bouncycastle.org/licence.html"]},{"urls":["https://opensource.org/license/mit/","https://opensource.org/licenses/MIT","https://github.com/lisawray/groupie/blob/master/LICENSE.md","https://github.com/omadahealth/SwipyRefreshLayoutblob/master/LICENSE"],"shortName":"MIT","name":"MIT License"},{"name":"SIL Open Font License, Version 1.1","urls":["http://scripts.sil.org/cms/scripts/page.php?item_id=OFL_web"],"shortName":"SIL Open Font License, Version 1.1"},{"shortName":"Unicode License","urls":["https://www.unicode.org/copyright.html#License","http://www.unicode.org/copyright.html#License"],"name":"Unicode, Inc. License"}]} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e221003f..27508ddf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -298,7 +298,7 @@ android:windowSoftInputMode="adjustResize|stateAlwaysHidden" /> diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActLanguageFilter.kt b/app/src/main/java/jp/juggler/subwaytooter/ActLanguageFilter.kt deleted file mode 100644 index 9005636d..00000000 --- a/app/src/main/java/jp/juggler/subwaytooter/ActLanguageFilter.kt +++ /dev/null @@ -1,478 +0,0 @@ -package jp.juggler.subwaytooter - -import android.annotation.SuppressLint -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.os.PersistableBundle -import android.os.Process -import android.text.Editable -import android.text.TextWatcher -import android.view.View -import android.view.ViewGroup -import android.widget.* -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.FileProvider -import jp.juggler.subwaytooter.api.entity.TootStatus -import jp.juggler.subwaytooter.column.Column -import jp.juggler.subwaytooter.databinding.ActLanguageFilterBinding -import jp.juggler.subwaytooter.dialog.actionsDialog -import jp.juggler.subwaytooter.pref.FILE_PROVIDER_AUTHORITY -import jp.juggler.util.* -import jp.juggler.util.coroutine.launchAndShowError -import jp.juggler.util.coroutine.launchProgress -import jp.juggler.util.data.* -import jp.juggler.util.log.LogCategory -import jp.juggler.util.log.showToast -import jp.juggler.util.ui.* -import org.jetbrains.anko.textColor -import java.io.File -import java.io.FileOutputStream -import java.util.* - -class ActLanguageFilter : AppCompatActivity(), View.OnClickListener { - - private class MyItem( - val code: String, - var allow: Boolean, - ) - - companion object { - - internal val log = LogCategory("ActLanguageFilter") - - internal const val EXTRA_COLUMN_INDEX = "column_index" - private const val STATE_LANGUAGE_LIST = "language_list" - - fun createIntent(activity: ActMain, idx: Int) = - Intent(activity, ActLanguageFilter::class.java).apply { - putExtra(EXTRA_COLUMN_INDEX, idx) - } - - private val languageComparator = Comparator { a, b -> - when { - a.code == TootStatus.LANGUAGE_CODE_DEFAULT -> -1 - b.code == TootStatus.LANGUAGE_CODE_DEFAULT -> 1 - a.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> -1 - b.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> 1 - else -> a.code.compareTo(b.code) - } - } - - private fun equalsLanguageList(a: JsonObject?, b: JsonObject?): Boolean { - fun JsonObject.encodeToString(): String { - val clone = this.toString().decodeJsonObject() - if (!clone.contains(TootStatus.LANGUAGE_CODE_DEFAULT)) { - clone[TootStatus.LANGUAGE_CODE_DEFAULT] = true - } - return clone.keys.sorted().joinToString(",") { "$it=${this[it]}" } - } - - val a_sign = (a ?: JsonObject()).encodeToString() - val b_sign = (b ?: JsonObject()).encodeToString() - return a_sign == b_sign - } - } - - private val languageNameMap by lazy { - HashMap().apply { - - // from https://github.com/google/cld3/blob/master/src/task_context_params.cc#L43 - val languageNamesCld3 = arrayOf( - "eo", "co", "eu", "ta", "de", "mt", "ps", "te", "su", "uz", "zh-Latn", "ne", - "nl", "sw", "sq", "hmn", "ja", "no", "mn", "so", "ko", "kk", "sl", "ig", - "mr", "th", "zu", "ml", "hr", "bs", "lo", "sd", "cy", "hy", "uk", "pt", - "lv", "iw", "cs", "vi", "jv", "be", "km", "mk", "tr", "fy", "am", "zh", - "da", "sv", "fi", "ht", "af", "la", "id", "fil", "sm", "ca", "el", "ka", - "sr", "it", "sk", "ru", "ru-Latn", "bg", "ny", "fa", "haw", "gl", "et", - "ms", "gd", "bg-Latn", "ha", "is", "ur", "mi", "hi", "bn", "hi-Latn", "fr", - "yi", "hu", "xh", "my", "tg", "ro", "ar", "lb", "el-Latn", "st", "ceb", - "kn", "az", "si", "ky", "mg", "en", "gu", "es", "pl", "ja-Latn", "ga", "lt", - "sn", "yo", "pa", "ku" - ) - - for (src1 in languageNamesCld3) { - val src2 = src1.replace("-Latn", "") - val isLatn = src2 != src1 - val locale = Locale(src2) - log.w("languageNameMap $src1 ${locale.language} ${locale.country} ${locale.displayName}") - put( - src1, if (isLatn) { - "${locale.displayName}(Latn)" - } else { - locale.displayName - } - ) - } - put(TootStatus.LANGUAGE_CODE_DEFAULT, getString(R.string.language_code_default)) - put(TootStatus.LANGUAGE_CODE_UNKNOWN, getString(R.string.language_code_unknown)) - } - } - - private fun getDesc(item: MyItem): String { - val code = item.code - return languageNameMap[code] ?: getString(R.string.custom) - } - - private var columnIndex: Int = 0 - internal lateinit var column: Column - internal lateinit var appState: AppState - internal var density: Float = 0f - - private val views by lazy { - ActLanguageFilterBinding.inflate(layoutInflater) - } - private lateinit var adapter: MyAdapter - private val languageList = ArrayList() - private var loadingBusy: Boolean = false - - private val arExport = ActivityResultHandler(log) { - } - - private val arImport = ActivityResultHandler(log) { r -> - if (r.isNotOk) return@ActivityResultHandler - r.data?.checkMimeTypeAndGrant(contentResolver) - ?.firstOrNull()?.uri?.let { import2(it) } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - backPressed { confirmBack() } - arExport.register(this) - arImport.register(this) - - App1.setActivityTheme(this) - initUI() - - appState = App1.getAppState(this) - density = appState.density - columnIndex = intent.int(EXTRA_COLUMN_INDEX) ?: 0 - column = appState.column(columnIndex)!! - - if (savedInstanceState != null) { - try { - val sv = savedInstanceState.getString(STATE_LANGUAGE_LIST, null) - if (sv != null) { - val list = sv.decodeJsonObject() - load(list) - return - } - } catch (ex: Throwable) { - log.e(ex, "restore failed.") - } - } - load(column.languageFilter) - } - - override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) { - super.onSaveInstanceState(outState, outPersistentState) - outState.putString(STATE_LANGUAGE_LIST, encodeLanguageList().toString()) - } - - private fun initUI() { - setContentView(views.root) - setSupportActionBar(views.toolbar) - setNavigationBack(views.toolbar) - fixHorizontalMargin(views.llContent) - - arrayOf( - views.btnAdd, - views.btnSave, - views.btnMore, - ).forEach { - it.setOnClickListener(this) - } - - adapter = MyAdapter() - views.listView.adapter = adapter - views.listView.onItemClickListener = adapter - } - - // UIのデータをJsonObjectにエンコード - private fun encodeLanguageList() = buildJsonObject { - for (item in languageList) { - put(item.code, item.allow) - } - } - - private fun load(src: JsonObject?) { - loadingBusy = true - try { - languageList.clear() - - if (src != null) { - for (key in src.keys) { - languageList.add(MyItem(key, src.boolean(key) ?: true)) - } - } - - if (languageList.none { it.code == TootStatus.LANGUAGE_CODE_DEFAULT }) { - languageList.add(MyItem(TootStatus.LANGUAGE_CODE_DEFAULT, true)) - } - - languageList.sortWith(languageComparator) - - adapter.notifyDataSetChanged() - } finally { - loadingBusy = false - } - } - - private fun save() { - column.languageFilter = encodeLanguageList() - } - - private inner class MyAdapter : BaseAdapter(), AdapterView.OnItemClickListener { - - override fun getCount(): Int = languageList.size - override fun getItemId(idx: Int): Long = 0L - override fun getItem(idx: Int): Any = languageList[idx] - - override fun getView(idx: Int, viewArg: View?, parent: ViewGroup?): View { - val tv = (viewArg ?: layoutInflater.inflate( - R.layout.lv_language_filter, - parent, - false - )) as TextView - val item = languageList[idx] - tv.text = - "${item.code} ${getDesc(item)} : ${getString(if (item.allow) R.string.language_show else R.string.language_hide)}" - tv.textColor = attrColor( - when (item.allow) { - true -> R.attr.colorTextContent - false -> R.attr.colorRegexFilterError - } - ) - return tv - } - - override fun onItemClick(parent: AdapterView<*>?, viewArg: View?, idx: Int, id: Long) { - if (idx in languageList.indices) edit(languageList[idx]) - } - } - - override fun onClick(v: View) { - when (v.id) { - R.id.btnSave -> { - save() - val data = Intent() - data.putExtra(EXTRA_COLUMN_INDEX, columnIndex) - setResult(RESULT_OK, data) - finish() - } - - R.id.btnAdd -> edit(null) - - R.id.btnMore -> { - launchAndShowError { - actionsDialog { - action(getString(R.string.clear_all)) { - languageList.clear() - languageList.add(MyItem(TootStatus.LANGUAGE_CODE_DEFAULT, true)) - adapter.notifyDataSetChanged() - } - action(getString(R.string.export)) { export() } - action(getString(R.string.import_)) { import() } - } - } - } - } - } - - private fun edit(myItem: MyItem?) = - DlgLanguageFilter.open(this, myItem, object : DlgLanguageFilter.Callback { - override fun onOK(code: String, allow: Boolean) { - val it = languageList.iterator() - while (it.hasNext()) { - val item = it.next() - if (item.code == code) { - item.allow = allow - adapter.notifyDataSetChanged() - return - } - } - languageList.add(MyItem(code, allow)) - languageList.sortWith(languageComparator) - adapter.notifyDataSetChanged() - return - } - - override fun onDelete(code: String) { - val it = languageList.iterator() - while (it.hasNext()) { - val item = it.next() - if (item.code == code) it.remove() - } - adapter.notifyDataSetChanged() - } - }) - - private object DlgLanguageFilter { - - interface Callback { - - fun onOK(code: String, allow: Boolean) - fun onDelete(code: String) - } - - @SuppressLint("InflateParams") - fun open(activity: ActLanguageFilter, item: MyItem?, callback: Callback) { - - val view = activity.layoutInflater.inflate(R.layout.dlg_language_filter, null, false) - - val etLanguage: EditText = view.findViewById(R.id.etLanguage) - val btnPresets: ImageButton = view.findViewById(R.id.btnPresets) - val tvLanguage: TextView = view.findViewById(R.id.tvLanguage) - - val rbShow: RadioButton = view.findViewById(R.id.rbShow) - val rbHide: RadioButton = view.findViewById(R.id.rbHide) - - when (item?.allow ?: true) { - true -> rbShow.isChecked = true - else -> rbHide.isChecked = true - } - - fun updateDesc() { - val code = etLanguage.text.toString().trim() - val desc = activity.languageNameMap[code] ?: activity.getString(R.string.custom) - tvLanguage.text = desc - } - - val languageList = - activity.languageNameMap.map { MyItem(it.key, true) }.sortedWith(languageComparator) - btnPresets.setOnClickListener { - activity.run { - launchAndShowError { - actionsDialog(getString(R.string.presets)) { - for (a in languageList) { - action("${a.code} ${activity.getDesc(a)}") { - etLanguage.setText(a.code) - updateDesc() - } - } - } - } - } - } - - etLanguage.setText(item?.code ?: "") - updateDesc() - - etLanguage.addTextChangedListener(object : TextWatcher { - override fun afterTextChanged(p0: Editable?) { - updateDesc() - } - - override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { - } - - override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { - } - }) - if (item != null) { - etLanguage.isEnabledAlpha = false - btnPresets.setEnabledColor( - activity, - R.drawable.ic_edit, - activity.attrColor(R.attr.colorTextContent), - false - ) - } - - val builder = AlertDialog.Builder(activity) - .setView(view) - .setCancelable(true) - .setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok) { _, _ -> - callback.onOK(etLanguage.text.toString().trim(), rbShow.isChecked) - } - - if (item != null && item.code != TootStatus.LANGUAGE_CODE_DEFAULT) { - builder.setNeutralButton(R.string.delete) { _, _ -> - callback.onDelete(etLanguage.text.toString().trim()) - } - } - - builder.show() - } - } - - @Suppress("BlockingMethodInNonBlockingContext") - private fun export() { - launchProgress( - "export language filter", - doInBackground = { - val data = JsonObject().apply { - for (item in languageList) { - put(item.code, item.allow) - } - } - .toString() - .encodeUTF8() - - val cacheDir = this@ActLanguageFilter.cacheDir - cacheDir.mkdir() - - val file = File( - cacheDir, - "SubwayTooter-language-filter.${Process.myPid()}.${Process.myTid()}.json" - ) - FileOutputStream(file).use { - it.write(data) - } - file - }, - afterProc = { - val uri = FileProvider.getUriForFile( - this@ActLanguageFilter, - FILE_PROVIDER_AUTHORITY, - it - ) - val intent = Intent(Intent.ACTION_SEND) - intent.type = contentResolver.getType(uri) - intent.putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter language filter data") - intent.putExtra(Intent.EXTRA_STREAM, uri) - - intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION) - - arExport.launch(intent) - } - ) - } - - private fun import() { - arImport.launch(intentOpenDocument("*/*")) - } - - @Suppress("BlockingMethodInNonBlockingContext") - private fun import2(uri: Uri) { - launchProgress( - "import language filter", - doInBackground = { - log.d("import2 type=${contentResolver.getType(uri)}") - try { - contentResolver.openInputStream(uri)!!.use { - it.readBytes().decodeUTF8().decodeJsonObject() - } - } catch (ex: Throwable) { - showToast(ex, "openInputStream failed.") - null - } - }, - afterProc = { load(it) } - ) - } - - private fun confirmBack() { - if (equalsLanguageList(column.languageFilter, encodeLanguageList())) { - finish() - } else { - AlertDialog.Builder(this) - .setMessage(R.string.language_filter_quit_waring) - .setPositiveButton(R.string.ok) { _, _ -> finish() } - .setNegativeButton(R.string.cancel, null) - .show() - } - } -} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt index 2f2cda48..4ee79606 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/ActMain.kt @@ -90,6 +90,7 @@ import jp.juggler.subwaytooter.pref.PrefS import jp.juggler.subwaytooter.span.MyClickableSpan import jp.juggler.subwaytooter.span.MyClickableSpanHandler import jp.juggler.subwaytooter.table.daoSavedAccount +import jp.juggler.subwaytooter.ui.languageFilter.LanguageFilterActivity import jp.juggler.subwaytooter.util.DecodeOptions.Companion.reloadEmojiScale import jp.juggler.subwaytooter.util.EmojiDecoder import jp.juggler.subwaytooter.util.openBrowser @@ -309,11 +310,10 @@ class ActMain : AppCompatActivity(), } val arLanguageFilter = ActivityResultHandler(log) { r -> - if (r.isNotOk) return@ActivityResultHandler - appState.saveColumnList() - r.data?.int(ActLanguageFilter.EXTRA_COLUMN_INDEX) - ?.let { appState.column(it) } - ?.onLanguageFilterChanged() + LanguageFilterActivity.decodeResult(r)?.let { columnIndex -> + appState.saveColumnList() + appState.column(columnIndex) ?.onLanguageFilterChanged() + } } val arNickname = ActivityResultHandler(log) { r -> diff --git a/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ColumnViewHolderActions.kt b/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ColumnViewHolderActions.kt index 9bcac183..044ce7d3 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ColumnViewHolderActions.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/columnviewholder/ColumnViewHolderActions.kt @@ -3,7 +3,6 @@ package jp.juggler.subwaytooter.columnviewholder import android.view.View import android.widget.CompoundButton import jp.juggler.subwaytooter.ActColumnCustomize -import jp.juggler.subwaytooter.ActLanguageFilter import jp.juggler.subwaytooter.App1 import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.action.accountResendConfirmMail @@ -12,7 +11,13 @@ import jp.juggler.subwaytooter.action.notificationDeleteAll import jp.juggler.subwaytooter.actmain.closeColumn import jp.juggler.subwaytooter.actmain.closeColumnAll import jp.juggler.subwaytooter.api.entity.TootAnnouncement -import jp.juggler.subwaytooter.column.* +import jp.juggler.subwaytooter.column.Column +import jp.juggler.subwaytooter.column.ColumnType +import jp.juggler.subwaytooter.column.addColumnViewHolder +import jp.juggler.subwaytooter.column.fireShowContent +import jp.juggler.subwaytooter.column.isSearchColumn +import jp.juggler.subwaytooter.column.startLoading +import jp.juggler.subwaytooter.ui.languageFilter.LanguageFilterActivity.Companion.openLanguageFilterActivity import jp.juggler.util.log.showToast import jp.juggler.util.log.withCaption import jp.juggler.util.ui.hideKeyboard @@ -252,9 +257,9 @@ fun ColumnViewHolder.onClickImpl(v: View?) { btnLanguageFilter -> activity.appState.columnIndex(column)?.let { colIdx -> - - activity.arLanguageFilter.launch( - ActLanguageFilter.createIntent(activity, colIdx) + openLanguageFilterActivity( + activity.arLanguageFilter, + colIdx ) } diff --git a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.kt b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.kt index 4199b74f..84eaf721 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/dialog/DlgConfirm.kt @@ -1,12 +1,12 @@ package jp.juggler.subwaytooter.dialog import android.annotation.SuppressLint +import android.app.Activity import android.text.method.LinkMovementMethod import android.text.util.Linkify import android.view.View import androidx.annotation.StringRes import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity import jp.juggler.subwaytooter.R import jp.juggler.subwaytooter.databinding.DlgConfirmBinding import jp.juggler.util.ui.dismissSafe @@ -16,57 +16,8 @@ import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException object DlgConfirm { - -// interface Callback { -// var isConfirmEnabled: Boolean -// -// fun onOK() -// } - -// @SuppressLint("InflateParams") -// fun open(activity: Activity, message: String, callback: Callback): Dialog { -// -// if (!callback.isConfirmEnabled) { -// callback.onOK() -// return -// } -// -// val view = activity.layoutInflater.inflate(R.layout.dlg_confirm, null, false) -// val tvMessage = view.findViewById(R.id.tvMessage) -// val cbSkipNext = view.findViewById(R.id.cbSkipNext) -// tvMessage.text = message -// -// AlertDialog.Builder(activity) -// .setView(view) -// .setCancelable(true) -// .setNegativeButton(R.string.cancel, null) -// .setPositiveButton(R.string.ok) { _, _ -> -// if (cbSkipNext.isChecked) { -// callback.isConfirmEnabled = false -// } -// callback.onOK() -// } -// .show() -// } - -// @SuppressLint("InflateParams") -// fun openSimple(activity: Activity, message: String, callback: () -> Unit) { -// val view = activity.layoutInflater.inflate(R.layout.dlg_confirm, null, false) -// val tvMessage = view.findViewById(R.id.tvMessage) -// val cbSkipNext = view.findViewById(R.id.cbSkipNext) -// tvMessage.text = message -// cbSkipNext.visibility = View.GONE -// -// AlertDialog.Builder(activity) -// .setView(view) -// .setCancelable(true) -// .setNegativeButton(R.string.cancel, null) -// .setPositiveButton(R.string.ok) { _, _ -> callback() } -// .show() -// } - @SuppressLint("InflateParams") - suspend inline fun AppCompatActivity.confirm( + suspend inline fun Activity.confirm( message: String, isConfirmEnabled: Boolean, setConfirmEnabled: (newConfirmEnabled: Boolean) -> Unit, @@ -94,10 +45,10 @@ object DlgConfirm { if (skipNext) setConfirmEnabled(false) } - suspend fun AppCompatActivity.confirm(@StringRes messageId: Int, vararg args: Any?) = + suspend fun Activity.confirm(@StringRes messageId: Int, vararg args: Any?) = confirm(getString(messageId, *args)) - suspend fun AppCompatActivity.confirm(message: CharSequence, title: CharSequence? = null) { + suspend fun Activity.confirm(message: CharSequence, title: CharSequence? = null) { suspendCancellableCoroutine { cont -> try { val views = DlgConfirmBinding.inflate(layoutInflater) @@ -124,10 +75,10 @@ object DlgConfirm { } } - suspend fun AppCompatActivity.okDialog(@StringRes messageId: Int, vararg args: Any?) = + suspend fun Activity.okDialog(@StringRes messageId: Int, vararg args: Any?) = okDialog(getString(messageId, *args)) - suspend fun AppCompatActivity.okDialog(message: CharSequence, title: CharSequence? = null) { + suspend fun Activity.okDialog(message: CharSequence, title: CharSequence? = null) { suspendCancellableCoroutine { cont -> try { val views = DlgConfirmBinding.inflate(layoutInflater) diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterActivity.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterActivity.kt new file mode 100644 index 00000000..aef7b6da --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterActivity.kt @@ -0,0 +1,452 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import android.app.Application +import android.content.Intent +import android.os.Bundle +import android.os.PersistableBundle +import android.view.Window +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.result.ActivityResult +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredHeightIn +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.outlined.ArrowBack +import androidx.compose.material.icons.outlined.Add +import androidx.compose.material.icons.outlined.MoreVert +import androidx.compose.material.icons.outlined.Save +import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.core.content.FileProvider +import jp.juggler.subwaytooter.App1 +import jp.juggler.subwaytooter.R +import jp.juggler.subwaytooter.api.entity.TootStatus +import jp.juggler.subwaytooter.dialog.DlgConfirm.confirm +import jp.juggler.subwaytooter.dialog.actionsDialog +import jp.juggler.subwaytooter.pref.FILE_PROVIDER_AUTHORITY +import jp.juggler.subwaytooter.util.StColorScheme +import jp.juggler.subwaytooter.util.collectOnLifeCycle +import jp.juggler.subwaytooter.util.dummyStColorTheme +import jp.juggler.subwaytooter.util.fireBackPressed +import jp.juggler.subwaytooter.util.getStColorTheme +import jp.juggler.subwaytooter.util.provideViewModel +import jp.juggler.util.backPressed +import jp.juggler.util.coroutine.launchAndShowError +import jp.juggler.util.data.checkMimeTypeAndGrant +import jp.juggler.util.data.intentOpenDocument +import jp.juggler.util.int +import jp.juggler.util.log.LogCategory +import jp.juggler.util.log.showError +import jp.juggler.util.ui.ActivityResultHandler +import jp.juggler.util.ui.isNotOk +import jp.juggler.util.ui.isOk +import jp.juggler.util.ui.launch +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class LanguageFilterActivity : ComponentActivity() { + + companion object { + private val log = LogCategory("LanguageFilterActivity") + + fun openLanguageFilterActivity( + launcher: ActivityResultHandler, + columnIndex: Int, + ) { + Intent( + launcher.context + ?: error("openLanguageFilterActivity: launcher is not registered."), + LanguageFilterActivity::class.java + ).apply { + putExtra(LanguageFilterViewModel.EXTRA_COLUMN_INDEX, columnIndex) + }.launch(launcher) + } + + fun decodeResult(r: ActivityResult): Int? = + when { + r.isOk -> r.data?.int(LanguageFilterViewModel.EXTRA_COLUMN_INDEX) + else -> null + } + } + + private val viewModel by lazy { + provideViewModel(this) { + LanguageFilterViewModel(application) + } + } + + private val stColorScheme by lazy { + getStColorTheme() + } + + private val arImport = ActivityResultHandler(log) { r -> + if (r.isNotOk) return@ActivityResultHandler + r.data?.checkMimeTypeAndGrant(contentResolver) + ?.firstOrNull()?.uri?.let { + viewModel.import2(it) + } + } + + override fun onSaveInstanceState(outState: Bundle, outPersistentState: PersistableBundle) { + super.onSaveInstanceState(outState, outPersistentState) + viewModel.saveState(outState) + } + + override fun onCreate(savedInstanceState: Bundle?) { + arImport.register(this) + super.onCreate(savedInstanceState) + App1.setActivityTheme(this) + + backPressed { + launchAndShowError { + if (viewModel.isLanguageListChanged()) { + confirm(R.string.language_filter_quit_waring) + } + finish() + } + } + + viewModel.restoreOrInitialize( + this, + savedInstanceState, + intent, + ) + + // ステータスバーの色にattr色を使っているので、テーマの指定は必要 + requestWindowFeature(Window.FEATURE_NO_TITLE) + App1.setActivityTheme(this) + val stColorScheme = getStColorTheme() + setContent { + Screen( + viewModel = viewModel, + stColorScheme = stColorScheme, + languageListFlow = viewModel.languageList, + progressMessageFlow = viewModel.progressMessage, + saveAction = { + setResult(RESULT_OK, viewModel.save()) + finish() + }, + getDisplayName = { langDesc(it, viewModel.languageNameMap) }, + ) + } + collectOnLifeCycle(viewModel.error) { + it ?: return@collectOnLifeCycle + showError(it) + } + } + + private suspend fun edit(myItem: LanguageFilterItem?) { + val result = dialogLanguageFilterEdit( + myItem, + viewModel.languageNameMap, + stColorScheme, + ) + viewModel.handleEditResult(result) + } + + /** + * 言語フィルタのエクスポート + * - 現在のデータをjsonエンコードする + * - 保存先アプリに渡す + * 保存自体はすぐ終わるのでプログレス表示やFlow経由の結果受取はない + */ + suspend fun export() { + val file = withContext(Dispatchers.IO) { + viewModel.createExportCacheFile() + } + val uri = FileProvider.getUriForFile( + this@LanguageFilterActivity, + FILE_PROVIDER_AUTHORITY, + file, + ) + val intent = Intent(Intent.ACTION_SEND).apply { + type = contentResolver.getType(uri) + putExtra(Intent.EXTRA_SUBJECT, "SubwayTooter language filter data") + putExtra(Intent.EXTRA_STREAM, uri) + addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + startActivity(intent) + } + + @Preview + @Composable + fun DefaultPreview() { + Screen( + viewModel = LanguageFilterViewModel(Application()), + stColorScheme = dummyStColorTheme(), + languageListFlow = MutableStateFlow( + listOf( + LanguageFilterItem( + code = TootStatus.LANGUAGE_CODE_DEFAULT, + allow = true, + ), + LanguageFilterItem( + code = TootStatus.LANGUAGE_CODE_UNKNOWN, + allow = false, + ), + LanguageFilterItem( + code = "xxx", + allow = true, + ), + ) + ), + progressMessageFlow = MutableStateFlow( + StringResAndArgs(R.string.wait_previous_operation) + ), + saveAction = {}, + getDisplayName = { "言語の名前" }, + ) + } + + @OptIn(ExperimentalMaterial3Api::class) + @Composable + fun Screen( + viewModel: LanguageFilterViewModel, + stColorScheme: StColorScheme, + languageListFlow: StateFlow>, + progressMessageFlow: StateFlow, + saveAction: () -> Unit, + getDisplayName: (String) -> String, + ) { + val scope = rememberCoroutineScope() + val snackbarHostState = remember { SnackbarHostState() } + val progressMessageState = progressMessageFlow.collectAsState() + MaterialTheme(colorScheme = stColorScheme.materialColorScheme) { + CompositionLocalProvider(LocalLayoutDirection provides LayoutDirection.Ltr) { + Scaffold( + snackbarHost = { + SnackbarHost(hostState = snackbarHostState) + }, + topBar = { + TopAppBar( + colors = TopAppBarDefaults.topAppBarColors(), + title = { + Text(stringResource(R.string.language_filter)) + }, + navigationIcon = { + IconButton( + onClick = { + fireBackPressed() + } + ) { + Icon( + // imageVector = AutoMirrored.Outlined.ArrowBack, + imageVector = Icons.AutoMirrored.Outlined.ArrowBack, + contentDescription = stringResource(R.string.close) + ) + } + }, + actions = { + IconButton( + onClick = { + scope.launch { + try { + edit(null) + } catch (ex: Throwable) { + showError(ex) + } + } + }, + ) { + Icon( + Icons.Outlined.Add, + contentDescription = stringResource(R.string.add), + ) + } + IconButton( + onClick = { saveAction() } + ) { + Icon( + imageVector = Icons.Outlined.Save, + contentDescription = stringResource(R.string.close) + ) + } + IconButton( + onClick = { + scope.launch { + try { + actionsDialog { + action(getString(R.string.clear_all)) { + viewModel.clearAllLanguage() + } + action(getString(R.string.export)) { + scope.launch { + try { + export() + } catch (ex: Throwable) { + showError(ex) + } + } + } + action(getString(R.string.import_)) { + arImport.launch(intentOpenDocument("*/*")) + } + } + } catch (ex: Throwable) { + showError(ex) + } + } + }, + ) { + Icon( + Icons.Outlined.MoreVert, + contentDescription = stringResource(R.string.more), + ) + } + } + ) + }, + ) { innerPadding -> + ScrollContent( + scope = scope, + innerPadding = innerPadding, + languageListFlow = languageListFlow, + getDisplayName = getDisplayName, + stColorScheme = stColorScheme, + ) + val progressMessage = progressMessageState.value?.let { + stringResource(it.stringId, *it.args) + } + if (progressMessage != null) { + ProgressCircleAndText(stColorScheme, progressMessage) + } + } + } + } + } + + @Composable + fun ProgressCircleAndText( + stColorScheme: StColorScheme, + progressMessage: String, + ) { + Column( + modifier = Modifier.fillMaxSize().clickable { + // 奥の要素をクリックできなくする + }.background( + color = stColorScheme.colorProgressBackground, + ), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + CircularProgressIndicator( + modifier = Modifier.size(160.dp), + ) + Spacer(modifier = Modifier.size(20.dp)) + Text(progressMessage) + } + } + + @Composable + fun ScrollContent( + stColorScheme: StColorScheme, + scope: CoroutineScope, + innerPadding: PaddingValues, + languageListFlow: StateFlow>, + getDisplayName: (String) -> String, + ) { + val stateLanguageList = languageListFlow.collectAsState() + LazyColumn( + modifier = Modifier.padding(innerPadding).fillMaxSize(), + ) { + items(stateLanguageList.value) { + LanguageItemCard( + it, + scope, + getDisplayName, + ) + HorizontalDivider( + color = stColorScheme.colorDivider, + thickness = 1.dp + ) + } + } + } + + @Composable + fun LanguageItemCard( + item: LanguageFilterItem, + scope: CoroutineScope, + getDisplayName: (String) -> String, + ) { + Row( + modifier = Modifier.fillMaxWidth() +// .requiredHeightIn(min = 48.dp) + .clickable { + scope.launch { + try { + edit(item) + } catch (ex: Throwable) { + showError(ex) + } + } + }, + ) { + Text( + modifier = Modifier + .requiredHeightIn(min = 56.dp) + .wrapContentHeight() + .padding( + horizontal = 12.dp, + vertical = 6.dp, + ), + + text = "${ + item.code + } ${ + getDisplayName(item.code) + } : ${ + stringResource( + when { + item.allow -> R.string.language_show + else -> R.string.language_hide + } + ) + }", + color = when (item.allow) { + true -> MaterialTheme.colorScheme.onBackground + false -> MaterialTheme.colorScheme.error + } + ) + } + } +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterEditDialog.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterEditDialog.kt new file mode 100644 index 00000000..b093ce47 --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterEditDialog.kt @@ -0,0 +1,99 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import androidx.activity.ComponentActivity +import androidx.appcompat.app.AlertDialog +import androidx.compose.ui.graphics.toArgb +import androidx.core.widget.addTextChangedListener +import jp.juggler.subwaytooter.R +import jp.juggler.subwaytooter.api.entity.TootStatus +import jp.juggler.subwaytooter.databinding.DlgLanguageFilterBinding +import jp.juggler.subwaytooter.dialog.actionsDialog +import jp.juggler.subwaytooter.util.StColorScheme +import jp.juggler.util.coroutine.launchAndShowError +import jp.juggler.util.ui.dismissSafe +import jp.juggler.util.ui.isEnabledAlpha +import jp.juggler.util.ui.setEnabledColor +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlin.coroutines.resumeWithException + +sealed interface LanguageFilterEditResult { + class Update(val code: String, val allow: Boolean) : LanguageFilterEditResult + class Delete(val code: String) : LanguageFilterEditResult +} + +/** + * 言語コード1つを追加/編集/削除するダイアログ + */ +suspend fun ComponentActivity.dialogLanguageFilterEdit( + // 既存項目の編集時は非null + item: LanguageFilterItem?, + // 言語コード→表示名のマップ + nameMap: Map, + // 色スキーマ + stColorScheme: StColorScheme, +): LanguageFilterEditResult = suspendCancellableCoroutine { cont -> + val views = DlgLanguageFilterBinding.inflate(layoutInflater, null, false) + + views.apply { + fun updateDesc() { + val code = etLanguage.text.toString().trim() + tvLanguage.text = nameMap[code]?.displayName ?: getString(R.string.custom) + } + when (item?.allow ?: true) { + true -> rbShow.isChecked = true + else -> rbHide.isChecked = true + } + btnPresets.setOnClickListener { + launchAndShowError { + actionsDialog(getString(R.string.presets)) { + val languageList = nameMap.map { + LanguageFilterItem(it.key, true) + }.sortedWith(languageFilterItemComparator) + for (a in languageList) { + action("${a.code} ${langDesc(a.code, nameMap)}") { + etLanguage.setText(a.code) + updateDesc() + } + } + } + } + } + etLanguage.addTextChangedListener { updateDesc() } + etLanguage.setText(item?.code ?: "") + updateDesc() + // 編集時は言語コードを変更できない + etLanguage.isEnabledAlpha = item == null + btnPresets.setEnabledColor( + btnPresets.context, + R.drawable.ic_edit, + stColorScheme.colorTextContent.toArgb(), + item == null + ) + fun getCode() = etLanguage.text.toString().trim() + fun isAllow() = rbShow.isChecked + AlertDialog.Builder(this@dialogLanguageFilterEdit).apply { + setView(views.root) + setCancelable(true) + setNegativeButton(R.string.cancel, null) + setPositiveButton(R.string.ok) { _, _ -> + if (cont.isActive) cont.resume( + LanguageFilterEditResult.Update(getCode(), isAllow()) + ) {} + } + if (item != null && item.code != TootStatus.LANGUAGE_CODE_DEFAULT) { + setNeutralButton(R.string.delete) { _, _ -> + if (cont.isActive) cont.resume( + LanguageFilterEditResult.Delete(item.code) + ) {} + } + } + }.create().also { dialog -> + dialog.setOnDismissListener { + if (cont.isActive) cont.resumeWithException(CancellationException()) + } + cont.invokeOnCancellation { dialog.dismissSafe() } + dialog.show() + } + } +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterItem.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterItem.kt new file mode 100644 index 00000000..11778e10 --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterItem.kt @@ -0,0 +1,18 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import jp.juggler.subwaytooter.api.entity.TootStatus + +data class LanguageFilterItem( + val code: String, + var allow: Boolean, +) + +val languageFilterItemComparator = Comparator { a, b -> + when { + a.code == TootStatus.LANGUAGE_CODE_DEFAULT -> -1 + b.code == TootStatus.LANGUAGE_CODE_DEFAULT -> 1 + a.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> -1 + b.code == TootStatus.LANGUAGE_CODE_UNKNOWN -> 1 + else -> a.code.compareTo(b.code) + } +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterViewModel.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterViewModel.kt new file mode 100644 index 00000000..5fdd9d43 --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageFilterViewModel.kt @@ -0,0 +1,258 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import android.app.Application +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.os.Process +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.viewModelScope +import jp.juggler.subwaytooter.App1 +import jp.juggler.subwaytooter.AppState +import jp.juggler.subwaytooter.R +import jp.juggler.subwaytooter.api.entity.TootStatus +import jp.juggler.subwaytooter.column.Column +import jp.juggler.util.data.JsonObject +import jp.juggler.util.data.buildJsonObject +import jp.juggler.util.data.decodeJsonObject +import jp.juggler.util.data.decodeUTF8 +import jp.juggler.util.data.encodeUTF8 +import jp.juggler.util.int +import jp.juggler.util.log.LogCategory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import java.io.File +import java.io.FileOutputStream + +class LanguageFilterViewModel( + application: Application, +) : AndroidViewModel(application) { + companion object { + private val log = LogCategory("LanguageFilterViewModel") + private const val STATE_LANGUAGE_LIST = "language_list" + const val EXTRA_COLUMN_INDEX = "column_index" + } + + private var mastodonLanguageJsonCache: String? = null + + private val context: Context + get() = getApplication() + + lateinit var appState: AppState + + private var columnIndex: Int = 0 + + private lateinit var column: Column + + // 編集中の言語リスト + private val _languageList = MutableStateFlow>(emptyList()) + val languageList = _languageList.asStateFlow() + + // 言語コードと名前の対応表 + var languageNameMap: Map = emptyMap() + + // エラーイベント + private val _error = Channel(capacity = Channel.CONFLATED) + val error = _error.receiveAsFlow() + + // ロード中表示の文字列 + private val _progressMessage = MutableStateFlow(null) + val progressMessage = _progressMessage.asStateFlow() + + fun saveState(outState: Bundle) { + outState.putString(STATE_LANGUAGE_LIST, encodeLanguageList().toString()) + } + + fun restoreOrInitialize( + activityContext: Context, + savedInstanceState: Bundle?, + intent: Intent?, + ) { + appState = App1.getAppState(context) + columnIndex = intent?.int(EXTRA_COLUMN_INDEX) ?: 0 + column = appState.column(columnIndex) ?: error("missing column[$columnIndex]") + viewModelScope.launch { + try { + if (mastodonLanguageJsonCache == null) { + _progressMessage.value = StringResAndArgs(R.string.language_filter_loading) + mastodonLanguageJsonCache = try { + val accessInfo = column.accessInfo + if (accessInfo.isNA) { + "na" + } else if (accessInfo.isPseudo) { + loadMastodonLanguages(accessInfo.apiHost) + } else { + loadMastodonLanguages(accessInfo.apiHost, accessInfo.bearerAccessToken) + } + } catch (ex: Throwable) { + "error" + } + } + // 端末のconfiguration changeがありうるので、言語マップはActivityのonCreateのたびに再取得する + languageNameMap = withContext(Dispatchers.IO) { + getLanguageNames(context, mastodonLanguageJsonCache).apply { + val specDefault = LanguageInfo( + code = TootStatus.LANGUAGE_CODE_DEFAULT, + name = TootStatus.LANGUAGE_CODE_DEFAULT, + displayName = activityContext.getString(R.string.language_code_default), + ) + val specUnknown = LanguageInfo( + code = TootStatus.LANGUAGE_CODE_UNKNOWN, + name = TootStatus.LANGUAGE_CODE_UNKNOWN, + displayName = activityContext.getString(R.string.language_code_unknown) + ) + put(specDefault.code, specDefault) + put(specUnknown.code, specUnknown) + } + } + + // 状態の復元 + try { + savedInstanceState?.getString(STATE_LANGUAGE_LIST, null) + ?.decodeJsonObject() + ?.let { load(it) } + } catch (ex: Throwable) { + log.e(ex, "restore failed.") + } + // 未初期化なら初期データのロード + if (languageList.value.isEmpty()) { + load(column.languageFilter) + } + } catch (ex: Throwable) { + _error.send(ex) + } finally { + _progressMessage.value = null + } + } + } + + private fun load(src: JsonObject?) { + _languageList.value = buildList { + if (src != null) { + for (key in src.keys) { + add(LanguageFilterItem(key, src.boolean(key) ?: true)) + } + } + if (none { it.code == TootStatus.LANGUAGE_CODE_DEFAULT }) { + add(LanguageFilterItem(TootStatus.LANGUAGE_CODE_DEFAULT, true)) + } + log.i("load: list size=$size") + }.sortedWith(languageFilterItemComparator) + } + + fun createExportCacheFile(): File { + val bytes = JsonObject().apply { + for (item in _languageList.value) { + put(item.code, item.allow) + } + }.toString().encodeUTF8() + + val cacheDir = context.cacheDir + cacheDir.mkdirs() + val file = File( + cacheDir, + "SubwayTooter-language-filter.${Process.myPid()}.${Process.myTid()}.json" + ) + FileOutputStream(file).use { + it.write(bytes) + } + return file + } + + @Suppress("BlockingMethodInNonBlockingContext") + fun import2(uri: Uri) { + viewModelScope.launch { + try { + _progressMessage.value = StringResAndArgs(R.string.language_filter_importing) + val jsonObject = withContext(Dispatchers.IO) { + val resolver = context.contentResolver + log.i("import2 type=${resolver.getType(uri)}") + (resolver.openInputStream(uri) ?: error("openInputStream returns null")) + .use { + it.readBytes().decodeUTF8().decodeJsonObject() + } + } + load(jsonObject) + } catch (ex: Throwable) { + log.e(ex, "import2 failed.") + _error.send(ex) + } finally { + _progressMessage.value = null + } + } + } + + fun save(): Intent { + column.languageFilter = encodeLanguageList() + return Intent().apply { + putExtra(EXTRA_COLUMN_INDEX, columnIndex) + } + } + + // UIのデータをJsonObjectにエンコード + private fun encodeLanguageList() = buildJsonObject { + for (item in languageList.value) { + put(item.code, item.allow) + } + } + + fun isLanguageListChanged(): Boolean { + fun JsonObject.encodeSorted(): String { + val clone = this.toString().decodeJsonObject() + if (!clone.contains(TootStatus.LANGUAGE_CODE_DEFAULT)) { + clone[TootStatus.LANGUAGE_CODE_DEFAULT] = true + } + return clone.keys.sorted().joinToString(",") { "$it=${this[it]}" } + } + + val current = (encodeLanguageList()).encodeSorted() + val initial = (column.languageFilter ?: JsonObject()).encodeSorted() + return current != initial + } + + fun handleEditResult(result: LanguageFilterEditResult) { + _languageList.value = when (result) { + is LanguageFilterEditResult.Delete -> + _languageList.value.filter { it.code != result.code } + + is LanguageFilterEditResult.Update -> when ( + val item = languageList.value.find { it.code == result.code } + ) { + null -> (_languageList.value + listOf( + LanguageFilterItem( + result.code, + result.allow + ) + )) + .sortedWith(languageFilterItemComparator) + + else -> { + item.allow = result.allow + _languageList.value + } + } + } + } + + // 言語フィルタを初期状態に戻す + fun clearAllLanguage() { + viewModelScope.launch { + try { + _languageList.value = listOf( + LanguageFilterItem(TootStatus.LANGUAGE_CODE_DEFAULT, true) + ) + } catch (ex: Throwable) { + log.e(ex, "clearAllLanguage failed.") + _error.send(ex) + } finally { + _progressMessage.value = null + } + } + } +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageInfo.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageInfo.kt new file mode 100644 index 00000000..462539dc --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/LanguageInfo.kt @@ -0,0 +1,142 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import android.content.Context +import jp.juggler.subwaytooter.App1 +import jp.juggler.subwaytooter.R +import jp.juggler.subwaytooter.api.entity.Host +import jp.juggler.util.data.decodeJsonArray +import jp.juggler.util.data.loadRawResource +import jp.juggler.util.data.notBlank +import jp.juggler.util.log.LogCategory +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okhttp3.Request +import ru.gildor.coroutines.okhttp.await +import java.util.Locale + +private val log = LogCategory("GetLanguageNames") + +data class LanguageInfo( + // code,name from https://mastodon.social/api/v1/instance/languages + val code: String, + val name: String, + // displayName from locale + var displayName: String = "", +) { + val locales = HashSet() +} + +fun Context.langDesc(code: String, nameMap: Map) = + nameMap[code]?.displayName ?: getString(R.string.custom) + +suspend fun loadMastodonLanguages( + apiHost: Host, + accessToken: String? = null, +) = withContext(Dispatchers.IO) { + val request = Request.Builder().apply { + url("https://${apiHost.ascii}/api/v1/instance/languages") + get() + accessToken?.notBlank()?.let { + header("Authorization", "Bearer $it") + } + }.build() + val response = App1.ok_http_client.newCall(request).await() + if (!response.isSuccessful) error("HTTP ${response.code}") + response.body.string() +} + +private val languageStringIds = buildMap { + put("cnd", R.string.language_name_montenegrin) +} + +fun mergeLanguageName( + context: Context, + jsonString: String, +) = HashMap().also { dst -> + // read from mastodon languages + for (it in jsonString.decodeJsonArray().objectList()) { + val code = it.string("code")?.notBlank() ?: error("missing item.code") + val name = it.string("name")?.notBlank() ?: error("missing item.name") + dst[code] = LanguageInfo(code = code, name = name) + } + + // using Locale.forLanguageTag to find Java Locale + for (item in dst.values) { + val locale = Locale.forLanguageTag(item.code) + log.i("code=${item.code} locale=$locale lang=${locale.language} displayName=${locale.displayName}") + // 2018年に、ISO 639-2およびISO 639-3にモンテネグロ語の言語コード(cnr)が追加された + // Android Javaには定義がないが、この場合にdisplayNameは言語コードと同じ値になる + if (locale.displayName == item.code || locale.displayName.isNullOrBlank()) continue + item.locales.add(locale) + } + + // 今度はJavaのロケールを順に処理する + loop@ for (locale in Locale.getAvailableLocales().sortedBy { it.toLanguageTag() }) { + // 言語名が空やundはスキップ + if (locale.language.isEmpty() || locale.language == "und") continue + + // 既に対応するmastodon言語コードが判明している + if (dst.values.any { c -> c.locales.any { it == locale } }) continue + + // language名またはlanguage tagで検索 + for (code in arrayOf(locale.language, locale.toLanguageTag())) { + val item = dst.values.find { it.code.equals(code, ignoreCase = true) } + if (item != null) { + item.locales.add(locale) + continue@loop + } + } + // log.w("Java locale not match to mastodon lang list. ${locale.displayLanguage}(${locale.language}, ${locale.toLanguageTag()})") + } + + // 互換性があるなかで最も言語タグが短いロケールの表示名を使う + // fallback 1: 言語コード別の文字列リソースを参照する + // fallback 2: mastodon api のフォールバック用のname + // fallback 3: "?" + for (item in dst.values) { + val locale = item.locales.sortedBy { it.toLanguageTag() }.firstOrNull() + item.displayName = locale?.displayName?.notBlank() + ?: languageStringIds[item.code]?.let { context.getString(it) } + ?: item.name.notBlank() + ?: "?" + } + + return dst +} + +/** + * - Mastodonの言語リストをロードする。なければフォールバックのrawリソースを読む。 + * - 言語リストを + * 現在の表示言語にあう言語コード→名前マップを返す + */ +fun getLanguageNames( + context: Context, + jsonString: String?, +): HashMap { + if (jsonString?.contains("{") == true) { + try { + val map = mergeLanguageName( + context, + jsonString, + ) + if (map.isEmpty()) error("map is empty. (1)") + return map + } catch (ex: Throwable) { + log.e(ex, "loadMastodonLanguages failed.") + } + } + // fallback + try { + val map = mergeLanguageName( + context, + context.loadRawResource(R.raw.languages_fallback) + .decodeToString() + ) + if (map.isEmpty()) error("map is empty. (2)") + return map + } catch (ex: Throwable) { + log.e(ex, "loadRawResource failed.") + } + // error + return HashMap() +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/StringResAndArgs.kt b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/StringResAndArgs.kt new file mode 100644 index 00000000..a136d4f1 --- /dev/null +++ b/app/src/main/java/jp/juggler/subwaytooter/ui/languageFilter/StringResAndArgs.kt @@ -0,0 +1,20 @@ +package jp.juggler.subwaytooter.ui.languageFilter + +import android.content.Context +import androidx.annotation.StringRes + +class StringResAndArgs( + @StringRes val stringId: Int, + // composeのstringResource ではnullを受け付けなくなった + vararg val args: Any, +) { + fun toCharSequence(context: Context) = when { + args.isNotEmpty() -> context.getString(stringId, *args) + else -> context.getText(stringId) + } + + fun toString(context: Context) = when { + args.isNotEmpty() -> context.getString(stringId, *args) + else -> context.getString(stringId) + } +} diff --git a/app/src/main/java/jp/juggler/subwaytooter/util/ComposeUtils.kt b/app/src/main/java/jp/juggler/subwaytooter/util/ComposeUtils.kt index 6ed996fc..d7866015 100644 --- a/app/src/main/java/jp/juggler/subwaytooter/util/ComposeUtils.kt +++ b/app/src/main/java/jp/juggler/subwaytooter/util/ComposeUtils.kt @@ -2,6 +2,7 @@ package jp.juggler.subwaytooter.util import android.app.Activity import android.content.Context +import androidx.activity.ComponentActivity import androidx.compose.material3.ColorScheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme @@ -14,6 +15,10 @@ import jp.juggler.util.ui.resColor class StColorScheme( val materialColorScheme: ColorScheme, val colorTextLink: Color, + val colorTextContent: Color, + val colorTextError: Color, + val colorProgressBackground:Color, + val colorDivider: Color, ) fun Context.createStColorSchemeLight(): StColorScheme { @@ -33,13 +38,16 @@ fun Context.createStColorSchemeLight(): StColorScheme { secondary = colorTextLink, onSecondary = Color.White, - surface = Color(resColor(R.color.Light_colorColumnSettingBackground)), + surface = Color(resColor(R.color.Light_colorReplyBackground)), onSurface = colorTextContent, + onSurfaceVariant = colorTextContent, onTertiary = colorTextContent, - - onSurfaceVariant = Color(resColor(R.color.Light_colorTextHint)), ), colorTextLink = colorTextLink, + colorTextContent = colorTextContent, + colorTextError = colorTextError, + colorProgressBackground = Color(0xC0000000), + colorDivider = Color(resColor(R.color.Light_colorTextDivider)), ) } @@ -61,13 +69,16 @@ fun Context.createStColorSchemeDark(): StColorScheme { secondary = colorTextLink, onSecondary = colorTextContent, - surface = Color(resColor(R.color.Dark_colorColumnSettingBackground)), + surface = Color(resColor(R.color.Dark_colorColumnHeader)), onSurface = colorTextContent, + onSurfaceVariant = colorTextContent, onTertiary = colorTextContent, - - onSurfaceVariant = Color(resColor(R.color.Dark_colorTextHint)), ), colorTextLink = colorTextLink, + colorTextContent = colorTextContent, + colorTextError = colorTextError, + colorProgressBackground = Color(0xC0000000), + colorDivider = Color(resColor(R.color.Dark_colorSettingDivider)), ) } @@ -89,13 +100,16 @@ fun Context.createStColorSchemeMastodonDark(): StColorScheme { secondary = colorTextLink, onSecondary = colorTextContent, - surface = Color(resColor(R.color.Mastodon_colorColumnSettingBackground)), + surface = Color(resColor(R.color.Mastodon_colorColumnHeader)), onSurface = colorTextContent, + onSurfaceVariant = colorTextContent, onTertiary = colorTextContent, - - onSurfaceVariant = Color(resColor(R.color.Mastodon_colorTextHint)), ), colorTextLink = colorTextLink, + colorTextContent = colorTextContent, + colorTextError = colorTextError, + colorProgressBackground = Color(0xC0000000), + colorDivider = Color(resColor(R.color.Mastodon_colorSettingDivider)), ) } @@ -112,5 +126,12 @@ fun Activity.getStColorTheme(forceDark: Boolean = false): StColorScheme { fun dummyStColorTheme() = StColorScheme( materialColorScheme = darkColorScheme(), - colorTextLink = Color.Cyan, + colorTextContent = Color.White, + colorTextLink = Color(0xff0080ff), + colorTextError = Color.Red, + colorProgressBackground = Color(0x80808080), + colorDivider = Color(0x80808080), ) + +fun ComponentActivity.fireBackPressed() = + onBackPressedDispatcher.onBackPressed() diff --git a/app/src/main/res/layout/act_language_filter.xml b/app/src/main/res/layout/act_language_filter.xml deleted file mode 100644 index a7c7e33a..00000000 --- a/app/src/main/res/layout/act_language_filter.xml +++ /dev/null @@ -1,80 +0,0 @@ - - - - - - - - - - - - - -