From 522e900b5a73af35e1f43657b7057edabcba273b Mon Sep 17 00:00:00 2001 From: inorichi Date: Mon, 18 Jan 2016 18:04:07 +0100 Subject: [PATCH] Initial support for recent updates. #20 --- .../data/database/DatabaseHelper.java | 25 ++--- .../tachiyomi/data/database/DbOpenHelper.java | 2 +- .../data/database/models/MangaChapter.java | 12 +++ .../data/database/models/MangaSync.java | 2 +- .../resolvers/MangaChapterGetResolver.java | 49 +++++++++ .../resolvers/MangaWithUnreadGetResolver.java | 23 ---- .../data/download/DownloadManager.java | 1 - .../injection/component/AppComponent.java | 4 +- .../injection/module/DataModule.java | 2 +- .../ui/decoration/DividerItemDecoration.java | 10 +- .../tachiyomi/ui/main/MainActivity.java | 8 +- .../pager/horizontal/HorizontalPager.java | 2 +- .../viewer/pager/vertical/VerticalPager.java | 2 +- .../ui/recent/RecentChaptersAdapter.java | 102 ++++++++++++++++++ .../ui/recent/RecentChaptersFragment.java | 76 +++++++++++++ .../ui/recent/RecentChaptersHolder.java | 42 ++++++++ .../ui/recent/RecentChaptersPresenter.java | 78 ++++++++++++++ .../ui/setting/SettingsAccountsFragment.java | 2 +- .../res/layout/fragment_recent_chapters.xml | 18 ++++ .../main/res/layout/item_recent_chapter.xml | 47 ++++++++ .../layout/item_recent_chapter_section.xml | 14 +++ 21 files changed, 466 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.java delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaWithUnreadGetResolver.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersAdapter.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersFragment.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersHolder.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersPresenter.java create mode 100644 app/src/main/res/layout/fragment_recent_chapters.xml create mode 100644 app/src/main/res/layout/item_recent_chapter.xml create mode 100644 app/src/main/res/layout/item_recent_chapter_section.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.java index 35402e35b..bda2b1fb7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DatabaseHelper.java @@ -27,10 +27,12 @@ import eu.kanade.tachiyomi.data.database.models.ChapterSQLiteTypeMapping; import eu.kanade.tachiyomi.data.database.models.Manga; import eu.kanade.tachiyomi.data.database.models.MangaCategory; import eu.kanade.tachiyomi.data.database.models.MangaCategorySQLiteTypeMapping; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; import eu.kanade.tachiyomi.data.database.models.MangaSQLiteTypeMapping; import eu.kanade.tachiyomi.data.database.models.MangaSync; import eu.kanade.tachiyomi.data.database.models.MangaSyncSQLiteTypeMapping; import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver; +import eu.kanade.tachiyomi.data.database.resolvers.MangaChapterGetResolver; import eu.kanade.tachiyomi.data.database.tables.CategoryTable; import eu.kanade.tachiyomi.data.database.tables.ChapterTable; import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable; @@ -160,23 +162,14 @@ public class DatabaseHelper { .prepare(); } - public PreparedGetListOfObjects getChapters(long manga_id, boolean sortAToZ, boolean onlyUnread) { - Query.CompleteBuilder query = Query.builder() - .table(ChapterTable.TABLE) - - .orderBy(ChapterTable.COLUMN_CHAPTER_NUMBER + (sortAToZ ? " ASC" : " DESC")); - - if (onlyUnread) { - query = query.where(ChapterTable.COLUMN_MANGA_ID + "=? AND " + ChapterTable.COLUMN_READ + "=?") - .whereArgs(manga_id, 0); - } else { - query = query.where(ChapterTable.COLUMN_MANGA_ID + "=?") - .whereArgs(manga_id); - } - + public PreparedGetListOfObjects getRecentChapters() { return db.get() - .listOfObjects(Chapter.class) - .withQuery(query.build()) + .listOfObjects(MangaChapter.class) + .withQuery(RawQuery.builder() + .query(MangaChapterGetResolver.RECENT_CHAPTERS_QUERY) + .observesTables(ChapterTable.TABLE) + .build()) + .withGetResolver(MangaChapterGetResolver.INSTANCE) .prepare(); } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.java index ba073c71a..3fefdd98c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenHelper.java @@ -6,9 +6,9 @@ import android.database.sqlite.SQLiteOpenHelper; import android.support.annotation.NonNull; import eu.kanade.tachiyomi.data.database.tables.CategoryTable; +import eu.kanade.tachiyomi.data.database.tables.ChapterTable; import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable; import eu.kanade.tachiyomi.data.database.tables.MangaSyncTable; -import eu.kanade.tachiyomi.data.database.tables.ChapterTable; import eu.kanade.tachiyomi.data.database.tables.MangaTable; public class DbOpenHelper extends SQLiteOpenHelper { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.java new file mode 100644 index 000000000..609a466e4 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaChapter.java @@ -0,0 +1,12 @@ +package eu.kanade.tachiyomi.data.database.models; + +public class MangaChapter { + + public Manga manga; + public Chapter chapter; + + public MangaChapter(Manga manga, Chapter chapter) { + this.manga = manga; + this.chapter = chapter; + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaSync.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaSync.java index 0dfdaa896..619064c5a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaSync.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaSync.java @@ -5,8 +5,8 @@ import com.pushtorefresh.storio.sqlite.annotations.StorIOSQLiteType; import java.io.Serializable; -import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService; import eu.kanade.tachiyomi.data.database.tables.MangaSyncTable; +import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService; @StorIOSQLiteType(table = MangaSyncTable.TABLE) public class MangaSync implements Serializable { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.java new file mode 100644 index 000000000..2e4297c39 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaChapterGetResolver.java @@ -0,0 +1,49 @@ +package eu.kanade.tachiyomi.data.database.resolvers; + +import android.database.Cursor; +import android.support.annotation.NonNull; + +import com.pushtorefresh.storio.sqlite.operations.get.DefaultGetResolver; + +import eu.kanade.tachiyomi.data.database.models.Chapter; +import eu.kanade.tachiyomi.data.database.models.ChapterStorIOSQLiteGetResolver; +import eu.kanade.tachiyomi.data.database.models.Manga; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; +import eu.kanade.tachiyomi.data.database.models.MangaStorIOSQLiteGetResolver; +import eu.kanade.tachiyomi.data.database.tables.ChapterTable; +import eu.kanade.tachiyomi.data.database.tables.MangaTable; + +public class MangaChapterGetResolver extends DefaultGetResolver { + + public static final MangaChapterGetResolver INSTANCE = new MangaChapterGetResolver(); + + public static final String QUERY = String.format( + "SELECT * FROM %1$s JOIN %2$s on %1$s.%3$s = %2$s.%4$s", + MangaTable.TABLE, + ChapterTable.TABLE, + MangaTable.COLUMN_ID, + ChapterTable.COLUMN_MANGA_ID); + + public static final String RECENT_CHAPTERS_QUERY = String.format( + QUERY + " ORDER BY %1$s DESC LIMIT 100", ChapterTable.COLUMN_DATE_UPLOAD); + + @NonNull + private final MangaStorIOSQLiteGetResolver mangaGetResolver; + + @NonNull + private final ChapterStorIOSQLiteGetResolver chapterGetResolver; + + public MangaChapterGetResolver() { + this.mangaGetResolver = new MangaStorIOSQLiteGetResolver(); + this.chapterGetResolver = new ChapterStorIOSQLiteGetResolver(); + } + + @NonNull + @Override + public MangaChapter mapFromCursor(@NonNull Cursor cursor) { + final Manga manga = mangaGetResolver.mapFromCursor(cursor); + final Chapter chapter = chapterGetResolver.mapFromCursor(cursor); + + return new MangaChapter(manga, chapter); + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaWithUnreadGetResolver.java b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaWithUnreadGetResolver.java deleted file mode 100644 index 75a8d353d..000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaWithUnreadGetResolver.java +++ /dev/null @@ -1,23 +0,0 @@ -package eu.kanade.tachiyomi.data.database.resolvers; - -import android.database.Cursor; -import android.support.annotation.NonNull; - -import eu.kanade.tachiyomi.data.database.models.Manga; -import eu.kanade.tachiyomi.data.database.models.MangaStorIOSQLiteGetResolver; -import eu.kanade.tachiyomi.data.database.tables.MangaTable; - -public class MangaWithUnreadGetResolver extends MangaStorIOSQLiteGetResolver { - - public static final MangaWithUnreadGetResolver INSTANCE = new MangaWithUnreadGetResolver(); - - @Override - @NonNull - public Manga mapFromCursor(@NonNull Cursor cursor) { - Manga manga = super.mapFromCursor(cursor); - int unreadColumn = cursor.getColumnIndex(MangaTable.COLUMN_UNREAD); - manga.unread = cursor.getInt(unreadColumn); - return manga; - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.java b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.java index ab553a071..381bbd9fc 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/data/download/DownloadManager.java @@ -26,7 +26,6 @@ import eu.kanade.tachiyomi.data.source.base.Source; import eu.kanade.tachiyomi.data.source.model.Page; import eu.kanade.tachiyomi.event.DownloadChaptersEvent; import eu.kanade.tachiyomi.util.DiskUtils; -import eu.kanade.tachiyomi.util.DynamicConcurrentMergeOperator; import rx.Observable; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; diff --git a/app/src/main/java/eu/kanade/tachiyomi/injection/component/AppComponent.java b/app/src/main/java/eu/kanade/tachiyomi/injection/component/AppComponent.java index e9e0554af..c2d2faed6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/injection/component/AppComponent.java +++ b/app/src/main/java/eu/kanade/tachiyomi/injection/component/AppComponent.java @@ -14,8 +14,8 @@ import eu.kanade.tachiyomi.injection.module.AppModule; import eu.kanade.tachiyomi.injection.module.DataModule; import eu.kanade.tachiyomi.ui.catalogue.CataloguePresenter; import eu.kanade.tachiyomi.ui.download.DownloadPresenter; -import eu.kanade.tachiyomi.ui.library.category.CategoryPresenter; import eu.kanade.tachiyomi.ui.library.LibraryPresenter; +import eu.kanade.tachiyomi.ui.library.category.CategoryPresenter; import eu.kanade.tachiyomi.ui.manga.MangaActivity; import eu.kanade.tachiyomi.ui.manga.MangaPresenter; import eu.kanade.tachiyomi.ui.manga.chapter.ChaptersPresenter; @@ -23,6 +23,7 @@ import eu.kanade.tachiyomi.ui.manga.info.MangaInfoPresenter; import eu.kanade.tachiyomi.ui.manga.myanimelist.MyAnimeListPresenter; import eu.kanade.tachiyomi.ui.reader.ReaderActivity; import eu.kanade.tachiyomi.ui.reader.ReaderPresenter; +import eu.kanade.tachiyomi.ui.recent.RecentChaptersPresenter; import eu.kanade.tachiyomi.ui.setting.SettingsAccountsFragment; import eu.kanade.tachiyomi.ui.setting.SettingsActivity; @@ -44,6 +45,7 @@ public interface AppComponent { void inject(DownloadPresenter downloadPresenter); void inject(MyAnimeListPresenter myAnimeListPresenter); void inject(CategoryPresenter categoryPresenter); + void inject(RecentChaptersPresenter recentChaptersPresenter); void inject(ReaderActivity readerActivity); void inject(MangaActivity mangaActivity); diff --git a/app/src/main/java/eu/kanade/tachiyomi/injection/module/DataModule.java b/app/src/main/java/eu/kanade/tachiyomi/injection/module/DataModule.java index 7be95dba9..b085e2cbb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/injection/module/DataModule.java +++ b/app/src/main/java/eu/kanade/tachiyomi/injection/module/DataModule.java @@ -8,9 +8,9 @@ import dagger.Module; import dagger.Provides; import eu.kanade.tachiyomi.data.cache.ChapterCache; import eu.kanade.tachiyomi.data.cache.CoverCache; -import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager; import eu.kanade.tachiyomi.data.database.DatabaseHelper; import eu.kanade.tachiyomi.data.download.DownloadManager; +import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager; import eu.kanade.tachiyomi.data.network.NetworkHelper; import eu.kanade.tachiyomi.data.preference.PreferencesHelper; import eu.kanade.tachiyomi.data.source.SourceManager; diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/decoration/DividerItemDecoration.java b/app/src/main/java/eu/kanade/tachiyomi/ui/decoration/DividerItemDecoration.java index 591cc17b7..3c9394d6f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/decoration/DividerItemDecoration.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/decoration/DividerItemDecoration.java @@ -2,13 +2,13 @@ package eu.kanade.tachiyomi.ui.decoration; import android.content.Context; import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.LinearLayoutManager; -import android.view.View; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.graphics.Canvas; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.view.View; public class DividerItemDecoration extends RecyclerView.ItemDecoration { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.java b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.java index c2f45021e..cda74f7de 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.java @@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.ui.base.activity.BaseActivity; import eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment; import eu.kanade.tachiyomi.ui.download.DownloadFragment; import eu.kanade.tachiyomi.ui.library.LibraryFragment; +import eu.kanade.tachiyomi.ui.recent.RecentChaptersFragment; import eu.kanade.tachiyomi.ui.setting.SettingsActivity; import icepick.State; import nucleus.view.ViewWithPresenter; @@ -71,9 +72,9 @@ public class MainActivity extends BaseActivity { new PrimaryDrawerItem() .withName(R.string.label_library) .withIdentifier(R.id.nav_drawer_library), -// new PrimaryDrawerItem() -// .withName(R.string.recent_updates_title) -// .withIdentifier(R.id.nav_drawer_recent_updates), + new PrimaryDrawerItem() + .withName(R.string.label_recent_updates) + .withIdentifier(R.id.nav_drawer_recent_updates), new PrimaryDrawerItem() .withName(R.string.label_catalogues) .withIdentifier(R.id.nav_drawer_catalogues), @@ -95,6 +96,7 @@ public class MainActivity extends BaseActivity { setFragment(LibraryFragment.newInstance()); break; case R.id.nav_drawer_recent_updates: + setFragment(RecentChaptersFragment.newInstance()); break; case R.id.nav_drawer_catalogues: setFragment(CatalogueFragment.newInstance()); diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java index 9c89b4cd4..acbec7d49 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/horizontal/HorizontalPager.java @@ -8,8 +8,8 @@ import android.view.MotionEvent; import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import rx.functions.Action1; public class HorizontalPager extends ViewPager implements Pager { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java index 61e9dc624..25b6271b5 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/vertical/VerticalPager.java @@ -7,8 +7,8 @@ import android.view.MotionEvent; import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterBoundariesOutListener; import eu.kanade.tachiyomi.ui.reader.viewer.base.OnChapterSingleTapListener; -import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import eu.kanade.tachiyomi.ui.reader.viewer.pager.Pager; +import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerGestureListener; import rx.functions.Action1; public class VerticalPager extends VerticalViewPagerImpl implements Pager { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersAdapter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersAdapter.java new file mode 100644 index 000000000..8c2a2bb45 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersAdapter.java @@ -0,0 +1,102 @@ +package eu.kanade.tachiyomi.ui.recent; + +import android.support.v7.widget.RecyclerView; +import android.text.format.DateFormat; +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 eu.davidea.flexibleadapter.FlexibleAdapter; +import eu.kanade.tachiyomi.R; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; + +public class RecentChaptersAdapter extends FlexibleAdapter { + + private RecentChaptersFragment fragment; + + private static final int CHAPTER = 0; + private static final int SECTION = 1; + + 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(); + } + + public void setItems(List items) { + mItems = items; + notifyDataSetChanged(); + } + + @Override + public void updateDataSet(String param) { + + } + + @Override + public int getItemViewType(int position) { + return getItem(position) instanceof MangaChapter ? CHAPTER : SECTION; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + View v; + switch (viewType) { + case CHAPTER: + v = inflater.inflate(R.layout.item_recent_chapter, parent, false); + return new RecentChaptersHolder(v, this, fragment); + case 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) { + switch (holder.getItemViewType()) { + case CHAPTER: + final MangaChapter chapter = (MangaChapter) getItem(position); + ((RecentChaptersHolder) holder).onSetValues(chapter); + break; + case SECTION: + final Date date = (Date) getItem(position); + ((SectionViewHolder) holder).onSetValues(date); + } + + //When user scrolls this bind the correct selection status + holder.itemView.setActivated(isSelected(position)); + } + + public RecentChaptersFragment getFragment() { + return fragment; + } + + private static class SectionViewHolder extends RecyclerView.ViewHolder { + + private TextView view; + + public SectionViewHolder(View view) { + super(view); + this.view = (TextView) view; + } + + public void onSetValues(Date date) { + String s = DateFormat.getDateFormat(view.getContext()).format(date); + view.setText(s); + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersFragment.java new file mode 100644 index 000000000..be3e8b5d2 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersFragment.java @@ -0,0 +1,76 @@ +package eu.kanade.tachiyomi.ui.recent; + +import android.content.Intent; +import android.os.Bundle; +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 java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import eu.kanade.tachiyomi.R; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; +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; + +@RequiresPresenter(RecentChaptersPresenter.class) +public class RecentChaptersFragment extends BaseRxFragment 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; + } + + public void onNextMangaChapters(List chapters) { + adapter.setItems(chapters); + } + + @Override + public boolean onListItemClick(int position) { + Object item = adapter.getItem(position); + if (item instanceof MangaChapter) { + openChapter((MangaChapter) item); + } + return false; + } + + @Override + public void onListItemLongClick(int position) { + + } + + protected void openChapter(MangaChapter chapter) { + getPresenter().onOpenChapter(chapter); + Intent intent = ReaderActivity.newIntent(getActivity()); + startActivity(intent); + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersHolder.java b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersHolder.java new file mode 100644 index 000000000..93927e9fc --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersHolder.java @@ -0,0 +1,42 @@ +package eu.kanade.tachiyomi.ui.recent; + +import android.support.v4.content.ContextCompat; +import android.view.View; +import android.widget.TextView; + +import butterknife.Bind; +import butterknife.ButterKnife; +import eu.kanade.tachiyomi.R; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; +import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder; + +public class RecentChaptersHolder extends FlexibleViewHolder { + + @Bind(R.id.chapter_title) TextView chapterTitle; + @Bind(R.id.manga_title) TextView mangaTitle; + + private final int readColor; + private final int unreadColor; + + public RecentChaptersHolder(View view, RecentChaptersAdapter adapter, OnListItemClickListener onListItemClickListener) { + super(view, adapter, onListItemClickListener); + ButterKnife.bind(this, view); + + readColor = ContextCompat.getColor(view.getContext(), R.color.hint_text); + unreadColor = ContextCompat.getColor(view.getContext(), R.color.primary_text); + } + + public void onSetValues(MangaChapter item) { + chapterTitle.setText(item.chapter.name); + mangaTitle.setText(item.manga.title); + + if (item.chapter.read) { + chapterTitle.setTextColor(readColor); + mangaTitle.setTextColor(readColor); + } else { + chapterTitle.setTextColor(unreadColor); + mangaTitle.setTextColor(unreadColor); + } + } + +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersPresenter.java b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersPresenter.java new file mode 100644 index 000000000..76116e371 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/recent/RecentChaptersPresenter.java @@ -0,0 +1,78 @@ +package eu.kanade.tachiyomi.ui.recent; + +import android.os.Bundle; + +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 de.greenrobot.event.EventBus; +import eu.kanade.tachiyomi.data.database.DatabaseHelper; +import eu.kanade.tachiyomi.data.database.models.MangaChapter; +import eu.kanade.tachiyomi.data.source.SourceManager; +import eu.kanade.tachiyomi.data.source.base.Source; +import eu.kanade.tachiyomi.event.ReaderEvent; +import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter; +import rx.Observable; +import rx.android.schedulers.AndroidSchedulers; + +public class RecentChaptersPresenter extends BasePresenter { + + @Inject DatabaseHelper db; + @Inject SourceManager sourceManager; + + private static final int GET_RECENT_CHAPTERS = 1; + + @Override + protected void onCreate(Bundle savedState) { + super.onCreate(savedState); + + restartableLatestCache(GET_RECENT_CHAPTERS, + this::getRecentChaptersObservable, + RecentChaptersFragment::onNextMangaChapters); + + if (savedState == null) + start(GET_RECENT_CHAPTERS); + } + + private Observable> getRecentChaptersObservable() { + return db.getRecentChapters().createObservable() + // 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 items = new ArrayList<>(); + for (Map.Entry> recent : recents.entrySet()) { + items.add(recent.getKey()); + items.addAll(recent.getValue()); + } + return items; + }) + .observeOn(AndroidSchedulers.mainThread()); + } + + 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(); + } + + public void onOpenChapter(MangaChapter item) { + Source source = sourceManager.get(item.manga.source); + EventBus.getDefault().postSticky(new ReaderEvent(source, item.manga, item.chapter)); + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAccountsFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAccountsFragment.java index 8f3ce6988..b705fbc50 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAccountsFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsAccountsFragment.java @@ -12,8 +12,8 @@ import java.util.List; import javax.inject.Inject; import eu.kanade.tachiyomi.App; -import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService; import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager; +import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService; import eu.kanade.tachiyomi.data.source.SourceManager; import eu.kanade.tachiyomi.data.source.base.Source; import eu.kanade.tachiyomi.widget.preference.MangaSyncLoginDialog; diff --git a/app/src/main/res/layout/fragment_recent_chapters.xml b/app/src/main/res/layout/fragment_recent_chapters.xml new file mode 100644 index 000000000..a05e196cf --- /dev/null +++ b/app/src/main/res/layout/fragment_recent_chapters.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_recent_chapter.xml b/app/src/main/res/layout/item_recent_chapter.xml new file mode 100644 index 000000000..4c2dd163a --- /dev/null +++ b/app/src/main/res/layout/item_recent_chapter.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_recent_chapter_section.xml b/app/src/main/res/layout/item_recent_chapter_section.xml new file mode 100644 index 000000000..14d65a1ba --- /dev/null +++ b/app/src/main/res/layout/item_recent_chapter_section.xml @@ -0,0 +1,14 @@ + + + \ No newline at end of file