From 0447d3072d5766c311805d63f6e6daa21d61299d Mon Sep 17 00:00:00 2001 From: MM20 <15646950+MM2-0@users.noreply.github.com> Date: Thu, 20 Jan 2022 22:40:32 +0100 Subject: [PATCH] Migrate from Glide to Coil --- app/build.gradle.kts | 4 +- .../de/mm20/launcher2/LauncherApplication.kt | 15 ++- .../launcher2/licenses/OpenSourceLicenses.kt | 7 -- base/src/main/res/raw/license_glide.txt | 94 ------------------- base/src/main/res/values/licenses.xml | 1 - settings.gradle.kts | 11 +-- ui/build.gradle.kts | 2 - .../ui/legacy/component/WebSearchView.kt | 34 ++++--- .../search/WebsiteDetailRepresentation.kt | 5 +- .../search/WebsiteListRepresentation.kt | 7 +- .../search/WikipediaDetailRepresentation.kt | 4 +- .../search/WikipediaListRepresentation.kt | 25 +++-- .../websearch/WebSearchSettingsScreenVM.kt | 19 ++-- ui/src/main/res/layout/view_website_list.xml | 1 - .../main/res/layout/view_wikipedia_list.xml | 3 +- websites/build.gradle.kts | 3 +- .../de/mm20/launcher2/search/data/Website.kt | 27 +++--- 17 files changed, 91 insertions(+), 171 deletions(-) delete mode 100644 base/src/main/res/raw/license_glide.txt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1db618bd..ed410de8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -101,8 +101,8 @@ dependencies { implementation(libs.androidx.work) implementation(libs.androidx.multidex) - implementation(libs.glide) - implementation(libs.glidetransformations) + implementation(libs.coil.core) + implementation(libs.coil.svg) implementation(libs.lottie.core) diff --git a/app/src/main/java/de/mm20/launcher2/LauncherApplication.kt b/app/src/main/java/de/mm20/launcher2/LauncherApplication.kt index 2701161b..ce31d172 100644 --- a/app/src/main/java/de/mm20/launcher2/LauncherApplication.kt +++ b/app/src/main/java/de/mm20/launcher2/LauncherApplication.kt @@ -2,6 +2,9 @@ package de.mm20.launcher2 import android.app.Application import androidx.appcompat.app.AppCompatDelegate +import coil.ImageLoader +import coil.ImageLoaderFactory +import coil.decode.SvgDecoder import de.mm20.launcher2.accounts.accountsModule import de.mm20.launcher2.applications.applicationsModule import de.mm20.launcher2.badges.badgesModule @@ -34,7 +37,7 @@ import org.koin.core.logger.Level import java.text.Collator import kotlin.coroutines.CoroutineContext -class LauncherApplication : Application(), CoroutineScope { +class LauncherApplication : Application(), CoroutineScope, ImageLoaderFactory { override val coroutineContext: CoroutineContext get() = Dispatchers.Main + SupervisorJob() @@ -85,6 +88,16 @@ class LauncherApplication : Application(), CoroutineScope { } } + override fun newImageLoader(): ImageLoader { + return ImageLoader.Builder(applicationContext) + .componentRegistry { + add(SvgDecoder(applicationContext)) + } + .crossfade(true) + .crossfade(200) + .build() + } + companion object { val collator: Collator by lazy { diff --git a/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt b/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt index 042e5b09..005cf157 100644 --- a/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt +++ b/base/src/main/java/de/mm20/launcher2/licenses/OpenSourceLicenses.kt @@ -77,13 +77,6 @@ val OpenSourceLicenses = arrayOf( copyrightNote = "Copyright (c) 2009-2021 Jonathan Hedley ", url = "https://jsoup.org/" ), - OpenSourceLibrary( - name = "Glide", - description = "A fast and efficient open source media management and image loading framework for Android", - licenseName = R.string.glide_license_name, - licenseText = R.raw.license_glide, - url = "https://bumptech.github.io/glide/" - ), OpenSourceLibrary( name = "Glide Transformations", description = "An Android transformation library providing a variety of image transformations for Glide", diff --git a/base/src/main/res/raw/license_glide.txt b/base/src/main/res/raw/license_glide.txt deleted file mode 100644 index 441c3743..00000000 --- a/base/src/main/res/raw/license_glide.txt +++ /dev/null @@ -1,94 +0,0 @@ -License for everything not in third_party and not otherwise marked: - -Copyright 2014 Google, Inc. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are -permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of - conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list - of conditions and the following disclaimer in the documentation and/or other materials - provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those of the -authors and should not be interpreted as representing official policies, either expressed -or implied, of Google, Inc. ---------------------------------------------------------------------------------------------- -License for third_party/disklrucache: - -Copyright 2012 Jake Wharton -Copyright 2011 The Android Open Source Project - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. ---------------------------------------------------------------------------------------------- -License for third_party/gif_decoder: - -Copyright (c) 2013 Xcellent Creations, Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------------------------- -License for third_party/gif_encoder/AnimatedGifEncoder.java and -third_party/gif_encoder/LZWEncoder.java: - -No copyright asserted on the source code of this class. May be used for any -purpose, however, refer to the Unisys LZW patent for restrictions on use of -the associated LZWEncoder class. Please forward any corrections to -kweiner@fmsware.com. - ------------------------------------------------------------------------------ -License for third_party/gif_encoder/NeuQuant.java - -Copyright (c) 1994 Anthony Dekker - -NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See -"Kohonen neural networks for optimal colour quantization" in "Network: -Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of -the algorithm. - -Any party obtaining a copy of these files from the author, directly or -indirectly, is granted, free of charge, a full and unrestricted irrevocable, -world-wide, paid up, royalty-free, nonexclusive right and license to deal in -this software and documentation files (the "Software"), including without -limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons who -receive copies from any such party to do so, with the only requirement being -that this copyright notice remain intact. \ No newline at end of file diff --git a/base/src/main/res/values/licenses.xml b/base/src/main/res/values/licenses.xml index 7c73fd6a..27842144 100644 --- a/base/src/main/res/values/licenses.xml +++ b/base/src/main/res/values/licenses.xml @@ -4,7 +4,6 @@ Simplified BSD license Modified BSD license Apache license 2.0 - Glide license GNU General Public License Version 3 SIL OPEN FONT LICENSE \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 790fc6e4..b1e8397f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -289,6 +289,9 @@ dependencyResolutionManagement { alias("coil.core") .to("io.coil-kt", "coil") .versionRef("coil") + alias("coil.svg") + .to("io.coil-kt", "coil-svg") + .versionRef("coil") alias("coil.compose") .to("io.coil-kt", "coil-compose") .versionRef("coil") @@ -309,14 +312,6 @@ dependencyResolutionManagement { .to("org.jsoup", "jsoup") .version("1.14.2") - alias("glide") - .to("com.github.bumptech.glide", "glide") - .version("4.12.0") - - alias("glidetransformations") - .to("jp.wasabeef", "glide-transformations") - .version("4.3.0") - version("materialdialogs", "3.3.0") alias("materialdialogs.core") .to("com.afollestad.material-dialogs", "core") diff --git a/ui/build.gradle.kts b/ui/build.gradle.kts index 0021a28d..24658508 100644 --- a/ui/build.gradle.kts +++ b/ui/build.gradle.kts @@ -74,10 +74,8 @@ dependencies { implementation(libs.materialcomponents.composethemeadapter3) implementation(libs.viewpropertyobjectanimator) - implementation(libs.glide) implementation(libs.draglinearlayout) implementation(libs.lottie.core) - implementation(libs.glidetransformations) implementation(libs.accompanist.insets) implementation(libs.accompanist.systemuicontroller) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/WebSearchView.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/WebSearchView.kt index 9a6c7546..e9c9fd20 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/WebSearchView.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/component/WebSearchView.kt @@ -12,16 +12,19 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import androidx.lifecycle.LiveData import androidx.lifecycle.Observer -import com.bumptech.glide.Glide -import com.bumptech.glide.request.target.SimpleTarget -import com.bumptech.glide.request.transition.Transition +import coil.imageLoader +import coil.request.ImageRequest +import coil.size.Scale import com.google.android.material.chip.Chip import de.mm20.launcher2.ktx.dp +import de.mm20.launcher2.ktx.lifecycleScope import de.mm20.launcher2.legacy.helper.ActivityStarter import de.mm20.launcher2.search.data.Websearch import de.mm20.launcher2.ui.R import de.mm20.launcher2.ui.databinding.ViewWebsearchBinding import de.mm20.launcher2.ui.launcher.search.SearchViewModel +import kotlinx.coroutines.launch +import java.io.File class WebSearchView : FrameLayout { constructor(context: Context) : super(context) @@ -50,18 +53,19 @@ class WebSearchView : FrameLayout { for (search in websearches) { val chip = Chip(context) chip.text = search.label - if (search.icon != null) { - Glide.with(context) - .load(search.icon) - .into(object : SimpleTarget() { - override fun onResourceReady( - resource: Drawable, - transition: Transition? - ) { - chip.chipIcon = resource - } - - }) + val icon = search.icon + if (icon != null) { + val imageRequest = ImageRequest.Builder(context) + .data(File(icon)) + .size((32*dp).toInt()) + .scale(Scale.FIT) + .target { + chip.chipIcon = it + } + .build() + lifecycleScope.launch { + context.imageLoader.execute(imageRequest) + } chip.chipIconTint = null } else { chip.chipIcon = ContextCompat.getDrawable(context, R.drawable.ic_search) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteDetailRepresentation.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteDetailRepresentation.kt index eef0a7d5..b674536b 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteDetailRepresentation.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteDetailRepresentation.kt @@ -10,7 +10,8 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import androidx.transition.Scene -import com.bumptech.glide.Glide +import coil.load +import coil.size.Scale import de.mm20.launcher2.icons.IconRepository import de.mm20.launcher2.ktx.dp import de.mm20.launcher2.ktx.lifecycleOwner @@ -61,7 +62,7 @@ class WebsiteDetailRepresentation : Representation, KoinComponent { website.image.isNotBlank() -> { websiteImage.visibility = View.VISIBLE websiteFavIcon.visibility = FrameLayout.GONE - Glide.with(context).load(website.image).into(websiteImage) + websiteImage.load(website.image) websiteImage.transitionName = "icon" label.transitionName = "label" websiteFavIcon.transitionName = null diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteListRepresentation.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteListRepresentation.kt index 4a4d9da5..b66a5614 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteListRepresentation.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WebsiteListRepresentation.kt @@ -10,12 +10,11 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import androidx.transition.Scene -import com.bumptech.glide.Glide +import coil.load import de.mm20.launcher2.badges.BadgeRepository import de.mm20.launcher2.icons.IconRepository import de.mm20.launcher2.ktx.dp import de.mm20.launcher2.ktx.lifecycleOwner -import de.mm20.launcher2.ktx.lifecycleScope import de.mm20.launcher2.legacy.helper.ActivityStarter import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Website @@ -26,7 +25,6 @@ import de.mm20.launcher2.ui.legacy.view.LauncherIconView import de.mm20.launcher2.ui.legacy.view.ToolbarAction import de.mm20.launcher2.ui.legacy.view.ToolbarView import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import org.koin.core.component.KoinComponent @@ -66,7 +64,8 @@ class WebsiteListRepresentation : Representation, KoinComponent { website.image.isNotBlank() -> { websiteImage.visibility = View.VISIBLE websiteFavIcon.visibility = FrameLayout.GONE - Glide.with(context).load(website.image).into(websiteImage) + websiteImage.load(website.image) + websiteImage.load(website.image) websiteImage.transitionName = "icon" label.transitionName = "label" websiteFavIcon.transitionName = null diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaDetailRepresentation.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaDetailRepresentation.kt index 6a1ae286..68bfefac 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaDetailRepresentation.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaDetailRepresentation.kt @@ -7,7 +7,7 @@ import android.widget.ImageView import android.widget.TextView import androidx.core.text.HtmlCompat import androidx.transition.Scene -import com.bumptech.glide.Glide +import coil.load import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Wikipedia import de.mm20.launcher2.ui.R @@ -35,7 +35,7 @@ class WikipediaDetailRepresentation : Representation { it.scaleType = ImageView.ScaleType.CENTER_CROP } it.visibility = View.VISIBLE - Glide.with(context).load(wikipedia.image).into(it) + it.load(wikipedia.image) } } val toolbar = findViewById(R.id.wikipediaToolbar) diff --git a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaListRepresentation.kt b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaListRepresentation.kt index 14962316..0964c038 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaListRepresentation.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/legacy/search/WikipediaListRepresentation.kt @@ -7,7 +7,8 @@ import android.widget.ImageView import android.widget.TextView import androidx.core.text.HtmlCompat import androidx.transition.Scene -import com.bumptech.glide.Glide +import coil.load +import coil.size.Scale import de.mm20.launcher2.search.data.Searchable import de.mm20.launcher2.search.data.Wikipedia import de.mm20.launcher2.ui.R @@ -17,13 +18,19 @@ import de.mm20.launcher2.ui.legacy.view.ToolbarAction import de.mm20.launcher2.ui.legacy.view.ToolbarView class WikipediaListRepresentation : Representation { - override fun getScene(rootView: SearchableView, searchable: Searchable, previousRepresentation: Int?): Scene { + override fun getScene( + rootView: SearchableView, + searchable: Searchable, + previousRepresentation: Int? + ): Scene { val wikipedia = searchable as Wikipedia - val scene = Scene.getSceneForLayout(rootView, R.layout.view_wikipedia_list, rootView.context) + val scene = + Scene.getSceneForLayout(rootView, R.layout.view_wikipedia_list, rootView.context) scene.setEnterAction { with(rootView) { findViewById(R.id.wikipediaTitle).text = wikipedia.label - findViewById(R.id.wikipediaText).text = HtmlCompat.fromHtml(wikipedia.text, HtmlCompat.FROM_HTML_MODE_LEGACY) + findViewById(R.id.wikipediaText).text = + HtmlCompat.fromHtml(wikipedia.text, HtmlCompat.FROM_HTML_MODE_LEGACY) findViewById(R.id.wikipediaImage).also { if (wikipedia.image.isNullOrBlank()) { it.visibility = View.GONE @@ -35,7 +42,7 @@ class WikipediaListRepresentation : Representation { it.scaleType = ImageView.ScaleType.CENTER_CROP } it.visibility = View.VISIBLE - Glide.with(context).load(wikipedia.image).into(it) + it.load(wikipedia.image) } } val toolbar = findViewById(R.id.wikipediaToolbar) @@ -62,9 +69,11 @@ class WikipediaListRepresentation : Representation { private fun share(context: Context, wikipedia: Wikipedia) { val text = wikipedia.text.toString() val shareIntent = Intent(Intent.ACTION_SEND) - shareIntent.putExtra(Intent.EXTRA_TEXT, "${wikipedia.label}\n\n" + - "${text.substring(0, 200)}…\n\n" + - "${context.getString(R.string.wikipedia_url)}/wiki?curid=${wikipedia.id}") + shareIntent.putExtra( + Intent.EXTRA_TEXT, "${wikipedia.label}\n\n" + + "${text.substring(0, 200)}…\n\n" + + "${context.getString(R.string.wikipedia_url)}/wiki?curid=${wikipedia.id}" + ) shareIntent.type = "text/plain" context.startActivity(Intent.createChooser(shareIntent, null)) } diff --git a/ui/src/main/java/de/mm20/launcher2/ui/settings/websearch/WebSearchSettingsScreenVM.kt b/ui/src/main/java/de/mm20/launcher2/ui/settings/websearch/WebSearchSettingsScreenVM.kt index e36b87cf..335c8c20 100644 --- a/ui/src/main/java/de/mm20/launcher2/ui/settings/websearch/WebSearchSettingsScreenVM.kt +++ b/ui/src/main/java/de/mm20/launcher2/ui/settings/websearch/WebSearchSettingsScreenVM.kt @@ -4,10 +4,14 @@ import android.content.Context import android.graphics.Bitmap import android.graphics.BitmapFactory import android.net.Uri +import androidx.core.graphics.drawable.toBitmap import androidx.core.graphics.scale import androidx.lifecycle.ViewModel import androidx.lifecycle.asLiveData import androidx.lifecycle.viewModelScope +import coil.imageLoader +import coil.request.ImageRequest +import coil.size.Scale import de.mm20.launcher2.search.WebsearchRepository import de.mm20.launcher2.search.data.Websearch import kotlinx.coroutines.Dispatchers @@ -44,14 +48,13 @@ class WebSearchSettingsScreenVM: ViewModel(), KoinComponent { suspend fun createIcon(context: Context, uri: Uri, size: Int): String? = withContext( Dispatchers.IO) { val file = File(context.dataDir, System.currentTimeMillis().toString()) - val stream = context.contentResolver.openInputStream(uri) - val icon = BitmapFactory.decodeStream(stream) ?: return@withContext null - val (scaledW, scaledH) = if (icon.width > icon.height) { - size * icon.width / icon.height to size - } else { - size to size * icon.height / icon.width - } - val scaledIcon = icon.scale(scaledW, scaledH) + val imageRequest = ImageRequest.Builder(context) + .data(uri) + .size(size) + .scale(Scale.FIT) + .build() + val drawable = context.imageLoader.execute(imageRequest).drawable ?: return@withContext null + val scaledIcon = drawable.toBitmap() val out = FileOutputStream(file) scaledIcon.compress(Bitmap.CompressFormat.PNG, 100, out) out.close() diff --git a/ui/src/main/res/layout/view_website_list.xml b/ui/src/main/res/layout/view_website_list.xml index 3e08b6c0..61134b93 100644 --- a/ui/src/main/res/layout/view_website_list.xml +++ b/ui/src/main/res/layout/view_website_list.xml @@ -4,7 +4,6 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:clipChildren="false" android:transitionName="cardLayout">