From bdaf3da7e003377988c88a938eb1291d358dfc74 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Tue, 12 Dec 2023 15:58:45 +0200 Subject: [PATCH] New welcome screen --- .../koitharu/kotatsu/main/ui/MainActivity.kt | 4 +- .../kotatsu/main/ui/welcome/WelcomeSheet.kt | 127 ++++++++++++++++++ .../main/ui/welcome/WelcomeViewModel.kt | 107 +++++++++++++++ .../settings/onboard/OnboardDialogFragment.kt | 64 --------- .../settings/onboard/OnboardViewModel.kt | 91 ------------- .../onboard/adapter/SourceLocaleAD.kt | 29 ---- .../onboard/adapter/SourceLocaleListener.kt | 8 -- .../onboard/adapter/SourceLocalesAdapter.kt | 13 -- .../settings/onboard/model/SourceLocale.kt | 35 ----- app/src/main/res/layout/sheet_welcome.xml | 115 ++++++++++++++++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/values/styles.xml | 2 + 12 files changed, 355 insertions(+), 242 deletions(-) create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeSheet.kt create mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeViewModel.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleAD.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleListener.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocalesAdapter.kt delete mode 100644 app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/model/SourceLocale.kt create mode 100644 app/src/main/res/layout/sheet_welcome.xml diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt index 4b86ef110..1e0c356a0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/MainActivity.kt @@ -55,6 +55,7 @@ import org.koitharu.kotatsu.history.ui.HistoryListFragment import org.koitharu.kotatsu.local.ui.LocalStorageCleanupWorker import org.koitharu.kotatsu.main.ui.owners.AppBarOwner 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.MangaSource 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.settings.SettingsActivity import org.koitharu.kotatsu.settings.about.AppUpdateDialog -import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment import javax.inject.Inject import com.google.android.material.R as materialR @@ -142,7 +142,7 @@ class MainActivity : BaseActivity(), AppBarOwner, BottomNav viewModel.counters.observe(this, ::onCountersChanged) viewModel.appUpdate.observe(this, MenuInvalidator(this)) viewModel.onFirstStart.observeEvent(this) { - OnboardDialogFragment.show(supportFragmentManager) + WelcomeSheet.show(supportFragmentManager) } viewModel.isIncognitoMode.observe(this) { adjustSearchUI(isSearchOpened(), false) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeSheet.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeSheet.kt new file mode 100644 index 000000000..7b0d824b1 --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeSheet.kt @@ -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(), ChipsView.OnChipClickListener, View.OnClickListener, + ActivityResultCallback { + + private val viewModel by viewModels() + + 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) { + 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) { + 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) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeViewModel.kt new file mode 100644 index 000000000..311a6d64b --- /dev/null +++ b/app/src/main/kotlin/org/koitharu/kotatsu/main/ui/welcome/WelcomeViewModel.kt @@ -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( + 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(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) + } +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt deleted file mode 100644 index 63b8bf64e..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardDialogFragment.kt +++ /dev/null @@ -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(), - DialogInterface.OnClickListener, SourceLocaleListener { - - private val viewModel by viewModels() - - 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) - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt deleted file mode 100644 index 1e226870f..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/OnboardViewModel.kt +++ /dev/null @@ -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() - val list = MutableStateFlow?>(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 { - - 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) - } - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleAD.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleAD.kt deleted file mode 100644 index f5ae32b15..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleAD.kt +++ /dev/null @@ -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( - { 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) - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleListener.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleListener.kt deleted file mode 100644 index 087849a0c..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocaleListener.kt +++ /dev/null @@ -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) -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocalesAdapter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocalesAdapter.kt deleted file mode 100644 index a90329b74..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/adapter/SourceLocalesAdapter.kt +++ /dev/null @@ -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() { - - init { - delegatesManager.addDelegate(sourceLocaleAD(listener)) - } -} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/model/SourceLocale.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/model/SourceLocale.kt deleted file mode 100644 index ff8ea75c3..000000000 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/onboard/model/SourceLocale.kt +++ /dev/null @@ -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 { - - 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) - } - } -} diff --git a/app/src/main/res/layout/sheet_welcome.xml b/app/src/main/res/layout/sheet_welcome.xml new file mode 100644 index 000000000..5ba2efeb6 --- /dev/null +++ b/app/src/main/res/layout/sheet_welcome.xml @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 517127409..53e7f203d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -544,4 +544,6 @@ Filtering by both genres and states is not supported by this source Start typing the genre name Might help with getting the download started if you have any issues with it + Please select which content sources you would like to enable. This can also be configured later in settings + Login to sync account diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index af2f217b9..72a8a8c73 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -124,6 +124,8 @@