Migrate from Glide to Coil

This commit is contained in:
MM20 2022-01-20 22:40:32 +01:00
parent 401a493864
commit 0447d3072d
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389
17 changed files with 91 additions and 171 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -77,13 +77,6 @@ val OpenSourceLicenses = arrayOf(
copyrightNote = "Copyright (c) 2009-2021 Jonathan Hedley <https://jsoup.org/>",
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",

View File

@ -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.

View File

@ -4,7 +4,6 @@
<string name="bsd_2clause_name" translatable="false">Simplified BSD license</string>
<string name="bsd_3clause_name" translatable="false">Modified BSD license</string>
<string name="apache_license_name" translatable="false">Apache license 2.0</string>
<string name="glide_license_name" translatable="false">Glide license</string>
<string name="gpl3_name" translatable="false">GNU General Public License Version 3</string>
<string name="open_font_license_name" translatable="false">SIL OPEN FONT LICENSE</string>
</resources>

View File

@ -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")

View File

@ -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)

View File

@ -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<Drawable>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable>?
) {
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)

View File

@ -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

View File

@ -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

View File

@ -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<ToolbarView>(R.id.wikipediaToolbar)

View File

@ -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<TextView>(R.id.wikipediaTitle).text = wikipedia.label
findViewById<TextView>(R.id.wikipediaText).text = HtmlCompat.fromHtml(wikipedia.text, HtmlCompat.FROM_HTML_MODE_LEGACY)
findViewById<TextView>(R.id.wikipediaText).text =
HtmlCompat.fromHtml(wikipedia.text, HtmlCompat.FROM_HTML_MODE_LEGACY)
findViewById<ImageView>(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<ToolbarView>(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))
}

View File

@ -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()

View File

@ -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">
<de.mm20.launcher2.ui.legacy.view.AspectRationImageView

View File

@ -6,7 +6,6 @@
android:id="@+id/wikipediaRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:transitionName="cardLayout">
<de.mm20.launcher2.ui.legacy.view.AspectRationImageView
@ -14,7 +13,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/color_divider"
android:scaleType="centerCrop"
android:scaleType="fitCenter"
app:aspectRatio="0.5625"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"

View File

@ -44,11 +44,12 @@ dependencies {
implementation(libs.bundles.androidx.lifecycle)
implementation(libs.okhttp)
implementation(libs.glide)
implementation(libs.jsoup)
implementation(libs.koin.android)
implementation(libs.coil.core)
implementation(project(":preferences"))
implementation(project(":search"))
implementation(project(":base"))

View File

@ -8,7 +8,8 @@ import android.graphics.drawable.ColorDrawable
import android.net.Uri
import androidx.core.graphics.drawable.toBitmap
import androidx.palette.graphics.Palette
import com.bumptech.glide.Glide
import coil.imageLoader
import coil.request.ImageRequest
import de.mm20.launcher2.graphics.TextDrawable
import de.mm20.launcher2.icons.LauncherIcon
import de.mm20.launcher2.ktx.sp
@ -30,24 +31,24 @@ class Website(
override suspend fun loadIcon(context: Context, size: Int): LauncherIcon? {
if (favicon.isEmpty()) return null
try {
return withContext(Dispatchers.IO) {
val icon = Glide.with(context)
.asDrawable()
.load(favicon)
.submit()
.get()
val color = if (color != 0) color else {
val request = ImageRequest.Builder(context)
.data(favicon)
.size(size)
.build()
val icon = context.imageLoader.execute(request).drawable ?: return null
val color = if (color != 0) color else {
withContext(Dispatchers.Default) {
Palette
.from(icon.toBitmap())
.generate()
.getLightMutedColor(Color.WHITE)
}
LauncherIcon(
foreground = icon,
background = ColorDrawable(color),
foregroundScale = 0.7f
)
}
return LauncherIcon(
foreground = icon,
background = ColorDrawable(color),
foregroundScale = 0.7f
)
} catch (e: ExecutionException) {
return null
}