Merge pull request #190 from NoodleMage/kotlin
Rewrote Recent to Kotlin
This commit is contained in:
commit
306b1d74bb
12 changed files with 830 additions and 839 deletions
|
@ -81,7 +81,6 @@ public class MainActivity extends BaseActivity {
|
||||||
new PrimaryDrawerItem()
|
new PrimaryDrawerItem()
|
||||||
.withName(R.string.label_catalogues)
|
.withName(R.string.label_catalogues)
|
||||||
.withIdentifier(R.id.nav_drawer_catalogues)
|
.withIdentifier(R.id.nav_drawer_catalogues)
|
||||||
|
|
||||||
.withIcon(GoogleMaterial.Icon.gmd_explore),
|
.withIcon(GoogleMaterial.Icon.gmd_explore),
|
||||||
new PrimaryDrawerItem()
|
new PrimaryDrawerItem()
|
||||||
.withName(R.string.label_download_queue)
|
.withName(R.string.label_download_queue)
|
||||||
|
|
|
@ -1,140 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.recent;
|
|
||||||
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.text.format.DateUtils;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter;
|
|
||||||
import eu.kanade.tachiyomi.R;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter of RecentChaptersHolder.
|
|
||||||
* Connection between Fragment and Holder
|
|
||||||
* Holder updates should be called from here.
|
|
||||||
*/
|
|
||||||
public class RecentChaptersAdapter extends FlexibleAdapter<RecyclerView.ViewHolder, Object> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fragment of RecentChaptersFragment
|
|
||||||
*/
|
|
||||||
private final RecentChaptersFragment fragment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the view type
|
|
||||||
*/
|
|
||||||
private static final int VIEW_TYPE_CHAPTER = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the view type
|
|
||||||
*/
|
|
||||||
private static final int VIEW_TYPE_SECTION = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param fragment fragment
|
|
||||||
*/
|
|
||||||
public RecentChaptersAdapter(RecentChaptersFragment fragment) {
|
|
||||||
this.fragment = fragment;
|
|
||||||
setHasStableIds(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long getItemId(int position) {
|
|
||||||
Object item = getItem(position);
|
|
||||||
if (item instanceof MangaChapter)
|
|
||||||
return ((MangaChapter) item).chapter.id;
|
|
||||||
else
|
|
||||||
return item.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update items
|
|
||||||
*
|
|
||||||
* @param items items
|
|
||||||
*/
|
|
||||||
public void setItems(List<Object> items) {
|
|
||||||
mItems = items;
|
|
||||||
notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateDataSet(String param) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemViewType(int position) {
|
|
||||||
return getItem(position) instanceof MangaChapter ? VIEW_TYPE_CHAPTER : VIEW_TYPE_SECTION;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
|
||||||
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
|
|
||||||
View v;
|
|
||||||
|
|
||||||
// Check which view type and set correct values.
|
|
||||||
switch (viewType) {
|
|
||||||
case VIEW_TYPE_CHAPTER:
|
|
||||||
v = inflater.inflate(R.layout.item_recent_chapter, parent, false);
|
|
||||||
return new RecentChaptersHolder(v, this, fragment);
|
|
||||||
case VIEW_TYPE_SECTION:
|
|
||||||
v = inflater.inflate(R.layout.item_recent_chapter_section, parent, false);
|
|
||||||
return new SectionViewHolder(v);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
|
|
||||||
// Check which view type and set correct values.
|
|
||||||
switch (holder.getItemViewType()) {
|
|
||||||
case VIEW_TYPE_CHAPTER:
|
|
||||||
final MangaChapter chapter = (MangaChapter) getItem(position);
|
|
||||||
((RecentChaptersHolder) holder).onSetValues(chapter);
|
|
||||||
break;
|
|
||||||
case VIEW_TYPE_SECTION:
|
|
||||||
final Date date = (Date) getItem(position);
|
|
||||||
((SectionViewHolder) holder).onSetValues(date);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
//When user scrolls this bind the correct selection status
|
|
||||||
holder.itemView.setActivated(isSelected(position));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns fragment
|
|
||||||
* @return RecentChaptersFragment
|
|
||||||
*/
|
|
||||||
public RecentChaptersFragment getFragment() {
|
|
||||||
return fragment;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SectionViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
|
|
||||||
@Bind(R.id.section_text) TextView section;
|
|
||||||
|
|
||||||
private final long now = new Date().getTime();
|
|
||||||
|
|
||||||
public SectionViewHolder(View view) {
|
|
||||||
super(view);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onSetValues(Date date) {
|
|
||||||
CharSequence s = DateUtils.getRelativeTimeSpanString(
|
|
||||||
date.getTime(), now, DateUtils.DAY_IN_MILLIS);
|
|
||||||
section.setText(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||||
|
import eu.kanade.tachiyomi.util.inflate
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter of RecentChaptersHolder.
|
||||||
|
* Connection between Fragment and Holder
|
||||||
|
* Holder updates should be called from here.
|
||||||
|
*
|
||||||
|
* @param fragment a RecentChaptersFragment object
|
||||||
|
* @constructor creates an instance of the adapter.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class RecentChaptersAdapter(val fragment: RecentChaptersFragment) : FlexibleAdapter<RecyclerView.ViewHolder, Any>() {
|
||||||
|
/**
|
||||||
|
* The id of the view type
|
||||||
|
*/
|
||||||
|
private val VIEW_TYPE_CHAPTER = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the view type
|
||||||
|
*/
|
||||||
|
private val VIEW_TYPE_SECTION = 1
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Let each each item in the data set be represented with a unique identifier.
|
||||||
|
setHasStableIds(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when ViewHolder is bind
|
||||||
|
*
|
||||||
|
* @param holder bind holder
|
||||||
|
* @param position position of holder
|
||||||
|
*/
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
// Check which view type and set correct values.
|
||||||
|
val item = getItem(position)
|
||||||
|
when (holder.itemViewType) {
|
||||||
|
VIEW_TYPE_CHAPTER -> {
|
||||||
|
if (item is MangaChapter) {
|
||||||
|
(holder as RecentChaptersHolder).onSetValues(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
VIEW_TYPE_SECTION -> {
|
||||||
|
if (item is Date) {
|
||||||
|
(holder as SectionViewHolder).onSetValues(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//When user scrolls this bind the correct selection status
|
||||||
|
holder.itemView.isActivated = isSelected(position)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when ViewHolder is created
|
||||||
|
*
|
||||||
|
* @param parent parent View
|
||||||
|
* @param viewType int containing viewType
|
||||||
|
*/
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder? {
|
||||||
|
val view: View
|
||||||
|
|
||||||
|
// Check which view type and set correct values.
|
||||||
|
when (viewType) {
|
||||||
|
VIEW_TYPE_CHAPTER -> {
|
||||||
|
view = parent.inflate(R.layout.item_recent_chapter)
|
||||||
|
return RecentChaptersHolder(view, this, fragment)
|
||||||
|
}
|
||||||
|
VIEW_TYPE_SECTION -> {
|
||||||
|
view = parent.inflate(R.layout.item_recent_chapter_section)
|
||||||
|
return SectionViewHolder(view)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the correct ViewType
|
||||||
|
*
|
||||||
|
* @param position position of item
|
||||||
|
*/
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return if (getItem(position) is MangaChapter) VIEW_TYPE_CHAPTER else VIEW_TYPE_SECTION
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update items
|
||||||
|
|
||||||
|
* @param items items
|
||||||
|
*/
|
||||||
|
fun setItems(items: List<Any>) {
|
||||||
|
mItems = items
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Needed to determine holder id
|
||||||
|
*
|
||||||
|
* @param position position of holder item
|
||||||
|
*/
|
||||||
|
override fun getItemId(position: Int): Long {
|
||||||
|
val item = getItem(position)
|
||||||
|
if (item is MangaChapter)
|
||||||
|
return item.chapter.id
|
||||||
|
else
|
||||||
|
return item.hashCode().toLong()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract function (not needed).
|
||||||
|
*
|
||||||
|
* @param p0 a string.
|
||||||
|
*/
|
||||||
|
override fun updateDataSet(p0: String) {
|
||||||
|
// Empty function.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,200 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.recent;
|
|
||||||
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.support.annotation.Nullable;
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.support.v7.widget.LinearLayoutManager;
|
|
||||||
import android.support.v7.widget.RecyclerView;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import com.afollestad.materialdialogs.MaterialDialog;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import eu.kanade.tachiyomi.R;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter;
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadService;
|
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download;
|
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
|
||||||
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
|
|
||||||
import eu.kanade.tachiyomi.ui.decoration.DividerItemDecoration;
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity;
|
|
||||||
import nucleus.factory.RequiresPresenter;
|
|
||||||
import rx.Observable;
|
|
||||||
import rx.android.schedulers.AndroidSchedulers;
|
|
||||||
import rx.schedulers.Schedulers;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fragment that shows recent chapters.
|
|
||||||
* Uses R.layout.fragment_recent_chapters.
|
|
||||||
* UI related actions should be called from here.
|
|
||||||
*/
|
|
||||||
@RequiresPresenter(RecentChaptersPresenter.class)
|
|
||||||
public class RecentChaptersFragment extends BaseRxFragment<RecentChaptersPresenter> implements FlexibleViewHolder.OnListItemClickListener {
|
|
||||||
|
|
||||||
@Bind(R.id.chapter_list) RecyclerView recyclerView;
|
|
||||||
|
|
||||||
private RecentChaptersAdapter adapter;
|
|
||||||
|
|
||||||
public static RecentChaptersFragment newInstance() {
|
|
||||||
return new RecentChaptersFragment();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
View view = inflater.inflate(R.layout.fragment_recent_chapters, container, false);
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
|
|
||||||
// Init RecyclerView and adapter
|
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
|
||||||
recyclerView.addItemDecoration(new DividerItemDecoration(ContextCompat.getDrawable(
|
|
||||||
getContext(), R.drawable.line_divider)));
|
|
||||||
recyclerView.setHasFixedSize(true);
|
|
||||||
adapter = new RecentChaptersAdapter(this);
|
|
||||||
recyclerView.setAdapter(adapter);
|
|
||||||
|
|
||||||
setToolbarTitle(R.string.label_recent_updates);
|
|
||||||
return view;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populate adapter with chapters
|
|
||||||
*
|
|
||||||
* @param chapters list of chapters
|
|
||||||
*/
|
|
||||||
public void onNextMangaChapters(List<Object> chapters) {
|
|
||||||
adapter.setItems(chapters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onListItemClick(int position) {
|
|
||||||
// Get item from position
|
|
||||||
Object item = adapter.getItem(position);
|
|
||||||
if (item instanceof MangaChapter) {
|
|
||||||
// Open chapter in reader
|
|
||||||
openChapter((MangaChapter) item);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onListItemLongClick(int position) {
|
|
||||||
// Empty function
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open chapter in reader
|
|
||||||
*
|
|
||||||
* @param chapter selected chapter
|
|
||||||
*/
|
|
||||||
private void openChapter(MangaChapter chapter) {
|
|
||||||
getPresenter().onOpenChapter(chapter);
|
|
||||||
Intent intent = ReaderActivity.newIntent(getActivity());
|
|
||||||
startActivity(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update download status of chapter
|
|
||||||
*
|
|
||||||
* @param download download object containing download progress.
|
|
||||||
*/
|
|
||||||
public void onChapterStatusChange(Download download) {
|
|
||||||
RecentChaptersHolder holder = getHolder(download.chapter);
|
|
||||||
if (holder != null)
|
|
||||||
holder.onStatusChange(download.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private RecentChaptersHolder getHolder(Chapter chapter) {
|
|
||||||
return (RecentChaptersHolder) recyclerView.findViewHolderForItemId(chapter.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start downloading chapter
|
|
||||||
*
|
|
||||||
* @param chapters selected chapters
|
|
||||||
* @param manga manga that belongs to chapter
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
|
||||||
protected boolean onDownload(Observable<Chapter> chapters, Manga manga) {
|
|
||||||
// Start the download service.
|
|
||||||
DownloadService.start(getActivity());
|
|
||||||
|
|
||||||
// Refresh data on download competition.
|
|
||||||
Observable<Chapter> observable = chapters
|
|
||||||
.doOnCompleted(adapter::notifyDataSetChanged);
|
|
||||||
|
|
||||||
// Download chapter.
|
|
||||||
getPresenter().downloadChapter(observable, manga);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start deleting chapter
|
|
||||||
* @param chapters selected chapters
|
|
||||||
* @param manga manga that belongs to chapter
|
|
||||||
* @return success of deletion.
|
|
||||||
*/
|
|
||||||
protected boolean onDelete(Observable<Chapter> chapters, Manga manga) {
|
|
||||||
int size = adapter.getSelectedItemCount();
|
|
||||||
|
|
||||||
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
|
|
||||||
.title(R.string.deleting)
|
|
||||||
.progress(false, size, true)
|
|
||||||
.cancelable(false)
|
|
||||||
.show();
|
|
||||||
|
|
||||||
Observable<Chapter> observable = chapters
|
|
||||||
.concatMap(chapter -> {
|
|
||||||
getPresenter().deleteChapter(chapter, manga);
|
|
||||||
return Observable.just(chapter);
|
|
||||||
})
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.doOnNext(chapter -> {
|
|
||||||
dialog.incrementProgress(1);
|
|
||||||
chapter.status = Download.NOT_DOWNLOADED;
|
|
||||||
})
|
|
||||||
.doOnCompleted(adapter::notifyDataSetChanged)
|
|
||||||
.finallyDo(dialog::dismiss);
|
|
||||||
|
|
||||||
getPresenter().deleteChapters(observable);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark chapter as read
|
|
||||||
*
|
|
||||||
* @param chapters selected chapter
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
|
||||||
protected boolean onMarkAsRead(Observable<Chapter> chapters) {
|
|
||||||
getPresenter().markChaptersRead(chapters, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark chapter as unread
|
|
||||||
*
|
|
||||||
* @param chapters selected chapter
|
|
||||||
* @return true
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("SameReturnValue")
|
|
||||||
protected boolean onMarkAsUnread(Observable<Chapter> chapters) {
|
|
||||||
getPresenter().markChaptersRead(chapters, false);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadService
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||||
|
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
|
||||||
|
import eu.kanade.tachiyomi.ui.decoration.DividerItemDecoration
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
|
import kotlinx.android.synthetic.main.fragment_recent_chapters.*
|
||||||
|
import nucleus.factory.RequiresPresenter
|
||||||
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fragment that shows recent chapters.
|
||||||
|
* Uses R.layout.fragment_recent_chapters.
|
||||||
|
* UI related actions should be called from here.
|
||||||
|
*/
|
||||||
|
@RequiresPresenter(RecentChaptersPresenter::class)
|
||||||
|
class RecentChaptersFragment : BaseRxFragment<RecentChaptersPresenter>(), FlexibleViewHolder.OnListItemClickListener {
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* Create new RecentChaptersFragment.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun newInstance(): RecentChaptersFragment {
|
||||||
|
return RecentChaptersFragment()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapter containing the recent chapters.
|
||||||
|
*/
|
||||||
|
lateinit var adapter: RecentChaptersAdapter
|
||||||
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when view gets created
|
||||||
|
*
|
||||||
|
* @param inflater layout inflater
|
||||||
|
* @param container view group
|
||||||
|
* @param savedState status of saved state
|
||||||
|
*/
|
||||||
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedState: Bundle?): View? {
|
||||||
|
// Inflate view
|
||||||
|
return inflater.inflate(R.layout.fragment_recent_chapters, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when view is created
|
||||||
|
*
|
||||||
|
* @param view created view
|
||||||
|
* @param savedInstanceState status of saved sate
|
||||||
|
*/
|
||||||
|
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
|
||||||
|
// Init RecyclerView and adapter
|
||||||
|
recycler.layoutManager = LinearLayoutManager(activity)
|
||||||
|
recycler.addItemDecoration(DividerItemDecoration(ContextCompat.getDrawable(
|
||||||
|
context, R.drawable.line_divider)))
|
||||||
|
recycler.setHasFixedSize(true)
|
||||||
|
adapter = RecentChaptersAdapter(this)
|
||||||
|
recycler.adapter = adapter
|
||||||
|
|
||||||
|
// Update toolbar text
|
||||||
|
setToolbarTitle(R.string.label_recent_updates)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when item in list is clicked
|
||||||
|
*
|
||||||
|
* @param position position of clicked item
|
||||||
|
*/
|
||||||
|
override fun onListItemClick(position: Int): Boolean {
|
||||||
|
// Get item from position
|
||||||
|
val item = adapter.getItem(position)
|
||||||
|
if (item is MangaChapter) {
|
||||||
|
// Open chapter in reader
|
||||||
|
openChapter(item)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when item in list is long clicked
|
||||||
|
*
|
||||||
|
* @param position position of clicked item
|
||||||
|
*/
|
||||||
|
override fun onListItemLongClick(position: Int) {
|
||||||
|
// Empty function
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open chapter in reader
|
||||||
|
|
||||||
|
* @param chapter selected chapter
|
||||||
|
*/
|
||||||
|
private fun openChapter(chapter: MangaChapter) {
|
||||||
|
// Start reader event
|
||||||
|
presenter.onOpenChapter(chapter)
|
||||||
|
|
||||||
|
//Start reader intent
|
||||||
|
val intent = ReaderActivity.newIntent(activity)
|
||||||
|
startActivity(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate adapter with chapters
|
||||||
|
|
||||||
|
* @param chapters list of chapters
|
||||||
|
*/
|
||||||
|
fun onNextMangaChapters(chapters: List<Any>) {
|
||||||
|
adapter.setItems(chapters)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update download status of chapter
|
||||||
|
|
||||||
|
* @param download download object containing download progress.
|
||||||
|
*/
|
||||||
|
fun onChapterStatusChange(download: Download) {
|
||||||
|
getHolder(download)?.onStatusChange(download.status)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns holder belonging to chapter
|
||||||
|
*
|
||||||
|
* @param download download object containing download progress.
|
||||||
|
*/
|
||||||
|
private fun getHolder(download: Download): RecentChaptersHolder? {
|
||||||
|
return recycler.findViewHolderForItemId(download.chapter.id) as? RecentChaptersHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start downloading chapter
|
||||||
|
|
||||||
|
* @param chapters selected chapters
|
||||||
|
* @param manga manga that belongs to chapter
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
fun onDownload(chapters: Observable<Chapter>, manga: Manga): Boolean {
|
||||||
|
// Start the download service.
|
||||||
|
DownloadService.start(activity)
|
||||||
|
|
||||||
|
// Refresh data on download competition.
|
||||||
|
val observable = chapters
|
||||||
|
.doOnCompleted({
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
presenter.start(presenter.CHAPTER_STATUS_CHANGES)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Download chapter.
|
||||||
|
presenter.downloadChapter(observable, manga)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start deleting chapter
|
||||||
|
*
|
||||||
|
* @param chapters selected chapters
|
||||||
|
* @param manga manga that belongs to chapter
|
||||||
|
* @return success of deletion.
|
||||||
|
*/
|
||||||
|
fun onDelete(chapters: Observable<Chapter>, manga: Manga): Boolean {
|
||||||
|
//Create observable
|
||||||
|
val observable = chapters
|
||||||
|
.concatMap { chapter ->
|
||||||
|
presenter.deleteChapter(chapter, manga)
|
||||||
|
Observable.just(chapter)
|
||||||
|
}
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.doOnNext { chapter ->
|
||||||
|
chapter.status = Download.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
.doOnCompleted { adapter.notifyDataSetChanged() }
|
||||||
|
|
||||||
|
// Delete chapters with observable
|
||||||
|
presenter.deleteChapters(observable)
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark chapter as read
|
||||||
|
|
||||||
|
* @param chapters selected chapter
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
fun onMarkAsRead(chapters: Observable<Chapter>): Boolean {
|
||||||
|
// Set marked as read
|
||||||
|
presenter.markChaptersRead(chapters, true)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark chapter as unread
|
||||||
|
|
||||||
|
* @param chapters selected chapter
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
fun onMarkAsUnread(chapters: Observable<Chapter>): Boolean {
|
||||||
|
// Set marked as unread
|
||||||
|
presenter.markChaptersRead(chapters, false)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,187 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.recent;
|
|
||||||
|
|
||||||
import android.support.v4.content.ContextCompat;
|
|
||||||
import android.view.Menu;
|
|
||||||
import android.view.View;
|
|
||||||
import android.widget.PopupMenu;
|
|
||||||
import android.widget.RelativeLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import butterknife.Bind;
|
|
||||||
import butterknife.ButterKnife;
|
|
||||||
import eu.kanade.tachiyomi.R;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter;
|
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download;
|
|
||||||
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
|
|
||||||
import rx.Observable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Holder that contains chapter item
|
|
||||||
* Uses R.layout.item_recent_chapter.
|
|
||||||
* UI related actions should be called from here.
|
|
||||||
*/
|
|
||||||
public class RecentChaptersHolder extends FlexibleViewHolder {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter for recent chapters
|
|
||||||
*/
|
|
||||||
private final RecentChaptersAdapter adapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TextView containing chapter title
|
|
||||||
*/
|
|
||||||
@Bind(R.id.chapter_title) TextView chapterTitle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TextView containing manga name
|
|
||||||
*/
|
|
||||||
@Bind(R.id.manga_title) TextView mangaTitle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TextView containing download status
|
|
||||||
*/
|
|
||||||
@Bind(R.id.download_text) TextView downloadText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RelativeLayout containing popup menu with download options
|
|
||||||
*/
|
|
||||||
@Bind(R.id.chapter_menu) RelativeLayout chapterMenu;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Color of read chapter
|
|
||||||
*/
|
|
||||||
private final int readColor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Color of unread chapter
|
|
||||||
*/
|
|
||||||
private final int unreadColor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Object containing chapter information
|
|
||||||
*/
|
|
||||||
private MangaChapter mangaChapter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor of RecentChaptersHolder
|
|
||||||
* @param view view of ChapterHolder
|
|
||||||
* @param adapter adapter of ChapterHolder
|
|
||||||
* @param onListItemClickListener ClickListener
|
|
||||||
*/
|
|
||||||
public RecentChaptersHolder(View view, RecentChaptersAdapter adapter, OnListItemClickListener onListItemClickListener) {
|
|
||||||
super(view, adapter, onListItemClickListener);
|
|
||||||
this.adapter = adapter;
|
|
||||||
ButterKnife.bind(this, view);
|
|
||||||
|
|
||||||
// Set colors.
|
|
||||||
readColor = ContextCompat.getColor(view.getContext(), R.color.hint_text);
|
|
||||||
unreadColor = ContextCompat.getColor(view.getContext(), R.color.primary_text);
|
|
||||||
|
|
||||||
//Set OnClickListener for download menu
|
|
||||||
chapterMenu.setOnClickListener(v -> v.post(() -> showPopupMenu(v)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set values of view
|
|
||||||
*
|
|
||||||
* @param item item containing chapter information
|
|
||||||
*/
|
|
||||||
public void onSetValues(MangaChapter item) {
|
|
||||||
this.mangaChapter = item;
|
|
||||||
|
|
||||||
// Set chapter title
|
|
||||||
chapterTitle.setText(item.chapter.name);
|
|
||||||
|
|
||||||
// Set manga title
|
|
||||||
mangaTitle.setText(item.manga.title);
|
|
||||||
|
|
||||||
// Check if chapter is read and set correct color
|
|
||||||
if (item.chapter.read) {
|
|
||||||
chapterTitle.setTextColor(readColor);
|
|
||||||
mangaTitle.setTextColor(readColor);
|
|
||||||
} else {
|
|
||||||
chapterTitle.setTextColor(unreadColor);
|
|
||||||
mangaTitle.setTextColor(unreadColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set chapter status
|
|
||||||
onStatusChange(item.chapter.status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates chapter status in view.
|
|
||||||
*
|
|
||||||
* @param status download status
|
|
||||||
*/
|
|
||||||
public void onStatusChange(int status) {
|
|
||||||
switch (status) {
|
|
||||||
case Download.QUEUE:
|
|
||||||
downloadText.setText(R.string.chapter_queued);
|
|
||||||
break;
|
|
||||||
case Download.DOWNLOADING:
|
|
||||||
downloadText.setText(R.string.chapter_downloading);
|
|
||||||
break;
|
|
||||||
case Download.DOWNLOADED:
|
|
||||||
downloadText.setText(R.string.chapter_downloaded);
|
|
||||||
break;
|
|
||||||
case Download.ERROR:
|
|
||||||
downloadText.setText(R.string.chapter_error);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
downloadText.setText("");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Show pop up menu
|
|
||||||
* @param view view containing popup menu.
|
|
||||||
*/
|
|
||||||
private void showPopupMenu(View view) {
|
|
||||||
// Create a PopupMenu, giving it the clicked view for an anchor
|
|
||||||
PopupMenu popup = new PopupMenu(adapter.getFragment().getActivity(), view);
|
|
||||||
|
|
||||||
// Inflate our menu resource into the PopupMenu's Menu
|
|
||||||
popup.getMenuInflater().inflate(R.menu.chapter_recent, popup.getMenu());
|
|
||||||
|
|
||||||
// Hide download and show delete if the chapter is downloaded and
|
|
||||||
if (mangaChapter.chapter.isDownloaded()) {
|
|
||||||
Menu menu = popup.getMenu();
|
|
||||||
menu.findItem(R.id.action_download).setVisible(false);
|
|
||||||
menu.findItem(R.id.action_delete).setVisible(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide mark as unread when the chapter is unread
|
|
||||||
if (!mangaChapter.chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
|
|
||||||
popup.getMenu().findItem(R.id.action_mark_as_unread).setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide mark as read when the chapter is read
|
|
||||||
if (mangaChapter.chapter.read) {
|
|
||||||
popup.getMenu().findItem(R.id.action_mark_as_read).setVisible(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a listener so we are notified if a menu item is clicked
|
|
||||||
popup.setOnMenuItemClickListener(menuItem -> {
|
|
||||||
Observable<Chapter> chapterObservable = Observable.just(mangaChapter.chapter);
|
|
||||||
|
|
||||||
switch (menuItem.getItemId()) {
|
|
||||||
case R.id.action_download:
|
|
||||||
return adapter.getFragment().onDownload(chapterObservable, mangaChapter.manga);
|
|
||||||
case R.id.action_delete:
|
|
||||||
return adapter.getFragment().onDelete(chapterObservable, mangaChapter.manga);
|
|
||||||
case R.id.action_mark_as_read:
|
|
||||||
return adapter.getFragment().onMarkAsRead(chapterObservable);
|
|
||||||
case R.id.action_mark_as_unread:
|
|
||||||
return adapter.getFragment().onMarkAsUnread(chapterObservable);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Finally show the PopupMenu
|
|
||||||
popup.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
|
import android.support.v4.content.ContextCompat
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.PopupMenu
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder
|
||||||
|
import kotlinx.android.synthetic.main.item_recent_chapter.view.*
|
||||||
|
import rx.Observable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holder that contains chapter item
|
||||||
|
* Uses R.layout.item_recent_chapter.
|
||||||
|
* UI related actions should be called from here.
|
||||||
|
*
|
||||||
|
* @param view the inflated view for this holder.
|
||||||
|
* @param adapter the adapter handling this holder.
|
||||||
|
* @param listener a listener to react to single tap and long tap events.
|
||||||
|
* @constructor creates a new library holder.
|
||||||
|
*/
|
||||||
|
class RecentChaptersHolder(view: View, private val adapter: RecentChaptersAdapter, listener: FlexibleViewHolder.OnListItemClickListener) : FlexibleViewHolder(view, adapter, listener) {
|
||||||
|
/**
|
||||||
|
* Color of read chapter
|
||||||
|
*/
|
||||||
|
private val readColor: Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color of unread chapter
|
||||||
|
*/
|
||||||
|
private val unreadColor: Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object containing chapter information
|
||||||
|
*/
|
||||||
|
private var mangaChapter: MangaChapter? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
// Set colors.
|
||||||
|
readColor = ContextCompat.getColor(view.context, R.color.hint_text)
|
||||||
|
unreadColor = ContextCompat.getColor(view.context, R.color.primary_text)
|
||||||
|
|
||||||
|
//Set OnClickListener for download menu
|
||||||
|
itemView.chapterMenu.setOnClickListener { v -> v.post({ showPopupMenu(v) }) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set values of view
|
||||||
|
*
|
||||||
|
* @param item item containing chapter information
|
||||||
|
*/
|
||||||
|
fun onSetValues(item: MangaChapter) {
|
||||||
|
this.mangaChapter = item
|
||||||
|
|
||||||
|
// Set chapter title
|
||||||
|
itemView.chapter_title.text = item.chapter.name
|
||||||
|
|
||||||
|
// Set manga title
|
||||||
|
itemView.manga_title.text = item.manga.title
|
||||||
|
|
||||||
|
// Check if chapter is read and set correct color
|
||||||
|
if (item.chapter.read) {
|
||||||
|
itemView.chapter_title.setTextColor(readColor)
|
||||||
|
itemView.manga_title.setTextColor(readColor)
|
||||||
|
} else {
|
||||||
|
itemView.chapter_title.setTextColor(unreadColor)
|
||||||
|
itemView.manga_title.setTextColor(unreadColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set chapter status
|
||||||
|
onStatusChange(item.chapter.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates chapter status in view.
|
||||||
|
|
||||||
|
* @param status download status
|
||||||
|
*/
|
||||||
|
fun onStatusChange(status: Int) {
|
||||||
|
when (status) {
|
||||||
|
Download.QUEUE -> itemView.download_text.setText(R.string.chapter_queued)
|
||||||
|
Download.DOWNLOADING -> itemView.download_text.setText(R.string.chapter_downloading)
|
||||||
|
Download.DOWNLOADED -> itemView.download_text.setText(R.string.chapter_downloaded)
|
||||||
|
Download.ERROR -> itemView.download_text.setText(R.string.chapter_error)
|
||||||
|
else -> itemView.download_text.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show pop up menu
|
||||||
|
* @param view view containing popup menu.
|
||||||
|
*/
|
||||||
|
private fun showPopupMenu(view: View) {
|
||||||
|
// Create a PopupMenu, giving it the clicked view for an anchor
|
||||||
|
val popup = PopupMenu(adapter.fragment.activity, view)
|
||||||
|
|
||||||
|
// Inflate our menu resource into the PopupMenu's Menu
|
||||||
|
popup.menuInflater.inflate(R.menu.chapter_recent, popup.menu)
|
||||||
|
|
||||||
|
mangaChapter?.let {
|
||||||
|
|
||||||
|
// Hide download and show delete if the chapter is downloaded and
|
||||||
|
if (it.chapter.isDownloaded) {
|
||||||
|
val menu = popup.menu
|
||||||
|
menu.findItem(R.id.action_download).isVisible = false
|
||||||
|
menu.findItem(R.id.action_delete).isVisible = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide mark as unread when the chapter is unread
|
||||||
|
if (!it.chapter.read /*&& mangaChapter.chapter.last_page_read == 0*/) {
|
||||||
|
popup.menu.findItem(R.id.action_mark_as_unread).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide mark as read when the chapter is read
|
||||||
|
if (it.chapter.read) {
|
||||||
|
popup.menu.findItem(R.id.action_mark_as_read).isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set a listener so we are notified if a menu item is clicked
|
||||||
|
popup.setOnMenuItemClickListener { menuItem ->
|
||||||
|
val chapterObservable = Observable.just<Chapter>(it.chapter)
|
||||||
|
|
||||||
|
when (menuItem.itemId) {
|
||||||
|
R.id.action_download -> adapter.fragment.onDownload(chapterObservable, it.manga)
|
||||||
|
R.id.action_delete -> adapter.fragment.onDelete(chapterObservable, it.manga)
|
||||||
|
R.id.action_mark_as_read -> adapter.fragment.onMarkAsRead(chapterObservable);
|
||||||
|
R.id.action_mark_as_unread -> adapter.fragment.onMarkAsUnread(chapterObservable);
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally show the PopupMenu
|
||||||
|
popup.show()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,309 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.ui.recent;
|
|
||||||
|
|
||||||
import android.os.Bundle;
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Calendar;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaChapter;
|
|
||||||
import eu.kanade.tachiyomi.data.download.DownloadManager;
|
|
||||||
import eu.kanade.tachiyomi.data.download.model.Download;
|
|
||||||
import eu.kanade.tachiyomi.data.source.SourceManager;
|
|
||||||
import eu.kanade.tachiyomi.data.source.base.Source;
|
|
||||||
import eu.kanade.tachiyomi.event.DownloadChaptersEvent;
|
|
||||||
import eu.kanade.tachiyomi.event.ReaderEvent;
|
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter;
|
|
||||||
import rx.Observable;
|
|
||||||
import rx.android.schedulers.AndroidSchedulers;
|
|
||||||
import rx.schedulers.Schedulers;
|
|
||||||
import timber.log.Timber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Presenter of RecentChaptersFragment.
|
|
||||||
* Contains information and data for fragment.
|
|
||||||
* Observable updates should be called from here.
|
|
||||||
*/
|
|
||||||
public class RecentChaptersPresenter extends BasePresenter<RecentChaptersFragment> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the restartable.
|
|
||||||
*/
|
|
||||||
private static final int GET_RECENT_CHAPTERS = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The id of the restartable.
|
|
||||||
*/
|
|
||||||
private static final int CHAPTER_STATUS_CHANGES = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to connect to database
|
|
||||||
*/
|
|
||||||
@Inject DatabaseHelper db;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to get information from download manager
|
|
||||||
*/
|
|
||||||
@Inject DownloadManager downloadManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to get source from source id
|
|
||||||
*/
|
|
||||||
@Inject SourceManager sourceManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List containing chapter and manga information
|
|
||||||
*/
|
|
||||||
private List<MangaChapter> mangaChapters;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onCreate(Bundle savedState) {
|
|
||||||
super.onCreate(savedState);
|
|
||||||
|
|
||||||
// Used to get recent chapters
|
|
||||||
restartableLatestCache(GET_RECENT_CHAPTERS,
|
|
||||||
this::getRecentChaptersObservable,
|
|
||||||
(recentChaptersFragment, chapters) -> {
|
|
||||||
// Update adapter to show recent manga's
|
|
||||||
recentChaptersFragment.onNextMangaChapters(chapters);
|
|
||||||
// Update download status
|
|
||||||
updateChapterStatus(convertToMangaChaptersList(chapters));
|
|
||||||
});
|
|
||||||
|
|
||||||
// Used to update download status
|
|
||||||
startableLatestCache(CHAPTER_STATUS_CHANGES,
|
|
||||||
this::getChapterStatusObs,
|
|
||||||
RecentChaptersFragment::onChapterStatusChange,
|
|
||||||
(view, error) -> Timber.e(error.getCause(), error.getMessage()));
|
|
||||||
|
|
||||||
if (savedState == null) {
|
|
||||||
// Start fetching recent chapters
|
|
||||||
start(GET_RECENT_CHAPTERS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list only containing MangaChapter objects.
|
|
||||||
*
|
|
||||||
* @param input the list that will be converted.
|
|
||||||
* @return list containing MangaChapters objects.
|
|
||||||
*/
|
|
||||||
private List<MangaChapter> convertToMangaChaptersList(List<Object> input) {
|
|
||||||
// Create temp list
|
|
||||||
List<MangaChapter> tempMangaChapterList = new ArrayList<>();
|
|
||||||
|
|
||||||
// Only add MangaChapter objects
|
|
||||||
//noinspection Convert2streamapi
|
|
||||||
for (Object object : input) {
|
|
||||||
if (object instanceof MangaChapter) {
|
|
||||||
tempMangaChapterList.add((MangaChapter) object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return temp list
|
|
||||||
return tempMangaChapterList;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update status of chapters
|
|
||||||
*
|
|
||||||
* @param mangaChapters list containing recent chapters
|
|
||||||
*/
|
|
||||||
private void updateChapterStatus(List<MangaChapter> mangaChapters) {
|
|
||||||
// Set global list of chapters.
|
|
||||||
this.mangaChapters = mangaChapters;
|
|
||||||
|
|
||||||
// Update status.
|
|
||||||
//noinspection Convert2streamapi
|
|
||||||
for (MangaChapter mangaChapter : mangaChapters)
|
|
||||||
setChapterStatus(mangaChapter);
|
|
||||||
|
|
||||||
// Start onChapterStatusChange restartable.
|
|
||||||
start(CHAPTER_STATUS_CHANGES);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns observable containing chapter status.
|
|
||||||
*
|
|
||||||
* @return download object containing download progress.
|
|
||||||
*/
|
|
||||||
private Observable<Download> getChapterStatusObs() {
|
|
||||||
return downloadManager.getQueue().getStatusObservable()
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.filter(download -> chapterIdEquals(download.chapter.id))
|
|
||||||
.doOnNext(this::updateChapterStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to check if chapter is in recent list
|
|
||||||
* @param chaptersId id of chapter
|
|
||||||
* @return exist in recent list
|
|
||||||
*/
|
|
||||||
private boolean chapterIdEquals(Long chaptersId) {
|
|
||||||
for (MangaChapter mangaChapter : mangaChapters) {
|
|
||||||
if (chaptersId.equals(mangaChapter.chapter.id)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update status of chapters.
|
|
||||||
*
|
|
||||||
* @param download download object containing progress.
|
|
||||||
*/
|
|
||||||
private void updateChapterStatus(Download download) {
|
|
||||||
// Loop through list
|
|
||||||
for (MangaChapter item : mangaChapters) {
|
|
||||||
if (download.chapter.id.equals(item.chapter.id)) {
|
|
||||||
item.chapter.status = download.getStatus();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get observable containing recent chapters and date
|
|
||||||
* @return observable containing recent chapters and date
|
|
||||||
*/
|
|
||||||
private Observable<List<Object>> getRecentChaptersObservable() {
|
|
||||||
// Set date for recent chapters
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
cal.setTime(new Date());
|
|
||||||
cal.add(Calendar.MONTH, -1);
|
|
||||||
|
|
||||||
// Get recent chapters from database.
|
|
||||||
return db.getRecentChapters(cal.getTime()).asRxObservable()
|
|
||||||
// Group chapters by the date they were fetched on a ordered map.
|
|
||||||
.flatMap(recents -> Observable.from(recents)
|
|
||||||
.toMultimap(
|
|
||||||
recent -> getMapKey(recent.chapter.date_fetch),
|
|
||||||
recent -> recent,
|
|
||||||
() -> new TreeMap<>((d1, d2) -> d2.compareTo(d1))))
|
|
||||||
// Add every day and all its chapters to a single list.
|
|
||||||
.map(recents -> {
|
|
||||||
List<Object> items = new ArrayList<>();
|
|
||||||
for (Map.Entry<Date, Collection<MangaChapter>> recent : recents.entrySet()) {
|
|
||||||
items.add(recent.getKey());
|
|
||||||
items.addAll(recent.getValue());
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
})
|
|
||||||
.observeOn(AndroidSchedulers.mainThread());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the chapter status
|
|
||||||
* @param mangaChapter MangaChapter which status gets updated
|
|
||||||
*/
|
|
||||||
private void setChapterStatus(MangaChapter mangaChapter) {
|
|
||||||
// Check if chapter in queue
|
|
||||||
for (Download download : downloadManager.getQueue()) {
|
|
||||||
if (mangaChapter.chapter.id.equals(download.chapter.id)) {
|
|
||||||
mangaChapter.chapter.status = download.getStatus();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get source of chapter
|
|
||||||
Source source = sourceManager.get(mangaChapter.manga.source);
|
|
||||||
|
|
||||||
// Check if chapter is downloaded
|
|
||||||
if (downloadManager.isChapterDownloaded(source, mangaChapter.manga, mangaChapter.chapter)) {
|
|
||||||
mangaChapter.chapter.status = Download.DOWNLOADED;
|
|
||||||
} else {
|
|
||||||
mangaChapter.chapter.status = Download.NOT_DOWNLOADED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get date as time key
|
|
||||||
* @param date desired date
|
|
||||||
* @return date as time key
|
|
||||||
*/
|
|
||||||
private Date getMapKey(long date) {
|
|
||||||
Calendar cal = Calendar.getInstance();
|
|
||||||
cal.setTime(new Date(date));
|
|
||||||
cal.set(Calendar.HOUR_OF_DAY, 0);
|
|
||||||
cal.set(Calendar.MINUTE, 0);
|
|
||||||
cal.set(Calendar.SECOND, 0);
|
|
||||||
cal.set(Calendar.MILLISECOND, 0);
|
|
||||||
return cal.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Open chapter in reader
|
|
||||||
* @param item chapter that is opened
|
|
||||||
*/
|
|
||||||
public void onOpenChapter(MangaChapter item) {
|
|
||||||
Source source = sourceManager.get(item.manga.source);
|
|
||||||
EventBus.getDefault().postSticky(new ReaderEvent(source, item.manga, item.chapter));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Download selected chapter
|
|
||||||
* @param selectedChapter chapter that is selected
|
|
||||||
* @param manga manga that belongs to chapter
|
|
||||||
*/
|
|
||||||
public void downloadChapter(Observable<Chapter> selectedChapter, Manga manga) {
|
|
||||||
add(selectedChapter
|
|
||||||
.toList()
|
|
||||||
.subscribe(chapters -> {
|
|
||||||
EventBus.getDefault().postSticky(new DownloadChaptersEvent(manga, chapters));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete selected chapter
|
|
||||||
* @param chapter chapter that is selected
|
|
||||||
* @param manga manga that belongs to chapter
|
|
||||||
*/
|
|
||||||
public void deleteChapter(Chapter chapter, Manga manga) {
|
|
||||||
Source source = sourceManager.get(manga.source);
|
|
||||||
downloadManager.deleteChapter(source, manga, chapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete selected chapter observable
|
|
||||||
* @param selectedChapters chapter that are selected
|
|
||||||
*/
|
|
||||||
public void deleteChapters(Observable<Chapter> selectedChapters) {
|
|
||||||
add(selectedChapters
|
|
||||||
.subscribe(chapter -> {
|
|
||||||
downloadManager.getQueue().remove(chapter);
|
|
||||||
}, error -> {
|
|
||||||
Timber.e(error.getMessage());
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark selected chapter as read
|
|
||||||
* @param selectedChapters chapter that is selected
|
|
||||||
* @param read read status
|
|
||||||
*/
|
|
||||||
public void markChaptersRead(Observable<Chapter> selectedChapters, boolean read) {
|
|
||||||
add(selectedChapters
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.map(chapter -> {
|
|
||||||
chapter.read = read;
|
|
||||||
if (!read) chapter.last_page_read = 0;
|
|
||||||
return chapter;
|
|
||||||
})
|
|
||||||
.toList()
|
|
||||||
.flatMap(chapters -> db.insertChapters(chapters).asRxObservable())
|
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
|
||||||
.subscribe());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,310 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaChapter
|
||||||
|
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||||
|
import eu.kanade.tachiyomi.data.download.model.Download
|
||||||
|
import eu.kanade.tachiyomi.data.source.SourceManager
|
||||||
|
import eu.kanade.tachiyomi.event.DownloadChaptersEvent
|
||||||
|
import eu.kanade.tachiyomi.event.ReaderEvent
|
||||||
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import rx.Observable
|
||||||
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
|
import rx.schedulers.Schedulers
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class RecentChaptersPresenter : BasePresenter<RecentChaptersFragment>() {
|
||||||
|
/**
|
||||||
|
* Used to connect to database
|
||||||
|
*/
|
||||||
|
@Inject lateinit var db: DatabaseHelper
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get information from download manager
|
||||||
|
*/
|
||||||
|
@Inject lateinit var downloadManager: DownloadManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to get source from source id
|
||||||
|
*/
|
||||||
|
@Inject lateinit var sourceManager: SourceManager
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List containing chapter and manga information
|
||||||
|
*/
|
||||||
|
private var mangaChapters: List<MangaChapter>? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the restartable.
|
||||||
|
*/
|
||||||
|
val GET_RECENT_CHAPTERS = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the restartable.
|
||||||
|
*/
|
||||||
|
val CHAPTER_STATUS_CHANGES = 2
|
||||||
|
|
||||||
|
override fun onCreate(savedState: Bundle?) {
|
||||||
|
super.onCreate(savedState)
|
||||||
|
|
||||||
|
// Used to get recent chapters
|
||||||
|
restartableLatestCache(GET_RECENT_CHAPTERS,
|
||||||
|
{ getRecentChaptersObservable() },
|
||||||
|
{ recentChaptersFragment, chapters ->
|
||||||
|
// Update adapter to show recent manga's
|
||||||
|
recentChaptersFragment.onNextMangaChapters(chapters)
|
||||||
|
// Update download status
|
||||||
|
updateChapterStatus(convertToMangaChaptersList(chapters))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Used to update download status
|
||||||
|
startableLatestCache(CHAPTER_STATUS_CHANGES,
|
||||||
|
{ getChapterStatusObs() },
|
||||||
|
{ recentChaptersFragment, download ->
|
||||||
|
// Set chapter status
|
||||||
|
recentChaptersFragment.onChapterStatusChange(download)
|
||||||
|
},
|
||||||
|
{ view, error -> Timber.e(error.cause, error.message) }
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if (savedState == null) {
|
||||||
|
// Start fetching recent chapters
|
||||||
|
start(GET_RECENT_CHAPTERS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns observable containing chapter status.
|
||||||
|
|
||||||
|
* @return download object containing download progress.
|
||||||
|
*/
|
||||||
|
private fun getChapterStatusObs(): Observable<Download> {
|
||||||
|
return downloadManager.queue.statusObservable
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.filter { download: Download ->
|
||||||
|
if (chapterIdEquals(download.chapter.id))
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
}
|
||||||
|
.doOnNext { download1: Download -> updateChapterStatus(download1) }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to check if chapter is in recent list
|
||||||
|
* @param chaptersId id of chapter
|
||||||
|
* *
|
||||||
|
* @return exist in recent list
|
||||||
|
*/
|
||||||
|
private fun chapterIdEquals(chaptersId: Long): Boolean {
|
||||||
|
mangaChapters!!.forEach { mangaChapter ->
|
||||||
|
if (chaptersId == mangaChapter.chapter.id) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list only containing MangaChapter objects.
|
||||||
|
|
||||||
|
* @param input the list that will be converted.
|
||||||
|
* *
|
||||||
|
* @return list containing MangaChapters objects.
|
||||||
|
*/
|
||||||
|
private fun convertToMangaChaptersList(input: List<Any>): List<MangaChapter> {
|
||||||
|
// Create temp list
|
||||||
|
val tempMangaChapterList = ArrayList<MangaChapter>()
|
||||||
|
|
||||||
|
// Only add MangaChapter objects
|
||||||
|
//noinspection Convert2streamapi
|
||||||
|
input.forEach { `object` ->
|
||||||
|
if (`object` is MangaChapter) {
|
||||||
|
tempMangaChapterList.add(`object`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return temp list
|
||||||
|
return tempMangaChapterList
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update status of chapters.
|
||||||
|
|
||||||
|
* @param download download object containing progress.
|
||||||
|
*/
|
||||||
|
private fun updateChapterStatus(download: Download) {
|
||||||
|
// Loop through list
|
||||||
|
mangaChapters?.let {
|
||||||
|
for (item in it) {
|
||||||
|
if (download.chapter.id == item.chapter.id) {
|
||||||
|
// Update status.
|
||||||
|
item.chapter.status = download.status
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update status of chapters
|
||||||
|
|
||||||
|
* @param mangaChapters list containing recent chapters
|
||||||
|
*/
|
||||||
|
private fun updateChapterStatus(mangaChapters: List<MangaChapter>) {
|
||||||
|
// Set global list of chapters.
|
||||||
|
this.mangaChapters = mangaChapters
|
||||||
|
|
||||||
|
// Update status.
|
||||||
|
//noinspection Convert2streamapi
|
||||||
|
for (mangaChapter in mangaChapters)
|
||||||
|
setChapterStatus(mangaChapter)
|
||||||
|
|
||||||
|
// Start onChapterStatusChange restartable.
|
||||||
|
start(CHAPTER_STATUS_CHANGES)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the chapter status
|
||||||
|
* @param mangaChapter MangaChapter which status gets updated
|
||||||
|
*/
|
||||||
|
private fun setChapterStatus(mangaChapter: MangaChapter) {
|
||||||
|
// Check if chapter in queue
|
||||||
|
for (download in downloadManager.queue) {
|
||||||
|
if (mangaChapter.chapter.id == download.chapter.id) {
|
||||||
|
mangaChapter.chapter.status = download.status
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get source of chapter
|
||||||
|
val source = sourceManager.get(mangaChapter.manga.source)
|
||||||
|
|
||||||
|
// Check if chapter is downloaded
|
||||||
|
if (downloadManager.isChapterDownloaded(source, mangaChapter.manga, mangaChapter.chapter)) {
|
||||||
|
mangaChapter.chapter.status = Download.DOWNLOADED
|
||||||
|
} else {
|
||||||
|
mangaChapter.chapter.status = Download.NOT_DOWNLOADED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get observable containing recent chapters and date
|
||||||
|
* @return observable containing recent chapters and date
|
||||||
|
*/
|
||||||
|
fun getRecentChaptersObservable(): Observable<ArrayList<Any>>? {
|
||||||
|
// Set date for recent chapters
|
||||||
|
val cal = Calendar.getInstance()
|
||||||
|
cal.time = Date()
|
||||||
|
cal.add(Calendar.MONTH, -1)
|
||||||
|
|
||||||
|
return db.getRecentChapters(cal.time).asRxObservable()
|
||||||
|
// Group chapters by the date they were fetched on a ordered map.
|
||||||
|
.flatMap { recentItems ->
|
||||||
|
Observable.from(recentItems)
|
||||||
|
.toMultimap {
|
||||||
|
recent ->
|
||||||
|
(getMapKey(recent.chapter.date_fetch))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add every day and all its chapters to a single list.
|
||||||
|
.map { recentItems ->
|
||||||
|
val items = ArrayList<Any>()
|
||||||
|
recentItems.entries.forEach { recent ->
|
||||||
|
items.add(recent.key)
|
||||||
|
items.addAll(recent.value)
|
||||||
|
}
|
||||||
|
items
|
||||||
|
}
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get date as time key
|
||||||
|
* @param date desired date
|
||||||
|
* *
|
||||||
|
* @return date as time key
|
||||||
|
*/
|
||||||
|
private fun getMapKey(date: Long): Date {
|
||||||
|
val cal = Calendar.getInstance()
|
||||||
|
cal.time = Date(date)
|
||||||
|
cal[Calendar.HOUR_OF_DAY] = 0
|
||||||
|
cal[Calendar.MINUTE] = 0
|
||||||
|
cal[Calendar.SECOND] = 0
|
||||||
|
cal[Calendar.MILLISECOND] = 0
|
||||||
|
return cal.time
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open chapter in reader
|
||||||
|
* @param item chapter that is opened
|
||||||
|
*/
|
||||||
|
fun onOpenChapter(item: MangaChapter) {
|
||||||
|
val source = sourceManager.get(item.manga.source)
|
||||||
|
EventBus.getDefault().postSticky(ReaderEvent(source, item.manga, item.chapter))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download selected chapter
|
||||||
|
* @param selectedChapter chapter that is selected
|
||||||
|
* *
|
||||||
|
* @param manga manga that belongs to chapter
|
||||||
|
*/
|
||||||
|
fun downloadChapter(selectedChapter: Observable<Chapter>, manga: Manga) {
|
||||||
|
add(selectedChapter.toList().subscribe { chapters -> EventBus.getDefault().postSticky(DownloadChaptersEvent(manga, chapters)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete selected chapter
|
||||||
|
* @param chapter chapter that is selected
|
||||||
|
* *
|
||||||
|
* @param manga manga that belongs to chapter
|
||||||
|
*/
|
||||||
|
fun deleteChapter(chapter: Chapter, manga: Manga) {
|
||||||
|
val source = sourceManager.get(manga.source)
|
||||||
|
downloadManager.deleteChapter(source, manga, chapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete selected chapter observable
|
||||||
|
* @param selectedChapters chapter that are selected
|
||||||
|
*/
|
||||||
|
fun deleteChapters(selectedChapters: Observable<Chapter>) {
|
||||||
|
add(selectedChapters
|
||||||
|
.subscribe(
|
||||||
|
{ chapter -> downloadManager.queue.remove(chapter) })
|
||||||
|
{ error -> Timber.e(error.message) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark selected chapter as read
|
||||||
|
* @param selectedChapters chapter that is selected
|
||||||
|
* *
|
||||||
|
* @param read read status
|
||||||
|
*/
|
||||||
|
fun markChaptersRead(selectedChapters: Observable<Chapter>, read: Boolean) {
|
||||||
|
add(selectedChapters
|
||||||
|
.subscribeOn(Schedulers.io())
|
||||||
|
.map { chapter ->
|
||||||
|
chapter.read = read
|
||||||
|
if (!read) {
|
||||||
|
chapter.last_page_read = 0
|
||||||
|
}
|
||||||
|
chapter
|
||||||
|
}
|
||||||
|
.toList()
|
||||||
|
.flatMap { chapters -> db.insertChapters(chapters).asRxObservable() }
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.kanade.tachiyomi.ui.recent
|
||||||
|
|
||||||
|
import android.support.v7.widget.RecyclerView
|
||||||
|
import android.text.format.DateUtils
|
||||||
|
import android.view.View
|
||||||
|
import kotlinx.android.synthetic.main.item_recent_chapter_section.view.*
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class SectionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current date
|
||||||
|
*/
|
||||||
|
private val now = Date().time
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set value of section header
|
||||||
|
*
|
||||||
|
* @param date of section header
|
||||||
|
*/
|
||||||
|
fun onSetValues(date: Date) {
|
||||||
|
val s = DateUtils.getRelativeTimeSpanString(
|
||||||
|
date.time, now, DateUtils.DAY_IN_MILLIS)
|
||||||
|
itemView.section_text.text = s
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,7 @@
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<android.support.v7.widget.RecyclerView
|
<android.support.v7.widget.RecyclerView
|
||||||
android:id="@+id/chapter_list"
|
android:id="@+id/recycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:descendantFocusability="blocksDescendants"
|
android:descendantFocusability="blocksDescendants"
|
||||||
|
|
|
@ -77,9 +77,12 @@
|
||||||
android:gravity="center|end"
|
android:gravity="center|end"
|
||||||
android:paddingBottom="18dp"
|
android:paddingBottom="18dp"
|
||||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||||
android:paddingRight="?android:attr/listPreferredItemPaddingRight">
|
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
|
||||||
|
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
|
||||||
|
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
|
android:id="@+id/chapterMenu"
|
||||||
android:layout_width="24dp"
|
android:layout_width="24dp"
|
||||||
android:layout_height="24dp"
|
android:layout_height="24dp"
|
||||||
android:layout_alignParentEnd="false"
|
android:layout_alignParentEnd="false"
|
||||||
|
|
Reference in a new issue