diff --git a/.gitignore b/.gitignore
index a6eebd56..2d300346 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,7 @@
.gradle
/local.properties
/.idea
-.DS_Store
+*.iml
/build
-/captures
-.navigation
-.directory
+/captures/
+.directory
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index d49abf21..de5e87ad 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,20 @@
language: android
-android:
- components:
- - platform-tools
- - tools
- - build-tools-26.0.2
- - android-26
- - extra-android-m2repository
jdk:
- oraclejdk8
+
+android:
+ components:
+ - platform-tools
+ - tools
+ - tools
+ - build-tools-28.0.2
+ - android-28
+ - extra-android-m2repository
+
+ licenses:
+ - android-sdk-license-.+
+ - android-sdk-preview-license-.+
+
script:
- ./gradlew build connectedCheck
\ No newline at end of file
diff --git a/OpenManga.iml b/OpenManga.iml
deleted file mode 100644
index c15cda03..00000000
--- a/OpenManga.iml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/README.md b/README.md
index 169ebbc2..47b642c3 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,9 @@ OpenManga - Powerful manga reader for Android with online catalogues.
[![Get it on F-Droid](https://cloud.githubusercontent.com/assets/8948226/22860847/7476f5c4-f112-11e6-9031-5ac233d26678.png)](https://f-droid.org/repository/browse/?fdid=org.nv95.openmanga) [![Donate](https://cloud.githubusercontent.com/assets/8948226/26622455/20e44520-45f3-11e7-9257-7c3900697b75.png)](https://money.yandex.ru/to/410012543938752)
+## Current status
+Development is discontinued now. If you want to help with this project, please, [contact me](https://t.me/Koitharu)
+
## Features
- 14 online manga's catalogues with search
- Downloading manga to local storage
diff --git a/app/app.iml b/app/app.iml
deleted file mode 100644
index a9a90d89..00000000
--- a/app/app.iml
+++ /dev/null
@@ -1,134 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- generateDebugSources
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 236e46ae..b285af39 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,24 +1,30 @@
apply plugin: 'com.android.application'
-android {
- compileSdkVersion 26
- buildToolsVersion "26.0.2"
+def gitCommits = 'git rev-list --all --count'.execute([], rootDir).text.trim().toInteger()
+
+def timestamp = new Date().getTime()
+android {
+ compileSdkVersion 28
+ buildToolsVersion '28.0.3'
defaultConfig {
applicationId "org.nv95.openmanga"
- minSdkVersion 14
- targetSdkVersion 26
- versionCode 1115
- versionName "preview build"
+ minSdkVersion 15
+ targetSdkVersion 28
+ versionCode gitCommits
+ versionName "5.0"
+
+ resConfigs "en", "ru", "tr", "uk"
buildConfigField "boolean", "SELFUPDATE_ENABLED", "true"
buildConfigField "String", "SELFUPDATE_URL", "\"http://anibreak.ru/v.0.3/get/openmanga/version\""
- buildConfigField "String", "SYNC_URL", "\"http://46.36.36.38:5000/api/v1\""
+ buildConfigField "String", "SYNC_URL", "\"http://openmanga.pythonanywhere.com/api/v1\""
+ buildConfigField "long", "TIMESTAMP", "${timestamp}L"
}
signingConfigs {
debug {
storeFile file("debug.jks")
- storePassword 'develop'
+ storePassword "develop"
keyAlias "develop"
keyPassword "develop"
}
@@ -26,40 +32,54 @@ android {
buildTypes {
release {
- minifyEnabled false
- shrinkResources false
+ minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ setProperty("archivesBaseName", "OpenManga-v${defaultConfig.versionName}")
+ resValue "string", "app_name", "OpenManga"
}
- debug {
+ debug {
+ zipAlignEnabled true
applicationIdSuffix ".debug"
- minifyEnabled false
- shrinkResources false
- signingConfig signingConfigs.debug
+ versionNameSuffix="a"
+ signingConfig signingConfigs.debug
+ resValue "string", "app_name", "OpenManga Debug"
+ }
+
+ fdroid {
+ initWith release
+ buildConfigField "boolean", "SELFUPDATE_ENABLED", "false"
+ versionNameSuffix="-fdroid"
}
}
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
lintOptions {
disable 'MissingTranslation'
abortOnError false
}
- allprojects {
- repositories {
- jcenter()
- google()
- maven { url "https://jitpack.io" }
- }
- }
+}
+
+ext {
+ supportLib = '28.0.0'
}
dependencies {
+ implementation "com.android.support:design:${supportLib}"
+ implementation "com.android.support:support-v4:${supportLib}"
+ implementation "com.android.support:recyclerview-v7:${supportLib}"
+ implementation "com.android.support:cardview-v7:${supportLib}"
+ implementation "com.android.support:exifinterface:${supportLib}"
- compile 'com.android.support:design:26.1.0'
- compile 'com.android.support:recyclerview-v7:26.1.0'
- compile 'com.android.support:cardview-v7:26.1.0'
- compile 'org.jsoup:jsoup:1.10.3'
- compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.6.0'
- compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
- compile 'com.soundcloud.android:android-crop:1.0.1@aar'
- compile 'com.getkeepsafe.taptargetview:taptargetview:1.9.1'
- compile 'info.guardianproject.netcipher:netcipher:2.0.0-alpha1'
+ implementation 'com.squareup.okhttp3:okhttp:3.11.0'
+ implementation 'com.squareup.duktape:duktape-android:1.3.0'
+ implementation 'info.guardianproject.netcipher:netcipher:2.0.0-beta1'
+ implementation 'info.guardianproject.netcipher:netcipher-okhttp3:2.0.0-alpha1'
+ implementation 'org.jsoup:jsoup:1.11.3'
+ implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
+ implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
}
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 7b52c41f..2df912c1 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,11 +1,11 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
-# in /media/HDD1/Other/Android/Sdk/tools/proguard/proguard-android.txt
+# in C:/$USER/JTM/AppData/Local/Android/Sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
+# https://developer.android.com/studio/build/shrink-code.html
# Add any project specific keep options here:
@@ -15,3 +15,17 @@
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
+
+-keeppackagenames org.jsoup.nodes
+
+# JSR 305 annotations are for embedding nullability information.
+-dontwarn javax.annotation.**
+
+# A resource is loaded with a relative path so the package of this class must be preserved.
+-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
+
+# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
+-dontwarn org.codehaus.mojo.animal_sniffer.*
+
+# OkHttp platform used only on JVM and when Conscrypt dependency is available.
+-dontwarn okhttp3.internal.platform.ConscryptPlatform
\ No newline at end of file
diff --git a/app/src/debug/res/values/strings.xml b/app/src/debug/res/values/strings.xml
deleted file mode 100644
index b9f9a9b5..00000000
--- a/app/src/debug/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
- OpenManga Debug
-
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index f1cc58c4..a0e09bb0 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,95 +1,263 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ xmlns:tools="http://schemas.android.com/tools"
+ package="org.nv95.openmanga"
+ android:installLocation="auto">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/org/nv95/openmanga/AppBaseActivity.java b/app/src/main/java/org/nv95/openmanga/AppBaseActivity.java
new file mode 100644
index 00000000..831e9d74
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/AppBaseActivity.java
@@ -0,0 +1,193 @@
+package org.nv95.openmanga;
+
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.ColorRes;
+import android.support.annotation.IdRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.Toast;
+
+import org.nv95.openmanga.common.utils.ThemeUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public abstract class AppBaseActivity extends AppCompatActivity {
+
+ private boolean mActionBarVisible = false;
+ private boolean mHomeAsUpEnabled = false;
+ private int mTheme = 0;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mTheme = ThemeUtils.getAppTheme(this);
+ setTheme(ThemeUtils.getAppThemeRes(mTheme));
+ }
+
+ public boolean isDarkTheme() {
+ return mTheme > 7;
+ }
+
+ public void enableHomeAsUp() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null && !mHomeAsUpEnabled) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ mHomeAsUpEnabled = true;
+ }
+ }
+
+ public void enableHomeAsClose() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null && !mHomeAsUpEnabled) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_cancel_light);
+ mHomeAsUpEnabled = true;
+ }
+ }
+
+ public void disableTitle() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayShowTitleEnabled(false);
+ }
+ }
+
+ @Override
+ public void setSupportActionBar(@Nullable Toolbar toolbar) {
+ super.setSupportActionBar(toolbar);
+ mActionBarVisible = toolbar != null;
+ }
+
+ public void setSupportActionBar(@IdRes int toolbarId) {
+ setSupportActionBar(findViewById(toolbarId));
+ }
+
+ public void hideActionBar() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null && mActionBarVisible) {
+ mActionBarVisible = false;
+ actionBar.hide();
+ }
+ }
+
+ public void showActionBar() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null && !mActionBarVisible) {
+ mActionBarVisible = true;
+ actionBar.show();
+ }
+ }
+
+ public void toggleActionBar() {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ if (!mActionBarVisible) {
+ mActionBarVisible = true;
+ actionBar.show();
+ } else {
+ mActionBarVisible = false;
+ actionBar.hide();
+ }
+ }
+ }
+
+ public boolean isActionBarVisible() {
+ return mActionBarVisible;
+ }
+
+ public int getActivityTheme() {
+ return mTheme;
+ }
+
+ public void setSubtitle(@Nullable CharSequence subtitle) {
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setSubtitle(subtitle);
+ }
+ }
+
+ public void setSubtitle(@StringRes int subtitle) {
+ setSubtitle(getString(subtitle));
+ }
+
+ public void enableTransparentStatusBar(@ColorRes int color) {
+ if (Build.VERSION.SDK_INT >= 21) {
+ Window window = getWindow();
+ window.getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ if (color != 0) {
+ window.setStatusBarColor(ContextCompat.getColor(this, color));
+ }
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home && mHomeAsUpEnabled) {
+ finish();
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ public void setKeepScreenOn(boolean flag) {
+ if (flag) {
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ } else {
+ getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ }
+ }
+
+ public void checkPermissions(int requestCode, String... permissions) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ for (String o : permissions) {
+ onPermissionGranted(requestCode, o);
+ }
+ }
+ final ArrayList required = new ArrayList<>(permissions.length);
+ for (String o : permissions) {
+ if (ContextCompat.checkSelfPermission(this, o) != PackageManager.PERMISSION_GRANTED) {
+ required.add(o);
+ } else {
+ onPermissionGranted(requestCode, o);
+ }
+ }
+ if (!required.isEmpty()) {
+ ActivityCompat.requestPermissions(this, required.toArray(new String[required.size()]), requestCode);
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ for (int i = 0; i < permissions.length; i++) {
+ if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
+ onPermissionGranted(requestCode, permissions[i]);
+ }
+ }
+ }
+
+ protected void onPermissionGranted(int requestCode, String permission) {
+
+ }
+
+ protected void stub() {
+ Toast.makeText(this, "Not implemented", Toast.LENGTH_SHORT).show();
+ }
+}
+
diff --git a/app/src/main/java/org/nv95/openmanga/AppBaseDialogFragment.java b/app/src/main/java/org/nv95/openmanga/AppBaseDialogFragment.java
new file mode 100644
index 00000000..8ea43660
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/AppBaseDialogFragment.java
@@ -0,0 +1,21 @@
+package org.nv95.openmanga;
+
+import android.support.v7.app.AppCompatDialogFragment;
+import android.view.ViewGroup;
+import android.view.Window;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+public abstract class AppBaseDialogFragment extends AppCompatDialogFragment {
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Window window = getDialog().getWindow();
+ if (window != null) {
+ window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/AppBaseFragment.java b/app/src/main/java/org/nv95/openmanga/AppBaseFragment.java
new file mode 100644
index 00000000..86743d8f
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/AppBaseFragment.java
@@ -0,0 +1,22 @@
+package org.nv95.openmanga;
+
+import android.app.Fragment;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public abstract class AppBaseFragment extends Fragment {
+
+ protected View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @LayoutRes int resource) {
+ return inflater.inflate(resource, container, false);
+ }
+
+ public void scrollToTop() {
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/AsyncService.java b/app/src/main/java/org/nv95/openmanga/AsyncService.java
new file mode 100644
index 00000000..0d754865
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/AsyncService.java
@@ -0,0 +1,153 @@
+package org.nv95.openmanga;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Created by koitharu on 25.01.18.
+ */
+
+public abstract class AsyncService extends Service implements Handler.Callback {
+
+ private static final int MSG_PRE_EXECUTE = 1;
+ private static final int MSG_POST_EXECUTE = 2;
+ private static final int MSG_UPDATE_PROGRESS = 3;
+ private static final int MSG_STOP_SELF = 4;
+
+ private Handler mHandler;
+ @Nullable
+ private BackgroundThread mThread;
+ private LinkedBlockingQueue mQueue;
+ private final AtomicBoolean mCancelled = new AtomicBoolean();
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mHandler = new Handler(this);
+ mQueue = new LinkedBlockingQueue<>(2);
+ mThread = null;
+ }
+
+ @Override
+ public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
+ final String action = intent == null ? null : intent.getAction();
+ //noinspection ConstantConditions
+ if (action != null && onNewIntent(action, intent.getExtras())) {
+ //TODO
+ } else {
+ stopSelf();
+ }
+ return START_NOT_STICKY;
+ }
+
+ public abstract boolean onNewIntent(@NonNull String action, @NonNull Bundle extras);
+
+ public boolean onStopService() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_STOP_SELF:
+ if (onStopService()) {
+ stopSelf();
+ }
+ return true;
+ case MSG_PRE_EXECUTE:
+ onPreExecute((R) msg.obj);
+ return true;
+ case MSG_POST_EXECUTE:
+ onPostExecute((R) msg.obj, msg.arg1);
+ return true;
+ case MSG_UPDATE_PROGRESS:
+ onProgressUpdate(msg.arg1, msg.arg2, msg.obj);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @MainThread
+ public abstract void onPreExecute(R r);
+
+ @WorkerThread
+ public abstract int doInBackground(R r);
+
+ @MainThread
+ public abstract void onPostExecute(R r, int result);
+
+ @WorkerThread
+ protected final void setProgress(int progress, int max, @Nullable Object extra) {
+ Message msg = Message.obtain();
+ msg.what = MSG_UPDATE_PROGRESS;
+ msg.arg1 = progress;
+ msg.arg2 = max;
+ msg.obj = extra;
+ mHandler.sendMessage(msg);
+ }
+
+ public abstract void onProgressUpdate(int progress, int max, @Nullable Object extra);
+
+ @MainThread
+ public void startBackground(R r) {
+ try {
+ mQueue.put(r);
+ if (mThread == null) {
+ mThread = new BackgroundThread();
+ }
+ mCancelled.set(false);
+ mThread.start();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @MainThread
+ public void cancelBackground() {
+ mCancelled.set(true);
+ }
+
+ public boolean isCancelled() {
+ return mCancelled.get();
+ }
+
+ private final class BackgroundThread extends Thread {
+
+ @Override
+ public void run() {
+ R r;
+ while (!mCancelled.get() && (r = mQueue.poll()) != null) {
+ Message msg = Message.obtain();
+ msg.what = MSG_PRE_EXECUTE;
+ msg.obj = r;
+ mHandler.sendMessage(msg);
+ final int result = doInBackground(r);
+ msg = Message.obtain();
+ msg.what = MSG_POST_EXECUTE;
+ msg.arg1 = result;
+ msg.obj = r;
+ mHandler.sendMessage(msg);
+ }
+ mHandler.sendEmptyMessage(MSG_STOP_SELF);
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/MainActivity.java b/app/src/main/java/org/nv95/openmanga/MainActivity.java
new file mode 100644
index 00000000..aad23a8e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/MainActivity.java
@@ -0,0 +1,188 @@
+package org.nv95.openmanga;
+
+import android.app.Fragment;
+import android.app.SearchManager;
+import android.app.SearchableInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.widget.BottomNavigationView;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.PopupMenu;
+import android.support.v7.widget.SearchView;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageView;
+
+import org.nv95.openmanga.common.CrashHandler;
+import org.nv95.openmanga.core.storage.FlagsStorage;
+import org.nv95.openmanga.discover.DiscoverFragment;
+import org.nv95.openmanga.search.SearchActivity;
+import org.nv95.openmanga.shelf.OnTipsActionListener;
+import org.nv95.openmanga.shelf.ShelfFragment;
+import org.nv95.openmanga.tools.ToolsFragment;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public final class MainActivity extends AppBaseActivity implements BottomNavigationView.OnNavigationItemSelectedListener,
+ BottomNavigationView.OnNavigationItemReselectedListener, View.OnClickListener, PopupMenu.OnMenuItemClickListener,
+ OnTipsActionListener {
+
+ private BottomNavigationView mBottomNavigationView;
+ private PopupMenu mMainMenu;
+ private View mContent;
+ private AppBaseFragment mFragment;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ setSupportActionBar(R.id.toolbar);
+
+ mBottomNavigationView = findViewById(R.id.bottomNavView);
+ ImageView mImageViewMenu = findViewById(R.id.imageViewMenu);
+ SearchView mSearchView = findViewById(R.id.searchView);
+ mContent = findViewById(R.id.content);
+
+ mMainMenu = new PopupMenu(this, mImageViewMenu);
+ mMainMenu.setOnMenuItemClickListener(this);
+
+ mBottomNavigationView.setOnNavigationItemSelectedListener(this);
+ mBottomNavigationView.setOnNavigationItemReselectedListener(this);
+ mImageViewMenu.setOnClickListener(this);
+
+ final SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
+ final SearchableInfo searchableInfo;
+ if (searchManager != null) {
+ searchableInfo = searchManager.getSearchableInfo(new ComponentName(this, SearchActivity.class));
+ mSearchView.setSearchableInfo(searchableInfo);
+ }
+
+ mFragment = new ShelfFragment();
+ initMenu();
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content, mFragment)
+ .commitAllowingStateLoss();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mContent.requestFocus();
+ }
+
+ @Override
+ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
+ mFragment.onDestroyOptionsMenu();
+ switch (item.getItemId()) {
+ case R.id.section_shelf:
+ mFragment = new ShelfFragment();
+ break;
+ case R.id.section_discover:
+ mFragment = new DiscoverFragment();
+ break;
+ case R.id.action_tools:
+ mFragment = new ToolsFragment();
+ break;
+ default:
+ return false;
+ }
+ initMenu();
+ getFragmentManager().beginTransaction()
+ .replace(R.id.content, mFragment)
+ .commit();
+ return true;
+ }
+
+
+ @Override
+ public void onNavigationItemReselected(@NonNull MenuItem item) {
+ Fragment fragment = getFragmentManager().findFragmentById(R.id.content);
+ if (fragment != null && fragment instanceof AppBaseFragment) {
+ ((AppBaseFragment) fragment).scrollToTop();
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ switch (view.getId()) {
+ case R.id.imageViewMenu:
+ showMainMenu();
+ break;
+ }
+ }
+
+ private void initMenu() {
+ mMainMenu.getMenu().clear();
+ mFragment.onCreateOptionsMenu(mMainMenu.getMenu(), mMainMenu.getMenuInflater());
+ mMainMenu.inflate(R.menu.options_main);
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+
+ default:
+ return mFragment.onOptionsItemSelected(item);
+ }
+ }
+
+ private void onPrepareMenu(Menu menu) {
+ }
+
+ private void showMainMenu() {
+ onPrepareMenu(mMainMenu.getMenu());
+ mFragment.onPrepareOptionsMenu(mMainMenu.getMenu());
+ mMainMenu.show();
+ }
+
+ @Override
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_MENU) {
+ showMainMenu();
+ return true;
+ }
+ return super.onKeyUp(keyCode, event);
+ }
+
+ @Override
+ public void onTipActionClick(int actionId) {
+ switch (actionId) {
+ case R.id.action_crash_report:
+ final CrashHandler crashHandler = CrashHandler.get();
+ if (crashHandler != null) {
+ new AlertDialog.Builder(this)
+ .setTitle(crashHandler.getErrorClassName())
+ .setMessage(crashHandler.getErrorMessage() + "\n\n" + crashHandler.getErrorStackTrace())
+ .setNegativeButton(R.string.close, null)
+ .create()
+ .show();
+ }
+ break;
+ case R.id.action_discover:
+ mBottomNavigationView.setSelectedItemId(R.id.section_discover);
+ break;
+ }
+ }
+
+ @Override
+ public void onTipDismissed(int actionId) {
+ switch (actionId) {
+ case R.id.action_crash_report:
+ final CrashHandler crashHandler = CrashHandler.get();
+ if (crashHandler != null) {
+ crashHandler.clear();
+ }
+ break;
+ case R.id.action_wizard:
+ FlagsStorage.get(this).setWizardRequired(false);
+ break;
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/MangaListLoader.java b/app/src/main/java/org/nv95/openmanga/MangaListLoader.java
deleted file mode 100644
index 6fa4aae2..00000000
--- a/app/src/main/java/org/nv95/openmanga/MangaListLoader.java
+++ /dev/null
@@ -1,236 +0,0 @@
-package org.nv95.openmanga;
-
-import android.os.AsyncTask;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-
-import org.nv95.openmanga.adapters.EndlessAdapter;
-import org.nv95.openmanga.adapters.MangaListAdapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.lists.MangaList;
-
-/**
- * Created by nv95 on 25.01.16.
- */
-public class MangaListLoader implements EndlessAdapter.OnLoadMoreListener {
-
- private RecyclerView mRecyclerView;
- @NonNull
- private final MangaListAdapter mAdapter;
- private final OnContentLoadListener mContentLoadListener;
- @NonNull
- private final MangaList mList;
- @Nullable
- private LoadContentTask mTaskInstance;
-
- public MangaListLoader(RecyclerView recyclerView, @NonNull OnContentLoadListener listener) {
- mRecyclerView = recyclerView;
- mContentLoadListener = listener;
- mList = new MangaList();
- mAdapter = new MangaListAdapter(mList, mRecyclerView);
- mRecyclerView.setAdapter(mAdapter);
- mAdapter.setOnLoadMoreListener(this);
- }
-
- public void attach(RecyclerView recyclerView) {
- mRecyclerView = recyclerView;
- mAdapter.attach(recyclerView);
- mRecyclerView.setAdapter(mAdapter);
- }
-
- @Override
- public void onLoadMore() {
- new LoadContentTask(mList.getPagesCount(), true).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- public MangaListAdapter getAdapter() {
- return mAdapter;
- }
-
- public void clearItems() {
- clearItemsLazy();
- if (mContentLoadListener != null) {
- mContentLoadListener.onContentLoaded(true);
- }
- }
-
- public int getCurrentPage() {
- return mList.getPagesCount();
- }
-
- public void loadFromPage(int page) {
- mList.clear();
- mAdapter.notifyDataSetChanged();
- mList.setPagesCount(page);
- mList.setHasNext(true);
- cancelLoading();
- new LoadContentTask(page, true).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- public void loadContent(boolean appendable, boolean invalidate) {
- if (invalidate) {
- mList.clear();
- mAdapter.notifyDataSetChanged();
- }
- mList.setHasNext(appendable);
- cancelLoading();
- new LoadContentTask(0, appendable).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- public void addItem(MangaInfo data) {
- if (mList.add(data)) {
- mAdapter.notifyItemInserted(mList.size() - 1);
- if (mList.size() == 1 && mContentLoadListener != null) {
- mContentLoadListener.onContentLoaded(true);
- }
- }
- }
-
- public void addItem(MangaInfo data, int position) {
- mList.add(position, data);
- mAdapter.notifyItemInserted(position);
- if (mList.size() == 1 && mContentLoadListener != null) {
- mContentLoadListener.onContentLoaded(true);
- }
- }
-
- public void removeItem(int position) {
- mList.remove(position);
- mAdapter.notifyItemRemoved(position);
- if (mList.size() == 0 && mContentLoadListener != null) {
- mContentLoadListener.onContentLoaded(true);
- }
- }
-
- public void notifyRemoved(int position) {
- mAdapter.notifyItemRemoved(position);
- if (mList.size() == 0 && mContentLoadListener != null) {
- mContentLoadListener.onContentLoaded(true);
- }
- }
-
- public void moveItem(int from, int to) {
- MangaInfo item = mList.get(from);
- mList.remove(from);
- mList.add(to - (from >= to ? 0 : 1), item);
- mAdapter.notifyItemMoved(from, to);
- }
-
- public void updateItem(int pos, MangaInfo data) {
- mList.set(pos, data);
- mAdapter.notifyItemChanged(pos);
- }
-
- public void cancelLoading() {
- if (mTaskInstance != null && mTaskInstance.getStatus() != AsyncTask.Status.FINISHED) {
- mTaskInstance.cancel(true);
- }
- }
-
- public MangaList getList() {
- return mList;
- }
-
- public int getContentSize() {
- return mList.size();
- }
-
- public void clearItemsLazy() {
- mList.clear();
- mAdapter.notifyDataSetChanged();
- }
-
- public interface OnContentLoadListener {
- void onContentLoaded(boolean success);
-
- void onLoadingStarts(boolean hasItems);
-
- @Nullable
- MangaList onContentNeeded(int page);
- }
-
- public void updateLayout(boolean grid, int spanCount, ThumbSize thumbSize) {
- GridLayoutManager layoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager();
- int position = layoutManager.findFirstCompletelyVisibleItemPosition();
- layoutManager.setSpanCount(spanCount);
- layoutManager.setSpanSizeLookup(new AutoSpanSizeLookup(spanCount));
- mAdapter.setThumbnailsSize(thumbSize);
- if (mAdapter.setGrid(grid)) {
- mRecyclerView.setAdapter(mAdapter);
- }
- mRecyclerView.scrollToPosition(position);
- }
-
- public MangaInfo[] getItems(int[] positions) {
- MangaInfo[] items = new MangaInfo[positions.length];
- for (int i=0;i {
- private final int mPage;
- private final boolean mAppendable;
-
- public LoadContentTask(int page, boolean appendable) {
- this.mPage = page;
- cancelLoading();
- mTaskInstance = this;
- mAppendable = appendable;
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- mContentLoadListener.onLoadingStarts(!mList.isEmpty());
- }
-
- @Override
- protected MangaList doInBackground(Void... params) {
- return mContentLoadListener.onContentNeeded(mPage);
- }
-
- @Override
- protected void onPostExecute(MangaList list) {
- super.onPostExecute(list);
- if (list == null) {
- mList.setHasNext(false);
- mAdapter.notifyItemChanged(mList.size());
- mContentLoadListener.onContentLoaded(false);
- return;
- }
- mList.appendPage(list);
- if (list.size() != 0) {
- if (mList.size() == list.size()) {
- mAdapter.notifyDataSetChanged();
- } else {
- mAdapter.notifyItemRangeInserted(mList.size() - 1, mList.size() - list.size());
- }
- mList.setHasNext(mAppendable);
- } else {
- mList.setHasNext(false);
- mAdapter.notifyItemChanged(mList.size());
- }
- mAdapter.setLoaded();
- mContentLoadListener.onContentLoaded(true);
- mTaskInstance = null;
- }
- }
-
- public class AutoSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
- final int mCount;
-
- public AutoSpanSizeLookup(int mCount) {
- this.mCount = mCount;
- }
-
- @Override
- public int getSpanSize(int position) {
- return mAdapter.getItemViewType(position) == 0 ? mCount : 1;
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/OpenMangaApp.java b/app/src/main/java/org/nv95/openmanga/OpenMangaApp.java
new file mode 100644
index 00000000..96b91beb
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/OpenMangaApp.java
@@ -0,0 +1,62 @@
+package org.nv95.openmanga;
+
+import android.app.Activity;
+import android.app.Application;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+
+import org.nv95.openmanga.common.CrashHandler;
+import org.nv95.openmanga.common.utils.ImageUtils;
+import org.nv95.openmanga.common.utils.ResourceUtils;
+import org.nv95.openmanga.common.utils.network.CookieStore;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.storage.settings.AppSettings;
+import org.nv95.openmanga.updchecker.JobSetupReceiver;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public final class OpenMangaApp extends Application {
+
+ private CrashHandler mCrashHandler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ mCrashHandler = new CrashHandler(this);
+ Thread.setDefaultUncaughtExceptionHandler(mCrashHandler);
+ final AppSettings settings = AppSettings.get(this);
+ ImageUtils.init(this);
+ CookieStore.getInstance().init(this);
+ NetworkUtils.init(this, settings.isUseTor());
+ ResourceUtils.setLocale(getResources(), settings.getAppLocale());
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ if (!prefs.getBoolean(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, false)) {
+ PreferenceManager.setDefaultValues(this, R.xml.pref_appearance, true);
+ PreferenceManager.setDefaultValues(this, R.xml.pref_network, true);
+ //TODO other
+ JobSetupReceiver.setup(this);
+ prefs.edit().putBoolean(PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES, true).apply();
+ }
+ }
+
+ public void restart() {
+ final Intent intent = getBaseContext().getPackageManager()
+ .getLaunchIntentForPackage(getBaseContext().getPackageName());
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ startActivity(intent);
+ }
+
+ @NonNull
+ public CrashHandler getCrashHandler() {
+ return mCrashHandler;
+ }
+
+ @NonNull
+ public static OpenMangaApp from(Activity activity) {
+ return (OpenMangaApp) activity.getApplication();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/OpenMangaApplication.java b/app/src/main/java/org/nv95/openmanga/OpenMangaApplication.java
deleted file mode 100755
index 3c968b2b..00000000
--- a/app/src/main/java/org/nv95/openmanga/OpenMangaApplication.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.nv95.openmanga;
-
-import android.app.Application;
-import android.content.res.Resources;
-import android.preference.PreferenceManager;
-import android.text.TextUtils;
-import android.util.DisplayMetrics;
-
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.FileLogger;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.NetworkUtils;
-
-import java.util.Locale;
-
-/**
- * Created by nv95 on 10.12.15.
- */
-public class OpenMangaApplication extends Application {
-
- @Override
- public void onCreate() {
- super.onCreate();
- FileLogger.init(this);
- Resources resources = getResources();
- final float aspectRatio = 18f / 13f;
- ThumbSize.THUMB_SIZE_LIST = new ThumbSize(
- resources.getDimensionPixelSize(R.dimen.thumb_width_list),
- resources.getDimensionPixelSize(R.dimen.thumb_height_list)
- );
- ThumbSize.THUMB_SIZE_SMALL = new ThumbSize(
- resources.getDimensionPixelSize(R.dimen.thumb_width_small),
- aspectRatio
- );
- ThumbSize.THUMB_SIZE_MEDIUM = new ThumbSize(
- resources.getDimensionPixelSize(R.dimen.thumb_width_medium),
- aspectRatio
- );
- ThumbSize.THUMB_SIZE_LARGE = new ThumbSize(
- resources.getDimensionPixelSize(R.dimen.thumb_width_large),
- aspectRatio
- );
-
- ImageUtils.init(this);
- AnimUtils.init(this);
- NetworkUtils.setUseTor(this, PreferenceManager.getDefaultSharedPreferences(this).getBoolean("use_tor", false));
- ScheduledServiceReceiver.enable(this);
- setLanguage(getResources(), PreferenceManager.getDefaultSharedPreferences(this).getString("lang", ""));
- }
-
- public static void setLanguage(Resources res, String lang) {
- DisplayMetrics dm = res.getDisplayMetrics();
- android.content.res.Configuration conf = res.getConfiguration();
- conf.locale = TextUtils.isEmpty(lang) ? Locale.getDefault() : new Locale(lang);
- res.updateConfiguration(conf, dm);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/ScheduledServiceReceiver.java b/app/src/main/java/org/nv95/openmanga/ScheduledServiceReceiver.java
deleted file mode 100755
index 4cfae435..00000000
--- a/app/src/main/java/org/nv95/openmanga/ScheduledServiceReceiver.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.nv95.openmanga;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.net.ConnectivityManager;
-
-import org.nv95.openmanga.services.ScheduledService;
-import org.nv95.openmanga.utils.FileLogger;
-
-/**
- * Created by nv95 on 19.12.15.
- */
-public class ScheduledServiceReceiver extends BroadcastReceiver {
-
- public static final long SCHEDULE_INTERVAL = AlarmManager.INTERVAL_HOUR / 30;
-
- public static void enable(Context context) {
- Intent intent = new Intent(context, ScheduledService.class);
- PendingIntent pIntent = PendingIntent.getService(context, 478, intent, 0);
- AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
- alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
- SCHEDULE_INTERVAL, SCHEDULE_INTERVAL, pIntent);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getAction()) {
- case Intent.ACTION_BOOT_COMPLETED:
- case "android.intent.action.QUICKBOOT_POWERON":
- enable(context);
- break;
- case ConnectivityManager.CONNECTIVITY_ACTION:
- context.startService(new Intent(context, ScheduledService.class));
- break;
- default:
- FileLogger.getInstance().report("--ScheduledServiceReceiver unknown action");
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/SharedFileProvider.java b/app/src/main/java/org/nv95/openmanga/SharedFileProvider.java
new file mode 100644
index 00000000..83f5ea83
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/SharedFileProvider.java
@@ -0,0 +1,11 @@
+package org.nv95.openmanga;
+
+import android.support.v4.content.FileProvider;
+
+/**
+ * Created by koitharu on 30.01.18.
+ */
+
+public final class SharedFileProvider extends FileProvider {
+ public static final String AUTHORITY = "org.nv95.openmanga.files";
+}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/AboutActivity.java b/app/src/main/java/org/nv95/openmanga/activities/AboutActivity.java
deleted file mode 100644
index aed32058..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/AboutActivity.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.os.Bundle;
-import android.support.v7.widget.Toolbar;
-import android.text.Html;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.InternalLinkMovement;
-
-/**
- * Created by nv95 on 12.01.16.
- */
-public class AboutActivity extends BaseAppActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_about);
- setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
- enableHomeAsUp();
- TextView textView = (TextView) findViewById(R.id.textView);
- assert textView != null;
- textView.setText(Html.fromHtml(AppHelper.getRawString(this, R.raw.about)));
- textView.setMovementMethod(new InternalLinkMovement(null));
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/BaseAppActivity.java b/app/src/main/java/org/nv95/openmanga/activities/BaseAppActivity.java
deleted file mode 100644
index 662d980e..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/BaseAppActivity.java
+++ /dev/null
@@ -1,302 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.graphics.Color;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.annotation.ColorRes;
-import android.support.annotation.IdRes;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.design.widget.AppBarLayout;
-import android.support.design.widget.Snackbar;
-import android.support.v4.app.ActivityCompat;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.Toolbar;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.Toast;
-
-import com.getkeepsafe.taptargetview.TapTarget;
-import com.getkeepsafe.taptargetview.TapTargetView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.NetworkUtils;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 19.02.16.
- */
-public abstract class BaseAppActivity extends AppCompatActivity {
-
- private static final int REQUEST_PERMISSION = 112;
-
- private boolean mActionBarVisible = false;
- private boolean mHomeAsUpEnabled = false;
- private int mTheme = 0;
- @Nullable
- private ArrayList> mLoaders;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mTheme = LayoutUtils.getAppTheme(this);
- setTheme(LayoutUtils.getAppThemeRes(mTheme));
- }
-
- public boolean isDarkTheme() {
- return mTheme > 7;
- }
-
- public void enableHomeAsUp() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null && !mHomeAsUpEnabled) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- mHomeAsUpEnabled = true;
- }
- }
-
- public void enableHomeAsClose() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null && !mHomeAsUpEnabled) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setHomeAsUpIndicator(R.drawable.ic_cancel_light);
- mHomeAsUpEnabled = true;
- }
- }
-
- public void disableTitle() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setDisplayShowTitleEnabled(false);
- }
- }
-
- @Override
- public void setSupportActionBar(@Nullable Toolbar toolbar) {
- super.setSupportActionBar(toolbar);
- mActionBarVisible = toolbar != null;
- }
-
- void setupToolbarScrolling(Toolbar toolbar) {
- setToolbarScrollingLock(toolbar, false);
- }
-
- void setToolbarScrollingLock(Toolbar toolbar, boolean lock) {
- if (toolbar == null || !(toolbar.getParent() instanceof AppBarLayout)) {
- return;
- }
- boolean scrolls = !lock && PreferenceManager.getDefaultSharedPreferences(this).getBoolean("hide_toolbars", true);
- AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) toolbar.getLayoutParams();
- params.setScrollFlags(scrolls ? AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS : 0);
- }
-
- public void setSupportActionBar(@IdRes int toolbarId) {
- setSupportActionBar((Toolbar) findViewById(toolbarId));
- }
-
- public void hideActionBar() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null && mActionBarVisible) {
- mActionBarVisible = false;
- actionBar.hide();
- }
- }
-
- public void showActionBar() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null && !mActionBarVisible) {
- mActionBarVisible = true;
- actionBar.show();
- }
- }
-
- public void toggleActionBar() {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- if (!mActionBarVisible) {
- mActionBarVisible = true;
- actionBar.show();
- } else {
- mActionBarVisible = false;
- actionBar.hide();
- }
- }
- }
-
- public boolean isActionBarVisible() {
- return mActionBarVisible;
- }
-
- public int getActivityTheme() {
- return mTheme;
- }
-
- public void setSubtitle(@Nullable CharSequence subtitle) {
- final ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setSubtitle(subtitle);
- }
- }
-
- public void setSubtitle(@StringRes int subtitle) {
- setSubtitle(getString(subtitle));
- }
-
- public void enableTransparentStatusBar(@ColorRes int color) {
- if (Build.VERSION.SDK_INT >= 21) {
- Window window = getWindow();
- window.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- if (color != 0) {
- window.setStatusBarColor(ContextCompat.getColor(this, color));
- }
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home && mHomeAsUpEnabled) {
- finish();
- }
- return super.onOptionsItemSelected(item);
- }
-
- public void keepScreenOn() {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
-
- public boolean checkPermission(String permission) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- return true;
- }
- if (ContextCompat.checkSelfPermission(this,
- permission) == PackageManager.PERMISSION_GRANTED) {
- return true;
- }
- if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
- ActivityCompat.requestPermissions(this,
- new String[]{permission},
- REQUEST_PERMISSION);
- }
- return false;
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
- if (requestCode == REQUEST_PERMISSION) {
- for (int i = 0; i < permissions.length; i++) {
- if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
- onPermissionGranted(permissions[i]);
- }
- }
- }
- }
-
- protected void onPermissionGranted(String permission) {
-
- }
-
- public void showToast(CharSequence text, int gravity, int delay) {
- final Toast toast = Toast.makeText(this, text, delay);
- toast.setGravity(gravity, 0, 0);
- toast.show();
- }
-
- public void showToast(@StringRes int text, int gravity, int delay) {
- showToast(getString(text), gravity, delay);
- }
-
- public boolean checkConnectionWithSnackbar(View view) {
- if (NetworkUtils.checkConnection(this)) {
- return true;
- } else {
- Snackbar.make(view, R.string.no_network_connection, Snackbar.LENGTH_SHORT).show();
- return false;
- }
- }
-
- public void registerLoaderTask(AsyncTask task) {
- if (mLoaders == null) {
- mLoaders = new ArrayList<>();
- }
- mLoaders.add(new WeakReference<>(task));
- }
-
- @Override
- protected void onDestroy() {
- if (mLoaders != null) {
- for (WeakReference o : mLoaders) {
- AsyncTask task = o.get();
- if (task != null && task.getStatus() != AsyncTask.Status.FINISHED) {
- task.cancel(true);
- }
- }
- }
- mLoaders = null;
- super.onDestroy();
- }
-
- protected boolean showcase(final View view, @StringRes int title, @StringRes int body) {
- return showcase(view, title, body, false);
- }
-
- protected boolean showcase(final View view, @StringRes int title, @StringRes int body, boolean tint) {
- boolean dark = isDarkTheme();
- if (view != null && view.getVisibility() == View.VISIBLE
- && !getSharedPreferences("tips", MODE_PRIVATE).getBoolean(getClass().getSimpleName() + "_" + view.getId(), false)) {
- TapTargetView.showFor(this,
- TapTarget.forView(view, getString(title), getString(body))
- .transparentTarget(!tint)
- .textColorInt(Color.WHITE)
- .dimColorInt(LayoutUtils.getAttrColor(this, R.attr.colorPrimaryDark))
- .tintTarget(tint),
- new TapTargetView.Listener() { // The listener can listen for regular clicks, long clicks or cancels
- @Override
- public void onTargetClick(TapTargetView view1) {
- super.onTargetClick(view1);
- }
- });
- SharedPreferences prefs = getSharedPreferences("tips", MODE_PRIVATE);
- prefs.edit().putBoolean(BaseAppActivity.this.getClass().getSimpleName() + "_" + view.getId(), true).apply();
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * @param menuItemId
- * @param title
- * @param body
- * @return true if showcase shown
- */
- protected boolean showcase(@IdRes final int menuItemId, @StringRes int title, @StringRes int body) {
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- return toolbar != null && showcase(toolbar.findViewById(menuItemId), title, body, false);
- }
-
- /**
- * @return true only once for activity
- */
- protected boolean isFirstStart() {
- SharedPreferences prefs = getSharedPreferences("tips", MODE_PRIVATE);
- if (prefs.getBoolean(getClass().getName(), true)) {
- prefs.edit().putBoolean(getClass().getName(), false).apply();
- return true;
- }
- return false;
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/DownloadsActivity.java b/app/src/main/java/org/nv95/openmanga/activities/DownloadsActivity.java
deleted file mode 100644
index f6e45bd8..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/DownloadsActivity.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.DownloadsAdapter;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-
-/**
- * Created by nv95 on 03.01.16.
- */
-public class DownloadsActivity extends BaseAppActivity {
-
- private DownloadsAdapter mAdapter;
- private TextView mTextViewHolder;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_downloads);
- setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
- enableHomeAsClose();
- RecyclerView mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- assert mRecyclerView != null;
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- mTextViewHolder = (TextView) findViewById(R.id.textView_holder);
- mAdapter = new DownloadsAdapter(mRecyclerView);
- mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- super.onChanged();
- mTextViewHolder.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
- }
- });
- mRecyclerView.setAdapter(mAdapter);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mAdapter.enable();
- }
-
- @Override
- protected void onStop() {
- mAdapter.disable();
- super.onStop();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mAdapter.notifyDataSetChanged();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.downloads, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_cancel:
- new AlertDialog.Builder(this)
- .setNegativeButton(android.R.string.no, null)
- .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new MangaSaveHelper(DownloadsActivity.this).cancelAll();
- }
- })
- .setMessage(R.string.downloads_cancel_confirm)
- .create().show();
- return true;
- case R.id.action_resume:
- mAdapter.setTaskPaused(false);
- invalidateOptionsMenu();
- return true;
- case R.id.action_pause:
- mAdapter.setTaskPaused(true);
- invalidateOptionsMenu();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/FileSelectActivity.java b/app/src/main/java/org/nv95/openmanga/activities/FileSelectActivity.java
deleted file mode 100644
index 844e0488..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/FileSelectActivity.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.Manifest;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Environment;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.FileSelectAdapter;
-import org.nv95.openmanga.dialogs.DirSelectDialog;
-import org.nv95.openmanga.dialogs.StorageSelectDialog;
-
-import java.io.File;
-
-/**
- * Created by nv95 on 09.02.16.
- */
-public class FileSelectActivity extends BaseAppActivity implements DirSelectDialog.OnDirSelectListener, View.OnClickListener {
-
- public static final String EXTRA_INITIAL_DIR = "initial_dir";
- public static final String EXTRA_FILTER = "filter";
-
- @Nullable
- private FileSelectAdapter mAdapter;
- private RecyclerView mRecyclerView;
- private File mDir;
- private String mFilter;
- private TextView mTextViewTitle;
-
- private final RecyclerView.AdapterDataObserver mObserver = new RecyclerView.AdapterDataObserver() {
- @Override
- public void onChanged() {
- super.onChanged();
- File file = mAdapter.getCurrentDir();
- mTextViewTitle.setText(file.getPath());
- }
- };
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_importfile);
- setSupportActionBar(R.id.toolbar);
- enableHomeAsUp();
- mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- mTextViewTitle = (TextView) findViewById(R.id.textView_title);
- findViewById(R.id.imageButton).setOnClickListener(this);
- String dir = getIntent().getStringExtra(EXTRA_INITIAL_DIR);
- if (dir == null) {
- dir = getSharedPreferences(this.getLocalClassName(), MODE_PRIVATE)
- .getString("dir", null);
- }
- mDir = dir == null ? Environment.getExternalStorageDirectory()
- : new File(dir);
- mFilter = getIntent().getStringExtra(EXTRA_FILTER);
- if (checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
- onPermissionGranted(null);
- }
- }
-
- @Override
- protected void onPermissionGranted(String permission) {
- mAdapter = new FileSelectAdapter(mDir, mFilter, this);
- mAdapter.registerAdapterDataObserver(mObserver);
- mObserver.onChanged();
- mRecyclerView.setAdapter(mAdapter);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- public void onDirSelected(File dir) {
- if (dir.isDirectory()) {
- mAdapter.setDirectory(dir);
- } else {
- getSharedPreferences(this.getLocalClassName(), MODE_PRIVATE).edit()
- .putString("dir", mAdapter.getCurrentDir().getPath())
- .apply();
- Intent data = new Intent();
- data.putExtra(Intent.EXTRA_TEXT, dir.getPath());
- setResult(RESULT_OK, data);
- finish();
- }
- }
-
- @Override
- public void onClick(View view) {
- if (mAdapter == null) {
- return;
- }
- new StorageSelectDialog(this, true)
- .setDirSelectListener(new DirSelectDialog.OnDirSelectListener() {
- @Override
- public void onDirSelected(File dir) {
- mAdapter.setCurrentDir(dir);
- }
- })
- .show();
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/MainActivity.java b/app/src/main/java/org/nv95/openmanga/activities/MainActivity.java
deleted file mode 100755
index 2b40625f..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/MainActivity.java
+++ /dev/null
@@ -1,826 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.Manifest;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.FloatingActionButton;
-import android.support.design.widget.NavigationView;
-import android.support.design.widget.Snackbar;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.util.Pair;
-import android.support.v4.view.GravityCompat;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v7.app.ActionBar;
-import android.support.v7.app.ActionBarDrawerToggle;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-import android.text.Html;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.SubMenu;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import org.nv95.openmanga.MangaListLoader;
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.settings.SettingsActivity2;
-import org.nv95.openmanga.adapters.EndlessAdapter;
-import org.nv95.openmanga.adapters.GenresSortAdapter;
-import org.nv95.openmanga.components.OnboardSnackbar;
-import org.nv95.openmanga.dialogs.BookmarksDialog;
-import org.nv95.openmanga.dialogs.FastHistoryDialog;
-import org.nv95.openmanga.dialogs.NavigationListener;
-import org.nv95.openmanga.dialogs.PageNumberDialog;
-import org.nv95.openmanga.dialogs.RecommendationsPrefDialog;
-import org.nv95.openmanga.helpers.ContentShareHelper;
-import org.nv95.openmanga.helpers.ListModeHelper;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-import org.nv95.openmanga.helpers.SyncHelper;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.providers.FavouritesProvider;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.RecommendationsProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-import org.nv95.openmanga.services.ExportService;
-import org.nv95.openmanga.services.ImportService;
-import org.nv95.openmanga.services.SyncService;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.ChangesObserver;
-import org.nv95.openmanga.utils.DeltaUpdater;
-import org.nv95.openmanga.utils.DrawerHeaderImageTool;
-import org.nv95.openmanga.utils.FileLogger;
-import org.nv95.openmanga.utils.InternalLinkMovement;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.ProgressAsyncTask;
-import org.nv95.openmanga.utils.StorageUpgradeTask;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceCallback;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceController;
-
-import java.io.File;
-import java.util.List;
-
-public class MainActivity extends BaseAppActivity implements
- View.OnClickListener, MangaListLoader.OnContentLoadListener, ChangesObserver.OnMangaChangesListener,
- ListModeHelper.OnListModeListener, GenresSortAdapter.Callback, NavigationView.OnNavigationItemSelectedListener,
- InternalLinkMovement.OnLinkClickListener, ModalChoiceCallback, View.OnLongClickListener, NavigationListener {
-
- private static final int REQUEST_IMPORT = 792;
- private static final int REQUEST_SETTINGS = 795;
- //views
- private RecyclerView mRecyclerView;
- private DrawerLayout mDrawerLayout;
- private ActionBarDrawerToggle mToggle;
- private FloatingActionButton mFab;
- private TextView mTextViewHolder;
- private ProgressBar mProgressBar;
- //utils
- private MangaListLoader mListLoader;
- private MangaProviderManager mProviderManager;
- private ListModeHelper mListModeHelper;
- //data
- private MangaProvider mProvider;
- private GenresSortAdapter mGenresAdapter;
- private NavigationView mNavigationView;
- private int mSelectedItem;
- private DrawerHeaderImageTool mDrawerHeaderTool;
-
- private final BroadcastReceiver mSyncReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- switch (intent.getIntExtra("what", -1)) {
- case SyncService.MSG_FAV_FINISHED:
- if (mSelectedItem == R.id.nav_action_favourites) {
- new DeltaUpdater(mListLoader).update(FavouritesProvider.getInstance(MainActivity.this));
- }
- break;
- case SyncService.MSG_HIST_FINISHED:
- if (mSelectedItem == R.id.nav_action_history) {
- new DeltaUpdater(mListLoader).update(HistoryProvider.getInstance(MainActivity.this));
- }
- break;
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- enableTransparentStatusBar(android.R.color.transparent);
- Toolbar toolbar;
- setSupportActionBar(toolbar = (Toolbar) findViewById(R.id.toolbar));
- setupToolbarScrolling(toolbar);
- WelcomeActivity.show(this);
-
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- mFab = (FloatingActionButton) findViewById(R.id.fab_read);
- mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- mTextViewHolder = (TextView) findViewById(R.id.textView_holder);
- mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
-
- RecyclerView genresRecyclerView = (RecyclerView) findViewById(R.id.recyclerViewGenres);
- genresRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- genresRecyclerView.setAdapter(mGenresAdapter = new GenresSortAdapter(this));
-
- mTextViewHolder.setMovementMethod(new InternalLinkMovement(this));
- mFab.setOnClickListener(this);
- mFab.setOnLongClickListener(this);
- mFab.setVisibility(PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
- .getBoolean("fab", true) ? View.VISIBLE : View.GONE);
- mNavigationView = (NavigationView) findViewById(R.id.navigation_drawer);
- mNavigationView.setNavigationItemSelectedListener(this);
- mRecyclerView.setLayoutManager(new GridLayoutManager(this, 1));
- mProviderManager = new MangaProviderManager(this);
- int defSection = Integer.parseInt(PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
- .getString("defsection", String.valueOf(MangaProviderManager.PROVIDER_LOCAL)));
- final MenuItem menuItem = mNavigationView.getMenu().getItem(4 + defSection);
- menuItem.setChecked(true);
- mSelectedItem = menuItem.getItemId();
- mToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
- @Override
- public void onDrawerOpened(View drawerView) {
- super.onDrawerOpened(drawerView);
- invalidateOptionsMenu();
- }
-
- @Override
- public void onDrawerClosed(View drawerView) {
- super.onDrawerClosed(drawerView);
- invalidateOptionsMenu();
- }
- };
- mDrawerLayout.addDrawerListener(mToggle);
-
- ActionBar actionBar = getSupportActionBar();
- if (actionBar != null) {
- actionBar.setHomeButtonEnabled(true);
- }
-
- initDrawerRemoteProviders();
-
- setTitle(getResources().getStringArray(R.array.section_names)[4 + defSection]);
- mProvider = mProviderManager.getProviderById(defSection);
- mListLoader = new MangaListLoader(mRecyclerView, this);
- mListLoader.getAdapter().getChoiceController().setCallback(this);
- mListLoader.getAdapter().getChoiceController().setEnabled(true);
- mListModeHelper = new ListModeHelper(this, this);
- mListModeHelper.applyCurrent();
- mListModeHelper.enable();
- StorageUpgradeTask.doUpgrade(this);
- mGenresAdapter.fromProvider(this, mProvider);
- mListLoader.loadContent(mProvider.isMultiPage(), true);
-
- if (isDarkTheme()) {
- ColorStateList csl = ColorStateList.valueOf(ContextCompat.getColor(this, R.color.white_overlay_85));
- mNavigationView.setItemTextColor(csl);
- mNavigationView.setItemIconTintList(csl);
- }
- //Load saved image in drawer head
- mDrawerHeaderTool = new DrawerHeaderImageTool(this, mNavigationView);
- mDrawerHeaderTool.initDrawerImage();
- if (isFirstStart()) {
- mDrawerLayout.postDelayed(new Runnable() {
- @Override
- public void run() {
- mDrawerLayout.openDrawer(GravityCompat.START);
- }
- }, 700);
- }
-
- ChangesObserver.getInstance().addListener(this);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
- }
- registerReceiver(mSyncReceiver, new IntentFilter(SyncService.SYNC_EVENT));
- }
-
- /**
- * Добавляем remote providers в левое меню
- */
- private void initDrawerRemoteProviders() {
-
- SubMenu navMenu = mNavigationView.getMenu().findItem(R.id.nav_remote_storage).getSubMenu();
- navMenu.removeGroup(R.id.groupRemote);
- List providers = mProviderManager.getOrderedProviders();
- for (int i = 0; i < mProviderManager.getProvidersCount(); i++) {
- navMenu.add(R.id.groupRemote, providers.get(i).id, i, providers.get(i).name);
- }
- navMenu.setGroupCheckable(R.id.groupRemote, true, true);
- }
-
- @Override
- public boolean onCreateOptionsMenu(final Menu menu) {
- getMenuInflater().inflate(R.menu.main, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- private int getCurrentProviderIndex(){
- switch (mSelectedItem){
- case R.id.nav_local_storage: return MangaProviderManager.PROVIDER_LOCAL;
- case R.id.nav_action_favourites: return MangaProviderManager.PROVIDER_FAVOURITES;
- case R.id.nav_action_history: return MangaProviderManager.PROVIDER_HISTORY;
- case R.id.nav_action_recommendations: return MangaProviderManager.PROVIDER_RECOMMENDATIONS;
- default: return mSelectedItem;
- }
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- menu.setGroupVisible(R.id.group_local, mSelectedItem == R.id.nav_local_storage);
- menu.setGroupVisible(R.id.group_history, mSelectedItem == R.id.nav_action_history);
- menu.setGroupVisible(R.id.group_favourites, mSelectedItem == R.id.nav_action_favourites);
- menu.findItem(R.id.action_goto).setVisible(mProvider.isMultiPage());
- menu.findItem(R.id.action_recommend_opts).setVisible(mSelectedItem == R.id.nav_action_recommendations);
- SyncHelper syncHelper = SyncHelper.get(this);
- menu.findItem(R.id.action_sync).setVisible(
- syncHelper.isAuthorized() && (
- (mSelectedItem == R.id.nav_action_history && syncHelper.isHistorySyncEnabled()) ||
- (mSelectedItem == R.id.nav_action_favourites && syncHelper.isFavouritesSyncEnabled())
- )
- );
- mListModeHelper.onPrepareOptionsMenu(menu);
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- protected void onDestroy() {
- unregisterReceiver(mSyncReceiver);
- mListLoader.cancelLoading();
- ChangesObserver.getInstance().removeListener(this);
- mListModeHelper.disable();
- super.onDestroy();
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == REQUEST_IMPORT && resultCode == RESULT_OK) {
- String f = data.getStringExtra(Intent.EXTRA_TEXT);
- if (f == null) {
- return;
- }
- f = new File(f).getName();
- new AlertDialog.Builder(this)
- .setMessage(getString(R.string.import_file_confirm, f))
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.import_file, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- startService(new Intent(MainActivity.this, ImportService.class)
- .putExtras(data).putExtra("action", ImportService.ACTION_START));
- }
- })
- .create().show();
- } else if (requestCode == REQUEST_SETTINGS || requestCode == WelcomeActivity.REQUEST_ONBOARDING) {
- if (getActivityTheme() != LayoutUtils.getAppTheme(this)) {
- recreate();
- return;
- }
- setupToolbarScrolling((Toolbar) findViewById(R.id.toolbar));
- mFab.setVisibility(PreferenceManager.getDefaultSharedPreferences(getApplicationContext())
- .getBoolean("fab", true) ? View.VISIBLE : View.GONE);
- if (mProviderManager != null && mNavigationView != null){
- mProviderManager.update();
- initDrawerRemoteProviders();
- mNavigationView.setCheckedItem(mSelectedItem);
- }
- } else {
- mDrawerHeaderTool.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mToggle.onOptionsItemSelected(item)) {
- return true;
- }
- switch (item.getItemId()) {
- case R.id.action_search:
- startActivity(new Intent(MainActivity.this, SearchActivity.class)
- .putExtra("provider", getCurrentProviderIndex()));
- return true;
- case R.id.action_import:
- startActivityForResult(new Intent(this, FileSelectActivity.class)
- .putExtra(FileSelectActivity.EXTRA_FILTER, "cbz;zip"), REQUEST_IMPORT);
- return true;
- case R.id.action_goto:
- new PageNumberDialog(this)
- .setNavigationListener(this)
- .show(mListLoader.getCurrentPage());
- return true;
- case R.id.action_recommend_opts:
- new RecommendationsPrefDialog(this, this).show();
- return true;
- case R.id.action_sync:
- SyncService.start(this);
- Snackbar.make(mRecyclerView, R.string.sync_started, Snackbar.LENGTH_SHORT).show();
- return true;
- case R.id.action_filter:
- mDrawerLayout.openDrawer(GravityCompat.END);
- return true;
- case R.id.action_bookmarks:
- new BookmarksDialog(this).show();
- return true;
- case R.id.action_histclear:
- if (mProvider instanceof HistoryProvider) {
- new AlertDialog.Builder(MainActivity.this)
- .setCancelable(true)
- .setPositiveButton(R.string.clear, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (((HistoryProvider) mProvider).clear()) {
- mListLoader.clearItems();
- } else {
- Snackbar.make(mRecyclerView, R.string.error, Snackbar.LENGTH_SHORT).show();
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .setMessage(R.string.history_will_cleared)
- .create().show();
- }
- return true;
- case R.id.action_updates:
- startActivity(new Intent(this, NewChaptersActivity.class));
- return true;
- case R.id.action_settings:
- startActivityForResult(new Intent(this, SettingsActivity2.class), REQUEST_SETTINGS);
- return true;
- default:
- return mListModeHelper.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onApply(int genre, int sort, @Nullable String genreName, @Nullable String sortName) {
- mDrawerLayout.closeDrawer(GravityCompat.END);
- setSubtitle(genre == 0 ? null : genreName);
- MangaProviderManager.saveSortOrder(MainActivity.this, mProvider, sort);
- updateContent();
- }
-
- @Override
- public boolean onNavigationItemSelected(@NonNull MenuItem item) {
- switch (item.getItemId()) {
- case R.id.nav_action_settings:
- startActivityForResult(new Intent(this, SettingsActivity2.class), REQUEST_SETTINGS);
- return true;
- case R.id.nav_local_storage:
- mProvider = LocalMangaProvider.getInstance(this);
- break;
- case R.id.nav_action_recommendations:
- mProvider = RecommendationsProvider.getInstance(this);
- break;
- case R.id.nav_action_favourites:
- mProvider = FavouritesProvider.getInstance(this);
- break;
- case R.id.nav_action_history:
- mProvider = HistoryProvider.getInstance(this);
- break;
- default:
- mProvider = mProviderManager.getProviderById(item.getItemId());
- break;
- }
- mSelectedItem = item.getItemId();
- mGenresAdapter.fromProvider(this, mProvider);
- setSubtitle(null);
- mDrawerLayout.closeDrawer(GravityCompat.START);
- setTitle(mProvider.getName());
- updateContent();
- return true;
- }
-
- @Override
- protected void onPostCreate(Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- mToggle.syncState();
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mToggle.onConfigurationChanged(newConfig);
- mListModeHelper.applyCurrent();
- }
-
- @Override
- public void onBackPressed() {
- if (mDrawerLayout.isDrawerOpen(GravityCompat.END)) {
- mDrawerLayout.closeDrawer(GravityCompat.END);
- } else if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
- mDrawerLayout.closeDrawer(GravityCompat.START);
- } else {
- super.onBackPressed();
- }
- }
-
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.fab_read:
- new OpenLastTask(this).start(true);
- break;
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- switch (v.getId()) {
- case R.id.fab_read:
- //new OpenLastTask(this).attach(this).start(false);
- new FastHistoryDialog(this).show(3);
- return true;
- default:
- return false;
- }
- }
-
- @Override
- public void onContentLoaded(boolean success) {
- AnimUtils.crossfade(mProgressBar, null);
- if (mListLoader.getContentSize() == 0) {
- String holder;
- if (mProvider instanceof LocalMangaProvider) {
- holder = getString(R.string.no_saved_manga);
- } else if (mProvider instanceof FavouritesProvider) {
- holder = getString(R.string.no_favourites);
- } else if (mProvider instanceof HistoryProvider) {
- holder = getString(R.string.history_empty);
- } else {
- holder = getString(R.string.no_manga_found);
- }
- mTextViewHolder.setText(holder);
- AnimUtils.crossfade(null, mTextViewHolder);
- if (!success) {
- if (!NetworkUtils.checkConnection(this) && MangaProviderManager.needConnectionFor(mProvider)) {
- mTextViewHolder.setText(Html.fromHtml(getString(R.string.no_network_connection_html)));
- } else {
- Snackbar.make(mRecyclerView, R.string.loading_error, Snackbar.LENGTH_INDEFINITE)
- .setAction(R.string.retry, new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- updateContent();
- }
- })
- .show();
- }
- }
- } else {
- mRecyclerView.postDelayed(new ListTipHelper(), 500);
- }
- }
-
- @Override
- public void onLoadingStarts(boolean hasItems) {
- if (!hasItems) {
- AnimUtils.noanim(mTextViewHolder, mProgressBar);
- mListLoader.getAdapter().getChoiceController().clearSelection();
- }
- }
-
- @Nullable
- @Override
- public MangaList onContentNeeded(int page) {
- try {
- return mProvider.getList(page, mGenresAdapter.getSelectedSort(), mGenresAdapter.getSelectedGenre());
- } catch (Exception e) {
- Log.e("OCN", e.getMessage());
- return null;
- }
- }
-
- @Override
- public void onListModeChanged(boolean grid, int sizeMode) {
- int spans;
- ThumbSize thumbSize;
- switch (sizeMode) {
- case -1:
- spans = LayoutUtils.isTabletLandscape(this) ? 2 : 1;
- thumbSize = ThumbSize.THUMB_SIZE_LIST;
- break;
- case 0:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_SMALL);
- break;
- case 1:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_MEDIUM);
- break;
- case 2:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_LARGE);
- break;
- default:
- return;
- }
- mListLoader.updateLayout(grid, spans, thumbSize);
- }
-
- @Override
- public void onLinkClicked(TextView view, String scheme, String url) {
- switch (url) {
- case "update":
- updateContent();
- break;
- }
- }
-
- private void updateContent() {
- mListLoader.loadContent(mProvider.isMultiPage(), true);
- }
-
- @Override
- public boolean onCreateActionMode(android.view.ActionMode mode, Menu menu) {
- getMenuInflater().inflate(R.menu.actionmode_mangas, menu);
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(android.view.ActionMode mode, Menu menu) {
- menu.findItem(R.id.action_remove).setVisible(mProvider.isItemsRemovable());
- menu.findItem(R.id.action_save).setVisible(mSelectedItem != R.id.nav_local_storage);
- menu.findItem(R.id.action_share).setVisible(mSelectedItem != R.id.nav_local_storage);
- menu.findItem(R.id.action_move).setVisible(mSelectedItem == R.id.nav_action_favourites);
- menu.findItem(R.id.action_export).setVisible(mSelectedItem == R.id.nav_local_storage);
- menu.findItem(R.id.action_select_all).setVisible(
- mSelectedItem == R.id.nav_action_favourites
- || mSelectedItem == R.id.nav_action_history
- || mSelectedItem == R.id.nav_local_storage
- );
- return false;
- }
-
- @Override
- public boolean onActionItemClicked(android.view.ActionMode mode, MenuItem item) {
- final int[] items = mListLoader.getAdapter().getChoiceController().getSelectedItemsPositions();
- final long[] ids = new long[items.length];
- for (int i=0;i> implements DialogInterface.OnCancelListener {
-
- OpenLastTask(MainActivity mainActivity) {
- super(mainActivity);
- setCancelable(true);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected Pair doInBackground(Boolean... params) {
- try {
- Intent intent;
- HistoryProvider historyProvider = HistoryProvider.getInstance(getActivity());
- MangaInfo info = historyProvider.getLast();
- if (info == null) {
- return new Pair<>(2, null);
- }
- if (params.length != 0 && !params[0]) {
- intent = new Intent(getActivity(), PreviewActivity2.class);
- intent.putExtras(info.toBundle());
- return new Pair<>(0, intent);
- }
- MangaProvider provider;
- if (info.provider.equals(LocalMangaProvider.class)) {
- provider = LocalMangaProvider.getInstance(getActivity());
- } else {
- if (!NetworkUtils.checkConnection(getActivity())) {
- provider = LocalMangaProvider.getInstance(getActivity());
- info = ((LocalMangaProvider)provider).getLocalManga(info);
- if (info.provider != LocalMangaProvider.class) {
- return new Pair<>(1, null);
- }
- } else {
- provider = MangaProviderManager.instanceProvider(getActivity(), info.provider);
- }
- }
- MangaSummary summary = provider.getDetailedInfo(info);
- intent = new Intent(getActivity(), ReadActivity2.class);
- intent.putExtras(summary.toBundle());
- HistoryProvider.HistorySummary hs = historyProvider.get(info);
- if (hs != null) {
- int index = summary.chapters.indexByNumber(hs.getChapter());
- if (index != -1) {
- intent.putExtra("chapter", index);
- intent.putExtra("page", hs.getPage());
- }
- }
- return new Pair<>(0, intent);
- } catch (Exception e) {
- FileLogger.getInstance().report("OPENLAST", e);
- return new Pair<>(3, null);
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull BaseAppActivity mainActivity, Pair result) {
- int msg;
- switch (result.first) {
- case 0:
- mainActivity.startActivity(result.second);
- return;
- case 1:
- msg = R.string.no_network_connection;
- break;
- case 2:
- msg = R.string.history_empty;
- break;
- default:
- msg = R.string.error;
- break;
- }
- new AlertDialog.Builder(mainActivity)
- .setCancelable(true)
- .setPositiveButton(R.string.close, null)
- .setMessage(mainActivity.getString(msg))
- .create().show();
- }
- }
-
- private class ListTipHelper implements Runnable {
-
- @SuppressWarnings("StatementWithEmptyBody")
- @Override
- public void run() {
- if (mProvider instanceof FavouritesProvider && OnboardSnackbar.askOnce(mRecyclerView, R.string.tip_chapter_checking, R.string.no_thanks, R.string.configure, new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- SettingsActivity2.openChaptersCheckSettings(MainActivity.this, 0);
- }
- })) {
- //done
- } else if (mProvider instanceof HistoryProvider || mProvider instanceof FavouritesProvider) {
- OnboardSnackbar.askOnce(mRecyclerView, R.string.sync_tip, R.string.no_thanks, R.string.configure, new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- SettingsActivity2.openSyncSettings(MainActivity.this, 0);
- }
- });
- } else if (mProvider instanceof RecommendationsProvider) {
- OnboardSnackbar.askOnce(mRecyclerView, R.string.recommendations_tip, R.string.skip, R.string.configure, new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new RecommendationsPrefDialog(MainActivity.this, MainActivity.this).show();
- }
- });
- } else if (MangaProviderManager.needConnectionFor(mProvider)) { //returns true on online provider
- showcase(R.id.action_search, R.string.action_search, R.string.tip_search_main);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/NewChaptersActivity.java b/app/src/main/java/org/nv95/openmanga/activities/NewChaptersActivity.java
deleted file mode 100644
index e498d91d..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/NewChaptersActivity.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.NewChaptersAdapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.providers.FavouritesProvider;
-import org.nv95.openmanga.providers.NewChaptersProvider;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.FileLogger;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.io.IOException;
-import java.util.Map;
-
-/**
- * Created by nv95 on 17.04.16.
- */
-public class NewChaptersActivity extends BaseAppActivity {
-
- //views
- private RecyclerView mRecyclerView;
- private TextView mTextViewHolder;
- private ProgressBar mProgressBar;
- //utils
- private final MangaList mList = new MangaList();
- private final NewChaptersAdapter mAdapter = new NewChaptersAdapter(mList);
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_updates);
- setSupportActionBar(R.id.toolbar);
- enableHomeAsUp();
-
- mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- mTextViewHolder = (TextView) findViewById(R.id.textView_holder);
- mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
-
- mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
- mRecyclerView.setAdapter(mAdapter);
- new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
- ItemTouchHelper.START | ItemTouchHelper.END) {
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
- return false;
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- final int pos = viewHolder.getAdapterPosition();
- final MangaInfo o = mList.get(pos);
- NewChaptersProvider.getInstance(NewChaptersActivity.this)
- .markAsViewed(o.hashCode());
- mList.remove(pos);
- mAdapter.notifyItemRemoved(pos);
- mTextViewHolder.setVisibility(mList.size() == 0 ? View.VISIBLE : View.GONE);
- }
- }).attachToRecyclerView(mRecyclerView);
-
- if (NetworkUtils.checkConnection(this)) {
- new LoadTask(this).attach(this).start();
- } else {
- mTextViewHolder.setText(R.string.no_network_connection);
- AnimUtils.crossfade(mProgressBar, mTextViewHolder);
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.updates, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_checkall:
- new AlertDialog.Builder(this)
- .setMessage(R.string.mark_all_viewed_confirm)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- NewChaptersProvider.getInstance(NewChaptersActivity.this)
- .markAllAsViewed();
- mList.clear();
- mAdapter.notifyDataSetChanged();
- mTextViewHolder.setVisibility(View.VISIBLE);
- }
- }).create().show();
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- private static class LoadTask extends WeakAsyncTask {
-
- LoadTask(NewChaptersActivity object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull NewChaptersActivity object) {
- object.mProgressBar.setVisibility(View.VISIBLE);
- }
-
-
- @Override
- protected MangaList doInBackground(Void... params) {
- try {
- final FavouritesProvider favs = FavouritesProvider.getInstance(getObject());
- final NewChaptersProvider news = NewChaptersProvider.getInstance(getObject());
- news.checkForNewChapters();
- MangaList mangas = favs.getList(0, 0, 0);
- Map updates = news.getLastUpdates();
- Integer t;
- final MangaList res = new MangaList();
- for (MangaInfo o:mangas) {
- t = updates.get(o.hashCode());
- if (t != null && t != 0) {
- o.extra = "+" + t;
- res.add(o);
- }
- }
- return res;
- } catch (IOException e) {
- FileLogger.getInstance().report("CHUPD", e);
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull NewChaptersActivity activity, MangaList mangaInfos) {
- if (mangaInfos == null) {
- AnimUtils.crossfade(activity.mProgressBar, activity.mTextViewHolder);
- Toast.makeText(activity, R.string.error, Toast.LENGTH_SHORT).show();
- } else {
- if (mangaInfos.isEmpty()) {
- AnimUtils.crossfade(activity.mProgressBar, activity.mTextViewHolder);
- } else {
- activity.mList.clear();
- activity.mList.addAll(mangaInfos);
- activity.mAdapter.notifyDataSetChanged();
- AnimUtils.crossfade(activity.mProgressBar, activity.mRecyclerView);
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/PreviewActivity2.java b/app/src/main/java/org/nv95/openmanga/activities/PreviewActivity2.java
deleted file mode 100644
index bd92a30b..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/PreviewActivity2.java
+++ /dev/null
@@ -1,516 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.annotation.SuppressLint;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.AppBarLayout;
-import android.support.design.widget.Snackbar;
-import android.support.design.widget.TabLayout;
-import android.support.v4.view.ViewPager;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.BookmarksAdapter;
-import org.nv95.openmanga.adapters.ChaptersAdapter;
-import org.nv95.openmanga.adapters.OnChapterClickListener;
-import org.nv95.openmanga.adapters.SimpleViewPagerAdapter;
-import org.nv95.openmanga.dialogs.ChaptersSelectDialog;
-import org.nv95.openmanga.dialogs.MenuDialog;
-import org.nv95.openmanga.helpers.ContentShareHelper;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-import org.nv95.openmanga.items.Bookmark;
-import org.nv95.openmanga.items.MangaChapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.lists.ChaptersList;
-import org.nv95.openmanga.providers.BookmarksProvider;
-import org.nv95.openmanga.providers.FavouritesProvider;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.NewChaptersProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.services.ExportService;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.ChangesObserver;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.MangaStore;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.ProgressAsyncTask;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.util.Collections;
-import java.util.List;
-
-import static org.nv95.openmanga.R.string.bookmarks;
-import static org.nv95.openmanga.R.string.description;
-
-/**
- * Created by unravel22 on 18.02.17.
- */
-
-public class PreviewActivity2 extends BaseAppActivity implements BookmarksAdapter.OnBookmarkClickListener,
- OnChapterClickListener, AppBarLayout.OnOffsetChangedListener, ChangesObserver.OnMangaChangesListener {
-
- private MangaSummary mManga;
- private boolean mToolbarCollapsed = false;
-
- private TabLayout mTabLayout;
- private ImageView mImageView;
- private RecyclerView mRecyclerViewChapters;
- private RecyclerView mRecyclerViewBookmarks;
- private TextView mTextViewChaptersHolder;
- private TextView mTextViewBookmarksHolder;
- private TextView mTextViewSummary;
- private TextView mTextViewDescription;
- private TextView mTextViewState;
- private TextView mTextViewTitle;
- private ProgressBar mProgressBar;
- private ViewPager mViewPager;
- private Toolbar mToolbarMenu;
-
- private SimpleViewPagerAdapter mPagerAdapter;
- private ChaptersAdapter mChaptersAdapter;
-
- @SuppressLint("CutPasteId")
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_preview2);
- setSupportActionBar(R.id.toolbar);
- enableHomeAsUp();
- disableTitle();
-
- mImageView = findViewById(R.id.imageView);
- mTabLayout = findViewById(R.id.tabs);
- mTextViewSummary = findViewById(R.id.textView_summary);
- mTextViewTitle = findViewById(R.id.textView_title);
- mProgressBar = findViewById(R.id.progressBar);
- mTextViewState = findViewById(R.id.textView_state);
- mViewPager = findViewById(R.id.pager);
- mToolbarMenu = findViewById(R.id.toolbarMenu);
- AppBarLayout appBar = findViewById(R.id.appbar_container);
- if (appBar != null) {
- appBar.addOnOffsetChangedListener(this);
- }
- mPagerAdapter = new SimpleViewPagerAdapter();
- //
- View page = LayoutInflater.from(this).inflate(R.layout.page_text, mViewPager, false);
- mTextViewDescription = page.findViewById(R.id.textView);
- mPagerAdapter.addView(page, getString(description));
- //
- page = LayoutInflater.from(this).inflate(R.layout.page_list, mViewPager, false);
- mRecyclerViewChapters = page.findViewById(R.id.recyclerView);
- mTextViewChaptersHolder = page.findViewById(R.id.textView_holder);
- mRecyclerViewChapters.setLayoutManager(new LinearLayoutManager(this));
- mTextViewChaptersHolder.setText(R.string.no_chapters_found);
- mPagerAdapter.addView(page, getString(R.string.chapters));
- //
- page = LayoutInflater.from(this).inflate(R.layout.page_list, mViewPager, false);
- mRecyclerViewBookmarks = page.findViewById(R.id.recyclerView);
- mTextViewBookmarksHolder = page.findViewById(R.id.textView_holder);
- mRecyclerViewBookmarks.setLayoutManager(new LinearLayoutManager(this));
- mTextViewBookmarksHolder.setText(R.string.no_bookmarks_tip);
- mPagerAdapter.addView(page, getString(bookmarks));
-
- mViewPager.setAdapter(mPagerAdapter);
- mTabLayout.setupWithViewPager(mViewPager);
- mChaptersAdapter = new ChaptersAdapter(this);
- mChaptersAdapter.setOnItemClickListener(this);
- mRecyclerViewChapters.setAdapter(mChaptersAdapter);
- mToolbarMenu.inflateMenu(R.menu.toolbar_actions);
- mToolbarMenu.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- return PreviewActivity2.this.onOptionsItemSelected(item);
- }
- });
-
- MangaInfo mangaInfo = new MangaInfo(getIntent().getExtras());
- if (mangaInfo.provider != LocalMangaProvider.class && !NetworkUtils.checkConnection(this)) {
- mManga = LocalMangaProvider.getInstance(this).getLocalManga(mangaInfo);
- Snackbar.make(mViewPager, R.string.no_network_connection, Snackbar.LENGTH_SHORT).show();
- } else {
- mManga = new MangaSummary(mangaInfo);
- }
- ImageUtils.setImage(mImageView, mManga.preview);
- mTextViewTitle.setText(mManga.name);
- mTextViewSummary.setText(mManga.genres);
- mViewPager.setCurrentItem(HistoryProvider.getInstance(this).has(mManga) ? 1 : 0, false);
- switch (LocalMangaProvider.class.equals(mManga.provider) ? MangaInfo.STATUS_UNKNOWN : mManga.status) {
- case MangaInfo.STATUS_COMPLETED:
- mTextViewState.setText(R.string.status_completed);
- break;
- case MangaInfo.STATUS_ONGOING:
- mTextViewState.setText(R.string.status_ongoing);
- break;
- default:
- mTextViewState.setVisibility(View.GONE);
- }
- invalidateMenuBar();
- ChangesObserver.getInstance().addListener(this);
- new LoadTask(this).attach(this).start();
-
- new ContentShareHelper(this).buildOpenWithSubmenu(mManga,
- mToolbarMenu.getMenu().findItem(R.id.action_open_ext));
- }
-
- @Override
- protected void onDestroy() {
- ChangesObserver.getInstance().removeListener(this);
- super.onDestroy();
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.preview2, menu);
- new ContentShareHelper(this).buildOpenWithSubmenu(mManga,
- menu.findItem(R.id.action_open_ext));
- return super.onCreateOptionsMenu(menu);
- }
-
- public void invalidateMenuBar() {
- if (mToolbarCollapsed) {
- return;
- }
- Menu menu = mToolbarMenu.getMenu();
- boolean isLocal = LocalMangaProvider.class.equals(mManga.provider);
- menu.findItem(R.id.action_save).setVisible(!isLocal);
- menu.findItem(R.id.action_remove).setVisible(isLocal);
- menu.findItem(R.id.action_export).setVisible(isLocal);
- menu.findItem(R.id.action_sort).setIcon(mChaptersAdapter.isReversed() ? R.drawable.ic_sort_ascending_white : R.drawable.ic_sort_descending_white);
- menu.findItem(R.id.action_save_more).setVisible(isLocal && mManga.status == MangaInfo.STATUS_ONGOING);
- if (isLocal) {
- menu.findItem(R.id.action_favourite).setVisible(false);
- } else if (FavouritesProvider.getInstance(this).has(mManga)) {
- menu.findItem(R.id.action_favourite).setIcon(R.drawable.ic_favorite_light);
- menu.findItem(R.id.action_favourite).setTitle(R.string.action_unfavourite);
- } else {
- menu.findItem(R.id.action_favourite).setIcon(R.drawable.ic_favorite_outline_light);
- menu.findItem(R.id.action_favourite).setTitle(R.string.action_favourite);
- }
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- if (mToolbarCollapsed) {
- menu.setGroupVisible(R.id.group_all, true);
- boolean isLocal = LocalMangaProvider.class.equals(mManga.provider);
- menu.findItem(R.id.action_save).setVisible(!isLocal);
- menu.findItem(R.id.action_remove).setVisible(isLocal);
- menu.findItem(R.id.action_export).setVisible(isLocal);
- menu.findItem(R.id.action_save_more).setVisible(isLocal && mManga.status == MangaInfo.STATUS_ONGOING);
- if (isLocal) {
- menu.findItem(R.id.action_favourite).setVisible(false);
- } else if (FavouritesProvider.getInstance(this).has(mManga)) {
- menu.findItem(R.id.action_favourite).setTitle(R.string.action_unfavourite);
- } else {
- menu.findItem(R.id.action_favourite).setTitle(R.string.action_favourite);
- }
- } else {
- menu.setGroupVisible(R.id.group_all, false);
- }
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_favourite:
- final FavouritesProvider favouritesProvider = FavouritesProvider.getInstance(this);
- FavouritesProvider.dialog(this, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_NEUTRAL) {
- if (favouritesProvider.remove(mManga)) {
- ChangesObserver.getInstance().emitOnFavouritesChanged(mManga, -1);
- Snackbar.make(mViewPager, R.string.unfavourited, Snackbar.LENGTH_SHORT).show();
- }
- } else {
- NewChaptersProvider.getInstance(PreviewActivity2.this)
- .storeChaptersCount(mManga.id, mManga.getChapters().size());
- ChangesObserver.getInstance().emitOnFavouritesChanged(mManga, which);
- Snackbar.make(mViewPager, R.string.favourited, Snackbar.LENGTH_SHORT).show();
- }
- }
- }, mManga);
- return true;
- case R.id.action_save:
- if (mManga.chapters.size() != 0) {
- new MangaSaveHelper(this).confirmSave(mManga);
- }
- return true;
- case R.id.action_share:
- new ContentShareHelper(this).share(mManga);
- return true;
- case R.id.action_sort:
- mChaptersAdapter.reverse();
- item.setIcon(mChaptersAdapter.isReversed() ? R.drawable.ic_sort_ascending_white : R.drawable.ic_sort_descending_white);
- return true;
- case R.id.action_relative:
- startActivity(new Intent(this, SearchActivity.class)
- .putExtra("query", mManga.name));
- return true;
- case R.id.action_shortcut:
- new ContentShareHelper(this).createShortcut(mManga);
- return true;
- case R.id.action_export:
- ExportService.start(this, mManga);
- return true;
- case R.id.action_remove:
- deleteDialog();
- return true;
- case R.id.action_save_more:
- if (checkConnectionWithSnackbar(mTextViewDescription)) {
- new LoadSourceTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mManga);
- }
- return true;
- default:
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onBookmarkSelected(Bookmark bookmark) {
- HistoryProvider.getInstance(this).add(mManga, bookmark.chapter, 0);
- startActivity(new Intent(this, ReadActivity2.class).putExtra("chapter", bookmark.chapter).putExtra("page", bookmark.page).putExtras(mManga.toBundle()));
- }
-
- private void deleteDialog() {
- new ChaptersSelectDialog(this)
- .showRemove(mManga, new ChaptersSelectDialog.OnChaptersRemoveListener() {
- @Override
- public void onChaptersRemove(@Nullable long[] ids) {
- if (ids == null) {
- if (new MangaStore(PreviewActivity2.this).dropMangas(new long[]{mManga.id})) {
- HistoryProvider.getInstance(PreviewActivity2.this).remove(new long[]{mManga.id});
- ChangesObserver.getInstance().emitOnLocalChanged(mManga.id, null);
- finish();
- }
- } else {
- if (new MangaStore(PreviewActivity2.this).dropChapters(mManga.id, ids)) {
- Snackbar.make(mTextViewDescription, getString(R.string.chapters_removed, ids.length), Snackbar.LENGTH_SHORT).show();
- } else {
- Snackbar.make(mTextViewDescription, R.string.error, Snackbar.LENGTH_SHORT).show();
- }
- new LoadTask(PreviewActivity2.this).attach(PreviewActivity2.this).start();
- }
- }
- });
- }
-
- @Override
- public void onChapterClick(int pos, MangaChapter chapter) {
- if (pos == -1) {
- Intent intent = new Intent(this, ReadActivity2.class);
- intent.putExtras(mManga.toBundle());
- HistoryProvider.HistorySummary hs = HistoryProvider.getInstance(this).get(mManga);
- if (hs != null) {
- int index = mManga.chapters.indexByNumber(hs.getChapter());
- if (index != -1) {
- intent.putExtra("chapter", index);
- intent.putExtra("page", hs.getPage());
- }
- }
- startActivity(intent);
- } else {
- if (mChaptersAdapter.isReversed()) pos = mManga.chapters.size() - pos - 1;
- HistoryProvider.getInstance(this).add(mManga, chapter.number, 0);
- startActivity(new Intent(this, ReadActivity2.class).putExtra("chapter", pos).putExtras(mManga.toBundle()));
- }
- }
-
- @Override
- public boolean onChapterLongClick(int pos, MangaChapter chapter) {
- if (pos == -1 || mManga.provider == LocalMangaProvider.class) {
- return false;
- } else {
- new MenuDialog(this, R.menu.chapter, chapter.name)
- .setOnItemClickListener(new ChapterMenuListener(chapter))
- .show();
- return true;
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- if (mChaptersAdapter.getItemCount() != 0) {
- mChaptersAdapter.setExtra(HistoryProvider.getInstance(PreviewActivity2.this).get(mManga));
- mChaptersAdapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
- if (verticalOffset <= appBarLayout.getTotalScrollRange() / -2) {
- if (!mToolbarCollapsed) {
- mToolbarCollapsed = true;
- invalidateOptionsMenu();
- }
- } else {
- if (mToolbarCollapsed) {
- mToolbarCollapsed = false;
- invalidateOptionsMenu();
- invalidateMenuBar();
- }
- }
- }
-
- @Override
- public void onLocalChanged(int id, @Nullable MangaInfo manga) {
- if (id == mManga.id && manga == null) {
- finish();
- }
- }
-
- @Override
- public void onFavouritesChanged(@NonNull MangaInfo manga, int category) {
- invalidateMenuBar();
- invalidateOptionsMenu();
- }
-
- @Override
- public void onHistoryChanged(@NonNull MangaInfo manga) {
-
- }
-
- private static class LoadTask extends WeakAsyncTask, MangaSummary> {
-
- LoadTask(PreviewActivity2 object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull PreviewActivity2 activity) {
- AnimUtils.crossfade(null, activity.mProgressBar);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected MangaSummary doInBackground(Void... params) {
- try {
- //noinspection unchecked
- publishProgress(BookmarksProvider.getInstance(getObject()).getAll(getObject().mManga.id));
- MangaProvider provider = MangaProviderManager.instanceProvider(getObject(), getObject().mManga.provider);
- return provider.getDetailedInfo(getObject().mManga);
- } catch (Exception e) {
- return null;
- }
- }
-
- @Override
- protected void onProgressUpdate(@NonNull PreviewActivity2 activity, List[] values) {
- activity.mRecyclerViewBookmarks.setAdapter(new BookmarksAdapter(values[0], activity));
- if (values[0].isEmpty()) {
- activity.mTextViewBookmarksHolder.setText(R.string.no_bookmarks_tip);
- activity.mTextViewBookmarksHolder.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull PreviewActivity2 activity, MangaSummary mangaSummary) {
- if (mangaSummary != null) {
- activity.mManga = mangaSummary;
- activity.invalidateOptionsMenu();
- activity.invalidateMenuBar();
- activity.mTextViewSummary.setText(activity.mManga.genres);
- activity.mTextViewDescription.setText(activity.mManga.description);
- ImageUtils.updateImage(activity.mImageView, activity.mManga.preview);
- activity.mChaptersAdapter.setData(activity.mManga.chapters);
- activity.mChaptersAdapter.setExtra(HistoryProvider.getInstance(activity).get(activity.mManga));
- activity.mChaptersAdapter.notifyDataSetChanged();
- if (mangaSummary.chapters.isEmpty()) {
- activity.mTextViewChaptersHolder.setText(R.string.no_chapters_found);
- AnimUtils.crossfade(activity.mProgressBar, activity.mTextViewChaptersHolder);
- } else {
- AnimUtils.crossfade(activity.mProgressBar, null);
- if (!activity.showcase(activity.mToolbarMenu.findViewById(R.id.action_favourite), R.string.action_favourite, R.string.tip_favourite)) {
- if (LocalMangaProvider.class.equals(activity.mManga.provider)) {
- activity.showcase(activity.mToolbarMenu.findViewById(R.id.action_save_more), R.string.action_save_add, R.string.tip_save_more);
- } else {
- activity.showcase(activity.mToolbarMenu.findViewById(R.id.action_save), R.string.save_manga, R.string.tip_save);
- }
- }
- }
- } else {
- activity.mTextViewChaptersHolder.setText(R.string.loading_error);
- AnimUtils.crossfade(activity.mProgressBar, activity.mTextViewChaptersHolder);
- activity.mTextViewDescription.setText(R.string.loading_error);
- }
- }
- }
-
- private static class LoadSourceTask extends ProgressAsyncTask implements DialogInterface.OnCancelListener {
-
- LoadSourceTask(PreviewActivity2 object) {
- super(object);
- }
-
- @Override
- protected MangaSummary doInBackground(MangaInfo... params) {
- return LocalMangaProvider.getInstance(getActivity())
- .getSource(params[0]);
- }
-
- @Override
- protected void onPostExecute(@NonNull BaseAppActivity activity, MangaSummary sourceManga) {
- PreviewActivity2 a = (PreviewActivity2) activity;
- if (sourceManga == null) {
- Snackbar.make(a.mViewPager, R.string.loading_error, Snackbar.LENGTH_SHORT)
- .show();
- return;
- }
- ChaptersList newChapters = sourceManga.chapters.complementByName(a.mManga.chapters);
- if (sourceManga.chapters.size() <= a.mManga.chapters.size()) {
- Snackbar.make(a.mViewPager, R.string.no_new_chapters, Snackbar.LENGTH_SHORT)
- .show();
- } else {
- sourceManga.chapters = newChapters;
- new MangaSaveHelper(a).confirmSave(sourceManga, R.string.action_save_add);
- }
- }
- }
-
- private class ChapterMenuListener implements MenuItem.OnMenuItemClickListener {
-
- private final MangaChapter mChapter;
-
- ChapterMenuListener(MangaChapter chapter) {
- mChapter = chapter;
- }
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_save:
- new MangaSaveHelper(PreviewActivity2.this)
- .save(mManga, mChapter);
- return true;
- case R.id.action_save_prev:
- new MangaSaveHelper(PreviewActivity2.this)
- .save(mManga, mManga.chapters.first(), mChapter);
- return true;
- case R.id.action_save_next:
- new MangaSaveHelper(PreviewActivity2.this)
- .save(mManga, mChapter, mManga.chapters.last());
- return true;
- default:
- return false;
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/ReadActivity2.java b/app/src/main/java/org/nv95/openmanga/activities/ReadActivity2.java
deleted file mode 100644
index 6f6770e4..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/ReadActivity2.java
+++ /dev/null
@@ -1,728 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Point;
-import android.os.AsyncTask;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Environment;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.Snackbar;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AlertDialog;
-import android.util.DisplayMetrics;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.settings.SettingsActivity2;
-import org.nv95.openmanga.components.ReaderMenu;
-import org.nv95.openmanga.components.reader.MangaReader;
-import org.nv95.openmanga.components.reader.OnOverScrollListener;
-import org.nv95.openmanga.components.reader.PageWrapper;
-import org.nv95.openmanga.components.reader.StandardMangaReader;
-import org.nv95.openmanga.components.reader.webtoon.WebtoonReader;
-import org.nv95.openmanga.dialogs.HintDialog;
-import org.nv95.openmanga.dialogs.NavigationListener;
-import org.nv95.openmanga.dialogs.ThumbnailsDialog;
-import org.nv95.openmanga.helpers.BrightnessHelper;
-import org.nv95.openmanga.helpers.ContentShareHelper;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-import org.nv95.openmanga.helpers.PermissionsHelper;
-import org.nv95.openmanga.helpers.ReaderConfig;
-import org.nv95.openmanga.items.MangaChapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.MangaPage;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.items.SimpleDownload;
-import org.nv95.openmanga.lists.ChaptersList;
-import org.nv95.openmanga.providers.BookmarksProvider;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.utils.ChangesObserver;
-import org.nv95.openmanga.utils.InternalLinkMovement;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.StorageUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * Created by nv95 on 16.11.16.
- */
-
-public class ReadActivity2 extends BaseAppActivity implements View.OnClickListener, ReaderMenu.Callback,
- OnOverScrollListener, NavigationListener, InternalLinkMovement.OnLinkClickListener {
-
- private static final int REQUEST_SETTINGS = 1299;
-
- private FrameLayout mProgressFrame;
- private MangaReader mReader;
- private ReaderMenu mMenuPanel;
- private ImageView mMenuButton;
- private FrameLayout mOverScrollFrame;
- private ImageView mOverScrollArrow;
- private TextView mOverScrollText;
-
- private MangaSummary mManga;
- private int mChapter;
- private ReaderConfig mConfig;
- private BrightnessHelper mBrightnessHelper;
- @NonNull
- private final Point mViewport = new Point(1, 1);
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_reader2);
- mProgressFrame = findViewById(R.id.loader);
- mMenuPanel = findViewById(R.id.menuPanel);
- mReader = findViewById(R.id.reader);
- mMenuButton = findViewById(R.id.imageView_menu);
- mOverScrollFrame = findViewById(R.id.overscrollFrame);
- mOverScrollArrow = findViewById(R.id.imageView_arrow);
- mOverScrollText = findViewById(R.id.textView_title);
-
- if (isDarkTheme()) {
- mMenuButton.setColorFilter(ContextCompat.getColor(this, R.color.white_overlay_85));
- }
- mMenuButton.setOnClickListener(this);
-
- mBrightnessHelper = new BrightnessHelper(getWindow());
- mReader.initAdapter(this, this);
- mReader.addOnPageChangedListener(mMenuPanel);
- mReader.setOnOverScrollListener(this);
-
- Bundle extras = savedInstanceState != null ? savedInstanceState : getIntent().getExtras();
- mManga = new MangaSummary(extras);
- mChapter = extras.getInt("chapter", 0);
- int page = extras.getInt("page", 0);
-
- mMenuPanel.setData(mManga);
- mMenuPanel.setCallback(this);
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT) {
- mMenuPanel.setFitsSystemWindows(true);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Window window = getWindow();
- int color = ContextCompat.getColor(this, R.color.transparent_dark);
- window.setStatusBarColor(color);
- window.setNavigationBarColor(color);
- }
- }
- updateConfig();
- new ChapterLoadTask(this, page).attach(this).start(mManga.getChapters().get(mChapter));
- }
-
- @Override
- protected void onPostResume() {
- super.onPostResume();
- DisplayMetrics dm = getResources().getDisplayMetrics();
- mViewport.set(dm.widthPixels, dm.heightPixels);
- }
-
- @Override
- public void onWindowFocusChanged(boolean hasFocus) {
- super.onWindowFocusChanged(hasFocus);
- if (hasFocus && Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT && !mMenuPanel.isVisible()) {
- getWindow().getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
- }
-
- @Override
- protected void onPause() {
- saveHistory();
- super.onPause();
- }
-
- @Override
- protected void onDestroy() {
- mReader.finish();
- ChangesObserver.getInstance().emitOnHistoryChanged(mManga);
- super.onDestroy();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putAll(mManga.toBundle());
- outState.putInt("page", mReader.getCurrentPosition());
- outState.putInt("chapter", mChapter);
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- switch (requestCode) {
- case REQUEST_SETTINGS:
- int pageIndex = mReader.getCurrentPosition();
- updateConfig();
- mReader.getLoader().setEnabled(false);
- mReader.scrollToPosition(pageIndex);
- mReader.getLoader().setEnabled(true);
- mReader.notifyDataSetChanged();
- break;
- case PermissionsHelper.REQUEST_CODE:
- if (resultCode == Activity.RESULT_OK) {
- new ImageSaveTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
- mReader.getItem(mReader.getCurrentPosition()));
- } else {
- Snackbar.make((View) mReader, R.string.dir_no_access, Snackbar.LENGTH_SHORT).show();
- }
- break;
- }
- }
-
- private void saveHistory() {
- if (mChapter >= 0 && mChapter < mManga.chapters.size()) {
- HistoryProvider.getInstance(this).add(mManga, mManga.chapters.get(mChapter).number, mReader.getCurrentPosition());
- }
- }
-
- @Override
- public void onClick(View view) {
- switch (view.getId()) {
- case R.id.imageView_menu:
- mMenuPanel.show();
- break;
- }
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_MENU) {
- if (mProgressFrame.getVisibility() != View.VISIBLE) {
- if (mMenuPanel.isShown()) {
- mMenuPanel.hide();
- } else {
- mMenuPanel.show();
- }
- }
- return super.onKeyDown(keyCode, event);
- }
- if (mConfig.scrollByVolumeKeys) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
- if (!mReader.scrollToNext(true)) {
- if (mChapter < mManga.getChapters().size() - 1) {
- mChapter++;
- Toast t = Toast.makeText(this, mManga.getChapters().get(mChapter).name, Toast.LENGTH_SHORT);
- t.setGravity(Gravity.TOP, 0, 0);
- t.show();
- new ChapterLoadTask(ReadActivity2.this,0)
- .attach(ReadActivity2.this)
- .start(mManga.getChapters().get(mChapter));
- return true;
- }
- } else {
- return true;
- }
- } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
- if (!mReader.scrollToPrevious(true)) {
- if (mChapter > 0) {
- mChapter--;
- Toast t = Toast.makeText(this, mManga.getChapters().get(mChapter).name, Toast.LENGTH_SHORT);
- t.setGravity(Gravity.TOP, 0, 0);
- t.show();
- new ChapterLoadTask(ReadActivity2.this, -1)
- .attach(ReadActivity2.this)
- .start(mManga.getChapters().get(mChapter));
- return true;
- }
- } else {
- return true;
- }
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- return mConfig.scrollByVolumeKeys &&
- (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) ||
- super.onKeyUp(keyCode, event);
- }
-
- private void updateConfig() {
- boolean isWeb = HistoryProvider.getInstance(this).isWebMode(mManga);
- if (isWeb) {
- if (mReader instanceof StandardMangaReader) {
- StandardMangaReader oldReader = (StandardMangaReader) mReader;
- ViewGroup parent = (ViewGroup) ((View) mReader).getParent();
- parent.removeView((View) mReader);
- mReader = new WebtoonReader(this);
- mReader.initAdapter(this, this);
- mReader.setPages(oldReader.getPages());
- mReader.scrollToPosition(oldReader.getCurrentPosition());
- mReader.addOnPageChangedListener(mMenuPanel);
- mReader.setOnOverScrollListener(this);
- ((View) mReader).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- parent.addView((View) mReader, 0);
- }
- } else {
- if (mReader instanceof WebtoonReader) {
- WebtoonReader oldReader = (WebtoonReader) mReader;
- ViewGroup parent = (ViewGroup) ((View) mReader).getParent();
- parent.removeView((View) mReader);
- mReader = new StandardMangaReader(this);
- mReader.initAdapter(this, this);
- mReader.setPages(oldReader.getPages());
- mReader.scrollToPosition(oldReader.getCurrentPosition());
- mReader.addOnPageChangedListener(mMenuPanel);
- mReader.setOnOverScrollListener(this);
- ((View) mReader).setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- parent.addView((View) mReader, 0);
- }
- }
- mConfig = ReaderConfig.load(this, mManga);
- mReader.applyConfig(
- mConfig.scrollDirection == ReaderConfig.DIRECTION_VERTICAL,
- mConfig.scrollDirection == ReaderConfig.DIRECTION_REVERSED,
- mConfig.mode == ReaderConfig.MODE_PAGES,
- mConfig.showNumbers
- );
- if (mConfig.keepScreenOn) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
- if (mConfig.hideMenuButton) {
- mMenuButton.setImageDrawable(null);
- } else {
- mMenuButton.setImageResource(R.drawable.ic_action_navigation_more_vert);
- }
- mReader.getLoader().setPreloadEnabled(mConfig.preload == ReaderConfig.PRELOAD_ALWAYS
- || (mConfig.preload == ReaderConfig.PRELOAD_WLAN_ONLY && MangaProviderManager.isWlan(this)));
- mReader.setScaleMode(mConfig.scaleMode);
- if (mConfig.adjustBrightness) {
- mBrightnessHelper.setBrightness(mConfig.brightnessValue);
- } else {
- mBrightnessHelper.reset();
- }
- mReader.setTapNavs(mConfig.tapNavs);
- }
-
- @Override
- public void onActionClick(int id) {
- final int pos = mReader.getCurrentPosition();
- switch (id) {
- case android.R.id.home:
- finish();
- break;
- case R.id.progressBar:
- case android.R.id.title:
- showChaptersList();
- break;
- case R.id.action_save:
- new MangaSaveHelper(this).confirmSave(mManga);
- break;
- case R.id.action_save_more:
- new LoadSourceTask(this).attach(this).start(mManga);
- break;
- case R.id.action_save_image:
- if (PermissionsHelper.accessCommonDir(this, Environment.DIRECTORY_PICTURES)) {
- new ImageSaveTask(this).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mReader.getItem(pos));
- }
- break;
- case R.id.menuitem_thumblist:
- new ThumbnailsDialog(this, mReader.getLoader())
- .setNavigationListener(this)
- .show(pos);
- break;
- case R.id.action_webmode:
- updateConfig();
- HintDialog.showOnce(this, R.string.tip_webtoon);
- break;
- case R.id.nav_action_settings:
- SettingsActivity2.openReaderSettings(this, REQUEST_SETTINGS);
- break;
- case R.id.menuitem_bookmark:
- mMenuPanel.onBookmarkAdded(
- BookmarksProvider.getInstance(this)
- .add(mManga, mManga.chapters.get(mChapter).number, pos, mReader.getItem(pos).getFilename())
- );
- LayoutUtils.centeredToast(this, R.string.bookmark_added);
- break;
- case R.id.menuitem_unbookmark:
- if (BookmarksProvider.getInstance(this)
- .remove(mManga, mManga.chapters.get(mChapter).number, pos)) {
- mMenuPanel.onBookmarkRemoved(pos);
- LayoutUtils.centeredToast(this, R.string.bookmark_removed);
- }
- break;
- case R.id.menuitem_rotation:
- int orientation = getResources().getConfiguration().orientation;
- setRequestedOrientation(orientation == Configuration.ORIENTATION_LANDSCAPE ?
- ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT : ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
- break;
- /*case R.id.nav_left:
- case R.id.nav_right:
- int rd = getRealDirection(id == R.id.nav_left ? OnOverScrollListener.LEFT : OnOverScrollListener.RIGHT);
- if (rd == -1) {
- if (!mReader.scrollToPrevious(true)) {
- if (mChapter > 0) {
- mChapter--;
- Toast t = Toast.makeText(this, mManga.getChapters().get(mChapter).name, Toast.LENGTH_SHORT);
- t.setGravity(Gravity.TOP, 0, 0);
- t.show();
- new ChapterLoadTask(-1).startLoading(mManga.getChapters().get(mChapter));
- }
- }
- } else {
- if (!mReader.scrollToNext(true)) {
- if (mChapter < mManga.getChapters().size() - 1) {
- mChapter++;
- Toast t = Toast.makeText(this, mManga.getChapters().get(mChapter).name, Toast.LENGTH_SHORT);
- t.setGravity(Gravity.TOP, 0, 0);
- t.show();
- new ChapterLoadTask(0).startLoading(mManga.getChapters().get(mChapter));
- }
- }
- }
- break;*/
- }
- }
-
- @Override
- public void onPageChanged(int index) {
- mReader.scrollToPosition(index);
- }
-
- @Override
- public void onVisibilityChanged(boolean visible) {
- mMenuButton.setVisibility(visible ? View.INVISIBLE : View.VISIBLE);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- View decorView = getWindow().getDecorView();
- if (visible) {
- decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
- } else {
- decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // прячем панель навигации
- | View.SYSTEM_UI_FLAG_FULLSCREEN // прячем строку состояния
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
- }
- }
-
-
- private void showChaptersList() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setSingleChoiceItems(mManga.getChapters().getNames(), mChapter, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mMenuPanel.hide();
- mChapter = which;
- new ChapterLoadTask(ReadActivity2.this,0)
- .attach(ReadActivity2.this)
- .start(mManga.getChapters().get(mChapter));
- dialog.dismiss();
- }
- });
- builder.setTitle(R.string.chapters_list);
- builder.create().show();
- }
-
- @Override
- public void onOverScrollFlying(int direction, int distance) {
- float d = distance / (float)(direction <= 1 ? mViewport.x : mViewport.y);
- mOverScrollFrame.setAlpha(Math.min(1f, d * 3.f));
- }
-
- @Override
- public boolean onOverScrollFinished(int direction, int distance) {
- float d = distance / (float)(direction <= 1 ? mViewport.x : mViewport.y);
- if (d >= 0.3f) {
- return true;
- } else {
- mOverScrollFrame.setVisibility(View.GONE);
- return false;
- }
- }
-
- @SuppressLint("RtlHardcoded")
- @Override
- public void onOverScrollStarted(int direction) {
- if (getRealDirection(direction) == -1) {
- //prev chapter
- if (mChapter > 0) {
- mOverScrollText.setText(getString(R.string.prev_chapter, mManga.getChapters().get(mChapter - 1).name));
- } else {
- return;
- }
- } else {
- //next chapter
- if (mChapter < mManga.getChapters().size() - 1) {
- mOverScrollText.setText(getString(R.string.next_chapter, mManga.getChapters().get(mChapter + 1).name));
- } else {
- return;
- }
- }
- mOverScrollFrame.setAlpha(0f);
- mOverScrollFrame.setVisibility(View.VISIBLE);
- if (direction == TOP) {
- ((FrameLayout.LayoutParams)mOverScrollText.getLayoutParams()).gravity = Gravity.CENTER;
- ((FrameLayout.LayoutParams)mOverScrollArrow.getLayoutParams()).gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- mOverScrollArrow.setRotation(0f);
- } else if (direction == LEFT) {
- ((FrameLayout.LayoutParams)mOverScrollText.getLayoutParams()).gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- ((FrameLayout.LayoutParams)mOverScrollArrow.getLayoutParams()).gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
- mOverScrollArrow.setRotation(-90f);
- } else if (direction == BOTTOM) {
- ((FrameLayout.LayoutParams)mOverScrollText.getLayoutParams()).gravity = Gravity.CENTER;
- ((FrameLayout.LayoutParams)mOverScrollArrow.getLayoutParams()).gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
- mOverScrollArrow.setRotation(180f);
- } else if (direction == RIGHT) {
- ((FrameLayout.LayoutParams)mOverScrollText.getLayoutParams()).gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL;
- ((FrameLayout.LayoutParams)mOverScrollArrow.getLayoutParams()).gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
- mOverScrollArrow.setRotation(90f);
- }
- }
-
- @Override
- public void onOverScrolled(int direction) {
- if (mOverScrollFrame.getVisibility() != View.VISIBLE) {
- return;
- }
- mOverScrollFrame.setVisibility(View.GONE);
- int rd = getRealDirection(direction);
- mChapter += rd;
- new ChapterLoadTask(this, rd == -1 ? -1 : 0)
- .attach(this)
- .start(mManga.getChapters().get(mChapter));
- }
-
- private int getRealDirection(int direction) {
- return direction == TOP || direction == LEFT ? mReader.isReversed() ? 1 : -1 : mReader.isReversed() ? -1 : 1;
- }
-
- @Override
- public void onPageChange(int page) {
- mReader.scrollToPosition(page);
- }
-
- @Override
- public void onLinkClicked(TextView view, String scheme, String url) {
- switch (scheme) {
- case "app":
- switch (url) {
- case "retry":
- mReader.reload(mReader.getCurrentPosition());
- break;
- }
- break;
- }
- }
-
- private static class ChapterLoadTask extends WeakAsyncTask> implements DialogInterface.OnCancelListener {
-
- private final int mPageIndex;
-
- ChapterLoadTask(ReadActivity2 object, int page) {
- super(object);
- mPageIndex = page;
- }
-
- @Override
- protected void onPreExecute(@NonNull ReadActivity2 a) {
- a.mProgressFrame.setVisibility(View.VISIBLE);
- a.mReader.getLoader().cancelAll();
- a.mReader.getLoader().setEnabled(false);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected List doInBackground(MangaChapter... mangaChapters) {
- try {
- MangaProvider provider = MangaProviderManager.instanceProvider(getObject(), mangaChapters[0].provider);
- return provider.getPages(mangaChapters[0].readLink);
- } catch (Exception ignored) {
- return null;
- }
- }
-
- private void onFailed(@NonNull final ReadActivity2 a) {
- new AlertDialog.Builder(a)
- .setMessage(NetworkUtils.checkConnection(a) ? R.string.loading_error : R.string.no_network_connection)
- .setTitle(R.string.app_name)
- .setOnCancelListener(this)
- .setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- new ChapterLoadTask(a, mPageIndex)
- .attach(a)
- .start(a.mManga.getChapters().get(a.mChapter));
- }
- })
- .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- })
- .create()
- .show();
- }
-
- @Override
- protected void onPostExecute(@NonNull ReadActivity2 a, List mangaPages) {
- if (mangaPages == null) {
- onFailed(a);
- return;
- }
- a.mReader.setPages(mangaPages);
- a.mReader.notifyDataSetChanged();
- int pos = mPageIndex == -1 ? a.mReader.getItemCount() - 1 : mPageIndex;
- a.mReader.scrollToPosition(pos);
- a.mReader.getLoader().setEnabled(true);
- a.mReader.notifyDataSetChanged();
- a.mMenuPanel.onChapterChanged(a.mManga.chapters.get(a.mChapter) ,mangaPages.size());
- a.mProgressFrame.setVisibility(View.GONE);
- a.showcase(a.mMenuButton, R.string.menu, R.string.tip_reader_menu);
- }
-
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- ReadActivity2 a = getObject();
- if (a != null && a.mReader.getItemCount() == 0) {
- a.finish();
- }
- }
- }
-
- private static class ImageSaveTask extends WeakAsyncTask {
-
- ImageSaveTask(ReadActivity2 object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@Nullable ReadActivity2 a) {
- if (a != null) {
- a.mProgressFrame.setVisibility(View.VISIBLE);
- a.mMenuPanel.hide();
- }
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected File doInBackground(PageWrapper... pageWrappers) {
- File dest;
- try {
- MangaProvider provider;
- provider = MangaProviderManager.instanceProvider(getObject(), pageWrappers[0].page.provider);
- String url = provider.getPageImage(pageWrappers[0].page);
- if (pageWrappers[0].isLoaded()) {
- //noinspection ConstantConditions
- dest = new File(pageWrappers[0].getFilename());
- } else {
- dest = new File(getObject().getExternalFilesDir("temp"), String.valueOf(url.hashCode()));
-
- final SimpleDownload dload = new SimpleDownload(url, dest);
- dload.run();
- if (!dload.isSuccess()) {
- return null;
- }
- }
- File dest2 = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), String.valueOf(url.hashCode()) + ".png");
- Bitmap b = BitmapFactory.decodeFile(dest.getPath());
- if (!StorageUtils.saveBitmap(b, dest2.getPath())) {
- dest2 = null;
- }
- b.recycle();
- return dest2;
- } catch (Exception ignored) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull final ReadActivity2 a, final File file) {
- a.mProgressFrame.setVisibility(View.GONE);
- if (file != null && file.exists()) {
- StorageUtils.scanMediaFile(a, file);
- Snackbar.make(a.mMenuPanel, R.string.image_saved, Snackbar.LENGTH_LONG)
- .setAction(R.string.action_share, new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new ContentShareHelper(a).shareImage(file);
- }
- })
- .show();
- } else {
- Snackbar.make(a.mMenuPanel, R.string.unable_to_save_image, Snackbar.LENGTH_SHORT).show();
- }
-
- }
- }
-
- private static class LoadSourceTask extends WeakAsyncTask {
-
- LoadSourceTask(ReadActivity2 object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull ReadActivity2 a) {
- a.mProgressFrame.setVisibility(View.VISIBLE);
- }
-
- @Override
- protected MangaSummary doInBackground(MangaInfo... params) {
- try {
- return LocalMangaProvider.getInstance(getObject())
- .getSource(params[0]);
- } catch (Exception e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull ReadActivity2 a, MangaSummary sourceManga) {
- a.mProgressFrame.setVisibility(View.GONE);
- if (sourceManga == null) {
- Snackbar.make(a.mMenuPanel, R.string.loading_error, Snackbar.LENGTH_SHORT)
- .show();
- return;
- }
- ChaptersList newChapters = sourceManga.chapters.complementByName(a.mManga.chapters);
- if (sourceManga.chapters.size() <= a.mManga.chapters.size()) {
- Snackbar.make(a.mMenuPanel, R.string.no_new_chapters, Snackbar.LENGTH_SHORT)
- .show();
- } else {
- sourceManga.chapters = newChapters;
- new MangaSaveHelper(a).confirmSave(sourceManga, R.string.action_save_add);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/SearchActivity.java b/app/src/main/java/org/nv95/openmanga/activities/SearchActivity.java
deleted file mode 100644
index a653209e..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/SearchActivity.java
+++ /dev/null
@@ -1,458 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.text.TextUtils;
-import android.view.ActionMode;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.jsoup.helper.StringUtil;
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.SearchHistoryAdapter;
-import org.nv95.openmanga.adapters.SearchResultsAdapter;
-import org.nv95.openmanga.components.SearchInput;
-import org.nv95.openmanga.helpers.ContentShareHelper;
-import org.nv95.openmanga.helpers.ListModeHelper;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-import org.nv95.openmanga.providers.staff.Providers;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceCallback;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceController;
-
-import java.util.ArrayDeque;
-
-/**
- * Created by nv95 on 24.12.16.
- */
-
-public class SearchActivity extends BaseAppActivity implements ListModeHelper.OnListModeListener,
-SearchHistoryAdapter.OnHistoryEventListener, SearchResultsAdapter.OnMoreEventListener, TextView.OnEditorActionListener,
- View.OnFocusChangeListener, SearchInput.OnTextChangedListener, ModalChoiceCallback {
-
- @Nullable
- private String mQuery;
- private SearchInput mSearchInput;
- private RecyclerView mRecyclerView;
- private TextView mTextViewHolder;
- private ProgressBar mProgressBar;
- private Toolbar mToolbar;
- private RecyclerView mRecyclerViewSearch;
- private ListModeHelper mListModeHelper;
- private SearchHistoryAdapter mHistoryAdapter;
- private SearchResultsAdapter mResultsAdapter;
- private int mPage;
- private int mStage;
- private int mActiveProviderId;
- private MangaProvider mCurrentProvider;
- private ArrayDeque mProviders;
- private MangaProviderManager mProviderManager;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_search);
- mToolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(mToolbar);
- enableHomeAsUp();
- setupToolbarScrolling(mToolbar);
-
- Bundle extras = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
- mQuery = extras.getString("query");
- mActiveProviderId = extras.getInt("provider", -5);
-
- mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
- mTextViewHolder = (TextView) findViewById(R.id.textView_holder);
- mSearchInput = (SearchInput) findViewById(R.id.searchInput);
- mRecyclerViewSearch = (RecyclerView) findViewById(R.id.recyclerViewSearch);
-
- mRecyclerView.setLayoutManager(new GridLayoutManager(this, 1));
- mSearchInput.getEditText().setOnEditorActionListener(this);
- mHistoryAdapter = new SearchHistoryAdapter(this, this);
- mResultsAdapter = new SearchResultsAdapter(mRecyclerView);
- mResultsAdapter.setOnLoadMoreListener(this);
- mSearchInput.setOnEditFocusChangeListener(this);
- mSearchInput.setOnTextChangedListener(this);
-
- new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
- return false;
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- long id = viewHolder.getItemId();
- SearchHistoryAdapter.removeFromHistory(SearchActivity.this, id);
- mHistoryAdapter.requery(mSearchInput.getEditText().getText().toString());
- }
- }).attachToRecyclerView(mRecyclerViewSearch);
-
- mListModeHelper = new ListModeHelper(this, this);
- mListModeHelper.applyCurrent();
- mListModeHelper.enable();
-
- mResultsAdapter.getChoiceController().setCallback(this);
- mResultsAdapter.getChoiceController().setEnabled(true);
-
- mProviderManager = new MangaProviderManager(this);
- mProviders = new ArrayDeque<>(mProviderManager.getProvidersCount());
-
- mRecyclerView.setAdapter(mResultsAdapter);
- mRecyclerViewSearch.setAdapter(mHistoryAdapter);
- mSearchInput.getEditText().setText(mQuery);
- }
-
- @Override
- protected void onPostCreate(@Nullable Bundle savedInstanceState) {
- super.onPostCreate(savedInstanceState);
- if (TextUtils.isEmpty(mQuery)) {
- LayoutUtils.showSoftKeyboard(mSearchInput.getEditText());
- } else {
- closeHistory();
- search(0);
- }
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putString("query", mQuery);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.search, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- @Override
- public boolean onPrepareOptionsMenu(Menu menu) {
- mListModeHelper.onPrepareOptionsMenu(menu);
- return super.onPrepareOptionsMenu(menu);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_clear:
- SearchHistoryAdapter.clearHistory(this);
- mHistoryAdapter.requeryAsync(null);
- return true;
- default:
- return mListModeHelper.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onListModeChanged(boolean grid, int sizeMode) {
- int spans;
- ThumbSize thumbSize;
- switch (sizeMode) {
- case -1:
- spans = LayoutUtils.isTabletLandscape(this) ? 2 : 1;
- thumbSize = ThumbSize.THUMB_SIZE_LIST;
- break;
- case 0:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_SMALL);
- break;
- case 1:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_MEDIUM);
- break;
- case 2:
- spans = LayoutUtils.getOptimalColumnsCount(getResources(), thumbSize = ThumbSize.THUMB_SIZE_LARGE);
- break;
- default:
- return;
- }
- GridLayoutManager layoutManager = (GridLayoutManager) mRecyclerView.getLayoutManager();
- int position = layoutManager.findFirstCompletelyVisibleItemPosition();
- layoutManager.setSpanCount(spans);
- layoutManager.setSpanSizeLookup(mResultsAdapter.getSpanSizeLookup(spans));
- mResultsAdapter.setThumbnailsSize(thumbSize);
- if (mResultsAdapter.setGrid(grid)) {
- mRecyclerView.setAdapter(mResultsAdapter);
- }
- mRecyclerView.scrollToPosition(position);
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- mListModeHelper.applyCurrent();
- }
-
- @Override
- protected void onDestroy() {
- mListModeHelper.disable();
- super.onDestroy();
- }
-
- @Override
- public void onHistoryItemClick(String text, boolean apply) {
- mSearchInput.setText(text);
- if (apply) {
- mSearchInput.getEditText().onEditorAction(EditorInfo.IME_ACTION_SEARCH);
- }
- }
-
- @Override
- public void onMoreButtonClick() {
- search(1);
- }
-
- @Override
- public boolean onLoadMore() {
- new SearchTask(this).attach(this).start();
- return true;
- }
-
- private void search(int stage) {
- ProviderSummary prov = Providers.getById(mActiveProviderId);
- if (stage == 0) {
- mResultsAdapter.clearData();
- AnimUtils.crossfade(mTextViewHolder, mProgressBar);
- mPage = 0;
- mStage = 0;
- mCurrentProvider = null;
- mProviders.clear();
- if (prov == null) {
- mProviders.add(LocalMangaProvider.getProviderSummary(this));
- mProviders.add(HistoryProvider.getProviderSummary(this));
- mProviders.addAll(mProviderManager.getEnabledOrderedProviders());
- mStage = 1;
- } else {
- mProviders.add(LocalMangaProvider.getProviderSummary(this));
- mProviders.add(HistoryProvider.getProviderSummary(this));
- mProviders.add(prov);
- }
- new SearchTask(this).start();
- } else {
- mProviders.addAll(mProviderManager.getEnabledOrderedProviders());
- if (prov != null) {
- mProviders.remove(prov);
- }
- mPage = 0;
- mCurrentProvider = null;
- if (mProviders.isEmpty()) {
- if (mResultsAdapter.hasItems()) {
- mResultsAdapter.hideFooter();
- } else {
- AnimUtils.crossfade(mProgressBar, mTextViewHolder);
- }
- } else {
- if (mProgressBar.getVisibility() != View.VISIBLE) {
- mResultsAdapter.setFooterProgress();
- } else {
- mResultsAdapter.hideFooter();
- }
- new SearchTask(this).attach(this).start();
- }
- mStage = 1;
- }
- }
-
- @Override
- public boolean onEditorAction(final TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_SEARCH) {
- mQuery = v.getText().toString();
- if (StringUtil.isBlank(mQuery)) {
- showToast(R.string.search_query_empty, Gravity.TOP, Toast.LENGTH_SHORT);
- v.postDelayed(new Runnable() {
- @Override
- public void run() {
- LayoutUtils.showSoftKeyboard(v);
- }
- }, 500);
- return true;
- }
- SearchHistoryAdapter.addToHistory(this, mQuery);
- closeHistory();
- search(0);
- return true;
- } else {
- return false;
- }
- }
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (hasFocus) {
- mHistoryAdapter.requeryAsync(mQuery);
- AnimUtils.crossfade(null, mRecyclerViewSearch);
- setToolbarScrollingLock(mToolbar, true);
- } else {
- AnimUtils.crossfade(mRecyclerViewSearch, null);
- mSearchInput.getEditText().setText(mQuery);
- setToolbarScrollingLock(mToolbar, false);
- }
- }
-
- @Override
- public void onBackPressed() {
- if (mRecyclerViewSearch.getVisibility() == View.VISIBLE) {
- if (TextUtils.isEmpty(mQuery)) {
- super.onBackPressed();
- } else {
- closeHistory();
- }
- } else {
- super.onBackPressed();
- }
- }
-
- private void closeHistory() {
- LayoutUtils.hideSoftKeyboard(mRecyclerView);
- if (!mRecyclerViewSearch.isFocused()) {
- onFocusChange(mRecyclerViewSearch, false);
- }
- mRecyclerView.requestFocus();
- }
-
- @Override
- public void onTextChanged(CharSequence text) {
- mHistoryAdapter.requeryAsync(text.toString());
- }
-
- @Override
- public void onChoiceChanged(ActionMode actionMode, ModalChoiceController controller, int count) {
- actionMode.setTitle(String.valueOf(count));
- actionMode.getMenu().findItem(R.id.action_share).setVisible(count == 1);
- }
-
- @Override
- public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
- getMenuInflater().inflate(R.menu.actionmode_mangas, menu);
- menu.findItem(R.id.action_save).setVisible(true);
- return true;
- }
-
- @Override
- public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
- return false;
- }
-
- @Override
- public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {
- final int[] indeces = mResultsAdapter.getChoiceController().getSelectedItemsPositions();
- final MangaInfo[] items = new MangaInfo[indeces.length];
- for (int i=0;i {
-
- @Nullable
- private final ProviderSummary mSummary;
-
-
- SearchTask(SearchActivity a) {
- super(a);
- if (a.mCurrentProvider == null) {
- mSummary = a.mProviders.pop();
- a.mCurrentProvider = a.mProviderManager.instanceProvider(mSummary.aClass);
- a.mPage = 0;
- } else {
- mSummary = null;
- }
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected MangaList doInBackground(Void... params) {
- try {
- return getObject().mCurrentProvider.search(
- getObject().mQuery,
- getObject().mPage);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull SearchActivity a, MangaList mangaInfos) {
- a.mResultsAdapter.loadingComplete();
- if (mangaInfos != null && !mangaInfos.isEmpty()) {
- a.mPage++;
- a.mResultsAdapter.append(mSummary, mangaInfos);
- if (a.mProgressBar.getVisibility() == View.VISIBLE) {
- AnimUtils.crossfade(a.mProgressBar, null);
- a.mResultsAdapter.setFooterProgress();
- }
- a.mResultsAdapter.onScrolled(a.mRecyclerView);
- } else {
- //nothing found
- if (a.mProviders.isEmpty()) {
- //no more providers
- if (a.mStage == 0) {
- if (a.mResultsAdapter.hasItems()) {
- a.mResultsAdapter.setFooterButton(a.getString(R.string.search_on_another_sources));
- } else {
- a.onMoreButtonClick();
- }
- } else {
- if (a.mResultsAdapter.hasItems()) {
- a.mResultsAdapter.hideFooter();
- } else {
- AnimUtils.crossfade(a.mProgressBar, a.mTextViewHolder);
- }
- }
- } else {
- //next provider
- a.mCurrentProvider = null;
- if (a.mResultsAdapter.hasItems()) {
- a.mResultsAdapter.setFooterProgress();
- a.mResultsAdapter.onScrolled(a.mRecyclerView);
- } else {
- a.onLoadMore();
- }
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/WelcomeActivity.java b/app/src/main/java/org/nv95/openmanga/activities/WelcomeActivity.java
deleted file mode 100755
index 62a7b600..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/WelcomeActivity.java
+++ /dev/null
@@ -1,222 +0,0 @@
-package org.nv95.openmanga.activities;
-
-import android.Manifest;
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
-import android.text.Html;
-import android.view.View;
-import android.widget.Button;
-import android.widget.Checkable;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.BuildConfig;
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.settings.SettingsActivity2;
-import org.nv95.openmanga.dialogs.DirSelectDialog;
-import org.nv95.openmanga.dialogs.StorageSelectDialog;
-import org.nv95.openmanga.providers.staff.Providers;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.BackupRestoreUtil;
-import org.nv95.openmanga.utils.MangaStore;
-
-import java.io.File;
-
-/**
- * Created by nv95 on 18.10.15.
- */
-public class WelcomeActivity extends BaseAppActivity {
-
- public static final int REQUEST_ONBOARDING = 131;
- public static final int REQUEST_SOURCES = 132;
-
- private static final int WELCOME_CHANGELOG = 1;
- private static final int WELCOME_ONBOARDING = 2;
-
- private TextView mTextViewSources;
- private TextView mTextViewTheme;
- private TextView mTextViewStorage;
-
- /**
- *
- * @param context
- * @return true if first call
- */
- public static boolean show(Activity context) {
- SharedPreferences prefs = context.getSharedPreferences(WelcomeActivity.class.getName(), MODE_PRIVATE);
- int version = BuildConfig.VERSION_CODE;
- int lastVersion = prefs.getInt("version", -1);
- if (lastVersion == -1) {
- context.startActivityForResult(
- new Intent(context, WelcomeActivity.class)
- .putExtra("mode", WELCOME_ONBOARDING),
- REQUEST_ONBOARDING
- );
- } else if (lastVersion < version) {
- if (version % 2 == 0 && prefs.getBoolean("showChangelog", true)) {
- context.startActivity(
- new Intent(context, WelcomeActivity.class)
- .putExtra("mode", WELCOME_CHANGELOG)
- );
- }
- }
- prefs.edit().putInt("version", version).apply();
- return lastVersion == -1;
- }
-
- @SuppressLint("SetTextI18n")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_welcome);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- //init view
- mTextViewSources = (TextView) findViewById(R.id.textViewSources);
- mTextViewStorage = (TextView) findViewById(R.id.textViewStorage);
- mTextViewTheme = (TextView) findViewById(R.id.textViewTheme);
- //---------
- int mode = getIntent().getIntExtra("mode", WELCOME_CHANGELOG);
- switch (mode) {
- case WELCOME_CHANGELOG:
- findViewById(R.id.page_changelog).setVisibility(View.VISIBLE);
- ((TextView) findViewById(R.id.textView)).setText(
- Html.fromHtml(AppHelper.getRawString(this, R.raw.changelog))
- );
- findViewById(R.id.button_close).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
- findViewById(R.id.checkBox_showChangelog).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (v instanceof Checkable) {
- getSharedPreferences(WelcomeActivity.class.getName(), MODE_PRIVATE)
- .edit().putBoolean("showChangelog", ((Checkable) v).isChecked()).apply();
- }
- }
- });
- break;
- case WELCOME_ONBOARDING:
- ViewCompat.setElevation(toolbar, 0);
- findViewById(R.id.page_onboarding1).setVisibility(View.VISIBLE);
- findViewById(R.id.button_done).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
- final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- final String[] themes = getResources().getStringArray(R.array.themes_names);
- int selTheme = Integer.parseInt(prefs.getString("theme", "0"));
- mTextViewTheme.setText(getString(R.string.theme) + ": " + themes[selTheme]);
- mTextViewTheme.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new AlertDialog.Builder(WelcomeActivity.this)
- .setItems(themes, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- mTextViewTheme.setText(getString(R.string.theme) + ": " + themes[i]);
- prefs.edit()
- .putString("theme", String.valueOf(i))
- .apply();
- dialogInterface.dismiss();
- }
- })
- .create()
- .show();
- }
- });
- Button buttonRestore = (Button) findViewById(R.id.buttonRestore);
- buttonRestore.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
- BackupRestoreUtil.showRestoreDialog(WelcomeActivity.this);
- }
- }
- });
- Button buttonSync = (Button) findViewById(R.id.buttonSync);
- buttonSync.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- SettingsActivity2.openSyncSettings(WelcomeActivity.this, 0);
- }
- });
- int active = Math.min(
- getSharedPreferences("providers", Context.MODE_PRIVATE).getInt("count", Providers.getCount()),
- Providers.getCount()
- );
- mTextViewSources.setText(getString(R.string.sources) + ": " + getString(R.string.providers_pref_summary, active, Providers.getCount()));
- mTextViewSources.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- SettingsActivity2.openProvidersSettings(WelcomeActivity.this, REQUEST_SOURCES);
- }
- });
- mTextViewStorage.setText(MangaStore.getMangasDir(this).getPath());
- mTextViewStorage.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- new StorageSelectDialog(WelcomeActivity.this, false)
- .setDirSelectListener(new DirSelectDialog.OnDirSelectListener() {
- @Override
- public void onDirSelected(File dir) {
- prefs.edit()
- .putString("mangadir", dir.getPath())
- .apply();
- mTextViewStorage.setText(dir.getPath());
- }
- })
- .show();
- }
- });
- break;
- default:
- finish();
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case BackupRestoreUtil.BACKUP_IMPORT_CODE:
- if (resultCode == RESULT_OK) {
- File file = AppHelper.getFileFromUri(this, data.getData());
- if (file != null) {
- new BackupRestoreUtil(this).restore(file);
- } else {
- Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show();
- }
- }
- break;
- case REQUEST_SOURCES:
- int active = Math.min(
- getSharedPreferences("providers", Context.MODE_PRIVATE).getInt("count", Providers.getCount()),
- Providers.getCount()
- );
- mTextViewSources.setText(getString(R.string.sources) + ": " + getString(R.string.providers_pref_summary, active, Providers.getCount()));
- break;
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- protected void onPermissionGranted(String permission) {
- if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)) {
- BackupRestoreUtil.showRestoreDialog(WelcomeActivity.this);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/AppearanceSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/AppearanceSettingsFragment.java
deleted file mode 100644
index 2dad20e9..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/AppearanceSettingsFragment.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.PreferencesUtils;
-
-/**
- * Created by admin on 21.07.17.
- */
-
-public class AppearanceSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_appearance);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- PreferencesUtils.bindPreferenceSummary(findPreference("theme"), (Preference.OnPreferenceChangeListener) getActivity());
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Activity activity = getActivity();
- if (activity != null) {
- activity.setTitle(R.string.appearance);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/GeneralSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/GeneralSettingsFragment.java
deleted file mode 100644
index 28303064..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/GeneralSettingsFragment.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.preference.ListPreference;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.widget.Toast;
-
-import org.nv95.openmanga.OpenMangaApplication;
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.PreferencesUtils;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class GeneralSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_general);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- Activity activity = getActivity();
-
- PreferencesUtils.bindPreferenceSummary(findPreference("lang"), new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- OpenMangaApplication.setLanguage(preference.getContext().getApplicationContext().getResources(), (String) newValue);
- int index = ((ListPreference) preference).findIndexOfValue((String) newValue);
- String summ = ((ListPreference) preference).getEntries()[index].toString();
- preference.setSummary(summ);
- Toast.makeText(preference.getContext(), R.string.need_restart, Toast.LENGTH_SHORT).show();
- return true;
- }
- });
-
- findPreference("recommendations").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
-
- PreferencesUtils.bindPreferenceSummary(findPreference("fav.categories"));
- PreferencesUtils.bindPreferenceSummary(findPreference("defsection"));
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Activity activity = getActivity();
- if (activity != null) {
- activity.setTitle(R.string.appearance);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/OtherSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/OtherSettingsFragment.java
deleted file mode 100644
index eb4a66db..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/OtherSettingsFragment.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceFragment;
-import android.support.annotation.NonNull;
-import android.widget.Toast;
-
-import org.nv95.openmanga.BuildConfig;
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.BaseAppActivity;
-import org.nv95.openmanga.adapters.SearchHistoryAdapter;
-import org.nv95.openmanga.helpers.ScheduleHelper;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.MangaStore;
-import org.nv95.openmanga.utils.PreferencesUtils;
-import org.nv95.openmanga.utils.StorageUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-/**
- * Created by admin on 21.07.17.
- */
-
-public class OtherSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_other);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- Activity activity = getActivity();
- findPreference("movemanga").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
- findPreference("backup").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
- findPreference("restore").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
-
- Preference p = findPreference("mangadir");
- try {
- p.setSummary(MangaStore.getMangasDir(activity).getPath());
- } catch (Exception e) {
- p.setSummary(R.string.unknown);
- }
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
-
- PreferencesUtils.bindPreferenceSummary(findPreference("cache_max"), new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- try {
- int size = (int) newValue;
- if (size >= ImageUtils.CACHE_MIN_MB && size <= ImageUtils.CACHE_MAX_MB) {
- //noinspection ConstantConditions
- int aval = StorageUtils.getFreeSpaceMb(preference.getContext().getExternalCacheDir().getPath());
- if (aval != 0 && size >= aval - 50) {
- Toast.makeText(preference.getContext(), R.string.too_small_free_space, Toast.LENGTH_SHORT).show();
- return false;
- }
- return true;
- }
- } catch (Exception ignored) {
- }
- Toast.makeText(preference.getContext(), getString(R.string.cache_size_invalid, ImageUtils.CACHE_MIN_MB, ImageUtils.CACHE_MAX_MB), Toast.LENGTH_SHORT).show();
- return false;
- }
- }, activity.getString(R.string.size_mb));
-
-
- PreferencesUtils.bindPreferenceSummary(findPreference("save_threads"));
-
- findPreference("ccache").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
-
- p = findPreference("csearchhist");
- p.setSummary(getString(R.string.items_, SearchHistoryAdapter.getHistorySize(activity)));
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
-
- findPreference("bugreport").setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
- findPreference("use_tor").setOnPreferenceChangeListener((Preference.OnPreferenceChangeListener) activity);
-
- p = findPreference("update");
- if (BuildConfig.SELFUPDATE_ENABLED) {
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
- long lastCheck = new ScheduleHelper(activity).getActionRawTime(ScheduleHelper.ACTION_CHECK_APP_UPDATES);
- p.setSummary(getString(R.string.last_update_check,
- lastCheck == -1 ? getString(R.string.unknown) : AppHelper.getReadableDateTimeRelative(lastCheck)));
- } else if (p != null) {
- PreferenceCategory cat = (PreferenceCategory) findPreference("cat_help");
- cat.removePreference(p);
- cat.removePreference(findPreference("autoupdate"));
- }
-
- p = findPreference("about");
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) activity);
- p.setSummary(String.format(activity.getString(R.string.version),
- BuildConfig.VERSION_NAME));
-
- new CacheSizeTask(findPreference("ccache")).attach((BaseAppActivity) activity).start();
- }
-
- private static class CacheSizeTask extends WeakAsyncTask {
-
- CacheSizeTask(Preference object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull Preference preference) {
- preference.setSummary(R.string.size_calculating);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected Float doInBackground(Void... voids) {
- try {
- return StorageUtils.dirSize(getObject().getContext().getExternalCacheDir()) / 1048576f;
- } catch (Exception e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull Preference preference, Float aFloat) {
- preference.setSummary(String.format(preference.getContext().getString(R.string.cache_size),
- aFloat == null ? 0 : aFloat));
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Activity activity = getActivity();
- if (activity != null) {
- activity.setTitle(R.string.other_settings);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/PreferenceHeader.java b/app/src/main/java/org/nv95/openmanga/activities/settings/PreferenceHeader.java
deleted file mode 100644
index ae78f19f..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/PreferenceHeader.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.content.Context;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.DrawableRes;
-import android.support.annotation.StringRes;
-import android.support.v4.content.ContextCompat;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class PreferenceHeader {
-
- public String title;
- public Drawable icon;
-
- public PreferenceHeader(Context context, @StringRes int title, @DrawableRes int icon) {
- this.title = context.getString(title);
- this.icon = ContextCompat.getDrawable(context, icon);
- this.icon.setColorFilter(LayoutUtils.getAttrColor(context, R.attr.colorAccent), PorterDuff.Mode.SRC_ATOP);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderPreferencesActivity.java b/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderPreferencesActivity.java
deleted file mode 100644
index eedbfa1e..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderPreferencesActivity.java
+++ /dev/null
@@ -1,138 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceFragment;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.BaseAppActivity;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-import org.nv95.openmanga.providers.staff.Providers;
-
-import java.lang.reflect.Method;
-
-/**
- * Created by nv95 on 21.11.16.
- */
-
-public class ProviderPreferencesActivity extends BaseAppActivity {
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_settings);
- setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
- enableHomeAsUp();
- int pid = getIntent().getIntExtra("provider", -1);
- if (pid == -1) {
- finish();
- return;
- }
- ProviderSummary ps = Providers.getById(pid);
- if (ps == null) {
- finish();
- return;
- }
- setTitle(ps.name);
- setSubtitle(R.string.action_settings);
- ProviderPrefFragment fragment = new ProviderPrefFragment();
- fragment.setArguments(getIntent().getExtras());
- getFragmentManager().beginTransaction()
- .replace(R.id.content, fragment)
- .commit();
- }
-
- public static class ProviderPrefFragment extends PreferenceFragment {
-
- private ProviderSummary mProvider;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mProvider = Providers.getById(getArguments().getInt("provider"));
- getPreferenceManager().setSharedPreferencesName("prov_" + mProvider.aClass.getSimpleName());
- addPreferencesFromResource(mProvider.preferences);
-
- Preference testPref = findPreference("auth_test");
- if (testPref != null) {
- testPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- SharedPreferences prefs = getPreferenceManager().getSharedPreferences();
- new TestAuthTask(getActivity()).executeOnExecutor(
- AsyncTask.THREAD_POOL_EXECUTOR,
- prefs.getString("login",""),
- prefs.getString("password",""),
- prefs.getString("domain","")
- );
- return true;
- }
- });
- }
- }
-
- private class TestAuthTask extends AsyncTask implements DialogInterface.OnCancelListener {
-
- private final Activity mActivity;
- private final ProgressDialog mDialog;
-
- TestAuthTask(Activity activity) {
- this.mActivity = activity;
- mDialog = new ProgressDialog(mActivity);
- mDialog.setOwnerActivity(mActivity);
- mDialog.setMessage(mActivity.getString(R.string.wait));
- mDialog.setOnCancelListener(this);
- mDialog.setCancelable(true);
- mDialog.setCanceledOnTouchOutside(true);
- mDialog.setIndeterminate(true);
- }
-
- @Override
- protected void onPreExecute() {
- mDialog.show();
- super.onPreExecute();
- }
-
- @Override
- protected Boolean doInBackground(String... strings) {
- try {
- Method m = mProvider.aClass.getMethod("auth", String.class, String.class, String.class);
- return (Boolean) m.invoke(null, strings[0], strings[1], strings[2]);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(Boolean aBoolean) {
- super.onPostExecute(aBoolean);
- int msg = R.string.error;
- if (Boolean.TRUE.equals(aBoolean)) {
- msg = R.string.successfully;
- } else if (Boolean.FALSE.equals(aBoolean)) {
- msg = R.string.auth_failed;
- }
- mDialog.dismiss();
- new AlertDialog.Builder(mActivity)
- .setMessage(msg)
- .setPositiveButton(R.string.close, null)
- .create()
- .show();
- }
-
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- this.cancel(false);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderSelectFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderSelectFragment.java
deleted file mode 100644
index b5658d5f..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/ProviderSelectFragment.java
+++ /dev/null
@@ -1,140 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.app.Fragment;
-import android.os.Bundle;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.ProvidersAdapter;
-import org.nv95.openmanga.components.DividerItemDecoration;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by admin on 23.07.17.
- */
-
-public class ProviderSelectFragment extends Fragment implements ProvidersAdapter.OnStartDragListener {
-
- private RecyclerView mRecyclerView;
- private List mProviders;
- private MangaProviderManager mProviderManager;
- private ProvidersAdapter mAdapter;
- private ItemTouchHelper mItemTouchHelper;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
- View contentView = inflater.inflate(R.layout.fragment_provselect, container, false);
- mRecyclerView = contentView.findViewById(R.id.recyclerView);
- return contentView;
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- Activity activity = getActivity();
- mProviderManager = new MangaProviderManager(activity);
- mProviders = mProviderManager.getOrderedProviders();
-
- mRecyclerView.setLayoutManager(new LinearLayoutManager(activity));
- mRecyclerView.setAdapter(mAdapter = new ProvidersAdapter(activity, mProviders, this));
- mAdapter.setActiveCount(mProviderManager.getProvidersCount());
- mRecyclerView.addItemDecoration(new DividerItemDecoration(activity));
-
- mItemTouchHelper = new ItemTouchHelper(new OrderManager());
- mItemTouchHelper.attachToRecyclerView(mRecyclerView);
- }
-
- @Override
- public void onStartDrag(RecyclerView.ViewHolder viewHolder) {
- mItemTouchHelper.startDrag(viewHolder);
- }
-
- private class OrderManager extends ItemTouchHelper.Callback {
-
- @Override
- public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
- return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0);
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
- int fromPosition = viewHolder.getAdapterPosition();
- int toPosition = target.getAdapterPosition();
-
- if (toPosition == mProviders.size() + 1 || toPosition == mAdapter.getActiveCount()) { //drop to footer/divider
- return false;
- }
-
- if (viewHolder instanceof ProvidersAdapter.DividerHolder) { //divider
- if (toPosition == 0) {
- return false; //enabled providers count must be > 0
- }
- mAdapter.setActiveCount(toPosition);
- mAdapter.notifyItemMoved(fromPosition, toPosition);
- mProviderManager.setProvidersCount(toPosition);
- return true;
- }
-
- if (fromPosition > mAdapter.getActiveCount() && toPosition < mAdapter.getActiveCount()) {
- return false;
- }
-
- if (fromPosition < mAdapter.getActiveCount() && toPosition > mAdapter.getActiveCount()) {
- return false;
- }
-
- if (fromPosition > mAdapter.getActiveCount()) {
- fromPosition--;
- }
-
- if (toPosition > mAdapter.getActiveCount()) {
- toPosition--;
- }
-
- if (fromPosition < toPosition) {
- for (int i = fromPosition; i < toPosition; i++) {
- Collections.swap(mProviders, i, i + 1);
- }
- } else {
- for (int i = fromPosition; i > toPosition; i--) {
- Collections.swap(mProviders, i, i - 1);
- }
- }
-
- mAdapter.notifyItemMoved(viewHolder.getAdapterPosition(), target.getAdapterPosition());
- mProviderManager.updateOrder(mProviders);
- return true;
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
-
- }
-
- @Override
- public boolean isLongPressDragEnabled() {
- return false;
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Activity activity = getActivity();
- if (activity != null) {
- activity.setTitle(R.string.manga_catalogues);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/ReadSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/ReadSettingsFragment.java
deleted file mode 100644
index 433d0f9a..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/ReadSettingsFragment.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.preference.PreferenceFragment;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.PreferencesUtils;
-
-/**
- * Created by admin on 21.07.17.
- */
-
-public class ReadSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_read);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- Activity activity = getActivity();
- PreferencesUtils.bindPreferenceSummary(findPreference("direction"));
- PreferencesUtils.bindPreferenceSummary(findPreference("r2_mode"));
- PreferencesUtils.bindPreferenceSummary(findPreference("scalemode"));
- PreferencesUtils.bindPreferenceSummary(findPreference("preload"));
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Activity activity = getActivity();
- if (activity != null) {
- activity.setTitle(R.string.action_reading_options);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsActivity2.java b/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsActivity2.java
deleted file mode 100644
index a0c9eb01..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsActivity2.java
+++ /dev/null
@@ -1,616 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.Manifest;
-import android.app.Activity;
-import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.AppBarLayout;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.CardView;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.FrameLayout;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.AboutActivity;
-import org.nv95.openmanga.activities.BaseAppActivity;
-import org.nv95.openmanga.adapters.SearchHistoryAdapter;
-import org.nv95.openmanga.dialogs.DirSelectDialog;
-import org.nv95.openmanga.dialogs.LocalMoveDialog;
-import org.nv95.openmanga.dialogs.RecommendationsPrefDialog;
-import org.nv95.openmanga.dialogs.StorageSelectDialog;
-import org.nv95.openmanga.helpers.DirRemoveHelper;
-import org.nv95.openmanga.helpers.ScheduleHelper;
-import org.nv95.openmanga.helpers.SyncHelper;
-import org.nv95.openmanga.items.RESTResponse;
-import org.nv95.openmanga.providers.AppUpdatesProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.services.SyncService;
-import org.nv95.openmanga.services.UpdateService;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.BackupRestoreUtil;
-import org.nv95.openmanga.utils.FileLogger;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.ProgressAsyncTask;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.io.File;
-import java.util.ArrayList;
-
-import info.guardianproject.netcipher.proxy.OrbotHelper;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class SettingsActivity2 extends BaseAppActivity implements AdapterView.OnItemClickListener,
- Preference.OnPreferenceClickListener, Preference.OnPreferenceChangeListener, FragmentManager.OnBackStackChangedListener {
-
- private static final int SECTION_READER = 2;
- private static final int SECTION_PROVIDERS = 3;
- private static final int SECTION_SYNC = 4;
- private static final int SECTION_CHUPD = 5;
-
- private Fragment mFragment;
- private SettingsHeadersAdapter mAdapter;
- private ArrayList mHeaders;
- private AppBarLayout mAppBarLayout;
- private CardView mCardView;
- private FrameLayout mContent;
- private TextView mTitleTextView;
- private boolean mIsTwoPanesMode;
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_settings2);
- setSupportActionBar(R.id.toolbar);
- enableHomeAsUp();
- disableTitle();
-
- mIsTwoPanesMode = LayoutUtils.isTabletLandscape(this);
-
- mContent = (FrameLayout) findViewById(R.id.content);
- mCardView = (CardView) findViewById(R.id.cardView);
- mTitleTextView = (TextView) findViewById(R.id.textView_title);
- mAppBarLayout = (AppBarLayout) findViewById(R.id.appbar_container);
- RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
- recyclerView.setLayoutManager(new LinearLayoutManager(this));
- mHeaders = new ArrayList<>();
-
- mHeaders.add(new PreferenceHeader(this, R.string.general, R.drawable.ic_pref_home));
- mHeaders.add(new PreferenceHeader(this, R.string.appearance, R.drawable.ic_pref_appearance));
- mHeaders.add(new PreferenceHeader(this, R.string.manga_catalogues, R.drawable.ic_pref_sources));
- mHeaders.add(new PreferenceHeader(this, R.string.action_reading_options, R.drawable.ic_pref_reader));
- mHeaders.add(new PreferenceHeader(this, R.string.checking_new_chapters, R.drawable.ic_pref_cheknew));
- mHeaders.add(new PreferenceHeader(this, R.string.sync, R.drawable.ic_pref_sync));
- mHeaders.add(new PreferenceHeader(this, R.string.more_, R.drawable.ic_pref_more));
-
- recyclerView.setAdapter(mAdapter = new SettingsHeadersAdapter(mHeaders, this));
- getFragmentManager().addOnBackStackChangedListener(this);
-
- mFragment = null;
- int section = getIntent().getIntExtra("section", 0);
- switch (section) {
- case SECTION_READER:
- mFragment = new ReadSettingsFragment();
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(3);
- }
- break;
- case SECTION_PROVIDERS:
- mFragment = new ProviderSelectFragment();
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(2);
- }
- break;
- case SECTION_SYNC:
- mFragment = SyncHelper.get(this).isAuthorized() ? new SyncSettingsFragment() : new SyncLoginFragment();
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(5);
- }
- break;
- case SECTION_CHUPD:
- mFragment = new UpdatesCheckSettingsFragment();
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(4);
- }
- break;
- default:
- if (mIsTwoPanesMode) {
- mFragment = new GeneralSettingsFragment();
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(0);
- }
- } else {
- mFragment = null;
- }
- }
-
- if (mFragment != null) {
- if (!mIsTwoPanesMode) {
- mAppBarLayout.setExpanded(false, false);
- AnimUtils.noanim(mCardView, mContent);
- }
- FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.replace(R.id.content, mFragment);
- transaction.commit();
- }
- }
-
- @Override
- public void onItemClick(AdapterView> adapterView, View view, int i, long l) {
- switch (i) {
- case 0:
- openFragment(new GeneralSettingsFragment());
- break;
- case 1:
- openFragment(new AppearanceSettingsFragment());
- break;
- case 2:
- openFragment(new ProviderSelectFragment());
- break;
- case 3:
- openFragment(new ReadSettingsFragment());
- break;
- case 4:
- openFragment(new UpdatesCheckSettingsFragment());
- break;
- case 5:
- if (SyncHelper.get(this).isAuthorized()) {
- openFragment(new SyncSettingsFragment());
- } else {
- openFragment(new SyncLoginFragment());
- }
- break;
- case 6:
- openFragment(new OtherSettingsFragment());
- break;
- }
- if (mIsTwoPanesMode) {
- mAdapter.setActivatedPosition(i);
- }
- }
-
- public void openFragment(Fragment fragment) {
- mFragment = fragment;
- FragmentTransaction transaction = getFragmentManager().beginTransaction();
- transaction.replace(R.id.content, mFragment);
- if (!mIsTwoPanesMode) {
- transaction.addToBackStack(null);
- }
- transaction.commit();
- }
-
- @Override
- public void setTitle(int titleId) {
- if (!mIsTwoPanesMode) {
- mTitleTextView.setText(titleId);
- }
- }
-
- @Override
- public void setTitle(CharSequence title) {
- if (!mIsTwoPanesMode) {
- mTitleTextView.setText(title);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item.getItemId() == android.R.id.home) {
- if (!getFragmentManager().popBackStackImmediate()) {
- finish();
- }
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public boolean onPreferenceClick(final Preference preference) {
- switch (preference.getKey()) {
- case "bugreport":
- FileLogger.sendLog(this);
- return true;
- case "csearchhist":
- SearchHistoryAdapter.clearHistory(this);
- Toast.makeText(this, R.string.completed, Toast.LENGTH_SHORT).show();
- preference.setSummary(getString(R.string.items_, 0));
- return true;
- case "about":
- startActivity(new Intent(this, AboutActivity.class));
- return true;
- case "recommendations":
- new RecommendationsPrefDialog(this, null).show();
- return true;
- case "backup":
- if (checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- BackupRestoreUtil.showBackupDialog(this);
- }
- return true;
- case "restore":
- if (checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
- BackupRestoreUtil.showRestoreDialog(this);
- }
- return true;
- case "ccache":
- new CacheClearTask(preference).attach(this).start();
- return true;
- case "movemanga":
- if (checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE) && checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
- new LocalMoveDialog(this,
- LocalMangaProvider.getInstance(this).getAllIds())
- .showSelectSource(null);
- }
- return true;
- case "mangadir":
- if (!checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
- return true;
- }
- new StorageSelectDialog(this)
- .setDirSelectListener(new DirSelectDialog.OnDirSelectListener() {
- @Override
- public void onDirSelected(final File dir) {
- if (!dir.canWrite()) {
- Toast.makeText(SettingsActivity2.this, R.string.dir_no_access,
- Toast.LENGTH_SHORT).show();
- return;
- }
- preference.setSummary(dir.getPath());
- preference.getEditor()
- .putString("mangadir", dir.getPath()).apply();
- checkPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE);
- }
- })
- .show();
- return true;
- case "update":
- new CheckUpdatesTask(this).attach(this).start();
- return true;
- case "sync.start":
- SyncService.start(this);
- return true;
- case "sync.username":
- new AlertDialog.Builder(this)
- .setMessage(R.string.logout_confirm)
- .setPositiveButton(R.string.logout, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- new SyncLogoutTask(SettingsActivity2.this).start();
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create().show();
- return true;
- default:
- try {
- if (preference.getKey().startsWith("sync.dev")) {
- int devId = Integer.parseInt(preference.getKey().substring(9));
- detachDevice(devId, preference);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return false;
- }
- }
-
- public void onSaveInstanceState(Bundle outState){
- if (mFragment != null) {
- outState.putString("fragment", mFragment.getClass().getName());
- }
- }
- public void onRestoreInstanceState(Bundle inState){
- String fragment = inState.getString("fragment");
- if (fragment != null) {
- try {
- Fragment f = (Fragment) Class.forName(fragment).newInstance();
- openFragment(f);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- @Override
- public boolean onPreferenceChange(Preference preference, Object o) {
- switch (preference.getKey()) {
- case "use_tor":
- if (Boolean.TRUE.equals(o)) {
- if (NetworkUtils.setUseTor(this, true)) {
- return true;
- } else {
- new AlertDialog.Builder(this)
- .setTitle(R.string.use_tor_proxy)
- .setMessage(R.string.orbot_required)
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- OrbotHelper.get(SettingsActivity2.this).installOrbot(SettingsActivity2.this);
- }
- }).create().show();
- return false;
- }
- } else if (Boolean.FALSE.equals(o)) {
- NetworkUtils.setUseTor(this, false);
- return true;
- }
- break;
- case "theme":
- mCardView.postDelayed(new Runnable() {
- @Override
- public void run() {
- recreate();
- }
- }, 100);
- return true;
- }
- return false;
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case BackupRestoreUtil.BACKUP_IMPORT_CODE:
- if (resultCode == RESULT_OK) {
- File file = AppHelper.getFileFromUri(this, data.getData());
- if (file != null) {
- new BackupRestoreUtil(this).restore(file);
- } else {
- Toast.makeText(this, R.string.error, Toast.LENGTH_SHORT).show();
- }
- }
- break;
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
-
- @Override
- public void onBackPressed() {
- if (!getFragmentManager().popBackStackImmediate()) {
- super.onBackPressed();
- }
- }
-
- @Override
- public void onBackStackChanged() {
- if (getFragmentManager().getBackStackEntryCount() == 0) {
- mFragment = null;
- AnimUtils.crossfade(mContent, mCardView);
- setTitle(R.string.action_settings);
- mAppBarLayout.setExpanded(true, true);
- } else {
- AnimUtils.crossfade(mCardView, mContent);
- mAppBarLayout.setExpanded(false, true);
- }
- }
-
- private static class CacheClearTask extends WeakAsyncTask {
-
- CacheClearTask(Preference object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull Preference preference) {
- preference.setSummary(R.string.cache_clearing);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected Void doInBackground(Void... params) {
- try {
- File dir = getObject().getContext().getExternalCacheDir();
- new DirRemoveHelper(dir).run();
- } catch (Exception ignored) {
- }
- return null;
- }
-
- @Override
- protected void onPostExecute(@NonNull Preference preference, Void aVoid) {
- preference.setSummary(String.format(preference.getContext().getString(R.string.cache_size), 0f));
- }
- }
-
- private static class CheckUpdatesTask extends WeakAsyncTask implements DialogInterface.OnCancelListener {
-
- private int mSelected = 0;
- private final ProgressDialog mDialog;
-
- CheckUpdatesTask(SettingsActivity2 activity) {
- super(activity);
- mDialog = new ProgressDialog(activity);
- mDialog.setMessage(activity.getString(R.string.checking_updates));
- mDialog.setCancelable(true);
- mDialog.setIndeterminate(true);
- mDialog.setOnCancelListener(this);
- }
-
- @Override
- protected void onPreExecute(@NonNull SettingsActivity2 activity) {
- mDialog.show();
- }
-
- @Override
- protected AppUpdatesProvider doInBackground(Void... params) {
- return new AppUpdatesProvider();
- }
-
- @Override
- protected void onCancelled() {
- super.onCancelled();
- mDialog.dismiss();
- }
-
- @Override
- protected void onPostExecute(@NonNull final SettingsActivity2 activity, AppUpdatesProvider appUpdatesProvider) {
- mDialog.dismiss();
- if (appUpdatesProvider.isSuccess()) {
- if (activity.mFragment instanceof OtherSettingsFragment) {
- Preference p = ((OtherSettingsFragment) activity.mFragment).findPreference("update");
- if (p != null) {
- p.setSummary(activity.getString(R.string.last_update_check,
- AppHelper.getReadableDateTimeRelative(System.currentTimeMillis())));
- }
- }
- new ScheduleHelper(activity).actionDone(ScheduleHelper.ACTION_CHECK_APP_UPDATES);
- final AppUpdatesProvider.AppUpdateInfo[] updates = appUpdatesProvider.getLatestUpdates();
- if (updates.length == 0) {
- new AlertDialog.Builder(activity)
- .setMessage(R.string.no_app_updates)
- .setPositiveButton(R.string.close, null)
- .create().show();
- return;
- }
- final String[] titles = new String[updates.length];
- for (int i = 0; i < titles.length; i++) {
- titles[i] = updates[i].getVersionName();
- }
- new AlertDialog.Builder(activity)
- .setTitle(R.string.update)
- .setSingleChoiceItems(titles, 0, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- mSelected = which;
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .setPositiveButton(R.string.download, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- UpdateService.start(activity, updates[mSelected].getUrl());
- }
- })
- .setCancelable(true)
- .create().show();
- } else {
- Toast.makeText(activity, R.string.error, Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- this.cancel(false);
- }
- }
-
- private void detachDevice(final int devId, final Preference p) {
- new AlertDialog.Builder(this)
- .setMessage(getString(R.string.device_detach_confirm, p.getTitle().toString()))
- .setPositiveButton(R.string.detach, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- p.setSelectable(false);
- new DeviceDetachTask(p).attach(SettingsActivity2.this).start(devId);
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create().show();
- }
-
- private static class DeviceDetachTask extends WeakAsyncTask {
-
- DeviceDetachTask(Preference preference) {
- super(preference);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected RESTResponse doInBackground(Integer... integers) {
- try {
- return SyncHelper.get(getObject().getContext()).detachDevice(integers[0]);
- } catch (Exception e) {
- e.printStackTrace();
- return RESTResponse.fromThrowable(e);
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull Preference p, RESTResponse restResponse) {
- if (restResponse.isSuccess()) {
- p.setEnabled(false);
- p.setSummary(R.string.device_detached);
- Toast.makeText(p.getContext(), R.string.device_detached, Toast.LENGTH_SHORT).show();
- } else {
- p.setSelectable(true);
- Toast.makeText(p.getContext(), restResponse.getMessage(), Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- private static class SyncLogoutTask extends ProgressAsyncTask {
-
- SyncLogoutTask(BaseAppActivity activity) {
- super(activity);
- setCancelable(false);
- }
-
- @Override
- protected RESTResponse doInBackground(Void... voids) {
- try {
- return SyncHelper.get(getActivity()).logout();
- } catch (Exception e) {
- e.printStackTrace();
- return RESTResponse.fromThrowable(e);
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull BaseAppActivity activity, RESTResponse restResponse) {
- if (restResponse.isSuccess()) {
- ((SettingsActivity2)activity).openFragment(new SyncLoginFragment());
- } else {
- Toast.makeText(activity, restResponse.getMessage(), Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- private static void openSettings(Context context, int requestCode, int section) {
- Intent intent = new Intent(context, SettingsActivity2.class);
- intent.putExtra("section", section);
- if (requestCode != 0) {
- if (context instanceof Activity) {
- ((Activity) context).startActivityForResult(intent, requestCode);
- return;
- }
- }
- context.startActivity(intent);
- }
-
- public static void openReaderSettings(Context context, int requestCode) {
- openSettings(context, requestCode, SECTION_READER);
- }
-
- public static void openProvidersSettings(Context context, int requestCode) {
- openSettings(context, requestCode, SECTION_PROVIDERS);
- }
-
- public static void openSyncSettings(Context context, int requestCode) {
- openSettings(context, requestCode, SECTION_SYNC);
- }
-
-
- public static void openChaptersCheckSettings(Context context, int requestCode) {
- openSettings(context, requestCode, SECTION_CHUPD);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsHeadersAdapter.java b/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsHeadersAdapter.java
deleted file mode 100644
index c528f674..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/SettingsHeadersAdapter.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.support.v4.content.ContextCompat;
-import android.support.v4.view.ViewCompat;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.util.ArrayList;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class SettingsHeadersAdapter extends RecyclerView.Adapter {
-
- private final ArrayList mDataset;
- private final AdapterView.OnItemClickListener mClickListener;
- private int mCurrentPosition = -1;
-
- public SettingsHeadersAdapter(ArrayList headers, AdapterView.OnItemClickListener clickListener) {
- mDataset = headers;
- mClickListener = clickListener;
- setHasStableIds(true);
- }
-
- @Override
- public PreferenceHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new PreferenceHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_pref_header, parent,false), mClickListener);
- }
-
- public void setActivatedPosition(int pos) {
- int lastPos = mCurrentPosition;
- mCurrentPosition = pos;
- if (lastPos != -1) {
- notifyItemChanged(lastPos);
- }
- if (mCurrentPosition != -1) {
- notifyItemChanged(mCurrentPosition);
- }
- }
-
- @Override
- public void onBindViewHolder(PreferenceHolder holder, int position) {
- PreferenceHeader item = mDataset.get(position);
- holder.text.setText(item.title);
- holder.icon.setImageDrawable(item.icon);
- holder.setActivated(position == mCurrentPosition);
- }
-
- @Override
- public long getItemId(int position) {
- return mDataset.get(position).title.hashCode();
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size();
- }
-
- static class PreferenceHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-
- private final ImageView icon;
- private final TextView text;
- private final AdapterView.OnItemClickListener clickListener;
-
- PreferenceHolder(View itemView, AdapterView.OnItemClickListener listener) {
- super(itemView);
- icon = itemView.findViewById(android.R.id.icon);
- text = itemView.findViewById(android.R.id.text1);
- clickListener = listener;
- itemView.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View view) {
- clickListener.onItemClick(null, itemView, getAdapterPosition(), getItemId());
- }
-
- void setActivated(boolean activated) {
- if (activated) {
- itemView.setBackgroundColor(ContextCompat.getColor(itemView.getContext(), R.color.light_gray));
- } else {
- ViewCompat.setBackground(itemView, LayoutUtils.getSelectableBackground(itemView.getContext()));
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/SyncLoginFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/SyncLoginFragment.java
deleted file mode 100644
index 67c90d3a..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/SyncLoginFragment.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Fragment;
-import android.content.DialogInterface;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.BaseAppActivity;
-import org.nv95.openmanga.helpers.SyncHelper;
-import org.nv95.openmanga.items.RESTResponse;
-import org.nv95.openmanga.services.SyncService;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.ProgressAsyncTask;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class SyncLoginFragment extends Fragment implements View.OnClickListener {
-
- private EditText mEditLogin;
- private EditText mEditPassword;
- private Button mButtonLogin;
- private Button mButtonRegister;
-
- @Nullable
- @Override
- public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
- return inflater.inflate(R.layout.fragment_syncauth, container, false);
- }
-
- @Override
- public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- mEditLogin = view.findViewById(R.id.editLogin);
- mEditPassword = view.findViewById(R.id.editPassword);
- mButtonLogin = view.findViewById(R.id.buttonLogin);
- mButtonRegister = view.findViewById(R.id.buttonRegister);
- mButtonRegister.setOnClickListener(this);
- mButtonLogin.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View view) {
- final String login = mEditLogin.getText().toString().trim();
- final String password = mEditPassword.getText().toString().trim();
- if (login.isEmpty()) {
- LayoutUtils.showSoftKeyboard(mEditLogin);
- return;
- }
- if (password.isEmpty()) {
- LayoutUtils.showSoftKeyboard(mEditPassword);
- return;
- }
- LayoutUtils.hideSoftKeyboard(mEditPassword);
- new AuthTask((SettingsActivity2) getActivity(), view.getId() == R.id.buttonRegister)
- .executeOnExecutor(
- AsyncTask.THREAD_POOL_EXECUTOR,
- login,
- password
- );
- }
-
-
- private static class AuthTask extends ProgressAsyncTask implements DialogInterface.OnCancelListener {
-
-
- private final boolean mRegister;
-
- AuthTask(SettingsActivity2 activity, boolean isRegister) {
- super(activity);
- mRegister = isRegister;
- }
-
-
- @Override
- protected RESTResponse doInBackground(String... strings) {
- try {
- SyncHelper syncHelper = SyncHelper.get(getActivity());
- if (mRegister) {
- return syncHelper.register(strings[0], strings[1]);
- } else {
- return syncHelper.authorize(strings[0], strings[1]);
- }
- } catch (Exception e) {
- e.printStackTrace();
- return RESTResponse.fromThrowable(e);
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull BaseAppActivity activity, RESTResponse restResponse) {
- if (restResponse.isSuccess()) {
- Toast.makeText(activity, R.string.successfully, Toast.LENGTH_SHORT).show();
- ((SettingsActivity2)activity).openFragment(new SyncSettingsFragment());
- SyncService.start(activity);
- } else {
- new AlertDialog.Builder(activity)
- .setTitle(R.string.auth_failed)
- .setMessage(restResponse.getMessage())
- .setPositiveButton(android.R.string.ok, null)
- .create().show();
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/SyncSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/SyncSettingsFragment.java
deleted file mode 100644
index da17aacc..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/SyncSettingsFragment.java
+++ /dev/null
@@ -1,182 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.app.Activity;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.PreferenceCategory;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceScreen;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.design.widget.Snackbar;
-import android.view.View;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.BaseAppActivity;
-import org.nv95.openmanga.helpers.SyncHelper;
-import org.nv95.openmanga.items.SyncDevice;
-import org.nv95.openmanga.services.SyncService;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.NetworkUtils;
-import org.nv95.openmanga.utils.PreferencesUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.util.ArrayList;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-public class SyncSettingsFragment extends PreferenceFragment {
-
- private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int what = intent.getIntExtra("what", -1);
- Preference p;
- switch (what) {
- case SyncService.MSG_UNAUTHORIZED:
- Activity activity = getActivity();
- if (activity != null && activity instanceof SettingsActivity2) {
- Toast.makeText(activity, R.string.auth_failed, Toast.LENGTH_SHORT).show();
- ((SettingsActivity2) activity).openFragment(new SyncLoginFragment());
- }
- break;
- case SyncService.MSG_HIST_STARTED:
- p = findPreference("sync.history");
- p.setSummary(R.string.sync_started);
- p.setEnabled(false);
- break;
- case SyncService.MSG_HIST_FAILED:
- p = findPreference("sync.history");
- p.setSummary(R.string.sync_failed);
- p.setEnabled(true);
- break;
- case SyncService.MSG_HIST_FINISHED:
- p = findPreference("sync.history");
- p.setSummary(R.string.sync_finished);
- p.setEnabled(true);
- break;
- case SyncService.MSG_FAV_STARTED:
- p = findPreference("sync.favourites");
- p.setSummary(R.string.sync_started);
- p.setEnabled(false);
- break;
- case SyncService.MSG_FAV_FAILED:
- p = findPreference("sync.favourites");
- p.setSummary(R.string.sync_failed);
- p.setEnabled(true);
- break;
- case SyncService.MSG_FAV_FINISHED:
- p = findPreference("sync.favourites");
- p.setSummary(R.string.sync_finished);
- p.setEnabled(true);
- break;
- }
- }
- };
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_sync);
- }
-
- @Override
- public void onActivityCreated(@Nullable Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- Context context = getActivity();
- SyncHelper syncHelper = SyncHelper.get(context);
- Preference p = findPreference("sync.start");
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) context);
-
- p = findPreference("sync.history");
- long lastSync = syncHelper.getLastHistorySync();
- p.setSummary(context.getString(R.string.last_sync, lastSync == 0 ? context.getString(R.string.unknown) : AppHelper.getReadableDateTimeRelative(lastSync)));
-
- p = findPreference("sync.favourites");
- lastSync = syncHelper.getLastFavouritesSync();
- p.setSummary(context.getString(R.string.last_sync, lastSync == 0 ? context.getString(R.string.unknown) : AppHelper.getReadableDateTimeRelative(lastSync)));
-
- PreferencesUtils.bindPreferenceSummary(findPreference("sync.interval"));
-
- p = findPreference("sync.username");
- PreferencesUtils.bindPreferenceSummary(p);
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) context);
-
- if (NetworkUtils.checkConnection(context)) {
- new LoadDevicesTask(this)
- .attach((BaseAppActivity) context)
- .start();
- }
- }
-
- @Override
- public void onStart() {
- super.onStart();
- Activity activity = getActivity();
- activity.registerReceiver(mEventReceiver, new IntentFilter(SyncService.SYNC_EVENT));
- }
-
- @Override
- public void onStop() {
- Activity activity = getActivity();
- activity.unregisterReceiver(mEventReceiver);
- super.onStop();
- }
-
- private static class LoadDevicesTask extends WeakAsyncTask> {
-
-
- LoadDevicesTask(SyncSettingsFragment syncSettingsFragment) {
- super(syncSettingsFragment);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected ArrayList doInBackground(Void... voids) {
- try {
- return SyncHelper.get(getObject().getActivity())
- .getUserDevices(false);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull SyncSettingsFragment f, ArrayList devices) {
- if (devices == null) {
- View v = f.getView();
- if (v != null) {
- Snackbar.make(v, R.string.server_inaccessible, Snackbar.LENGTH_INDEFINITE).show();
- } else {
- Toast.makeText(f.getActivity(), R.string.server_inaccessible, Toast.LENGTH_LONG).show();
- }
- } else {
- Context c = f.getActivity();
- PreferenceScreen ps = f.getPreferenceScreen();
- PreferenceCategory cat = new PreferenceCategory(c);
- cat.setTitle(c.getString(R.string.sync_devices, devices.size()));
- ps.addPreference(cat);
- for (SyncDevice o : devices) {
- Preference p = new Preference(c);
- p.setTitle(o.name);
- p.setSummary(AppHelper.getReadableDateTime(c, o.created_at));
- p.setKey("sync.dev." + o.id);
- if (c instanceof Preference.OnPreferenceClickListener) {
- p.setOnPreferenceClickListener((Preference.OnPreferenceClickListener) c);
- } else {
- p.setSelectable(false);
- }
- cat.addPreference(p);
- }
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/activities/settings/UpdatesCheckSettingsFragment.java b/app/src/main/java/org/nv95/openmanga/activities/settings/UpdatesCheckSettingsFragment.java
deleted file mode 100644
index ea9558cb..00000000
--- a/app/src/main/java/org/nv95/openmanga/activities/settings/UpdatesCheckSettingsFragment.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.nv95.openmanga.activities.settings;
-
-import android.os.Bundle;
-import android.preference.PreferenceFragment;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.PreferencesUtils;
-
-/**
- * Created by admin on 25.07.17.
- */
-
-public class UpdatesCheckSettingsFragment extends PreferenceFragment {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- addPreferencesFromResource(R.xml.pref_chupd);
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- PreferencesUtils.bindPreferenceSummary(findPreference("chupd.interval"));
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/BookmarksAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/BookmarksAdapter.java
deleted file mode 100644
index e09328ca..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/BookmarksAdapter.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.annotation.SuppressLint;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.Bookmark;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.ImageUtils;
-
-import java.util.List;
-
-/**
- * Created by unravel22 on 18.02.17.
- */
-
-public class BookmarksAdapter extends RecyclerView.Adapter implements View.OnClickListener {
-
- private final List mBookmarks;
- @Nullable
- private final OnBookmarkClickListener mClickListener;
-
- public BookmarksAdapter(List list, @Nullable OnBookmarkClickListener clickListener) {
- mBookmarks = list;
- mClickListener = clickListener;
- }
-
- @Override
- public BookmarkHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- BookmarkHolder holder = new BookmarkHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bookmark, parent, false));
- holder.itemView.setOnClickListener(this);
- return holder;
- }
-
- @SuppressLint("SetTextI18n")
- @Override
- public void onBindViewHolder(BookmarkHolder holder, int position) {
- Bookmark o = mBookmarks.get(position);
- ImageUtils.setThumbnail(holder.imageView, "file://" + o.thumbnailFile);
- holder.textView1.setText(o.name + "\n" + holder.imageView.getContext().getString(R.string.bookmark_pos, o.chapter, o.page));
- holder.textView2.setText(AppHelper.getReadableDateTimeRelative(o.datetime));
- holder.itemView.setTag(o);
- }
-
- @Override
- public int getItemCount() {
- return mBookmarks.size();
- }
-
- @Override
- public void onClick(View v) {
- Object tag = v.getTag();
- if (mClickListener != null && tag instanceof Bookmark) {
- mClickListener.onBookmarkSelected((Bookmark) tag);
- }
- }
-
- static class BookmarkHolder extends RecyclerView.ViewHolder {
-
- final ImageView imageView;
- final TextView textView1;
- final TextView textView2;
-
- BookmarkHolder(View itemView) {
- super(itemView);
- imageView = itemView.findViewById(R.id.imageView);
- textView1 = itemView.findViewById(R.id.textView_title);
- textView2 = itemView.findViewById(R.id.textView_subtitle);
- }
- }
-
- public interface OnBookmarkClickListener {
- void onBookmarkSelected(Bookmark bookmark);
- }
-}
-
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/ChaptersAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/ChaptersAdapter.java
deleted file mode 100644
index 07df2272..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/ChaptersAdapter.java
+++ /dev/null
@@ -1,196 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.Context;
-import android.graphics.Typeface;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.MangaChapter;
-import org.nv95.openmanga.lists.ChaptersList;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Created by unravel22 on 18.02.17.
- */
-
-public class ChaptersAdapter extends RecyclerView.Adapter implements OnChapterClickListener {
-
- private final int ITEM_DEFAULT = 0;
- private final int ITEM_HEADER = 1;
-
- private final ChaptersList mDataset;
- private int mLastNumber = 2;
- private long mLastTime = 0;
- @Nullable
- private OnChapterClickListener mClickListener;
- private final int[] mColors;
- private boolean mReversed = false;
-
- public ChaptersAdapter(Context context) {
- mClickListener = null;
- mLastNumber = -1;
- mDataset = new ChaptersList();
- mColors = new int[] {
- LayoutUtils.getAttrColor(context, android.R.attr.textColorPrimary),
- LayoutUtils.getAttrColor(context, android.R.attr.textColorSecondary)
- };
- setHasStableIds(true);
- }
-
- public void setOnItemClickListener(@Nullable OnChapterClickListener listener) {
- mClickListener = listener;
- }
-
- public void setExtra(@Nullable HistoryProvider.HistorySummary hs) {
- mLastNumber = hs != null ? hs.getChapter() : -1;
- mLastTime = hs != null ? hs.getTime() : 0;
- }
-
- public void setData(List chapters) {
- mDataset.clear();
- mDataset.addAll(chapters);
- }
-
- public void reverse() {
- Collections.reverse(mDataset);
- notifyDataSetChanged();
- mReversed = !mReversed;
- }
-
- public boolean isReversed() {
- return mReversed;
- }
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if (viewType == ITEM_HEADER) {
- return new HeaderHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.header_chapter, parent, false), this);
- } else {
- return new ChapterHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_chapter, parent, false), this);
- }
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- if (holder instanceof ChapterHolder) {
- MangaChapter ch = mDataset.get(position - (mLastNumber >= 0 ? 1 : 0));
- TextView tv = ((ChapterHolder) holder).getTextView();
- tv.setText(ch.name);
- tv.setTextColor(ch.number >= mLastNumber ? mColors[0] : mColors[1]);
- tv.setTypeface(ch.number == mLastNumber ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT);
- } else if (holder instanceof HeaderHolder) {
- MangaChapter ch = mDataset.getByNumber(mLastNumber);
- if (ch != null) {
- ((HeaderHolder) holder).textViewTitle.setText(ch.name);
- ((HeaderHolder) holder).textViewSubtitle.setText(AppHelper.getReadableDateTimeRelative(mLastTime));
- }
- }
- }
-
- @Override
- public int getItemViewType(int position) {
- return (position == 0 && mLastNumber >= 0) ? ITEM_HEADER : ITEM_DEFAULT;
- }
-
- @Override
- public long getItemId(int position) {
- if (mLastNumber >= 0) {
- return position == 0 ? 0 : mDataset.get(position - 1).id();
- } else {
- return mDataset.get(position).id();
- }
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size() + (mLastNumber >= 0 ? 1 : 0);
- }
-
- @Override
- public void onChapterClick(int pos, MangaChapter chapter) {
- if (mClickListener != null) {
- if (mLastNumber < 0) {
- mClickListener.onChapterClick(pos, mDataset.get(pos));
- } else {
- if (pos == -1) {
- mClickListener.onChapterClick(-1, null);
- } else {
- mClickListener.onChapterClick(pos - 1, mDataset.get(pos - 1));
- }
- }
- }
- }
-
- @Override
- public boolean onChapterLongClick(int pos, MangaChapter chapter) {
- if (mClickListener != null) {
- if (mLastNumber < 0) {
- return mClickListener.onChapterLongClick(pos, mDataset.get(pos));
- } else {
- if (pos == -1) {
- return mClickListener.onChapterLongClick(-1, null);
- } else {
- return mClickListener.onChapterLongClick(pos - 1, mDataset.get(pos - 1));
- }
- }
- }
- return false;
- }
-
- static class HeaderHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-
- private final OnChapterClickListener mListener;
- final TextView textViewTitle;
- final TextView textViewSubtitle;
-
- HeaderHolder(View itemView, OnChapterClickListener listener) {
- super(itemView);
- itemView.findViewById(R.id.button_positive).setOnClickListener(this);
- mListener = listener;
- textViewTitle = itemView.findViewById(R.id.textView_title);
- textViewSubtitle = itemView.findViewById(R.id.textView_subtitle);
- }
-
- @Override
- public void onClick(View v) {
- mListener.onChapterClick(-1, null);
- }
- }
-
- static class ChapterHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
-
- private final OnChapterClickListener mListener;
-
- ChapterHolder(View itemView, OnChapterClickListener listener) {
- super(itemView);
- itemView.setOnClickListener(this);
- itemView.setOnLongClickListener(this);
- mListener = listener;
- }
-
- public TextView getTextView() {
- return (TextView) itemView;
- }
-
- @Override
- public void onClick(View v) {
- mListener.onChapterClick(getAdapterPosition(), null);
- }
-
- @Override
- public boolean onLongClick(View view) {
- return mListener.onChapterLongClick(getAdapterPosition(), null);
- }
- }
-}
-
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/DirAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/DirAdapter.java
deleted file mode 100644
index 9e3128f7..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/DirAdapter.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 01.01.16.
- */
-public class DirAdapter extends BaseAdapter {
-
- private final Context mContext;
- private final ArrayList mFiles;
- private File mCurrentDir;
- private final Drawable[] mIcons;
-
- public DirAdapter(Context context, File dir) {
- mContext = context;
- mFiles = new ArrayList<>();
- mIcons = LayoutUtils.getThemedIcons(
- context,
- R.drawable.ic_directory_dark,
- R.drawable.ic_directory_null_dark
- );
- setCurrentDir(dir);
- }
-
- @NonNull
- public File getCurrentDir() {
- return mCurrentDir;
- }
-
- public void setCurrentDir(@NonNull File dir) {
- mCurrentDir = dir;
- mFiles.clear();
- File[] list = dir.listFiles();
- if (list != null) {
- for (File o : list) {
- if (o.isDirectory()) {
- mFiles.add(o);
- }
- }
- }
- }
-
- @Override
- public int getCount() {
- return mFiles.size();
- }
-
- @Override
- public File getItem(int position) {
- return mFiles.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return mFiles.get(position).hashCode();
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView textView = (TextView) (convertView == null ? View.inflate(mContext, R.layout.item_dir, null) : convertView);
- File f = getItem(position);
- textView.setText(f.getName());
- textView.setCompoundDrawablesWithIntrinsicBounds(f.canWrite() ? mIcons[0]: mIcons[1], null, null, null);
- return textView;
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/DownloadsAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/DownloadsAdapter.java
deleted file mode 100644
index c7a41278..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/DownloadsAdapter.java
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright (C) 2016 Vasily Nikitin
- *
- * This program is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation,
- * either version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with this program.
- * If not, see http://www.gnu.org/licenses/.
- */
-
-package org.nv95.openmanga.adapters;
-
-import android.annotation.SuppressLint;
-import android.content.ComponentName;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.graphics.drawable.Drawable;
-import android.os.IBinder;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.DownloadInfo;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.services.SaveService;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.PausableAsyncTask.ExStatus;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 03.01.16.
- */
-public class DownloadsAdapter extends RecyclerView.Adapter
- implements ServiceConnection, SaveService.OnSaveProgressListener, View.OnClickListener {
-
- private final Intent mIntent;
- @Nullable
- private SaveService.SaveServiceBinder mBinder;
- private final RecyclerView mRecyclerView;
- private final ArrayList mItemsIds;
- private final Drawable[] mIcons;
-
- public DownloadsAdapter(RecyclerView recyclerView) {
- mItemsIds = new ArrayList<>();
- mIntent = new Intent(recyclerView.getContext(), SaveService.class);
- mBinder = null;
- mRecyclerView = recyclerView;
- mIcons = LayoutUtils.getThemedIcons(recyclerView.getContext(), R.drawable.ic_resume_darker, R.drawable.ic_pause_darker, R.drawable.ic_cancel_darker);
- setHasStableIds(true);
- }
-
- public void enable() {
- mRecyclerView.getContext().bindService(mIntent, this, 0);
- }
-
- public void disable() {
- if (mBinder != null) {
- mBinder.removeListener(this);
- }
- mRecyclerView.getContext().unbindService(this);
- }
-
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- mBinder = (SaveService.SaveServiceBinder) service;
- mItemsIds.clear();
- mItemsIds.addAll(mBinder.getAllIds());
- mBinder.addListener(this);
- notifyDataSetChanged();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mBinder = null;
- notifyDataSetChanged();
- }
-
- @Override
- public DownloadHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- DownloadHolder holder = new DownloadHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_download, parent, false));
- holder.imageRemove.setOnClickListener(this);
- holder.imageRemove.setImageDrawable(mIcons[2]);
- holder.imageRemove.setTag(holder);
- holder.imagePause.setOnClickListener(this);
- holder.imagePause.setImageDrawable(mIcons[1]);
- holder.imagePause.setTag(holder);
- holder.imageResume.setOnClickListener(this);
- holder.imageResume.setImageDrawable(mIcons[0]);
- holder.imageResume.setTag(holder);
- return holder;
- }
-
- @Override
- public void onBindViewHolder(DownloadHolder holder, int position) {
- if (mBinder != null) {
- int id = (int) getItemId(position);
- holder.fill(mBinder.getItemById(id), mBinder.getTaskStatus(id));
- }
- }
-
- @Override
- public int getItemCount() {
- return mBinder != null ? mBinder.getTaskCount() : 0;
- }
-
- @Override
- public long getItemId(int position) {
- if (mItemsIds.size() < position + 1) {
- mItemsIds.clear();
- mItemsIds.addAll(mBinder.getAllIds());
- }
- return mItemsIds.get(position);
- }
-
- @Override
- public void onProgressUpdated(int id) {
- int position = mItemsIds.indexOf(id);
- RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
- if (mBinder != null && holder != null && holder instanceof DownloadHolder) {
- DownloadInfo item = mBinder.getItemById(id);
- if (item.pos < item.max) {
- ((DownloadHolder) holder).updateProgress(
- item.pos * 100 + item.getChapterProgressPercent(),
- item.max * 100,
- item.chaptersProgresses[item.pos],
- item.chaptersSizes[item.pos],
- item.chapters.get(item.pos).name
- );
- } else {
- notifyItemChanged(position);
- }
- }
- }
-
- @Override
- public void onDataUpdated(int id) {
- /*int pos = mItemsIds.indexOf(id);
- if (pos >= 0) {
- notifyItemChanged(pos);
- } else {
- onDataUpdated();
- }*/
- onDataUpdated();
- }
-
- @Override
- public void onDataUpdated() {
- mItemsIds.clear();
- mItemsIds.addAll(mBinder.getAllIds());
- notifyDataSetChanged();
- }
-
- public void setTaskPaused(boolean paused) {
- if (mBinder != null) {
- if (paused) {
- mBinder.pauseAll();
- } else {
- mBinder.resumeAll();
- }
- }
- }
-
- @Override
- public void onClick(View view) {
- if (mBinder == null) return;
- Object tag = view.getTag();
- if (tag != null && tag instanceof DownloadHolder) {
- DownloadHolder holder = (DownloadHolder) tag;
- final int pos = holder.getAdapterPosition();
- switch (view.getId()) {
- case R.id.buttonRemove:
- new AlertDialog.Builder(view.getContext())
- .setMessage(view.getContext().getString(R.string.download_unqueue_confirm, holder.mTextViewTitle.getText()))
- .setPositiveButton(R.string.action_remove, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- if (mBinder != null) {
- mBinder.cancelAndRemove((int) getItemId(pos));
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create()
- .show();
- break;
- case R.id.buttonPause:
- mBinder.setPaused((int) getItemId(pos), true);
- notifyItemChanged(pos);
- break;
- case R.id.buttonResume:
- mBinder.setPaused((int) getItemId(pos), false);
- notifyItemChanged(pos);
- break;
- }
- }
- }
-
- static class DownloadHolder extends RecyclerView.ViewHolder {
-
- private final ImageView mImageView;
- private final TextView mTextViewTitle;
- private final TextView mTextViewSubtitle;
- private final TextView mTextViewState;
- private final TextView mTextViewPercent;
- private final ProgressBar mProgressBarPrimary;
- private final ProgressBar mProgressBarSecondary;
- final ImageView imageRemove;
- final ImageView imagePause;
- final ImageView imageResume;
-
- DownloadHolder(View itemView) {
- super(itemView);
- mImageView = itemView.findViewById(R.id.imageView);
- mTextViewTitle = itemView.findViewById(R.id.textView_title);
- mTextViewSubtitle = itemView.findViewById(R.id.textView_subtitle);
- mTextViewState = itemView.findViewById(R.id.textView_state);
- mProgressBarPrimary = itemView.findViewById(R.id.progressBar_primary);
- mProgressBarSecondary = itemView.findViewById(R.id.progressBar_secondary);
- mTextViewPercent = itemView.findViewById(R.id.textView_percent);
- imageRemove = itemView.findViewById(R.id.buttonRemove);
- imagePause = itemView.findViewById(R.id.buttonPause);
- imageResume = itemView.findViewById(R.id.buttonResume);
- }
-
- @SuppressLint("SetTextI18n")
- public void fill(DownloadInfo data, ExStatus status) {
- mTextViewTitle.setText(data.name);
- ImageUtils.setThumbnail(mImageView, data.preview, ThumbSize.THUMB_SIZE_LIST);
- switch (status) {
- case PENDING:
- mTextViewState.setText(R.string.queue);
- imagePause.setVisibility(View.GONE);
- imageResume.setVisibility(View.GONE);
- imageRemove.setVisibility(View.VISIBLE);
- break;
- case FINISHED:
- mTextViewState.setText(R.string.completed);
- imagePause.setVisibility(View.GONE);
- imageResume.setVisibility(View.GONE);
- imageRemove.setVisibility(View.GONE);
- break;
- case RUNNING:
- mTextViewState.setText(R.string.saving_manga);
- imagePause.setVisibility(View.VISIBLE);
- imageResume.setVisibility(View.GONE);
- imageRemove.setVisibility(View.VISIBLE);
- break;
- case PAUSED:
- mTextViewState.setText(R.string.paused);
- imagePause.setVisibility(View.GONE);
- imageResume.setVisibility(View.VISIBLE);
- imageRemove.setVisibility(View.VISIBLE);
- break;
- }
- if (data.pos < data.max) {
- updateProgress(data.pos, data.max, data.chaptersProgresses[data.pos], data.chaptersSizes[data.pos],
- data.chapters.get(data.pos).name);
- } else {
- mProgressBarPrimary.setProgress(mProgressBarPrimary.getMax());
- mProgressBarSecondary.setProgress(mProgressBarSecondary.getMax());
- mTextViewPercent.setText("100%");
- mTextViewSubtitle.setText(itemView.getContext().getString(R.string.chapters_total, data.max));
- }
- }
-
- /**
- *
- * @param tPos current chapter
- * @param tMax chapters count
- * @param cPos current page
- * @param cMax pages count
- * @param subtitle chapter name
- */
- @SuppressLint("SetTextI18n")
- void updateProgress(int tPos, int tMax, int cPos, int cMax, String subtitle) {
- mProgressBarPrimary.setMax(tMax);
- mProgressBarPrimary.setProgress(tPos);
- mProgressBarSecondary.setMax(cMax);
- mProgressBarSecondary.setProgress(cPos);
- mTextViewSubtitle.setText(subtitle);
- mTextViewPercent.setText((tMax == 0 ? 0 : tPos * 100 / tMax) + "%");
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/EndlessAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/EndlessAdapter.java
deleted file mode 100644
index 94b454c8..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/EndlessAdapter.java
+++ /dev/null
@@ -1,135 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ProgressBar;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.lists.PagedList;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-/**
- * Created by nv95 on 25.01.16.
- */
-public abstract class EndlessAdapter extends RecyclerView.Adapter {
-
- public static final int VIEW_ITEM = 1;
- private static final int VIEW_PROGRESS = 0;
-
- private final PagedList mDataset;
- private final int mVisibleThreshold = 2;
- private int mLastVisibleItem, mTotalItemCount;
- private boolean mLoading;
- private OnLoadMoreListener mOnLoadMoreListener;
-
- public EndlessAdapter(PagedList dataset, RecyclerView recyclerView) {
- mDataset = dataset;
- attach(recyclerView);
- }
-
- public void attach(RecyclerView recyclerView) {
- recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- super.onScrolled(recyclerView, dx, dy);
- mTotalItemCount = LayoutUtils.getItemCount(recyclerView);
- mLastVisibleItem = LayoutUtils.findLastVisibleItemPosition(recyclerView);
- if (!mLoading && isLoadEnabled() && mTotalItemCount <= (mLastVisibleItem + mVisibleThreshold)) {
- // End has been reached
- // Do something
- if (mOnLoadMoreListener != null) {
- mOnLoadMoreListener.onLoadMore();
- mLoading = true;
- }
- }
- }
- });
- }
-
- @Override
- public int getItemViewType(int position) {
- return getItem(position) != null ? VIEW_ITEM : VIEW_PROGRESS;
- }
-
- @Override
- public long getItemId(int position) {
- if (position == mDataset.size()) {
- return 0;
- } else {
- return getItemId(mDataset.get(position));
- }
- }
-
- @Override
- public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if (viewType == VIEW_ITEM) {
- return onCreateHolder(parent);
- } else {
- return new ProgressViewHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.footer_loading, parent, false));
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- T item = getItem(position);
- if (item != null) {
- onBindHolder((VH) holder, item, position);
- } else if (holder instanceof ProgressViewHolder) {
- ((ProgressViewHolder) holder).setVisible(isLoadEnabled());
- }
- }
-
- public void setLoaded() {
- mLoading = false;
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size() + 1;
- }
-
- @Nullable
- public T getItem(int position) {
- if (position == mDataset.size()) {
- return null;
- } else {
- return mDataset.get(position);
- }
- }
-
- public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
- mOnLoadMoreListener = onLoadMoreListener;
- }
-
- private boolean isLoadEnabled() {
- return mDataset.size() != 0 && mDataset.isHasNext();
- }
-
- public abstract VH onCreateHolder(ViewGroup parent);
-
- public abstract void onBindHolder(VH viewHolder, T data, int position);
-
- public abstract long getItemId(T data);
-
- public interface OnLoadMoreListener {
- void onLoadMore();
- }
-
- private static class ProgressViewHolder extends RecyclerView.ViewHolder {
- private final ProgressBar mProgressBar;
-
- ProgressViewHolder(View v) {
- super(v);
- mProgressBar = v.findViewById(R.id.progressBar);
- }
-
- public void setVisible(boolean visible) {
- mProgressBar.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/FastHistoryAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/FastHistoryAdapter.java
deleted file mode 100644
index c740ffa8..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/FastHistoryAdapter.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.HistoryMangaInfo;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.utils.AppHelper;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.choicecontrol.OnHolderClickListener;
-
-/**
- * Created by admin on 19.07.17.
- */
-
-public class FastHistoryAdapter extends RecyclerView.Adapter implements View.OnClickListener {
-
- private final MangaList mDataset;
- private final OnHolderClickListener mClickListener;
-
- public FastHistoryAdapter(MangaList dataset, OnHolderClickListener clickListener) {
- mDataset = dataset;
- mClickListener = clickListener;
- }
-
- @Override
- public FastHistoryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- FastHistoryHolder holder = new FastHistoryHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_history, parent, false));
- holder.contentLayout.setOnClickListener(this);
- holder.contentLayout.setTag(holder);
- return holder;
- }
-
- @Override
- public void onBindViewHolder(FastHistoryHolder holder, int position) {
- MangaInfo manga = mDataset.get(position);
- holder.textViewTitle.setText(manga.name);
- if (manga instanceof HistoryMangaInfo) {
- holder.textViewSubtitle.setText(AppHelper.getReadableDateTimeRelative(((HistoryMangaInfo) manga).timestamp));
- } else {
- holder.textViewSubtitle.setText(manga.subtitle);
- }
- ImageUtils.setThumbnail(holder.imageView, manga.preview);
-
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size();
- }
-
- @Override
- public void onClick(View view) {
- FastHistoryHolder holder = (FastHistoryHolder) view.getTag();
- mClickListener.onClick(holder);
- }
-
- public MangaInfo getItem(int position) {
- return mDataset.get(position);
- }
-
- static class FastHistoryHolder extends RecyclerView.ViewHolder {
-
- final RelativeLayout contentLayout;
- final ImageView imageView;
- final TextView textViewTitle;
- final TextView textViewSubtitle;
-
- FastHistoryHolder(View itemView) {
- super(itemView);
- contentLayout = itemView.findViewById(R.id.content);
- imageView = itemView.findViewById(R.id.imageView);
- textViewTitle = itemView.findViewById(R.id.textView_title);
- textViewSubtitle = itemView.findViewById(R.id.textView_subtitle);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/FileHolderCallback.java b/app/src/main/java/org/nv95/openmanga/adapters/FileHolderCallback.java
deleted file mode 100644
index 32b9069f..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/FileHolderCallback.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-/**
- * Created by nv95 on 09.02.16.
- */
-public interface FileHolderCallback {
- void onItemClick(FileSelectAdapter.FileViewHolder holder);
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/FileSelectAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/FileSelectAdapter.java
deleted file mode 100644
index 2d09200f..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/FileSelectAdapter.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.graphics.drawable.Drawable;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.dialogs.DirSelectDialog;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-/**
- * Created by nv95 on 09.02.16.
- */
-public class FileSelectAdapter extends RecyclerView.Adapter
- implements FileHolderCallback{
-
- private String[] mPattern;
- private final DirSelectDialog.OnDirSelectListener mCallback;
- private File mCurrentDir;
- private final ArrayList files;
-
- public FileSelectAdapter(File currentDir, @Nullable String pattern,
- DirSelectDialog.OnDirSelectListener callback) {
- files = new ArrayList<>();
- mCallback = callback;
- mPattern = pattern == null ? null : pattern.split(";");
- setCurrentDir(currentDir);
- }
-
- @NonNull
- public File getCurrentDir() {
- return mCurrentDir;
- }
-
- public void setCurrentDir(@NonNull File dir) {
- mCurrentDir = dir;
- files.clear();
- File[] list = dir.listFiles();
- for (File o : list) {
- if (o.isDirectory() || checkPattern(o.getName())) {
- files.add(o);
- }
- }
- Collections.sort(files, new FileSortComparator());
- files.add(0, new File(dir, ".."));
- notifyDataSetChanged();
- }
-
- private boolean checkPattern(String name) {
- if (mPattern == null) {
- return true;
- }
- String ext = name.substring(name.lastIndexOf('.') + 1);
- for (String o : mPattern) {
- if (ext.equalsIgnoreCase(o)) {
- return true;
- }
- }
- return false;
- }
-
- public boolean toParentDir() {
- File parentDir = mCurrentDir.getParentFile();
- if (parentDir == null || !parentDir.canRead()) {
- return false;
- }
- files.clear();
- File[] list = parentDir.listFiles();
- for (File o : list) {
- if (o.isDirectory() || checkPattern(o.getName())) {
- files.add(o);
- }
- }
- Collections.sort(files, new FileSortComparator());
- files.add(0, new File(parentDir, ".."));
- int position = files.indexOf(mCurrentDir);
- mCurrentDir = parentDir;
- notifyDataSetChanged();
- return true;
- }
-
- public boolean setDirectory(File directory) {
- if (!directory.canRead()) {
- return false;
- }
- int position = files.indexOf(directory);
- if (position == -1) {
- setCurrentDir(directory);
- return true;
- }
- if (directory.getName().equals("..")) {
- return toParentDir();
- }
- files.clear();
- File[] list = directory.listFiles();
- for (File o : list) {
- if (o.isDirectory() || checkPattern(o.getName())) {
- files.add(o);
- }
- }
- Collections.sort(files, new FileSortComparator());
- files.add(0, new File(directory, ".."));
- mCurrentDir = directory;
- notifyDataSetChanged();
- return true;
- }
-
- @Override
- public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new FileViewHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_dir, parent, false), this);
- }
-
- @Override
- public void onBindViewHolder(FileViewHolder holder, int position) {
- holder.fill(files.get(position));
- }
-
- @Override
- public int getItemCount() {
- return files.size();
- }
-
- @Override
- public void onItemClick(FileViewHolder holder) {
- mCallback.onDirSelected(holder.mFile);
- }
-
- static class FileViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
- private static Drawable[] icons = null;
- private File mFile;
- private final TextView mTextView;
- private final FileHolderCallback mCallback;
-
- public FileViewHolder(View itemView, FileHolderCallback callback) {
- super(itemView);
- mCallback = callback;
- mTextView = (TextView) itemView;
- itemView.setOnClickListener(this);
- if (icons == null) {
- icons = LayoutUtils.getThemedIcons(
- mTextView.getContext(),
- R.drawable.ic_arrow_up,
- R.drawable.ic_directory_dark,
- R.drawable.ic_directory_null_dark,
- R.drawable.ic_file_dark
- );
- }
- }
-
- protected void fill(File file) {
- mFile = file;
- mTextView.setText(file.getName());
- int icon;
- if ("..".endsWith(file.getName())) {
- icon = 0;
- } else if (file.isDirectory()) {
- icon = file.canRead() ? 1 : 2;
- } else {
- icon = 3;
- }
- mTextView.setCompoundDrawablesWithIntrinsicBounds(icons[icon], null, null, null);
- }
-
- @Override
- public void onClick(View v) {
- mCallback.onItemClick(this);
- }
- }
-
- private class FileSortComparator implements Comparator {
-
- @Override
- public int compare(File lhs, File rhs) {
- if (lhs.isDirectory())
- return rhs.isDirectory() ? lhs.compareTo(rhs) : -1;
- else if (rhs.isDirectory())
- return 1;
- return lhs.compareTo(rhs);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/GenresSortAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/GenresSortAdapter.java
deleted file mode 100644
index 0a320958..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/GenresSortAdapter.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.Context;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Checkable;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.providers.FavouritesProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 28.11.16.
- */
-
-public class GenresSortAdapter extends RecyclerView.Adapter implements View.OnClickListener {
-
- private static final int TYPE_HEADER = 0;
- private static final int TYPE_SORT = 1;
- private static final int TYPE_GENRE = 2;
-
- private final ArrayList mDataset;
- private final Callback mCallback;
- private int mSelGenre, mSelSort;
-
- public GenresSortAdapter(Callback callback) {
- mDataset = new ArrayList<>();
- mCallback = callback;
- mSelGenre = 0;
- mSelSort = 0;
- }
-
- public void fromProvider(Context context, MangaProvider provider) {
- String[] data;
- mDataset.clear();
- if (provider.hasSort()) {
- data = provider.getSortTitles(context);
- if (data != null) {
- mDataset.add(new TypedString(context.getString(R.string.action_sort), TYPE_HEADER));
- for (int i = 0; i < data.length; i++) {
- mDataset.add(new TypedString(data[i], TYPE_SORT, i));
- }
- }
- mSelSort = MangaProviderManager.restoreSortOrder(context, provider);
- } else {
- mSelSort = 0;
- }
- if (provider.hasGenres()) {
- data = provider.getGenresTitles(context);
- if (data != null) {
- mDataset.add(new TypedString(context.getString(
- provider instanceof FavouritesProvider
- ? R.string.action_category : R.string.action_genre
- ), TYPE_HEADER));
- for (int i = 0; i < data.length; i++) {
- mDataset.add(new TypedString(data[i], TYPE_GENRE, i));
- }
- }
- }
- mSelGenre = 0;
- if (mDataset.size() == 0) {
- mDataset.add(new TypedString(context.getString(R.string.no_options_available), TYPE_HEADER));
- }
- notifyDataSetChanged();
- }
-
- public int getSelectedGenre() {
- return mSelGenre;
- }
-
- public int getSelectedSort() {
- return mSelSort;
- }
-
- @Override
- public TextViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- LayoutInflater inflater = LayoutInflater.from(parent.getContext());
- switch (viewType) {
- case TYPE_SORT:
- case TYPE_GENRE:
- RadioCheckHolder holder = new RadioCheckHolder(inflater.inflate(R.layout.item_radiocheck, parent, false));
- holder.itemView.setOnClickListener(this);
- return holder;
- default:
- return new TextViewHolder(inflater.inflate(R.layout.header_group, parent, false));
- }
- }
-
- @Override
- public void onBindViewHolder(TextViewHolder holder, int position) {
- TypedString item = mDataset.get(position);
- holder.getTextView().setText(item.data);
- if (holder instanceof RadioCheckHolder) {
- ((RadioCheckHolder) holder).setChecked(
- item.type == TYPE_SORT && item.subPosition == mSelSort
- || item.type == TYPE_GENRE && item.subPosition == mSelGenre
- );
- }
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size();
- }
-
- @Override
- public int getItemViewType(int position) {
- return mDataset.get(position).type;
- }
-
- private int getAbsolutePosition(int type, int subPos) {
- TypedString o;
- for (int i = 0; i < mDataset.size(); i++) {
- o = mDataset.get(i);
- if (o.type == type && o.subPosition == subPos) {
- return i;
- }
- }
- return -1;
- }
-
- @Nullable
- public String getSelectedGenreName() {
- int pos = getAbsolutePosition(TYPE_GENRE, mSelGenre);
- return pos == -1 ? null : mDataset.get(pos).data;
- }
-
- @Nullable
- public String getSelectedSortName() {
- int pos = getAbsolutePosition(TYPE_SORT, mSelSort);
- return pos == -1 ? null : mDataset.get(pos).data;
- }
-
- @Override
- public void onClick(View view) {
- Object tag = view.getTag();
- if (tag != null && tag instanceof RadioCheckHolder) {
- int pos = ((RadioCheckHolder) tag).getAdapterPosition();
- TypedString item = mDataset.get(pos);
- if (item.type == TYPE_SORT) {
- mSelSort = item.subPosition;
- mCallback.onApply(mSelGenre, mSelSort, getSelectedGenreName(), item.data);
-
- notifyDataSetChanged();
- } else if (item.type == TYPE_GENRE) {
- mSelGenre = item.subPosition;
- mCallback.onApply(mSelGenre, mSelSort, item.data, getSelectedSortName());
- notifyDataSetChanged();
- }
- }
- }
-
- private static class TypedString {
- final String data;
- final int type;
- int subPosition;
-
- public TypedString(String data, int type) {
- this.data = data;
- this.type = type;
- this.subPosition = 0;
- }
-
- public TypedString(String data, int type, int subpos) {
- this.data = data;
- this.type = type;
- this.subPosition = subpos;
- }
-
- @Override
- public String toString() {
- return data;
- }
- }
-
- private static class RadioCheckHolder extends TextViewHolder implements Checkable {
-
- RadioCheckHolder(View itemView) {
- super(itemView);
- itemView.setTag(this);
- }
-
- @Override
- public void setChecked(boolean b) {
- ((Checkable) itemView).setChecked(b);
- }
-
- @Override
- public boolean isChecked() {
- return ((Checkable) itemView).isChecked();
- }
-
- @Override
- public void toggle() {
- ((Checkable) itemView).toggle();
- }
- }
-
- static class TextViewHolder extends RecyclerView.ViewHolder {
-
- TextViewHolder(View itemView) {
- super(itemView);
- }
-
- TextView getTextView() {
- return (TextView) itemView;
- }
- }
-
- public interface Callback {
- void onApply(int genre, int sort, @Nullable String genreName, @Nullable String sortName);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/HeaderedAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/HeaderedAdapter.java
deleted file mode 100644
index 49e608a3..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/HeaderedAdapter.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 09.08.16.
- */
-
-public abstract class HeaderedAdapter extends RecyclerView.Adapter {
-
- private int mHeaders = 0;
- private ArrayList mHeaderViews = new ArrayList<>();
-
- @Override
- public final int getItemCount() {
- return mHeaders + getDataItemCount();
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position < mHeaders) {
- return position;
- } else {
- return mHeaders + getDataItemType(position - mHeaders);
- }
- }
-
- @Override
- public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- if (viewType < mHeaders) {
- return new HeaderHolder(mHeaderViews.get(viewType));
- } else {
- return onCreateDataViewHolder(parent, viewType - mHeaders);
- }
- }
-
- @Override
- public final void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- if (!(holder instanceof HeaderedAdapter.HeaderHolder)) {
- //noinspection unchecked
- onBindDataViewHolder((VH) holder, position - mHeaders);
- }
- }
-
- public void addHeader(View header, int position) {
- mHeaderViews.add(position, header);
- mHeaders++;
- notifyItemInserted(position);
- }
-
- public abstract int getDataItemCount();
-
- public int getDataItemType(int position) {
- return 0;
- }
-
- public abstract VH onCreateDataViewHolder(ViewGroup parent, int viewType);
-
- public abstract void onBindDataViewHolder(VH holder, int position);
-
- public int getHeadersCount() {
- return mHeaders;
- }
-
- private static class HeaderHolder extends RecyclerView.ViewHolder {
-
- public HeaderHolder(View itemView) {
- super(itemView);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/MangaListAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/MangaListAdapter.java
deleted file mode 100755
index 70a66cb1..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/MangaListAdapter.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.AsyncTask;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Checkable;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.PreviewActivity2;
-import org.nv95.openmanga.components.RatingView;
-import org.nv95.openmanga.dialogs.PreviewDialog;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.lists.PagedList;
-import org.nv95.openmanga.utils.ImageUtils;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.QuickReadTask;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceController;
-import org.nv95.openmanga.utils.choicecontrol.OnHolderClickListener;
-
-/**
- * Created by nv95 on 30.09.15.
- */
-public class MangaListAdapter extends EndlessAdapter {
-
- private boolean mGrid;
- private ThumbSize mThumbSize;
- @Nullable
- private OnItemLongClickListener mOnItemLongClickListener;
- private final ModalChoiceController mChoiceController;
-
- public MangaListAdapter(PagedList dataset, RecyclerView recyclerView) {
- super(dataset, recyclerView);
- mChoiceController = new ModalChoiceController(this);
- if (MangaViewHolder.PADDING_4 == 0) {
- MangaViewHolder.PADDING_4 = LayoutUtils.DpToPx(recyclerView.getResources(), 4);
- MangaViewHolder.PADDING_16 = LayoutUtils.DpToPx(recyclerView.getResources(), 16);
- MangaViewHolder.HEIGHT_68 = LayoutUtils.DpToPx(recyclerView.getResources(), 68);
- MangaViewHolder.HEIGHT_42 = LayoutUtils.DpToPx(recyclerView.getResources(), 42);
- }
- }
-
- public boolean setGrid(boolean grid) {
- if (mGrid != grid) {
- mGrid = grid;
- notifyDataSetChanged();
- return true;
- } else {
- return false;
- }
- }
-
- public ModalChoiceController getChoiceController() {
- return mChoiceController;
- }
-
- public void setThumbnailsSize(@NonNull ThumbSize size) {
- if (!size.equals(mThumbSize)) {
- mThumbSize = size;
- notifyItemRangeChanged(0, getItemCount());
- }
- }
-
- @Override
- public MangaViewHolder onCreateHolder(ViewGroup parent) {
- MangaViewHolder holder = new MangaViewHolder(LayoutInflater.from(parent.getContext())
- .inflate(mGrid ? R.layout.item_mangagrid : R.layout.item_mangalist, parent, false), mOnItemLongClickListener);
- holder.setListener(mChoiceController);
-
- return holder;
- }
-
- @Override
- public long getItemId(MangaInfo data) {
- return data.id;
- }
-
- @Override
- public void onBindHolder(MangaViewHolder viewHolder, MangaInfo data, int position) {
- viewHolder.fill(data, mThumbSize, mChoiceController.isSelected(position));
- }
-
- static class MangaViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
-
- private static int PADDING_16 = 0;
- private static int PADDING_4 = 0;
- private static int HEIGHT_68 = 0;
- private static int HEIGHT_42 = 0;
-
- @Nullable
- private final OnItemLongClickListener mLongClickListener;
- private final TextView textViewTitle;
- @Nullable
- private final TextView textViewSubtitle;
- private final TextView textViewSummary;
- private final TextView textViewBadge;
- @Nullable
- private final RatingView ratingView;
- private final ImageView imageView;
- @Nullable
- private final ImageView imageViewStatus;
- private final View buttonRead;
- private MangaInfo mData;
- @Nullable
- private OnHolderClickListener mListener;
- @Nullable
- private final View cellFooter;
- private int viewMode;
-
- MangaViewHolder(final View itemView, @Nullable OnItemLongClickListener longClickListener) {
- super(itemView);
- textViewTitle = itemView.findViewById(R.id.textView_title);
- textViewSubtitle = itemView.findViewById(R.id.textView_subtitle);
- textViewSummary = itemView.findViewById(R.id.textView_summary);
- textViewBadge = itemView.findViewById(R.id.textView_badge);
- ratingView = itemView.findViewById(R.id.ratingView);
- imageView = itemView.findViewById(R.id.imageView);
- buttonRead = itemView.findViewById(R.id.buttonRead);
- cellFooter = itemView.findViewById(R.id.cell_footer);
- imageViewStatus = itemView.findViewById(R.id.imageView_status);
- itemView.setOnClickListener(this);
- mLongClickListener = longClickListener;
- itemView.setOnLongClickListener(this);
- buttonRead.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (itemView instanceof Checkable && ((Checkable) itemView).isChecked()) {
- return;
- }
- new QuickReadTask(view.getContext())
- .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mData);
- }
- });
- buttonRead.setOnLongClickListener(new View.OnLongClickListener() {
- @Override
- public boolean onLongClick(View view) {
- if (itemView instanceof Checkable && ((Checkable) itemView).isChecked()) {
- return false;
- }
- new PreviewDialog(view.getContext())
- .show(mData);
- return true;
- }
- });
- }
-
- public MangaInfo getData() {
- return mData;
- }
-
- private void updateViewMode(ThumbSize thumbSize) {
- int mode = 3; //large grid
- if (cellFooter == null) {
- mode = 0; //list
- } else if (thumbSize.getWidth() <= ThumbSize.THUMB_SIZE_SMALL.getWidth()) {
- mode = 1; //small grid
- } else if (thumbSize.getWidth() <= ThumbSize.THUMB_SIZE_MEDIUM.getWidth()) {
- mode = 2; //medium grid
- }
- if (viewMode == mode) {
- return;
- }
- viewMode = mode;
- switch (viewMode) {
- case 0:
- buttonRead.setVisibility(View.VISIBLE);
- textViewSummary.setVisibility(View.VISIBLE);
- textViewTitle.setMaxLines(2);
- break;
- case 1:
- buttonRead.setVisibility(View.GONE);
- textViewSummary.setVisibility(View.GONE);
- textViewTitle.setMaxLines(2);
- cellFooter.getLayoutParams().height = HEIGHT_42;
- cellFooter.setPadding(PADDING_4, PADDING_4, PADDING_4, PADDING_4);
- break;
- case 2:
- buttonRead.setVisibility(View.GONE);
- textViewTitle.setMaxLines(1);
- textViewSummary.setVisibility(View.VISIBLE);
- cellFooter.getLayoutParams().height = HEIGHT_68;
- cellFooter.setPadding(PADDING_4, PADDING_4, PADDING_4, PADDING_4);
- break;
- case 3:
- buttonRead.setVisibility(View.VISIBLE);
- textViewSummary.setVisibility(View.VISIBLE);
- textViewTitle.setMaxLines(1);
- cellFooter.getLayoutParams().height = HEIGHT_68;
- cellFooter.setPadding(PADDING_16, PADDING_16, PADDING_16, PADDING_16);
- }
- }
-
- public void fill(MangaInfo data, ThumbSize thumbSize, boolean checked) {
- mData = data;
- updateViewMode(thumbSize);
- if (itemView instanceof Checkable) {
- ((Checkable) itemView).setChecked(checked);
- }
- textViewTitle.setText(mData.name);
- if (textViewSubtitle != null) {
- if (TextUtils.isEmpty(mData.subtitle)) {
- textViewSubtitle.setVisibility(View.GONE);
- } else {
- textViewSubtitle.setText(mData.subtitle);
- textViewSubtitle.setVisibility(View.VISIBLE);
- }
- }
- textViewSummary.setText(mData.genres);
- if (ratingView != null) {
- ratingView.setRating(mData.rating);
- }
- ImageUtils.setThumbnail(imageView, data.preview, thumbSize);
- if (imageViewStatus != null) {
- if (mData.status == MangaInfo.STATUS_UNKNOWN) {
- imageViewStatus.setVisibility(View.INVISIBLE);
- } else {
- imageViewStatus.setImageResource(mData.isCompleted() ? R.drawable.ic_completed : R.drawable.ic_ongoing);
- imageViewStatus.setVisibility(View.VISIBLE);
- }
- }
- if (mData.extra == null) {
- textViewBadge.setVisibility(View.GONE);
- } else {
- textViewBadge.setText(mData.extra);
- textViewBadge.setVisibility(View.VISIBLE);
- }
- }
-
- public void setListener(@Nullable OnHolderClickListener listener) {
- this.mListener = listener;
- }
-
- @Override
- public void onClick(View v) {
- if (mListener == null || !mListener.onClick(this)) {
- Context context = v.getContext();
- Intent intent = new Intent(context, PreviewActivity2.class);
- intent.putExtras(mData.toBundle());
- context.startActivity(intent);
- }
- }
-
- @Override
- public boolean onLongClick(View v) {
- return !(mListener == null || !mListener.onLongClick(this)) || mLongClickListener != null && mLongClickListener.onItemLongClick(this);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/NewChaptersAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/NewChaptersAdapter.java
deleted file mode 100644
index 2639b7d7..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/NewChaptersAdapter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.Context;
-import android.content.Intent;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.PreviewActivity2;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.utils.ImageUtils;
-
-/**
- * Created by nv95 on 17.04.16.
- */
-public class NewChaptersAdapter extends RecyclerView.Adapter {
-
- private final MangaList mDataset;
-
- public NewChaptersAdapter(MangaList dataset) {
- this.mDataset = dataset;
- }
-
- @Override
- public UpdatesHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- return new UpdatesHolder(LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_updates, parent, false));
- }
-
- @Override
- public void onBindViewHolder(UpdatesHolder holder, int position) {
- holder.fill(mDataset.get(position));
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size();
- }
-
- static class UpdatesHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
- private final TextView mTextViewTitle;
- private final ImageView imageView;
- private final TextView mTextViewBadge;
- private final TextView mTextViewSubtitle;
- private MangaInfo mData;
-
- public UpdatesHolder(View itemView) {
- super(itemView);
- imageView = itemView.findViewById(R.id.imageView);
- mTextViewTitle = itemView.findViewById(R.id.textView_title);
- mTextViewSubtitle = itemView.findViewById(R.id.textView_subtitle);
- mTextViewBadge = itemView.findViewById(R.id.textView_badge);
- itemView.setOnClickListener(this);
- }
-
- public void fill(MangaInfo manga) {
- mData = manga;
- ImageUtils.setThumbnail(imageView, mData.preview);
- mTextViewTitle.setText(mData.name);
- mTextViewSubtitle.setText(mData.subtitle);
- mTextViewBadge.setText(mData.extra);
- }
-
- @Override
- public void onClick(View v) {
- Context context = v.getContext();
- Intent intent = new Intent(context, PreviewActivity2.class);
- intent.putExtras(mData.toBundle());
- context.startActivity(intent);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/OnChapterClickListener.java b/app/src/main/java/org/nv95/openmanga/adapters/OnChapterClickListener.java
deleted file mode 100644
index 0e3ca995..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/OnChapterClickListener.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import org.nv95.openmanga.items.MangaChapter;
-
-public interface OnChapterClickListener {
- void onChapterClick(int pos, MangaChapter chapter);
- boolean onChapterLongClick(int pos, MangaChapter chapter);
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/OnItemLongClickListener.java b/app/src/main/java/org/nv95/openmanga/adapters/OnItemLongClickListener.java
deleted file mode 100644
index 45dbf3d1..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/OnItemLongClickListener.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.support.v7.widget.RecyclerView;
-
-/**
- * Created by nv95 on 28.01.16.
- */
-public interface OnItemLongClickListener {
- boolean onItemLongClick(VH viewHolder);
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/ProvidersAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/ProvidersAdapter.java
deleted file mode 100644
index d715f576..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/ProvidersAdapter.java
+++ /dev/null
@@ -1,181 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.app.Activity;
-import android.content.Intent;
-import android.support.v4.view.MotionEventCompat;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.settings.ProviderPreferencesActivity;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.util.List;
-
-/**
- * Created by nv95 on 12.07.16.
- */
-
-public class ProvidersAdapter extends RecyclerView.Adapter implements View.OnClickListener {
-
- private static final int ITEM_VIEW = 0;
- private static final int ITEM_FOOTER = 1;
- private static final int ITEM_DIVIDER = 2;
-
- private final List mDataset;
- private final String[] languages;
- private final OnStartDragListener mDragListener;
- private final Activity mActivity;
- private int mActiveCount = 4;
-
- public ProvidersAdapter(Activity context, List providers, OnStartDragListener dragListener) {
- mActivity = context;
- mDataset = providers;
- mDragListener = dragListener;
- languages = context.getResources().getStringArray(R.array.languages);
- }
-
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- switch (viewType) {
- case ITEM_VIEW:
- ProviderHolder pholder = new ProviderHolder(
- LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_provider, parent, false),
- mDragListener
- );
- pholder.imageButton.setOnClickListener(this);
- return pholder;
- case ITEM_DIVIDER:
- return new DividerHolder(
- LayoutInflater.from(parent.getContext())
- .inflate(R.layout.item_provider_divider, parent, false),
- mDragListener
- );
- default:
- return new FooterHolder(
- LayoutInflater.from(parent.getContext())
- .inflate(R.layout.footer_disclaimer, parent, false)
- );
- }
- }
-
- @Override
- public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
- if (holder instanceof ProviderHolder) {
- ProviderSummary item = getItem(position);
- ((ProviderHolder)holder).text1.setText(item.name);
- ((ProviderHolder)holder).text2.setText(languages[item.lang]);
- ((ProviderHolder)holder).imageButton.setVisibility(item.preferences == 0 ? View.GONE : View.VISIBLE);
- ((ProviderHolder)holder).imageButton.setTag(item);
- }
- }
-
- private ProviderSummary getItem(int position) {
- return mDataset.get(position < mActiveCount ? position : position - 1);
- }
-
-
- public void setActiveCount(int count) {
- mActiveCount = count;
- }
-
- @Override
- public int getItemCount() {
- return mDataset.size() + 2;
- }
-
- @Override
- public int getItemViewType(int position) {
- if (position <= mDataset.size()) {
- if (position == mActiveCount) {
- return ITEM_DIVIDER;
- } else {
- return ITEM_VIEW;
- }
- } else {
- return ITEM_FOOTER;
- }
- }
-
- public int getActiveCount() {
- return mActiveCount;
- }
-
- @Override
- public void onClick(View view) {
- Object tag = view.getTag();
- if (tag != null && tag instanceof ProviderSummary) {
- mActivity.startActivity(new Intent(mActivity, ProviderPreferencesActivity.class).putExtra("provider", ((ProviderSummary) tag).id));
- }
- }
-
- private static class ProviderHolder extends RecyclerView.ViewHolder implements View.OnTouchListener {
-
- final TextView text1;
- final TextView text2;
- final ImageView imageButton;
- private final OnStartDragListener mStartDragListener;
-
- ProviderHolder(View itemView, OnStartDragListener sdl) {
- super(itemView);
- text1 = itemView.findViewById(android.R.id.text1);
- text2 = itemView.findViewById(android.R.id.text2);
- imageButton = itemView.findViewById(R.id.imageButton);
- mStartDragListener = sdl;
- itemView.findViewById(R.id.imageView_draghandle).setOnTouchListener(this);
- if (LayoutUtils.isAppThemeDark(itemView.getContext())) {
- LayoutUtils.setAllImagesColor((ViewGroup) itemView, R.color.white_overlay_85);
- }
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (MotionEventCompat.getActionMasked(event) ==
- MotionEvent.ACTION_DOWN) {
- mStartDragListener.onStartDrag(this);
- }
- return false;
- }
- }
-
- private static class FooterHolder extends RecyclerView.ViewHolder {
-
- FooterHolder(View itemView) {
- super(itemView);
- }
- }
-
- public static class DividerHolder extends RecyclerView.ViewHolder implements View.OnTouchListener {
-
- private final OnStartDragListener mStartDragListener;
-
- DividerHolder(View itemView, OnStartDragListener startDragListener) {
- super(itemView);
- mStartDragListener = startDragListener;
- if (LayoutUtils.isAppThemeDark(itemView.getContext())) {
- LayoutUtils.setAllImagesColor((ViewGroup) itemView, R.color.white_overlay_85);
- }
- itemView.findViewById(R.id.imageView_draghandle).setOnTouchListener(this);
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- if (MotionEventCompat.getActionMasked(event) ==
- MotionEvent.ACTION_DOWN) {
- mStartDragListener.onStartDrag(this);
- }
- return false;
- }
- }
-
- public interface OnStartDragListener {
- void onStartDrag(RecyclerView.ViewHolder viewHolder);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/SearchHistoryAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/SearchHistoryAdapter.java
deleted file mode 100644
index 36bf59cb..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/SearchHistoryAdapter.java
+++ /dev/null
@@ -1,265 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.text.TextUtils;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.helpers.StorageHelper;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.lang.ref.WeakReference;
-
-/**
- * Created by nv95 on 02.01.16.
- */
-public class SearchHistoryAdapter extends RecyclerView.Adapter {
-
- private static final String TABLE_NAME = "search_history";
- private final Drawable[] mIcons;
-
- private final StorageHelper mStorageHelper;
- @Nullable
- private Cursor mCursor;
- @Nullable
- private static WeakReference sStorageHelperRef;
- @NonNull
- private final OnHistoryEventListener mClickListener;
- @Nullable
- private WeakReference mQueryTaskRef = null;
-
- public SearchHistoryAdapter(Context context, @NonNull OnHistoryEventListener clickListener) {
- mStorageHelper = new StorageHelper(context);
- sStorageHelperRef = new WeakReference<>(mStorageHelper);
- setHasStableIds(true);
- mClickListener = clickListener;
- mCursor = null;
- mIcons = LayoutUtils.getThemedIcons(context, R.drawable.ic_history_dark, R.drawable.ic_launch_black);
- }
-
- @Override
- protected void finalize() throws Throwable {
- mStorageHelper.close();
- if (sStorageHelperRef != null) {
- sStorageHelperRef.clear();
- sStorageHelperRef = null;
- }
- super.finalize();
- }
-
- @Override
- public ItemHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- ItemHolder holder = new ItemHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_search, parent, false), mClickListener);
- holder.textView.setCompoundDrawablesWithIntrinsicBounds(mIcons[0], null, null, null);
- holder.imageButton.setImageDrawable(mIcons[1]);
- return holder;
- }
-
- @Override
- public void onBindViewHolder(ItemHolder holder, int position) {
- if (mCursor != null) {
- mCursor.moveToPosition(position);
- holder.fill(mCursor.getString(1));
- }
- }
-
- @Override
- public long getItemId(int position) {
- if (mCursor != null) {
- mCursor.moveToPosition(position);
- return mCursor.getInt(0);
- } else {
- return 0;
- }
- }
-
- private void swapCursor(@Nullable Cursor newCursor) {
- Cursor oldCursor = mCursor;
- mCursor = newCursor;
- if (oldCursor != null) {
- oldCursor.close();
- }
- notifyDataSetChanged();
- }
-
- public void requery(@Nullable String prefix) {
- cancelTask();
- Cursor cursor = mStorageHelper.getReadableDatabase().query(TABLE_NAME, null,
- TextUtils.isEmpty(prefix) ? null : "query LIKE ?",
- TextUtils.isEmpty(prefix) ? null : new String[] {prefix + "%"}, null, null, null);
- swapCursor(cursor);
- }
-
- public void requeryAsync(@Nullable String prefix) {
- cancelTask();
- QueryTask task = new QueryTask(this);
- mQueryTaskRef = new WeakReference<>(task);
- task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, prefix);
- }
-
- private void cancelTask() {
- if (mQueryTaskRef != null) {
- QueryTask task = mQueryTaskRef.get();
- if (task != null && task.canCancel()) {
- task.cancel(false);
- }
- }
- mQueryTaskRef = null;
- }
-
- @Override
- public int getItemCount() {
- return mCursor == null ? 0 : mCursor.getCount();
- }
-
- static class ItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-
- private final OnHistoryEventListener mClickListener;
- private String mText;
- final TextView textView;
- final ImageView imageButton;
-
- ItemHolder(View itemView, OnHistoryEventListener listener) {
- super(itemView);
- mClickListener = listener;
- textView = itemView.findViewById(android.R.id.text1);
- imageButton = itemView.findViewById(R.id.imageButton);
- imageButton.setOnClickListener(this);
- textView.setOnClickListener(this);
- }
-
- public void fill(String text) {
- mText = text;
- textView.setText(text);
- }
-
- @Override
- public void onClick(View view) {
- mClickListener.onHistoryItemClick(mText, view.getId() != imageButton.getId());
- }
- }
-
- public interface OnHistoryEventListener {
- void onHistoryItemClick(String text, boolean apply);
- }
-
- public static void clearHistory(Context context) {
- StorageHelper storageHelper = null;
- boolean reused = true;
- if (sStorageHelperRef != null) {
- storageHelper = sStorageHelperRef.get();
- }
- if (storageHelper == null) {
- storageHelper = new StorageHelper(context);
- reused = false;
- }
- storageHelper.getWritableDatabase().delete(TABLE_NAME, null, null);
- if (!reused) {
- storageHelper.close();
- }
- }
-
- public static void addToHistory(Context context, String what) {
- StorageHelper storageHelper = null;
- boolean reused = true;
- if (sStorageHelperRef != null) {
- storageHelper = sStorageHelperRef.get();
- }
- if (storageHelper == null) {
- storageHelper = new StorageHelper(context);
- reused = false;
- }
- SQLiteDatabase database = storageHelper.getWritableDatabase();
- ContentValues cv = new ContentValues();
- cv.put("_id", what.hashCode());
- cv.put("query", what);
- int updCount = database.update(TABLE_NAME, cv, "_id=" + what.hashCode(), null);
- if (updCount == 0) {
- database.insert(TABLE_NAME, null, cv);
- }
- if (!reused) {
- storageHelper.close();
- }
- }
-
- public static void removeFromHistory(Context context, long what) {
- StorageHelper storageHelper = null;
- boolean reused = true;
- if (sStorageHelperRef != null) {
- storageHelper = sStorageHelperRef.get();
- }
- if (storageHelper == null) {
- storageHelper = new StorageHelper(context);
- reused = false;
- }
- SQLiteDatabase database = storageHelper.getWritableDatabase();
- database.delete(TABLE_NAME, "_id=" + what, null);
- if (!reused) {
- storageHelper.close();
- }
- }
-
-
- public static int getHistorySize(Context context) {
- StorageHelper storageHelper = null;
- boolean reused = true;
- if (sStorageHelperRef != null) {
- storageHelper = sStorageHelperRef.get();
- }
- if (storageHelper == null) {
- storageHelper = new StorageHelper(context);
- reused = false;
- }
- int res = StorageHelper.getRowCount(
- storageHelper.getReadableDatabase(),
- TABLE_NAME,
- null
- );
- if (!reused) {
- storageHelper.close();
- }
- return res;
- }
-
-
- private static class QueryTask extends WeakAsyncTask {
-
- QueryTask(SearchHistoryAdapter searchHistoryAdapter) {
- super(searchHistoryAdapter);
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected Cursor doInBackground(String... strings) {
- try {
- String prefix = strings.length > 0 ? strings[0] : null;
- return getObject().mStorageHelper.getReadableDatabase().query(TABLE_NAME, null,
- TextUtils.isEmpty(prefix) ? null : "query LIKE ?",
- TextUtils.isEmpty(prefix) ? null : new String[] {prefix + "%"}, null, null, null);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull SearchHistoryAdapter searchHistoryAdapter, Cursor cursor) {
- if (cursor != null) {
- searchHistoryAdapter.swapCursor(cursor);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/adapters/SearchResultsAdapter.java b/app/src/main/java/org/nv95/openmanga/adapters/SearchResultsAdapter.java
deleted file mode 100644
index 85687c46..00000000
--- a/app/src/main/java/org/nv95/openmanga/adapters/SearchResultsAdapter.java
+++ /dev/null
@@ -1,263 +0,0 @@
-package org.nv95.openmanga.adapters;
-
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.GridLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.ThumbSize;
-import org.nv95.openmanga.providers.staff.ProviderSummary;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.choicecontrol.ModalChoiceController;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 24.12.16.
- */
-
-public class SearchResultsAdapter extends RecyclerView.Adapter implements View.OnClickListener {
-
- private static final int VIEW_HEADER = 0;
- private static final int VIEW_ITEM = 1;
- private static final int VIEW_FOOTER = 2;
-
- private static final int FOOTER_NONE = 0;
- private static final int FOOTER_BUTTON = 1;
- private static final int FOOTER_PROGRESS = 2;
-
- private final ArrayList
- *
- * @author amit
- * @see RecyclerViewOverScrollDecorAdapter
- * @see IOverScrollDecoratorAdapter
- */
-public abstract class OverScrollBounceEffectDecoratorBase implements IOverScrollDecor, View.OnTouchListener {
-
- public static final String TAG = "OverScrollDecor";
-
- public static final float DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD = 3f;
- public static final float DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK = 1f;
- public static final float DEFAULT_DECELERATE_FACTOR = -2f;
-
- protected static final int MAX_BOUNCE_BACK_DURATION_MS = 800;
- protected static final int MIN_BOUNCE_BACK_DURATION_MS = 200;
-
- protected final OverScrollStartAttributes mStartAttr = new OverScrollStartAttributes();
- protected final IOverScrollDecoratorAdapter mViewAdapter;
-
- protected final IdleState mIdleState;
- protected final OverScrollingState mOverScrollingState;
- protected final BounceBackState mBounceBackState;
- protected IDecoratorState mCurrentState;
-
- protected IOverScrollStateListener mStateListener = new ListenerStubs.OverScrollStateListenerStub();
- protected IOverScrollUpdateListener mUpdateListener = new ListenerStubs.OverScrollUpdateListenerStub();
-
- /**
- * When in over-scroll mode, keep track of dragging velocity to provide a smooth slow-down
- * for the bounce-back effect.
- */
- protected float mVelocity;
-
- /**
- * Motion attributes: keeps data describing current motion event.
- *
Orientation agnostic: subclasses provide either horizontal or vertical
- * initialization of the agnostic attributes.
- */
- protected abstract static class MotionAttributes {
- public float mAbsOffset;
- public float mDeltaOffset;
- public boolean mDir; // True = 'forward', false = 'backwards'.
-
- protected abstract boolean init(View view, MotionEvent event);
- }
-
- protected static class OverScrollStartAttributes {
- protected int mPointerId;
- protected float mAbsOffset;
- protected boolean mDir; // True = 'forward', false = 'backwards'.
- }
-
- protected abstract static class AnimationAttributes {
- public Property mProperty;
- public float mAbsOffset;
- public float mMaxOffset;
-
- protected abstract void init(View view);
- }
-
- /**
- * Interface of decorator-state delegation classes. Defines states as handles of two fundamental
- * touch events: actual movement, up/cancel.
- */
- protected interface IDecoratorState {
-
- /**
- * Handle a motion (touch) event.
- *
- * @param event The event from onTouch.
- * @return Return value for onTouch.
- */
- boolean handleMoveTouchEvent(MotionEvent event);
-
- /**
- * Handle up / touch-cancel events.
- *
- * @param event The event from onTouch.
- * @return Return value for onTouch.
- */
- boolean handleUpOrCancelTouchEvent(MotionEvent event);
-
- /**
- * Handle a transition onto this state, as it becomes 'current' state.
- *
- * @param fromState
- */
- void handleEntryTransition(IDecoratorState fromState);
-
- /**
- * The client-perspective ID of the state associated with this (internal) one. ID's
- * are as specified in {@link IOverScrollState}.
- *
- * @return The ID, e.g. {@link IOverScrollState#STATE_IDLE}.
- */
- int getStateId();
- }
-
- /**
- * Idle state: monitors move events, trying to figure out whether over-scrolling should be
- * initiated (i.e. when scrolled further when the view is at one of its displayable ends).
- *
When such is the case, it hands over control to the over-scrolling state.
- */
- protected class IdleState implements IDecoratorState {
-
- final MotionAttributes mMoveAttr;
-
- public IdleState() {
- mMoveAttr = createMotionAttributes();
- }
-
- @Override
- public int getStateId() {
- return STATE_IDLE;
- }
-
- @Override
- public boolean handleMoveTouchEvent(MotionEvent event) {
-
- final View view = mViewAdapter.getView();
- if (!mMoveAttr.init(view, event)) {
- return false;
- }
-
- // Has over-scrolling officially started?
- if ((mViewAdapter.isInAbsoluteStart() && mMoveAttr.mDir) ||
- (mViewAdapter.isInAbsoluteEnd() && !mMoveAttr.mDir)) {
-
- // Save initial over-scroll attributes for future reference.
- mStartAttr.mPointerId = event.getPointerId(0);
- mStartAttr.mAbsOffset = mMoveAttr.mAbsOffset;
- mStartAttr.mDir = mMoveAttr.mDir;
-
- issueStateTransition(mOverScrollingState);
- return mOverScrollingState.handleMoveTouchEvent(event);
- }
-
- return false;
- }
-
- @Override
- public boolean handleUpOrCancelTouchEvent(MotionEvent event) {
- return false;
- }
-
- @Override
- public void handleEntryTransition(IDecoratorState fromState) {
- mStateListener.onOverScrollStateChange(OverScrollBounceEffectDecoratorBase.this, fromState.getStateId(), this.getStateId());
- }
- }
-
- /**
- * Handles the actual over-scrolling: thus translating the view according to configuration
- * and user interactions, dynamically.
- *
- *
The state is exited - thus completing over-scroll handling, in one of two cases:
- *
When user lets go of the view, it transitions control to the bounce-back state.
- *
When user moves the view back onto a potential 'under-scroll' state, it abruptly
- * transitions control to the idle-state, so as to return touch-events management to the
- * normal over-scroll-less environment (thus preventing under-scrolling and potentially regaining
- * regular scrolling).
- */
- protected class OverScrollingState implements IDecoratorState {
-
- protected final float mTouchDragRatioFwd;
- protected final float mTouchDragRatioBck;
-
- final MotionAttributes mMoveAttr;
- int mCurrDragState;
-
- public OverScrollingState(float touchDragRatioFwd, float touchDragRatioBck) {
- mMoveAttr = createMotionAttributes();
- mTouchDragRatioFwd = touchDragRatioFwd;
- mTouchDragRatioBck = touchDragRatioBck;
- }
-
- @Override
- public int getStateId() {
- // This is really a single class that implements 2 states, so our ID depends on what
- // it was during the last invocation.
- return mCurrDragState;
- }
-
- @Override
- public boolean handleMoveTouchEvent(MotionEvent event) {
-
- // Switching 'pointers' (e.g. fingers) on-the-fly isn't supported -- abort over-scroll
- // smoothly using the default bounce-back animation in this case.
- if (mStartAttr.mPointerId != event.getPointerId(0)) {
- issueStateTransition(mBounceBackState);
- return true;
- }
-
- final View view = mViewAdapter.getView();
- if (!mMoveAttr.init(view, event)) {
- // Keep intercepting the touch event as long as we're still over-scrolling...
- return true;
- }
-
- float deltaOffset = mMoveAttr.mDeltaOffset / (mMoveAttr.mDir == mStartAttr.mDir ? mTouchDragRatioFwd : mTouchDragRatioBck);
- float newOffset = mMoveAttr.mAbsOffset + deltaOffset;
-
- // If moved in counter direction onto a potential under-scroll state -- don't. Instead, abort
- // over-scrolling abruptly, thus returning control to which-ever touch handlers there
- // are waiting (e.g. regular scroller handlers).
- if ((mStartAttr.mDir && !mMoveAttr.mDir && (newOffset <= mStartAttr.mAbsOffset)) ||
- (!mStartAttr.mDir && mMoveAttr.mDir && (newOffset >= mStartAttr.mAbsOffset))) {
- translateViewAndEvent(view, mStartAttr.mAbsOffset, event);
- mUpdateListener.onOverScrollUpdate(OverScrollBounceEffectDecoratorBase.this, mCurrDragState, 0);
-
- issueStateTransition(mIdleState);
- return true;
- }
-
- if (view.getParent() != null) {
- view.getParent().requestDisallowInterceptTouchEvent(true);
- }
-
- long dt = event.getEventTime() - event.getHistoricalEventTime(0);
- if (dt > 0) { // Sometimes (though rarely) dt==0 cause originally timing is in nanos, but is presented in millis.
- mVelocity = deltaOffset / dt;
- }
-
- translateView(view, newOffset);
- mUpdateListener.onOverScrollUpdate(OverScrollBounceEffectDecoratorBase.this, mCurrDragState, newOffset);
-
- return true;
- }
-
- @Override
- public boolean handleUpOrCancelTouchEvent(MotionEvent event) {
- issueStateTransition(mBounceBackState);
- return false;
- }
-
- @Override
- public void handleEntryTransition(IDecoratorState fromState) {
- mCurrDragState = (mStartAttr.mDir ? STATE_DRAG_START_SIDE : STATE_DRAG_END_SIDE);
- mStateListener.onOverScrollStateChange(OverScrollBounceEffectDecoratorBase.this, fromState.getStateId(), this.getStateId());
- }
- }
-
- /**
- * When entered, starts the bounce-back animation.
- *
Upon animation completion, transitions control onto the idle state; Does so by
- * registering itself as an animation listener.
- *
In the meantime, blocks (intercepts) all touch events.
- */
- protected class BounceBackState implements IDecoratorState, Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
-
- protected final Interpolator mBounceBackInterpolator = new DecelerateInterpolator();
- protected final float mDecelerateFactor;
- protected final float mDoubleDecelerateFactor;
-
- protected final AnimationAttributes mAnimAttributes;
-
- public BounceBackState(float decelerateFactor) {
- mDecelerateFactor = decelerateFactor;
- mDoubleDecelerateFactor = 2f * decelerateFactor;
-
- mAnimAttributes = createAnimationAttributes();
- }
-
- @Override
- public int getStateId() {
- return STATE_BOUNCE_BACK;
- }
-
- @Override
- public void handleEntryTransition(IDecoratorState fromState) {
-
- mStateListener.onOverScrollStateChange(OverScrollBounceEffectDecoratorBase.this, fromState.getStateId(), this.getStateId());
-
- Animator bounceBackAnim = createAnimator();
- bounceBackAnim.addListener(this);
-
- bounceBackAnim.start();
- }
-
- @Override
- public boolean handleMoveTouchEvent(MotionEvent event) {
- // Flush all touches down the drain till animation is over.
- return true;
- }
-
- @Override
- public boolean handleUpOrCancelTouchEvent(MotionEvent event) {
- // Flush all touches down the drain till animation is over.
- return true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- issueStateTransition(mIdleState);
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mUpdateListener.onOverScrollUpdate(OverScrollBounceEffectDecoratorBase.this, STATE_BOUNCE_BACK, (Float) animation.getAnimatedValue());
- }
-
- @Override
- public void onAnimationStart(Animator animation) {
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- }
-
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
-
- protected Animator createAnimator() {
-
- final View view = mViewAdapter.getView();
-
- mAnimAttributes.init(view);
-
- // Set up a low-duration slow-down animation IN the drag direction.
-
- // Exception: If wasn't dragging in 'forward' direction (or velocity=0 -- i.e. not dragging at all),
- // skip slow-down anim directly to the bounce-back.
- if (mVelocity == 0f || (mVelocity < 0 && mStartAttr.mDir) || (mVelocity > 0 && !mStartAttr.mDir)) {
- return createBounceBackAnimator(mAnimAttributes.mAbsOffset);
- }
-
- // dt = (Vt - Vo) / a; Vt=0 ==> dt = -Vo / a
- float slowdownDuration = -mVelocity / mDecelerateFactor;
- slowdownDuration = (slowdownDuration < 0 ? 0 : slowdownDuration); // Happens in counter-direction dragging
-
- // dx = (Vt^2 - Vo^2) / 2a; Vt=0 ==> dx = -Vo^2 / 2a
- float slowdownDistance = -mVelocity * mVelocity / mDoubleDecelerateFactor;
- float slowdownEndOffset = mAnimAttributes.mAbsOffset + slowdownDistance;
-
- ObjectAnimator slowdownAnim = createSlowdownAnimator(view, (int) slowdownDuration, slowdownEndOffset);
-
- // Set up the bounce back animation, bringing the view back into the original, pre-overscroll position (translation=0).
-
- ObjectAnimator bounceBackAnim = createBounceBackAnimator(slowdownEndOffset);
-
- // Play the 2 animations as a sequence.
- AnimatorSet wholeAnim = new AnimatorSet();
- wholeAnim.playSequentially(slowdownAnim, bounceBackAnim);
- return wholeAnim;
- }
-
- protected ObjectAnimator createSlowdownAnimator(View view, int slowdownDuration, float slowdownEndOffset) {
- ObjectAnimator slowdownAnim = ObjectAnimator.ofFloat(view, mAnimAttributes.mProperty, slowdownEndOffset);
- slowdownAnim.setDuration(slowdownDuration);
- slowdownAnim.setInterpolator(mBounceBackInterpolator);
- slowdownAnim.addUpdateListener(this);
- return slowdownAnim;
- }
-
- protected ObjectAnimator createBounceBackAnimator(float startOffset) {
-
- final View view = mViewAdapter.getView();
-
- // Duration is proportional to the view's size.
- float bounceBackDuration = (Math.abs(startOffset) / mAnimAttributes.mMaxOffset) * MAX_BOUNCE_BACK_DURATION_MS;
- ObjectAnimator bounceBackAnim = ObjectAnimator.ofFloat(view, mAnimAttributes.mProperty, mStartAttr.mAbsOffset);
- bounceBackAnim.setDuration(Math.max((int) bounceBackDuration, MIN_BOUNCE_BACK_DURATION_MS));
- bounceBackAnim.setInterpolator(mBounceBackInterpolator);
- bounceBackAnim.addUpdateListener(this);
- return bounceBackAnim;
- }
- }
-
- public OverScrollBounceEffectDecoratorBase(IOverScrollDecoratorAdapter viewAdapter, float decelerateFactor, float touchDragRatioFwd, float touchDragRatioBck) {
- mViewAdapter = viewAdapter;
-
- mBounceBackState = new BounceBackState(decelerateFactor);
- mOverScrollingState = new OverScrollingState(touchDragRatioFwd, touchDragRatioBck);
- mIdleState = new IdleState();
-
- mCurrentState = mIdleState;
-
- attach();
- }
-
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_MOVE:
- return mCurrentState.handleMoveTouchEvent(event);
-
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- return mCurrentState.handleUpOrCancelTouchEvent(event);
- }
-
- return false;
- }
-
- @Override
- public void setOverScrollStateListener(IOverScrollStateListener listener) {
- mStateListener = (listener != null ? listener : new ListenerStubs.OverScrollStateListenerStub());
- }
-
- @Override
- public void setOverScrollUpdateListener(IOverScrollUpdateListener listener) {
- mUpdateListener = (listener != null ? listener : new ListenerStubs.OverScrollUpdateListenerStub());
- }
-
- @Override
- public int getCurrentState() {
- return mCurrentState.getStateId();
- }
-
- @Override
- public View getView() {
- return mViewAdapter.getView();
- }
-
- protected void issueStateTransition(IDecoratorState state) {
- IDecoratorState oldState = mCurrentState;
- mCurrentState = state;
- mCurrentState.handleEntryTransition(oldState);
- }
-
- protected void attach() {
- getView().setOnTouchListener(this);
- getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
- }
-
- @Override
- public void detach() {
- if (mCurrentState != mIdleState) {
- Log.w(TAG, "Decorator detached while over-scroll is in effect. You might want to add a precondition of that getCurrentState()==STATE_IDLE, first.");
- }
- getView().setOnTouchListener(null);
- getView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
- }
-
- protected abstract MotionAttributes createMotionAttributes();
-
- protected abstract AnimationAttributes createAnimationAttributes();
-
- protected abstract void translateView(View view, float offset);
-
- protected abstract void translateViewAndEvent(View view, float offset, MotionEvent event);
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/RecyclerViewOverScrollDecorAdapter.java b/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/RecyclerViewOverScrollDecorAdapter.java
deleted file mode 100644
index 89e78e66..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/RecyclerViewOverScrollDecorAdapter.java
+++ /dev/null
@@ -1,223 +0,0 @@
-package org.nv95.openmanga.components.reader.recyclerpager.overscroll;
-
-import android.graphics.Canvas;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.StaggeredGridLayoutManager;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.view.View;
-
-import java.util.List;
-
-
-/**
- * @author amitd
- * @see HorizontalOverScrollBounceEffectDecorator
- * @see VerticalOverScrollBounceEffectDecorator
- */
-public class RecyclerViewOverScrollDecorAdapter implements IOverScrollDecoratorAdapter {
-
- /**
- * A delegation of the adapter implementation of this view that should provide the processing
- * of {@link #isInAbsoluteStart()} and {@link #isInAbsoluteEnd()}. Essentially needed simply
- * because the implementation depends on the layout manager implementation being used.
- */
- protected interface Impl {
- boolean isInAbsoluteStart();
-
- boolean isInAbsoluteEnd();
- }
-
- protected final RecyclerView mRecyclerView;
- protected final Impl mImpl;
-
- protected boolean mIsItemTouchInEffect = false;
-
- public RecyclerViewOverScrollDecorAdapter(RecyclerView recyclerView) {
-
- mRecyclerView = recyclerView;
-
- final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
- if (layoutManager instanceof LinearLayoutManager ||
- layoutManager instanceof StaggeredGridLayoutManager) {
- final int orientation =
- (layoutManager instanceof LinearLayoutManager
- ? ((LinearLayoutManager) layoutManager).getOrientation()
- : ((StaggeredGridLayoutManager) layoutManager).getOrientation());
-
- if (orientation == LinearLayoutManager.HORIZONTAL) {
- mImpl = new ImplHorizLayout();
- } else {
- mImpl = new ImplVerticalLayout();
- }
- } else {
- throw new IllegalArgumentException("Recycler views with custom layout managers are not supported by this adapter out of the box." +
- "Try implementing and providing an explicit 'impl' parameter to the other c'tors, or otherwise create a custom adapter subclass of your own.");
- }
- }
-
- public RecyclerViewOverScrollDecorAdapter(RecyclerView recyclerView, Impl impl) {
- mRecyclerView = recyclerView;
- mImpl = impl;
- }
-
- public RecyclerViewOverScrollDecorAdapter(RecyclerView recyclerView, ItemTouchHelper.Callback itemTouchHelperCallback) {
- this(recyclerView);
- setUpTouchHelperCallback(itemTouchHelperCallback);
- }
-
- public RecyclerViewOverScrollDecorAdapter(RecyclerView recyclerView, Impl impl, ItemTouchHelper.Callback itemTouchHelperCallback) {
- this(recyclerView, impl);
- setUpTouchHelperCallback(itemTouchHelperCallback);
- }
-
- protected void setUpTouchHelperCallback(final ItemTouchHelper.Callback itemTouchHelperCallback) {
- new ItemTouchHelper(new ItemTouchHelperCallbackWrapper(itemTouchHelperCallback) {
- @Override
- public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
- mIsItemTouchInEffect = actionState != 0;
- super.onSelectedChanged(viewHolder, actionState);
- }
- }).attachToRecyclerView(mRecyclerView);
- }
-
- @Override
- public View getView() {
- return mRecyclerView;
- }
-
- @Override
- public boolean isInAbsoluteStart() {
- return !mIsItemTouchInEffect && mImpl.isInAbsoluteStart();
- }
-
- @Override
- public boolean isInAbsoluteEnd() {
- return !mIsItemTouchInEffect && mImpl.isInAbsoluteEnd();
- }
-
- protected class ImplHorizLayout implements Impl {
-
- @Override
- public boolean isInAbsoluteStart() {
- return !mRecyclerView.canScrollHorizontally(-1);
- }
-
- @Override
- public boolean isInAbsoluteEnd() {
- return !mRecyclerView.canScrollHorizontally(1);
- }
- }
-
- protected class ImplVerticalLayout implements Impl {
-
- @Override
- public boolean isInAbsoluteStart() {
- return !mRecyclerView.canScrollVertically(-1);
- }
-
- @Override
- public boolean isInAbsoluteEnd() {
- return !mRecyclerView.canScrollVertically(1);
- }
- }
-
- private static class ItemTouchHelperCallbackWrapper extends ItemTouchHelper.Callback {
-
- final ItemTouchHelper.Callback mCallback;
-
- private ItemTouchHelperCallbackWrapper(ItemTouchHelper.Callback callback) {
- mCallback = callback;
- }
-
- @Override
- public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
- return mCallback.getMovementFlags(recyclerView, viewHolder);
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
- return mCallback.onMove(recyclerView, viewHolder, target);
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- mCallback.onSwiped(viewHolder, direction);
- }
-
- @Override
- public int convertToAbsoluteDirection(int flags, int layoutDirection) {
- return mCallback.convertToAbsoluteDirection(flags, layoutDirection);
- }
-
- @Override
- public boolean canDropOver(RecyclerView recyclerView, RecyclerView.ViewHolder current, RecyclerView.ViewHolder target) {
- return mCallback.canDropOver(recyclerView, current, target);
- }
-
- @Override
- public boolean isLongPressDragEnabled() {
- return mCallback.isLongPressDragEnabled();
- }
-
- @Override
- public boolean isItemViewSwipeEnabled() {
- return mCallback.isItemViewSwipeEnabled();
- }
-
- @Override
- public int getBoundingBoxMargin() {
- return mCallback.getBoundingBoxMargin();
- }
-
- @Override
- public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
- return mCallback.getSwipeThreshold(viewHolder);
- }
-
- @Override
- public float getMoveThreshold(RecyclerView.ViewHolder viewHolder) {
- return mCallback.getMoveThreshold(viewHolder);
- }
-
- @Override
- public RecyclerView.ViewHolder chooseDropTarget(RecyclerView.ViewHolder selected, List dropTargets, int curX, int curY) {
- return mCallback.chooseDropTarget(selected, dropTargets, curX, curY);
- }
-
- @Override
- public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
- mCallback.onSelectedChanged(viewHolder, actionState);
- }
-
- @Override
- public void onMoved(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, int fromPos, RecyclerView.ViewHolder target, int toPos, int x, int y) {
- mCallback.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y);
- }
-
- @Override
- public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
- mCallback.clearView(recyclerView, viewHolder);
- }
-
- @Override
- public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
- mCallback.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
- }
-
- @Override
- public void onChildDrawOver(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
- mCallback.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
- }
-
- @Override
- public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {
- return mCallback.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
- }
-
- @Override
- public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize, int viewSizeOutOfBounds, int totalSize, long msSinceStartScroll) {
- return mCallback.interpolateOutOfBoundsScroll(recyclerView, viewSize, viewSizeOutOfBounds, totalSize, msSinceStartScroll);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/VerticalOverScrollBounceEffectDecorator.java b/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/VerticalOverScrollBounceEffectDecorator.java
deleted file mode 100644
index 671b3331..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/recyclerpager/overscroll/VerticalOverScrollBounceEffectDecorator.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package org.nv95.openmanga.components.reader.recyclerpager.overscroll;
-
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * A concrete implementation of {@link OverScrollBounceEffectDecoratorBase} for a vertical orientation.
- *
- * @author amit
- */
-public class VerticalOverScrollBounceEffectDecorator extends OverScrollBounceEffectDecoratorBase {
-
- protected static class MotionAttributesVertical extends MotionAttributes {
-
- public boolean init(View view, MotionEvent event) {
-
- // We must have history available to calc the dx. Normally it's there - if it isn't temporarily,
- // we declare the event 'invalid' and expect it in consequent events.
- if (event.getHistorySize() == 0) {
- return false;
- }
-
- // Allow for counter-orientation-direction operations (e.g. item swiping) to run fluently.
- final float dy = event.getY(0) - event.getHistoricalY(0, 0);
- final float dx = event.getX(0) - event.getHistoricalX(0, 0);
- if (Math.abs(dx) > Math.abs(dy)) {
- return false;
- }
-
- mAbsOffset = view.getTranslationY();
- mDeltaOffset = dy;
- mDir = mDeltaOffset > 0;
-
- return true;
- }
- }
-
- protected static class AnimationAttributesVertical extends AnimationAttributes {
-
- public AnimationAttributesVertical() {
- mProperty = View.TRANSLATION_Y;
- }
-
- @Override
- protected void init(View view) {
- mAbsOffset = view.getTranslationY();
- mMaxOffset = view.getHeight();
- }
- }
-
- /**
- * C'tor, creating the effect with default arguments:
- *
Touch-drag ratio in 'forward' direction will be set to DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD.
- *
Touch-drag ratio in 'backwards' direction will be set to DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK.
- *
Deceleration factor (for the bounce-back effect) will be set to DEFAULT_DECELERATE_FACTOR.
- *
- * @param viewAdapter The view's encapsulation.
- */
- public VerticalOverScrollBounceEffectDecorator(IOverScrollDecoratorAdapter viewAdapter) {
- this(viewAdapter, DEFAULT_TOUCH_DRAG_MOVE_RATIO_FWD, DEFAULT_TOUCH_DRAG_MOVE_RATIO_BCK, DEFAULT_DECELERATE_FACTOR);
- }
-
- /**
- * C'tor, creating the effect with explicit arguments.
- *
- * @param viewAdapter The view's encapsulation.
- * @param touchDragRatioFwd Ratio of touch distance to actual drag distance when in 'forward' direction.
- * @param touchDragRatioBck Ratio of touch distance to actual drag distance when in 'backward'
- * direction (opposite to initial one).
- * @param decelerateFactor Deceleration factor used when decelerating the motion to create the
- * bounce-back effect.
- */
- public VerticalOverScrollBounceEffectDecorator(IOverScrollDecoratorAdapter viewAdapter,
- float touchDragRatioFwd, float touchDragRatioBck, float decelerateFactor) {
- super(viewAdapter, decelerateFactor, touchDragRatioFwd, touchDragRatioBck);
- }
-
- @Override
- protected MotionAttributes createMotionAttributes() {
- return new MotionAttributesVertical();
- }
-
- @Override
- protected AnimationAttributes createAnimationAttributes() {
- return new AnimationAttributesVertical();
- }
-
- @Override
- protected void translateView(View view, float offset) {
- view.setTranslationY(offset);
- }
-
- @Override
- protected void translateViewAndEvent(View view, float offset, MotionEvent event) {
- view.setTranslationY(offset);
- event.offsetLocation(offset - event.getY(0), 0f);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncBitmapDecoder.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncBitmapDecoder.java
deleted file mode 100644
index 91482780..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncBitmapDecoder.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import java.util.concurrent.Executor;
-
-/**
- * Created by admin on 02.08.17.
- */
-
-public class AsyncBitmapDecoder implements Runnable {
-
- private final String mFilename;
- private final DecodeCallback mCallback;
-
- public AsyncBitmapDecoder(String filename, DecodeCallback callback) {
- mFilename = filename;
- mCallback = callback;
- }
-
- @Override
- public void run() {
- try {
- Bitmap bitmap = BitmapFactory.decodeFile(mFilename);
- mCallback.onBitmapDecoded(bitmap);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- public interface DecodeCallback {
- @WorkerThread
- void onBitmapDecoded(@Nullable Bitmap bitmap);
- }
-
- public static void decode(String filename, DecodeCallback callback, Executor executor) {
- executor.execute(new AsyncBitmapDecoder(filename, callback));
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncScroller.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncScroller.java
deleted file mode 100644
index 5d011a7c..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/AsyncScroller.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.content.Context;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.Nullable;
-import android.widget.Scroller;
-
-
-/**
- * Created by admin on 15.08.17.
- */
-
-public class AsyncScroller extends Scroller implements Handler.Callback {
-
- private final OnFlyListener mListener;
- private final Handler mHandler;
- @Nullable
- private WatcherThread mThread = null;
-
- public AsyncScroller(Context context, OnFlyListener listener) {
- super(context);
- mHandler = new Handler(this);
- mListener = listener;
- }
-
- @Override
- public void fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) {
- if (mThread != null) {
- mThread.interrupt();
- }
- mThread = new WatcherThread(startX, startY);
- super.fling(startX, startY, velocityX, velocityY, minX, maxX, minY, maxY);
- mThread.start();
- }
-
- @Override
- public void startScroll(int startX, int startY, int dx, int dy) {
- if (mThread != null) {
- mThread.interrupt();
- }
- mThread = new WatcherThread(startX, startY);
- super.startScroll(startX, startY, dx, dy);
- mThread.start();
- }
-
- @Override
- public void startScroll(int startX, int startY, int dx, int dy, int duration) {
- if (mThread != null) {
- mThread.interrupt();
- }
- mThread = new WatcherThread(startX, startY);
- super.startScroll(startX, startY, dx, dy, duration);
- mThread.start();
- }
-
- @Override
- public boolean handleMessage(Message message) {
- mListener.onScrolled(message.arg1, message.arg2);
- return false;
- }
-
- private class WatcherThread extends Thread {
-
- private int oldX, oldY;
-
- public WatcherThread(int oldX, int oldY) {
- this.oldX = oldX;
- this.oldY = oldY;
- }
-
- @Override
- public void run() {
- while (!isInterrupted() && !AsyncScroller.this.isFinished()) {
- if (computeScrollOffset()) {
- Message msg = new Message();
- msg.arg1 = getCurrX();
- msg.arg2 = getCurrY();
- if (msg.arg1 != oldX || msg.arg2 != oldY) {
- mHandler.sendMessage(msg);
- oldX = msg.arg1;
- oldY = msg.arg2;
- }
- }
- }
- super.run();
- }
- }
-
- @Override
- public void abortAnimation() {
- if (mThread != null) {
- mThread.interrupt();
- mThread = null;
- }
- super.abortAnimation();
- }
-
- public interface OnFlyListener {
- void onScrolled(int currentX, int currentY);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ChangesListener.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ChangesListener.java
deleted file mode 100644
index 1b2d233f..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ChangesListener.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-/**
- * Created by admin on 03.08.17.
- */
-
-public interface ChangesListener {
-
- void notifyDataSetChanged();
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/DrawableView.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/DrawableView.java
deleted file mode 100644
index c31b23af..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/DrawableView.java
+++ /dev/null
@@ -1,348 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.support.annotation.MainThread;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-import android.util.AttributeSet;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Created by admin on 14.08.17.
- */
-
-public abstract class DrawableView extends SurfaceView implements SurfaceHolder.Callback, ScaleGestureDetector.OnScaleGestureListener, AsyncScroller.OnFlyListener, ScaleAnimator.ZoomCallback {
-
- @Nullable
- private DrawThread mThread;
- private final GestureDetector mGestureDetector;
- private final ScaleGestureDetector mScaleDetector;
- private final AsyncScroller mScroller;
- private final Rect mViewport;
- protected final AtomicReference mScrollState;
-
- public DrawableView(Context context) {
- this(context, null, 0);
- }
-
- public DrawableView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public DrawableView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mGestureDetector = new GestureDetector(context, new GestureListener());
- mScaleDetector = new ScaleGestureDetector(context, this);
- mScroller = new AsyncScroller(context, this);
- mViewport = new Rect(0, 0, 0, 0);
- mThread = null;
- mScrollState = new AtomicReference<>(new ScrollState(1f, 0, 0));
- SurfaceHolder holder = getHolder();
- holder.addCallback(this);
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder surfaceHolder) {
- mThread = new DrawThread(surfaceHolder);
- mThread.start();
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
- int oldHeight = mViewport.height();
- int oldWidth = mViewport.width();
- mViewport.set(0, 0, width, height);
- onViewportChanged(oldHeight, oldWidth, height, width);
- forceRedraw();
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
- if (mThread != null) {
- mThread.interrupt();
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mGestureDetector.onTouchEvent(event);
- mScaleDetector.onTouchEvent(event);
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- ScrollState state = mScrollState.get();
-
- float scaleFactor = state.scale;
- scaleFactor *= detector.getScaleFactor();
- if (scaleFactor < 1f) {
- if (state.scale == 1f) {
- return false;
- } else {
- scaleFactor = 1f;
- }
- } else if (scaleFactor > 2f) {
- if (state.scale == 2f) {
- return false;
- } else {
- scaleFactor = 2f;
- }
- }
-
-
- float scrollFactor = scaleFactor - state.scale;
- int newScrollX = (int) (state.scrollX + detector.getFocusX() * scrollFactor);
- int newScrollY = (int) (state.scrollY + detector.getFocusY() * scrollFactor);
-
- mScrollState.set(new ScrollState(scaleFactor, newScrollX, newScrollY));
- onZoomChanged();
- return true;
- }
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
- return true;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
-
- }
-
- @Override
- public void onZoomAnimated(float scale, int scrollX, int scrollY) {
- Rect bounds = computeScrollRange(scale);
-
- if (scrollX < bounds.left) scrollX = bounds.left;
- else if (scrollX > bounds.right) scrollX = bounds.right;
-
- if (scrollY < bounds.top) scrollY = bounds.top;
- else if (scrollY > bounds.bottom) scrollY = bounds.bottom;
-
- mScrollState.set(new ScrollState(scale, scrollX, scrollY));
- }
-
- @Override
- public void onZoomAnimationFinished() {
- onZoomChanged();
- }
-
- private class GestureListener extends GestureDetector.SimpleOnGestureListener {
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- Rect bounds = getScrollBounds();
- ScrollState state = mScrollState.get();
- mScroller.fling(
- state.scrollX,
- state.scrollY,
- -(int) velocityX,
- -(int) velocityY,
- bounds.left,
- bounds.right,
- bounds.top,
- bounds.bottom);
- awakenScrollBars(mScroller.getDuration());
- return true;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (e2.getPointerCount() != 1) return false;
-
- Rect bounds = getScrollBounds();
- ScrollState state = mScrollState.get();
- int scrollY = (int) (state.scrollY + distanceY);
- int scrollX = (int) (state.scrollX + distanceX);
-
- if (scrollX < bounds.left) scrollX = bounds.left;
- else if (scrollX > bounds.right) scrollX = bounds.right;
-
- if (scrollY < bounds.top) scrollY = bounds.top;
- else if (scrollY > bounds.bottom) scrollY = bounds.bottom;
-
- mScrollState.set(state.offset(scrollX, scrollY));
-
- return super.onScroll(e1, e2, distanceX, distanceY);
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- if (e.getPointerCount() == 1) {
- mScroller.abortAnimation();
- }
- return super.onDown(e);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- ScaleAnimator animator = new ScaleAnimator(DrawableView.this);
- ScrollState state = mScrollState.get();
- if (state.scale == 1f) {
- animator.animate(
- state.scale,
- state.scrollX,
- state.scrollY,
- 1.6f,
- (int) (state.scrollX + e.getX() * 1.6f),
- (int) (state.scrollY + e.getY() * 1.6f)
- );
- } else {
- animator.animate(
- state.scale,
- state.scrollX,
- state.scrollY,
- 1f,
- (int) (state.scrollX - e.getX() * 1.6f),
- (int) (state.scrollY - e.getY() * 1.6f)
- );
- }
- return super.onDoubleTap(e);
- }
- }
-
-
- @Override
- public void onScrolled(int currentX, int currentY) {
- mScrollState.set(mScrollState.get().offset(currentX, currentY));
- }
-
- public void forceRedraw() {
- if (mThread != null) {
- mThread.force = true;
- }
- }
-
- @Override
- public boolean canScrollHorizontally(int direction) {
- Rect bounds = getScrollBounds();
- ScrollState state = mScrollState.get();
- if (direction < 0) {
- return state.scrollX > bounds.right;
- } else if (direction > 0) {
- return state.scrollX < bounds.left;
- } else return super.canScrollHorizontally(direction);
- }
-
- @Override
- public boolean canScrollVertically(int direction) {
- Rect bounds = getScrollBounds();
- ScrollState state = mScrollState.get();
- if (direction < 0) {
- return state.scrollY > bounds.top;
- } else if (direction > 0) {
- return state.scrollY < bounds.bottom;
- } else return super.canScrollVertically(direction);
- }
-
- private class DrawThread extends Thread {
-
- private final SurfaceHolder mSurface;
-
- private int lastOffsetX = 0, lastOffsetY = 0;
- private float lastZoom = 0;
- boolean force;
-
- DrawThread(SurfaceHolder surface) {
- mSurface = surface;
- }
-
- @Override
- public void run() {
- Canvas canvas;
- while (!interrupted()) {
- canvas = null;
- try {
- // получаем объект Canvas и выполняем отрисовку
- ScrollState state = mScrollState.get();
- int offsetX = -state.scrollX;
- int offsetY = -state.scrollY;
- if (!force && lastOffsetX == offsetX && lastOffsetY == offsetY && lastZoom == state.scale) {
- continue;
- }
- force = false;
- canvas = mSurface.lockCanvas(null);
- synchronized (mSurface) {
- //long time = System.currentTimeMillis();
- onSurfaceDraw(canvas, lastOffsetX - offsetX, lastOffsetY - offsetY, state.scale);
- /*time = System.currentTimeMillis() - time;
- Log.d("FPS", 1f / time * 1000f + " fps");*/
-
- lastOffsetX = offsetX;
- lastOffsetY = offsetY;
- lastZoom = state.scale;
- }
- } catch (Exception e) {
- e.printStackTrace();
- } finally {
- if (canvas != null) {
- // отрисовка выполнена. выводим результат на экран
- mSurface.unlockCanvasAndPost(canvas);
- }
- }
- }
- }
- }
-
- public boolean smoothScrollBy(int dX, int dY) {
- mScroller.forceFinished(true);
- Rect bounds = getScrollBounds();
- ScrollState state = mScrollState.get();
- if (dY < 0) {
- dY = Math.max(dY, bounds.top - state.scrollY);
- } else if (dY > 0) {
- dY = Math.min(dY, bounds.bottom - state.scrollY);
- }
- if (dX < 0) {
- dX = Math.max(dX, bounds.left - state.scrollY);
- } else if (dX > 0) {
- dX = Math.min(dX, bounds.right - state.scrollY);
- }
- if (dX == 0 && dY == 0) {
- return false;
- }
- mScroller.startScroll(
- state.scrollX,
- state.scrollY,
- dX,
- dY,
- 800
- );
- return true;
- }
-
- public float getScaleFactor() {
- return mScrollState.get().scale;
- }
-
- public int getViewportWidth() {
- return mViewport.width();
- }
-
- public int getViewportHeight() {
- return mViewport.height();
- }
-
- @WorkerThread
- protected abstract void onSurfaceDraw(Canvas canvas, int dX, int dY, float zoom);
-
- protected void onIdle(){}
-
- protected void onViewportChanged(int oldHeight, int oldWidth, int newHeight, int newWidth){};
-
- protected void onZoomChanged(){};
-
- @MainThread
- protected abstract Rect getScrollBounds();
-
- protected abstract Rect computeScrollRange(float scale);
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ImagesPool.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ImagesPool.java
deleted file mode 100644
index b5450796..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ImagesPool.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-
-import org.nv95.openmanga.components.reader.PageLoader;
-import org.nv95.openmanga.components.reader.PageWrapper;
-
-import java.util.Collections;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-/**
- * Created by admin on 01.08.17.
- */
-
-public class ImagesPool {
-
- private final PagesLruCache mCache;
- private final PageLoader mLoader;
- private final ChangesListener mListener;
- private final ExecutorService mExecutor;
- private final Set mDecodeQueue;
- private int mBaseWidth = 0;
-
- public ImagesPool(Context context, ChangesListener listener) {
- mExecutor = Executors.newSingleThreadExecutor();
- mLoader = new PageLoader(context);
- mListener = listener;
- mDecodeQueue = Collections.synchronizedSet(new TreeSet());
- mCache = new PagesLruCache(4);
- }
-
- @Nullable
- public PageImage get(int pos) {
- PageImage page = mCache.get(pos);
- if (page != null && !page.isRecycled()) {
- return page;
- }
- load(pos);
- return null;
- }
-
- public void prefetch(final int pos) {
- if (!mCache.contains(pos)) {
- load(pos);
- }
- }
-
- private void load(final int pos) {
- PageWrapper pw = mLoader.requestPage(pos);
- if (pw != null && pw.isLoaded() && !mDecodeQueue.contains(pos)) {
- mDecodeQueue.add(pos);
- AsyncBitmapDecoder.decode(pw.getFilename(), new AsyncBitmapDecoder.DecodeCallback() {
- @WorkerThread
- @Override
- public void onBitmapDecoded(@Nullable Bitmap bitmap) {
- if (bitmap != null) {
- int w = bitmap.getWidth();
- int h = (int)(mBaseWidth / (float)w * bitmap.getHeight());
- mCache.put(pos, new PageImage(Bitmap.createScaledBitmap(
- bitmap,
- mBaseWidth,
- h,
- true
- )));
- bitmap.recycle();
- mListener.notifyDataSetChanged();
- }
- mDecodeQueue.remove(pos);
- }
- }, mExecutor);
- }
- }
-
- public PageLoader getLoader() {
- return mLoader;
- }
-
- public void recycle() {
- mCache.evictAll();
- }
-
- public void setBaseWidth(int width) {
- if (mBaseWidth != width) {
- mCache.evictAll();
- mBaseWidth = width;
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PageImage.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PageImage.java
deleted file mode 100644
index 3b723338..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PageImage.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-
-import org.nv95.openmanga.utils.DecartUtils;
-
-/**
- * Created by admin on 01.08.17.
- */
-
-public class PageImage {
-
- @NonNull
- private final Bitmap mBitmap;
-
- public PageImage(@NonNull Bitmap bitmap) {
- mBitmap = bitmap;
- }
-
- public int getHeight() {
- return mBitmap.getHeight();
- }
-
- public int getWidth() {
- return mBitmap.getWidth();
- }
-
- public Rect draw(Canvas canvas, Paint paint, int offsetX, int offsetY, Rect viewport, float scale) {
- Rect outRect = new Rect(
- offsetX,
- offsetY,
- ((int) (offsetX + (getWidth() * scale))),
- (int) (offsetY + (getHeight() * scale))
- );
- DecartUtils.trimRect(outRect, viewport);
- if (!isRecycled()) {
- Rect inRect = new Rect(outRect);
- DecartUtils.translateRect(inRect, -offsetX, -offsetY);
- if (scale != 1f) {
- DecartUtils.scaleRect(inRect, 1f / scale);
- }
- canvas.drawBitmap(mBitmap, inRect, outRect, paint);
- }
- return outRect;
- }
-
- public boolean isRecycled() {
- return mBitmap.isRecycled();
- }
-
- public void recycle() {
- mBitmap.recycle();
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PagesLruCache.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PagesLruCache.java
deleted file mode 100644
index 4073b085..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/PagesLruCache.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.util.LruCache;
-
-/**
- * Created by admin on 02.08.17.
- */
-
-public class PagesLruCache extends LruCache {
-
- public PagesLruCache(int maxSize) {
- super(maxSize);
- }
-
- @Override
- protected void entryRemoved(boolean evicted, Integer key, PageImage oldValue, PageImage newValue) {
- oldValue.recycle();
- }
-
- public boolean contains(Integer key) {
- PageImage value = get(key);
- return value != null && !value.isRecycled();
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScaleAnimator.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScaleAnimator.java
deleted file mode 100644
index fb3f3695..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScaleAnimator.java
+++ /dev/null
@@ -1,95 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.animation.Animator;
-import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
-import android.support.annotation.Nullable;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-/**
- * Created by admin on 15.08.17.
- */
-
-public class ScaleAnimator implements ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
-
- private final ZoomCallback mCallback;
- @Nullable
- private ValueAnimator mAnimator;
-
- public ScaleAnimator(ZoomCallback callback) {
- mCallback = callback;
- }
-
- public void animate(float initialScale, int initialX, int initialY, float targetScale, int targetX, int targetY) {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- mAnimator = ValueAnimator.ofObject(
- new ZoomEvaluator(),
- new ZoomState(initialScale, initialX, initialY),
- new ZoomState(targetScale, targetX, targetY)
- );
- assert mAnimator != null;
- mAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
- mAnimator.setDuration(500);
- mAnimator.addUpdateListener(this);
- mAnimator.addListener(this);
- mAnimator.start();
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- ZoomState curState = (ZoomState) valueAnimator.getAnimatedValue();
- mCallback.onZoomAnimated(curState.scale, curState.offsetX, curState.offsetY);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
-
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- mCallback.onZoomAnimationFinished();
- }
-
- @Override
- public void onAnimationCancel(Animator animator) {
-
- }
-
- @Override
- public void onAnimationRepeat(Animator animator) {
-
- }
-
- public static class ZoomState {
-
- final float scale;
- final int offsetX;
- final int offsetY;
-
- ZoomState(float scale, int offsetX, int offsetY) {
- this.scale = scale;
- this.offsetX = offsetX;
- this.offsetY = offsetY;
- }
- }
-
- private static class ZoomEvaluator implements TypeEvaluator {
-
- @Override
- public ZoomState evaluate(float fraction, ZoomState startValue, ZoomState endValue) {
- return new ZoomState(
- startValue.scale + fraction * (endValue.scale - startValue.scale),
- (int)(startValue.offsetX + fraction * (endValue.offsetX - startValue.offsetX)),
- (int)(startValue.offsetY + fraction * (endValue.offsetY - startValue.offsetY))
- );
- }
- }
-
- public interface ZoomCallback {
- void onZoomAnimated(float scale, int scrollX, int scrollY);
- void onZoomAnimationFinished();
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScrollState.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScrollState.java
deleted file mode 100644
index e4d07807..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/ScrollState.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-/**
- * Created by admin on 15.08.17.
- */
-
-class ScrollState {
-
- final float scale;
- final int scrollX;
- final int scrollY;
-
- ScrollState(float scale, int scrollX, int scrollY) {
- this.scale = scale;
- this.scrollX = scrollX;
- this.scrollY = scrollY;
- }
-
- public ScrollState scale(float newScale) {
- return new ScrollState(newScale, scrollX, scrollY);
- }
-
- public ScrollState offsetX(int newOffsetX) {
- return new ScrollState(scale, newOffsetX, scrollY);
- }
-
- public ScrollState offsetY(int newOffsetY) {
- return new ScrollState(scale, scrollX, newOffsetY);
- }
-
- public ScrollState offset(int newOffsetX, int newOffsetY) {
- return new ScrollState(scale, newOffsetX, newOffsetY);
- }
-
- public ScrollState offsetRel(int deltaX, int deltaY) {
- return new ScrollState(scale, scrollX + deltaX, scrollY + deltaY);
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/WebtoonReader.java b/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/WebtoonReader.java
deleted file mode 100644
index ab4a323d..00000000
--- a/app/src/main/java/org/nv95/openmanga/components/reader/webtoon/WebtoonReader.java
+++ /dev/null
@@ -1,411 +0,0 @@
-package org.nv95.openmanga.components.reader.webtoon;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Message;
-import android.support.annotation.Nullable;
-import android.support.annotation.WorkerThread;
-import android.util.AttributeSet;
-import android.util.SparseIntArray;
-import android.view.MotionEvent;
-
-import org.nv95.openmanga.components.reader.MangaReader;
-import org.nv95.openmanga.components.reader.OnOverScrollListener;
-import org.nv95.openmanga.components.reader.OverscrollDetector;
-import org.nv95.openmanga.components.reader.PageLoadListener;
-import org.nv95.openmanga.components.reader.PageLoader;
-import org.nv95.openmanga.components.reader.PageWrapper;
-import org.nv95.openmanga.components.reader.recyclerpager.RecyclerViewPager;
-import org.nv95.openmanga.items.MangaPage;
-import org.nv95.openmanga.utils.DecartUtils;
-import org.nv95.openmanga.utils.InternalLinkMovement;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeMap;
-import java.util.Vector;
-
-/**
- * Created by admin on 14.08.17.
- */
-
-public class WebtoonReader extends DrawableView implements MangaReader, PageLoadListener,
- ChangesListener, Handler.Callback {
-
- private static final int MSG_IMGSIZE = 1;
- private static final int MSG_PAGE_CHANGED = 2;
-
- private ImagesPool mPool;
- private final Paint mPaint;
- private final TreeMap mHeights;
- private int mFullHeight = 0;
- private final Handler mHandler;
- private int mCurrentPage;
- private final Vector mPageChangeListeners;
- private volatile int mOffsetX = 0, mOffsetY = 0;
- private final Rect mScrollBounds;
- private int mTopPage, mTopPageOffset;
- private volatile boolean mShowNumbers;
- private final SparseIntArray mProgressMap;
- @Nullable
- private OverscrollDetector mOverscrollDetector;
-
- public WebtoonReader(Context context) {
- this(context, null, 0);
- }
-
- public WebtoonReader(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WebtoonReader(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setHorizontalScrollBarEnabled(false);
- setVerticalScrollBarEnabled(true);
- mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mPaint.setColor(Color.DKGRAY);
- mPaint.setSubpixelText(true);
- mPaint.setTextSize(LayoutUtils.DpToPx(getResources(), 18));
- mHeights = new TreeMap<>();
- mProgressMap = new SparseIntArray();
- mHandler = new Handler(this);
- mPageChangeListeners = new Vector<>();
- mCurrentPage = 0;
- mTopPage = mTopPageOffset = 0;
- mScrollBounds = new Rect();
- mOverscrollDetector = null;
- }
-
- @WorkerThread
- @Override
- protected void onSurfaceDraw(Canvas canvas, int dX, int dY, float zoom) {
- canvas.drawColor(Color.LTGRAY);
- final Rect viewport = canvas.getClipBounds();
- if (mPool != null) {
- mOffsetY -= dY;
- mOffsetX -= dX;
- int offsetY = mOffsetY;
- int page = mCurrentPage;
- //draw previous pages
- if (offsetY > 0) {
- while (offsetY > 0) {
- PageImage image = mPool.get(page - 1);
- if (image == null) break;
- notifyPageHeight(page, image.getHeight());
- offsetY -= image.getHeight() * zoom;
- mOffsetY = offsetY;
- page--;
- notifyPageChanged(mCurrentPage - 1);
- }
- mPool.prefetch(page-1);
- }
- //draw current page and next
- while (offsetY < canvas.getHeight()) {
- PageImage image = mPool.get(page);
- if (image == null) break;
- notifyPageHeight(page, image.getHeight());
- Rect rect = image.draw(canvas, mPaint, mOffsetX, offsetY, viewport, zoom);
- if (rect.bottom <= 0) {
- mOffsetY = rect.bottom;
- notifyPageChanged(mCurrentPage + 1);
- mPool.prefetch(page + 2);
- }
- page++;
- offsetY = rect.bottom;
- }
- //prefetch next
- //mPool.prefetch(page);
-
- int progress = mProgressMap.get(mCurrentPage, 0);
- String text = "";
- if (mShowNumbers) {
- text += String.valueOf(mCurrentPage + 1);
- if (progress == -1) {
- text += " - ERROR";
- } else if (progress != 0 && progress != 100) {
- text += " - " + progress + "%";
- }
- } else {
- if (progress == -1) {
- text += "ERROR";
- } else if (progress != 0 && progress != 100) {
- text += progress + "%";
- }
- }
- canvas.drawText(text, 5, canvas.getHeight() - 10, mPaint);
- }
- }
-
- private void recomputeWidth() {
- int count = mHeights.size();
- if (count == 0) {
- mFullHeight = getViewportHeight();
- mTopPageOffset = 0;
- return;
- }
- final int total = getItemCount();
- int sum = 0;
-
- for (int o : mHeights.values()) {
- sum += o;
- }
- int avgHeight = sum / count;
- sum += avgHeight * (total - count);
-
- mTopPageOffset = 0;
- for (int i = 0; i < mTopPage; i++) {
- Integer o = mHeights.get(i);
- mTopPageOffset += o == null ? avgHeight : o;
- }
- mFullHeight = sum;
- recomputeScrollRange();
- }
-
- @Override
- protected void onViewportChanged(int oldHeight, int oldWidth, int newHeight, int newWidth) {
- if (mPool != null) {
- mPool.setBaseWidth(newWidth);
- }
- if (oldHeight != 0) {
- mFullHeight = mFullHeight / oldHeight * newHeight;
- for (Integer i : mHeights.keySet()) {
- mHeights.put(i, mHeights.get(i) / oldHeight * newHeight);
- }
- } else {
- mHeights.clear();
- }
- }
-
- @Override
- protected void onZoomChanged() {
- recomputeScrollRange();
- }
-
- private void recomputeScrollRange() {
- mScrollBounds.top = 0;
- mScrollBounds.left = 0;
- mScrollBounds.bottom = mFullHeight;
- mScrollBounds.right = getViewportWidth();
- DecartUtils.scaleRect(mScrollBounds, getScaleFactor());
- DecartUtils.translateRect(mScrollBounds, 0, -mTopPageOffset);
- mScrollBounds.bottom -= getViewportHeight();
- mScrollBounds.right -= getViewportWidth();
- }
-
- @Override
- protected void onIdle() {
- //recomputeWidth();
- }
-
- @Override
- protected Rect getScrollBounds() {
- return mScrollBounds;
- }
-
- @Override
- public void applyConfig(boolean vertical, boolean reverse, boolean sticky, boolean showNumbers) {
- mShowNumbers = showNumbers;
- }
-
- @Override
- public boolean scrollToNext(boolean animate) {
- return smoothScrollBy(0, (int) (getViewportHeight() * 0.9f));
- }
-
- @Override
- public boolean scrollToPrevious(boolean animate) {
- return smoothScrollBy(0, (int) -(getViewportHeight() * 0.9f));
- }
-
- @Override
- public int getCurrentPosition() {
- return mCurrentPage;
- }
-
- @Override
- public void scrollToPosition(int position) {
- int oldPage = mCurrentPage;
- mCurrentPage = position;
- mOffsetY = 0;
- mScrollState.set(mScrollState.get().offsetY(0));
- mTopPage = position;
- recomputeWidth();
- forceRedraw();
- for (RecyclerViewPager.OnPageChangedListener o : mPageChangeListeners) {
- o.OnPageChanged(oldPage, mCurrentPage);
- }
- }
-
- @Override
- public void setTapNavs(boolean val) {
-
- }
-
- @Override
- public void addOnPageChangedListener(RecyclerViewPager.OnPageChangedListener listener) {
- mPageChangeListeners.add(listener);
- }
-
- @Override
- public void setOnOverScrollListener(OnOverScrollListener listener) {
- mOverscrollDetector = new OverscrollDetector(listener);
- mOverscrollDetector.setDirections(true, false);
- }
-
- @Override
- public boolean isReversed() {
- return false;
- }
-
- @Override
- public int getItemCount() {
- return getLoader().getWrappersList().size();
- }
-
- @Override
- public void initAdapter(Context context, InternalLinkMovement.OnLinkClickListener linkListener) {
- mPool = new ImagesPool(context, this);
- mPool.getLoader().addListener(this);
- }
-
- @Override
- public PageLoader getLoader() {
- return mPool.getLoader();
- }
-
- @Override
- public void notifyDataSetChanged() {
- recomputeWidth();
- forceRedraw();
- }
-
- @Override
- public PageWrapper getItem(int position) {
- return mPool.getLoader().getWrappersList().get(position);
- }
-
- @Override
- public void setScaleMode(int scaleMode) {
-
- }
-
- @Override
- public void reload(int position) {
- mPool.getLoader().requestPage(position);
- notifyDataSetChanged();
- }
-
- @Override
- public void setPages(List mangaPages) {
- mPool.recycle();
- mHeights.clear();
- mProgressMap.clear();
- getLoader().setPages(mangaPages);
- scrollToPosition(0);
- }
-
- @Override
- public void finish() {
- getLoader().cancelAll();
- mPool.recycle();
- }
-
- @SuppressLint("ClickableViewAccessibility")
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (mOverscrollDetector != null) {
- mOverscrollDetector.onTouch(this, event);
- }
- return super.onTouchEvent(event);
- }
-
- protected Rect computeScrollRange(float scale) {
- Rect range = new Rect(mScrollBounds);
- range.bottom = range.top + (int)(mFullHeight * scale) - getViewportHeight();
- range.right = range.left + (int)(getViewportWidth() * scale) - getViewportWidth();
- return range;
- }
-
- @Override
- public List getPages() {
- List wrappers = mPool.getLoader().getWrappersList();
- ArrayList pages = new ArrayList<>(wrappers.size());
- for (PageWrapper o : wrappers) {
- pages.add(o.page);
- }
- return pages;
- }
-
- @Override
- public void onLoadingStarted(PageWrapper page, boolean shadow) {
-
- }
-
- @Override
- public void onProgressUpdated(PageWrapper page, boolean shadow, int percent) {
- mProgressMap.put(page.position, percent);
- notifyDataSetChanged();
- }
-
- @Override
- public void onLoadingComplete(PageWrapper page, boolean shadow) {
- mProgressMap.put(page.position, 100);
- notifyDataSetChanged();
- }
-
- @Override
- public void onLoadingFail(PageWrapper page, boolean shadow) {
- mProgressMap.put(page.position, -1);
- notifyDataSetChanged();
- }
-
- @Override
- public void onLoadingCancelled(PageWrapper page, boolean shadow) {
- mProgressMap.put(page.position, 0);
- notifyDataSetChanged();
- }
-
- @WorkerThread
- private void notifyPageHeight(int page, int height) {
- Message msg = new Message();
- msg.what = MSG_IMGSIZE;
- msg.arg1 = page;
- msg.arg2 = height;
- mHandler.sendMessage(msg);
- }
-
- @WorkerThread
- private void notifyPageChanged(int page) {
- Message msg = new Message();
- msg.what = MSG_PAGE_CHANGED;
- msg.arg1 = page;
- mHandler.sendMessage(msg);
- }
-
- @Override
- public boolean handleMessage(Message message) {
- switch (message.what) {
- case MSG_IMGSIZE:
- if (!mHeights.containsKey(message.arg1)) {
- mHeights.put(message.arg1, message.arg2);
- recomputeWidth();
- }
- return true;
- case MSG_PAGE_CHANGED:
- int oldPage = mCurrentPage;
- mCurrentPage = message.arg1;
- for (RecyclerViewPager.OnPageChangedListener o : mPageChangeListeners) {
- o.OnPageChanged(oldPage, mCurrentPage);
- }
- return true;
- default:
- return false;
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/core/ListWrapper.java b/app/src/main/java/org/nv95/openmanga/core/ListWrapper.java
new file mode 100644
index 00000000..a48b2307
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/ListWrapper.java
@@ -0,0 +1,33 @@
+package org.nv95.openmanga.core;
+
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 12.01.18.
+ */
+
+public class ListWrapper extends ObjectWrapper> {
+
+ public ListWrapper(ArrayList object) {
+ super(object);
+ }
+
+ public ListWrapper(Throwable error) {
+ super(error);
+ }
+
+ public boolean isEmpty() {
+ return mObject == null || mObject.isEmpty();
+ }
+
+ @NonNull
+ public static ListWrapper badList() {
+ return new ListWrapper<>(new BadResultException());
+ }
+
+ public int size() {
+ return mObject == null ? 0 : mObject.size();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/MangaLocale.java b/app/src/main/java/org/nv95/openmanga/core/MangaLocale.java
new file mode 100644
index 00000000..3ce7c049
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/MangaLocale.java
@@ -0,0 +1,23 @@
+package org.nv95.openmanga.core;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+@Retention(RetentionPolicy.SOURCE)
+@IntDef({MangaLocale.EN, MangaLocale.RU, MangaLocale.JP, MangaLocale.TR, MangaLocale.MULTI, MangaLocale.VIE, MangaLocale.FR})
+public @interface MangaLocale {
+
+ int EN = 0;
+ int RU = 1;
+ int JP = 2;
+ int TR = 3;
+ int MULTI = 4;
+ int VIE = 5;
+ int FR = 6;
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/MangaStatus.java b/app/src/main/java/org/nv95/openmanga/core/MangaStatus.java
new file mode 100644
index 00000000..a7df8bde
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/MangaStatus.java
@@ -0,0 +1,19 @@
+package org.nv95.openmanga.core;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+@Retention(RetentionPolicy.SOURCE)
+@IntDef({MangaStatus.STATUS_UNKNOWN, MangaStatus.STATUS_COMPLETED, MangaStatus.STATUS_ONGOING})
+public @interface MangaStatus {
+
+ int STATUS_UNKNOWN = 0;
+ int STATUS_COMPLETED = 1;
+ int STATUS_ONGOING = 2;
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/ObjectWrapper.java b/app/src/main/java/org/nv95/openmanga/core/ObjectWrapper.java
new file mode 100644
index 00000000..fedafa51
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/ObjectWrapper.java
@@ -0,0 +1,49 @@
+package org.nv95.openmanga.core;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 12.01.18.
+ */
+
+public class ObjectWrapper {
+
+ @Nullable
+ protected final T mObject;
+ @Nullable
+ private final Throwable mThrowable;
+
+ public ObjectWrapper(@NonNull T object) {
+ mObject = object;
+ mThrowable = null;
+ }
+
+ public ObjectWrapper(@NonNull Throwable error) {
+ mObject = null;
+ mThrowable = error;
+ }
+
+ public T get() {
+ return mObject;
+ }
+
+ public Throwable getError() {
+ return mThrowable;
+ }
+
+ public boolean isSuccess() {
+ return mThrowable == null;
+ }
+
+ public boolean isFailed() {
+ return mThrowable != null;
+ }
+
+ public static class BadResultException extends Exception {}
+
+ @NonNull
+ public static ObjectWrapper badObject() {
+ return new ObjectWrapper<>(new BadResultException());
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/Category.java b/app/src/main/java/org/nv95/openmanga/core/models/Category.java
new file mode 100644
index 00000000..5c0509bf
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/Category.java
@@ -0,0 +1,53 @@
+package org.nv95.openmanga.core.models;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+
+import org.nv95.openmanga.R;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public class Category {
+
+ public final int id;
+ public final String name;
+ public final long createdAt;
+
+ public Category(int id, String name, long createdAt) {
+ this.id = id;
+ this.name = name;
+ this.createdAt = createdAt;
+ }
+
+ public Category(String name, long createdAt) {
+ this.id = name.hashCode();
+ this.name = name;
+ this.createdAt = createdAt;
+ }
+
+ @NonNull
+ public static Category createDefault(Context context) {
+ return new Category(context.getString(R.string.action_favourites), System.currentTimeMillis());
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(3);
+ bundle.putInt("id", id);
+ bundle.putString("name", name);
+ bundle.putLong("created_at", createdAt);
+ return bundle;
+ }
+
+ @NonNull
+ public static Category fromBundle(Bundle bundle) {
+ return new Category(
+ bundle.getInt("id"),
+ bundle.getString("name"),
+ bundle.getLong("created_at")
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/FileDesc.java b/app/src/main/java/org/nv95/openmanga/core/models/FileDesc.java
new file mode 100644
index 00000000..db961b27
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/FileDesc.java
@@ -0,0 +1,14 @@
+package org.nv95.openmanga.core.models;
+
+import java.io.File;
+
+public final class FileDesc {
+
+ public final File file;
+ public final int entryCount;
+
+ public FileDesc(File file, int entryCount) {
+ this.file = file;
+ this.entryCount = entryCount;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/ListHeader.java b/app/src/main/java/org/nv95/openmanga/core/models/ListHeader.java
new file mode 100644
index 00000000..d1a45fb6
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/ListHeader.java
@@ -0,0 +1,30 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public class ListHeader {
+
+ @StringRes
+ public final int textResId;
+ @Nullable
+ public final String text;
+ @Nullable
+ public final Object extra;
+
+ public ListHeader(@Nullable String text, @Nullable Object extra) {
+ this.text = text;
+ this.textResId = 0;
+ this.extra = extra;
+ }
+
+ public ListHeader(int textResId, @Nullable Object extra) {
+ this.textResId = textResId;
+ this.text = null;
+ this.extra = extra;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaBookmark.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaBookmark.java
new file mode 100644
index 00000000..21c98af4
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaBookmark.java
@@ -0,0 +1,112 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public final class MangaBookmark implements Parcelable, UniqueObject {
+
+ public final long id;
+ public final MangaHeader manga;
+ public final long chapterId;
+ public final long pageId;
+ public final long createdAt;
+
+ public MangaBookmark(long id, MangaHeader manga, long chapterId, long pageId, long createdAt) {
+ this.id = id;
+ this.manga = manga;
+ this.chapterId = chapterId;
+ this.pageId = pageId;
+ this.createdAt = createdAt;
+ }
+
+ public MangaBookmark(MangaHeader manga, long chapterId, long pageId, long createdAt) {
+ this.id = pageId + 1; //magic
+ this.manga = manga;
+ this.chapterId = chapterId;
+ this.pageId = pageId;
+ this.createdAt = createdAt;
+ }
+
+ protected MangaBookmark(Parcel in) {
+ id = in.readLong();
+ manga = new MangaHeader(in);
+ chapterId = in.readLong();
+ pageId = in.readLong();
+ createdAt = in.readLong();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaBookmark createFromParcel(Parcel in) {
+ return new MangaBookmark(in);
+ }
+
+ @Override
+ public MangaBookmark[] newArray(int size) {
+ return new MangaBookmark[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(id);
+ manga.writeToParcel(dest, flags);
+ dest.writeLong(chapterId);
+ dest.writeLong(pageId);
+ dest.writeLong(createdAt);
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MangaBookmark bookmark = (MangaBookmark) o;
+
+ return id == bookmark.id;
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (id ^ (id >>> 32));
+ }
+
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(5);
+ bundle.putLong("id", id);
+ bundle.putBundle("manga", manga.toBundle());
+ bundle.putLong("chapter_id", chapterId);
+ bundle.putLong("page_id", pageId);
+ bundle.putLong("created_at", createdAt);
+ return bundle;
+ }
+
+ @Nullable
+ public static MangaBookmark from(Bundle bundle) {
+ if (bundle.containsKey("bookmark")) {
+ return bundle.getParcelable("bookmark");
+ } else return new MangaBookmark(
+ bundle.getLong("id"),
+ MangaHeader.from(bundle.getBundle("manga")),
+ bundle.getLong("chapter_id"),
+ bundle.getLong("page_id"),
+ bundle.getLong("created_at")
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaChapter.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaChapter.java
new file mode 100644
index 00000000..575962a4
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaChapter.java
@@ -0,0 +1,104 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public class MangaChapter implements Parcelable, UniqueObject {
+
+ public static final int FLAG_CHAPTER_SAVED = 1;
+ public static final int FLAG_CHAPTER_NEW = 2;
+
+ public final long id;
+ public final String name;
+ public final int number;
+ public final String url;
+ public final String provider;
+
+ private int mFlags = 0;
+
+ public MangaChapter(String name, int number, String url, String provider) {
+ this.name = name;
+ this.number = number;
+ this.url = url;
+ this.provider = provider;
+ this.id = provider.hashCode() + url.hashCode();
+ }
+
+ public MangaChapter(long id, String name, int number, String url, String provider) {
+ this.id = id;
+ this.name = name;
+ this.number = number;
+ this.url = url;
+ this.provider = provider;
+ }
+
+ protected MangaChapter(Parcel in) {
+ id = in.readLong();
+ name = in.readString();
+ number = in.readInt();
+ url = in.readString();
+ provider = in.readString();
+
+ mFlags = in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaChapter createFromParcel(Parcel in) {
+ return new MangaChapter(in);
+ }
+
+ @Override
+ public MangaChapter[] newArray(int size) {
+ return new MangaChapter[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(id);
+ dest.writeString(name);
+ dest.writeInt(number);
+ dest.writeString(url);
+ dest.writeString(provider);
+
+ dest.writeInt(mFlags);
+ }
+
+ public Bundle toBundle() {
+ Bundle bundle = new Bundle(1);
+ bundle.putParcelable("_chapter", this);
+ return bundle;
+ }
+
+ public static MangaChapter from(Bundle bundle) {
+ return bundle.getParcelable("_chapter");
+ }
+
+ public boolean isSaved() {
+ return (mFlags & FLAG_CHAPTER_SAVED) != 0;
+ }
+
+ public void addFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ public void removeFlag(int flag) {
+ mFlags &= ~flag;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaChaptersList.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaChaptersList.java
new file mode 100644
index 00000000..0f1a57e7
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaChaptersList.java
@@ -0,0 +1,100 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public class MangaChaptersList extends ArrayList {
+
+ public static final MangaChaptersList EMPTY_LIST = new MangaChaptersList(0);
+
+ public MangaChaptersList() {
+ }
+
+ public MangaChaptersList(int initialCapacity) {
+ super(initialCapacity);
+ }
+
+ public MangaChaptersList(ArrayList source) {
+ super(source);
+ }
+
+ @Nullable
+ public MangaChapter findItemById(long id) {
+ for (MangaChapter o : this) {
+ if (o != null && o.id == id) {
+ return o;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int indexOf(@Nullable Object obj) {
+ if (obj instanceof MangaChapter) {
+ for (int i = 0; i < size(); i++) {
+ if (get(i).id == ((MangaChapter) obj).id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public int lastIndexOf(@Nullable Object obj) {
+ if (obj instanceof MangaChapter) {
+ for (int i = size() - 1; i >= 0; i--) {
+ if (get(i).id == ((MangaChapter) obj).id) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @NonNull
+ public MangaChaptersList subListFrom(MangaChapter from, int count) {
+ int pos = indexOf(from);
+ if (pos == -1) {
+ return EMPTY_LIST;
+ }
+ final MangaChaptersList list = new MangaChaptersList(count + 1);
+ int last = Math.min(size() - 1, pos + count);
+ for (int i = pos; i <= last; i++) {
+ list.add(get(i));
+ }
+ return list;
+ }
+
+ @NonNull
+ public MangaChaptersList subListFrom(MangaChapter from) {
+ int pos = indexOf(from);
+ if (pos == -1) {
+ return EMPTY_LIST;
+ }
+ final MangaChaptersList list = new MangaChaptersList(size() - pos);
+ for (int i = pos; i < size(); i++) {
+ list.add(get(i));
+ }
+ return list;
+ }
+
+ @NonNull
+ public MangaChaptersList subListTo(MangaChapter to) {
+ int pos = indexOf(to);
+ if (pos == -1) {
+ return EMPTY_LIST;
+ }
+ final MangaChaptersList list = new MangaChaptersList(pos + 1);
+ for (int i = 0; i <= pos; i++) {
+ list.add(get(i));
+ }
+ return list;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaDetails.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaDetails.java
new file mode 100644
index 00000000..87d6b6ff
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaDetails.java
@@ -0,0 +1,86 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Parcel;
+import android.support.annotation.NonNull;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public final class MangaDetails extends MangaHeader {
+
+ public final String description;
+ public final String cover;
+ public final String author;
+ @NonNull
+ public final MangaChaptersList chapters;
+
+ public MangaDetails(String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, String description, String cover, String author, MangaChaptersList chapters) {
+ super(name, summary, genres, url, thumbnail, provider, status, rating);
+ this.description = description;
+ this.cover = cover;
+ this.author = author;
+ this.chapters = chapters;
+ }
+
+ public MangaDetails(long id, String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, String description, String cover, String author, MangaChaptersList chapters) {
+ super(id, name, summary, genres, url, thumbnail, provider, status, rating);
+ this.description = description;
+ this.cover = cover;
+ this.author = author;
+ this.chapters = chapters;
+ }
+
+ public MangaDetails(MangaHeader header, String description, String cover, String author) {
+ super(header.id, header.name, header.summary, header.genres, header.url, header.thumbnail, header.provider, header.status, header.rating);
+ this.description = description;
+ this.cover = cover;
+ this.author = author;
+ this.chapters = new MangaChaptersList();
+ }
+
+ protected MangaDetails(Parcel in) {
+ super(in);
+ description = in.readString();
+ cover = in.readString();
+ author = in.readString();
+ chapters = new MangaChaptersList();
+ in.readTypedList(chapters, MangaChapter.CREATOR);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaDetails createFromParcel(Parcel in) {
+ return new MangaDetails(in);
+ }
+
+ @Override
+ public MangaDetails[] newArray(int size) {
+ return new MangaDetails[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ super.writeToParcel(parcel, i);
+ parcel.writeString(description);
+ parcel.writeString(cover);
+ parcel.writeString(author);
+ parcel.writeTypedList(chapters);
+ }
+
+ @NonNull
+ public static MangaDetails from(SavedManga manga) {
+ return new MangaDetails(
+ manga,
+ manga.description,
+ manga.thumbnail,
+ manga.author
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaFavourite.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaFavourite.java
new file mode 100644
index 00000000..d4a6230d
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaFavourite.java
@@ -0,0 +1,40 @@
+package org.nv95.openmanga.core.models;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public final class MangaFavourite extends MangaHeader {
+
+ public final long createdAt;
+ public final int categoryId;
+ public final int totalChapters;
+ public final int newChapters;
+
+ public MangaFavourite(long id, String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, long createdAt, int categoryId, int totalChapters, int newChapters) {
+ super(id, name, summary, genres, url, thumbnail, provider, status, rating);
+ this.createdAt = createdAt;
+ this.categoryId = categoryId;
+ this.totalChapters = totalChapters;
+ this.newChapters = newChapters;
+ }
+
+
+ public static MangaFavourite from(MangaHeader mangaHeader, int categoryId, int totalChapters) {
+ return new MangaFavourite(
+ mangaHeader.id,
+ mangaHeader.name,
+ mangaHeader.summary,
+ mangaHeader.genres,
+ mangaHeader.url,
+ mangaHeader.thumbnail,
+ mangaHeader.provider,
+ mangaHeader.status,
+ mangaHeader.rating,
+ System.currentTimeMillis(),
+ categoryId,
+ totalChapters,
+ 0
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaGenre.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaGenre.java
new file mode 100644
index 00000000..76232879
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaGenre.java
@@ -0,0 +1,96 @@
+package org.nv95.openmanga.core.models;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public final class MangaGenre implements Parcelable {
+
+ @StringRes
+ public final int nameId;
+ @NonNull
+ public final String value;
+
+ public MangaGenre(int nameId, @NonNull String value) {
+ this.nameId = nameId;
+ this.value = value;
+ }
+
+ private MangaGenre(Parcel in) {
+ nameId = in.readInt();
+ value = in.readString();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaGenre createFromParcel(Parcel in) {
+ return new MangaGenre(in);
+ }
+
+ @Override
+ public MangaGenre[] newArray(int size) {
+ return new MangaGenre[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeInt(nameId);
+ parcel.writeString(value);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ MangaGenre that = (MangaGenre) o;
+
+ return nameId == that.nameId && value.equals(that.value);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * nameId + value.hashCode();
+ }
+
+ @NonNull
+ public static String joinNames(@NonNull Context context, @NonNull MangaGenre[] genres, @NonNull String delimiter) {
+ final StringBuilder builder = new StringBuilder();
+ boolean nonFirst = false;
+ for (MangaGenre o: genres) {
+ if (nonFirst) {
+ builder.append(delimiter);
+ } else {
+ nonFirst = true;
+ }
+ builder.append(context.getString(o.nameId));
+ }
+ return builder.toString();
+ }
+
+ public static int indexOf(MangaGenre[] array, @NonNull String value) {
+ for (int i = 0; i < array.length; i++) {
+ if (value.equalsIgnoreCase(array[i].value)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaHeader.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaHeader.java
new file mode 100644
index 00000000..86655316
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaHeader.java
@@ -0,0 +1,146 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.MangaStatus;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public class MangaHeader implements Parcelable, UniqueObject {
+
+ public final long id;
+ public final String name;
+ public final String summary;
+ public final String genres;
+ public final String url;
+ public final String thumbnail;
+ public final String provider;
+ @MangaStatus
+ public final int status;
+ public final short rating; //0..100
+
+ public MangaHeader(String name, String summary, String genres, String url, String thumbnail, String provider, @MangaStatus int status, short rating) {
+ this.name = name;
+ this.summary = summary;
+ this.genres = genres;
+ this.url = url;
+ this.thumbnail = thumbnail;
+ this.provider = provider;
+ this.status = status;
+ this.rating = rating;
+ this.id = provider.hashCode() + url.hashCode();
+ }
+
+ public MangaHeader(long id, String name, String summary, String genres, String url, String thumbnail, String provider, @MangaStatus int status, short rating) {
+ this.id = id;
+ this.name = name;
+ this.summary = summary;
+ this.genres = genres;
+ this.url = url;
+ this.thumbnail = thumbnail;
+ this.provider = provider;
+ this.status = status;
+ this.rating = rating;
+ }
+
+
+ protected MangaHeader(Parcel in) {
+ id = in.readLong();
+ name = in.readString();
+ summary = in.readString();
+ genres = in.readString();
+ url = in.readString();
+ thumbnail = in.readString();
+ provider = in.readString();
+ status = in.readInt();
+ rating = (short) in.readInt();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaHeader createFromParcel(Parcel in) {
+ return new MangaHeader(in);
+ }
+
+ @Override
+ public MangaHeader[] newArray(int size) {
+ return new MangaHeader[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ parcel.writeLong(id);
+ parcel.writeString(name);
+ parcel.writeString(summary);
+ parcel.writeString(genres);
+ parcel.writeString(url);
+ parcel.writeString(thumbnail);
+ parcel.writeString(provider);
+ parcel.writeInt(status);
+ parcel.writeInt((int) rating);
+ }
+
+ @NonNull
+ public static MangaHeader from(MangaHeader other) {
+ return new MangaHeader(
+ other.id,
+ other.name,
+ other.summary,
+ other.genres,
+ other.url,
+ other.thumbnail,
+ other.provider,
+ other.status,
+ other.rating
+ );
+ }
+
+ @Nullable
+ public static MangaHeader from(Bundle bundle) {
+ if (bundle.containsKey("manga")) {
+ return bundle.getParcelable("manga");
+ } else return new MangaHeader(
+ bundle.getLong("id"),
+ bundle.getString("name"),
+ bundle.getString("summary"),
+ bundle.getString("genres"),
+ bundle.getString("url"),
+ bundle.getString("thumbnail"),
+ bundle.getString("provider"),
+ bundle.getInt("status"),
+ (short) bundle.getInt("rating")
+ );
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle();
+ bundle.putLong("id", id);
+ bundle.putString("name", name);
+ bundle.putString("summary", summary);
+ bundle.putString("genres", genres);
+ bundle.putString("url", url);
+ bundle.putString("thumbnail", thumbnail);
+ bundle.putString("provider", provider);
+ bundle.putInt("status", status);
+ bundle.putInt("rating", rating);
+ return bundle;
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaHistory.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaHistory.java
new file mode 100644
index 00000000..7608adbd
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaHistory.java
@@ -0,0 +1,42 @@
+package org.nv95.openmanga.core.models;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public final class MangaHistory extends MangaHeader {
+
+ public final long chapterId;
+ public final long pageId;
+ public final long updatedAt;
+ public final short readerPreset;
+ public final int totalChapters;
+
+ public MangaHistory(String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, long chapterId, long pageId, long updatedAt, short readerPreset, int totalChapters) {
+ super(name, summary, genres, url, thumbnail, provider, status, rating);
+ this.chapterId = chapterId;
+ this.pageId = pageId;
+ this.updatedAt = updatedAt;
+ this.readerPreset = readerPreset;
+ this.totalChapters = totalChapters;
+ }
+
+ public MangaHistory(long id, String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, long chapterId, long pageId, long updatedAt, short readerPreset, int totalChapters) {
+ super(id, name, summary, genres, url, thumbnail, provider, status, rating);
+ this.chapterId = chapterId;
+ this.pageId = pageId;
+ this.updatedAt = updatedAt;
+ this.readerPreset = readerPreset;
+ this.totalChapters = totalChapters;
+ }
+
+ public MangaHistory(MangaHeader header, MangaChapter chapter, int totalChapters, MangaPage page, short readerPreset) {
+ super(header.id, header.name, header.summary, header.genres, header.url, header.thumbnail, header.provider, header.status, header.rating);
+ this.chapterId = chapter.id;
+ this.totalChapters = totalChapters;
+ this.pageId = page.id;
+ updatedAt = System.currentTimeMillis();
+ this.readerPreset = readerPreset;
+
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaPage.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaPage.java
new file mode 100644
index 00000000..fddd38ac
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaPage.java
@@ -0,0 +1,65 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public class MangaPage implements Parcelable, UniqueObject {
+
+ public final long id;
+ @NonNull
+ public final String url;
+ public final String provider;
+
+ public MangaPage(String url, String provider) {
+ this.url = url;
+ this.provider = provider;
+ this.id = provider.hashCode() + url.hashCode();
+ }
+
+ public MangaPage(long id, @NonNull String url, String provider) {
+ this.id = id;
+ this.url = url;
+ this.provider = provider;
+ }
+
+ @SuppressWarnings("ConstantConditions")
+ protected MangaPage(Parcel in) {
+ id = in.readLong();
+ url = in.readString();
+ provider = in.readString();
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public MangaPage createFromParcel(Parcel in) {
+ return new MangaPage(in);
+ }
+
+ @Override
+ public MangaPage[] newArray(int size) {
+ return new MangaPage[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(id);
+ dest.writeString(url);
+ dest.writeString(provider);
+ }
+
+ @Override
+ public long getId() {
+ return id;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaRecommendation.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaRecommendation.java
new file mode 100644
index 00000000..0105fed7
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaRecommendation.java
@@ -0,0 +1,43 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Parcel;
+
+/**
+ * Created by koitharu on 29.01.18.
+ */
+
+public final class MangaRecommendation extends MangaHeader {
+
+ public final int category;
+
+ public MangaRecommendation(long id, String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, int category) {
+ super(id, name, summary, genres, url, thumbnail, provider, status, rating);
+ this.category = category;
+ }
+
+ protected MangaRecommendation(Parcel in) {
+ super(in);
+ category = in.readInt();
+ }
+
+ public MangaRecommendation(MangaHeader mangaHeader, int category) {
+ this(
+ mangaHeader.id,
+ mangaHeader.name,
+ mangaHeader.summary,
+ mangaHeader.genres,
+ mangaHeader.url,
+ mangaHeader.thumbnail,
+ mangaHeader.provider,
+ mangaHeader.status,
+ mangaHeader.rating,
+ category
+ );
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ super.writeToParcel(parcel, i);
+ parcel.writeInt(category);
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/MangaUpdateInfo.java b/app/src/main/java/org/nv95/openmanga/core/models/MangaUpdateInfo.java
new file mode 100644
index 00000000..b3178be4
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/MangaUpdateInfo.java
@@ -0,0 +1,23 @@
+package org.nv95.openmanga.core.models;
+
+/**
+ * Created by koitharu on 30.01.18.
+ */
+
+public final class MangaUpdateInfo implements UniqueObject {
+
+ public final long mangaId;
+ public final String mangaName;
+ public final int newChapters;
+
+ public MangaUpdateInfo(long mangaId, String mangaName, int newChapters) {
+ this.mangaId = mangaId;
+ this.mangaName = mangaName;
+ this.newChapters = newChapters;
+ }
+
+ @Override
+ public long getId() {
+ return mangaId;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/ProviderHeader.java b/app/src/main/java/org/nv95/openmanga/core/models/ProviderHeader.java
new file mode 100644
index 00000000..476c33a8
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/ProviderHeader.java
@@ -0,0 +1,30 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.NonNull;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public class ProviderHeader {
+
+ @NonNull
+ public final String cName;
+ @NonNull
+ public final String dName;
+
+ public ProviderHeader(@NonNull String cName, @NonNull String dName) {
+ this.cName = cName;
+ this.dName = dName;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null && obj instanceof ProviderHeader && ((ProviderHeader) obj).cName.equals(cName);
+ }
+
+ @Override
+ public int hashCode() {
+ return cName.hashCode();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/SavedChapter.java b/app/src/main/java/org/nv95/openmanga/core/models/SavedChapter.java
new file mode 100644
index 00000000..c7f234f0
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/SavedChapter.java
@@ -0,0 +1,34 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.NonNull;
+
+/**
+ * Created by koitharu on 25.01.18.
+ */
+
+public class SavedChapter extends MangaChapter {
+
+ public final long mangaId;
+
+ public SavedChapter(String name, int number, String url, String provider, long mangaId) {
+ super(name, number, url, provider);
+ this.mangaId = mangaId;
+ }
+
+ public SavedChapter(long id, String name, int number, String url, String provider, long mangaId) {
+ super(id, name, number, url, provider);
+ this.mangaId = mangaId;
+ }
+
+ @NonNull
+ public static SavedChapter from(MangaChapter chapter, long mangaId) {
+ return new SavedChapter(
+ chapter.id,
+ chapter.name,
+ chapter.number,
+ chapter.url,
+ chapter.provider,
+ mangaId
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/SavedManga.java b/app/src/main/java/org/nv95/openmanga/core/models/SavedManga.java
new file mode 100644
index 00000000..deae8829
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/SavedManga.java
@@ -0,0 +1,88 @@
+package org.nv95.openmanga.core.models;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
+import java.io.File;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+public final class SavedManga extends MangaHeader implements Parcelable {
+
+ public final long createdAt;
+ public final String localPath;
+ public final String description;
+ public final String author;
+
+ public SavedManga(String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, long createdAt, String localPath, String description, String author) {
+ super(name, summary, genres, url, thumbnail, provider, status, rating);
+ this.createdAt = createdAt;
+ this.localPath = localPath;
+ this.description = description;
+ this.author = author;
+ }
+
+ public SavedManga(long id, String name, String summary, String genres, String url, String thumbnail, String provider, int status, short rating, long createdAt, String localPath, String description, String author) {
+ super(id, name, summary, genres, url, thumbnail, provider, status, rating);
+ this.createdAt = createdAt;
+ this.localPath = localPath;
+ this.description = description;
+ this.author = author;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SavedManga createFromParcel(Parcel in) {
+ return new SavedManga(in);
+ }
+
+ @Override
+ public SavedManga[] newArray(int size) {
+ return new SavedManga[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int i) {
+ super.writeToParcel(parcel, i);
+ parcel.writeLong(createdAt);
+ parcel.writeString(localPath);
+ parcel.writeString(description);
+ parcel.writeString(author);
+ }
+
+ protected SavedManga(Parcel in) {
+ super(in);
+ createdAt = in.readLong();
+ localPath = in.readString();
+ description = in.readString();
+ author = in.readString();
+ }
+
+ @NonNull
+ public static SavedManga from(@NonNull MangaDetails other, @NonNull File localPath) {
+ return new SavedManga(
+ other.id,
+ other.name,
+ other.summary,
+ other.genres,
+ other.url,
+ other.thumbnail,
+ other.provider,
+ other.status,
+ other.rating,
+ System.currentTimeMillis(),
+ localPath.getPath(),
+ other.description,
+ other.author
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/SavedPage.java b/app/src/main/java/org/nv95/openmanga/core/models/SavedPage.java
new file mode 100644
index 00000000..91a02b08
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/SavedPage.java
@@ -0,0 +1,36 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.NonNull;
+
+/**
+ * Created by koitharu on 25.01.18.
+ */
+
+public class SavedPage extends MangaPage {
+
+ public final long chapterId;
+ public final int number;
+
+ public SavedPage(String url, String provider, long chapterId, int number) {
+ super(url, provider);
+ this.chapterId = chapterId;
+ this.number = number;
+ }
+
+ public SavedPage(long id, String url, String provider, long chapterId, int number) {
+ super(id, url, provider);
+ this.chapterId = chapterId;
+ this.number = number;
+ }
+
+ @NonNull
+ public static SavedPage from(MangaPage page, long chapterId, int number) {
+ return new SavedPage(
+ page.id,
+ page.url,
+ page.provider,
+ chapterId,
+ number
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/TypedString.java b/app/src/main/java/org/nv95/openmanga/core/models/TypedString.java
new file mode 100644
index 00000000..944f0a9e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/TypedString.java
@@ -0,0 +1,40 @@
+package org.nv95.openmanga.core.models;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.StringRes;
+
+public final class TypedString {
+
+ @StringRes
+ private final int mStringResId;
+ private final String mString;
+ private final int mType;
+ private final int mSubPos;
+
+ public TypedString(@NonNull Context context, @StringRes int stringResId, int type, int subPos) {
+ mStringResId = stringResId;
+ mString = context.getString(stringResId);
+ mType = type;
+ mSubPos = subPos;
+ }
+
+ public int getType() {
+ return mType;
+ }
+
+ public int getSubPosition() {
+ return mSubPos;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return mString;
+ }
+
+ @Override
+ public int hashCode() {
+ return mStringResId;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/UniqueObject.java b/app/src/main/java/org/nv95/openmanga/core/models/UniqueObject.java
new file mode 100644
index 00000000..26e1a037
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/UniqueObject.java
@@ -0,0 +1,10 @@
+package org.nv95.openmanga.core.models;
+
+/**
+ * Created by koitharu on 29.01.18.
+ */
+
+public interface UniqueObject {
+
+ long getId();
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/models/UserTip.java b/app/src/main/java/org/nv95/openmanga/core/models/UserTip.java
new file mode 100644
index 00000000..92a8073c
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/models/UserTip.java
@@ -0,0 +1,70 @@
+package org.nv95.openmanga.core.models;
+
+import android.support.annotation.DrawableRes;
+import android.support.annotation.IdRes;
+import android.support.annotation.StringRes;
+
+/**
+ * Created by koitharu on 12.01.18.
+ */
+
+public final class UserTip {
+
+ public static final int FLAG_NO_DISMISSIBLE = 1;
+ public static final int FLAG_DISMISS_BUTTON = 2;
+
+ public final String title;
+ public final String content;
+ @DrawableRes
+ public final int icon;
+ @StringRes
+ public final int actionText;
+ @IdRes
+ public final int actionId;
+ private int mFlags = 0;
+
+ public UserTip(String title, String content) {
+ this.title = title;
+ this.content = content;
+ this.icon = 0;
+ this.actionText = 0;
+ this.actionId = 0;
+ }
+
+ public UserTip(String title, String content, @DrawableRes int icon) {
+ this.title = title;
+ this.content = content;
+ this.icon = icon;
+ this.actionText = 0;
+ this.actionId = 0;
+ }
+
+ public UserTip(String title, String content, @DrawableRes int icon, @StringRes int actionText, @IdRes int actionId) {
+ this.title = title;
+ this.content = content;
+ this.icon = icon;
+ this.actionText = actionText;
+ this.actionId = actionId;
+ }
+
+ public UserTip addFlag(int flag) {
+ mFlags |= flag;
+ return this;
+ }
+
+ public boolean isDismissible() {
+ return (mFlags & FLAG_NO_DISMISSIBLE) == 0;
+ }
+
+ public boolean hasDismissButton() {
+ return (mFlags & FLAG_DISMISS_BUTTON) != 0;
+ }
+
+ public boolean hasIcon() {
+ return icon != 0;
+ }
+
+ public boolean hasAction() {
+ return actionText != 0 && actionId != 0;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/CName.java b/app/src/main/java/org/nv95/openmanga/core/providers/CName.java
new file mode 100644
index 00000000..4548aceb
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/CName.java
@@ -0,0 +1,21 @@
+package org.nv95.openmanga.core.providers;
+
+import android.support.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Created by koitharu on 11.01.18.
+ */
+
+@Retention(RetentionPolicy.SOURCE)
+@StringDef({
+ DesumeProvider.CNAME,
+ ExhentaiProvider.CNAME,
+ ReadmangaruProvider.CNAME,
+ MintmangaProvider.CNAME,
+ SelfmangaProvider.CNAME
+})
+public @interface CName {
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/DesumeProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/DesumeProvider.java
new file mode 100644
index 00000000..3e3fe19b
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/DesumeProvider.java
@@ -0,0 +1,176 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+@SuppressLint("DefaultLocale")
+public final class DesumeProvider extends MangaProvider {
+
+ public static final String CNAME = "network/desu.me";
+ public static final String DNAME = "DesuMe";
+
+ private final int[] mSorts = new int[] {
+ R.string.sort_alphabetical,
+ R.string.sort_popular,
+ R.string.sort_updated
+ };
+
+ private final String[] mSortValues = new String[] {
+ "name",
+ "popular",
+ ""
+ };
+
+ private final MangaGenre[] mGenres = new MangaGenre[]{
+ new MangaGenre(R.string.genre_action, "action"),
+ new MangaGenre(R.string.genre_martialarts, "martial%20arts"),
+ new MangaGenre(R.string.genre_vampires, "vampire"),
+ new MangaGenre(R.string.web, "manhwa"),
+ new MangaGenre(R.string.genre_military, "military"),
+ new MangaGenre(R.string.genre_harem, "harem"),
+ new MangaGenre(R.string.genre_youkai, "demons"),
+ new MangaGenre(R.string.genre_drama, "drama"),
+ new MangaGenre(R.string.genre_josei, "josei"),
+ new MangaGenre(R.string.genre_game, "game"),
+ new MangaGenre(R.string.genre_historical, "historical"),
+ new MangaGenre(R.string.genre_comedy, "comedy"),
+ new MangaGenre(R.string.genre_magic, "magic"),
+ new MangaGenre(R.string.genre_mecha, "mecha"),
+ new MangaGenre(R.string.genre_mystery, "mystery"),
+ new MangaGenre(R.string.genre_music, "music"),
+ new MangaGenre(R.string.genre_sci_fi, "sci-fi"),
+ new MangaGenre(R.string.genre_parodi, "parody"),
+ new MangaGenre(R.string.genre_slice_of_life, "slice%20of%20life"),
+ new MangaGenre(R.string.genre_police, "police"),
+ new MangaGenre(R.string.genre_adventure, "adventure"),
+ new MangaGenre(R.string.genre_psychological, "psychological"),
+ new MangaGenre(R.string.genre_romance, "romance"),
+ new MangaGenre(R.string.genre_samurai, "samurai"),
+ new MangaGenre(R.string.genre_supernatural, "supernatural"),
+ new MangaGenre(R.string.genre_genderbender, "gender%20bender"),
+ new MangaGenre(R.string.genre_sports, "sports"),
+ new MangaGenre(R.string.genre_superpower, "super%20power"),
+ new MangaGenre(R.string.genre_seinen, "seinen"),
+ new MangaGenre(R.string.genre_shoujo, "shoujo"),
+ new MangaGenre(R.string.genre_shounen, "shounen"),
+ new MangaGenre(R.string.genre_shounen_ai, "shounen%20ai"),
+ new MangaGenre(R.string.genre_thriller, "thriller"),
+ new MangaGenre(R.string.genre_horror, "horror"),
+ new MangaGenre(R.string.genre_fantasy, "fantasy"),
+ new MangaGenre(R.string.genre_hentai, "hentai"),
+ new MangaGenre(R.string.genre_school, "school"),
+ new MangaGenre(R.string.genre_ecchi, "ecchi"),
+ new MangaGenre(R.string.genre_yuri, "yuri"),
+ new MangaGenre(R.string.genre_yaoi, "yaoi")
+ };
+
+ public DesumeProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ String url = String.format(
+ "http://desu.me/manga/api/?limit=20&order_by=%s&page=%d&genres=%s&search=%s",
+ sortOrder == -1 ? "popular" : mSortValues[sortOrder],
+ page + 1,
+ TextUtils.join(",", genres),
+ search == null ? "" : search
+ );
+ JSONArray ja = NetworkUtils.getJSONObject(url).getJSONArray("response");
+ ArrayList list = new ArrayList<>(ja.length());
+ for (int i = 0; i < ja.length(); i++) {
+ JSONObject jo = ja.getJSONObject(i);
+ int status = MangaStatus.STATUS_UNKNOWN;
+ switch (jo.getString("status")) {
+ case "released":
+ status = MangaStatus.STATUS_COMPLETED;
+ break;
+ case "ongoing":
+ status = MangaStatus.STATUS_ONGOING;
+ break;
+ }
+ list.add(new MangaHeader(
+ jo.getString("name"),
+ jo.getString("russian"),
+ jo.getString("genres"),
+ "http://desu.me/manga/api/" + jo.getInt("id"),
+ jo.getJSONObject("image").getString("x225"),
+ CNAME,
+ status,
+ (byte) (jo.getDouble("score") * 10)
+ ));
+ }
+ return list;
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ JSONObject jo = NetworkUtils.getJSONObject(header.url).getJSONObject("response");
+ MangaDetails details = new MangaDetails(
+ header,
+ jo.getString("description"),
+ jo.getJSONObject("image").getString("original"),
+ "" //not supported by desu.me
+ );
+ JSONArray ja = jo.getJSONObject("chapters").getJSONArray("list");
+ final int total = ja.length();
+ for (int i = 0; i < total; i++) {
+ JSONObject chapter = ja.getJSONObject(i);
+ details.chapters.add(0, new MangaChapter(
+ chapter.isNull("title") ? "Chapter " + (total - i) : chapter.getString("title"),
+ i,
+ details.url + "/chapter/" + chapter.getInt("id"),
+ CNAME
+ ));
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ JSONObject jo = NetworkUtils.getJSONObject(chapterUrl).getJSONObject("response");
+ JSONArray ja = jo.getJSONObject("pages").getJSONArray("list");
+ ArrayList pages = new ArrayList<>(ja.length());
+ for (int i = 0; i < ja.length(); i++) {
+ jo = ja.getJSONObject(i);
+ pages.add(new MangaPage(
+ jo.getString("img"),
+ CNAME
+ ));
+ }
+ return pages;
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/ExhentaiProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/ExhentaiProvider.java
new file mode 100644
index 00000000..5bfd5d2f
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/ExhentaiProvider.java
@@ -0,0 +1,284 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.network.CookieStore;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Created by koitharu on 12.01.18.
+ */
+
+public final class ExhentaiProvider extends MangaProvider {
+
+ public static final String CNAME = "network/exhentai";
+ public static final String DNAME = "ExHentai";
+
+ private static final String COOKIE_DEFAULT = "sl=dm_1; nw=1; uconfig=dm_t; igneous=0";
+
+ static {
+ CookieStore.getInstance().put("e-hentai.org", COOKIE_DEFAULT);
+ CookieStore.getInstance().put("exhentai.org", COOKIE_DEFAULT);
+ }
+
+ private final MangaGenre[] mGenres = new MangaGenre[] {
+ new MangaGenre(R.string.genre_doujinshi, "f_doujinshi"),
+ new MangaGenre(R.string.genre_manga, "f_manga"),
+ new MangaGenre(R.string.genre_artistcg, "f_artistcg"),
+ new MangaGenre(R.string.genre_gamecg, "f_gamecg"),
+ new MangaGenre(R.string.genre_western, "f_western"),
+ new MangaGenre(R.string.genre_nonh, "f_non-h"),
+ new MangaGenre(R.string.genre_imageset, "f_imageset"),
+ new MangaGenre(R.string.genre_cosplay, "f_cosplay"),
+ new MangaGenre(R.string.genre_asianporn, "f_asianporn"),
+ new MangaGenre(R.string.genre_misc, "f_misc"),
+ };
+
+ @NonNull
+ private String mDomain;
+
+ public ExhentaiProvider(Context context) {
+ super(context);
+ final String authCookie = getAuthCookie();
+ if (authCookie == null) {
+ mDomain = "e-hentai.org";
+ } else {
+ mDomain = "exhentai.org";
+ CookieStore.getInstance().put(mDomain, authCookie);
+ }
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ final StringJoinerCompat query = new StringJoinerCompat("&", "", "&");
+ for (String g : genres) {
+ query.add(g + "=1");
+ }
+ if (search != null) {
+ query.add("f_search=" + search);
+ }
+ String url = String.format(
+ "https://%s/?page=%d&%sf_apply=Apply+Filter",
+ mDomain,
+ page,
+ query.toString()
+ );
+ final Document document = NetworkUtils.getDocument(url);
+ final Element root = document.body().select("div.itg").first();
+ final Elements elements = root.select("div.id1");
+ if (elements == null) {
+ throw new RuntimeException("div.id1 is null");
+ }
+ final ArrayList list = new ArrayList<>(elements.size());
+ for (Element o : elements) {
+ try {
+ final Element a = o.selectFirst("a");
+ final String name = a.text();
+ list.add(new MangaHeader(
+ name.replaceAll("\\[[^\\[,\\]]+]", "").trim(),
+ getFromBrackets(name),
+ "",
+ a.attr("href"),
+ o.selectFirst("img").attr("src"),
+ CNAME,
+ MangaStatus.STATUS_UNKNOWN,
+ parseRating(o.select("div.id43").first().attr("style"))
+ ));
+ } catch (Exception ignored) {
+ }
+ }
+ return list;
+ }
+
+ @SuppressLint("DefaultLocale")
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final Element body = NetworkUtils.getDocument(header.url).body();
+ final Element taglist = body.getElementById("taglist");
+ final StringBuilder description = new StringBuilder();
+ final Elements trs = taglist.select("tr");
+ String author = "";
+ for (Element o : trs) {
+ final Element td = o.selectFirst("td");
+ if (td == null) {
+ continue;
+ }
+ final String title = td.text();
+ if (title.startsWith("artist")) {
+ author = td.nextElementSibling().text();
+ continue;
+ }
+ description.append("")
+ .append(title)
+ .append(" ")
+ .append(td.nextElementSibling().text())
+ .append("
");
+ }
+ String cover = header.thumbnail;
+ try {
+ final String pvw = body.getElementById("gd1").child(0).attr("style");
+ int p = pvw.indexOf("url(") + 4;
+ cover = pvw.substring(p, pvw.indexOf(')', p));
+ } catch (Exception ignored) {
+ }
+ final MangaDetails details = new MangaDetails(
+ header,
+ description.toString(),
+ cover,
+ author
+ );
+ final Element table = body.selectFirst("table.ptt");
+ if (table != null) {
+ final Elements cells = table.select("td");
+ if (cells.size() > 2) {
+ cells.remove(cells.size() - 1);
+ cells.remove(0);
+ for (int i = 0; i < cells.size(); i++) {
+ final Element a = cells.get(i).selectFirst("a");
+ if (a != null) {
+ details.chapters.add(new MangaChapter(
+ String.format("%s (%s)", header.name, a.text()),
+ i,
+ url("https://" + mDomain, a.attr("href")),
+ header.provider
+ ));
+ }
+ }
+ } else {
+ details.chapters.add(new MangaChapter(
+ header.name,
+ 0,
+ header.url,
+ header.provider
+ ));
+ }
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ final ArrayList pages = new ArrayList<>();
+ final Element body = NetworkUtils.getDocument(chapterUrl).body();
+ final Elements cells = body.select("div.gdtm");
+ for (Element cell : cells) {
+ pages.add(new MangaPage(
+ url("https://" + mDomain, cell.selectFirst("a").attr("href")),
+ CNAME
+ ));
+ }
+ return pages;
+ }
+
+ @NonNull
+ @Override
+ public String getImageUrl(MangaPage page) throws Exception {
+ return url("https://" + mDomain, NetworkUtils.getDocument(page.url).getElementById("img").attr("src"));
+ }
+
+ @Override
+ public boolean isAuthorizationSupported() {
+ return true;
+ }
+
+ @Nullable
+ @Override
+ public String authorize(@NonNull String login, @NonNull String password) throws Exception {
+ String cookie = NetworkUtils.authorize(
+ "https://forums.e-hentai.org/index.php?act=Login&CODE=01",
+ "referer",
+ "https://forums.e-hentai.org/index.php",
+ "UserName",
+ login,
+ "PassWord",
+ password,
+ "CookieDate",
+ "1"
+ );
+ if (cookie == null || !cookie.contains("ipb_pass_hash")) {
+ return null;
+ }
+ cookie = COOKIE_DEFAULT + "; " + cookie;
+ mDomain = "exhentai.org";
+ setAuthCookie(cookie);
+ return cookie;
+ }
+
+ private short parseRating(String r) {
+ r = r.substring(
+ r.indexOf(":") + 1,
+ r.indexOf(";")
+ );
+ String[] a = r.split(" ");
+ short res;
+ switch (a[0].trim()) {
+ case "0px":
+ res = 90;
+ break;
+ case "-16px":
+ res = 70;
+ break;
+ case "-32px":
+ res = 50;
+ break;
+ case "-48px":
+ res = 30;
+ break;
+ case "-64px":
+ res = 10;
+ break;
+ default:
+ res = 0;
+ }
+ if (a.length > 1 && res != 0 && "-1px".equals(a[1])) {
+ res += 10;
+ }
+ return res;
+ }
+
+ @NonNull
+ private String getFromBrackets(String src) {
+ Matcher m = Pattern.compile("\\[[^\\[,\\]]+]").matcher(src);
+ StringBuilder sb = new StringBuilder();
+ String t;
+ boolean firstTime = true;
+ while (m.find()) {
+ t = m.group(0);
+ t = t.substring(1, t.length() - 2);
+ if (firstTime) {
+ firstTime = false;
+ } else {
+ sb.append(", ");
+ }
+ sb.append(t);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/GroupleMangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/GroupleMangaProvider.java
new file mode 100644
index 00000000..184fcd27
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/GroupleMangaProvider.java
@@ -0,0 +1,178 @@
+package org.nv95.openmanga.core.providers;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.json.JSONArray;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaChaptersList;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 26.01.18.
+ */
+
+abstract class GroupleMangaProvider extends MangaProvider {
+
+ public GroupleMangaProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ boolean hasQuery = !TextUtils.isEmpty(search);
+ boolean multipleGenres = genres.length >= 1;
+ if (multipleGenres) {
+ return page != 0 ? EMPTY_HEADERS : advancedSearch(org.nv95.openmanga.common.utils.TextUtils.notNull(search), genres);
+ } else if (hasQuery) {
+ return simpleSearch(search, page);
+ } else {
+ return getList(page, sortOrder, null);
+ }
+ }
+
+ @NonNull
+ protected abstract ArrayList getList(int page, int sortOrder, @Nullable String genre) throws Exception;
+
+ @NonNull
+ protected abstract ArrayList simpleSearch(@NonNull String search, int page) throws Exception;
+
+ @NonNull
+ protected abstract ArrayList advancedSearch(@NonNull String search, @NonNull String[] genres) throws Exception;
+
+ protected final ArrayList parseList(Elements elements, String domain) {
+ final ArrayList list = new ArrayList<>(elements.size());
+ for (Element e : elements) {
+ if (!e.select(".fa-external-link").isEmpty()) {
+ continue;
+ }
+ final Element title = e.selectFirst("h3").child(0);
+ final Element rating = e.selectFirst("div.rating");
+ final Element tags = e.selectFirst(".tags");
+ int status = MangaStatus.STATUS_UNKNOWN;
+ if (!tags.select(".mangaCompleted").isEmpty()) {
+ status = MangaStatus.STATUS_COMPLETED;
+ } else if (!tags.select(".mangaTranslationCompleted").isEmpty()) {
+ status = MangaStatus.STATUS_COMPLETED;
+ }
+ final Element subtitle = e.selectFirst("h4");
+ final Element img = e.selectFirst("img.lazy");
+ list.add(new MangaHeader(
+ title.text(),
+ subtitle == null ? "" : subtitle.text(),
+ parseGenres(e.select(".element-link"), ""),
+ url(domain, title.attr("href")),
+ img == null ? "" : img.attr("data-original"),
+ getCName(),
+ status,
+ rating == null ? 0 : parseRating(rating.attr("title"))
+ ));
+ }
+ return list;
+ }
+
+ private short parseRating(String title) {
+ try {
+ int p = title.indexOf('.');
+ return Short.parseShort(title.substring(0, p + 2).replace(".", ""));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final Document doc = NetworkUtils.getDocument(header.url);
+ Element root = doc.body().getElementById("mangaBox");
+ final Element description = root.selectFirst(".manga-description");
+ final Element author = root.selectFirst(".elem_author");
+ final MangaDetails details = new MangaDetails(
+ header.id,
+ header.name,
+ header.summary,
+ parseGenres(root.select(".elem_genre a"),header.genres),
+ header.url,
+ header.thumbnail,
+ header.provider,
+ header.status,
+ header.rating,
+ description == null ? "" : description.html(),
+ root.selectFirst("div.picture-fotorama").child(0).attr("data-full"),
+ author == null ? "" : author.child(0).text(),
+ new MangaChaptersList()
+ );
+ root = root.selectFirst("div.chapters-link");
+ if (root == null) {
+ return details;
+ }
+ root = root.selectFirst("tbody");
+ final Elements ch = root.select("a");
+ final String domain = NetworkUtils.getDomainWithScheme(header.url);
+ final int len = ch.size();
+ for (int i = 0; i < len; i++) {
+ Element o = ch.get(len - i - 1);
+ details.chapters.add(new MangaChapter(
+ o.text(),
+ i,
+ url(domain, o.attr("href") + "?mtr=1"),
+ header.provider
+ ));
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ final Elements scripts = NetworkUtils.getDocument(chapterUrl).select("script");
+ final String domain = NetworkUtils.getDomainWithScheme(chapterUrl);
+ final ArrayList pages = new ArrayList<>();
+ for (Element script : scripts) {
+ String s = script.html();
+ int start = s.indexOf("rm_h.init(");
+ if (start == -1) {
+ continue;
+ }
+ start += 10;
+ final int p = s.lastIndexOf("]") + 1;
+ s = s.substring(start, p);
+ final JSONArray array = new JSONArray(s);
+ for (int i = 0; i < array.length(); i++) {
+ JSONArray item = array.getJSONArray(i);
+ pages.add(new MangaPage(
+ url(domain, item.getString(1) + item.getString(0) + item.getString(2)),
+ getCName()
+ ));
+ }
+ return pages;
+ }
+ throw new RuntimeException("No reader script found");
+ }
+
+ @NonNull
+ private String parseGenres(@Nullable Elements elements, @NonNull String defValue) {
+ if (elements == null || elements.isEmpty()) {
+ return defValue;
+ }
+ StringJoinerCompat joiner = new StringJoinerCompat(", ");
+ for (Element o : elements) {
+ joiner.add(o.text());
+ }
+ return joiner.toString();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/MangaFoxProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/MangaFoxProvider.java
new file mode 100644
index 00000000..8484faa5
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/MangaFoxProvider.java
@@ -0,0 +1,230 @@
+package org.nv95.openmanga.core.providers;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.CollectionsUtils;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.common.utils.network.UrlQueryBuilder;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+import org.nv95.openmanga.core.providers.MangaProvider;
+
+import java.util.ArrayList;
+import java.util.regex.Pattern;
+
+public final class MangaFoxProvider extends MangaProvider {
+
+ public static final String CNAME = "network/mangafox";
+ public static final String DNAME = "MangaFox";
+
+ private final int[] mSorts = new int[]{
+ R.string.sort_updated,
+ R.string.sort_rating,
+ R.string.sort_popular,
+ R.string.sort_alphabetical
+ };
+
+ private final String[] mSortValues = new String[]{
+ "?latest",
+ "?rating",
+ "",
+ "?az"
+ };
+
+ private final String[] mSortValuesAdv = new String[]{
+ "last_chapter_time",
+ "rating",
+ "views",
+ "name"
+ };
+
+ private final MangaGenre[] mGenres = new MangaGenre[]{
+ new MangaGenre(R.string.genre_action, "action"),
+ new MangaGenre(R.string.genre_adult, "adult"),
+ new MangaGenre(R.string.genre_adventure, "adventure"),
+ new MangaGenre(R.string.genre_comedy, "comedy"),
+ new MangaGenre(R.string.genre_doujinshi, "doujinshi"),
+ new MangaGenre(R.string.genre_drama, "drama"),
+ new MangaGenre(R.string.genre_ecchi, "ecchi"),
+ new MangaGenre(R.string.genre_fantasy, "fantasy"),
+ new MangaGenre(R.string.genre_genderbender, "gender-bender"),
+ new MangaGenre(R.string.genre_harem, "harem"),
+ new MangaGenre(R.string.genre_historical, "historical"),
+ new MangaGenre(R.string.genre_horror, "horror"),
+ new MangaGenre(R.string.genre_josei, "josei"),
+ new MangaGenre(R.string.genre_martialarts, "martial-arts"),
+ new MangaGenre(R.string.genre_mature, "mature"),
+ new MangaGenre(R.string.genre_mecha, "mecha"),
+ new MangaGenre(R.string.genre_mystery, "mystery"),
+ new MangaGenre(R.string.genre_oneshot, "one-shot"),
+ new MangaGenre(R.string.genre_psychological, "psychological"),
+ new MangaGenre(R.string.genre_romance, "romance"),
+ new MangaGenre(R.string.genre_school, "school-life"),
+ new MangaGenre(R.string.genre_sci_fi, "sci-fi"),
+ new MangaGenre(R.string.genre_seinen, "seinen"),
+ new MangaGenre(R.string.genre_shoujo, "shoujo"),
+ new MangaGenre(R.string.genre_shoujo_ai, "shoujo-ai"),
+ new MangaGenre(R.string.genre_shounen, "shounen"),
+ new MangaGenre(R.string.genre_shounen_ai, "shounen-ai"),
+ new MangaGenre(R.string.genre_slice_of_life, "slice-of-life"),
+ new MangaGenre(R.string.genre_smut, "smut"),
+ new MangaGenre(R.string.genre_sports, "sports"),
+ new MangaGenre(R.string.genre_supernatural, "supernatural"),
+ new MangaGenre(R.string.genre_tragedy, "tragedy"),
+ new MangaGenre(R.string.web, "webtoons"),
+ new MangaGenre(R.string.genre_yaoi, "yaoi"),
+ new MangaGenre(R.string.genre_yuri, "yuri"),
+
+ };
+
+ public MangaFoxProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ boolean hasQuery = !TextUtils.isEmpty(search);
+ boolean multipleGenres = genres.length > 1;
+ Element root;
+ if (multipleGenres || hasQuery) { //advanced search
+ final UrlQueryBuilder query = new UrlQueryBuilder("http://fanfox.net/search.php");
+ query.put("advopts", 1);
+ query.put("artist", "");
+ query.put("artist_method", "cw");
+ query.put("author", "");
+ query.put("artist_method", "cw");
+ for (MangaGenre g : mGenres) {
+ query.put("genres[" + g.value.replaceAll("-", "+") + "]", CollectionsUtils.contains(genres, g) ? 1 : 0);
+ }
+ query.put("is_completed", "");
+ query.put("name", urlEncode(search));
+ query.put("name_method", "cw");
+ query.put("rating", "");
+ query.put("rating_method", "eq");
+ query.put("released", "");
+ query.put("released_method", "eq");
+ if (sortOrder != -1) {
+ query.put("order", "za");
+ query.put("sort", mSortValuesAdv[sortOrder]);
+ }
+ final Document doc = NetworkUtils.getDocument(query.toString());
+ root = doc.body().getElementById("listing").selectFirst("div.left");
+ } else {
+ final String genre = CollectionsUtils.getOrNull(genres, 0);
+ final Document doc = NetworkUtils.getDocument("http://fanfox.net/directory/" + (TextUtils.isEmpty(genre) ? "" : genre + "/")
+ + page + ".htm" + (sortOrder == -1 ? mSortValues[0] : mSortValues[sortOrder]));
+ root = doc.body().getElementById("mangalist");
+ }
+ final Elements elements = root.selectFirst("ul.list").select("li");
+ final ArrayList list = new ArrayList<>(elements.size());
+ for (Element o : elements) {
+ try {
+ final Element a = o.selectFirst("a.title");
+ final String name = a.text();
+ list.add(new MangaHeader(
+ name,
+ "",
+ o.selectFirst("p.info").attr("title"),
+ "http:" + a.attr("href"),
+ o.selectFirst("img").attr("src"),
+ CNAME,
+ MangaStatus.STATUS_UNKNOWN,
+ (short) (Integer.parseInt(o.selectFirst("span.rate").text().replaceAll("[^0-9]", "")) * 2)
+ ));
+ } catch (Exception ignored) {
+ }
+ }
+ return list;
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final Document doc = NetworkUtils.getDocument(header.url);
+ Element root = doc.body().getElementById("page");
+ final Element title = root.getElementById("title");
+ String author = "";
+ try {
+ author = title.selectFirst("table").select("tr").get(1).select("td").get(1).text();
+ } catch (Exception ignored) {
+ }
+ String description = title.selectFirst("p.summary").html();
+ final Element warning = root.selectFirst("div.warning");
+ if (warning != null) {
+ description = String.format("%s
", warning.html()) + description;
+ }
+ final MangaDetails details = new MangaDetails(
+ header,
+ description,
+ root.selectFirst("div.cover").selectFirst("img").attr("src"),
+ author
+ );
+ root = root.getElementById("chapters");
+ final Elements lis = root.select("li");
+ int i = 0;
+ for (Element li : lis) {
+ final Element h3 = li.selectFirst("h3");
+ if (h3 == null) {
+ continue;
+ }
+ final Element a = h3.selectFirst("a");
+ details.chapters.add(new MangaChapter(
+ h3.text(),
+ i,
+ "http:" + a.attr("href"),
+ header.provider
+ ));
+ i++;
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ final ArrayList pages = new ArrayList<>();
+ final Document document = NetworkUtils.getDocument(chapterUrl);
+ final String prefix = chapterUrl.substring(0, chapterUrl.lastIndexOf('/') + 1);
+ final Elements els = document.body().selectFirst("select.m").select("option");
+ final Pattern numberPattern = Pattern.compile("[0-9]+");
+ for (Element o : els) {
+ final String val = o.attr("value");
+ if (numberPattern.matcher(val).matches()) {
+ pages.add(new MangaPage(
+ prefix + val + ".htm",
+ CNAME
+ ));
+ }
+ }
+ return pages;
+ }
+
+ @NonNull
+ @Override
+ public String getImageUrl(@NonNull MangaPage page) throws Exception {
+ return NetworkUtils.getDocument(page.url).getElementById("image").attr("src");
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/MangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/MangaProvider.java
new file mode 100644
index 00000000..d689e380
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/MangaProvider.java
@@ -0,0 +1,234 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.util.LruCache;
+
+import org.nv95.openmanga.common.utils.TextUtils;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Created by koitharu on 21.12.17.
+ */
+
+public abstract class MangaProvider {
+
+ private static final HashMap sDomainsMap = new HashMap<>();
+ protected static final ArrayList EMPTY_HEADERS = new ArrayList<>(0);
+
+ protected final Context mContext;
+
+ public MangaProvider(Context context) {
+ mContext = context;
+ }
+
+ protected SharedPreferences getPreferences() {
+ return mContext.getSharedPreferences("prov_" + this.getCName().replace('/','_'), Context.MODE_PRIVATE);
+ }
+
+ /**
+ *
+ * @param search - search query or null
+ * @param page - from 0 to infinity
+ * @param sortOrder - index of {@link #getAvailableSortOrders()} or -1
+ * @param genres - array of values from {@link #getAvailableGenres()}
+ * @return list
+ * @throws Exception if anything wrong
+ */
+ @NonNull
+ public abstract ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception;
+
+ @NonNull
+ public abstract MangaDetails getDetails(MangaHeader header) throws Exception;
+
+ @NonNull
+ public abstract ArrayList getPages(String chapterUrl) throws Exception;
+
+ @NonNull
+ public String getImageUrl(@NonNull MangaPage page) throws Exception {
+ return page.url;
+ }
+
+ public boolean signIn(String login, String password) throws Exception {
+ return false;
+ }
+
+ protected void setAuthCookie(@Nullable String cookie) {
+ getPreferences().edit()
+ .putString("_cookie", cookie)
+ .apply();
+ }
+
+ @Nullable
+ protected String getAuthCookie() {
+ return getPreferences().getString("_cookie", null);
+ }
+
+ public boolean isSearchSupported() {
+ return true;
+ }
+
+ public boolean isMultipleGenresSupported() {
+ return true;
+ }
+
+ public boolean isAuthorizationSupported() {
+ return false;
+ }
+
+ @Nullable
+ @SuppressLint("WrongConstant")
+ public String authorize(@NonNull String login, @NonNull String password) throws Exception {
+ throw new UnsupportedOperationException("Authorization not supported for " + getCName());
+ }
+
+ public MangaGenre[] getAvailableGenres() {
+ return new MangaGenre[0];
+ }
+
+ public int[] getAvailableSortOrders() {
+ return new int[0];
+ }
+
+ public final boolean isAuthorized() {
+ return !android.text.TextUtils.isEmpty(getAuthCookie());
+ }
+
+ @Nullable
+ public String getName() {
+ try {
+ return ((String)this.getClass().getField("DNAME").get(this));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @CName
+ @Nullable
+ public String getCName() {
+ try {
+ return ((String)this.getClass().getField("CNAME").get(this));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static LruCache sProviderCache = new LruCache<>(4);
+
+ @NonNull
+ public static MangaProvider get(Context context, @NonNull @CName String cName) throws AssertionError {
+ MangaProvider provider = sProviderCache.get(cName);
+ if (provider != null) {
+ return NetworkUtils.isNetworkAvailable(context) ? provider : new OfflineMangaProvider(context, provider);
+ }
+ switch (cName) {
+ case DesumeProvider.CNAME:
+ provider = new DesumeProvider(context);
+ break;
+ case ExhentaiProvider.CNAME:
+ provider = new ExhentaiProvider(context);
+ break;
+ case ReadmangaruProvider.CNAME:
+ provider = new ReadmangaruProvider(context);
+ break;
+ case MintmangaProvider.CNAME:
+ provider = new MintmangaProvider(context);
+ break;
+ case SelfmangaProvider.CNAME:
+ provider = new SelfmangaProvider(context);
+ break;
+ case MangarawProvider.CNAME:
+ provider = new MangarawProvider(context);
+ break;
+ case NudeMoonProvider.CNAME:
+ provider = new NudeMoonProvider(context);
+ break;
+ case MangaFoxProvider.CNAME:
+ provider = new MangaFoxProvider(context);
+ break;
+ case ZipArchiveProvider.CNAME:
+ provider = new ZipArchiveProvider(context);
+ sProviderCache.put(cName, provider);
+ return provider;
+ default:
+ throw new AssertionError(String.format("Provider %s not registered", cName));
+ }
+ sProviderCache.put(cName, provider);
+ return NetworkUtils.isNetworkAvailable(context) ? provider : new OfflineMangaProvider(context, provider);
+ }
+
+ @Nullable
+ public static MangaGenre findGenre(MangaProvider provider, @StringRes int genreNameRes) {
+ MangaGenre[] genres = provider.getAvailableGenres();
+ for (MangaGenre o : genres) {
+ if (o.nameId == genreNameRes) {
+ return o;
+ }
+ }
+ return null;
+ }
+
+ public static int findSortIndex(MangaProvider provider, @StringRes int sortOrder) {
+ int[] sorts = provider.getAvailableSortOrders();
+ for (int i = 0; i < sorts.length; i++) {
+ if (sorts[i] == sortOrder) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @NonNull
+ public static String getDomain(@CName String cName) {
+ if (sDomainsMap.isEmpty()) {
+ //init
+ sDomainsMap.put(DesumeProvider.CNAME, "desu.me");
+ sDomainsMap.put(ExhentaiProvider.CNAME, "exhentai.org");
+ sDomainsMap.put(ReadmangaruProvider.CNAME, "readmanga.me");
+ sDomainsMap.put(MintmangaProvider.CNAME, "mintmanga.com");
+ sDomainsMap.put(NudeMoonProvider.CNAME, "http://nude-moon.me");
+ }
+ return sDomainsMap.get(cName);
+ }
+
+ public static SharedPreferences getSharedPreferences(@NonNull Context context, @NonNull @CName String cName) {
+ return context.getSharedPreferences("prov_" + cName.replace('/','_'), Context.MODE_PRIVATE);
+ }
+
+ @Nullable
+ public static String getCookie(@NonNull Context context, @NonNull @CName String cName) {
+ return getSharedPreferences(context, cName).getString("_cookie", null);
+ }
+
+ protected static String url(@NonNull String domain, String subj) {
+ return subj.charAt(0) == '/' ? domain + subj : subj;
+ }
+
+ @NonNull
+ static String urlEncode(@Nullable String text) {
+ if (android.text.TextUtils.isEmpty(text)) {
+ return "";
+ }
+ try {
+ return URLEncoder.encode(text, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return text;
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/MangarawProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/MangarawProvider.java
new file mode 100644
index 00000000..c72d9f7a
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/MangarawProvider.java
@@ -0,0 +1,98 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaChaptersList;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.util.ArrayList;
+
+/**
+ * TODO
+ */
+public final class MangarawProvider extends MangaProvider {
+
+ public static final String CNAME = "network/mangaraw";
+ public static final String DNAME = "MangaRaw";
+
+ public MangarawProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ final Element body = NetworkUtils.getDocument(String.format("https://mangaraw.online/manga-list?page=%d", page+1));
+ final Elements elements = body.selectFirst(".type-content").select(".media");
+ final ArrayList list = new ArrayList<>(elements.size());
+ for (Element e : elements) {
+ final Element a = e.selectFirst("a.thumbnail");
+ list.add(new MangaHeader(
+ e.selectFirst(".chart-title").text(),
+ "",
+ "",
+ url("https://mangaraw.online", a.attr("href")),
+ url("https://mangaraw.online",a.selectFirst("img").attr("src")),
+ CNAME,
+ MangaStatus.STATUS_UNKNOWN,
+ (short) 0
+ ));
+ }
+ return list;
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final Document doc = NetworkUtils.getDocument(header.url);
+ Element root = doc.body();
+ final Element dlh = root.selectFirst(".dl-horizontal");
+ final MangaDetails details = new MangaDetails(
+ header.id,
+ header.name,
+ header.summary,
+ header.genres,
+ header.url,
+ header.thumbnail,
+ header.provider,
+ header.status,
+ header.rating,
+ "",
+ root.selectFirst(".img-responsive").attr("src"),
+ "",
+ new MangaChaptersList()
+ );
+ root = root.selectFirst("ul.chapters");
+ final Elements ch = root.select("li h5 a");
+ final String domain = "https://mangaraw.online";
+ final int len = ch.size();
+ for (int i = 0; i < len; i++) {
+ Element o = ch.get(len - i - 1);
+ details.chapters.add(new MangaChapter(
+ o.text(),
+ i,
+ url(domain, o.attr("href")),
+ header.provider
+ ));
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ return null;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/MintmangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/MintmangaProvider.java
new file mode 100644
index 00000000..c0b66139
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/MintmangaProvider.java
@@ -0,0 +1,198 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 05.02.18.
+ */
+
+public final class MintmangaProvider extends GroupleMangaProvider {
+
+ public static final String CNAME = "network/mint";
+ public static final String DNAME = "MintManga";
+
+ private final int[] mSorts = new int[] {
+ R.string.sort_popular,
+ R.string.sort_rating,
+ R.string.sort_latest,
+ R.string.sort_updated
+ };
+
+ private final String[] mSortValues = new String[] {
+ "rate",
+ "votes",
+ "created",
+ "updated"
+ };
+
+ private final MangaGenre[] mGenres = new MangaGenre[]{
+ new MangaGenre(R.string.genre_art, "art"),
+ new MangaGenre(R.string.genre_bara, "bara"),
+ new MangaGenre(R.string.genre_action, "action"),
+ new MangaGenre(R.string.genre_martialarts, "martial_arts"),
+ new MangaGenre(R.string.genre_vampires, "vampires"),
+ new MangaGenre(R.string.genre_harem, "harem"),
+ new MangaGenre(R.string.genre_genderbender, "hender_intriga"),
+ new MangaGenre(R.string.genre_hero_fantasy, "heroic_fantasy"),
+ new MangaGenre(R.string.genre_detective, "detective"),
+ new MangaGenre(R.string.genre_josei, "josei"),
+ new MangaGenre(R.string.genre_doujinshi, "doujinshi"),
+ new MangaGenre(R.string.genre_drama, "drama"),
+ new MangaGenre(R.string.genre_game, "game"),
+ new MangaGenre(R.string.genre_historical, "historical"),
+ new MangaGenre(R.string.genre_cyberpunk, "cyberpunk"),
+ new MangaGenre(R.string.genre_comedy, "comedy"),
+ new MangaGenre(R.string.genre_mecha, "mecha"),
+ new MangaGenre(R.string.genre_mystery, "mystery"),
+ new MangaGenre(R.string.genre_sci_fi, "sci_fi"),
+ new MangaGenre(R.string.genre_omegaverse, "omegaverse"),
+ new MangaGenre(R.string.genre_natural, "natural"),
+ new MangaGenre(R.string.genre_postapocalipse, "postapocalypse"),
+ new MangaGenre(R.string.genre_adventure, "adventure"),
+ new MangaGenre(R.string.genre_psychological, "psychological"),
+ new MangaGenre(R.string.genre_romance, "romance"),
+ new MangaGenre(R.string.genre_samurai, "samurai"),
+ new MangaGenre(R.string.genre_supernatural, "supernatural"),
+ new MangaGenre(R.string.genre_shoujo, "shoujo"),
+ new MangaGenre(R.string.genre_shoujo_ai, "shoujo_ai"),
+ new MangaGenre(R.string.genre_shounen, "shounen"),
+ new MangaGenre(R.string.genre_shounen_ai, "shounen_ai"),
+ new MangaGenre(R.string.genre_sports, "sport"),
+ new MangaGenre(R.string.genre_seinen, "seinen"),
+ new MangaGenre(R.string.genre_tragedy, "tragedy"),
+ new MangaGenre(R.string.genre_thriller, "thriller"),
+ new MangaGenre(R.string.genre_horror, "horror"),
+ new MangaGenre(R.string.genre_fantastic, "fantastic"),
+ new MangaGenre(R.string.genre_fantasy, "fantasy"),
+ new MangaGenre(R.string.genre_school, "school"),
+ new MangaGenre(R.string.genre_erotica, "erotica"),
+ new MangaGenre(R.string.genre_ecchi, "ecchi"),
+ new MangaGenre(R.string.genre_yuri, "yuri"),
+ new MangaGenre(R.string.genre_yaoi, "yaoi")
+ };
+
+ private final String[] mTags = new String[] {
+ "el_2220",
+ "el_1353",
+ "el_1346",
+ "el_1334",
+ "el_1339",
+ "el_1333",
+ "el_1347",
+ "el_1337",
+ "el_1343",
+ "el_1349",
+ "el_1332",
+ "el_1310",
+ "el_5229",
+ "el_1311",
+ "el_1351",
+ "el_1328",
+ "el_1318",
+ "el_1324",
+ "el_1325",
+ "el_5676",
+ "el_1327",
+ "el_1342",
+ "el_1322",
+ "el_1335",
+ "el_1313",
+ "el_1316",
+ "el_1350",
+ "el_1314",
+ "el_1320",
+ "el_1326",
+ "el_1330",
+ "el_1321",
+ "el_1329",
+ "el_1344",
+ "el_1341",
+ "el_1317",
+ "el_1331",
+ "el_1323",
+ "el_1319",
+ "el_1340",
+ "el_1354",
+ "el_1315",
+ "el_1336"
+ };
+
+ public MintmangaProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @SuppressLint("DefaultLocale")
+ protected ArrayList getList(int page, int sortOrder, @Nullable String genre) throws Exception {
+ String url = String.format(
+ "http://mintmanga.com/list%s?lang=&sortType=%s&offset=%d&max=70",
+ genre == null ? "" : "/genre/" + genre,
+ sortOrder == -1 ? "rate" : mSortValues[sortOrder],
+ page * 70
+ );
+ Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaBox").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://mintmanga.com/");
+ }
+
+ @NonNull
+ @SuppressLint("DefaultLocale")
+ protected ArrayList simpleSearch(@NonNull String search, int page) throws Exception {
+ String url = String.format(
+ "http://mintmanga.com/search?q=%s&offset=%d&max=50",
+ search,
+ page * 50
+ );
+ Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ if (root == null) {
+ return EMPTY_HEADERS;
+ }
+ return parseList(root.select(".tile"), "http://mintmanga.com/");
+ }
+
+ @NonNull
+ @SuppressLint("DefaultLocale")
+ protected ArrayList advancedSearch(@NonNull String search, @NonNull String[] genres) throws Exception {
+ final StringJoinerCompat query = new StringJoinerCompat("&", "&", "");
+ for (String o : genres) {
+ int i = MangaGenre.indexOf(mGenres, o);
+ if (i < 0 || i >= mTags.length) {
+ continue;
+ }
+ String tag = mTags[i];
+ query.add(tag + "=in");
+ }
+ Document doc = NetworkUtils.getDocument("http://mintmanga.com/search/advanced?q=" + urlEncode(search) + query.toString());
+ Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://readmanga.me/");
+ }
+
+ @CName
+ public String getCName() {
+ return CNAME;
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/NudeMoonProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/NudeMoonProvider.java
new file mode 100644
index 00000000..5a9ae014
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/NudeMoonProvider.java
@@ -0,0 +1,146 @@
+package org.nv95.openmanga.core.providers;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.jsoup.select.Elements;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.utils.CollectionsUtils;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaChaptersList;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.util.ArrayList;
+
+public final class NudeMoonProvider extends MangaProvider {
+
+ private static final String BASE_URL = "http://nude-moon.me";
+
+ public static final String CNAME = "network/nude-moon";
+ public static final String DNAME = "Nude-Moon";
+
+ private final int[] mSorts = new int[] {
+ R.string.sort_latest,
+ R.string.sort_popular,
+ R.string.sort_comments,
+ R.string.sort_rating
+ };
+
+ private final String[] mSortValues = new String[] {
+ "date",
+ "views",
+ "com",
+ "like"
+ };
+
+ public NudeMoonProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ final StringBuilder url = new StringBuilder("http://nude-moon.me/");
+ if (!TextUtils.isEmpty(search)) {
+ if (search.startsWith(":")) { //tags
+ url.append("tags/").append(TextUtils.join("_", search.substring(1).split("\\s"))).append("+");
+ } else {
+ url.append("search?stext=").append(search);
+ }
+ url.append("&").append(sortOrder == -1 ? "date" : mSortValues[sortOrder]);
+ } else {
+ url.append("all_manga?").append(sortOrder == -1 ? "date" : mSortValues[sortOrder]);
+ }
+ final Document document = NetworkUtils.getDocument(url.toString());
+ final Element root = document.body().selectFirst("td.main-bg");
+ final Elements elements = root.select("table.news_pic2");
+ if (elements == null) {
+ throw new RuntimeException("td.main-bg > table.news_pic2 is null");
+ }
+ final ArrayList list = new ArrayList<>(elements.size());
+ for (Element o : elements) {
+ try {
+ final Element a = o.selectFirst(".bg_style1").selectFirst("a");
+ final String[] name = a.text().split(" / ");
+ list.add(new MangaHeader(
+ name[0],
+ name.length > 1 ? name[1] : "",
+ o.getElementById("tags").text(),
+ url(BASE_URL, a.attr("href")),
+ url(BASE_URL, o.selectFirst("img.news_pic2").attr("src")),
+ CNAME,
+ MangaStatus.STATUS_UNKNOWN,
+ (short) 0
+ ));
+ } catch (Exception ignored) {
+ }
+ }
+ return list;
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final Document doc = NetworkUtils.getDocument(header.url);
+ Element root = doc.body().selectFirst("td.main-body");
+ final StringBuilder description = new StringBuilder();
+ final Elements titles = root.select("font.darkgreen");
+ String author = "";
+ for (Element o : titles) {
+ final String title = o.text();
+ if (title.startsWith("Автор")) {
+ author = o.nextElementSibling().text();
+ continue;
+ }
+ description.append("")
+ .append(title)
+ .append(" ")
+ .append(o.nextElementSibling().text())
+ .append("
");
+ }
+ final MangaDetails details = new MangaDetails(
+ header,
+ description.toString(),
+ url(BASE_URL, root.selectFirst("img.news_pic2").attr("src")),
+ author
+ );
+ details.chapters.add(new MangaChapter(
+ header.name,
+ 0,
+ url(BASE_URL, root.selectFirst("td.button").getElementsContainingOwnText("Читать онлайн").first().attr("href") + "?row"),
+ header.provider
+ ));
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ final ArrayList pages = new ArrayList<>();
+ final Element root = NetworkUtils.getDocument(chapterUrl).body().selectFirst("div.square-red");
+ final Elements cells = root.select("center");
+ for (Element cell : cells) {
+ final Element img = cell.selectFirst("img");
+ if (img != null) {
+ pages.add(new MangaPage(
+ url(BASE_URL, img.attr("src")),
+ CNAME
+ ));
+ }
+ }
+ return pages;
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/OfflineMangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/OfflineMangaProvider.java
new file mode 100644
index 00000000..ec9bd4d9
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/OfflineMangaProvider.java
@@ -0,0 +1,169 @@
+package org.nv95.openmanga.core.providers;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+import org.nv95.openmanga.core.models.SavedChapter;
+import org.nv95.openmanga.core.models.SavedManga;
+import org.nv95.openmanga.core.models.SavedPage;
+import org.nv95.openmanga.core.storage.db.SavedChaptersRepository;
+import org.nv95.openmanga.core.storage.db.SavedChaptersSpecification;
+import org.nv95.openmanga.core.storage.db.SavedMangaRepository;
+import org.nv95.openmanga.core.storage.db.SavedPagesRepository;
+import org.nv95.openmanga.core.storage.db.SavedPagesSpecification;
+import org.nv95.openmanga.core.storage.files.SavedPagesStorage;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by koitharu on 31.01.18.
+ */
+
+public final class OfflineMangaProvider extends MangaProvider {
+
+ private final MangaProvider mDelegate;
+
+ public OfflineMangaProvider(Context context, MangaProvider delegate) {
+ super(context);
+ mDelegate = delegate;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ return mDelegate.query(search, page, sortOrder, genres);
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ if (NetworkUtils.isNetworkAvailable(mContext)) {
+ return mDelegate.getDetails(header);
+ }
+ final SavedManga savedManga = SavedMangaRepository.get(mContext).find(header);
+ if (savedManga == null) {
+ throw new FileNotFoundException();
+ }
+ final MangaDetails details = MangaDetails.from(savedManga);
+ final ArrayList savedChapters = SavedChaptersRepository.get(mContext)
+ .query(new SavedChaptersSpecification().manga(header));
+ if (savedChapters != null) {
+ for (SavedChapter o : savedChapters) {
+ o.addFlag(MangaChapter.FLAG_CHAPTER_SAVED);
+ details.chapters.add(o);
+ }
+ }
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ if (NetworkUtils.isNetworkAvailable(mContext)) {
+ return mDelegate.getPages(chapterUrl);
+ }
+ final SavedPagesRepository repository = SavedPagesRepository.get(mContext);
+ final SavedChapter chapter = SavedChaptersRepository.get(mContext).findChapterByUrl(chapterUrl);
+ if (chapter == null) {
+ throw new RuntimeException("Chapter not found");
+ }
+ final List pages = repository.query(new SavedPagesSpecification(chapter));
+ if (pages == null) {
+ throw new RuntimeException("Failed query saved pages");
+ }
+ final ArrayList result = new ArrayList<>(pages.size());
+ final SavedManga savedManga = SavedMangaRepository.get(mContext).get(chapter.mangaId);
+ if (savedManga == null) {
+ throw new RuntimeException("Manga not saved!");
+ }
+ final SavedPagesStorage localStorage = new SavedPagesStorage(savedManga);
+ for (SavedPage o : pages) {
+ result.add(new MangaPage(
+ o.id,
+ "file://" + localStorage.getFile(o).getPath(),
+ o.provider
+ ));
+ }
+ return result;
+ }
+
+ @Override
+ protected SharedPreferences getPreferences() {
+ return mDelegate.getPreferences();
+ }
+
+ @NonNull
+ @Override
+ public String getImageUrl(MangaPage page) throws Exception {
+ return page.url.startsWith("file://") ? page.url : mDelegate.getImageUrl(page);
+ }
+
+ @Override
+ public boolean signIn(String login, String password) throws Exception {
+ return mDelegate.signIn(login, password);
+ }
+
+ @Override
+ protected void setAuthCookie(@Nullable String cookie) {
+ mDelegate.setAuthCookie(cookie);
+ }
+
+ @Nullable
+ @Override
+ protected String getAuthCookie() {
+ return mDelegate.getAuthCookie();
+ }
+
+ @Override
+ public boolean isSearchSupported() {
+ return mDelegate.isSearchSupported();
+ }
+
+ @Override
+ public boolean isMultipleGenresSupported() {
+ return mDelegate.isMultipleGenresSupported();
+ }
+
+ @Override
+ public boolean isAuthorizationSupported() {
+ return mDelegate.isAuthorizationSupported();
+ }
+
+ @Nullable
+ @Override
+ public String authorize(@NonNull String login, @NonNull String password) throws Exception {
+ return mDelegate.authorize(login, password);
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mDelegate.getAvailableGenres();
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mDelegate.getAvailableSortOrders();
+ }
+
+ @Nullable
+ @Override
+ public String getCName() {
+ return mDelegate.getCName();
+ }
+
+ @Nullable
+ @Override
+ public String getName() {
+ return mDelegate.getName();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/ReadmangaruProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/ReadmangaruProvider.java
new file mode 100644
index 00000000..bba29c1e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/ReadmangaruProvider.java
@@ -0,0 +1,197 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 26.01.18.
+ */
+
+public final class ReadmangaruProvider extends GroupleMangaProvider {
+
+ public static final String CNAME = "network/readmanga.ru";
+ public static final String DNAME = "ReadManga";
+
+ private final int[] mSorts = new int[] {
+ R.string.sort_popular,
+ R.string.sort_rating,
+ R.string.sort_latest,
+ R.string.sort_updated
+ };
+
+ private final String[] mSortValues = new String[] {
+ "rate",
+ "votes",
+ "created",
+ "updated"
+ };
+
+ private final MangaGenre[] mGenres = new MangaGenre[]{
+ new MangaGenre(R.string.genre_art, "art"),
+ new MangaGenre(R.string.genre_action, "action"),
+ new MangaGenre(R.string.genre_martialarts, "martial_arts"),
+ new MangaGenre(R.string.genre_vampires, "vampires"),
+ new MangaGenre(R.string.genre_harem, "harem"),
+ new MangaGenre(R.string.genre_genderbender, "hender_intriga"),
+ new MangaGenre(R.string.genre_hero_fantasy, "heroic_fantasy"),
+ new MangaGenre(R.string.genre_detective, "detective"),
+ new MangaGenre(R.string.genre_josei, "josei"),
+ new MangaGenre(R.string.genre_doujinshi, "doujinshi"),
+ new MangaGenre(R.string.genre_drama, "drama"),
+ new MangaGenre(R.string.genre_game, "game"),
+ new MangaGenre(R.string.genre_historical, "historical"),
+ new MangaGenre(R.string.genre_cyberpunk, "cyberpunk"),
+ new MangaGenre(R.string.genre_codomo, "codomo"),
+ new MangaGenre(R.string.genre_comedy, "comedy"),
+ new MangaGenre(R.string.genre_maho_shoujo, "maho_shoujo"),
+ new MangaGenre(R.string.genre_mecha, "mecha"),
+ new MangaGenre(R.string.genre_mystery, "mystery"),
+ new MangaGenre(R.string.genre_sci_fi, "sci_fi"),
+ new MangaGenre(R.string.genre_natural, "natural"),
+ new MangaGenre(R.string.genre_postapocalipse, "postapocalypse"),
+ new MangaGenre(R.string.genre_adventure, "adventure"),
+ new MangaGenre(R.string.genre_psychological, "psychological"),
+ new MangaGenre(R.string.genre_romance, "romance"),
+ new MangaGenre(R.string.genre_samurai, "samurai"),
+ new MangaGenre(R.string.genre_supernatural, "supernatural"),
+ new MangaGenre(R.string.genre_shoujo, "shoujo"),
+ new MangaGenre(R.string.genre_shoujo_ai, "shoujo_ai"),
+ new MangaGenre(R.string.genre_shounen, "shounen"),
+ new MangaGenre(R.string.genre_shounen_ai, "shounen_ai"),
+ new MangaGenre(R.string.genre_sports, "sport"),
+ new MangaGenre(R.string.genre_seinen, "seinen"),
+ new MangaGenre(R.string.genre_tragedy, "tragedy"),
+ new MangaGenre(R.string.genre_thriller, "thriller"),
+ new MangaGenre(R.string.genre_horror, "horror"),
+ new MangaGenre(R.string.genre_fantastic, "fantastic"),
+ new MangaGenre(R.string.genre_fantasy, "fantasy"),
+ new MangaGenre(R.string.genre_school, "school"),
+ new MangaGenre(R.string.genre_ecchi, "ecchi"),
+ new MangaGenre(R.string.genre_yuri, "yuri")
+ };
+
+ private final String[] mTags = new String[] {
+ "el_5685",
+ "el_2155",
+ "el_2143",
+ "el_2148",
+ "el_2142",
+ "el_2156",
+ "el_2146",
+ "el_2152",
+ "el_2158",
+ "el_2141",
+ "el_2118",
+ "el_2154",
+ "el_2119",
+ "el_8032",
+ "el_2137",
+ "el_2136",
+ "el_2147",
+ "el_2126",
+ "el_2132",
+ "el_2133",
+ "el_2135",
+ "el_2151",
+ "el_2130",
+ "el_2144",
+ "el_2121",
+ "el_2124",
+ "el_2159",
+ "el_2122",
+ "el_2128",
+ "el_2134",
+ "el_2139",
+ "el_2129",
+ "el_2138",
+ "el_2153",
+ "el_2150",
+ "el_2125",
+ "el_2140",
+ "el_2131",
+ "el_2127",
+ "el_2149",
+ "el_2123"
+ };
+
+ public ReadmangaruProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList getList(int page, int sortOrder, @Nullable String genre) throws Exception {
+ String url = String.format(
+ "http://readmanga.me/list%s?lang=&sortType=%s&offset=%d&max=70",
+ genre == null ? "" : "/genre/" + genre,
+ sortOrder == -1 ? "rate" : mSortValues[sortOrder],
+ page * 70
+ );
+ Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaBox").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://readmanga.me/");
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList simpleSearch(@NonNull String search, int page) throws Exception {
+ final String url = String.format(
+ "http://readmanga.me/search?q=%s&offset=%d&max=50",
+ search,
+ page * 50
+ ); //TODO fix "nothing found" problem
+ final Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ if (root == null) {
+ return EMPTY_HEADERS;
+ }
+ return parseList(root.select(".tile"), "http://readmanga.me/");
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList advancedSearch(@NonNull String search, @NonNull String[] genres) throws Exception {
+ final StringJoinerCompat query = new StringJoinerCompat("&", "&", "");
+ for (String o : genres) {
+ int i = MangaGenre.indexOf(mGenres, o);
+ if (i < 0 || i >= mTags.length) {
+ continue;
+ }
+ String tag = mTags[i];
+ query.add(tag + "=in");
+ }
+ final Document doc = NetworkUtils.getDocument("http://readmanga.me/search/advanced?q=" + urlEncode(search) + query.toString());
+ final Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://readmanga.me/");
+ }
+
+ @CName
+ public String getCName() {
+ return CNAME;
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/RelativeMangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/RelativeMangaProvider.java
new file mode 100644
index 00000000..00fb88e3
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/RelativeMangaProvider.java
@@ -0,0 +1,14 @@
+package org.nv95.openmanga.core.providers;
+
+import org.nv95.openmanga.core.models.MangaHeader;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 17.01.18.
+ */
+
+public interface RelativeMangaProvider {
+
+ ArrayList getRelativeManga(MangaHeader manga);
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/SelfmangaProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/SelfmangaProvider.java
new file mode 100644
index 00000000..739f746b
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/SelfmangaProvider.java
@@ -0,0 +1,181 @@
+package org.nv95.openmanga.core.providers;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.StringJoinerCompat;
+import org.nv95.openmanga.common.utils.network.NetworkUtils;
+import org.nv95.openmanga.core.models.MangaGenre;
+import org.nv95.openmanga.core.models.MangaHeader;
+
+import java.util.ArrayList;
+
+public final class SelfmangaProvider extends GroupleMangaProvider {
+
+ public static final String CNAME = "network/selfmanga.ru";
+ public static final String DNAME = "SelfManga";
+
+ private final int[] mSorts = new int[] {
+ R.string.sort_popular,
+ R.string.sort_rating,
+ R.string.sort_latest,
+ R.string.sort_updated
+ };
+
+ private final String[] mSortValues = new String[] {
+ "rate",
+ "votes",
+ "created",
+ "updated"
+ };
+
+ private final MangaGenre[] mGenres = new MangaGenre[]{
+ new MangaGenre(R.string.genre_action, "action"),
+ new MangaGenre(R.string.genre_martialarts, "martial_arts"),
+ new MangaGenre(R.string.genre_vampires, "vampires"),
+ new MangaGenre(R.string.genre_harem, "harem"),
+ new MangaGenre(R.string.genre_genderbender, "hender_intriga"),
+ new MangaGenre(R.string.genre_hero_fantasy, "heroic_fantasy"),
+ new MangaGenre(R.string.genre_detective, "detective"),
+ new MangaGenre(R.string.genre_josei, "josei"),
+ new MangaGenre(R.string.genre_doujinshi, "doujinshi"),
+ new MangaGenre(R.string.genre_drama, "drama"),
+ new MangaGenre(R.string.genre_yonkoma, "yonkoma"),
+ new MangaGenre(R.string.genre_historical, "historical"),
+ new MangaGenre(R.string.genre_comedy, "comedy"),
+ new MangaGenre(R.string.genre_maho_shoujo, "maho_shoujo"),
+ new MangaGenre(R.string.genre_mystery, "mystery"),
+ new MangaGenre(R.string.genre_sci_fi, "sci_fi"),
+ new MangaGenre(R.string.genre_natural, "natural"),
+ new MangaGenre(R.string.genre_postapocalipse, "postapocalypse"),
+ new MangaGenre(R.string.genre_adventure, "adventure"),
+ new MangaGenre(R.string.genre_psychological, "psychological"),
+ new MangaGenre(R.string.genre_romance, "romance"),
+ new MangaGenre(R.string.genre_supernatural, "supernatural"),
+ new MangaGenre(R.string.genre_shoujo, "shoujo"),
+ new MangaGenre(R.string.genre_shoujo_ai, "shoujo_ai"),
+ new MangaGenre(R.string.genre_shounen, "shounen"),
+ new MangaGenre(R.string.genre_shounen_ai, "shounen_ai"),
+ new MangaGenre(R.string.genre_sports, "sport"),
+ new MangaGenre(R.string.genre_seinen, "seinen"),
+ new MangaGenre(R.string.genre_tragedy, "tragedy"),
+ new MangaGenre(R.string.genre_thriller, "thriller"),
+ new MangaGenre(R.string.genre_horror, "horror"),
+ new MangaGenre(R.string.genre_fantastic, "fantastic"),
+ new MangaGenre(R.string.genre_fantasy, "fantasy"),
+ new MangaGenre(R.string.genre_school, "school"),
+ new MangaGenre(R.string.genre_ecchi, "ecchi")
+ };
+
+ private final String[] mTags = new String[] {
+ "el_2155",
+ "el_2143",
+ "el_2148",
+ "el_2142",
+ "el_2156",
+ "el_2146",
+ "el_2152",
+ "el_2158",
+ "el_2141",
+ "el_2118",
+ "el_2161",
+ "el_2119",
+ "el_2136",
+ "el_2147",
+ "el_2132",
+ "el_2133",
+ "el_2135",
+ "el_2151",
+ "el_2130",
+ "el_2144",
+ "el_2121",
+ "el_2159",
+ "el_2122",
+ "el_2128",
+ "el_2134",
+ "el_2139",
+ "el_2129",
+ "el_2138",
+ "el_2153",
+ "el_2150",
+ "el_2125",
+ "el_2140",
+ "el_2131",
+ "el_2127",
+ "el_4982"
+ };
+
+ public SelfmangaProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList getList(int page, int sortOrder, @Nullable String genre) throws Exception {
+ String url = String.format(
+ "http://selfmanga.ru/list%s?lang=&sortType=%s&offset=%d&max=70",
+ genre == null ? "" : "/genre/" + genre,
+ sortOrder == -1 ? "rate" : mSortValues[sortOrder],
+ page * 70
+ );
+ Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaBox").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://selfmanga.ru/");
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList simpleSearch(@NonNull String search, int page) throws Exception {
+ String url = String.format(
+ "http://selfmanga.ru/search?q=%s&offset=%d&max=50",
+ search,
+ page * 50
+ );
+ Document doc = NetworkUtils.getDocument(url);
+ Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ if (root == null) {
+ return EMPTY_HEADERS;
+ }
+ return parseList(root.select(".tile"), "http://selfmanga.ru/");
+ }
+
+ @NonNull
+ @Override
+ @SuppressLint("DefaultLocale")
+ protected ArrayList advancedSearch(@NonNull String search, @NonNull String[] genres) throws Exception {
+ final StringJoinerCompat query = new StringJoinerCompat("&", "&", "");
+ for (String o : genres) {
+ int i = MangaGenre.indexOf(mGenres, o);
+ if (i < 0 || i >= mTags.length) {
+ continue;
+ }
+ String tag = mTags[i];
+ query.add(tag + "=in");
+ }
+ Document doc = NetworkUtils.getDocument("http://selfmanga.ru/search/advanced?q=" + urlEncode(search) + query.toString());
+ Element root = doc.body().getElementById("mangaResults").selectFirst("div.tiles");
+ return parseList(root.select(".tile"), "http://selfmanga.ru/");
+ }
+
+ @CName
+ public String getCName() {
+ return CNAME;
+ }
+
+ @Override
+ public MangaGenre[] getAvailableGenres() {
+ return mGenres;
+ }
+
+ @Override
+ public int[] getAvailableSortOrders() {
+ return mSorts;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/providers/ZipArchiveProvider.java b/app/src/main/java/org/nv95/openmanga/core/providers/ZipArchiveProvider.java
new file mode 100644
index 00000000..4d04066e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/providers/ZipArchiveProvider.java
@@ -0,0 +1,281 @@
+package org.nv95.openmanga.core.providers;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.ThumbnailUtils;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.util.Pair;
+
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.NaturalOrderComparator;
+import org.nv95.openmanga.common.utils.CollectionsUtils;
+import org.nv95.openmanga.common.utils.FilesystemUtils;
+import org.nv95.openmanga.common.utils.MetricsUtils;
+import org.nv95.openmanga.core.MangaStatus;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+
+public final class ZipArchiveProvider extends MangaProvider {
+
+ public static final String CNAME = "storage/zip";
+ public static final String DNAME = "Archive";
+ public static final String SCHEME = "manga+zip";
+
+ public ZipArchiveProvider(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ @Override
+ public ArrayList query(@Nullable String search, int page, int sortOrder, @NonNull String[] genres) throws Exception {
+ return EMPTY_HEADERS;
+ }
+
+ @NonNull
+ @Override
+ public MangaDetails getDetails(MangaHeader header) throws Exception {
+ final MangaDetails details = new MangaDetails(
+ header,
+ "",
+ header.thumbnail,
+ ""
+ );
+ details.chapters.add(new MangaChapter(header.name, 0, header.url, CNAME));
+ return details;
+ }
+
+ @NonNull
+ @Override
+ public ArrayList getPages(String chapterUrl) throws Exception {
+ ZipFile zipFile = null;
+ final Uri uri = Uri.parse(chapterUrl);
+ try {
+ final ArrayList> pagesPairs = new ArrayList<>();
+ zipFile = new ZipFile(uri.getPath());
+ final Uri zipUri = new Uri.Builder()
+ .scheme(SCHEME)
+ .encodedPath(uri.getEncodedPath())
+ .build();
+ final Enumeration extends ZipEntry> entries = zipFile.entries();
+ ZipEntry e;
+ while (entries.hasMoreElements()) {
+ e = entries.nextElement();
+ if (!e.isDirectory()) {
+ pagesPairs.add(new Pair<>(e.getName(), new MangaPage(
+ Uri.withAppendedPath(zipUri, e.getName()).toString(),
+ CNAME
+ )));
+ }
+ }
+ Collections.sort(pagesPairs, new NaturalOrderComparator>() {
+ @Override
+ protected String objectToString(Pair obj) {
+ return obj.first;
+ }
+ });
+ return CollectionsUtils.mapSeconds(pagesPairs);
+ } finally {
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ @NonNull
+ @Override
+ public String getName() {
+ return mContext.getString(R.string.file_archive);
+ }
+
+ @WorkerThread
+ @Nullable
+ public static MangaHeader getManga(@NonNull Context context, @NonNull Uri uri) {
+ try {
+ new ZipFile(uri.getPath()).close(); //check if supported format
+ final File thumbRoot = new File(context.getExternalFilesDir("thumb"), "zip");
+ if (!thumbRoot.exists() && !thumbRoot.mkdirs()) {
+ return null;
+ }
+ String thumbUri = "";
+ final Bitmap page = getFirstPage(context, uri);
+ if (page != null) {
+ try {
+ final File thumbFile = new File(thumbRoot, String.valueOf(uri.toString().hashCode()));
+ final MetricsUtils.Size size = MetricsUtils.getPreferredCellSizeMedium(context.getResources());
+ final Bitmap thumb = ThumbnailUtils.extractThumbnail(page, size.width, size.height);
+ page.recycle();
+ FileOutputStream outputStream = new FileOutputStream(thumbFile);
+ thumb.compress(Bitmap.CompressFormat.PNG, 9, outputStream);
+ outputStream.close();
+ thumb.recycle();
+ thumbUri = Uri.fromFile(thumbFile).toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return new MangaHeader(
+ FilesystemUtils.getBasename(uri.getLastPathSegment()),
+ "",
+ "",
+ uri.toString(),
+ thumbUri,
+ CNAME,
+ MangaStatus.STATUS_UNKNOWN,
+ (short) 0
+
+ );
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Nullable
+ public static File createThumbnail(@NonNull Context context, @NonNull Uri uri, @NonNull MetricsUtils.Size size) {
+ File cacheDir = context.getExternalCacheDir();
+ if (cacheDir == null) {
+ cacheDir = context.getCacheDir();
+ }
+ if (cacheDir == null) {
+ return null;
+ }
+ cacheDir = new File(cacheDir, "zipthumbs");
+ if (!cacheDir.exists() && !cacheDir.mkdir()) {
+ return null;
+ }
+ final File output = new File(cacheDir, String.valueOf(uri.toString().hashCode()));
+ if (output.exists()) {
+ return output;
+ }
+ FileOutputStream outputStream = null;
+ try {
+ final Bitmap page = getFirstPage(context, uri);
+ if (page != null) {
+ final Bitmap thumbnail = ThumbnailUtils.extractThumbnail(page, size.width, size.height);
+ page.recycle();
+ outputStream = new FileOutputStream(output);
+ thumbnail.compress(Bitmap.CompressFormat.PNG, 9, outputStream);
+ return output;
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ public static boolean isFileSupported(@NonNull File file) {
+ return isFileSupported(file.getPath());
+ }
+
+ public static boolean isFileSupported(@NonNull String filename) {
+ final String ext = FilesystemUtils.getExtension(filename);
+ return "cbz".equalsIgnoreCase(ext) || "zip".equalsIgnoreCase(ext);
+ }
+
+ @Nullable
+ private static Bitmap getFirstPage(@NonNull Context context, @NonNull Uri uri) {
+ ZipInputStream zipInputStream = null;
+ try {
+ int tries = 4;
+ zipInputStream = new ZipInputStream(context.getContentResolver().openInputStream(uri));
+ ZipEntry entry;
+ while (tries >= 0 && (entry = zipInputStream.getNextEntry()) != null) {
+ if (!entry.isDirectory()) {
+ try {
+ final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ int len;
+ final byte[] buffer = new byte[512];
+ while ((len = zipInputStream.read(buffer)) > 0) {
+ bytes.write(buffer, 0, len);
+ }
+ return BitmapFactory.decodeByteArray(bytes.toByteArray(), 0, bytes.size());
+ } catch (Exception e) {
+ e.printStackTrace();
+ tries--;
+ }
+ }
+ }
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ if (zipInputStream != null) {
+ try {
+ zipInputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ public static void extractTo(String pageUrl, File destination) throws Throwable {
+ InputStream inputStream = null;
+ FileOutputStream outputStream = null;
+ ZipFile zipFile = null;
+ try {
+ final Uri uri = Uri.parse(pageUrl);
+ final String name = uri.getLastPathSegment();
+ String path = uri.getPath();
+ path = path.substring(0, path.lastIndexOf('/'));
+ zipFile = new ZipFile(path);
+ final ZipEntry entry = zipFile.getEntry(name);
+ inputStream = zipFile.getInputStream(entry);
+ outputStream = new FileOutputStream(destination);
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = inputStream.read(buffer)) > 0) {
+ outputStream.write(buffer, 0, length);
+ }
+ outputStream.flush();
+ //throw new FileNotFoundException(String.format("Entry %s was not found in archive", name));
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ if (zipFile != null) {
+ try {
+ zipFile.close();
+ } catch (IOException ignored) {
+ }
+ }
+ if (outputStream != null) {
+ try {
+ outputStream.close();
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/FlagsStorage.java b/app/src/main/java/org/nv95/openmanga/core/storage/FlagsStorage.java
new file mode 100644
index 00000000..517b71ee
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/FlagsStorage.java
@@ -0,0 +1,79 @@
+package org.nv95.openmanga.core.storage;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 29.01.18.
+ */
+
+public final class FlagsStorage {
+
+ @Nullable
+ private static WeakReference sInstanceReference = null;
+
+ private final SharedPreferences mPreferences;
+
+ public static synchronized FlagsStorage get(Context context) {
+ FlagsStorage instance = sInstanceReference == null ? null : sInstanceReference.get();
+ if (instance == null) {
+ instance = new FlagsStorage(context);
+ sInstanceReference = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private FlagsStorage(Context context) {
+ mPreferences = context.getApplicationContext().getSharedPreferences("flags", Context.MODE_PRIVATE);
+ }
+
+ public boolean isWizardRequired() {
+ return mPreferences.getBoolean("wizard_required", true);
+ }
+
+ public void setWizardRequired(boolean value) {
+ mPreferences.edit().putBoolean("wizard_required", value).apply();
+ }
+
+ public boolean isListDetailed() {
+ return mPreferences.getBoolean("list_detailed", false);
+ }
+
+ public void setIsListDetailed(boolean value) {
+ mPreferences.edit().putBoolean("list_detailed", value).apply();
+ }
+
+ public boolean isHistoryDetailed() {
+ return mPreferences.getBoolean("history_detailed", false);
+ }
+
+ public void setIsHistoryDetailed(boolean value) {
+ mPreferences.edit().putBoolean("history_detailed", value).apply();
+ }
+
+ public void setLastPickerDir(@NonNull File root) {
+ mPreferences.edit().putString("picker_root", root.getAbsolutePath()).apply();
+ }
+
+ public File getLastPickerRoot(File defValue) {
+ final String stored = mPreferences.getString("picker_root", null);
+ if (android.text.TextUtils.isEmpty(stored)) {
+ return defValue;
+ }
+ final File root = new File(stored);
+ return root.exists() && root.canRead() ? root : defValue;
+ }
+
+ public boolean isPickerFilterFiles() {
+ return mPreferences.getBoolean("picker_filter", false);
+ }
+
+ public void setPickerFilterFiles(boolean value) {
+ mPreferences.edit().putBoolean("picker_filter", value).apply();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/ProvidersStore.java b/app/src/main/java/org/nv95/openmanga/core/storage/ProvidersStore.java
new file mode 100644
index 00000000..8fc6a281
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/ProvidersStore.java
@@ -0,0 +1,100 @@
+package org.nv95.openmanga.core.storage;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.support.annotation.NonNull;
+import android.text.TextUtils;
+import android.util.SparseBooleanArray;
+
+import org.nv95.openmanga.common.utils.CollectionsUtils;
+import org.nv95.openmanga.core.models.ProviderHeader;
+import org.nv95.openmanga.core.providers.DesumeProvider;
+import org.nv95.openmanga.core.providers.ExhentaiProvider;
+import org.nv95.openmanga.core.providers.MangaFoxProvider;
+import org.nv95.openmanga.core.providers.MintmangaProvider;
+import org.nv95.openmanga.core.providers.NudeMoonProvider;
+import org.nv95.openmanga.core.providers.ReadmangaruProvider;
+import org.nv95.openmanga.core.providers.SelfmangaProvider;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * Created by koitharu on 17.01.18.
+ */
+
+public final class ProvidersStore {
+
+ private static final ProviderHeader[] sProviders = new ProviderHeader[]{
+ new ProviderHeader(ReadmangaruProvider.CNAME, ReadmangaruProvider.DNAME), //0
+ new ProviderHeader(MintmangaProvider.CNAME, MintmangaProvider.DNAME), //1
+ new ProviderHeader(DesumeProvider.CNAME, DesumeProvider.DNAME), //2
+ new ProviderHeader(ExhentaiProvider.CNAME, ExhentaiProvider.DNAME), //3
+ new ProviderHeader(SelfmangaProvider.CNAME, SelfmangaProvider.DNAME), //4
+ new ProviderHeader(NudeMoonProvider.CNAME, NudeMoonProvider.DNAME), //5
+ new ProviderHeader(MangaFoxProvider.CNAME, MangaFoxProvider.DNAME), //6
+ //new ProviderHeader(MangarawProvider.CNAME, MangarawProvider.DNAME) //7
+ };
+
+ private final SharedPreferences mPreferences;
+
+ public ProvidersStore(Context context) {
+ mPreferences = context.getSharedPreferences("providers", Context.MODE_PRIVATE);
+ }
+
+ public ArrayList getAllProvidersSorted() {
+ final ArrayList list = new ArrayList<>(sProviders.length);
+ final int[] order = CollectionsUtils.convertToInt(mPreferences.getString("order", "").split("\\|"), -1);
+ for (int o : order) {
+ ProviderHeader h = CollectionsUtils.getOrNull(sProviders, o);
+ if (h != null) {
+ list.add(h);
+ }
+ }
+ for (ProviderHeader h : sProviders) {
+ if (!list.contains(h)) {
+ list.add(h);
+ }
+ }
+ return list;
+ }
+
+ public ArrayList getUserProviders() {
+ final ArrayList list = getAllProvidersSorted();
+ final int[] disabled = getDisabledIds();
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ProviderHeader h = iterator.next();
+ if (CollectionsUtils.indexOf(disabled, h.hashCode()) != -1) {
+ iterator.remove();
+ }
+ }
+ return list;
+ }
+
+ public void save(ArrayList providers, SparseBooleanArray enabled) {
+ final Integer[] order = new Integer[providers.size()];
+ for (int i = 0; i < sProviders.length; i++) {
+ ProviderHeader h = sProviders[i];
+ int p = providers.indexOf(h);
+ if (p != -1) {
+ order[i] = p;
+ }
+ }
+ final ArrayList disabled = new ArrayList<>();
+ for (int i=0;i args = new ArrayList<>(4);
+ args.add(mRemoved ? "1" : "0");
+ if (mMangaId != null) {
+ args.add(String.valueOf(mMangaId));
+ }
+ if (mChapterId != null) {
+ args.add(String.valueOf(mChapterId));
+ }
+ return args.toArray(new String[args.size()]);
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(5);
+ bundle.putString("order_by", mOrderBy);
+ bundle.putString("limit", mLimit);
+ if (mMangaId != null) {
+ bundle.putLong("manga_id", mMangaId);
+ }
+ if (mChapterId != null) {
+ bundle.putLong("chapter_id", mChapterId);
+ }
+ bundle.putBoolean("removed", mRemoved);
+ return bundle;
+ }
+
+ @NonNull
+ public static BookmarkSpecification from(Bundle bundle) {
+ final BookmarkSpecification spec = new BookmarkSpecification();
+ spec.mOrderBy = bundle.getString("order_by");
+ spec.mLimit = bundle.getString("limit");
+ if (bundle.containsKey("manga_id")) {
+ spec.mMangaId = bundle.getLong("manga_id", 0);
+ }
+ if (bundle.containsKey("chapter_id")) {
+ spec.mChapterId = bundle.getLong("chapter_id", 0);
+ }
+ spec.mRemoved = bundle.getBoolean("removed");
+ return spec;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/BookmarksRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/BookmarksRepository.java
new file mode 100644
index 00000000..423d7bf0
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/BookmarksRepository.java
@@ -0,0 +1,142 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaBookmark;
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 22.01.18.
+ */
+
+public final class BookmarksRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "bookmarks";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "manga_id", //1
+ "name", //2
+ "summary", //3
+ "genres", //4
+ "url", //5
+ "thumbnail", //6
+ "provider", //7
+ "status", //8
+ "rating", //9
+ "chapter_id", //10
+ "page_id", //11
+ "created_at", //12
+ "removed" //13
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static BookmarksRepository get(Context context) {
+ BookmarksRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new BookmarksRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private BookmarksRepository(Context context) {
+ super(context);
+ }
+
+
+ @Override
+ protected void toContentValues(@NonNull MangaBookmark bookmark, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], bookmark.id);
+ cv.put(PROJECTION[1], bookmark.manga.id);
+ cv.put(PROJECTION[2], bookmark.manga.name);
+ cv.put(PROJECTION[3], bookmark.manga.summary);
+ cv.put(PROJECTION[4], bookmark.manga.genres);
+ cv.put(PROJECTION[5], bookmark.manga.url);
+ cv.put(PROJECTION[6], bookmark.manga.thumbnail);
+ cv.put(PROJECTION[7], bookmark.manga.provider);
+ cv.put(PROJECTION[8], bookmark.manga.status);
+ cv.put(PROJECTION[9], bookmark.manga.rating);
+ cv.put(PROJECTION[10], bookmark.chapterId);
+ cv.put(PROJECTION[11], bookmark.pageId);
+ cv.put(PROJECTION[12], bookmark.createdAt);
+ cv.put(PROJECTION[13], 0);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull MangaBookmark bookmark) {
+ return bookmark.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected MangaBookmark fromCursor(@NonNull Cursor cursor) {
+ return new MangaBookmark(
+ cursor.getLong(0),
+ new MangaHeader(
+ cursor.getLong(1),
+ cursor.getString(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getString(5),
+ cursor.getString(6),
+ cursor.getString(7),
+ cursor.getInt(8),
+ cursor.getShort(9)
+ ),
+ cursor.getLong(10),
+ cursor.getLong(11),
+ cursor.getLong(12)
+ );
+ }
+
+ @Nullable
+ public MangaBookmark find(MangaHeader manga, MangaChapter chapter, MangaPage page) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ getTableName(),
+ getProjection(),
+ "manga_id = ? AND chapter_id = ? AND page_id = ?",
+ new String[]{String.valueOf(manga.id), String.valueOf(chapter.id), String.valueOf(page.id)},
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return fromCursor(cursor);
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesRepository.java
new file mode 100644
index 00000000..a68d389e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesRepository.java
@@ -0,0 +1,80 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.Category;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public final class CategoriesRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "categories";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "name", //1
+ "created_at" //2
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static CategoriesRepository get(Context context) {
+ CategoriesRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new CategoriesRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private CategoriesRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull Category category, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], category.id);
+ cv.put(PROJECTION[1], category.name);
+ cv.put(PROJECTION[2], category.createdAt);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull Category category) {
+ return category.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected Category fromCursor(@NonNull Cursor cursor) {
+ return new Category(
+ cursor.getInt(0),
+ cursor.getString(1),
+ cursor.getLong(2)
+ );
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesSpecification.java
new file mode 100644
index 00000000..19346d6d
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/CategoriesSpecification.java
@@ -0,0 +1,53 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public final class CategoriesSpecification implements SqlSpecification {
+
+ @Nullable
+ private String mOrderBy = null;
+
+ public CategoriesSpecification orderByDate(boolean descending) {
+ mOrderBy = "created_at";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public CategoriesSpecification orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public String getSelection() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String[] getSelectionArgs() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesRepository.java
new file mode 100644
index 00000000..41b71f6b
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesRepository.java
@@ -0,0 +1,185 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaFavourite;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaUpdateInfo;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public final class FavouritesRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "favourites";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "name", //1
+ "summary", //2
+ "genres", //3
+ "url", //4
+ "thumbnail", //5
+ "provider", //6
+ "status", //7
+ "rating", //8
+ "created_at", //9
+ "category_id", //10
+ "total_chapters", //11
+ "new_chapters", //12
+ "removed" //13
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static FavouritesRepository get(Context context) {
+ FavouritesRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new FavouritesRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private FavouritesRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull MangaFavourite mangaFavourite, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], mangaFavourite.id);
+ cv.put(PROJECTION[1], mangaFavourite.name);
+ cv.put(PROJECTION[2], mangaFavourite.summary);
+ cv.put(PROJECTION[3], mangaFavourite.genres);
+ cv.put(PROJECTION[4], mangaFavourite.url);
+ cv.put(PROJECTION[5], mangaFavourite.thumbnail);
+ cv.put(PROJECTION[6], mangaFavourite.provider);
+ cv.put(PROJECTION[7], mangaFavourite.status);
+ cv.put(PROJECTION[8], mangaFavourite.rating);
+ cv.put(PROJECTION[9], mangaFavourite.createdAt);
+ cv.put(PROJECTION[10], mangaFavourite.categoryId);
+ cv.put(PROJECTION[11], mangaFavourite.totalChapters);
+ cv.put(PROJECTION[12], mangaFavourite.newChapters);
+ //cv.put(PROJECTION[13], 0);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull MangaFavourite mangaFavourite) {
+ return mangaFavourite.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected MangaFavourite fromCursor(@NonNull Cursor cursor) {
+ return new MangaFavourite(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getString(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getString(5),
+ cursor.getString(6),
+ cursor.getInt(7),
+ cursor.getShort(8),
+ cursor.getLong(9),
+ cursor.getInt(10),
+ cursor.getInt(11),
+ cursor.getInt(12)
+ );
+ }
+
+ @Nullable
+ public MangaFavourite get(MangaHeader mangaHeader) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ TABLE_NAME,
+ PROJECTION,
+ "id = ?",
+ new String[]{String.valueOf(mangaHeader.id)},
+ null,
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return fromCursor(cursor);
+ } else {
+ return null;
+ }
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ public boolean remove(MangaHeader manga) {
+ return mStorageHelper.getWritableDatabase()
+ .delete(TABLE_NAME, "id=?", new String[]{String.valueOf(manga.id)}) > 0;
+ }
+
+ public boolean putUpdateInfo(MangaUpdateInfo updateInfo) {
+ try {
+ final ContentValues cv = new ContentValues(1);
+ cv.put("new_chapters", updateInfo.newChapters);
+ return mStorageHelper.getWritableDatabase().update(getTableName(), cv,
+ "id=?", new String[]{String.valueOf(updateInfo.mangaId)}) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public void setNoUpdates(MangaHeader manga) {
+ final SQLiteDatabase database = mStorageHelper.getWritableDatabase();
+ try {
+ database.beginTransaction();
+ database.rawQuery("UPDATE " + TABLE_NAME + " SET total_chapters = total_chapters + new_chapters WHERE id = ?", new String[]{String.valueOf(manga.id)});
+ database.rawQuery("UPDATE " + TABLE_NAME + " SET new_chapters = 0 WHERE id = ?", new String[]{String.valueOf(manga.id)});
+ database.setTransactionSuccessful();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ database.endTransaction();
+ }
+ }
+
+ public void clearNewChapters() {
+ final SQLiteDatabase database = mStorageHelper.getWritableDatabase();
+ try {
+ database.beginTransaction();
+ database.rawQuery("UPDATE " + TABLE_NAME + " SET total_chapters = total_chapters + new_chapters", null);
+ database.rawQuery("UPDATE " + TABLE_NAME + " SET new_chapters = 0", null);
+ database.setTransactionSuccessful();
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ database.endTransaction();
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesSpecification.java
new file mode 100644
index 00000000..b862710b
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/FavouritesSpecification.java
@@ -0,0 +1,131 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.UniqueObject;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public final class FavouritesSpecification implements SqlSpecification, UniqueObject {
+
+ @Nullable
+ private String mOrderBy = null;
+ @Nullable
+ private String mLimit = null;
+ @Nullable
+ private Integer mCategory = null;
+ private boolean mOnlyNew = false;
+ private boolean mRemoved = false;
+
+ public FavouritesSpecification removed(boolean value) {
+ mRemoved = value;
+ return this;
+ }
+
+ public FavouritesSpecification category(int category) {
+ mCategory = category;
+ return this;
+ }
+
+ public FavouritesSpecification onlyWithNewChapters() {
+ mOnlyNew = true;
+ return this;
+ }
+
+ public FavouritesSpecification orderByDate(boolean descending) {
+ mOrderBy = "created_at";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public FavouritesSpecification orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public FavouritesSpecification orderByNewChapters() {
+ mOrderBy = "new_chapters DESC";
+ return this;
+ }
+
+ public FavouritesSpecification limit(int limit) {
+ mLimit = String.valueOf(limit);
+ return this;
+ }
+
+ @Override
+ public String getSelection() {
+ final StringBuilder builder = new StringBuilder("removed = ?");
+ if (mCategory != null) {
+ builder.append(" AND category_id = ?");
+ }
+ if (mOnlyNew) {
+ builder.append(" AND new_chapters > 0");
+ }
+ return builder.toString();
+ }
+
+ @Override
+ public String[] getSelectionArgs() {
+ ArrayList args = new ArrayList<>(4);
+ args.add(mRemoved ? "1" : "0");
+ if (mCategory != null) {
+ args.add(String.valueOf(mCategory));
+ }
+ return args.toArray(new String[args.size()]);
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(5);
+ bundle.putString("order_by", mOrderBy);
+ bundle.putString("limit", mLimit);
+ if (mCategory != null) {
+ bundle.putInt("category", mCategory);
+ }
+ bundle.putBoolean("only_new", mOnlyNew);
+ bundle.putBoolean("removed", mRemoved);
+ return bundle;
+ }
+
+ @NonNull
+ public static FavouritesSpecification from(Bundle bundle) {
+ final FavouritesSpecification spec = new FavouritesSpecification();
+ spec.mOrderBy = bundle.getString("order_by");
+ spec.mLimit = bundle.getString("limit");
+ if (bundle.containsKey("category")) {
+ spec.mCategory = bundle.getInt("category", 0);
+ }
+ spec.mOnlyNew = bundle.getBoolean("only_new");
+ spec.mRemoved = bundle.getBoolean("removed");
+ return spec;
+ }
+
+ @Override
+ public long getId() {
+ return mCategory == null ? 0 : mCategory;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/HistoryRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/HistoryRepository.java
new file mode 100644
index 00000000..a61910ed
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/HistoryRepository.java
@@ -0,0 +1,182 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaChapter;
+import org.nv95.openmanga.core.models.MangaDetails;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.MangaHistory;
+import org.nv95.openmanga.core.models.MangaPage;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public class HistoryRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "history";
+ private static final String[] PROJECTION = new String[] {
+ "id", //0
+ "name", //1
+ "summary", //2
+ "genres", //3
+ "url", //4
+ "thumbnail", //5
+ "provider", //6
+ "status", //7
+ "rating", //8
+ "chapter_id", //9
+ "page_id", //10
+ "updated_at", //11
+ "reader_preset", //12
+ "total_chapters", //13
+ "removed" //14
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static HistoryRepository get(Context context) {
+ HistoryRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new HistoryRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private HistoryRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull MangaHistory mangaHistory, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], mangaHistory.id);
+ cv.put(PROJECTION[1], mangaHistory.name);
+ cv.put(PROJECTION[2], mangaHistory.summary);
+ cv.put(PROJECTION[3], mangaHistory.genres);
+ cv.put(PROJECTION[4], mangaHistory.url);
+ cv.put(PROJECTION[5], mangaHistory.thumbnail);
+ cv.put(PROJECTION[6], mangaHistory.provider);
+ cv.put(PROJECTION[7], mangaHistory.status);
+ cv.put(PROJECTION[8], mangaHistory.rating);
+ cv.put(PROJECTION[9], mangaHistory.chapterId);
+ cv.put(PROJECTION[10], mangaHistory.pageId);
+ cv.put(PROJECTION[11], mangaHistory.updatedAt);
+ cv.put(PROJECTION[12], mangaHistory.readerPreset);
+ cv.put(PROJECTION[13], mangaHistory.totalChapters);
+ //cv.put(PROJECTION[14], 0);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull MangaHistory history) {
+ return history.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected MangaHistory fromCursor(@NonNull Cursor cursor) {
+ return new MangaHistory(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getString(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getString(5),
+ cursor.getString(6),
+ cursor.getInt(7),
+ cursor.getShort(8),
+ cursor.getLong(9),
+ cursor.getLong(10),
+ cursor.getLong(11),
+ cursor.getShort(12),
+ cursor.getInt(13)
+ );
+ }
+
+ @Nullable
+ public MangaHistory find(MangaHeader mangaHeader) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ TABLE_NAME,
+ PROJECTION,
+ "id = ?",
+ new String[]{String.valueOf(mangaHeader.id)},
+ null,
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return fromCursor(cursor);
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ public boolean quickUpdate(MangaHeader manga, MangaChapter chapter, MangaPage page) {
+ try {
+ final ContentValues cv = new ContentValues();
+ cv.put(PROJECTION[9], chapter.id);
+ cv.put(PROJECTION[10], page.id);
+ cv.put(PROJECTION[11], System.currentTimeMillis());
+ return mStorageHelper.getWritableDatabase()
+ .update(TABLE_NAME, cv,
+ "id=?", new String[]{String.valueOf(manga.id)}) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public short getPreset(MangaDetails manga, short defaultValue) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ TABLE_NAME,
+ new String[]{PROJECTION[12]},
+ "id = ?",
+ new String[]{String.valueOf(manga.id)},
+ null,
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return cursor.getShort(0);
+ }
+ return defaultValue;
+ } catch (Exception e) {
+ return defaultValue;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/HistorySpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/HistorySpecification.java
new file mode 100644
index 00000000..8834f94e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/HistorySpecification.java
@@ -0,0 +1,86 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public class HistorySpecification implements SqlSpecification {
+
+ @Nullable
+ private String mOrderBy = null;
+ @Nullable
+ private String mLimit = null;
+
+ private boolean mRemoved = false;
+
+ public HistorySpecification removed(boolean value) {
+ mRemoved = value;
+ return this;
+ }
+
+ public HistorySpecification orderByDate(boolean descending) {
+ mOrderBy = "updated_at";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public HistorySpecification orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public HistorySpecification limit(int limit) {
+ mLimit = String.valueOf(limit);
+ return this;
+ }
+
+ @Override
+ public String getSelection() {
+ return "removed = ?";
+ }
+
+ @Override
+ public String[] getSelectionArgs() {
+ return new String[]{
+ mRemoved ? "1" : "0"
+ };
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(3);
+ bundle.putString("limit", mLimit);
+ bundle.putString("order_by", mOrderBy);
+ bundle.putBoolean("removed", mRemoved);
+ return bundle;
+ }
+
+ public static HistorySpecification from(Bundle bundle) {
+ final HistorySpecification specification = new HistorySpecification();
+ specification.mLimit = bundle.getString("limit", null);
+ specification.mOrderBy = bundle.getString("order_by", null);
+ specification.mRemoved = bundle.getBoolean("removed", false);
+ return specification;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsRepository.java
new file mode 100644
index 00000000..5a1d4121
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsRepository.java
@@ -0,0 +1,125 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaRecommendation;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 29.01.18.
+ */
+
+public final class RecommendationsRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "recommendations";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "name", //1
+ "summary", //2
+ "genres", //3
+ "url", //4
+ "thumbnail", //5
+ "provider", //6
+ "status", //7
+ "rating", //8
+ "category" //9
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static RecommendationsRepository get(Context context) {
+ RecommendationsRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new RecommendationsRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private RecommendationsRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull MangaRecommendation mangaRecommendation, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], mangaRecommendation.id);
+ cv.put(PROJECTION[1], mangaRecommendation.name);
+ cv.put(PROJECTION[2], mangaRecommendation.summary);
+ cv.put(PROJECTION[3], mangaRecommendation.genres);
+ cv.put(PROJECTION[4], mangaRecommendation.url);
+ cv.put(PROJECTION[5], mangaRecommendation.thumbnail);
+ cv.put(PROJECTION[6], mangaRecommendation.provider);
+ cv.put(PROJECTION[7], mangaRecommendation.status);
+ cv.put(PROJECTION[8], mangaRecommendation.rating);
+ cv.put(PROJECTION[9], mangaRecommendation.category);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull MangaRecommendation mangaRecommendation) {
+ return mangaRecommendation.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected MangaRecommendation fromCursor(@NonNull Cursor cursor) {
+ return new MangaRecommendation(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getString(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getString(5),
+ cursor.getString(6),
+ cursor.getInt(7),
+ cursor.getShort(8),
+ cursor.getInt(9)
+ );
+ }
+
+
+ @NonNull
+ public ArrayList getCategories() {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().rawQuery("SELECT category FROM " + getTableName() + " GROUP BY category", null);
+ final ArrayList list = new ArrayList<>(cursor.getCount());
+ if (cursor.moveToFirst()) {
+ do {
+ list.add(cursor.getInt(0));
+ } while (cursor.moveToNext());
+ }
+ return list;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new ArrayList<>(0);
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsSpecifications.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsSpecifications.java
new file mode 100644
index 00000000..b5bcb6fb
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/RecommendationsSpecifications.java
@@ -0,0 +1,90 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.UniqueObject;
+
+/**
+ * Created by koitharu on 29.01.18.
+ */
+
+public final class RecommendationsSpecifications implements SqlSpecification, UniqueObject {
+
+ @Nullable
+ private String mOrderBy = null;
+ @Nullable
+ private String mLimit = null;
+ @Nullable
+ private Integer mCategory = null;
+
+ public RecommendationsSpecifications orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public RecommendationsSpecifications orderByRand() {
+ mOrderBy = "RANDOM()";
+ return this;
+ }
+
+ public RecommendationsSpecifications category(@Nullable Integer category) {
+ mCategory = category;
+ return this;
+ }
+
+ @Override
+ public long getId() {
+ return mCategory == null ? 0 : mCategory;
+ }
+
+ @Nullable
+ @Override
+ public String getSelection() {
+ return mCategory == null ? null : "category = ?";
+ }
+
+ @Nullable
+ @Override
+ public String[] getSelectionArgs() {
+ return mCategory == null ? null : new String[]{String.valueOf(mCategory)};
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(5);
+ bundle.putString("order_by", mOrderBy);
+ bundle.putString("limit", mLimit);
+ if (mCategory != null) {
+ bundle.putInt("category", mCategory);
+ }
+ return bundle;
+ }
+
+ @NonNull
+ public static RecommendationsSpecifications from(Bundle bundle) {
+ final RecommendationsSpecifications spec = new RecommendationsSpecifications();
+ spec.mOrderBy = bundle.getString("order_by");
+ spec.mLimit = bundle.getString("limit");
+ if (bundle.containsKey("category")) {
+ spec.mCategory = bundle.getInt("category", 0);
+ }
+ return spec;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/Repository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/Repository.java
new file mode 100644
index 00000000..549faa30
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/Repository.java
@@ -0,0 +1,22 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public interface Repository {
+
+ boolean add(@NonNull T t);
+ boolean remove(@NonNull T t);
+ boolean update(@NonNull T t);
+ void clear();
+ boolean contains(@NonNull T t);
+
+ @Nullable
+ List query(@NonNull SqlSpecification specification);
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SQLiteRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SQLiteRepository.java
new file mode 100644
index 00000000..a2fd60fd
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SQLiteRepository.java
@@ -0,0 +1,179 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+abstract class SQLiteRepository implements Repository {
+
+ protected final StorageHelper mStorageHelper;
+
+ protected SQLiteRepository(Context context) {
+ mStorageHelper = new StorageHelper(context);
+ }
+
+ @Override
+ public boolean add(@NonNull T t) {
+ try {
+ final ContentValues cv = new ContentValues(getProjection().length);
+ toContentValues(t, cv);
+ return mStorageHelper.getWritableDatabase()
+ .insert(getTableName(), null, cv) >= 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean remove(@NonNull T t) {
+ return mStorageHelper.getWritableDatabase()
+ .delete(getTableName(), "id=?", new String[]{String.valueOf(getId(t))}) >= 0;
+ }
+
+ @Override
+ public boolean update(@NonNull T t) {
+ try {
+ final ContentValues cv = new ContentValues(getProjection().length);
+ toContentValues(t, cv);
+ return mStorageHelper.getWritableDatabase().update(getTableName(), cv,
+ "id=?", new String[]{String.valueOf(getId(t))}) > 0;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ public boolean addOrUpdate(@NonNull T t) {
+ final ContentValues cv = new ContentValues(getProjection().length);
+ toContentValues(t, cv);
+ final SQLiteDatabase database = mStorageHelper.getWritableDatabase();
+ try {
+ if(database.insert(getTableName(), null, cv) >= 0) {
+ return true;
+ }
+ } catch (Exception ignored) {
+ }
+ try {
+ if(database.update(getTableName(), cv,"id=?", new String[]{String.valueOf(getId(t))}) > 0) {
+ return true;
+ }
+ } catch (Exception ignored) {
+ }
+ return false;
+ }
+
+ public boolean updateOrAdd(@NonNull T t) {
+ final ContentValues cv = new ContentValues(getProjection().length);
+ toContentValues(t, cv);
+ final SQLiteDatabase database = mStorageHelper.getWritableDatabase();
+ try {
+ if(database.update(getTableName(), cv,"id=?", new String[]{String.valueOf(getId(t))}) > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ }
+ try {
+ if(database.insert(getTableName(), null, cv) >= 0) {
+ return true;
+ }
+ } catch (Exception ignored) {
+ }
+ return false;
+ }
+
+ @Override
+ public void clear() {
+ mStorageHelper.getWritableDatabase().delete(getTableName(), null, null);
+ }
+
+ @Override
+ public boolean contains(@NonNull T t) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().rawQuery("SELECT * FROM " + getTableName() + " WHERE id = ?", new String[]{String.valueOf(getId(t))});
+ return cursor.getCount() > 0;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ @Nullable
+ @Override
+ public ArrayList query(@NonNull SqlSpecification specification) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ getTableName(),
+ getProjection(),
+ specification.getSelection(),
+ specification.getSelectionArgs(),
+ null,
+ null,
+ specification.getOrderBy(),
+ specification.getLimit()
+ );
+ ArrayList list = new ArrayList<>();
+ if (cursor.moveToFirst()) {
+ do {
+ list.add(fromCursor(cursor));
+ } while (cursor.moveToNext());
+ }
+ return list;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ @Nullable
+ protected T findById(@NonNull Object id) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ getTableName(),
+ getProjection(),
+ "id = ?",
+ new String[]{String.valueOf(id)},
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return fromCursor(cursor);
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
+ protected abstract void toContentValues(@NonNull T t, @NonNull ContentValues cv);
+
+ @NonNull
+ protected abstract String getTableName();
+
+ @NonNull
+ protected abstract Object getId(@NonNull T t);
+
+ @NonNull
+ protected abstract String[] getProjection();
+
+ @NonNull
+ protected abstract T fromCursor(@NonNull Cursor cursor);
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersRepository.java
new file mode 100644
index 00000000..84756023
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersRepository.java
@@ -0,0 +1,131 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.SavedChapter;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+public final class SavedChaptersRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "saved_chapters";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "name", //1
+ "number", //2
+ "url", //3
+ "provider", //4
+ "manga_id" //5
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static synchronized SavedChaptersRepository get(Context context) {
+ SavedChaptersRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new SavedChaptersRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private SavedChaptersRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull SavedChapter chapter, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], chapter.id);
+ cv.put(PROJECTION[1], chapter.name);
+ cv.put(PROJECTION[2], chapter.number);
+ cv.put(PROJECTION[3], chapter.url);
+ cv.put(PROJECTION[4], chapter.provider);
+ cv.put(PROJECTION[5], chapter.mangaId);
+ }
+
+ @NonNull
+ @Override
+ protected SavedChapter fromCursor(@NonNull Cursor cursor) {
+ return new SavedChapter(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getInt(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getLong(5)
+ );
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull SavedChapter chapter) {
+ return chapter.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ public int count(MangaHeader manga) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase()
+ .rawQuery("SELECT COUNT(*) FROM " + TABLE_NAME + " WHERE manga_id = ?",
+ new String[]{String.valueOf(manga.id)});
+ return cursor.moveToFirst() ? cursor.getInt(0) : -1;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return -1;
+ } finally {
+ if (cursor != null) {
+ cursor.close();
+ }
+ }
+ }
+
+ @Nullable
+ public SavedChapter findChapterByUrl(String chapterUrl) {
+ Cursor cursor = null;
+ try {
+ cursor = mStorageHelper.getReadableDatabase().query(
+ getTableName(),
+ getProjection(),
+ "url = ?",
+ new String[]{String.valueOf(chapterUrl)},
+ null,
+ null,
+ null
+ );
+ if (cursor.moveToFirst()) {
+ return fromCursor(cursor);
+ }
+ return null;
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersSpecification.java
new file mode 100644
index 00000000..2875fef5
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedChaptersSpecification.java
@@ -0,0 +1,92 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaHeader;
+
+/**
+ * Created by koitharu on 26.01.18.
+ */
+
+public final class SavedChaptersSpecification implements SqlSpecification {
+
+ @Nullable
+ private String mOrderBy = null;
+ @Nullable
+ private String mLimit = null;
+ @Nullable
+ private Long mMangaId = null;
+
+ public SavedChaptersSpecification orderByDate(boolean descending) {
+ mOrderBy = "created_at";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public SavedChaptersSpecification orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public SavedChaptersSpecification limit(int limit) {
+ mLimit = String.valueOf(limit);
+ return this;
+ }
+
+ public SavedChaptersSpecification manga(@Nullable MangaHeader manga) {
+ mMangaId = manga == null ? null : manga.id;
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public String getSelection() {
+ return mMangaId == null ? null : "manga_id = ?";
+ }
+
+ @Nullable
+ @Override
+ public String[] getSelectionArgs() {
+ return mMangaId == null ? null : new String[]{String.valueOf(mMangaId)};
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(3);
+ bundle.putString("limit", mLimit);
+ if (mMangaId != null) {
+ bundle.putLong("manga_id", mMangaId);
+ }
+ bundle.putString("order_by", mOrderBy);
+ return bundle;
+ }
+
+ public static SavedChaptersSpecification from(Bundle bundle) {
+ final SavedChaptersSpecification specification = new SavedChaptersSpecification();
+ specification.mLimit = bundle.getString("limit", null);
+ if (bundle.containsKey("manga_id")) {
+ specification.mMangaId = bundle.getLong("manga_id");
+ }
+ specification.mOrderBy = bundle.getString("order_by", null);
+ return specification;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaRepository.java
new file mode 100644
index 00000000..9e93b3a4
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaRepository.java
@@ -0,0 +1,121 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.SavedManga;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+public final class SavedMangaRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "saved";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "name", //1
+ "summary", //2
+ "genres", //3
+ "url", //4
+ "thumbnail", //5
+ "provider", //6
+ "status", //7
+ "rating", //8
+ "created_at", //9
+ "local_path", //10
+ "description", //11
+ "author" //12
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ private SavedMangaRepository(Context context) {
+ super(context);
+ }
+
+ @NonNull
+ public static synchronized SavedMangaRepository get(Context context) {
+ SavedMangaRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new SavedMangaRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ @Override
+ protected void toContentValues(@NonNull SavedManga manga, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], manga.id);
+ cv.put(PROJECTION[1], manga.name);
+ cv.put(PROJECTION[2], manga.summary);
+ cv.put(PROJECTION[3], manga.genres);
+ cv.put(PROJECTION[4], manga.url);
+ cv.put(PROJECTION[5], manga.thumbnail);
+ cv.put(PROJECTION[6], manga.provider);
+ cv.put(PROJECTION[7], manga.status);
+ cv.put(PROJECTION[8], manga.rating);
+ cv.put(PROJECTION[9], manga.createdAt);
+ cv.put(PROJECTION[10], manga.localPath);
+ cv.put(PROJECTION[11], manga.description);
+ cv.put(PROJECTION[12], manga.author);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull SavedManga manga) {
+ return manga.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected SavedManga fromCursor(@NonNull Cursor cursor) {
+ return new SavedManga(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getString(2),
+ cursor.getString(3),
+ cursor.getString(4),
+ cursor.getString(5),
+ cursor.getString(6),
+ cursor.getInt(7),
+ cursor.getShort(8),
+ cursor.getLong(9),
+ cursor.getString(10),
+ cursor.getString(11),
+ cursor.getString(12)
+ );
+ }
+
+ @Nullable
+ public SavedManga find(MangaHeader manga) {
+ return findById(manga.id);
+ }
+
+ @Nullable
+ public SavedManga get(long id) {
+ return findById(id);
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaSpecification.java
new file mode 100644
index 00000000..aefc7bec
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedMangaSpecification.java
@@ -0,0 +1,77 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 26.01.18.
+ */
+
+public final class SavedMangaSpecification implements SqlSpecification {
+
+ @Nullable
+ private String mOrderBy = null;
+ @Nullable
+ private String mLimit = null;
+
+ public SavedMangaSpecification orderByDate(boolean descending) {
+ mOrderBy = "created_at";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public SavedMangaSpecification orderByName(boolean descending) {
+ mOrderBy = "name";
+ if (descending) {
+ mOrderBy += " DESC";
+ }
+ return this;
+ }
+
+ public SavedMangaSpecification limit(int limit) {
+ mLimit = String.valueOf(limit);
+ return this;
+ }
+
+ @Nullable
+ @Override
+ public String getSelection() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String[] getSelectionArgs() {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getOrderBy() {
+ return mOrderBy;
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return mLimit;
+ }
+
+ @NonNull
+ public Bundle toBundle() {
+ final Bundle bundle = new Bundle(2);
+ bundle.putString("limit", mLimit);
+ bundle.putString("order_by", mOrderBy);
+ return bundle;
+ }
+
+ public static SavedMangaSpecification from(Bundle bundle) {
+ final SavedMangaSpecification specification = new SavedMangaSpecification();
+ specification.mLimit = bundle.getString("limit", null);
+ specification.mOrderBy = bundle.getString("order_by", null);
+ return specification;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesRepository.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesRepository.java
new file mode 100644
index 00000000..3d43c352
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesRepository.java
@@ -0,0 +1,88 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.SavedPage;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 23.01.18.
+ */
+
+public final class SavedPagesRepository extends SQLiteRepository {
+
+ private static final String TABLE_NAME = "saved_pages";
+ private static final String[] PROJECTION = new String[]{
+ "id", //0
+ "url", //1
+ "provider", //2
+ "chapter_id", //3
+ "number" //4
+ };
+
+ @Nullable
+ private static WeakReference sInstanceRef = null;
+
+ @NonNull
+ public static synchronized SavedPagesRepository get(Context context) {
+ SavedPagesRepository instance = null;
+ if (sInstanceRef != null) {
+ instance = sInstanceRef.get();
+ }
+ if (instance == null) {
+ instance = new SavedPagesRepository(context);
+ sInstanceRef = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ private SavedPagesRepository(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void toContentValues(@NonNull SavedPage page, @NonNull ContentValues cv) {
+ cv.put(PROJECTION[0], page.id);
+ cv.put(PROJECTION[1], page.url);
+ cv.put(PROJECTION[2], page.provider);
+ cv.put(PROJECTION[3], page.chapterId);
+ cv.put(PROJECTION[4], page.number);
+ }
+
+ @NonNull
+ @Override
+ protected String getTableName() {
+ return TABLE_NAME;
+ }
+
+ @NonNull
+ @Override
+ protected Object getId(@NonNull SavedPage page) {
+ return page.id;
+ }
+
+ @NonNull
+ @Override
+ protected String[] getProjection() {
+ return PROJECTION;
+ }
+
+ @NonNull
+ @Override
+ protected SavedPage fromCursor(@NonNull Cursor cursor) {
+ return new SavedPage(
+ cursor.getLong(0),
+ cursor.getString(1),
+ cursor.getString(2),
+ cursor.getLong(3),
+ cursor.getInt(4)
+ );
+ }
+
+
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesSpecification.java
new file mode 100644
index 00000000..7d2e18a6
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SavedPagesSpecification.java
@@ -0,0 +1,44 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.core.models.MangaChapter;
+
+/**
+ * Created by koitharu on 31.01.18.
+ */
+
+public final class SavedPagesSpecification implements SqlSpecification {
+
+ @Nullable
+ private final Long mChapterId;
+
+ public SavedPagesSpecification(@Nullable MangaChapter chapter) {
+ mChapterId = chapter == null ? null : chapter.id;
+ }
+
+ @Nullable
+ @Override
+ public String getSelection() {
+ return mChapterId == null ? null : "chapter_id = ?";
+ }
+
+ @Nullable
+ @Override
+ public String[] getSelectionArgs() {
+ return mChapterId == null ? null : new String[]{String.valueOf(mChapterId)};
+ }
+
+ @NonNull
+ @Override
+ public String getOrderBy() {
+ return "number";
+ }
+
+ @Nullable
+ @Override
+ public String getLimit() {
+ return null;
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/SqlSpecification.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/SqlSpecification.java
new file mode 100644
index 00000000..fc0b68fd
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/SqlSpecification.java
@@ -0,0 +1,19 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.support.annotation.Nullable;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+interface SqlSpecification {
+
+ @Nullable
+ String getSelection();
+ @Nullable
+ String[] getSelectionArgs();
+ @Nullable
+ String getOrderBy();
+ @Nullable
+ String getLimit();
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/db/StorageHelper.java b/app/src/main/java/org/nv95/openmanga/core/storage/db/StorageHelper.java
new file mode 100644
index 00000000..e694ae7e
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/db/StorageHelper.java
@@ -0,0 +1,54 @@
+package org.nv95.openmanga.core.storage.db;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+import org.nv95.openmanga.R;
+import org.nv95.openmanga.common.utils.ResourceUtils;
+import org.nv95.openmanga.common.utils.TextUtils;
+
+/**
+ * Created by koitharu on 24.12.17.
+ */
+
+public class StorageHelper extends SQLiteOpenHelper {
+
+ private static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "storage";
+
+ private final Resources mResources;
+
+ public StorageHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ mResources = context.getResources();
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase sqLiteDatabase) {
+ String[] parts = ResourceUtils.getRawString(mResources, R.raw.storage).split(";");
+ sqLiteDatabase.beginTransaction();
+ try {
+ for (String query : parts) {
+ sqLiteDatabase.execSQL(TextUtils.inline(query));
+ }
+ sqLiteDatabase.setTransactionSuccessful();
+ /*} catch (Exception e) { //TODO handle it
+ e.printStackTrace();*/
+ } finally {
+ sqLiteDatabase.endTransaction();
+ }
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
+
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ close();
+ super.finalize();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/files/FilesStorage.java b/app/src/main/java/org/nv95/openmanga/core/storage/files/FilesStorage.java
new file mode 100644
index 00000000..bbcb7f64
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/files/FilesStorage.java
@@ -0,0 +1,30 @@
+package org.nv95.openmanga.core.storage.files;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+
+import java.io.File;
+
+/**
+ * Created by koitharu on 22.01.18.
+ */
+
+public interface FilesStorage {
+
+ @NonNull
+ File getFile(@NonNull K key);
+
+ @Nullable
+ V get(@NonNull K key);
+
+ void put(@NonNull K key, @Nullable V v);
+
+ boolean remove(@NonNull K key);
+
+ @WorkerThread
+ void clear();
+
+ @WorkerThread
+ long size();
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/files/SavedPagesStorage.java b/app/src/main/java/org/nv95/openmanga/core/storage/files/SavedPagesStorage.java
new file mode 100644
index 00000000..7ee1a31a
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/files/SavedPagesStorage.java
@@ -0,0 +1,79 @@
+package org.nv95.openmanga.core.storage.files;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.common.utils.FilesystemUtils;
+import org.nv95.openmanga.core.models.MangaHeader;
+import org.nv95.openmanga.core.models.SavedManga;
+import org.nv95.openmanga.core.models.SavedPage;
+import org.nv95.openmanga.core.storage.db.SavedMangaRepository;
+
+import java.io.File;
+
+/**
+ * Created by koitharu on 25.01.18.
+ */
+
+public final class SavedPagesStorage implements FilesStorage {
+
+ private final File mRootDirectory;
+
+ public SavedPagesStorage(@NonNull SavedManga manga) {
+ mRootDirectory = new File(manga.localPath);
+ //noinspection ResultOfMethodCallIgnored
+ mRootDirectory.mkdirs();
+ }
+
+ @NonNull
+ @Override
+ public File getFile(@NonNull SavedPage key) {
+ return new File(mRootDirectory, encodeName(key));
+ }
+
+ @Nullable
+ @Override
+ public File get(@NonNull SavedPage key) {
+ final File file = getFile(key);
+ return file.exists() ? file : null;
+ }
+
+ @Override
+ public void put(@NonNull SavedPage key, @Nullable File file) {
+ final File f = getFile(key);
+ if (f.exists()) {
+ f.delete();
+ }
+ if (file != null) {
+ //TODO not implemented
+ }
+ }
+
+ @Override
+ public boolean remove(@NonNull SavedPage key) {
+ File file = getFile(key);
+ return file.exists() && file.delete();
+ }
+
+ @Override
+ public void clear() {
+ FilesystemUtils.clearDir(mRootDirectory);
+ }
+
+ @Override
+ public long size() {
+ return FilesystemUtils.getFileSize(mRootDirectory);
+ }
+
+ @NonNull
+ private static String encodeName(SavedPage page) {
+ return page.chapterId + "_" + page.id;
+ }
+
+ @Nullable
+ public static SavedPagesStorage get(@NonNull Context context, @NonNull MangaHeader manga) {
+ final SavedManga savedManga = SavedMangaRepository.get(context).find(manga);
+ return savedManga == null ? null : new SavedPagesStorage(savedManga);
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/files/ThumbnailsStorage.java b/app/src/main/java/org/nv95/openmanga/core/storage/files/ThumbnailsStorage.java
new file mode 100644
index 00000000..5f7ea035
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/files/ThumbnailsStorage.java
@@ -0,0 +1,90 @@
+package org.nv95.openmanga.core.storage.files;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.nv95.openmanga.common.utils.FilesystemUtils;
+import org.nv95.openmanga.core.models.MangaBookmark;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * Created by koitharu on 22.01.18.
+ */
+
+public final class ThumbnailsStorage implements FilesStorage {
+
+ private final File mRootDirectory;
+
+ public ThumbnailsStorage(Context context) {
+ mRootDirectory = new File(context.getExternalFilesDir("thumb"), "bookmarks");
+ mRootDirectory.mkdirs();
+ }
+
+ @NonNull
+ @Override
+ public File getFile(@NonNull MangaBookmark key) {
+ return new File(mRootDirectory, encodeName(key));
+ }
+
+ @Nullable
+ @Override
+ public Bitmap get(@NonNull MangaBookmark key) {
+ final File f = getFile(key);
+ if (!f.exists()) {
+ return null;
+ }
+ return BitmapFactory.decodeFile(f.getPath());
+ }
+
+ @Override
+ public void put(@NonNull MangaBookmark key, @Nullable Bitmap bitmap) {
+ final File f = getFile(key);
+ if (f.exists()) {
+ f.delete();
+ }
+ if (bitmap != null) {
+ FileOutputStream output = null;
+ try {
+ output = new FileOutputStream(f);
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, output);
+ output.flush();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (output != null) {
+ output.close();
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean remove(@NonNull MangaBookmark key) {
+ File file = getFile(key);
+ return file.exists() && file.delete();
+ }
+
+ @Override
+ public void clear() {
+ FilesystemUtils.clearDir(mRootDirectory);
+ }
+
+ @Override
+ public long size() {
+ return FilesystemUtils.getFileSize(mRootDirectory);
+ }
+
+ @NonNull
+ private static String encodeName(MangaBookmark bookmark) {
+ return String.valueOf(bookmark.id);
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/settings/AppSettings.java b/app/src/main/java/org/nv95/openmanga/core/storage/settings/AppSettings.java
new file mode 100644
index 00000000..10615e45
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/settings/AppSettings.java
@@ -0,0 +1,72 @@
+package org.nv95.openmanga.core.storage.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 26.12.17.
+ */
+
+public class AppSettings {
+
+ @Nullable
+ private static WeakReference sInstanceReference = null;
+
+ private final SharedPreferences mPreferences;
+ public final ReaderSettings readerSettings;
+ public final ShelfSettings shelfSettings;
+
+ private AppSettings(Context context) {
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ readerSettings = new ReaderSettings(mPreferences);
+ shelfSettings = new ShelfSettings(mPreferences);
+ }
+
+ public static AppSettings get(Context context) {
+ AppSettings instance = sInstanceReference == null ? null : sInstanceReference.get();
+ if (instance == null) {
+ instance = new AppSettings(context);
+ sInstanceReference = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ public static NetworkSettings getNetworkSettings(Context context) {
+ NetworkSettings instance = NetworkSettings.sInstanceReference == null ? null : NetworkSettings.sInstanceReference.get();
+ if (instance == null) {
+ instance = new NetworkSettings(context);
+ NetworkSettings.sInstanceReference = new WeakReference<>(instance);
+ }
+ return instance;
+ }
+
+ public boolean isUseTor() {
+ return mPreferences.getBoolean("use_tor", false);
+ }
+
+ public String getAppLocale() {
+ return mPreferences.getString("lang", "");
+ }
+
+ public int getCacheMaxSizeMb() {
+ int value = mPreferences.getInt("cache_max", 100);
+ if (value < 20) {
+ value = 20; //20M
+ } else if (value > 1024) {
+ value = 1024; //1G
+ }
+ return value;
+ }
+
+ public int getAppTheme() {
+ try {
+ return Integer.parseInt(mPreferences.getString("theme", "0"));
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/settings/NetworkSettings.java b/app/src/main/java/org/nv95/openmanga/core/storage/settings/NetworkSettings.java
new file mode 100644
index 00000000..dcad135f
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/settings/NetworkSettings.java
@@ -0,0 +1,43 @@
+package org.nv95.openmanga.core.storage.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.net.ConnectivityManager;
+import android.os.Build;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * Created by koitharu on 17.01.18.
+ */
+
+final class NetworkSettings {
+
+ @Nullable
+ static WeakReference sInstanceReference = null;
+
+ private final SharedPreferences mPreferences;
+ private final ConnectivityManager mConnectivityManager;
+
+ NetworkSettings(Context context) {
+ mPreferences = PreferenceManager.getDefaultSharedPreferences(context);
+ mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+
+ public boolean isNetworkSaveMode() {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
+ && mConnectivityManager.isActiveNetworkMetered()
+ && mConnectivityManager.getRestrictBackgroundStatus()
+ == ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
+ }
+
+ private boolean isUseSystem() {
+ return mPreferences.getBoolean("network.usage.system", true);
+ }
+
+ public boolean isThumbnailsWifiOnly() {
+ return "1".equals(mPreferences.getString("network.usage.show_thumbnails", "0"));
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/settings/ReaderSettings.java b/app/src/main/java/org/nv95/openmanga/core/storage/settings/ReaderSettings.java
new file mode 100644
index 00000000..0dcaa502
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/settings/ReaderSettings.java
@@ -0,0 +1,55 @@
+package org.nv95.openmanga.core.storage.settings;
+
+import android.content.SharedPreferences;
+import android.graphics.Color;
+import android.support.annotation.ColorInt;
+
+/**
+ * Created by koitharu on 06.02.18.
+ */
+
+public final class ReaderSettings {
+
+ private final SharedPreferences mPreferences;
+
+ ReaderSettings(SharedPreferences preferences) {
+ mPreferences = preferences;
+ }
+
+ public short getDefaultPreset() {
+ try {
+ return Short.parseShort(mPreferences.getString("reader.default_preset", "0"));
+ } catch (Exception e) {
+ return 0;
+ }
+ }
+
+ public boolean isVolumeKeysEnabled() {
+ return mPreferences.getBoolean("reader.volume_keys", true);
+ }
+
+ public boolean isWakelockEnabled() {
+ return mPreferences.getBoolean("reader.wakelock", true);
+ }
+
+ public boolean isBrightnessAdjustEnabled() {
+ return mPreferences.getBoolean("reader.brightness_adjust", false);
+ }
+
+ public int getBrightnessValue() {
+ return mPreferences.getInt("reader.brightness_value", 20);
+ }
+
+ public boolean isStatusBarEnbaled() {
+ return mPreferences.getBoolean("reader.statusbar", true);
+ }
+
+ public boolean isCustomBackground() {
+ return mPreferences.getBoolean("reader.background_apply", false);
+ }
+
+ @ColorInt
+ public int getBackgroundColor() {
+ return mPreferences.getInt("reader.background", Color.BLACK);
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/core/storage/settings/ShelfSettings.java b/app/src/main/java/org/nv95/openmanga/core/storage/settings/ShelfSettings.java
new file mode 100644
index 00000000..6d0c7ef8
--- /dev/null
+++ b/app/src/main/java/org/nv95/openmanga/core/storage/settings/ShelfSettings.java
@@ -0,0 +1,64 @@
+package org.nv95.openmanga.core.storage.settings;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.nv95.openmanga.core.models.Category;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+
+public class ShelfSettings {
+
+ private final SharedPreferences mPreferences;
+
+ ShelfSettings(SharedPreferences preferences) {
+ mPreferences = preferences;
+ }
+
+ public boolean isRecentEnabled() {
+ return mPreferences.getBoolean("shelf.recent_enabled", true);
+ }
+
+ public boolean isHistoryEnabled() {
+ return mPreferences.getBoolean("shelf.history_enabled", true);
+ }
+
+ public int getMaxHistoryRows() {
+ return mPreferences.getInt("shelf.history_rows", 1);
+ }
+
+ public boolean isFavouritesEnabled() {
+ return mPreferences.getBoolean("shelf.favourites_enabled", true);
+ }
+
+ public ArrayList getEnabledCategories(ArrayList allCategories){
+ if (allCategories == null) {
+ return new ArrayList<>(0);
+ }
+ final Set enabledCats = mPreferences.getStringSet("shelf.favourites_categories", null);
+ if (enabledCats == null) {
+ return allCategories;
+ }
+ final ArrayList result = new ArrayList<>(enabledCats.size());
+ for (Category o : allCategories) {
+ if (enabledCats.contains(String.valueOf(o.id))) {
+ result.add(o);
+ }
+ }
+ return result;
+ }
+
+ public int getMaxFavouritesRows() {
+ return mPreferences.getInt("shelf.favourites_cat_rows", 1);
+ }
+
+ public static void onCategoryAdded(Context context, Category category) {
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
+ final Set enabledCats = preferences.getStringSet("shelf.favourites_categories", new HashSet<>(1));
+ enabledCats.add(String.valueOf(category.id));
+ preferences.edit().putStringSet("shelf.favourites_categories", enabledCats).apply();
+ }
+}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/BookmarksDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/BookmarksDialog.java
deleted file mode 100644
index 5f07d5f8..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/BookmarksDialog.java
+++ /dev/null
@@ -1,250 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Canvas;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.AsyncTask;
-import android.support.design.widget.Snackbar;
-import android.support.v4.content.ContextCompat;
-import android.support.v4.util.Pair;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
-import android.support.v7.widget.helper.ItemTouchHelper;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.ReadActivity2;
-import org.nv95.openmanga.adapters.BookmarksAdapter;
-import org.nv95.openmanga.items.Bookmark;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.providers.BookmarksProvider;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 20.11.16.
- */
-
-public class BookmarksDialog implements BookmarksAdapter.OnBookmarkClickListener, View.OnClickListener {
-
- private final Activity mActivity;
- private final AlertDialog mDialog;
- private final View mContentView;
- private final TextView mHolder;
- private final RecyclerView mRecyclerView;
- private final Toolbar mToolbar;
-
- private ArrayList mBookmarks;
-
- public BookmarksDialog(Activity context) {
- mActivity = context;
- mContentView = LayoutInflater.from(context)
- .inflate(R.layout.dialog_bookmarks, null, false);
- mRecyclerView = mContentView.findViewById(R.id.recyclerView);
- mToolbar = mContentView.findViewById(R.id.toolbar);
- mHolder = mContentView.findViewById(R.id.textView_holder);
- mToolbar.setNavigationIcon(R.drawable.ic_cancel_light);
- mToolbar.setNavigationOnClickListener(this);
- mToolbar.setTitle(R.string.bookmarks);
- mRecyclerView.setLayoutManager(new LinearLayoutManager(context));
-
- mDialog = new AlertDialog.Builder(context)
- .setView(mContentView)
- .create();
- mDialog.setOwnerActivity(mActivity);
-
- ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) {
-
- private Drawable background;
- private Drawable xMark;
- boolean initialized = false;
-
- private void init() {
- background = new ColorDrawable(ContextCompat.getColor(mActivity, R.color.red_overlay));
- xMark = ContextCompat.getDrawable(mActivity, R.drawable.ic_delete_light);
- initialized = true;
- }
-
- @Override
- public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
- return false;
- }
-
- @Override
- public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
- int pos = viewHolder.getAdapterPosition();
- if (BookmarksProvider.getInstance(mActivity).remove(mBookmarks.get(pos).hashCode())) {
- mBookmarks.remove(pos);
- mRecyclerView.getAdapter().notifyItemRemoved(pos);
- showHideHolder();
- Snackbar.make(mContentView, R.string.bookmark_removed, Snackbar.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
- float dX, float dY, int actionState, boolean isCurrentlyActive) {
-
- if (viewHolder.getAdapterPosition() == -1) {
- return;
- }
-
- View itemView = viewHolder.itemView;
-
- if (!initialized) {
- init();
- }
-
- background.setBounds(itemView.getRight() + (int) dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
- background.draw(c);
-
- int itemHeight = itemView.getBottom() - itemView.getTop();
- int intrinsicWidth = xMark.getIntrinsicWidth();
- int intrinsicHeight = xMark.getIntrinsicWidth();
-
- int xMarkPos = (int) ((dX + intrinsicHeight) / 2);
- xMark.setAlpha(Math.min(255, (int)(-dX)));
-
- int xMarkLeft = itemView.getRight() + xMarkPos - intrinsicWidth;
- int xMarkRight = itemView.getRight() + xMarkPos;
- int xMarkTop = itemView.getTop() + (itemHeight - intrinsicHeight)/2;
- int xMarkBottom = xMarkTop + intrinsicHeight;
- xMark.setBounds(xMarkLeft, xMarkTop, xMarkRight, xMarkBottom);
-
- xMark.draw(c);
-
- super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
- }
- });
- itemTouchHelper.attachToRecyclerView(mRecyclerView);
- }
-
- public void show() {
- mBookmarks = BookmarksProvider.getInstance(mActivity).getAll();
- mRecyclerView.setAdapter(new BookmarksAdapter(mBookmarks, this));
- showHideHolder();
- mDialog.show();
- }
-
- public void show(MangaInfo manga) {
- mToolbar.setSubtitle(manga.name);
- mBookmarks = BookmarksProvider.getInstance(mActivity).getAll(manga.id);
- mRecyclerView.setAdapter(new BookmarksAdapter(mBookmarks, this));
- showHideHolder();
- mDialog.show();
- }
-
- private void showHideHolder() {
- if (mBookmarks.isEmpty()) {
- mHolder.setVisibility(View.VISIBLE);
- mRecyclerView.setVisibility(View.GONE);
- } else {
- mHolder.setVisibility(View.GONE);
- mRecyclerView.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onBookmarkSelected(Bookmark bookmark) {
- mDialog.dismiss();
- new BookmarkOpenTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, bookmark);
- }
-
- @Override
- public void onClick(View v) {
- mDialog.dismiss();
- }
-
-
- private class BookmarkOpenTask extends AsyncTask> implements DialogInterface.OnCancelListener {
-
- private final ProgressDialog mProgressDialog;
-
- BookmarkOpenTask() {
- mProgressDialog = new ProgressDialog(mActivity);
- mProgressDialog.setIndeterminate(true);
- mProgressDialog.setCancelable(true);
- mProgressDialog.setOnCancelListener(this);
- mProgressDialog.setMessage(mActivity.getString(R.string.loading));
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- mProgressDialog.show();
- }
-
- @Override
- protected Pair doInBackground(Bookmark... params) {
- try {
- Intent intent;
- HistoryProvider historyProvider = HistoryProvider.getInstance(mActivity);
- MangaInfo info = historyProvider.get(params[0].mangaId);
- if (info == null) {
- return new Pair<>(2, null);
- }
- MangaProvider provider;
- if (info.provider.equals(LocalMangaProvider.class)) {
- provider = LocalMangaProvider.getInstance(mActivity);
- } else {
- if (!MangaProviderManager.checkConnection(mActivity)) {
- return new Pair<>(1, null);
- }
- provider = MangaProviderManager.instanceProvider(mActivity, info.provider);
- }
- MangaSummary summary = provider.getDetailedInfo(info);
- intent = new Intent(mActivity, ReadActivity2.class);
- intent.putExtras(summary.toBundle());
- intent.putExtra("chapter", summary.getChapters().indexByNumber(params[0].chapter));
- intent.putExtra("page", params[0].page);
- return new Pair<>(0, intent);
- } catch (Exception e) {
- return new Pair<>(3, null);
- }
- }
-
- @Override
- protected void onPostExecute(Pair result) {
- super.onPostExecute(result);
- mProgressDialog.dismiss();
- int msg;
- switch (result.first) {
- case 0:
- mActivity.startActivity(result.second);
- return;
- case 1:
- msg = R.string.no_network_connection;
- break;
- case 2:
- msg = R.string.history_empty;
- break;
- default:
- msg = R.string.error;
- break;
- }
- new AlertDialog.Builder(mActivity)
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, null)
- .setMessage(mActivity.getString(msg))
- .create().show();
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- this.cancel(false);
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/ChaptersSelectDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/ChaptersSelectDialog.java
deleted file mode 100644
index 79441c8c..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/ChaptersSelectDialog.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.support.annotation.Nullable;
-import android.support.annotation.StringRes;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.Toolbar;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.helpers.MangaSaveHelper;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-
-import java.util.ArrayList;
-
-/**
- * Created by nv95 on 27.09.16.
- */
-
-public class ChaptersSelectDialog implements Toolbar.OnMenuItemClickListener, View.OnClickListener {
-
- private final AlertDialog mDialog;
- private final View mContentView;
-
- private final ListView mListView;
- private final Toolbar mToolbar;
-
- public ChaptersSelectDialog(Context context) {
- mContentView = LayoutInflater.from(context)
- .inflate(R.layout.dialog_chapters, null, false);
- mListView = mContentView.findViewById(R.id.listView);
- mToolbar = mContentView.findViewById(R.id.toolbar);
- mToolbar.setNavigationIcon(R.drawable.ic_cancel_light);
- mToolbar.inflateMenu(R.menu.chapters);
- mToolbar.setNavigationOnClickListener(this);
- mToolbar.setOnMenuItemClickListener(this);
-
- mDialog = new AlertDialog.Builder(context)
- .setView(mContentView)
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- }
-
- public void showSave(MangaSummary mangaSummary, @StringRes int title) {
- mToolbar.setTitle(title);
- mToolbar.setSubtitle(mContentView.getContext().getString(R.string.chapters_total, mangaSummary.chapters.size()));
- mListView.setAdapter(new ArrayAdapter<>(
- mContentView.getContext(),
- R.layout.item_multiple_choice,
- mangaSummary.getChapters().getNames()
- ));
- checkUnsaved(mangaSummary);
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE, mContentView.getContext().getString(R.string.action_save), new SaveClickListener(mangaSummary));
- mDialog.show();
- }
-
- public void showRemove(MangaSummary mangaSummary, OnChaptersRemoveListener listener) {
- mToolbar.setTitle(R.string.action_remove);
- mToolbar.setSubtitle(mContentView.getContext().getString(R.string.chapters_total, mangaSummary.chapters.size()));
- mListView.setAdapter(new ArrayAdapter<>(
- mContentView.getContext(),
- R.layout.item_multiple_choice,
- mangaSummary.getChapters().getNames()
- ));
- checkAll();
- mDialog.setButton(DialogInterface.BUTTON_POSITIVE, mContentView.getContext().getString(R.string.action_remove), new RemoveClickListener(mangaSummary, listener));
- mDialog.show();
- }
-
- private void checkAll() {
- for (int i=mListView.getCount() - 1;i>=0;i--) {
- mListView.setItemChecked(i, true);
- }
- }
-
- private void checkUnsaved(MangaSummary mangaSummary) {
- ArrayList ids = LocalMangaProvider.getInstance(mDialog.getContext())
- .getLocalChaptersNumbers(mangaSummary.id);
- for (int i=mListView.getCount() - 1;i>=0;i--) {
- mListView.setItemChecked(i, !ids.contains(mangaSummary.chapters.get(i).number));
- }
- }
-
- @Override
- public boolean onMenuItemClick(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.action_checkall:
- for (int i=mListView.getCount() - 1;i>=0;i--) {
- mListView.setItemChecked(i, !mListView.isItemChecked(i));
- }
- break;
-
- }
- return true;
- }
-
- @Override
- public void onClick(View v) {
- mDialog.dismiss();
- }
-
- private class SaveClickListener implements DialogInterface.OnClickListener {
-
- private final MangaSummary mMangaSummary;
-
- private SaveClickListener(MangaSummary manga) {
- mMangaSummary = manga;
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- MangaSummary copy = new MangaSummary(mMangaSummary);
- copy.chapters.clear();
- for (int i=0;i parent, View view, int position, long id) {
- if (position == 0) {
- File dir = mAdapter.getCurrentDir().getParentFile();
- if (dir != null) {
- mAdapter.setCurrentDir(mAdapter.getCurrentDir().getParentFile());
- }
- } else {
- mAdapter.setCurrentDir(mAdapter.getItem(position - 1));
- }
- mHeaderUp.setText(mAdapter.getCurrentDir().getPath());
- mAdapter.notifyDataSetChanged();
- }
-
- public DirSelectDialog setDirSelectListener(OnDirSelectListener dirSelectListener) {
- this.mDirSelectListener = dirSelectListener;
- return this;
- }
-
- public void show() {
- mDialog.show();
- }
-
- public interface OnDirSelectListener {
- void onDirSelected(File dir);
- }
-
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/FastHistoryDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/FastHistoryDialog.java
deleted file mode 100644
index 59dac0c2..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/FastHistoryDialog.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
-import android.os.AsyncTask;
-import android.os.Build;
-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.Window;
-import android.view.WindowManager;
-import android.view.animation.AnimationUtils;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.FastHistoryAdapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.lists.MangaList;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.utils.QuickReadTask;
-import org.nv95.openmanga.utils.choicecontrol.OnHolderClickListener;
-
-/**
- * Created by admin on 19.07.17.
- */
-
-public class FastHistoryDialog implements OnHolderClickListener {
-
- private final Dialog mDialog;
- private final RecyclerView mRecyclerView;
- private final HistoryProvider mProvider;
- private final TextView mTextViewHolder;
-
- public FastHistoryDialog(Context context) {
- View view = LayoutInflater.from(context).inflate(R.layout.dialog_fasthist, null, false);
- mRecyclerView = view.findViewById(R.id.recyclerView);
- LinearLayoutManager layoutManager = new LinearLayoutManager(context);
- layoutManager.setStackFromEnd(true);
- layoutManager.setReverseLayout(true);
- mRecyclerView.setLayoutManager(layoutManager);
- mTextViewHolder = view.findViewById(R.id.textView_holder);
- mDialog = new Dialog(context, R.style.FullScreenDialog);
- if (context instanceof Activity) {
- mDialog.setOwnerActivity((Activity) context);
- }
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- mDialog.setContentView(view);
- final int color = ContextCompat.getColor(context, R.color.transparent_dark);
- final Window window = mDialog.getWindow();
- assert window != null;
- window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- window.setBackgroundDrawable(new ColorDrawable(color));
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- view.setFitsSystemWindows(true);
- }
- mProvider = HistoryProvider.getInstance(context);
- view.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- mRecyclerView.startAnimation(AnimationUtils.loadAnimation(mDialog.getContext(), R.anim.up_to_bottom));
- mDialog.dismiss();
- }
- });
- }
-
- public void show(int maxItems) {
- MangaList list = mProvider.getLast(maxItems);
- if (list.isEmpty()) {
- mTextViewHolder.setVisibility(View.VISIBLE);
- } else {
- mRecyclerView.setAdapter(new FastHistoryAdapter(list, this));
- mRecyclerView.startAnimation(AnimationUtils.loadAnimation(mDialog.getContext(), R.anim.up_from_bottom));
- }
- mDialog.show();
- }
-
- @Override
- public boolean onClick(RecyclerView.ViewHolder viewHolder) {
- FastHistoryAdapter adapter = (FastHistoryAdapter) mRecyclerView.getAdapter();
- MangaInfo mangaInfo = adapter.getItem(viewHolder.getAdapterPosition());
- new QuickReadTask(mDialog.getContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mangaInfo);
- mDialog.dismiss();
- return true;
- }
-
- @Override
- public boolean onLongClick(RecyclerView.ViewHolder viewHolder) {
- return false;
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/HintDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/HintDialog.java
deleted file mode 100644
index 42cbbd27..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/HintDialog.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.support.annotation.StringRes;
-
-/**
- * Created by nv95 on 05.12.16.
- */
-
-public class HintDialog {
-
- private final Dialog mDialog;
-
- private HintDialog(Context context, @StringRes int text) {
- mDialog = new AlertDialog.Builder(context)
- .setMessage(text)
- .setCancelable(true)
- .setPositiveButton(android.R.string.ok, null)
- .create();
- }
-
- private void show() {
- mDialog.show();
- }
-
- public static boolean showOnce(Context context, @StringRes int hint) {
- SharedPreferences prefs = context.getSharedPreferences("tips", Context.MODE_PRIVATE);
- final String key = "tip_" + hint;
- if (prefs.getBoolean(key, false)) {
- return false;
- }
- new HintDialog(context, hint).show();
- prefs.edit()
- .putBoolean(key, true)
- .apply();
- return true;
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/LocalMoveDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/LocalMoveDialog.java
deleted file mode 100644
index 0663e5f2..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/LocalMoveDialog.java
+++ /dev/null
@@ -1,254 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.os.AsyncTask;
-import android.os.PowerManager;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.text.format.Formatter;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.ListView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.items.LocalMangaInfo;
-import org.nv95.openmanga.providers.LocalMangaProvider;
-import org.nv95.openmanga.utils.MangaStore;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Created by nv95 on 02.07.16.
- */
-
-public class LocalMoveDialog {
-
- private final Context mContext;
- private final long[] mIds;
- @Nullable
- private String mDestinaton = null;
-
- public LocalMoveDialog(Context context, long... ids) {
- mContext = context;
- mIds = ids;
- }
-
- public LocalMoveDialog setDestination(String path) {
- mDestinaton = path;
- return this;
- }
-
- public void showSelectSource(@Nullable String exclude) {
- new LoadDataTask(exclude).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- public void showSelectDestination(final LocalMangaInfo[] mangas) {
- new DirSelectDialog(mContext)
- .setDirSelectListener(new DirSelectDialog.OnDirSelectListener() {
- @Override
- public void onDirSelected(File dir) {
- mDestinaton = dir.getPath();
- showMove(mangas);
- }
- }).show();
- }
-
- public void showMove(LocalMangaInfo[] mangas) {
- new MoveMangaTask(mDestinaton).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mangas);
- }
-
- private class MoveMangaTask extends AsyncTask {
-
- private final ProgressDialog mProgressDialog;
- private PowerManager.WakeLock mWakeLock;
- private final String mDest;
-
- MoveMangaTask(String dest) {
- mDest = dest;
- mWakeLock = ((PowerManager) mContext.getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Moving manga");
- mProgressDialog = new ProgressDialog(mContext);
- mProgressDialog.setTitle(R.string.moving_files);
- mProgressDialog.setMessage(mContext.getString(R.string.loading));
- mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- mProgressDialog.setCancelable(false);
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- mProgressDialog.show();
- mWakeLock.acquire();
- }
-
- @Override
- protected Long doInBackground(LocalMangaInfo... params) {
- MangaStore store = new MangaStore(mContext);
- long totalSize = 0;
- for (int i = 0; i < params.length; i++) {
- publishProgress(i, params.length, params[i].name);
- if (params[i].path.equals(mDest)) {
- continue;
- }
- if (!store.moveManga(params[i].id, mDest)) {
- return null;
- }
- totalSize += params[i].size;
- }
- return totalSize;
- }
-
- @Override
- protected void onProgressUpdate(Object... values) {
- super.onProgressUpdate(values);
- mProgressDialog.setMax((Integer) values[1]);
- mProgressDialog.setProgress((Integer) values[0]);
- mProgressDialog.setMessage((CharSequence) values[2]);
- }
-
- @Override
- protected void onPostExecute(Long aLong) {
- super.onPostExecute(aLong);
- mProgressDialog.dismiss();
- mWakeLock.release();
- String msg = aLong == null ?
- mContext.getString(R.string.error) : mContext.getString(
- R.string.mangas_moved_done, mDest,
- Formatter.formatFileSize(mContext, aLong)
- );
- new AlertDialog.Builder(mContext)
- .setMessage(msg)
- .setPositiveButton(android.R.string.ok, null)
- .setCancelable(true)
- .create().show();
- }
- }
-
- private class LoadDataTask extends AsyncTask> {
-
- private final ProgressDialog mProgressDialog;
- private final String mExclude;
-
- LoadDataTask(String exclude) {
- mExclude = exclude;
- mProgressDialog = new ProgressDialog(mContext);
- mProgressDialog.setMessage(mContext.getString(R.string.loading));
- mProgressDialog.setIndeterminate(true);
- mProgressDialog.setCancelable(false);
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- mProgressDialog.show();
- }
-
- @Override
- protected List doInBackground(Void... params) {
- LocalMangaInfo[] infos = LocalMangaProvider.getInstance(mContext)
- .getLocalInfo(mIds);
- ArrayList res = new ArrayList<>();
- for (LocalMangaInfo o : infos) {
- if (o != null && !o.path.equals(mExclude)) {
- res.add(o);
- }
- }
- return res;
- }
-
- @Override
- protected void onPostExecute(List localMangaInfos) {
- super.onPostExecute(localMangaInfos);
- mProgressDialog.dismiss();
- if (localMangaInfos.size() == 0) {
- Toast.makeText(mContext, R.string.no_manga_found, Toast.LENGTH_SHORT).show();
- return;
- }
- final SelectAdapter adapter = new SelectAdapter(mContext, localMangaInfos);
- ListView listView = new ListView(mContext);
- listView.setAdapter(adapter);
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView> parent, View view, int position, long id) {
- adapter.toggle(position);
- }
- });
- new AlertDialog.Builder(mContext)
- .setView(listView)
- .setTitle(R.string.move_saved)
- .setPositiveButton(R.string.next, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- LocalMangaInfo[] items = adapter.getCheckedItems();
- if (items.length == 0) {
- Toast.makeText(mContext, R.string.nothing_selected, Toast.LENGTH_SHORT).show();
- } else {
- if (mDestinaton == null) {
- showSelectDestination(items);
- } else {
- showMove(items);
- }
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .setCancelable(true)
- .create().show();
- }
- }
-
- private static class SelectAdapter extends ArrayAdapter {
-
- final boolean[] mChecked;
-
- SelectAdapter(Context context, List objects) {
- super(context, R.layout.item_adapter_checkable, objects);
- mChecked = new boolean[objects.size()];
- Arrays.fill(mChecked, true);
- }
-
- @NonNull
- @SuppressLint("SetTextI18n")
- @Override
- public View getView(int position, View convertView, @NonNull ViewGroup parent) {
- View v = convertView != null ? convertView : LayoutInflater.from(getContext())
- .inflate(R.layout.item_adapter_checkable, parent, false);
- LocalMangaInfo item = getItem(position);
- ((TextView) v.findViewById(android.R.id.text1)).setText(item.name);
- ((TextView) v.findViewById(android.R.id.text2)).setText(
- new File(item.path).getParent()
- + "\n"
- + Formatter.formatFileSize(getContext(), item.size)
- );
- ((CheckBox) v.findViewById(android.R.id.checkbox)).setChecked(mChecked[position]);
- return v;
- }
-
- public LocalMangaInfo[] getCheckedItems() {
- ArrayList list = new ArrayList<>();
- for (int i = 0; i < getCount(); i++) {
- if (mChecked[i]) {
- list.add(getItem(i));
- }
- }
- return list.toArray(new LocalMangaInfo[list.size()]);
- }
-
- public void toggle(int position) {
- mChecked[position] = !mChecked[position];
- notifyDataSetChanged();
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/MenuDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/MenuDialog.java
deleted file mode 100644
index 5f175857..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/MenuDialog.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.support.annotation.MenuRes;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.view.menu.MenuAdapter;
-import android.support.v7.view.menu.MenuBuilder;
-import android.view.LayoutInflater;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-
-/**
- * Created by admin on 24.07.17.
- */
-
-@SuppressLint("RestrictedApi")
-public class MenuDialog implements DialogInterface.OnClickListener {
-
- private final AlertDialog mDialog;
- private final MenuBuilder mMenu;
- @Nullable
- private MenuItem.OnMenuItemClickListener mItemClickListener;
-
- public MenuDialog(Context context, @MenuRes int menuId, @Nullable CharSequence title) {
- mMenu = new MenuBuilder(context);
- new MenuInflater(context).inflate(menuId, mMenu);
- mDialog = new AlertDialog.Builder(context)
- .setAdapter(new MenuAdapter(mMenu, LayoutInflater.from(context), false), this)
- .setTitle(title)
- .create();
- }
-
- public MenuDialog setOnItemClickListener(MenuItem.OnMenuItemClickListener listener) {
- mItemClickListener = listener;
- return this;
- }
-
- public void show() {
- mDialog.show();
- }
-
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- if (mItemClickListener != null) {
- mItemClickListener.onMenuItemClick(mMenu.getItem(i));
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/NavigationListener.java b/app/src/main/java/org/nv95/openmanga/dialogs/NavigationListener.java
deleted file mode 100644
index df215cdc..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/NavigationListener.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-/**
- * Created by nv95 on 09.10.16.
- */
-
-public interface NavigationListener {
- void onPageChange(int page);
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/PageNumberDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/PageNumberDialog.java
deleted file mode 100644
index 5a6ae301..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/PageNumberDialog.java
+++ /dev/null
@@ -1,93 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-
-/**
- * Created by nv95 on 09.10.16.
- */
-
-public class PageNumberDialog implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener, DialogInterface.OnShowListener {
-
- private AlertDialog mDialog;
- private NavigationListener mNavigationListener;
- private Context mContext;
- //controls
- private EditText mEditText;
- private TextView mTextView;
-
- public PageNumberDialog(Context context) {
- this.mContext = context;
- View view = View.inflate(context, R.layout.dialog_pagenumber, null);
- mEditText = view.findViewById(R.id.editText);
- mTextView = view.findViewById(R.id.textView);
- AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setView(view);
- builder.setTitle(R.string.navigate);
- builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
- builder.setPositiveButton(R.string.navigate, this);
- mDialog = builder.create();
- mDialog.setOnShowListener(this);
- }
-
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- mTextView.setText(mContext.getString(R.string.goto_page, progress + 1, seekBar.getMax()));
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
-
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
-
- }
-
- public void show(int current) {
- mEditText.setText(String.valueOf(current));
- mDialog.show();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (mNavigationListener != null)
- try {
- int num = Integer.parseInt(mEditText.getText().toString());
- if (num < 0) {
- Toast.makeText(mContext, R.string.invalid_value, Toast.LENGTH_SHORT).show();
- } else {
- mNavigationListener.onPageChange(num);
- }
- } catch (NumberFormatException e) {
- Toast.makeText(mContext, R.string.invalid_value, Toast.LENGTH_SHORT).show();
- }
- }
-
- public PageNumberDialog setNavigationListener(NavigationListener navigationListener) {
- this.mNavigationListener = navigationListener;
- return this;
- }
-
- @Override
- public void onShow(DialogInterface dialog) {
- mEditText.setSelection(mEditText.getText().length());
- LayoutUtils.showSoftKeyboard(mEditText);
- }
-}
-
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/PreviewDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/PreviewDialog.java
deleted file mode 100644
index 08543f10..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/PreviewDialog.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.support.annotation.NonNull;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ProgressBar;
-import android.widget.TextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.activities.ReadActivity2;
-import org.nv95.openmanga.adapters.ChaptersAdapter;
-import org.nv95.openmanga.adapters.OnChapterClickListener;
-import org.nv95.openmanga.items.Bookmark;
-import org.nv95.openmanga.items.MangaChapter;
-import org.nv95.openmanga.items.MangaInfo;
-import org.nv95.openmanga.items.MangaSummary;
-import org.nv95.openmanga.providers.HistoryProvider;
-import org.nv95.openmanga.providers.MangaProvider;
-import org.nv95.openmanga.providers.staff.MangaProviderManager;
-import org.nv95.openmanga.utils.AnimUtils;
-import org.nv95.openmanga.utils.WeakAsyncTask;
-
-import java.lang.ref.WeakReference;
-import java.util.List;
-
-/**
- * Created by admin on 16.08.17.
- */
-
-public class PreviewDialog implements DialogInterface.OnDismissListener, OnChapterClickListener {
-
- private final AlertDialog mDialog;
- private final View mContentView;
- private final TextView mHolder;
- private final ProgressBar mProgressBar;
- private final RecyclerView mRecyclerView;
- private final ChaptersAdapter mChaptersAdapter;
- private MangaSummary mManga;
- private WeakReference mTaskRef;
-
- public PreviewDialog(Context context) {
- mContentView = LayoutInflater.from(context)
- .inflate(R.layout.dialog_preview, null, false);
- mRecyclerView = mContentView.findViewById(R.id.recyclerView);
- mHolder = mContentView.findViewById(R.id.textView_holder);
- mProgressBar = mContentView.findViewById(R.id.progressBar);
- mChaptersAdapter = new ChaptersAdapter(context);
- mChaptersAdapter.setOnItemClickListener(this);
- mRecyclerView.setAdapter(mChaptersAdapter);
-
- mDialog = new AlertDialog.Builder(context)
- .setView(mContentView)
- .setCancelable(true)
- .setOnDismissListener(this)
- .create();
- }
-
- public void show(MangaInfo mangaInfo) {
- mManga = new MangaSummary(mangaInfo);
- LoadTask task = new LoadTask(this);
- mTaskRef = new WeakReference<>(task);
- task.start();
- mDialog.show();
- }
-
- @Override
- public void onDismiss(DialogInterface dialogInterface) {
- WeakAsyncTask.cancel(mTaskRef, true);
- }
-
- @Override
- public void onChapterClick(int pos, MangaChapter chapter) {
- if (pos == -1) {
- Intent intent = new Intent(mDialog.getContext(), ReadActivity2.class);
- intent.putExtras(mManga.toBundle());
- HistoryProvider.HistorySummary hs = HistoryProvider.getInstance(mDialog.getContext())
- .get(mManga);
- if (hs != null) {
- int index = mManga.chapters.indexByNumber(hs.getChapter());
- if (index != -1) {
- intent.putExtra("chapter", index);
- intent.putExtra("page", hs.getPage());
- }
- }
- mDialog.getContext().startActivity(intent);
- } else {
- HistoryProvider.getInstance(mDialog.getContext()).add(mManga, chapter.number, 0);
- mDialog.getContext().startActivity(new Intent(mDialog.getContext(), ReadActivity2.class)
- .putExtra("chapter", pos).putExtras(mManga.toBundle()));
- }
- mDialog.dismiss();
- }
-
- @Override
- public boolean onChapterLongClick(int pos, MangaChapter chapter) {
- return false;
- }
-
- private static class LoadTask extends WeakAsyncTask, MangaSummary> {
-
- LoadTask(PreviewDialog object) {
- super(object);
- }
-
- @Override
- protected void onPreExecute(@NonNull PreviewDialog dialog) {
- }
-
- @SuppressWarnings("ConstantConditions")
- @Override
- protected MangaSummary doInBackground(Void... params) {
- try {
- //noinspection unchecked
- MangaProvider provider = MangaProviderManager.instanceProvider(getObject().mDialog.getContext(), getObject().mManga.provider);
- return provider.getDetailedInfo(getObject().mManga);
- } catch (Exception e) {
- return null;
- }
- }
-
- @Override
- protected void onPostExecute(@NonNull final PreviewDialog dialog, MangaSummary mangaSummary) {
- if (mangaSummary != null) {
- dialog.mManga = mangaSummary;
- if (mangaSummary.chapters.isEmpty()) {
- dialog.mHolder.setText(R.string.no_chapters_found);
- AnimUtils.crossfade(dialog.mProgressBar, dialog.mHolder);
- } else {
- dialog.mChaptersAdapter.setData(dialog.mManga.chapters);
- dialog.mChaptersAdapter.setExtra(HistoryProvider.getInstance(dialog.mDialog.getContext()).get(dialog.mManga));
- dialog.mChaptersAdapter.notifyDataSetChanged();
- dialog.mRecyclerView.postDelayed(new Runnable() {
- @Override
- public void run() {
- dialog.mRecyclerView.scrollToPosition(0);
- }
- }, 500);
- AnimUtils.crossfade(dialog.mProgressBar, null);
- }
- } else {
- dialog.mHolder.setText(R.string.loading_error);
- AnimUtils.crossfade(dialog.mProgressBar, dialog.mHolder);
- }
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/RecommendationsPrefDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/RecommendationsPrefDialog.java
deleted file mode 100644
index fa64965b..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/RecommendationsPrefDialog.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.support.annotation.Nullable;
-import android.support.v7.app.AlertDialog;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.Checkable;
-import android.widget.CheckedTextView;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.adapters.GenresSortAdapter;
-
-/**
- * Created by nv95 on 22.06.16.
- */
-
-public class RecommendationsPrefDialog implements View.OnClickListener {
-
- private final Dialog mDialog;
- @Nullable
- private final GenresSortAdapter.Callback mCallback;
-
- public RecommendationsPrefDialog(final Context context, @Nullable GenresSortAdapter.Callback callback) {
- @SuppressLint("InflateParams")
- View contentView = LayoutInflater.from(context)
- .inflate(R.layout.dialog_recommendprefs, null);
- final CheckedTextView checkedTextViewFav = contentView.findViewById(R.id.checkedTextView_fav);
- final CheckedTextView checkedTextViewHist = contentView.findViewById(R.id.checkedTextView_hist);
- final CheckedTextView checkedTextViewMatch = contentView.findViewById(R.id.checkedTextView_match);
-
- checkedTextViewFav.setOnClickListener(this);
- checkedTextViewHist.setOnClickListener(this);
- checkedTextViewMatch.setOnClickListener(this);
-
- final SharedPreferences prefs = context.getSharedPreferences("recommendations", Context.MODE_PRIVATE);
- checkedTextViewFav.setChecked(prefs.getBoolean("fav", true));
- checkedTextViewHist.setChecked(prefs.getBoolean("hist", true));
- checkedTextViewMatch.setChecked(prefs.getBoolean("match", false));
-
- mDialog = new AlertDialog.Builder(context)
- .setView(contentView)
- .setCancelable(true)
- .setTitle(R.string.recommendations_options)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- prefs.edit()
- .putBoolean("fav", checkedTextViewFav.isChecked())
- .putBoolean("hist", checkedTextViewHist.isChecked())
- .putBoolean("match", checkedTextViewMatch.isChecked())
- .apply();
- if (mCallback != null) {
- mCallback.onApply(
- 0, checkedTextViewMatch.isChecked() ? 100 : 50, null, null
- );
- }
- }
- })
- .setNegativeButton(android.R.string.cancel, null)
- .create();
- mCallback = callback;
- }
-
- public void show() {
- mDialog.show();
- }
-
- @Override
- public void onClick(View v) {
- if (v instanceof Checkable) {
- ((Checkable)v).toggle();
- }
- }
-}
diff --git a/app/src/main/java/org/nv95/openmanga/dialogs/StorageSelectDialog.java b/app/src/main/java/org/nv95/openmanga/dialogs/StorageSelectDialog.java
deleted file mode 100644
index 8a8fa9e7..00000000
--- a/app/src/main/java/org/nv95/openmanga/dialogs/StorageSelectDialog.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package org.nv95.openmanga.dialogs;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.graphics.drawable.Drawable;
-import android.support.v7.app.AlertDialog;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.SimpleAdapter;
-
-import org.nv95.openmanga.R;
-import org.nv95.openmanga.utils.LayoutUtils;
-import org.nv95.openmanga.utils.StorageUtils;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Created by nv95 on 22.11.16.
- */
-
-public class StorageSelectDialog implements DialogInterface.OnClickListener, SimpleAdapter.ViewBinder {
-
- private final AlertDialog mDialog;
- private final SimpleAdapter mAdapter;
- private final List mStorages;
- private DirSelectDialog.OnDirSelectListener mDirSelectListener;
- private final boolean mOnlyRoots;
-
- public StorageSelectDialog(Context context) {
- this(context, false);
- }
-
- public StorageSelectDialog(final Context context, boolean onlyRoots) {
- mOnlyRoots = onlyRoots;
- mStorages = StorageUtils.getAvailableStorages(context);
- final Drawable[] icons = LayoutUtils.getThemedIcons(
- context,
- R.drawable.ic_storage_52,
- R.drawable.ic_directory_52
- );
- ArrayList