Use dependency injection for most singletons

This commit is contained in:
MM20
2021-10-10 12:15:54 +02:00
parent 023bb2cbb1
commit 087d4fd455
144 changed files with 1789 additions and 1277 deletions
@@ -7,12 +7,29 @@ import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatDelegate
import de.mm20.launcher2.applications.applicationsModule
import de.mm20.launcher2.badges.badgesModule
import de.mm20.launcher2.calculator.calculatorModule
import de.mm20.launcher2.calendar.calendarModule
import de.mm20.launcher2.contacts.contactsModule
import de.mm20.launcher2.debug.Debug
import de.mm20.launcher2.icons.IconRepository
import de.mm20.launcher2.favorites.favoritesModule
import de.mm20.launcher2.files.filesModule
import de.mm20.launcher2.hiddenitems.hiddenItemsModule
import de.mm20.launcher2.icons.iconsModule
import de.mm20.launcher2.music.musicModule
import de.mm20.launcher2.preferences.LauncherPreferences
import de.mm20.launcher2.preferences.Themes
import de.mm20.launcher2.search.searchModule
import de.mm20.launcher2.ui.legacy.helper.WallpaperBlur
import de.mm20.launcher2.unitconverter.unitConverterModule
import de.mm20.launcher2.websites.websitesModule
import de.mm20.launcher2.widgets.widgetsModule
import de.mm20.launcher2.wikipedia.wikipediaModule
import kotlinx.coroutines.*
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.context.startKoin
import java.text.Collator
import kotlin.coroutines.CoroutineContext
@@ -23,29 +40,12 @@ class LauncherApplication : Application(), CoroutineScope {
var blurredWallpaper: Bitmap? = null
private val appReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
IconRepository.getInstance(this@LauncherApplication).requestIconPackListUpdate()
}
}
override fun onCreate() {
super.onCreate()
Debug()
instance = this
LauncherPreferences.initialize(this)
IconRepository.getInstance(this).requestIconPackListUpdate()
registerReceiver(appReceiver, IntentFilter().apply {
addAction(Intent.ACTION_PACKAGE_REPLACED)
addAction(Intent.ACTION_PACKAGE_ADDED)
addAction(Intent.ACTION_PACKAGE_REMOVED)
addAction(Intent.ACTION_MY_PACKAGE_REPLACED)
addAction(Intent.ACTION_PACKAGE_CHANGED)
addDataScheme("package")
})
val theme = LauncherPreferences.instance.theme
AppCompatDelegate.setDefaultNightMode(
when (theme) {
@@ -58,6 +58,30 @@ class LauncherApplication : Application(), CoroutineScope {
WallpaperBlur.requestBlur(this)
@Suppress("DEPRECATION") // We need to access the wallpaper directly to blur it
registerReceiver(WallpaperReceiver(), IntentFilter(Intent.ACTION_WALLPAPER_CHANGED))
startKoin {
androidLogger()
androidContext(this@LauncherApplication)
modules(
listOf(
applicationsModule,
calculatorModule,
badgesModule,
calendarModule,
contactsModule,
favoritesModule,
filesModule,
hiddenItemsModule,
iconsModule,
musicModule,
searchModule,
unitConverterModule,
websitesModule,
widgetsModule,
wikipediaModule
)
)
}
}
companion object {
@@ -7,9 +7,12 @@ import android.os.Build
import android.os.Bundle
import de.mm20.launcher2.favorites.FavoritesRepository
import de.mm20.launcher2.search.data.AppShortcut
import org.koin.android.ext.android.inject
class AddItemActivity : Activity() {
val favoritesRepository: FavoritesRepository by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -20,7 +23,7 @@ class AddItemActivity : Activity() {
packageManager.getApplicationInfo(shortcutInfo.`package`, 0)
.loadLabel(packageManager).toString())
if (pinRequest.accept()) {
FavoritesRepository.getInstance(this).pinItem(shortcut)
favoritesRepository.pinItem(shortcut)
}
}
finish()
@@ -29,6 +29,7 @@ import de.mm20.launcher2.preferences.LauncherPreferences
import de.mm20.launcher2.preferences.Themes
import de.mm20.launcher2.ui.legacy.view.LauncherIconView
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
class PreferencesAppearanceFragment : PreferenceFragmentCompat() {
@@ -74,9 +75,10 @@ class PreferencesAppearanceFragment : PreferenceFragmentCompat() {
true
}
val manager = IconPackManager.getInstance(requireContext())
val iconPackManager: IconPackManager by inject()
val iconRepository: IconRepository by inject()
lifecycleScope.launch {
val packs = manager.getInstalledIconPacks()
val packs = iconPackManager.getInstalledIconPacks()
findPreference<ListPreference>("icon_pack")?.apply {
entries = packs.map { it.name }.toMutableList().apply { add(0, "System") }.toTypedArray()
entryValues = (-1 until packs.size).map { it.toString() }.toTypedArray()
@@ -86,14 +88,14 @@ class PreferencesAppearanceFragment : PreferenceFragmentCompat() {
} else {
isEnabled = true
summary = "%s"
value = packs.indexOfFirst { it.packageName == manager.selectedIconPack }.toString()
value = packs.indexOfFirst { it.packageName == iconPackManager.selectedIconPack }.toString()
}
setOnPreferenceChangeListener { _, newValue ->
val index = (newValue as String).toInt()
IconRepository.getInstance(requireContext()).clearCache()
if (index == -1) manager.selectIconPack("")
iconRepository.clearCache()
if (index == -1) iconPackManager.selectIconPack("")
else {
manager.selectIconPack(packs[index].packageName)
iconPackManager.selectIconPack(packs[index].packageName)
}
true
}
@@ -101,7 +103,7 @@ class PreferencesAppearanceFragment : PreferenceFragmentCompat() {
}
findPreference<Preference>("legacy_icon_bg")?.setOnPreferenceChangeListener { _, _ ->
IconRepository.getInstance(requireContext()).clearCache()
iconRepository.clearCache()
true
}
@@ -1,4 +1,4 @@
package de.mm20.launcher2.fragment
package de.mm20.launcher2.fragment
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
@@ -7,32 +7,35 @@ import androidx.preference.PreferenceFragmentCompat
import de.mm20.launcher2.R
import de.mm20.launcher2.badges.BadgeProvider
import de.mm20.launcher2.notifications.NotificationService
import org.koin.android.ext.android.inject
class PreferencesBadgesFragment : PreferenceFragmentCompat() {
private val badgesProvider: BadgeProvider by inject()
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences_badges)
findPreference<Preference>("notification_badges")?.setOnPreferenceChangeListener { _, newValue ->
if (newValue as Boolean) {
de.mm20.launcher2.notifications.NotificationService.getInstance()?.generateBadges()
NotificationService.getInstance()?.generateBadges()
} else {
BadgeProvider.getInstance(requireContext()).removeNotificationBadges()
badgesProvider.removeNotificationBadges()
}
true
}
findPreference<Preference>("suspended_badges")?.setOnPreferenceChangeListener { _, newValue ->
if (newValue as Boolean) {
BadgeProvider.getInstance(requireContext()).addSuspendBadges()
badgesProvider.addSuspendBadges()
} else {
BadgeProvider.getInstance(requireContext()).removeSuspendBadges()
badgesProvider.removeSuspendBadges()
}
true
}
findPreference<Preference>("cloud_badges")?.setOnPreferenceChangeListener { _, newValue ->
if (newValue as Boolean) {
BadgeProvider.getInstance(requireContext()).addCloudBadges()
badgesProvider.addCloudBadges()
} else {
BadgeProvider.getInstance(requireContext()).removeCloudBadges()
badgesProvider.removeCloudBadges()
}
true
}
@@ -42,6 +45,6 @@ class PreferencesBadgesFragment : PreferenceFragmentCompat() {
override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar
?.setTitle(R.string.preference_screen_badges)
?.setTitle(R.string.preference_screen_badges)
}
}
@@ -19,9 +19,12 @@ import de.mm20.launcher2.nextcloud.NextcloudApiHelper
import de.mm20.launcher2.owncloud.OwncloudClient
import de.mm20.launcher2.preferences.LauncherPreferences
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
class PreferencesSearchFragment : PreferenceFragmentCompat() {
private val googleApiHelper: GoogleApiHelper by inject()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
lifecycleScope.launch {
@@ -17,7 +17,6 @@ import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.core.graphics.scale
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import com.afollestad.materialdialogs.MaterialDialog
@@ -29,9 +28,9 @@ import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.transition.Transition
import de.mm20.launcher2.R
import de.mm20.launcher2.ktx.dp
import de.mm20.launcher2.search.SearchViewModel
import de.mm20.launcher2.search.WebsearchViewModel
import de.mm20.launcher2.search.data.Websearch
import org.koin.androidx.viewmodel.ext.android.viewModel
import java.io.File
import java.io.FileOutputStream
import java.lang.ref.WeakReference
@@ -42,9 +41,7 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
private var sheetIcon: WeakReference<ImageView>? = null
private val viewModel by lazy {
ViewModelProvider(context as AppCompatActivity)[WebsearchViewModel::class.java]
}
private val viewModel: WebsearchViewModel by viewModel()
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceScreen = preferenceManager.createPreferenceScreen(activity)
@@ -61,19 +58,23 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
val pref = Preference(context)
pref.title = search.label
if (search.icon == null) {
val drawable = resources.getDrawable(R.drawable.ic_search, requireActivity().theme).mutate()
val drawable =
resources.getDrawable(R.drawable.ic_search, requireActivity().theme).mutate()
drawable.setTintMode(PorterDuff.Mode.SRC_ATOP)
drawable.setTint(search.color)
pref.icon = drawable
} else {
Glide.with(requireContext())
.asDrawable()
.load(search.icon)
.into(object : SimpleTarget<Drawable>() {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
pref.icon = resource
}
})
.asDrawable()
.load(search.icon)
.into(object : SimpleTarget<Drawable>() {
override fun onResourceReady(
resource: Drawable,
transition: Transition<in Drawable>?
) {
pref.icon = resource
}
})
}
pref.setOnPreferenceClickListener {
editSearch(search)
@@ -109,23 +110,23 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
imageTintList = ColorStateList.valueOf(websearch.color)
} else {
Glide.with(this)
.load(websearch.icon)
.into(this)
.load(websearch.icon)
.into(this)
}
sheetIcon = WeakReference(this)
}
val sheet = MaterialDialog(requireContext(), BottomSheet())
.cornerRadius(8f)
.customView(view = dialogView)
.cornerRadius(8f)
.customView(view = dialogView)
val radius = 8 * dialogView.dp
dialogView.background = GradientDrawable().apply {
cornerRadii = floatArrayOf(
radius, radius, // top left
radius, radius, // top right
0f, 0f, // bottom left
0f, 0f // bottom right
radius, radius, // top left
radius, radius, // top right
0f, 0f, // bottom left
0f, 0f // bottom right
)
}
@@ -134,30 +135,31 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
sheet.noAutoDismiss()
.positiveButton(android.R.string.ok) {
val newUrl = urlEdit.text.toString()
val newName = nameEdit.text.toString()
if (!newUrl.contains("\${1}")) {
urlEdit.error = getString(R.string.websearch_dialog_url_error)
return@positiveButton
.positiveButton(android.R.string.ok) {
val newUrl = urlEdit.text.toString()
val newName = nameEdit.text.toString()
if (!newUrl.contains("\${1}")) {
urlEdit.error = getString(R.string.websearch_dialog_url_error)
return@positiveButton
}
File(requireContext().cacheDir, "websearch-tmp").takeIf { it.exists() }?.let {
websearch.icon?.let { File(it).takeIf { it.exists() }?.delete() }
val newFile =
File(requireContext().filesDir, "websearch-${System.currentTimeMillis()}")
it.copyTo(newFile, true)
it.delete()
newIcon = newFile.absolutePath
}
if (newIcon == null) {
websearch.icon?.let { File(it).takeIf { it.exists() }?.delete() }
}
websearch.urlTemplate = newUrl
websearch.label = newName
websearch.icon = newIcon
websearch.color = newColor
viewModel.insertWebsearch(websearch)
sheet.dismiss()
}
File(requireContext().cacheDir, "websearch-tmp").takeIf { it.exists() }?.let {
websearch.icon?.let { File(it).takeIf { it.exists() }?.delete() }
val newFile = File(requireContext().filesDir, "websearch-${System.currentTimeMillis()}")
it.copyTo(newFile, true)
it.delete()
newIcon = newFile.absolutePath
}
if (newIcon == null) {
websearch.icon?.let { File(it).takeIf { it.exists() }?.delete() }
}
websearch.urlTemplate = newUrl
websearch.label = newName
websearch.icon = newIcon
websearch.color = newColor
viewModel.insertWebsearch(websearch)
sheet.dismiss()
}
sheet.negativeButton(android.R.string.cancel) {
sheet.cancel()
@@ -188,15 +190,16 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
}
title(R.string.websearch_dialog_choose_icon_color)
colorChooser(
colors = context.resources.getIntArray(R.array.color_chooser_presets),
allowCustomArgb = true,
showAlphaSelector = false
colors = context.resources.getIntArray(R.array.color_chooser_presets),
allowCustomArgb = true,
showAlphaSelector = false
) { _, color ->
iconView.setImageResource(R.drawable.ic_search)
iconView.imageTintList = ColorStateList.valueOf(color)
newColor = color
newIcon = null
File(requireContext().cacheDir, "websearch-tmp").takeIf { it.exists() }?.delete()
File(requireContext().cacheDir, "websearch-tmp").takeIf { it.exists() }
?.delete()
dismiss()
}
}
@@ -207,7 +210,7 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
override fun onResume() {
super.onResume()
(activity as AppCompatActivity).supportActionBar
?.setTitle(R.string.preference_search_edit_websearch)
?.setTitle(R.string.preference_search_edit_websearch)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@@ -216,7 +219,8 @@ class PreferencesWebSearchesFragment : PreferenceFragmentCompat() {
if (requestCode == 24 && resultCode == Activity.RESULT_OK && dataUri != null) {
val stream = requireActivity().contentResolver.openInputStream(dataUri)
val icon = BitmapFactory.decodeStream(stream)
val scaledIcon = icon.scale((32 * requireContext().dp).toInt(), (32 * requireContext().dp).toInt())
val scaledIcon =
icon.scale((32 * requireContext().dp).toInt(), (32 * requireContext().dp).toInt())
val out = FileOutputStream(File(requireContext().cacheDir, "websearch-tmp"))
scaledIcon.compress(Bitmap.CompressFormat.PNG, 100, out)
out.close()