Manga languages onboarding
This commit is contained in:
7
.idea/misc.xml
generated
7
.idea/misc.xml
generated
@@ -14,6 +14,8 @@
|
|||||||
<entry key="app/src/main/res/drawable/ic_clear_all.xml" value="0.275" />
|
<entry key="app/src/main/res/drawable/ic_clear_all.xml" value="0.275" />
|
||||||
<entry key="app/src/main/res/drawable/ic_complete.xml" value="0.275" />
|
<entry key="app/src/main/res/drawable/ic_complete.xml" value="0.275" />
|
||||||
<entry key="app/src/main/res/drawable/ic_history.xml" value="0.275" />
|
<entry key="app/src/main/res/drawable/ic_history.xml" value="0.275" />
|
||||||
|
<entry key="app/src/main/res/drawable/ic_locale.xml" value="0.197" />
|
||||||
|
<entry key="app/src/main/res/drawable/ic_open_external.xml" value="0.197" />
|
||||||
<entry key="app/src/main/res/drawable/tab_indicator.xml" value="0.28512820512820514" />
|
<entry key="app/src/main/res/drawable/tab_indicator.xml" value="0.28512820512820514" />
|
||||||
<entry key="app/src/main/res/drawable/tabs_background.xml" value="0.28512820512820514" />
|
<entry key="app/src/main/res/drawable/tabs_background.xml" value="0.28512820512820514" />
|
||||||
<entry key="app/src/main/res/layout-w600dp/activity_details.xml" value="0.18072916666666666" />
|
<entry key="app/src/main/res/layout-w600dp/activity_details.xml" value="0.18072916666666666" />
|
||||||
@@ -23,6 +25,7 @@
|
|||||||
<entry key="app/src/main/res/layout/activity_setup_protect.xml" value="0.26927083333333335" />
|
<entry key="app/src/main/res/layout/activity_setup_protect.xml" value="0.26927083333333335" />
|
||||||
<entry key="app/src/main/res/layout/dialog_favorite_categories.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/layout/dialog_favorite_categories.xml" value="0.2601851851851852" />
|
||||||
<entry key="app/src/main/res/layout/dialog_list_mode.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/layout/dialog_list_mode.xml" value="0.2601851851851852" />
|
||||||
|
<entry key="app/src/main/res/layout/dialog_onboard.xml" value="0.25885416666666666" />
|
||||||
<entry key="app/src/main/res/layout/fragment_chapters.xml" value="0.24739583333333334" />
|
<entry key="app/src/main/res/layout/fragment_chapters.xml" value="0.24739583333333334" />
|
||||||
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
<entry key="app/src/main/res/layout/fragment_details.xml" value="0.26145833333333335" />
|
||||||
<entry key="app/src/main/res/layout/fragment_favourites.xml" value="0.26296296296296295" />
|
<entry key="app/src/main/res/layout/fragment_favourites.xml" value="0.26296296296296295" />
|
||||||
@@ -31,6 +34,7 @@
|
|||||||
<entry key="app/src/main/res/layout/fragment_search_suggestion.xml" value="0.25885416666666666" />
|
<entry key="app/src/main/res/layout/fragment_search_suggestion.xml" value="0.25885416666666666" />
|
||||||
<entry key="app/src/main/res/layout/item_branch.xml" value="0.24739583333333334" />
|
<entry key="app/src/main/res/layout/item_branch.xml" value="0.24739583333333334" />
|
||||||
<entry key="app/src/main/res/layout/item_branch_dropdown.xml" value="0.25743589743589745" />
|
<entry key="app/src/main/res/layout/item_branch_dropdown.xml" value="0.25743589743589745" />
|
||||||
|
<entry key="app/src/main/res/layout/item_category.xml" value="0.25885416666666666" />
|
||||||
<entry key="app/src/main/res/layout/item_category_checkable.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/layout/item_category_checkable.xml" value="0.2601851851851852" />
|
||||||
<entry key="app/src/main/res/layout/item_manga_grid.xml" value="0.26042632066728455" />
|
<entry key="app/src/main/res/layout/item_manga_grid.xml" value="0.26042632066728455" />
|
||||||
<entry key="app/src/main/res/layout/item_manga_list_details.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/layout/item_manga_list_details.xml" value="0.2601851851851852" />
|
||||||
@@ -41,9 +45,12 @@
|
|||||||
<entry key="app/src/main/res/layout/item_search_suggestion_manga.xml" value="0.24479166666666666" />
|
<entry key="app/src/main/res/layout/item_search_suggestion_manga.xml" value="0.24479166666666666" />
|
||||||
<entry key="app/src/main/res/layout/item_search_suggestion_query.xml" value="0.587248322147651" />
|
<entry key="app/src/main/res/layout/item_search_suggestion_query.xml" value="0.587248322147651" />
|
||||||
<entry key="app/src/main/res/layout/item_source_config.xml" value="0.25885416666666666" />
|
<entry key="app/src/main/res/layout/item_source_config.xml" value="0.25885416666666666" />
|
||||||
|
<entry key="app/src/main/res/layout/item_source_locale.xml" value="0.25885416666666666" />
|
||||||
<entry key="app/src/main/res/layout/item_tracklog.xml" value="0.24479166666666666" />
|
<entry key="app/src/main/res/layout/item_tracklog.xml" value="0.24479166666666666" />
|
||||||
<entry key="app/src/main/res/layout/sheet_pages.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/layout/sheet_pages.xml" value="0.2601851851851852" />
|
||||||
|
<entry key="app/src/main/res/menu/opt_browser.xml" value="0.24479166666666666" />
|
||||||
<entry key="app/src/main/res/menu/opt_protect.xml" value="0.26927083333333335" />
|
<entry key="app/src/main/res/menu/opt_protect.xml" value="0.26927083333333335" />
|
||||||
|
<entry key="app/src/main/res/menu/opt_sources.xml" value="0.24479166666666666" />
|
||||||
<entry key="app/src/main/res/menu/popup_category.xml" value="0.2601851851851852" />
|
<entry key="app/src/main/res/menu/popup_category.xml" value="0.2601851851851852" />
|
||||||
<entry key="app/src/main/res/xml/pref_main.xml" value="0.26927083333333335" />
|
<entry key="app/src/main/res/xml/pref_main.xml" value="0.26927083333333335" />
|
||||||
</map>
|
</map>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ dependencies {
|
|||||||
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
|
implementation 'androidx.lifecycle:lifecycle-process:2.3.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.0'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01'
|
implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01'
|
||||||
implementation 'androidx.preference:preference-ktx:1.1.1'
|
implementation 'androidx.preference:preference-ktx:1.1.1'
|
||||||
implementation 'androidx.work:work-runtime-ktx:2.5.0'
|
implementation 'androidx.work:work-runtime-ktx:2.5.0'
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ enum class MangaSource(
|
|||||||
NINEMANGA_RU("NineManga Русский", "ru", NineMangaRepository.Russian::class.java),
|
NINEMANGA_RU("NineManga Русский", "ru", NineMangaRepository.Russian::class.java),
|
||||||
NINEMANGA_DE("NineManga Deutsch", "de", NineMangaRepository.Deutsch::class.java),
|
NINEMANGA_DE("NineManga Deutsch", "de", NineMangaRepository.Deutsch::class.java),
|
||||||
NINEMANGA_IT("NineManga Italiano", "it", NineMangaRepository.Italiano::class.java),
|
NINEMANGA_IT("NineManga Italiano", "it", NineMangaRepository.Italiano::class.java),
|
||||||
NINEMANGA_BR("NineManga Brasil", "br", NineMangaRepository.Brazil::class.java),
|
NINEMANGA_BR("NineManga Brasil", "pt", NineMangaRepository.Brazil::class.java),
|
||||||
NINEMANGA_FR("NineManga Français", "fr", NineMangaRepository.Francais::class.java),
|
NINEMANGA_FR("NineManga Français", "fr", NineMangaRepository.Francais::class.java),
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -101,6 +101,9 @@ class AppSettings private constructor(private val prefs: SharedPreferences) :
|
|||||||
|
|
||||||
var hiddenSources by StringSetPreferenceDelegate(KEY_SOURCES_HIDDEN)
|
var hiddenSources by StringSetPreferenceDelegate(KEY_SOURCES_HIDDEN)
|
||||||
|
|
||||||
|
val isSourcesSelected: Boolean
|
||||||
|
get() = KEY_SOURCES_HIDDEN in prefs
|
||||||
|
|
||||||
fun getStorageDir(context: Context): File? {
|
fun getStorageDir(context: Context): File? {
|
||||||
val value = prefs.getString(KEY_LOCAL_STORAGE, null)?.let {
|
val value = prefs.getString(KEY_LOCAL_STORAGE, null)?.let {
|
||||||
File(it)
|
File(it)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import androidx.fragment.app.commit
|
|||||||
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
|
||||||
import com.google.android.material.navigation.NavigationView
|
import com.google.android.material.navigation.NavigationView
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.base.ui.BaseActivity
|
import org.koitharu.kotatsu.base.ui.BaseActivity
|
||||||
@@ -41,6 +42,7 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
|
|||||||
import org.koitharu.kotatsu.search.ui.suggestion.SearchUI
|
import org.koitharu.kotatsu.search.ui.suggestion.SearchUI
|
||||||
import org.koitharu.kotatsu.settings.AppUpdateChecker
|
import org.koitharu.kotatsu.settings.AppUpdateChecker
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
||||||
import org.koitharu.kotatsu.tracker.ui.FeedFragment
|
import org.koitharu.kotatsu.tracker.ui.FeedFragment
|
||||||
import org.koitharu.kotatsu.tracker.work.TrackWorker
|
import org.koitharu.kotatsu.tracker.work.TrackWorker
|
||||||
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
|
||||||
@@ -86,6 +88,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(),
|
|||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
TrackWorker.setup(applicationContext)
|
TrackWorker.setup(applicationContext)
|
||||||
AppUpdateChecker(this).launchIfNeeded()
|
AppUpdateChecker(this).launchIfNeeded()
|
||||||
|
OnboardDialogFragment.showWelcome(get(), supportFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.onOpenReader.observe(this, this::onOpenReader)
|
viewModel.onOpenReader.observe(this, this::onOpenReader)
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.koitharu.kotatsu.core.backup.RestoreRepository
|
|||||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
import org.koitharu.kotatsu.settings.backup.BackupViewModel
|
import org.koitharu.kotatsu.settings.backup.BackupViewModel
|
||||||
import org.koitharu.kotatsu.settings.backup.RestoreViewModel
|
import org.koitharu.kotatsu.settings.backup.RestoreViewModel
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.OnboardViewModel
|
||||||
import org.koitharu.kotatsu.settings.protect.ProtectSetupViewModel
|
import org.koitharu.kotatsu.settings.protect.ProtectSetupViewModel
|
||||||
|
|
||||||
val settingsModule
|
val settingsModule
|
||||||
@@ -21,4 +22,5 @@ val settingsModule
|
|||||||
viewModel { BackupViewModel(get(), androidContext()) }
|
viewModel { BackupViewModel(get(), androidContext()) }
|
||||||
viewModel { (uri: Uri?) -> RestoreViewModel(uri, get(), androidContext()) }
|
viewModel { (uri: Uri?) -> RestoreViewModel(uri, get(), androidContext()) }
|
||||||
viewModel { ProtectSetupViewModel(get()) }
|
viewModel { ProtectSetupViewModel(get()) }
|
||||||
|
viewModel { OnboardViewModel(get()) }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.onboard
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocalesAdapter
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
||||||
|
import org.koitharu.kotatsu.utils.ext.observeNotNull
|
||||||
|
import org.koitharu.kotatsu.utils.ext.withArgs
|
||||||
|
|
||||||
|
class OnboardDialogFragment : AlertDialogFragment<DialogOnboardBinding>(),
|
||||||
|
OnListItemClickListener<SourceLocale>, DialogInterface.OnClickListener {
|
||||||
|
|
||||||
|
private val viewModel by viewModel<OnboardViewModel>(mode = LazyThreadSafetyMode.NONE)
|
||||||
|
private var isWelcome: Boolean = false
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
arguments?.run {
|
||||||
|
isWelcome = getBoolean(ARG_WELCOME, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInflateView(
|
||||||
|
inflater: LayoutInflater,
|
||||||
|
container: ViewGroup?,
|
||||||
|
) = DialogOnboardBinding.inflate(inflater, container, false)
|
||||||
|
|
||||||
|
override fun onBuildDialog(builder: AlertDialog.Builder) {
|
||||||
|
builder
|
||||||
|
.setPositiveButton(R.string.done, this)
|
||||||
|
.setCancelable(true)
|
||||||
|
if (isWelcome) {
|
||||||
|
builder.setTitle(R.string.welcome)
|
||||||
|
} else {
|
||||||
|
builder
|
||||||
|
.setTitle(R.string.remote_sources)
|
||||||
|
.setNegativeButton(android.R.string.cancel, this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val adapter = SourceLocalesAdapter(this)
|
||||||
|
binding.recyclerView.adapter = adapter
|
||||||
|
viewModel.list.observeNotNull(viewLifecycleOwner) {
|
||||||
|
adapter.items = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemClick(item: SourceLocale, view: View) {
|
||||||
|
viewModel.setItemChecked(item.key, !item.isChecked)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(dialog: DialogInterface?, which: Int) {
|
||||||
|
when (which) {
|
||||||
|
DialogInterface.BUTTON_POSITIVE -> viewModel.apply()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG = "OnboardDialog"
|
||||||
|
private const val ARG_WELCOME = "welcome"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager) = OnboardDialogFragment().show(fm, TAG)
|
||||||
|
|
||||||
|
fun showWelcome(settings: AppSettings, fm: FragmentManager) {
|
||||||
|
if (!settings.isSourcesSelected) {
|
||||||
|
OnboardDialogFragment().withArgs(1) {
|
||||||
|
putBoolean(ARG_WELCOME, true)
|
||||||
|
}.show(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.onboard
|
||||||
|
|
||||||
|
import androidx.collection.ArraySet
|
||||||
|
import androidx.core.os.LocaleListCompat
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
||||||
|
import org.koitharu.kotatsu.utils.ext.map
|
||||||
|
import org.koitharu.kotatsu.utils.ext.mapTo
|
||||||
|
import org.koitharu.kotatsu.utils.ext.mapToSet
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class OnboardViewModel(
|
||||||
|
private val settings: AppSettings,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
private val allSources = MangaSource.values().filterNot { x -> x == MangaSource.LOCAL }
|
||||||
|
|
||||||
|
private val locales = allSources.mapTo(ArraySet()) {
|
||||||
|
it.locale
|
||||||
|
}
|
||||||
|
|
||||||
|
private val selectedLocales = locales.toMutableSet()
|
||||||
|
|
||||||
|
val list = MutableLiveData<List<SourceLocale>?>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (settings.isSourcesSelected) {
|
||||||
|
selectedLocales.removeAll(settings.hiddenSources.map { x -> MangaSource.valueOf(x).locale })
|
||||||
|
} else {
|
||||||
|
LocaleListCompat.getDefault().mapTo(selectedLocales) { x ->
|
||||||
|
x.language
|
||||||
|
}
|
||||||
|
selectedLocales.retainAll(allSources.map { x -> x.locale })
|
||||||
|
if (selectedLocales.isEmpty()) {
|
||||||
|
selectedLocales += "en"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rebuildList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setItemChecked(key: String?, isChecked: Boolean) {
|
||||||
|
val isModified = if (isChecked) {
|
||||||
|
selectedLocales.add(key)
|
||||||
|
} else {
|
||||||
|
selectedLocales.remove(key)
|
||||||
|
}
|
||||||
|
if (isModified) {
|
||||||
|
rebuildList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apply() {
|
||||||
|
settings.hiddenSources = allSources.filterNot { x ->
|
||||||
|
x.locale in selectedLocales
|
||||||
|
}.mapToSet { x -> x.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rebuildList() {
|
||||||
|
list.value = locales.map { key ->
|
||||||
|
val locale = if (key != null) {
|
||||||
|
Locale(key)
|
||||||
|
} else null
|
||||||
|
SourceLocale(
|
||||||
|
key = key,
|
||||||
|
title = locale?.getDisplayLanguage(locale)?.capitalize(locale),
|
||||||
|
isChecked = key in selectedLocales
|
||||||
|
)
|
||||||
|
}.sortedWith(SourceLocaleComparator())
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SourceLocaleComparator : Comparator<SourceLocale> {
|
||||||
|
|
||||||
|
private val deviceLocales = LocaleListCompat.getAdjustedDefault()
|
||||||
|
.map { it.language }
|
||||||
|
|
||||||
|
override fun compare(a: SourceLocale?, b: SourceLocale?): Int {
|
||||||
|
return when {
|
||||||
|
a === b -> 0
|
||||||
|
a?.key == null -> 1
|
||||||
|
b?.key == null -> -1
|
||||||
|
else -> {
|
||||||
|
val index = deviceLocales.indexOf(a.key)
|
||||||
|
if (index == -1) {
|
||||||
|
compareValues(a.title, b.title)
|
||||||
|
} else {
|
||||||
|
-2 - index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.onboard.adapter
|
||||||
|
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemSourceLocaleBinding
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
||||||
|
|
||||||
|
fun sourceLocaleAD(
|
||||||
|
clickListener: OnListItemClickListener<SourceLocale>
|
||||||
|
) = adapterDelegateViewBinding<SourceLocale, SourceLocale, ItemSourceLocaleBinding>(
|
||||||
|
{ inflater, parent -> ItemSourceLocaleBinding.inflate(inflater, parent, false) }
|
||||||
|
) {
|
||||||
|
|
||||||
|
binding.root.setOnClickListener {
|
||||||
|
clickListener.onItemClick(item, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
bind {
|
||||||
|
binding.root.text = item.title ?: getString(R.string.other)
|
||||||
|
binding.root.isChecked = item.isChecked
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.onboard.adapter
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
||||||
|
|
||||||
|
class SourceLocalesAdapter(
|
||||||
|
clickListener: OnListItemClickListener<SourceLocale>,
|
||||||
|
) : AsyncListDifferDelegationAdapter<SourceLocale>(DiffCallback()) {
|
||||||
|
|
||||||
|
init {
|
||||||
|
delegatesManager.addDelegate(sourceLocaleAD(clickListener))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DiffCallback : DiffUtil.ItemCallback<SourceLocale>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: SourceLocale,
|
||||||
|
newItem: SourceLocale,
|
||||||
|
): Boolean = oldItem.key == newItem.key
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: SourceLocale,
|
||||||
|
newItem: SourceLocale,
|
||||||
|
): Boolean = oldItem == newItem
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.onboard.model
|
||||||
|
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
data class SourceLocale(
|
||||||
|
val key: String?,
|
||||||
|
val title: String?,
|
||||||
|
val isChecked: Boolean,
|
||||||
|
) : Comparable<SourceLocale> {
|
||||||
|
|
||||||
|
override fun compareTo(other: SourceLocale): Int {
|
||||||
|
return when {
|
||||||
|
this === other -> 0
|
||||||
|
key == Locale.getDefault().language -> -2
|
||||||
|
key == null -> 1
|
||||||
|
other.key == null -> -1
|
||||||
|
else -> compareValues(title, other.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
package org.koitharu.kotatsu.settings.sources
|
package org.koitharu.kotatsu.settings.sources
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.*
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.view.updatePadding
|
import androidx.core.view.updatePadding
|
||||||
import androidx.recyclerview.widget.DividerItemDecoration
|
import androidx.recyclerview.widget.DividerItemDecoration
|
||||||
@@ -16,6 +14,7 @@ import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
|
|||||||
import org.koitharu.kotatsu.core.model.MangaSource
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
|
import org.koitharu.kotatsu.databinding.FragmentSettingsSourcesBinding
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
|
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
||||||
|
|
||||||
class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
|
class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
|
||||||
OnListItemClickListener<MangaSource> {
|
OnListItemClickListener<MangaSource> {
|
||||||
@@ -25,6 +24,7 @@ class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
reorderHelper = ItemTouchHelper(SourcesReorderCallback())
|
reorderHelper = ItemTouchHelper(SourcesReorderCallback())
|
||||||
|
setHasOptionsMenu(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onInflateView(
|
override fun onInflateView(
|
||||||
@@ -51,6 +51,22 @@ class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
|
|||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
|
// TODO handle changes in dialog
|
||||||
|
// inflater.inflate(R.menu.opt_sources, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
return when(item.itemId) {
|
||||||
|
R.id.action_languages -> {
|
||||||
|
OnboardDialogFragment.show(parentFragmentManager)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else -> super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onWindowInsetsChanged(insets: Insets) {
|
override fun onWindowInsetsChanged(insets: Insets) {
|
||||||
binding.recyclerView.updatePadding(
|
binding.recyclerView.updatePadding(
|
||||||
bottom = insets.bottom,
|
bottom = insets.bottom,
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package org.koitharu.kotatsu.utils.ext
|
||||||
|
|
||||||
|
import androidx.core.os.LocaleListCompat
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
fun LocaleListCompat.toList(): List<Locale> {
|
||||||
|
val list = ArrayList<Locale>(size())
|
||||||
|
for (i in 0 until size()) {
|
||||||
|
list += get(i)
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <R, C : MutableCollection<in R>> LocaleListCompat.mapTo(
|
||||||
|
destination: C,
|
||||||
|
block: (Locale) -> R,
|
||||||
|
): C {
|
||||||
|
val len = size()
|
||||||
|
for (i in 0 until len) {
|
||||||
|
val item = get(i)
|
||||||
|
destination.add(block(item))
|
||||||
|
}
|
||||||
|
return destination
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <T> LocaleListCompat.map(block: (Locale) -> T): List<T> {
|
||||||
|
return mapTo(ArrayList(size()), block)
|
||||||
|
}
|
||||||
11
app/src/main/res/drawable/ic_locale.xml
Normal file
11
app/src/main/res/drawable/ic_locale.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12.87,15.07l-2.54,-2.51 0.03,-0.03c1.74,-1.94 2.98,-4.17 3.71,-6.53L17,6L17,4h-7L10,2L8,2v2L1,4v1.99h11.17C11.5,7.92 10.44,9.75 9,11.35 8.07,10.32 7.3,9.19 6.69,8h-2c0.73,1.63 1.73,3.17 2.98,4.56l-5.09,5.02L4,19l5,-5 3.11,3.11 0.76,-2.04zM18.5,10h-2L12,22h2l1.12,-3h4.75L21,22h2l-4.5,-12zM15.88,17l1.62,-4.33L19.12,17h-3.24z" />
|
||||||
|
</vector>
|
||||||
29
app/src/main/res/layout/dialog_onboard.xml
Normal file
29
app/src/main/res/layout/dialog_onboard.xml
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="?listPreferredItemPaddingStart"
|
||||||
|
android:paddingTop="6dp"
|
||||||
|
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||||
|
android:paddingBottom="6dp"
|
||||||
|
android:text="Select languages which you want to read manga. You can change it later in settings."
|
||||||
|
android:textAppearance="?android:textAppearanceSmall" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:scrollbars="vertical"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_source_locale" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
16
app/src/main/res/layout/item_source_locale.xml
Normal file
16
app/src/main/res/layout/item_source_locale.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<CheckedTextView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?android:listPreferredItemHeightSmall"
|
||||||
|
android:background="?selectableItemBackground"
|
||||||
|
android:drawableStart="?android:listChoiceIndicatorMultiple"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="?listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
|
android:textColor="?android:attr/textColorPrimary"
|
||||||
|
tools:text="@tools:sample/lorem[2]" />
|
||||||
12
app/src/main/res/menu/opt_sources.xml
Normal file
12
app/src/main/res/menu/opt_sources.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_languages"
|
||||||
|
android:icon="@drawable/ic_locale"
|
||||||
|
android:title="@string/languages"
|
||||||
|
app:showAsAction="ifRoom" />
|
||||||
|
|
||||||
|
</menu>
|
||||||
@@ -207,4 +207,7 @@
|
|||||||
<string name="password_length_hint">Пароль должен содержать не менее 4 символов</string>
|
<string name="password_length_hint">Пароль должен содержать не менее 4 символов</string>
|
||||||
<string name="hide_toolbar">Прятать заголовок при прокрутке</string>
|
<string name="hide_toolbar">Прятать заголовок при прокрутке</string>
|
||||||
<string name="search_only_on_s">Поиск только по %s</string>
|
<string name="search_only_on_s">Поиск только по %s</string>
|
||||||
|
<string name="other">Другие</string>
|
||||||
|
<string name="languages">Languages</string>
|
||||||
|
<string name="welcome">Welcome</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -210,4 +210,7 @@
|
|||||||
<string name="hide_toolbar">Hide toolbar when scrolling</string>
|
<string name="hide_toolbar">Hide toolbar when scrolling</string>
|
||||||
<string name="search_only_on_s">Search only on %s</string>
|
<string name="search_only_on_s">Search only on %s</string>
|
||||||
<string name="text_clear_search_history_prompt">Do you really want to remove all recent search queries? This action cannot be undone.</string>
|
<string name="text_clear_search_history_prompt">Do you really want to remove all recent search queries? This action cannot be undone.</string>
|
||||||
|
<string name="other">Other</string>
|
||||||
|
<string name="languages">Languages</string>
|
||||||
|
<string name="welcome">Welcome</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user