mirror of
https://github.com/mihonapp/mihon.git
synced 2025-06-26 19:17:51 +02:00
Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
0210fd8828 | |||
0332d8dd79 | |||
111ec5541f | |||
4bf15a5a2c | |||
416fd128ba | |||
dda0c50a1c | |||
f0a3c9c2dc | |||
8520a47286 | |||
522e900b5a | |||
b9bb41164f | |||
2b2fa0de2f | |||
e747083b06 | |||
e08dd95435 | |||
173e86320b | |||
b2e579173b | |||
79229d9c6a | |||
d25cbe9005 |
@ -1,4 +1,4 @@
|
||||
Tachiyomi is a manga reader for Android free and open source.
|
||||
Tachiyomi is a free and open source manga reader for Android.
|
||||
|
||||
Keep in mind it's still a beta, so expect it to crash sometimes.
|
||||
|
||||
@ -12,6 +12,11 @@ Current features:
|
||||
* Schedule searching for updates
|
||||
* Categories to organize your library
|
||||
|
||||
## Download
|
||||
|
||||
[](https://github.com/inorichi/tachiyomi/releases/download/v0.1.0/tachiyomi-v0.1.0.apk)
|
||||
[](http://tachiyomi.kanade.eu/latest/app-debug.apk)
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2015 Javier Tomás
|
||||
|
@ -39,8 +39,8 @@ android {
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 23
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
versionCode 1
|
||||
versionName "0.1.0"
|
||||
versionCode 2
|
||||
versionName "0.1.1"
|
||||
|
||||
buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\""
|
||||
buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\""
|
||||
@ -53,6 +53,9 @@ android {
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
applicationIdSuffix ".debug"
|
||||
}
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
@ -78,7 +81,7 @@ dependencies {
|
||||
final SUPPORT_LIBRARY_VERSION = '23.1.1'
|
||||
final DAGGER_VERSION = '2.0.2'
|
||||
final MOCKITO_VERSION = '1.10.19'
|
||||
final STORIO_VERSION = '1.7.0'
|
||||
final STORIO_VERSION = '1.8.0'
|
||||
final ICEPICK_VERSION = '3.1.0'
|
||||
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
@ -13,7 +13,7 @@ import eu.kanade.tachiyomi.injection.module.AppModule;
|
||||
import timber.log.Timber;
|
||||
|
||||
@ReportsCrashes(
|
||||
formUri = "http://mangafeed.kanade.eu/crash_report",
|
||||
formUri = "http://tachiyomi.kanade.eu/crash_report",
|
||||
reportType = org.acra.sender.HttpSender.Type.JSON,
|
||||
httpMethod = org.acra.sender.HttpSender.Method.PUT,
|
||||
excludeMatchingSharedPreferencesKeys={".*username.*",".*password.*"}
|
||||
|
@ -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<Chapter> 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<MangaChapter> 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();
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -0,0 +1,51 @@
|
||||
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<MangaChapter> {
|
||||
|
||||
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 + " WHERE %1$s = 1 ORDER BY %2$s DESC LIMIT 100",
|
||||
MangaTable.COLUMN_FAVORITE,
|
||||
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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
@ -42,7 +41,7 @@ public class DownloadManager {
|
||||
private PreferencesHelper preferences;
|
||||
private Gson gson;
|
||||
|
||||
private PublishSubject<Download> downloadsQueueSubject;
|
||||
private PublishSubject<List<Download>> downloadsQueueSubject;
|
||||
private BehaviorSubject<Boolean> runningSubject;
|
||||
private Subscription downloadsSubscription;
|
||||
|
||||
@ -68,7 +67,8 @@ public class DownloadManager {
|
||||
downloadsSubscription.unsubscribe();
|
||||
|
||||
downloadsSubscription = downloadsQueueSubject
|
||||
.flatMap(this::downloadChapter, preferences.downloadThreads())
|
||||
.concatMap(downloads -> Observable.from(downloads)
|
||||
.flatMap(this::downloadChapter, preferences.downloadThreads()))
|
||||
.onBackpressureBuffer()
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.map(download -> areAllDownloadsFinished())
|
||||
@ -103,6 +103,7 @@ public class DownloadManager {
|
||||
|
||||
// Used to avoid downloading chapters with the same name
|
||||
final List<String> addedChapters = new ArrayList<>();
|
||||
final List<Download> pending = new ArrayList<>();
|
||||
|
||||
for (Chapter chapter : event.getChapters()) {
|
||||
if (addedChapters.contains(chapter.name))
|
||||
@ -113,9 +114,10 @@ public class DownloadManager {
|
||||
|
||||
if (!prepareDownload(download)) {
|
||||
queue.add(download);
|
||||
if (isRunning) downloadsQueueSubject.onNext(download);
|
||||
pending.add(download);
|
||||
}
|
||||
}
|
||||
if (isRunning) downloadsQueueSubject.onNext(pending);
|
||||
}
|
||||
|
||||
// Public method to check if a chapter is downloaded
|
||||
@ -269,7 +271,7 @@ public class DownloadManager {
|
||||
// Get the filename for an image given the page
|
||||
private String getImageFilename(Page page) {
|
||||
String url = page.getImageUrl();
|
||||
return Uri.parse(url).getLastPathSegment();
|
||||
return Uri.parse(url).getLastPathSegment().replaceAll("[^\\sa-zA-Z0-9.-]", "_");
|
||||
}
|
||||
|
||||
private boolean isImageDownloaded(File imagePath) {
|
||||
@ -387,18 +389,19 @@ public class DownloadManager {
|
||||
if (queue.isEmpty())
|
||||
return false;
|
||||
|
||||
boolean hasPendingDownloads = false;
|
||||
if (downloadsSubscription == null)
|
||||
initializeSubscriptions();
|
||||
|
||||
final List<Download> pending = new ArrayList<>();
|
||||
for (Download download : queue) {
|
||||
if (download.getStatus() != Download.DOWNLOADED) {
|
||||
if (download.getStatus() != Download.QUEUE) download.setStatus(Download.QUEUE);
|
||||
if (!hasPendingDownloads) hasPendingDownloads = true;
|
||||
downloadsQueueSubject.onNext(download);
|
||||
pending.add(download);
|
||||
}
|
||||
}
|
||||
return hasPendingDownloads;
|
||||
downloadsQueueSubject.onNext(pending);
|
||||
|
||||
return !pending.isEmpty();
|
||||
}
|
||||
|
||||
public void stopDownloads() {
|
||||
|
@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.source;
|
||||
import android.content.Context;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@ -59,7 +60,9 @@ public class SourceManager {
|
||||
}
|
||||
|
||||
public List<Source> getSources() {
|
||||
return new ArrayList<>(sourcesMap.values());
|
||||
List<Source> sources = new ArrayList<>(sourcesMap.values());
|
||||
Collections.sort(sources, (s1, s2) -> s1.getName().compareTo(s2.getName()));
|
||||
return sources;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -228,12 +228,8 @@ public class Mangafox extends Source {
|
||||
|
||||
Elements pageUrlElements = parsedDocument.select("select.m").first().select("option:not([value=0])");
|
||||
String baseUrl = parsedDocument.select("div#series a").first().attr("href").replace("1.html", "");
|
||||
int counter = 1;
|
||||
for (Element pageUrlElement : pageUrlElements) {
|
||||
if(counter < pageUrlElements.size()) {
|
||||
pageUrlList.add(baseUrl + pageUrlElement.attr("value") + ".html");
|
||||
}
|
||||
counter++;
|
||||
pageUrlList.add(baseUrl + pageUrlElement.attr("value") + ".html");
|
||||
}
|
||||
|
||||
return pageUrlList;
|
||||
|
@ -63,7 +63,7 @@ public class UpdateMangaSyncService extends Service {
|
||||
subscriptions.add(Observable.defer(() -> sync.update(mangaSync))
|
||||
.flatMap(response -> {
|
||||
if (response.isSuccessful()) {
|
||||
return db.insertMangaSync(mangaSync).createObservable();
|
||||
return db.insertMangaSync(mangaSync).asRxObservable();
|
||||
}
|
||||
return Observable.error(new Exception("Could not update MAL"));
|
||||
})
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -18,6 +18,8 @@ import android.widget.AdapterView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -257,6 +259,17 @@ public class CatalogueFragment extends BaseRxFragment<CataloguePresenter>
|
||||
|
||||
@Override
|
||||
public void onListItemLongClick(int position) {
|
||||
// Do nothing
|
||||
final Manga selectedManga = adapter.getItem(position);
|
||||
|
||||
new MaterialDialog.Builder(getActivity())
|
||||
.items(getString(R.string.add_to_library))
|
||||
.itemsCallback((dialog, itemView, which, text) -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
getPresenter().addMangaToLibrary(selectedManga);
|
||||
break;
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
@ -170,4 +170,8 @@ public class CataloguePresenter extends BasePresenter<CatalogueFragment> {
|
||||
return sourceManager.getSources();
|
||||
}
|
||||
|
||||
public void addMangaToLibrary(Manga manga) {
|
||||
manga.favorite = true;
|
||||
db.insertManga(manga).executeAsBlocking();
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -32,8 +32,10 @@ public class LibraryAdapter extends SmartFragmentStatePagerAdapter {
|
||||
}
|
||||
|
||||
public void setCategories(List<Category> categories) {
|
||||
this.categories = categories;
|
||||
notifyDataSetChanged();
|
||||
if (this.categories != categories) {
|
||||
this.categories = categories;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSelectionMode(int mode) {
|
||||
|
@ -34,6 +34,7 @@ public class LibraryCategoryFragment extends BaseFragment
|
||||
|
||||
@State int position;
|
||||
private LibraryCategoryAdapter adapter;
|
||||
private List<Manga> mangas;
|
||||
|
||||
private Subscription numColumnsSubscription;
|
||||
|
||||
@ -112,10 +113,13 @@ public class LibraryCategoryFragment extends BaseFragment
|
||||
|
||||
Category category = categories.get(position);
|
||||
List<Manga> mangas = event.getMangasForCategory(category);
|
||||
if (mangas == null) {
|
||||
mangas = new ArrayList<>();
|
||||
if (this.mangas != mangas) {
|
||||
this.mangas = mangas;
|
||||
if (mangas == null) {
|
||||
mangas = new ArrayList<>();
|
||||
}
|
||||
setMangas(mangas);
|
||||
}
|
||||
setMangas(mangas);
|
||||
}
|
||||
|
||||
protected void openManga(Manga manga) {
|
||||
|
@ -70,12 +70,12 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
|
||||
}
|
||||
|
||||
private Observable<List<Category>> getCategoriesObservable() {
|
||||
return db.getCategories().createObservable()
|
||||
return db.getCategories().asRxObservable()
|
||||
.doOnNext(categories -> this.categories = categories);
|
||||
}
|
||||
|
||||
private Observable<Map<Integer, List<Manga>>> getLibraryMangasObservable() {
|
||||
return db.getLibraryMangas().createObservable()
|
||||
return db.getLibraryMangas().asRxObservable()
|
||||
.flatMap(mangas -> Observable.from(mangas)
|
||||
.groupBy(manga -> manga.category)
|
||||
.flatMap(group -> group.toList()
|
||||
|
@ -24,7 +24,7 @@ public class CategoryPresenter extends BasePresenter<CategoryActivity> {
|
||||
super.onCreate(savedState);
|
||||
|
||||
restartableLatestCache(GET_CATEGORIES,
|
||||
() -> db.getCategories().createObservable()
|
||||
() -> db.getCategories().asRxObservable()
|
||||
.doOnNext(categories -> this.categories = categories)
|
||||
.observeOn(AndroidSchedulers.mainThread()),
|
||||
CategoryActivity::setCategories);
|
||||
@ -46,11 +46,11 @@ public class CategoryPresenter extends BasePresenter<CategoryActivity> {
|
||||
}
|
||||
cat.order = max;
|
||||
|
||||
db.insertCategory(cat).createObservable().subscribe();
|
||||
db.insertCategory(cat).asRxObservable().subscribe();
|
||||
}
|
||||
|
||||
public void deleteCategories(List<Category> categories) {
|
||||
db.deleteCategories(categories).createObservable().subscribe();
|
||||
db.deleteCategories(categories).asRxObservable().subscribe();
|
||||
}
|
||||
|
||||
public void reorderCategories(List<Category> categories) {
|
||||
@ -58,11 +58,11 @@ public class CategoryPresenter extends BasePresenter<CategoryActivity> {
|
||||
categories.get(i).order = i;
|
||||
}
|
||||
|
||||
db.insertCategories(categories).createObservable().subscribe();
|
||||
db.insertCategories(categories).asRxObservable().subscribe();
|
||||
}
|
||||
|
||||
public void renameCategory(Category category, String name) {
|
||||
category.name = name;
|
||||
db.insertCategory(category).createObservable().subscribe();
|
||||
db.insertCategory(category).asRxObservable().subscribe();
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -72,7 +73,7 @@ public class MainActivity extends BaseActivity {
|
||||
.withName(R.string.label_library)
|
||||
.withIdentifier(R.id.nav_drawer_library),
|
||||
// new PrimaryDrawerItem()
|
||||
// .withName(R.string.recent_updates_title)
|
||||
// .withName(R.string.label_recent_updates)
|
||||
// .withIdentifier(R.id.nav_drawer_recent_updates),
|
||||
new PrimaryDrawerItem()
|
||||
.withName(R.string.label_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());
|
||||
|
@ -36,7 +36,7 @@ public class MangaPresenter extends BasePresenter<MangaActivity> {
|
||||
}
|
||||
|
||||
private Observable<Manga> getDbMangaObservable() {
|
||||
return db.getManga(mangaId).createObservable()
|
||||
return db.getManga(mangaId).asRxObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnNext(manga -> EventBus.getDefault().postSticky(manga));
|
||||
|
@ -254,6 +254,11 @@ public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implemen
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onMarkPreviousAsRead(Chapter chapter) {
|
||||
getPresenter().markPreviousChaptersAsRead(chapter);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean onDownload(Observable<Chapter> chapters) {
|
||||
DownloadService.start(getActivity());
|
||||
|
||||
|
@ -99,6 +99,8 @@ public class ChaptersHolder extends FlexibleViewHolder {
|
||||
return adapter.getFragment().onDownload(chapter);
|
||||
case R.id.action_delete:
|
||||
return adapter.getFragment().onDelete(chapter);
|
||||
case R.id.action_mark_previous_as_read:
|
||||
return adapter.getFragment().onMarkPreviousAsRead(item);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -97,7 +97,7 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
|
||||
source = sourceManager.get(manga.source);
|
||||
start(DB_CHAPTERS);
|
||||
|
||||
add(db.getChapters(manga).createObservable()
|
||||
add(db.getChapters(manga).asRxObservable()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.doOnNext(chapters -> {
|
||||
this.chapters = chapters;
|
||||
@ -202,11 +202,20 @@ public class ChaptersPresenter extends BasePresenter<ChaptersFragment> {
|
||||
return chapter;
|
||||
})
|
||||
.toList()
|
||||
.flatMap(chapters -> db.insertChapters(chapters).createObservable())
|
||||
.flatMap(chapters -> db.insertChapters(chapters).asRxObservable())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe());
|
||||
}
|
||||
|
||||
public void markPreviousChaptersAsRead(Chapter selected) {
|
||||
Observable.from(chapters)
|
||||
.filter(c -> c.chapter_number > -1 && c.chapter_number < selected.chapter_number)
|
||||
.doOnNext(c -> c.read = true)
|
||||
.toList()
|
||||
.flatMap(chapters -> db.insertChapters(chapters).asRxObservable())
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
public void downloadChapters(Observable<Chapter> selectedChapters) {
|
||||
add(selectedChapters
|
||||
.toList()
|
||||
|
@ -46,7 +46,7 @@ public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> {
|
||||
myAnimeList = syncManager.getMyAnimeList();
|
||||
|
||||
restartableLatestCache(GET_MANGA_SYNC,
|
||||
() -> db.getMangaSync(manga, myAnimeList).createObservable()
|
||||
() -> db.getMangaSync(manga, myAnimeList).asRxObservable()
|
||||
.doOnNext(mangaSync -> this.mangaSync = mangaSync)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread()),
|
||||
@ -75,7 +75,7 @@ public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> {
|
||||
}
|
||||
return Observable.error(new Exception("Could not find manga"));
|
||||
})
|
||||
.flatMap(myManga -> db.insertMangaSync(myManga).createObservable())
|
||||
.flatMap(myManga -> db.insertMangaSync(myManga).asRxObservable())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread()),
|
||||
(view, result) -> view.onRefreshDone(),
|
||||
@ -109,7 +109,7 @@ public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> {
|
||||
|
||||
private void updateRemote() {
|
||||
add(myAnimeList.update(mangaSync)
|
||||
.flatMap(response -> db.insertMangaSync(mangaSync).createObservable())
|
||||
.flatMap(response -> db.insertMangaSync(mangaSync).asRxObservable())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(next -> {},
|
||||
@ -139,7 +139,7 @@ public class MyAnimeListPresenter extends BasePresenter<MyAnimeListFragment> {
|
||||
add(myAnimeList.bind(manga)
|
||||
.flatMap(response -> {
|
||||
if (response.isSuccessful()) {
|
||||
return db.insertMangaSync(manga).createObservable();
|
||||
return db.insertMangaSync(manga).asRxObservable();
|
||||
}
|
||||
return Observable.error(new Exception("Could not bind manga"));
|
||||
})
|
||||
|
@ -172,8 +172,8 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||
|
||||
private Observable<Pair<Chapter, Chapter>> getAdjacentChaptersObservable() {
|
||||
return Observable.zip(
|
||||
db.getPreviousChapter(chapter).createObservable().take(1),
|
||||
db.getNextChapter(chapter).createObservable().take(1),
|
||||
db.getPreviousChapter(chapter).asRxObservable().take(1),
|
||||
db.getNextChapter(chapter).asRxObservable().take(1),
|
||||
Pair::create)
|
||||
.doOnNext(pair -> {
|
||||
previousChapter = pair.first;
|
||||
@ -211,7 +211,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||
}
|
||||
|
||||
private Observable<List<MangaSync>> getMangaSyncObservable() {
|
||||
return db.getMangasSync(manga).createObservable()
|
||||
return db.getMangasSync(manga).asRxObservable()
|
||||
.doOnNext(mangaSync -> this.mangaSyncList = mangaSync);
|
||||
}
|
||||
|
||||
@ -262,7 +262,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
|
||||
if (isChapterFinished()) {
|
||||
chapter.read = true;
|
||||
}
|
||||
db.insertChapter(chapter).createObservable().subscribe();
|
||||
db.insertChapter(chapter).asRxObservable().subscribe();
|
||||
}
|
||||
|
||||
// Check whether the chapter has been read
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -47,7 +47,6 @@ public class WebtoonAdapter extends RecyclerView.Adapter<WebtoonHolder> {
|
||||
|
||||
public void setPages(List<Page> pages) {
|
||||
this.pages = pages;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
|
@ -107,9 +107,8 @@ public class WebtoonReader extends BaseReader {
|
||||
if (pages != null) {
|
||||
unsubscribeStatus();
|
||||
recycler.clearOnScrollListeners();
|
||||
adapter.clear();
|
||||
recycler.scrollTo(0, 0);
|
||||
adapter.setPages(pages);
|
||||
recycler.setAdapter(adapter);
|
||||
setScrollListener();
|
||||
observeStatus(0);
|
||||
}
|
||||
|
@ -0,0 +1,103 @@
|
||||
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<RecyclerView.ViewHolder, Object> {
|
||||
|
||||
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<Object> 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);
|
||||
break;
|
||||
}
|
||||
|
||||
//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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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<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;
|
||||
}
|
||||
|
||||
public void onNextMangaChapters(List<Object> 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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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<RecentChaptersFragment> {
|
||||
|
||||
@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<List<Object>> getRecentChaptersObservable() {
|
||||
return db.getRecentChapters().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());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
18
app/src/main/res/layout/fragment_recent_chapters.xml
Normal file
18
app/src/main/res/layout/fragment_recent_chapters.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/chapter_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:background="@color/white"
|
||||
tools:listitem="@layout/item_recent_chapter">
|
||||
|
||||
</android.support.v7.widget.RecyclerView>
|
||||
|
||||
</RelativeLayout>
|
47
app/src/main/res/layout/item_recent_chapter.xml
Normal file
47
app/src/main/res/layout/item_recent_chapter.xml
Normal file
@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:background="@drawable/selector_chapter_light">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
|
||||
android:paddingLeft="?android:attr/listPreferredItemPaddingLeft"
|
||||
android:paddingRight="?android:attr/listPreferredItemPaddingRight"
|
||||
android:paddingStart="?android:attr/listPreferredItemPaddingStart">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="30dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manga_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
|
||||
android:singleLine="true"
|
||||
tools:text="My manga"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/chapter_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
android:maxLines="1"
|
||||
tools:text="Title"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</RelativeLayout>
|
14
app/src/main/res/layout/item_recent_chapter_section.xml
Normal file
14
app/src/main/res/layout/item_recent_chapter_section.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingLeft="24dp"
|
||||
android:singleLine="true"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/colorAccent"
|
||||
android:background="@android:color/transparent"
|
||||
android:textSize="16sp"
|
||||
android:id="@+id/section_text"
|
||||
android:textStyle="bold" />
|
@ -22,4 +22,9 @@
|
||||
android:title="@string/action_mark_as_unread"
|
||||
android:icon="@drawable/ic_action_undone_all"
|
||||
app:showAsAction="ifRoom"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/action_mark_previous_as_read"
|
||||
android:title="@string/action_mark_previous_as_read"/>
|
||||
|
||||
</menu>
|
@ -19,6 +19,7 @@
|
||||
<string name="action_select_all">Select all</string>
|
||||
<string name="action_mark_as_read">Mark as read</string>
|
||||
<string name="action_mark_as_unread">Mark as unread</string>
|
||||
<string name="action_mark_previous_as_read">Mark previous as read</string>
|
||||
<string name="action_download">Download</string>
|
||||
<string name="action_delete">Delete</string>
|
||||
<string name="action_update">Update</string>
|
||||
@ -64,7 +65,7 @@
|
||||
<string name="landscape">Landscape</string>
|
||||
<string name="default_columns">Default</string>
|
||||
<string name="pref_library_update_interval">Library update period</string>
|
||||
<string name="pref_update_only_non_completed">Update only non completed manga</string>
|
||||
<string name="pref_update_only_non_completed">Only update uncomplete manga</string>
|
||||
<string name="update_never">Manual</string>
|
||||
<string name="update_1hour">Hourly</string>
|
||||
<string name="update_2hour">Every 2 hours</string>
|
||||
@ -99,16 +100,16 @@
|
||||
<!-- Downloads section -->
|
||||
<string name="pref_download_directory">Downloads directory</string>
|
||||
<string name="pref_download_slots">Simultaneous downloads</string>
|
||||
<string name="pref_download_only_over_wifi">Download only over Wi-Fi</string>
|
||||
<string name="pref_download_only_over_wifi">Only download over Wi-Fi</string>
|
||||
|
||||
<!-- Advanced section -->
|
||||
<string name="pref_clear_chapter_cache">Clear chapter cache</string>
|
||||
<string name="used_cache">Used: %1$s</string>
|
||||
<string name="cache_deleted">Cache cleared. %1$d files have been deleted</string>
|
||||
<string name="cache_delete_error">An error occurred clearing cache</string>
|
||||
<string name="cache_delete_error">An error occurred while clearing cache</string>
|
||||
<string name="pref_clear_database">Clear database</string>
|
||||
<string name="pref_clear_database_summary">Delete mangas and chapters that are not in your library</string>
|
||||
<string name="clear_database_confirmation">Are you sure? Read chapters and progress of non library mangas will be lost</string>
|
||||
<string name="pref_clear_database_summary">Delete manga and chapters that are not in your library</string>
|
||||
<string name="clear_database_confirmation">Are you sure? Read chapters and progress of non-library manga will be lost</string>
|
||||
|
||||
<!-- About section -->
|
||||
<string name="version">Version</string>
|
||||
@ -116,7 +117,7 @@
|
||||
|
||||
<!-- ACRA -->
|
||||
<string name="pref_enable_acra">Send crash reports</string>
|
||||
<string name="pref_acra_summary">Help fixing bugs. Sensitive data is not sent</string>
|
||||
<string name="pref_acra_summary">Helps fixing bugs. No sensitive data is sent</string>
|
||||
|
||||
|
||||
<!-- Login dialog -->
|
||||
@ -178,7 +179,7 @@
|
||||
<string name="chapter_subtitle">Chapter %1$s</string>
|
||||
<string name="no_next_chapter">Next chapter not found</string>
|
||||
<string name="no_previous_chapter">Previous chapter not found</string>
|
||||
<string name="decode_image_error">The image could not be loaded.\nTry to change the image decoder</string>
|
||||
<string name="decode_image_error">Image could not be loaded.\nTry changing the image decoder</string>
|
||||
<string name="confirm_update_manga_sync">Update last chapter read in enabled services to %1$d?</string>
|
||||
|
||||
<!-- Downloads activity and service -->
|
||||
@ -187,9 +188,9 @@
|
||||
<!-- Library update service notifications -->
|
||||
<string name="notification_update_progress">Update progress: %1$d/%2$d</string>
|
||||
<string name="notification_update_completed">Update completed</string>
|
||||
<string name="notification_update_error">An unexpected error occurred updating the library</string>
|
||||
<string name="notification_update_error">An unexpected error occurred while updating the library</string>
|
||||
<string name="notification_no_new_chapters">No new chapters found</string>
|
||||
<string name="notification_new_chapters">Found new chapters for:</string>
|
||||
<string name="notification_manga_update_failed">Failed updating mangas:</string>
|
||||
<string name="notification_manga_update_failed">Failed updating manga:</string>
|
||||
|
||||
</resources>
|
||||
|
@ -1,40 +0,0 @@
|
||||
package eu.kanade.tachiyomi;
|
||||
|
||||
/**
|
||||
* Created by len on 1/10/15.
|
||||
*/
|
||||
import android.os.Build;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricGradleTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity;
|
||||
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
|
||||
@RunWith(RobolectricGradleTestRunner.class)
|
||||
public class MainActivityTest {
|
||||
private MainActivity activity;
|
||||
|
||||
// @Before => JUnit 4 annotation that specifies this method should run before each test is run
|
||||
// Useful to do setup for objects that are needed in the test
|
||||
@Before
|
||||
public void setup() {
|
||||
// Convenience method to run MainActivity through the Activity Lifecycle methods:
|
||||
// onCreate(...) => onStart() => onPostCreate(...) => onResume()
|
||||
activity = Robolectric.setupActivity(MainActivity.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validate() {
|
||||
Toolbar toolbar = (Toolbar)activity.findViewById(R.id.toolbar);
|
||||
assertNotNull(toolbar);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user