diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 83b0d3cf3..ffcc55356 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -66,6 +66,9 @@
+
(),
RecyclerViewOwner,
- ExploreListEventListener, OnListItemClickListener {
+ ExploreListEventListener,
+ OnListItemClickListener {
private val viewModel by viewModel()
private var exploreAdapter: ExploreAdapter? = null
@@ -78,6 +80,7 @@ class ExploreFragment : BaseFragment(),
R.id.button_history -> HistoryActivity.newIntent(v.context)
R.id.button_local -> MangaListActivity.newIntent(v.context, MangaSource.LOCAL)
R.id.button_bookmarks -> BookmarksActivity.newIntent(v.context)
+ R.id.button_suggestions -> SuggestionsActivity.newIntent(v.context)
else -> return
}
startActivity(intent)
@@ -90,7 +93,7 @@ class ExploreFragment : BaseFragment(),
override fun onRetryClick(error: Throwable) = Unit
- override fun onEmptyActionClick() = Unit
+ override fun onEmptyActionClick() = onManageClick(requireView())
companion object {
diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt
index c60b60eb0..8d5b2c962 100644
--- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/ExploreViewModel.kt
@@ -19,7 +19,11 @@ class ExploreViewModel(
) : BaseViewModel() {
val content: LiveData> = settings.observe()
- .filter { it == AppSettings.KEY_SOURCES_HIDDEN || it == AppSettings.KEY_SOURCES_ORDER }
+ .filter {
+ it == AppSettings.KEY_SOURCES_HIDDEN ||
+ it == AppSettings.KEY_SOURCES_ORDER ||
+ it == AppSettings.KEY_SUGGESTIONS
+ }
.onStart { emit("") }
.map { settings.getMangaSources(includeHidden = false) }
.distinctUntilChanged()
@@ -27,13 +31,20 @@ class ExploreViewModel(
.asLiveDataDistinct(viewModelScope.coroutineContext + Dispatchers.Default, emptyList())
private fun buildList(sources: List): List {
- val result = ArrayList(sources.size + 2)
- result += ExploreItem.Buttons
+ val result = ArrayList(sources.size + 3)
+ result += ExploreItem.Buttons(
+ isSuggestionsEnabled = settings.isSuggestionsEnabled,
+ )
+ result += ExploreItem.Header(R.string.remote_sources, sources.isNotEmpty())
if (sources.isNotEmpty()) {
- result += ExploreItem.Header(R.string.enabled_sources)
sources.mapTo(result) { ExploreItem.Source(it) }
} else {
- // TODO
+ result += ExploreItem.EmptyHint(
+ icon = R.drawable.ic_empty_search,
+ textPrimary = R.string.no_manga_sources,
+ textSecondary = R.string.no_manga_sources_text,
+ actionStringRes = R.string.manage,
+ )
}
return result
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapter.kt
index 4d8c47455..e9e0f9aff 100644
--- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapter.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapter.kt
@@ -16,4 +16,5 @@ class ExploreAdapter(
exploreButtonsAD(listener),
exploreSourcesHeaderAD(listener),
exploreSourceItemAD(coil, clickListener, lifecycleOwner),
+ exploreEmptyHintListAD(listener),
)
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
index 5df25dbc5..7a53d2402 100644
--- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/adapter/ExploreAdapterDelegates.kt
@@ -1,19 +1,22 @@
package org.koitharu.kotatsu.explore.ui.adapter
import android.view.View
+import androidx.core.view.isVisible
import androidx.lifecycle.LifecycleOwner
import coil.ImageLoader
import coil.request.Disposable
import coil.request.ImageRequest
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
-import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
+import org.koitharu.kotatsu.databinding.ItemEmptyCardBinding
import org.koitharu.kotatsu.databinding.ItemExploreButtonsBinding
import org.koitharu.kotatsu.databinding.ItemExploreHeaderBinding
import org.koitharu.kotatsu.databinding.ItemExploreSourceBinding
import org.koitharu.kotatsu.explore.ui.model.ExploreItem
+import org.koitharu.kotatsu.list.ui.adapter.ListStateHolderListener
import org.koitharu.kotatsu.utils.ext.enqueueWith
+import org.koitharu.kotatsu.utils.ext.setTextAndVisible
import org.koitharu.kotatsu.utils.image.FaviconFallbackDrawable
fun exploreButtonsAD(
@@ -26,6 +29,10 @@ fun exploreButtonsAD(
binding.buttonHistory.setOnClickListener(clickListener)
binding.buttonLocal.setOnClickListener(clickListener)
binding.buttonSuggestions.setOnClickListener(clickListener)
+
+ bind {
+ binding.buttonSuggestions.isVisible = item.isSuggestionsEnabled
+ }
}
fun exploreSourcesHeaderAD(
@@ -41,7 +48,8 @@ fun exploreSourcesHeaderAD(
binding.buttonMore.setOnClickListener(listenerAdapter)
bind {
- binding.textViewTitle.setText(R.string.remote_sources)
+ binding.textViewTitle.setText(item.titleResId)
+ binding.buttonMore.isVisible = item.isButtonVisible
}
}
@@ -77,4 +85,20 @@ fun exploreSourceItemAD(
imageRequest?.dispose()
imageRequest = null
}
+}
+
+fun exploreEmptyHintListAD(
+ listener: ListStateHolderListener,
+) = adapterDelegateViewBinding(
+ { inflater, parent -> ItemEmptyCardBinding.inflate(inflater, parent, false) }
+) {
+
+ binding.buttonRetry.setOnClickListener { listener.onEmptyActionClick() }
+
+ bind {
+ binding.icon.setImageResource(item.icon)
+ binding.textPrimary.setText(item.textPrimary)
+ binding.textSecondary.setTextAndVisible(item.textSecondary)
+ binding.buttonRetry.setTextAndVisible(item.actionStringRes)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt b/app/src/main/java/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt
index 59e6d174a..2c1a593d7 100644
--- a/app/src/main/java/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/explore/ui/model/ExploreItem.kt
@@ -1,26 +1,56 @@
package org.koitharu.kotatsu.explore.ui.model
import android.net.Uri
+import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
+import org.koitharu.kotatsu.list.ui.model.EmptyState
import org.koitharu.kotatsu.list.ui.model.ListModel
import org.koitharu.kotatsu.parsers.model.MangaSource
sealed interface ExploreItem : ListModel {
- object Buttons : ExploreItem
-
- class Header(
- @StringRes val titleResId: Int,
+ class Buttons(
+ val isSuggestionsEnabled: Boolean
) : ExploreItem {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
- other as Header
- return titleResId == other.titleResId
+
+ other as Buttons
+
+ if (isSuggestionsEnabled != other.isSuggestionsEnabled) return false
+
+ return true
}
- override fun hashCode(): Int = titleResId
+ override fun hashCode(): Int {
+ return isSuggestionsEnabled.hashCode()
+ }
+ }
+
+ class Header(
+ @StringRes val titleResId: Int,
+ val isButtonVisible: Boolean,
+ ) : ExploreItem {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as Header
+
+ if (titleResId != other.titleResId) return false
+ if (isButtonVisible != other.isButtonVisible) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = titleResId
+ result = 31 * result + isButtonVisible.hashCode()
+ return result
+ }
}
class Source(
@@ -46,4 +76,10 @@ sealed interface ExploreItem : ListModel {
}
}
+ class EmptyHint(
+ @DrawableRes icon: Int,
+ @StringRes textPrimary: Int,
+ @StringRes textSecondary: Int,
+ @StringRes actionStringRes: Int,
+ ) : EmptyState(icon, textPrimary, textSecondary, actionStringRes), ExploreItem
}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryMenuProvider.kt b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryMenuProvider.kt
index 7a7354328..849506353 100644
--- a/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryMenuProvider.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/library/ui/LibraryMenuProvider.kt
@@ -38,7 +38,7 @@ class LibraryMenuProvider(
}
private fun showClearHistoryDialog() {
- val selectionListener = RememberSelectionDialogListener(-1)
+ val selectionListener = RememberSelectionDialogListener(2)
MaterialAlertDialogBuilder(context, materialR.style.ThemeOverlay_Material3_MaterialAlertDialog_Centered)
.setTitle(R.string.clear_history)
.setSingleChoiceItems(
diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt
index eff8b5462..aa1e88f10 100644
--- a/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/MangaListFragment.kt
@@ -168,21 +168,20 @@ abstract class MangaListFragment :
}
override fun onWindowInsetsChanged(insets: Insets) {
- val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top
binding.root.updatePadding(
left = insets.left,
right = insets.right,
)
+ binding.recyclerView.updatePadding(
+ bottom = insets.bottom,
+ )
if (activity is MainActivity) {
+ val headerHeight = (activity as? AppBarOwner)?.appBar?.measureHeight() ?: insets.top
binding.swipeRefreshLayout.setProgressViewOffset(
true,
headerHeight + resources.resolveDp(-72),
headerHeight + resources.resolveDp(10),
)
- } else {
- binding.recyclerView.updatePadding(
- bottom = insets.bottom,
- )
}
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt
index 179bb25b5..ddef7eac6 100644
--- a/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/model/EmptyState.kt
@@ -3,9 +3,32 @@ package org.koitharu.kotatsu.list.ui.model
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
-data class EmptyState(
+open class EmptyState(
@DrawableRes val icon: Int,
@StringRes val textPrimary: Int,
@StringRes val textSecondary: Int,
@StringRes val actionStringRes: Int,
-) : ListModel
\ No newline at end of file
+) : ListModel {
+
+ override fun equals(other: Any?): Boolean {
+ if (this === other) return true
+ if (javaClass != other?.javaClass) return false
+
+ other as EmptyState
+
+ if (icon != other.icon) return false
+ if (textPrimary != other.textPrimary) return false
+ if (textSecondary != other.textSecondary) return false
+ if (actionStringRes != other.actionStringRes) return false
+
+ return true
+ }
+
+ override fun hashCode(): Int {
+ var result = icon
+ result = 31 * result + textPrimary
+ result = 31 * result + textSecondary
+ result = 31 * result + actionStringRes
+ return result
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
index 4b4b26dab..3fd5bb551 100644
--- a/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/main/ui/MainActivity.kt
@@ -30,7 +30,6 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.ActivityMainBinding
import org.koitharu.kotatsu.details.ui.DetailsActivity
import org.koitharu.kotatsu.explore.ui.ExploreFragment
-import org.koitharu.kotatsu.favourites.ui.FavouritesContainerFragment
import org.koitharu.kotatsu.library.ui.LibraryFragment
import org.koitharu.kotatsu.parsers.model.Manga
import org.koitharu.kotatsu.parsers.model.MangaTag
@@ -42,6 +41,7 @@ import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionFragment
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionViewModel
import org.koitharu.kotatsu.settings.AppUpdateChecker
+import org.koitharu.kotatsu.settings.SettingsHeadersFragment
import org.koitharu.kotatsu.settings.newsources.NewSourcesDialogFragment
import org.koitharu.kotatsu.settings.onboard.OnboardDialogFragment
import org.koitharu.kotatsu.suggestions.ui.SuggestionsWorker
@@ -256,6 +256,10 @@ class MainActivity :
setPrimaryFragment(FeedFragment.newInstance())
binding.root.isLiftAppBarOnScroll = true // --//--
}
+ R.id.nav_tools -> {
+ setPrimaryFragment(SettingsHeadersFragment())
+ binding.root.isLiftAppBarOnScroll = true // --//--
+ }
else -> return false
}
appBar.setExpanded(true)
diff --git a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt b/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt
index 3ecc7d9ed..d01e19ea6 100644
--- a/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/search/ui/MangaListActivity.kt
@@ -55,13 +55,7 @@ class MangaListActivity : BaseActivity() {
left = insets.left,
right = insets.right
)
- updateLayoutParams {
- topMargin = insets.top
- }
}
- binding.container.updatePadding(
- bottom = insets.bottom
- )
}
private class ApplyFilterRunnable(
diff --git a/app/src/main/java/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt
index ed9cae71e..90e6e6c8e 100644
--- a/app/src/main/java/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt
+++ b/app/src/main/java/org/koitharu/kotatsu/settings/ContentSettingsFragment.kt
@@ -5,7 +5,6 @@ import android.os.Bundle
import android.view.View
import androidx.preference.ListPreference
import androidx.preference.Preference
-import java.io.File
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
@@ -19,6 +18,7 @@ import org.koitharu.kotatsu.settings.utils.SliderPreference
import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.setDefaultValueCompat
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
+import java.io.File
class ContentSettingsFragment :
BasePreferenceFragment(R.string.content),
@@ -30,9 +30,6 @@ class ContentSettingsFragment :
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_content)
- findPreference(AppSettings.KEY_SUGGESTIONS)?.setSummary(
- if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
- )
findPreference(AppSettings.KEY_DOWNLOADS_PARALLELISM)?.run {
summary = value.toString()
setOnPreferenceChangeListener { preference, newValue ->
@@ -54,6 +51,9 @@ class ContentSettingsFragment :
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
findPreference(AppSettings.KEY_LOCAL_STORAGE)?.bindStorageName()
+ findPreference(AppSettings.KEY_SUGGESTIONS)?.setSummary(
+ if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
+ )
bindRemoteSourcesSummary()
settings.subscribe(this)
}
diff --git a/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsActivity.kt b/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsActivity.kt
new file mode 100644
index 000000000..46ff3fc5c
--- /dev/null
+++ b/app/src/main/java/org/koitharu/kotatsu/suggestions/ui/SuggestionsActivity.kt
@@ -0,0 +1,45 @@
+package org.koitharu.kotatsu.suggestions.ui
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.ViewGroup
+import androidx.core.graphics.Insets
+import androidx.core.view.updateLayoutParams
+import androidx.core.view.updatePadding
+import androidx.fragment.app.commit
+import org.koitharu.kotatsu.R
+import org.koitharu.kotatsu.base.ui.BaseActivity
+import org.koitharu.kotatsu.databinding.ActivityContainerBinding
+
+class SuggestionsActivity : BaseActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(ActivityContainerBinding.inflate(layoutInflater))
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ val fm = supportFragmentManager
+ if (fm.findFragmentById(R.id.container) == null) {
+ fm.commit {
+ val fragment = SuggestionsFragment.newInstance()
+ replace(R.id.container, fragment)
+ }
+ }
+ }
+
+ override fun onWindowInsetsChanged(insets: Insets) {
+ binding.toolbar.updateLayoutParams {
+ leftMargin = insets.left
+ rightMargin = insets.right
+ }
+ binding.root.updatePadding(
+ left = insets.left,
+ right = insets.right,
+ )
+ }
+
+ companion object {
+
+ fun newIntent(context: Context) = Intent(context, SuggestionsActivity::class.java)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_empty_card.xml b/app/src/main/res/layout/item_empty_card.xml
new file mode 100644
index 000000000..1b4c86e30
--- /dev/null
+++ b/app/src/main/res/layout/item_empty_card.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_explore_buttons.xml b/app/src/main/res/layout/item_explore_buttons.xml
index 1cd5b385d..408723edb 100644
--- a/app/src/main/res/layout/item_explore_buttons.xml
+++ b/app/src/main/res/layout/item_explore_buttons.xml
@@ -1,63 +1,56 @@
-
+ android:paddingHorizontal="8dp"
+ android:paddingVertical="4dp">
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8e2172e9b..c7579ee53 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -327,4 +327,6 @@
No bookmarks yet
You can create bookmark while reading manga
Bookmarks removed
+ No manga sources
+ Enable manga sources to read manga online
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index a4b3ab1de..ac719b110 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -130,7 +130,7 @@