Update history fragment

pull/1/head
Koitharu 6 years ago
parent d7eebcd795
commit ac935eb203

@ -27,6 +27,9 @@ abstract class HistoryDao {
@Query("UPDATE history SET page = :page, chapter_id = :chapterId, updated_at = :updatedAt WHERE manga_id = :mangaId") @Query("UPDATE history SET page = :page, chapter_id = :chapterId, updated_at = :updatedAt WHERE manga_id = :mangaId")
abstract suspend fun update(mangaId: Long, page: Int, chapterId: Long, updatedAt: Long): Int abstract suspend fun update(mangaId: Long, page: Int, chapterId: Long, updatedAt: Long): Int
@Query("DELETE FROM history WHERE manga_id = :mangaId")
abstract suspend fun delete(mangaId: Long)
suspend fun update(entity: HistoryEntity) = update(entity.mangaId, entity.page, entity.chapterId, entity.updatedAt) suspend fun update(entity: HistoryEntity) = update(entity.mangaId, entity.page, entity.chapterId, entity.updatedAt)
@Transaction @Transaction

@ -53,6 +53,11 @@ class HistoryRepository : KoinComponent {
notifyHistoryChanged() notifyHistoryChanged()
} }
suspend fun delete(manga: Manga) {
db.historyDao().delete(manga.id)
notifyHistoryChanged()
}
companion object { companion object {
private val listeners = HashSet<OnHistoryChangeListener>() private val listeners = HashSet<OnHistoryChangeListener>()

@ -2,11 +2,9 @@ package org.koitharu.kotatsu.ui.main.list
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.*
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.annotation.CallSuper import androidx.annotation.CallSuper
import androidx.appcompat.widget.PopupMenu
import androidx.core.view.GravityCompat import androidx.core.view.GravityCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
@ -42,7 +40,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
private val settings by inject<AppSettings>() private val settings by inject<AppSettings>()
private lateinit var adapter: MangaListAdapter private var adapter: MangaListAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -65,6 +63,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
} }
override fun onDestroyView() { override fun onDestroyView() {
adapter = null
settings.unsubscribe(this) settings.unsubscribe(this)
super.onDestroyView() super.onDestroyView()
} }
@ -103,8 +102,23 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
startActivity(MangaDetailsActivity.newIntent(context ?: return, item)) startActivity(MangaDetailsActivity.newIntent(context ?: return, item))
} }
override fun onItemLongClick(item: Manga, position: Int, view: View): Boolean {
val menu = PopupMenu(context ?: return false, view)
onCreatePopupMenu(menu.menuInflater, menu.menu, item)
return if (menu.menu.hasVisibleItems()) {
menu.setOnMenuItemClickListener {
onPopupMenuItemSelected(it, item)
}
menu.gravity = GravityCompat.END or Gravity.TOP
menu.show()
true
} else {
false
}
}
override fun onListChanged(list: List<Manga>) { override fun onListChanged(list: List<Manga>) {
adapter.replaceData(list) adapter?.replaceData(list)
if (list.isEmpty()) { if (list.isEmpty()) {
setUpEmptyListHolder() setUpEmptyListHolder()
layout_holder.isVisible = true layout_holder.isVisible = true
@ -114,7 +128,20 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
} }
override fun onListAppended(list: List<Manga>) { override fun onListAppended(list: List<Manga>) {
adapter.appendData(list) adapter?.appendData(list)
}
@CallSuper
override fun onItemRemoved(item: Manga) {
adapter?.let {
it.removeItem(item)
if (it.itemCount == 0) {
setUpEmptyListHolder()
layout_holder.isVisible = true
} else {
layout_holder.isVisible = false
}
}
} }
override fun onError(e: Exception) { override fun onError(e: Exception) {
@ -181,7 +208,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
recyclerView.adapter = null recyclerView.adapter = null
recyclerView.layoutManager = null recyclerView.layoutManager = null
recyclerView.clearItemDecorations() recyclerView.clearItemDecorations()
adapter.listMode = mode adapter?.listMode = mode
recyclerView.layoutManager = when (mode) { recyclerView.layoutManager = when (mode) {
ListMode.GRID -> GridLayoutManager(ctx, 3) ListMode.GRID -> GridLayoutManager(ctx, 3)
else -> LinearLayoutManager(ctx) else -> LinearLayoutManager(ctx)
@ -196,7 +223,7 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
) )
} }
) )
adapter.notifyDataSetChanged() adapter?.notifyDataSetChanged()
recyclerView.firstItem = position recyclerView.firstItem = position
} }
@ -213,4 +240,8 @@ abstract class MangaListFragment<E> : BaseFragment(R.layout.fragment_list), Mang
else -> null else -> null
} }
} }
protected open fun onCreatePopupMenu(inflater: MenuInflater, menu: Menu, data: Manga) = Unit
protected open fun onPopupMenuItemSelected(item: MenuItem, data: Manga) = false
} }

@ -23,4 +23,7 @@ interface MangaListView<E> : MvpView {
@StateStrategyType(AddToEndSingleStrategy::class) @StateStrategyType(AddToEndSingleStrategy::class)
fun onInitFilter(sortOrders: List<SortOrder>, tags: List<MangaTag>, currentFilter: MangaFilter?) fun onInitFilter(sortOrders: List<SortOrder>, tags: List<MangaTag>, currentFilter: MangaFilter?)
@StateStrategyType(AddToEndStrategy::class)
fun onItemRemoved(item: Manga)
} }

@ -6,6 +6,7 @@ import android.view.MenuItem
import kotlinx.android.synthetic.main.fragment_list.* import kotlinx.android.synthetic.main.fragment_list.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.ui.main.list.MangaListFragment import org.koitharu.kotatsu.ui.main.list.MangaListFragment
import org.koitharu.kotatsu.ui.main.list.MangaListView import org.koitharu.kotatsu.ui.main.list.MangaListView

@ -3,14 +3,18 @@ package org.koitharu.kotatsu.ui.main.list.history
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import androidx.appcompat.app.AlertDialog
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_list.* import kotlinx.android.synthetic.main.fragment_list.*
import moxy.ktx.moxyPresenter import moxy.ktx.moxyPresenter
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.ui.main.list.MangaListFragment import org.koitharu.kotatsu.ui.main.list.MangaListFragment
import org.koitharu.kotatsu.ui.main.list.MangaListView import org.koitharu.kotatsu.ui.main.list.MangaListView
import org.koitharu.kotatsu.utils.ext.ellipsize
class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<MangaHistory>{ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<MangaHistory> {
private val presenter by moxyPresenter(factory = ::HistoryListPresenter) private val presenter by moxyPresenter(factory = ::HistoryListPresenter)
@ -23,12 +27,20 @@ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<Man
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu, inflater)
} }
override fun onOptionsItemSelected(item: MenuItem) = when(item.itemId) { override fun onOptionsItemSelected(item: MenuItem): Boolean {
R.id.action_clear_history -> { return when (item.itemId) {
presenter.clearHistory() R.id.action_clear_history -> {
true AlertDialog.Builder(context ?: return false)
.setTitle(R.string.clear_history)
.setMessage(R.string.text_clear_history_prompt)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(R.string.clear) { _, _ ->
presenter.clearHistory()
}.show()
true
}
else -> super.onOptionsItemSelected(item)
} }
else -> super.onOptionsItemSelected(item)
} }
override fun getTitle(): CharSequence? { override fun getTitle(): CharSequence? {
@ -40,6 +52,31 @@ class HistoryListFragment : MangaListFragment<MangaHistory>(), MangaListView<Man
textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0) textView_holder.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, 0, 0)
} }
override fun onCreatePopupMenu(inflater: MenuInflater, menu: Menu, data: Manga) {
super.onCreatePopupMenu(inflater, menu, data)
inflater.inflate(R.menu.popup_history, menu)
}
override fun onPopupMenuItemSelected(item: MenuItem, data: Manga): Boolean {
return when (item.itemId) {
R.id.action_remove -> {
presenter.removeFromHistory(data)
true
}
else -> super.onPopupMenuItemSelected(item, data)
}
}
override fun onItemRemoved(item: Manga) {
super.onItemRemoved(item)
Snackbar.make(
recyclerView, getString(
R.string._s_removed_from_history,
item.title.ellipsize(14)
), Snackbar.LENGTH_SHORT
).show()
}
companion object { companion object {
fun newInstance() = HistoryListFragment() fun newInstance() = HistoryListFragment()

@ -5,6 +5,7 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import moxy.InjectViewState import moxy.InjectViewState
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaHistory import org.koitharu.kotatsu.core.model.MangaHistory
import org.koitharu.kotatsu.domain.history.HistoryRepository import org.koitharu.kotatsu.domain.history.HistoryRepository
import org.koitharu.kotatsu.ui.common.BasePresenter import org.koitharu.kotatsu.ui.common.BasePresenter
@ -61,4 +62,19 @@ class HistoryListPresenter : BasePresenter<MangaListView<MangaHistory>>() {
} }
} }
} }
fun removeFromHistory(manga: Manga) {
launch {
try {
withContext(Dispatchers.IO) {
repository.delete(manga)
}
viewState.onItemRemoved(manga)
} catch (e: Exception) {
if (BuildConfig.DEBUG) {
e.printStackTrace()
}
}
}
}
} }

@ -57,4 +57,8 @@ fun String.transliterate(skipMissing: Boolean): String {
fun String.toFileName() = this.transliterate(false) fun String.toFileName() = this.transliterate(false)
.replace(Regex("[^a-z0-9_\\-]", setOf(RegexOption.IGNORE_CASE)), " ") .replace(Regex("[^a-z0-9_\\-]", setOf(RegexOption.IGNORE_CASE)), " ")
.replace(Regex("\\s+"), "_") .replace(Regex("\\s+"), "_")
fun String.ellipsize(maxLength: Int) = if (this.length > maxLength) {
this.take(maxLength - 1) + Typography.ellipsis
} else this

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/action_remove"
android:title="@string/remove" />
</menu>

@ -61,4 +61,8 @@
<string name="dark">Dark</string> <string name="dark">Dark</string>
<string name="automatic">Automatic</string> <string name="automatic">Automatic</string>
<string name="pages">Pages</string> <string name="pages">Pages</string>
<string name="clear">Clear</string>
<string name="text_clear_history_prompt">Are you rally want to clear all your reading history? This action cannot be undone.</string>
<string name="remove">Remove</string>
<string name="_s_removed_from_history">\"%s\" removed from history</string>
</resources> </resources>
Loading…
Cancel
Save