New welcome screen
This commit is contained in:
@@ -55,6 +55,7 @@ import org.koitharu.kotatsu.history.ui.HistoryListFragment
|
|||||||
import org.koitharu.kotatsu.local.ui.LocalStorageCleanupWorker
|
import org.koitharu.kotatsu.local.ui.LocalStorageCleanupWorker
|
||||||
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
import org.koitharu.kotatsu.main.ui.owners.AppBarOwner
|
||||||
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
import org.koitharu.kotatsu.main.ui.owners.BottomNavOwner
|
||||||
|
import org.koitharu.kotatsu.main.ui.welcome.WelcomeSheet
|
||||||
import org.koitharu.kotatsu.parsers.model.Manga
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaTag
|
import org.koitharu.kotatsu.parsers.model.MangaTag
|
||||||
@@ -66,7 +67,6 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
|
|||||||
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
|
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
import org.koitharu.kotatsu.settings.about.AppUpdateDialog
|
import org.koitharu.kotatsu.settings.about.AppUpdateDialog
|
||||||
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import com.google.android.material.R as materialR
|
import com.google.android.material.R as materialR
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), AppBarOwner, BottomNav
|
|||||||
viewModel.counters.observe(this, ::onCountersChanged)
|
viewModel.counters.observe(this, ::onCountersChanged)
|
||||||
viewModel.appUpdate.observe(this, MenuInvalidator(this))
|
viewModel.appUpdate.observe(this, MenuInvalidator(this))
|
||||||
viewModel.onFirstStart.observeEvent(this) {
|
viewModel.onFirstStart.observeEvent(this) {
|
||||||
OnboardDialogFragment.show(supportFragmentManager)
|
WelcomeSheet.show(supportFragmentManager)
|
||||||
}
|
}
|
||||||
viewModel.isIncognitoMode.observe(this) {
|
viewModel.isIncognitoMode.observe(this) {
|
||||||
adjustSearchUI(isSearchOpened(), false)
|
adjustSearchUI(isSearchOpened(), false)
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
package org.koitharu.kotatsu.main.ui.welcome
|
||||||
|
|
||||||
|
import android.accounts.AccountManager
|
||||||
|
import android.net.Uri
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.activity.result.ActivityResultCallback
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.core.view.isGone
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.fragment.app.viewModels
|
||||||
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.core.model.titleResId
|
||||||
|
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||||
|
import org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.observe
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.showDistinct
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.tryLaunch
|
||||||
|
import org.koitharu.kotatsu.databinding.SheetWelcomeBinding
|
||||||
|
import org.koitharu.kotatsu.filter.ui.model.FilterProperty
|
||||||
|
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||||
|
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||||
|
import org.koitharu.kotatsu.settings.backup.RestoreDialogFragment
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class WelcomeSheet : BaseAdaptiveSheet<SheetWelcomeBinding>(), ChipsView.OnChipClickListener, View.OnClickListener,
|
||||||
|
ActivityResultCallback<Uri?> {
|
||||||
|
|
||||||
|
private val viewModel by viewModels<WelcomeViewModel>()
|
||||||
|
|
||||||
|
private val backupSelectCall = registerForActivityResult(
|
||||||
|
ActivityResultContracts.OpenDocument(),
|
||||||
|
this,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): SheetWelcomeBinding {
|
||||||
|
return SheetWelcomeBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewBindingCreated(binding: SheetWelcomeBinding, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewBindingCreated(binding, savedInstanceState)
|
||||||
|
binding.textViewWelcomeTitle.isGone = resources.getBoolean(R.bool.is_tablet)
|
||||||
|
binding.chipsLocales.onChipClickListener = this
|
||||||
|
binding.chipsType.onChipClickListener = this
|
||||||
|
binding.chipBackup.setOnClickListener(this)
|
||||||
|
binding.chipSync.setOnClickListener(this)
|
||||||
|
|
||||||
|
viewModel.locales.observe(viewLifecycleOwner, ::onLocalesChanged)
|
||||||
|
viewModel.types.observe(viewLifecycleOwner, ::onTypesChanged)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onChipClick(chip: Chip, data: Any?) {
|
||||||
|
when (data) {
|
||||||
|
is ContentType -> viewModel.setTypeChecked(data, chip.isChecked)
|
||||||
|
is Locale? -> viewModel.setLocaleChecked(data, chip.isChecked)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(v: View) {
|
||||||
|
when (v.id) {
|
||||||
|
R.id.chip_backup -> {
|
||||||
|
if (!backupSelectCall.tryLaunch(arrayOf("*/*"))) {
|
||||||
|
Snackbar.make(
|
||||||
|
v, R.string.operation_not_supported, Snackbar.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
R.id.chip_sync -> {
|
||||||
|
val am = AccountManager.get(v.context)
|
||||||
|
val accountType = getString(R.string.account_type_sync)
|
||||||
|
am.addAccount(accountType, accountType, null, null, requireActivity(), null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(result: Uri?) {
|
||||||
|
if (result != null) {
|
||||||
|
RestoreDialogFragment.show(parentFragmentManager, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onLocalesChanged(value: FilterProperty<Locale?>) {
|
||||||
|
val chips = viewBinding?.chipsLocales ?: return
|
||||||
|
chips.setChips(
|
||||||
|
value.availableItems.map {
|
||||||
|
ChipsView.ChipModel(
|
||||||
|
tint = 0,
|
||||||
|
title = it?.getDisplayLanguage(it)?.toTitleCase(it) ?: getString(R.string.various_languages),
|
||||||
|
icon = 0,
|
||||||
|
isCheckable = true,
|
||||||
|
isChecked = it in value.selectedItems,
|
||||||
|
data = it,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onTypesChanged(value: FilterProperty<ContentType>) {
|
||||||
|
val chips = viewBinding?.chipsType ?: return
|
||||||
|
chips.setChips(
|
||||||
|
value.availableItems.map {
|
||||||
|
ChipsView.ChipModel(
|
||||||
|
tint = 0,
|
||||||
|
title = getString(it.titleResId),
|
||||||
|
icon = 0,
|
||||||
|
isCheckable = true,
|
||||||
|
isChecked = it in value.selectedItems,
|
||||||
|
data = it,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG = "WelcomeSheet"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager) = WelcomeSheet().showDistinct(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
package org.koitharu.kotatsu.main.ui.welcome
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.os.ConfigurationCompat
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.util.LocaleComparator
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.sortedWithSafe
|
||||||
|
import org.koitharu.kotatsu.core.util.ext.toList
|
||||||
|
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
||||||
|
import org.koitharu.kotatsu.filter.ui.model.FilterProperty
|
||||||
|
import org.koitharu.kotatsu.parsers.model.ContentType
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||||
|
import java.util.EnumSet
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class WelcomeViewModel @Inject constructor(
|
||||||
|
private val repository: MangaSourcesRepository,
|
||||||
|
@ApplicationContext context: Context,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
private val allSources = repository.allMangaSources
|
||||||
|
private val localesGroups by lazy { allSources.groupBy { it.locale?.let { x -> Locale(x) } } }
|
||||||
|
|
||||||
|
private var updateJob: Job
|
||||||
|
|
||||||
|
val locales = MutableStateFlow(
|
||||||
|
FilterProperty<Locale?>(
|
||||||
|
availableItems = listOf(null),
|
||||||
|
selectedItems = setOf(null),
|
||||||
|
isLoading = true,
|
||||||
|
error = null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val types = MutableStateFlow(
|
||||||
|
FilterProperty(
|
||||||
|
availableItems = ContentType.entries.toList(),
|
||||||
|
selectedItems = setOf(ContentType.MANGA),
|
||||||
|
isLoading = false,
|
||||||
|
error = null,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
updateJob = launchJob(Dispatchers.Default) {
|
||||||
|
val languages = localesGroups.keys.associateBy { x -> x?.language }
|
||||||
|
val selectedLocales = HashSet<Locale?>(2)
|
||||||
|
selectedLocales += ConfigurationCompat.getLocales(context.resources.configuration).toList()
|
||||||
|
.firstNotNullOfOrNull { lc -> languages[lc.language] }
|
||||||
|
selectedLocales += null
|
||||||
|
locales.value = locales.value.copy(
|
||||||
|
availableItems = localesGroups.keys.sortedWithSafe(nullsFirst(LocaleComparator())),
|
||||||
|
selectedItems = selectedLocales,
|
||||||
|
isLoading = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setLocaleChecked(locale: Locale?, isChecked: Boolean) {
|
||||||
|
val snapshot = locales.value
|
||||||
|
locales.value = snapshot.copy(
|
||||||
|
selectedItems = if (isChecked) {
|
||||||
|
snapshot.selectedItems + locale
|
||||||
|
} else {
|
||||||
|
snapshot.selectedItems - locale
|
||||||
|
},
|
||||||
|
)
|
||||||
|
val prevJob = updateJob
|
||||||
|
updateJob = launchJob(Dispatchers.Default) {
|
||||||
|
prevJob.join()
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTypeChecked(type: ContentType, isChecked: Boolean) {
|
||||||
|
val snapshot = types.value
|
||||||
|
types.value = snapshot.copy(
|
||||||
|
selectedItems = if (isChecked) {
|
||||||
|
snapshot.selectedItems + type
|
||||||
|
} else {
|
||||||
|
snapshot.selectedItems - type
|
||||||
|
},
|
||||||
|
)
|
||||||
|
val prevJob = updateJob
|
||||||
|
updateJob = launchJob(Dispatchers.Default) {
|
||||||
|
prevJob.join()
|
||||||
|
commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun commit() {
|
||||||
|
val languages = locales.value.selectedItems.mapToSet { it?.language }
|
||||||
|
val types = types.value.selectedItems
|
||||||
|
val enabledSources = allSources.filterTo(EnumSet.noneOf(MangaSource::class.java)) { x ->
|
||||||
|
x.contentType in types && x.locale in languages
|
||||||
|
}
|
||||||
|
repository.setSourcesEnabledExclusive(enabledSources)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard
|
|
||||||
|
|
||||||
import android.content.DialogInterface
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.FragmentManager
|
|
||||||
import androidx.fragment.app.viewModels
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.ui.AlertDialogFragment
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.observe
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.showAllowStateLoss
|
|
||||||
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocaleListener
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.adapter.SourceLocalesAdapter
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
|
||||||
class OnboardDialogFragment :
|
|
||||||
AlertDialogFragment<DialogOnboardBinding>(),
|
|
||||||
DialogInterface.OnClickListener, SourceLocaleListener {
|
|
||||||
|
|
||||||
private val viewModel by viewModels<OnboardViewModel>()
|
|
||||||
|
|
||||||
override fun onCreateViewBinding(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
) = DialogOnboardBinding.inflate(inflater, container, false)
|
|
||||||
|
|
||||||
override fun onBuildDialog(builder: MaterialAlertDialogBuilder): MaterialAlertDialogBuilder {
|
|
||||||
super.onBuildDialog(builder)
|
|
||||||
.setPositiveButton(R.string.done, this)
|
|
||||||
.setCancelable(false)
|
|
||||||
builder.setTitle(R.string.welcome)
|
|
||||||
return builder
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewBindingCreated(binding: DialogOnboardBinding, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewBindingCreated(binding, savedInstanceState)
|
|
||||||
val adapter = SourceLocalesAdapter(this)
|
|
||||||
binding.recyclerView.adapter = adapter
|
|
||||||
binding.textViewTitle.setText(R.string.onboard_text)
|
|
||||||
viewModel.list.observe(viewLifecycleOwner, adapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onItemCheckedChanged(item: SourceLocale, isChecked: Boolean) {
|
|
||||||
viewModel.setItemChecked(item.key, isChecked)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(dialog: DialogInterface, which: Int) {
|
|
||||||
when (which) {
|
|
||||||
DialogInterface.BUTTON_POSITIVE -> dialog.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
|
|
||||||
private const val TAG = "OnboardDialog"
|
|
||||||
|
|
||||||
fun show(fm: FragmentManager) = OnboardDialogFragment().showAllowStateLoss(fm, TAG)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.core.os.ConfigurationCompat
|
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
|
||||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
|
||||||
import org.koitharu.kotatsu.core.util.LocaleComparator
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.sortedWithSafe
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.toList
|
|
||||||
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
|
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
|
||||||
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
|
||||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
|
||||||
import java.util.EnumSet
|
|
||||||
import java.util.Locale
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
@HiltViewModel
|
|
||||||
class OnboardViewModel @Inject constructor(
|
|
||||||
private val repository: MangaSourcesRepository,
|
|
||||||
@ApplicationContext context: Context,
|
|
||||||
) : BaseViewModel() {
|
|
||||||
|
|
||||||
private val allSources = repository.allMangaSources
|
|
||||||
private val locales = allSources.groupBy { it.locale }
|
|
||||||
private val selectedLocales = HashSet<String?>()
|
|
||||||
val list = MutableStateFlow<List<SourceLocale>?>(null)
|
|
||||||
private var updateJob: Job
|
|
||||||
|
|
||||||
init {
|
|
||||||
updateJob = launchJob(Dispatchers.Default) {
|
|
||||||
if (repository.isSetupRequired()) {
|
|
||||||
selectedLocales += ConfigurationCompat.getLocales(context.resources.configuration).toList()
|
|
||||||
.firstOrNull { lc -> lc.language in locales.keys }?.language
|
|
||||||
selectedLocales += null
|
|
||||||
} else {
|
|
||||||
selectedLocales.addAll(
|
|
||||||
repository.getEnabledSources().mapNotNullToSet { x -> x.locale },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
commit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setItemChecked(key: String?, isChecked: Boolean) {
|
|
||||||
val isModified = if (isChecked) {
|
|
||||||
selectedLocales.add(key)
|
|
||||||
} else {
|
|
||||||
selectedLocales.remove(key)
|
|
||||||
}
|
|
||||||
if (isModified) {
|
|
||||||
val prevJob = updateJob
|
|
||||||
updateJob = launchJob(Dispatchers.Default) {
|
|
||||||
prevJob.join()
|
|
||||||
commit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun commit() {
|
|
||||||
val enabledSources = allSources.filterTo(EnumSet.noneOf(MangaSource::class.java)) { x ->
|
|
||||||
x.locale in selectedLocales
|
|
||||||
}
|
|
||||||
repository.setSourcesEnabledExclusive(enabledSources)
|
|
||||||
list.value = locales.map { (key, srcs) ->
|
|
||||||
val locale = key?.let { Locale(it) }
|
|
||||||
SourceLocale(
|
|
||||||
key = key,
|
|
||||||
title = locale?.getDisplayLanguage(locale)?.toTitleCase(locale),
|
|
||||||
summary = srcs.joinToString { it.title },
|
|
||||||
isChecked = key in selectedLocales,
|
|
||||||
)
|
|
||||||
}.sortedWithSafe(SourceLocaleComparator())
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SourceLocaleComparator : Comparator<SourceLocale> {
|
|
||||||
|
|
||||||
private val delegate = nullsFirst(LocaleComparator())
|
|
||||||
|
|
||||||
override fun compare(a: SourceLocale, b: SourceLocale): Int {
|
|
||||||
val localeA = a.key?.let { Locale(it) }
|
|
||||||
val localeB = b.key?.let { Locale(it) }
|
|
||||||
return delegate.compare(localeA, localeB)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard.adapter
|
|
||||||
|
|
||||||
import android.widget.CompoundButton
|
|
||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.setChecked
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.textAndVisible
|
|
||||||
import org.koitharu.kotatsu.databinding.ItemSourceLocaleBinding
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
|
||||||
|
|
||||||
fun sourceLocaleAD(
|
|
||||||
listener: SourceLocaleListener,
|
|
||||||
) = adapterDelegateViewBinding<SourceLocale, SourceLocale, ItemSourceLocaleBinding>(
|
|
||||||
{ inflater, parent -> ItemSourceLocaleBinding.inflate(inflater, parent, false) },
|
|
||||||
) {
|
|
||||||
|
|
||||||
val checkedChangeListener = CompoundButton.OnCheckedChangeListener { _, isChecked ->
|
|
||||||
listener.onItemCheckedChanged(item, isChecked)
|
|
||||||
}
|
|
||||||
binding.switchToggle.setOnCheckedChangeListener(checkedChangeListener)
|
|
||||||
|
|
||||||
bind { payloads ->
|
|
||||||
binding.textViewTitle.text = item.title ?: getString(R.string.different_languages)
|
|
||||||
binding.textViewDescription.textAndVisible = item.summary
|
|
||||||
binding.switchToggle.setOnCheckedChangeListener(null)
|
|
||||||
binding.switchToggle.setChecked(item.isChecked, payloads.isNotEmpty())
|
|
||||||
binding.switchToggle.setOnCheckedChangeListener(checkedChangeListener)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard.adapter
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
|
||||||
|
|
||||||
interface SourceLocaleListener {
|
|
||||||
|
|
||||||
fun onItemCheckedChanged(item: SourceLocale, isChecked: Boolean)
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard.adapter
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.core.ui.BaseListAdapter
|
|
||||||
import org.koitharu.kotatsu.settings.onboard.model.SourceLocale
|
|
||||||
|
|
||||||
class SourceLocalesAdapter(
|
|
||||||
listener: SourceLocaleListener,
|
|
||||||
) : BaseListAdapter<SourceLocale>() {
|
|
||||||
|
|
||||||
init {
|
|
||||||
delegatesManager.addDelegate(sourceLocaleAD(listener))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.onboard.model
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.list.ui.ListModelDiffCallback
|
|
||||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
data class SourceLocale(
|
|
||||||
val key: String?,
|
|
||||||
val title: String?,
|
|
||||||
val summary: String?,
|
|
||||||
val isChecked: Boolean,
|
|
||||||
) : ListModel, Comparable<SourceLocale> {
|
|
||||||
|
|
||||||
override fun areItemsTheSame(other: ListModel): Boolean {
|
|
||||||
return other is SourceLocale && key == other.key
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getChangePayload(previousState: ListModel): Any? {
|
|
||||||
return if (previousState is SourceLocale && previousState.isChecked != isChecked) {
|
|
||||||
ListModelDiffCallback.PAYLOAD_CHECKED_CHANGED
|
|
||||||
} else {
|
|
||||||
super.getChangePayload(previousState)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
115
app/src/main/res/layout/sheet_welcome.xml
Normal file
115
app/src/main/res/layout/sheet_welcome.xml
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<?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"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||||
|
android:id="@+id/headerBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:title="@string/welcome" />
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/scrollView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:scrollIndicators="top">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingBottom="@dimen/margin_normal">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_welcome_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/welcome"
|
||||||
|
android:textAppearance="?textAppearanceTitleSmall" />
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:scrollbars="none">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
|
app:singleLine="true">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_backup"
|
||||||
|
style="@style/Widget.Kotatsu.Chip.Assist"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/restore_backup"
|
||||||
|
app:chipIcon="@drawable/ic_backup_restore" />
|
||||||
|
|
||||||
|
<com.google.android.material.chip.Chip
|
||||||
|
android:id="@+id/chip_sync"
|
||||||
|
style="@style/Widget.Kotatsu.Chip.Assist"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/sync_auth"
|
||||||
|
app:chipIcon="@drawable/ic_sync" />
|
||||||
|
|
||||||
|
</com.google.android.material.chip.ChipGroup>
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_hint"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
|
android:text="@string/welcome_text"
|
||||||
|
android:textAppearance="?textAppearanceBodyMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_locales_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||||
|
android:layout_marginTop="@dimen/margin_normal"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/languages"
|
||||||
|
android:textAppearance="?textAppearanceTitleSmall" />
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||||
|
android:id="@+id/chips_locales"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_normal"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
|
app:chipStyle="@style/Widget.Kotatsu.Chip.Filter" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_type_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||||
|
android:layout_marginTop="@dimen/margin_normal"
|
||||||
|
android:singleLine="true"
|
||||||
|
android:text="@string/type"
|
||||||
|
android:textAppearance="?textAppearanceTitleSmall" />
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.core.ui.widgets.ChipsView
|
||||||
|
android:id="@+id/chips_type"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/margin_normal"
|
||||||
|
android:paddingHorizontal="@dimen/margin_normal"
|
||||||
|
app:chipStyle="@style/Widget.Kotatsu.Chip.Filter" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -544,4 +544,6 @@
|
|||||||
<string name="error_filter_states_genre_not_supported">Filtering by both genres and states is not supported by this source</string>
|
<string name="error_filter_states_genre_not_supported">Filtering by both genres and states is not supported by this source</string>
|
||||||
<string name="genres_search_hint">Start typing the genre name</string>
|
<string name="genres_search_hint">Start typing the genre name</string>
|
||||||
<string name="disable_battery_optimization_summary_downloads">Might help with getting the download started if you have any issues with it</string>
|
<string name="disable_battery_optimization_summary_downloads">Might help with getting the download started if you have any issues with it</string>
|
||||||
|
<string name="welcome_text">Please select which content sources you would like to enable. This can also be configured later in settings</string>
|
||||||
|
<string name="sync_auth">Login to sync account</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -124,6 +124,8 @@
|
|||||||
|
|
||||||
<style name="Widget.Kotatsu.Chip.Filter" parent="Widget.Material3.Chip.Filter" />
|
<style name="Widget.Kotatsu.Chip.Filter" parent="Widget.Material3.Chip.Filter" />
|
||||||
|
|
||||||
|
<style name="Widget.Kotatsu.Chip.Assist" parent="Widget.Material3.Chip.Assist" />
|
||||||
|
|
||||||
<style name="Widget.Kotatsu.Button.More" parent="Widget.Material3.Button.TextButton">
|
<style name="Widget.Kotatsu.Button.More" parent="Widget.Material3.Button.TextButton">
|
||||||
<item name="android:minWidth">48dp</item>
|
<item name="android:minWidth">48dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user