Show new sources on app startup
This commit is contained in:
@@ -134,6 +134,20 @@ class AppSettings(context: Context) {
|
|||||||
val isSourcesSelected: Boolean
|
val isSourcesSelected: Boolean
|
||||||
get() = KEY_SOURCES_HIDDEN in prefs
|
get() = KEY_SOURCES_HIDDEN in prefs
|
||||||
|
|
||||||
|
val newSources: Set<MangaSource>
|
||||||
|
get() {
|
||||||
|
val known = sourcesOrder.toSet()
|
||||||
|
val hidden = hiddenSources
|
||||||
|
return remoteMangaSources
|
||||||
|
.filterNotTo(EnumSet.noneOf(MangaSource::class.java)) { x ->
|
||||||
|
x.name in known || x.name in hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun markKnownSources(sources: Collection<MangaSource>) {
|
||||||
|
sourcesOrder = sourcesOrder + sources.map { it.name }
|
||||||
|
}
|
||||||
|
|
||||||
val isPagesNumbersEnabled: Boolean
|
val isPagesNumbersEnabled: Boolean
|
||||||
get() = prefs.getBoolean(KEY_PAGES_NUMBERS, false)
|
get() = prefs.getBoolean(KEY_PAGES_NUMBERS, false)
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ 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.AppUpdateChecker
|
import org.koitharu.kotatsu.settings.AppUpdateChecker
|
||||||
import org.koitharu.kotatsu.settings.SettingsActivity
|
import org.koitharu.kotatsu.settings.SettingsActivity
|
||||||
|
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
|
||||||
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
|
||||||
import org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment
|
import org.koitharu.kotatsu.suggestions.ui.SuggestionsFragment
|
||||||
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
|
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
|
||||||
@@ -390,10 +391,14 @@ class MainActivity :
|
|||||||
if (AppUpdateChecker.isUpdateSupported(this@MainActivity)) {
|
if (AppUpdateChecker.isUpdateSupported(this@MainActivity)) {
|
||||||
AppUpdateChecker(this@MainActivity).checkIfNeeded()
|
AppUpdateChecker(this@MainActivity).checkIfNeeded()
|
||||||
}
|
}
|
||||||
if (!get<AppSettings>().isSourcesSelected) {
|
val settings = get<AppSettings>()
|
||||||
withContext(Dispatchers.Main) {
|
when {
|
||||||
|
!settings.isSourcesSelected -> withContext(Dispatchers.Main) {
|
||||||
OnboardDialogFragment.showWelcome(supportFragmentManager)
|
OnboardDialogFragment.showWelcome(supportFragmentManager)
|
||||||
}
|
}
|
||||||
|
settings.newSources.isNotEmpty() -> withContext(Dispatchers.Main) {
|
||||||
|
NewSourcesDialogFragment.show(supportFragmentManager)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.newsources.NewSourcesViewModel
|
||||||
import org.koitharu.kotatsu.settings.onboard.OnboardViewModel
|
import org.koitharu.kotatsu.settings.onboard.OnboardViewModel
|
||||||
import org.koitharu.kotatsu.settings.protect.ProtectSetupViewModel
|
import org.koitharu.kotatsu.settings.protect.ProtectSetupViewModel
|
||||||
import org.koitharu.kotatsu.settings.sources.SourcesSettingsViewModel
|
import org.koitharu.kotatsu.settings.sources.SourcesSettingsViewModel
|
||||||
@@ -27,4 +28,5 @@ val settingsModule
|
|||||||
viewModel { ProtectSetupViewModel(get()) }
|
viewModel { ProtectSetupViewModel(get()) }
|
||||||
viewModel { OnboardViewModel(get()) }
|
viewModel { OnboardViewModel(get()) }
|
||||||
viewModel { SourcesSettingsViewModel(get()) }
|
viewModel { SourcesSettingsViewModel(get()) }
|
||||||
|
viewModel { NewSourcesViewModel(get()) }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.newsources
|
||||||
|
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.fragment.app.FragmentManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.koin.android.ext.android.get
|
||||||
|
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.AlertDialogFragment
|
||||||
|
import org.koitharu.kotatsu.databinding.DialogOnboardBinding
|
||||||
|
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigAdapter
|
||||||
|
import org.koitharu.kotatsu.settings.sources.adapter.SourceConfigListener
|
||||||
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
|
|
||||||
|
class NewSourcesDialogFragment :
|
||||||
|
AlertDialogFragment<DialogOnboardBinding>(),
|
||||||
|
SourceConfigListener,
|
||||||
|
DialogInterface.OnClickListener {
|
||||||
|
|
||||||
|
private val viewModel by viewModel<NewSourcesViewModel>()
|
||||||
|
|
||||||
|
override fun onInflateView(inflater: LayoutInflater, container: ViewGroup?): DialogOnboardBinding {
|
||||||
|
return DialogOnboardBinding.inflate(inflater, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
val adapter = SourceConfigAdapter(this, get(), viewLifecycleOwner)
|
||||||
|
binding.recyclerView.adapter = adapter
|
||||||
|
binding.textViewTitle.setText(R.string.new_sources_text)
|
||||||
|
|
||||||
|
viewModel.sources.observe(viewLifecycleOwner) { adapter.items = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBuildDialog(builder: MaterialAlertDialogBuilder) {
|
||||||
|
builder
|
||||||
|
.setPositiveButton(R.string.done, this)
|
||||||
|
.setCancelable(true)
|
||||||
|
.setTitle(R.string.remote_sources)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onClick(dialog: DialogInterface, which: Int) {
|
||||||
|
viewModel.apply()
|
||||||
|
dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onItemSettingsClick(item: SourceConfigItem.SourceItem) = Unit
|
||||||
|
|
||||||
|
override fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) {
|
||||||
|
viewModel.onItemEnabledChanged(item, isEnabled)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDragHandleTouch(holder: RecyclerView.ViewHolder) = Unit
|
||||||
|
|
||||||
|
override fun onHeaderClick(header: SourceConfigItem.LocaleGroup) = Unit
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
private const val TAG = "NewSources"
|
||||||
|
|
||||||
|
fun show(fm: FragmentManager) = NewSourcesDialogFragment().show(fm, TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.newsources
|
||||||
|
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import org.koitharu.kotatsu.base.ui.BaseViewModel
|
||||||
|
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||||
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
|
|
||||||
|
class NewSourcesViewModel(
|
||||||
|
private val settings: AppSettings,
|
||||||
|
) : BaseViewModel() {
|
||||||
|
|
||||||
|
val sources = MutableLiveData<List<SourceConfigItem>>()
|
||||||
|
private val initialList = settings.newSources
|
||||||
|
|
||||||
|
init {
|
||||||
|
buildList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onItemEnabledChanged(item: SourceConfigItem.SourceItem, isEnabled: Boolean) {
|
||||||
|
if (isEnabled) {
|
||||||
|
settings.hiddenSources -= item.source.name
|
||||||
|
} else {
|
||||||
|
settings.hiddenSources += item.source.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apply() {
|
||||||
|
settings.markKnownSources(initialList)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildList() {
|
||||||
|
val hidden = settings.hiddenSources
|
||||||
|
sources.value = initialList.map {
|
||||||
|
SourceConfigItem.SourceItem(
|
||||||
|
source = it,
|
||||||
|
summary = null,
|
||||||
|
isEnabled = it.name !in hidden,
|
||||||
|
isDraggable = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,7 @@ class OnboardDialogFragment : AlertDialogFragment<DialogOnboardBinding>(),
|
|||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val adapter = SourceLocalesAdapter(this)
|
val adapter = SourceLocalesAdapter(this)
|
||||||
binding.recyclerView.adapter = adapter
|
binding.recyclerView.adapter = adapter
|
||||||
|
binding.textViewTitle.setText(R.string.onboard_text)
|
||||||
viewModel.list.observeNotNull(viewLifecycleOwner) {
|
viewModel.list.observeNotNull(viewLifecycleOwner) {
|
||||||
adapter.items = it
|
adapter.items = it
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,10 @@ class SourcesSettingsFragment : BaseFragment<FragmentSettingsSourcesBinding>(),
|
|||||||
recyclerView: RecyclerView,
|
recyclerView: RecyclerView,
|
||||||
current: RecyclerView.ViewHolder,
|
current: RecyclerView.ViewHolder,
|
||||||
target: RecyclerView.ViewHolder,
|
target: RecyclerView.ViewHolder,
|
||||||
): Boolean = current.itemViewType == target.itemViewType
|
): Boolean = current.itemViewType == target.itemViewType && viewModel.canReorder(
|
||||||
|
current.bindingAdapterPosition,
|
||||||
|
target.bindingAdapterPosition,
|
||||||
|
)
|
||||||
|
|
||||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) = Unit
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,9 @@ fun sourceConfigDraggableItemDelegate(
|
|||||||
on = { item, _, _ -> item is SourceConfigItem.SourceItem && item.isDraggable }
|
on = { item, _, _ -> item is SourceConfigItem.SourceItem && item.isDraggable }
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val eventListener = object : View.OnClickListener, View.OnTouchListener,
|
val eventListener = object :
|
||||||
|
View.OnClickListener,
|
||||||
|
View.OnTouchListener,
|
||||||
CompoundButton.OnCheckedChangeListener {
|
CompoundButton.OnCheckedChangeListener {
|
||||||
override fun onClick(v: View?) = listener.onItemSettingsClick(item)
|
override fun onClick(v: View?) = listener.onItemSettingsClick(item)
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,15 @@
|
|||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="?listPreferredItemPaddingStart"
|
android:paddingStart="?listPreferredItemPaddingStart"
|
||||||
android:paddingTop="6dp"
|
android:paddingTop="6dp"
|
||||||
android:paddingEnd="?listPreferredItemPaddingEnd"
|
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||||
android:paddingBottom="6dp"
|
android:paddingBottom="6dp"
|
||||||
android:text="@string/onboard_text"
|
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium" />
|
tools:text="@string/onboard_text" />
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/recycler_view"
|
android:id="@+id/recycler_view"
|
||||||
|
|||||||
@@ -276,4 +276,6 @@
|
|||||||
<string name="download_slowdown_summary">Помогает избежать блокировки IP-адреса</string>
|
<string name="download_slowdown_summary">Помогает избежать блокировки IP-адреса</string>
|
||||||
<string name="local_manga_processing">Обработка сохранённой манги</string>
|
<string name="local_manga_processing">Обработка сохранённой манги</string>
|
||||||
<string name="chapters_will_removed_background">Главы будут удалены в фоновом режиме. Это может занять какое-то время</string>
|
<string name="chapters_will_removed_background">Главы будут удалены в фоновом режиме. Это может занять какое-то время</string>
|
||||||
|
<string name="hide">Скрыть</string>
|
||||||
|
<string name="new_sources_text">Доступны новые источники манги</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -280,4 +280,5 @@
|
|||||||
<string name="local_manga_processing">Saved manga processing</string>
|
<string name="local_manga_processing">Saved manga processing</string>
|
||||||
<string name="chapters_will_removed_background">Chapters will be removed in the background. It can take some time</string>
|
<string name="chapters_will_removed_background">Chapters will be removed in the background. It can take some time</string>
|
||||||
<string name="hide">Hide</string>
|
<string name="hide">Hide</string>
|
||||||
|
<string name="new_sources_text">New manga sources are available</string>
|
||||||
</resources>
|
</resources>
|
||||||
Reference in New Issue
Block a user