diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt index 1baeb1e6d..894d4afc0 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/common/widgets/CoverImageView.kt @@ -6,23 +6,37 @@ import androidx.appcompat.widget.AppCompatImageView class CoverImageView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : AppCompatImageView(context, attrs, defStyleAttr) { - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - val originalWidth = MeasureSpec.getSize(widthMeasureSpec) - val calculatedHeight: Int = (originalWidth * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).toInt() + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + val widthMode = MeasureSpec.getMode(widthMeasureSpec) + val heightMode = MeasureSpec.getMode(heightMeasureSpec) + if (widthMode == MeasureSpec.UNSPECIFIED) { + val originalWidth = MeasureSpec.getSize(widthMeasureSpec) + super.onMeasure( + MeasureSpec.makeMeasureSpec(originalWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + (originalWidth * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).toInt(), + MeasureSpec.EXACTLY + ) + ) + } else { + val originalHeight = MeasureSpec.getSize(heightMeasureSpec) + super.onMeasure( + MeasureSpec.makeMeasureSpec( + (originalHeight * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).toInt(), + MeasureSpec.EXACTLY + ), + MeasureSpec.makeMeasureSpec(originalHeight, MeasureSpec.EXACTLY) + ) + } + } - super.onMeasure( - MeasureSpec.makeMeasureSpec(originalWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(calculatedHeight, MeasureSpec.EXACTLY) - ) - } + private companion object { - private companion object { - - const val ASPECT_RATIO_HEIGHT = 18f - const val ASPECT_RATIO_WIDTH = 13f - } + const val ASPECT_RATIO_HEIGHT = 18f + const val ASPECT_RATIO_WIDTH = 13f + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt index b6f47756a..d3b672c2f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListAdapter.kt @@ -7,7 +7,7 @@ import org.koitharu.kotatsu.ui.common.list.BaseRecyclerAdapter class MangaListAdapter(onItemClickListener: ((Manga) -> Unit)?) : BaseRecyclerAdapter(onItemClickListener) { - override fun onCreateViewHolder(parent: ViewGroup) = MangaGridHolder(parent) + override fun onCreateViewHolder(parent: ViewGroup) = MangaListHolder(parent) override fun onGetItemId(item: Manga) = item.id } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt index 5fb524d20..98422ce6f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListFragment.kt @@ -3,7 +3,9 @@ package org.koitharu.kotatsu.ui.main.list import android.os.Bundle import android.view.View import androidx.core.view.isVisible +import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.snackbar.Snackbar import kotlinx.android.synthetic.main.fragment_list.* import moxy.ktx.moxyPresenter import org.koitharu.kotatsu.R @@ -12,6 +14,7 @@ import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.ui.common.BaseFragment import org.koitharu.kotatsu.ui.common.list.PaginationScrollListener import org.koitharu.kotatsu.ui.common.list.SpacingItemDecoration +import org.koitharu.kotatsu.utils.ext.getDisplayMessage import org.koitharu.kotatsu.utils.ext.hasItems import org.koitharu.kotatsu.utils.ext.withArgs @@ -29,7 +32,8 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView, adapter = MangaListAdapter { } - recyclerView.addItemDecoration(SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))) +// recyclerView.addItemDecoration(SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))) + recyclerView.addItemDecoration(DividerItemDecoration(view.context, RecyclerView.VERTICAL)) recyclerView.adapter = adapter recyclerView.addOnScrollListener(PaginationScrollListener(4, this)) swipeRefreshLayout.setOnRefreshListener { @@ -54,6 +58,12 @@ class MangaListFragment : BaseFragment(R.layout.fragment_list), MangaListView, adapter.appendData(list) } + override fun onError(e: Exception) { + if (recyclerView.hasItems) { + Snackbar.make(recyclerView, e.getDisplayMessage(resources), Snackbar.LENGTH_SHORT).show() + } + } + override fun onLoadingChanged(isLoading: Boolean) { val hasItems = recyclerView.hasItems progressBar.isVisible = isLoading && !hasItems diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListHolder.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListHolder.kt new file mode 100644 index 000000000..1fa828792 --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListHolder.kt @@ -0,0 +1,24 @@ +package org.koitharu.kotatsu.ui.main.list + +import android.view.ViewGroup +import coil.api.load +import coil.request.RequestDisposable +import kotlinx.android.synthetic.main.item_manga_list.* +import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.model.Manga +import org.koitharu.kotatsu.ui.common.list.BaseViewHolder +import org.koitharu.kotatsu.utils.ext.textAndVisible + +class MangaListHolder(parent: ViewGroup) : BaseViewHolder(parent, R.layout.item_manga_list) { + + private var coverRequest: RequestDisposable? = null + + override fun onBind(data: Manga) { + coverRequest?.dispose() + textView_title.text = data.title + textView_subtitle.textAndVisible = data.localizedTitle + coverRequest = imageView_cover.load(data.coverUrl) { + crossfade(true) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListPresenter.kt index ebff58d2f..be1e88480 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListPresenter.kt @@ -4,6 +4,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import moxy.InjectViewState +import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.domain.MangaProviderFactory import org.koitharu.kotatsu.ui.common.BasePresenter @@ -25,7 +26,10 @@ class MangaListPresenter : BasePresenter() { viewState.onListAppended(list) } } catch (e: Exception) { - e.printStackTrace() + if (BuildConfig.DEBUG) { + e.printStackTrace() + } + viewState.onError(e) } finally { viewState.onLoadingChanged(false) } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListView.kt b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListView.kt index c0eea6edc..8583261f3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/main/list/MangaListView.kt @@ -1,10 +1,7 @@ package org.koitharu.kotatsu.ui.main.list import moxy.MvpView -import moxy.viewstate.strategy.AddToEndSingleStrategy -import moxy.viewstate.strategy.AddToEndSingleTagStrategy -import moxy.viewstate.strategy.AddToEndStrategy -import moxy.viewstate.strategy.StateStrategyType +import moxy.viewstate.strategy.* import org.koitharu.kotatsu.core.model.Manga interface MangaListView : MvpView { @@ -17,4 +14,7 @@ interface MangaListView : MvpView { @StateStrategyType(AddToEndSingleStrategy::class) fun onLoadingChanged(isLoading: Boolean) + + @StateStrategyType(OneExecutionStateStrategy::class) + fun onError(e: Exception) } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt index 0f28f0ee3..46d250b12 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CommonExt.kt @@ -1,6 +1,9 @@ package org.koitharu.kotatsu.utils.ext +import android.content.res.Resources import org.koitharu.kotatsu.BuildConfig +import org.koitharu.kotatsu.R +import java.io.IOException inline fun T.safe(action: T.() -> R?) = try { this.action() @@ -9,4 +12,13 @@ inline fun T.safe(action: T.() -> R?) = try { e.printStackTrace() } null +} + +fun Throwable.getDisplayMessage(resources: Resources) = when(this) { + is IOException -> resources.getString(R.string.network_error) + else -> if (BuildConfig.DEBUG) { + message ?: resources.getString(R.string.error_occurred) + } else { + resources.getString(R.string.error_occurred) + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index b622873ea..1a46b2bc9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -9,6 +9,8 @@ import android.view.inputmethod.InputMethodManager import android.widget.EditText import android.widget.TextView import androidx.annotation.LayoutRes +import androidx.core.view.isGone +import androidx.core.view.isVisible import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView @@ -52,4 +54,11 @@ var TextView.drawableEnd: Drawable? set(value) { val old = compoundDrawablesRelative setCompoundDrawablesRelativeWithIntrinsicBounds(old[0], old[1], value, old[3]) + } + +var TextView.textAndVisible: CharSequence? + get() = text?.takeIf { visibility == View.VISIBLE } + set(value) { + text = value + isGone = value.isNullOrEmpty() } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_list.xml b/app/src/main/res/layout/fragment_list.xml index a6dbb4b99..8707eb71e 100644 --- a/app/src/main/res/layout/fragment_list.xml +++ b/app/src/main/res/layout/fragment_list.xml @@ -16,8 +16,7 @@ android:layout_height="match_parent" android:orientation="vertical" android:scrollbars="vertical" - app:layoutManager="androidx.recyclerview.widget.GridLayoutManager" - app:spanCount="3" /> + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" /> diff --git a/app/src/main/res/layout/item_manga_list.xml b/app/src/main/res/layout/item_manga_list.xml new file mode 100644 index 000000000..ba78c829d --- /dev/null +++ b/app/src/main/res/layout/item_manga_list.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index cd8157960..42ed64e5f 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,4 +1,5 @@ 5dp + 84dp \ 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 c280e44cc..87d77b1e7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -5,4 +5,6 @@ Local storage Favourites History + An error has occurred + Network connection error \ No newline at end of file