Settings in Kotlin

This commit is contained in:
inorichi 2016-02-27 17:49:22 +01:00
parent 1a14fc5c48
commit fabdba4452
17 changed files with 577 additions and 679 deletions

View file

@ -1,62 +1,55 @@
@file:JvmName("IOHandler")
package eu.kanade.tachiyomi.data.io package eu.kanade.tachiyomi.data.io
import android.content.Context import android.content.Context
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.ToastUtil
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream import java.io.FileOutputStream
import java.io.IOException import java.io.IOException
/** /**
* Returns temp file location * Returns temp file location.
* *
* @param context context of application * @param context context of application.
* @throws IOException IO exception * @throws IOException IO exception.
* @return location of temp file * @return location of temp file.
*/ */
@Throws(IOException::class) @Throws(IOException::class)
private fun getTempFilename(context: Context): String { private fun getTempFilename(context: Context): String {
// Get output directory. // Get output directory.
val outputDir = context.cacheDir val outputDir = context.cacheDir
// Create temporary file // Create temporary file
val outputFile = File.createTempFile("temp_cover", "0", outputDir) val outputFile = File.createTempFile("temp_cover", "0", outputDir)
// Return path of temporary file // Return path of temporary file
return outputFile.absolutePath return outputFile.absolutePath
}
/**
* Download media to temp location and returns file path.
*
* @param input input stream containing input file.
* @param context context of application.
* @throws IOException IO exception.
* @return location of temp file.
*/
@Throws(IOException::class)
fun downloadMediaAndReturnPath(input: FileInputStream, context: Context): String {
var output: FileOutputStream? = null
try {
// Get temp file name.
val tempFilename = getTempFilename(context)
output = FileOutputStream(tempFilename)
// Copy input stream to temp location.
input.copyTo(output)
return tempFilename
} finally {
// Close streams.
input.close()
output?.close()
} }
/** }
* Download media to temp location and returns file path
*
* @param input input stream containing input file
* @param context context of application
* @throws IOException IO exception
* @return location of temp file
*/
@Throws(IOException::class)
fun downloadMediaAndReturnPath(input: FileInputStream, context: Context): String {
var tempFilename = ""
var output: FileOutputStream? = null
try {
// Get temp file name.
tempFilename = getTempFilename(context)
output = FileOutputStream(tempFilename)
// Copy input stream to temp location.
input.copyTo(output)
} catch (e: IOException) {
// Show user something went wrong and print stackTrace.
ToastUtil.showShort(context, R.string.notification_manga_update_failed)
e.printStackTrace()
} finally {
// Close streams.
input.close()
output?.close()
}
// Return temp name.
return tempFilename
}

View file

@ -7,6 +7,8 @@ import android.view.MenuItem;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import eu.kanade.tachiyomi.App;
import eu.kanade.tachiyomi.injection.component.AppComponent;
import icepick.Icepick; import icepick.Icepick;
public class BaseActivity extends AppCompatActivity { public class BaseActivity extends AppCompatActivity {
@ -67,4 +69,8 @@ public class BaseActivity extends AppCompatActivity {
EventBus.getDefault().unregister(this); EventBus.getDefault().unregister(this);
} }
protected AppComponent getApplicationComponent() {
return App.get(this).getComponent();
}
} }

View file

@ -14,6 +14,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.io.downloadMediaAndReturnPath
import eu.kanade.tachiyomi.data.library.LibraryUpdateService import eu.kanade.tachiyomi.data.library.LibraryUpdateService
import eu.kanade.tachiyomi.event.LibraryMangasEvent import eu.kanade.tachiyomi.event.LibraryMangasEvent
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment
@ -21,6 +22,7 @@ import eu.kanade.tachiyomi.ui.category.CategoryActivity
import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.main.MainActivity
import eu.kanade.tachiyomi.util.ToastUtil import eu.kanade.tachiyomi.util.ToastUtil
import eu.kanade.tachiyomi.util.inflate import eu.kanade.tachiyomi.util.inflate
import eu.kanade.tachiyomi.util.toast
import kotlinx.android.synthetic.main.fragment_library.* import kotlinx.android.synthetic.main.fragment_library.*
import nucleus.factory.RequiresPresenter import nucleus.factory.RequiresPresenter
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
@ -307,30 +309,29 @@ class LibraryFragment : BaseRxFragment<LibraryPresenter>(), ActionMode.Callback
} }
} }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMAGE_OPEN) { if (data != null && resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMAGE_OPEN) {
selectedCoverManga?.let { manga -> selectedCoverManga?.let { manga ->
try { try {
// Get the file's input stream from the incoming Intent // Get the file's input stream from the incoming Intent
val inputStream = context.contentResolver.openInputStream(data.data) val inputStream = context.contentResolver.openInputStream(data.data)
// Convert to absolute path to prevent FileNotFoundException // Convert to absolute path to prevent FileNotFoundException
val result = eu.kanade.tachiyomi.data.io.downloadMediaAndReturnPath(inputStream as FileInputStream, val result = downloadMediaAndReturnPath(inputStream as FileInputStream, context)
context)
// Get file from filepath // Get file from filepath
val picture = File(result) val picture = File(result)
// Update cover to selected file, show error if something went wrong // Update cover to selected file, show error if something went wrong
if (presenter.editCoverWithLocalFile(picture, manga)) { if (presenter.editCoverWithLocalFile(picture, manga)) {
adapter.refreshRegisteredAdapters() adapter.refreshRegisteredAdapters()
} else { } else {
ToastUtil.showShort(context, R.string.notification_manga_update_failed) context.toast(R.string.notification_manga_update_failed)
} }
} catch (e: IOException) { } catch (e: IOException) {
ToastUtil.showShort(context, R.string.notification_manga_update_failed) context.toast(R.string.notification_manga_update_failed)
e.printStackTrace() e.printStackTrace()
} }
} }

View file

@ -1,132 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.preference.Preference;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.afollestad.materialdialogs.MaterialDialog;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import eu.kanade.tachiyomi.BuildConfig;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker;
import eu.kanade.tachiyomi.data.updater.UpdateDownloader;
import eu.kanade.tachiyomi.util.ToastUtil;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class SettingsAboutFragment extends SettingsNestedFragment {
/**
* Checks for new releases
*/
private GithubUpdateChecker updateChecker;
/**
* The subscribtion service of the obtained release object
*/
private Subscription releaseSubscription;
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsAboutFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
//Check for update
updateChecker = new GithubUpdateChecker(getActivity());
super.onCreate(savedInstanceState);
}
@Override
public void onDestroyView() {
if (releaseSubscription != null)
releaseSubscription.unsubscribe();
super.onDestroyView();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
Preference version = findPreference(getString(R.string.pref_version));
Preference buildTime = findPreference(getString(R.string.pref_build_time));
version.setSummary(BuildConfig.DEBUG ? "r" + BuildConfig.COMMIT_COUNT :
BuildConfig.VERSION_NAME);
//Set onClickListener to check for new version
version.setOnPreferenceClickListener(preference -> {
if (!BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER)
checkVersion();
return true;
});
buildTime.setSummary(getFormattedBuildTime());
return super.onCreateView(inflater, container, savedState);
}
private String getFormattedBuildTime() {
try {
DateFormat inputDf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
inputDf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = inputDf.parse(BuildConfig.BUILD_TIME);
DateFormat outputDf = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault());
outputDf.setTimeZone(TimeZone.getDefault());
return outputDf.format(date);
} catch (ParseException e) {
// Do nothing
}
return "";
}
/**
* Checks version and shows a user prompt when update available.
*/
private void checkVersion() {
releaseSubscription = updateChecker.checkForApplicationUpdate()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(release -> {
//Get version of latest release
String newVersion = release.getVersion();
newVersion = newVersion.replaceAll("[^\\d.]", "");
//Check if latest version is different from current version
if (!newVersion.equals(BuildConfig.VERSION_NAME)) {
String downloadLink = release.getDownloadLink();
String body = release.getChangeLog();
//Create confirmation window
new MaterialDialog.Builder(getActivity())
.title(getString(R.string.update_check_title))
.content(body)
.positiveText(getString(R.string.update_check_confirm))
.negativeText(getString(R.string.update_check_ignore))
.onPositive((dialog, which) -> {
// User output that download has started
ToastUtil.showShort(getActivity(), getString(R.string.update_check_download_started));
// Start download
new UpdateDownloader(getActivity().getApplicationContext()).execute(downloadLink);
})
.show();
} else {
ToastUtil.showShort(getActivity(), getString(R.string.update_check_no_new_updates));
}
}, Throwable::printStackTrace);
}
}

View file

@ -0,0 +1,119 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.view.View
import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
import eu.kanade.tachiyomi.data.updater.UpdateDownloader
import eu.kanade.tachiyomi.util.ToastUtil
import eu.kanade.tachiyomi.util.toast
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import java.text.DateFormat
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*
class SettingsAboutFragment : SettingsNestedFragment() {
/**
* Checks for new releases
*/
private val updateChecker by lazy { GithubUpdateChecker(activity) }
/**
* The subscribtion service of the obtained release object
*/
private var releaseSubscription: Subscription? = null
companion object {
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
val fragment = SettingsAboutFragment()
fragment.setArgs(resourcePreference, resourceTitle)
return fragment
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val version = findPreference(getString(R.string.pref_version))
val buildTime = findPreference(getString(R.string.pref_build_time))
version.summary = if (BuildConfig.DEBUG)
"r" + BuildConfig.COMMIT_COUNT
else
BuildConfig.VERSION_NAME
//Set onClickListener to check for new version
version.setOnPreferenceClickListener {
if (!BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER)
checkVersion()
true
}
buildTime.summary = getFormattedBuildTime()
}
override fun onDestroyView() {
releaseSubscription?.unsubscribe()
super.onDestroyView()
}
private fun getFormattedBuildTime(): String {
try {
val inputDf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'")
inputDf.timeZone = TimeZone.getTimeZone("UTC")
val date = inputDf.parse(BuildConfig.BUILD_TIME)
val outputDf = DateFormat.getDateTimeInstance(
DateFormat.MEDIUM, DateFormat.SHORT, Locale.getDefault())
outputDf.timeZone = TimeZone.getDefault()
return outputDf.format(date)
} catch (e: ParseException) {
return BuildConfig.BUILD_TIME
}
}
/**
* Checks version and shows a user prompt if an update is available.
*/
private fun checkVersion() {
releaseSubscription?.unsubscribe()
releaseSubscription = updateChecker.checkForApplicationUpdate()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ release ->
//Get version of latest release
var newVersion = release.version
newVersion = newVersion.replace("[^\\d.]".toRegex(), "")
//Check if latest version is different from current version
if (newVersion != BuildConfig.VERSION_NAME) {
val downloadLink = release.downloadLink
val body = release.changeLog
//Create confirmation window
MaterialDialog.Builder(activity)
.title(R.string.update_check_title)
.content(body)
.positiveText(getString(R.string.update_check_confirm))
.negativeText(getString(R.string.update_check_ignore))
.onPositive { dialog, which ->
// User output that download has started
context.toast(R.string.update_check_download_started)
// Start download
UpdateDownloader(activity.applicationContext).execute(downloadLink)
}.show()
} else {
ToastUtil.showShort(activity, getString(R.string.update_check_no_new_updates))
}
}, {
it.printStackTrace()
})
}
}

View file

@ -1,82 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import javax.inject.Inject;
import eu.kanade.tachiyomi.App;
import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager;
import eu.kanade.tachiyomi.data.mangasync.base.MangaSyncService;
import eu.kanade.tachiyomi.data.source.SourceManager;
import eu.kanade.tachiyomi.data.source.base.Source;
import eu.kanade.tachiyomi.widget.preference.MangaSyncLoginDialog;
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog;
import rx.Observable;
public class SettingsAccountsFragment extends SettingsNestedFragment {
@Inject SourceManager sourceManager;
@Inject MangaSyncManager syncManager;
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsAccountsFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
App.get(getActivity()).getComponent().inject(this);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedSate) {
View view = super.onCreateView(inflater, container, savedSate);
PreferenceScreen screen = getPreferenceScreen();
List<Source> sourceAccounts = getSourcesWithLogin();
PreferenceCategory sourceCategory = new PreferenceCategory(screen.getContext());
sourceCategory.setTitle("Sources");
screen.addPreference(sourceCategory);
for (Source source : sourceAccounts) {
SourceLoginDialog dialog = new SourceLoginDialog(
screen.getContext(), preferences, source);
dialog.setTitle(source.getName());
sourceCategory.addPreference(dialog);
}
PreferenceCategory mangaSyncCategory = new PreferenceCategory(screen.getContext());
mangaSyncCategory.setTitle("Sync");
screen.addPreference(mangaSyncCategory);
for (MangaSyncService sync : syncManager.getServices()) {
MangaSyncLoginDialog dialog = new MangaSyncLoginDialog(
screen.getContext(), preferences, sync);
dialog.setTitle(sync.getName());
mangaSyncCategory.addPreference(dialog);
}
return view;
}
private List<Source> getSourcesWithLogin() {
return Observable.from(sourceManager.getSources())
.filter(Source::isLoginRequired)
.toList()
.toBlocking()
.single();
}
}

View file

@ -0,0 +1,51 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.preference.PreferenceCategory
import android.view.View
import eu.kanade.tachiyomi.data.source.base.Source
import eu.kanade.tachiyomi.widget.preference.MangaSyncLoginDialog
import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
class SettingsAccountsFragment : SettingsNestedFragment() {
companion object {
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
val fragment = SettingsAccountsFragment()
fragment.setArgs(resourcePreference, resourceTitle)
return fragment
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
PreferenceCategory(context).apply {
preferenceScreen.addPreference(this)
title = "Sources"
for (source in getSourcesWithLogin()) {
val dialog = SourceLoginDialog(context, preferences, source)
dialog.title = source.name
addPreference(dialog)
}
}
PreferenceCategory(context).apply {
preferenceScreen.addPreference(this)
title = "Sync"
for (sync in settingsActivity.syncManager.services) {
val dialog = MangaSyncLoginDialog(context, preferences, sync)
dialog.title = sync.name
addPreference(dialog)
}
}
}
fun getSourcesWithLogin(): List<Source> {
return settingsActivity.sourceManager.sources.filter { it.isLoginRequired }
}
}

View file

@ -1,96 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.support.v7.widget.Toolbar;
import javax.inject.Inject;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.App;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.cache.ChapterCache;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity;
public class SettingsActivity extends BaseActivity {
@Inject PreferencesHelper preferences;
@Inject ChapterCache chapterCache;
@Inject DatabaseHelper db;
@Bind(R.id.toolbar) Toolbar toolbar;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
App.get(this).getComponent().inject(this);
setContentView(R.layout.activity_preferences);
ButterKnife.bind(this);
setupToolbar(toolbar);
if (savedState == null)
getFragmentManager().beginTransaction().replace(R.id.settings_content,
new SettingsMainFragment())
.commit();
}
@Override
public void onBackPressed() {
if( !getFragmentManager().popBackStackImmediate() ) super.onBackPressed();
}
public static class SettingsMainFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_main);
registerSubpreference(R.string.pref_category_general_key,
SettingsGeneralFragment.newInstance(
R.xml.pref_general, R.string.pref_category_general));
registerSubpreference(R.string.pref_category_reader_key,
SettingsNestedFragment.newInstance(
R.xml.pref_reader, R.string.pref_category_reader));
registerSubpreference(R.string.pref_category_downloads_key,
SettingsDownloadsFragment.newInstance(
R.xml.pref_downloads, R.string.pref_category_downloads));
registerSubpreference(R.string.pref_category_accounts_key,
SettingsAccountsFragment.newInstance(
R.xml.pref_accounts, R.string.pref_category_accounts));
registerSubpreference(R.string.pref_category_advanced_key,
SettingsAdvancedFragment.newInstance(
R.xml.pref_advanced, R.string.pref_category_advanced));
registerSubpreference(R.string.pref_category_about_key,
SettingsAboutFragment.newInstance(
R.xml.pref_about, R.string.pref_category_about));
}
@Override
public void onResume() {
super.onResume();
((BaseActivity) getActivity()).setToolbarTitle(getString(R.string.label_settings));
}
private void registerSubpreference(int preferenceResource, PreferenceFragment fragment) {
findPreference(getString(preferenceResource))
.setOnPreferenceClickListener(preference -> {
getFragmentManager().beginTransaction()
.replace(R.id.settings_content, fragment)
.addToBackStack(fragment.getClass().getSimpleName()).commit();
return true;
});
}
}
}

View file

@ -0,0 +1,90 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.preference.PreferenceFragment
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.mangasync.MangaSyncManager
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.source.SourceManager
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import kotlinx.android.synthetic.main.toolbar.*
import javax.inject.Inject
class SettingsActivity : BaseActivity() {
@Inject lateinit var preferences: PreferencesHelper
@Inject lateinit var chapterCache: ChapterCache
@Inject lateinit var db: DatabaseHelper
@Inject lateinit var sourceManager: SourceManager
@Inject lateinit var syncManager: MangaSyncManager
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
setContentView(R.layout.activity_preferences)
applicationComponent.inject(this)
setupToolbar(toolbar)
if (savedState == null) {
fragmentManager.beginTransaction().replace(R.id.settings_content,
SettingsMainFragment()).commit()
}
}
override fun onBackPressed() {
if (!fragmentManager.popBackStackImmediate()) {
super.onBackPressed()
}
}
class SettingsMainFragment : PreferenceFragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_main)
registerSubpreference(R.string.pref_category_general_key,
SettingsGeneralFragment.newInstance(
R.xml.pref_general, R.string.pref_category_general))
registerSubpreference(R.string.pref_category_reader_key,
SettingsNestedFragment.newInstance(
R.xml.pref_reader, R.string.pref_category_reader))
registerSubpreference(R.string.pref_category_downloads_key,
SettingsDownloadsFragment.newInstance(
R.xml.pref_downloads, R.string.pref_category_downloads))
registerSubpreference(R.string.pref_category_accounts_key,
SettingsAccountsFragment.newInstance(
R.xml.pref_accounts, R.string.pref_category_accounts))
registerSubpreference(R.string.pref_category_advanced_key,
SettingsAdvancedFragment.newInstance(
R.xml.pref_advanced, R.string.pref_category_advanced))
registerSubpreference(R.string.pref_category_about_key,
SettingsAboutFragment.newInstance(
R.xml.pref_about, R.string.pref_category_about))
}
override fun onResume() {
super.onResume()
(activity as BaseActivity).setToolbarTitle(getString(R.string.label_settings))
}
private fun registerSubpreference(preferenceResource: Int, fragment: PreferenceFragment) {
findPreference(getString(preferenceResource)).setOnPreferenceClickListener {
fragmentManager.beginTransaction()
.replace(R.id.settings_content, fragment)
.addToBackStack(fragment.javaClass.simpleName)
.commit()
true
}
}
}
}

View file

@ -1,109 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.preference.Preference;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.cache.ChapterCache;
import eu.kanade.tachiyomi.data.database.DatabaseHelper;
import eu.kanade.tachiyomi.util.ToastUtil;
import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
public class SettingsAdvancedFragment extends SettingsNestedFragment {
private CompositeSubscription subscriptions;
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsAdvancedFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
View view = super.onCreateView(inflater, container, savedState);
subscriptions = new CompositeSubscription();
Preference clearCache = findPreference(getString(R.string.pref_clear_chapter_cache_key));
clearCache.setOnPreferenceClickListener(preference -> {
clearChapterCache(preference);
return true;
});
clearCache.setSummary(getString(R.string.used_cache, getChapterCache().getReadableSize()));
Preference clearDatabase = findPreference(getString(R.string.pref_clear_database_key));
clearDatabase.setOnPreferenceClickListener(preference -> {
clearDatabase();
return true;
});
return view;
}
@Override
public void onDestroyView() {
subscriptions.unsubscribe();
super.onDestroyView();
}
private void clearChapterCache(Preference preference) {
final ChapterCache chapterCache = getChapterCache();
final AtomicInteger deletedFiles = new AtomicInteger();
File[] files = chapterCache.getCacheDir().listFiles();
MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(R.string.deleting)
.progress(false, files.length, true)
.cancelable(false)
.show();
subscriptions.add(Observable.defer(() -> Observable.from(files))
.concatMap(file -> {
if (chapterCache.removeFileFromCache(file.getName())) {
deletedFiles.incrementAndGet();
}
return Observable.just(file);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(file -> dialog.incrementProgress(1),
error -> {
dialog.dismiss();
ToastUtil.showShort(getActivity(), getString(R.string.cache_delete_error));
}, () -> {
dialog.dismiss();
ToastUtil.showShort(getActivity(), getString(R.string.cache_deleted, deletedFiles.get()));
preference.setSummary(getString(R.string.used_cache, chapterCache.getReadableSize()));
}));
}
private void clearDatabase() {
final DatabaseHelper db = getSettingsActivity().db;
new MaterialDialog.Builder(getActivity())
.content(R.string.clear_database_confirmation)
.positiveText(R.string.button_yes)
.negativeText(R.string.button_no)
.onPositive((dialog1, which) -> {
db.deleteMangasNotInLibrary().executeAsBlocking();
})
.show();
}
private ChapterCache getChapterCache() {
return getSettingsActivity().chapterCache;
}
}

View file

@ -0,0 +1,100 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.preference.Preference
import android.view.View
import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.cache.ChapterCache
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.util.ToastUtil
import rx.Observable
import rx.Subscription
import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import java.util.concurrent.atomic.AtomicInteger
class SettingsAdvancedFragment : SettingsNestedFragment() {
private var clearCacheSubscription: Subscription? = null
companion object {
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
val fragment = SettingsAdvancedFragment()
fragment.setArgs(resourcePreference, resourceTitle)
return fragment
}
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
val clearCache = findPreference(getString(R.string.pref_clear_chapter_cache_key))
val clearDatabase = findPreference(getString(R.string.pref_clear_database_key))
clearCache.setOnPreferenceClickListener { preference ->
clearChapterCache(preference)
true
}
clearCache.summary = getString(R.string.used_cache, chapterCache.readableSize)
clearDatabase.setOnPreferenceClickListener { preference ->
clearDatabase()
true
}
}
override fun onDestroyView() {
clearCacheSubscription?.unsubscribe()
super.onDestroyView()
}
private fun clearChapterCache(preference: Preference) {
val deletedFiles = AtomicInteger()
val files = chapterCache.cacheDir.listFiles()
val dialog = MaterialDialog.Builder(activity)
.title(R.string.deleting)
.progress(false, files.size, true)
.cancelable(false)
.show()
clearCacheSubscription?.unsubscribe()
clearCacheSubscription = Observable.defer { Observable.from(files) }
.concatMap { file ->
if (chapterCache.removeFileFromCache(file.name)) {
deletedFiles.incrementAndGet()
}
Observable.just(file)
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
dialog.incrementProgress(1)
}, {
dialog.dismiss()
ToastUtil.showShort(activity, getString(R.string.cache_delete_error))
}, {
dialog.dismiss()
ToastUtil.showShort(activity, getString(R.string.cache_deleted, deletedFiles.get()))
preference.summary = getString(R.string.used_cache, chapterCache.readableSize)
})
}
private fun clearDatabase() {
MaterialDialog.Builder(activity)
.content(R.string.clear_database_confirmation)
.positiveText(R.string.button_yes)
.negativeText(R.string.button_no)
.onPositive { dialog, which -> db.deleteMangasNotInLibrary().executeAsBlocking() }
.show()
}
private val chapterCache: ChapterCache
get() = settingsActivity.chapterCache
private val db: DatabaseHelper
get() = settingsActivity.db
}

View file

@ -1,101 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.Preference;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
import com.nononsenseapps.filepicker.FilePickerActivity;
import com.nononsenseapps.filepicker.FilePickerFragment;
import com.nononsenseapps.filepicker.LogicHandler;
import java.io.File;
import eu.kanade.tachiyomi.R;
public class SettingsDownloadsFragment extends SettingsNestedFragment {
Preference downloadDirPref;
public static final int DOWNLOAD_DIR_CODE = 1;
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsDownloadsFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
downloadDirPref = findPreference(getString(R.string.pref_download_directory_key));
downloadDirPref.setOnPreferenceClickListener(preference -> {
Intent i = new Intent(getActivity(), CustomLayoutPickerActivity.class);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false);
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true);
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR);
i.putExtra(FilePickerActivity.EXTRA_START_PATH, preferences.getDownloadsDirectory());
startActivityForResult(i, DOWNLOAD_DIR_CODE);
return true;
});
return view;
}
@Override
public void onResume() {
super.onResume();
downloadDirPref.setSummary(preferences.getDownloadsDirectory());
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == DOWNLOAD_DIR_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
preferences.setDownloadsDirectory(uri.getPath());
// Persist access permissions.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
getActivity().getContentResolver().takePersistableUriPermission(uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION |
Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
}
}
}
public static class CustomLayoutPickerActivity extends FilePickerActivity {
@Override
protected AbstractFilePickerFragment<File> getFragment(
String startPath, int mode, boolean allowMultiple, boolean allowCreateDir) {
AbstractFilePickerFragment<File> fragment = new CustomLayoutFilePickerFragment();
fragment.setArgs(startPath, mode, allowMultiple, allowCreateDir);
return fragment;
}
}
public static class CustomLayoutFilePickerFragment extends FilePickerFragment {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
switch (viewType) {
case LogicHandler.VIEWTYPE_DIR:
v = LayoutInflater.from(getActivity()).inflate(R.layout.listitem_dir,
parent, false);
return new DirViewHolder(v);
default:
return super.onCreateViewHolder(parent, viewType);
}
}
}
}

View file

@ -0,0 +1,78 @@
package eu.kanade.tachiyomi.ui.setting
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.support.v7.widget.RecyclerView
import android.view.View
import android.view.ViewGroup
import com.nononsenseapps.filepicker.AbstractFilePickerFragment
import com.nononsenseapps.filepicker.FilePickerActivity
import com.nononsenseapps.filepicker.FilePickerFragment
import com.nononsenseapps.filepicker.LogicHandler
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.inflate
import java.io.File
class SettingsDownloadsFragment : SettingsNestedFragment() {
val downloadDirPref by lazy { findPreference(getString(R.string.pref_download_directory_key)) }
companion object {
val DOWNLOAD_DIR_CODE = 103
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
val fragment = SettingsDownloadsFragment()
fragment.setArgs(resourcePreference, resourceTitle)
return fragment
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
downloadDirPref.setOnPreferenceClickListener { preference ->
val i = Intent(activity, CustomLayoutPickerActivity::class.java)
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE, false)
i.putExtra(FilePickerActivity.EXTRA_ALLOW_CREATE_DIR, true)
i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR)
i.putExtra(FilePickerActivity.EXTRA_START_PATH, preferences.downloadsDirectory)
startActivityForResult(i, DOWNLOAD_DIR_CODE)
true
}
}
override fun onResume() {
super.onResume()
downloadDirPref.summary = preferences.downloadsDirectory
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (data != null && requestCode == DOWNLOAD_DIR_CODE && resultCode == Activity.RESULT_OK) {
preferences.downloadsDirectory = data.data.path
}
}
class CustomLayoutPickerActivity : FilePickerActivity() {
override fun getFragment(startPath: String?, mode: Int, allowMultiple: Boolean, allowCreateDir: Boolean):
AbstractFilePickerFragment<File> {
val fragment = CustomLayoutFilePickerFragment()
fragment.setArgs(startPath, mode, allowMultiple, allowCreateDir)
return fragment
}
}
class CustomLayoutFilePickerFragment : FilePickerFragment() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (viewType) {
LogicHandler.VIEWTYPE_DIR -> {
val view = parent.inflate(R.layout.listitem_dir)
return DirViewHolder(view)
}
else -> return super.onCreateViewHolder(parent, viewType)
}
}
}
}

View file

@ -1,44 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
import eu.kanade.tachiyomi.data.library.LibraryUpdateAlarm;
import eu.kanade.tachiyomi.widget.preference.IntListPreference;
import eu.kanade.tachiyomi.widget.preference.LibraryColumnsDialog;
public class SettingsGeneralFragment extends SettingsNestedFragment {
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsGeneralFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
View view = super.onCreateView(inflater, container, savedState);
PreferencesHelper preferences = getSettingsActivity().preferences;
LibraryColumnsDialog columnsDialog = (LibraryColumnsDialog) findPreference(
getString(R.string.pref_library_columns_dialog_key));
columnsDialog.setPreferencesHelper(preferences);
IntListPreference updateInterval = (IntListPreference) findPreference(
getString(R.string.pref_library_update_interval_key));
updateInterval.setOnPreferenceChangeListener((preference, newValue) -> {
LibraryUpdateAlarm.startAlarm(getActivity(), Integer.parseInt((String) newValue));
return true;
});
return view;
}
}

View file

@ -0,0 +1,35 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.view.View
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.library.LibraryUpdateAlarm
import eu.kanade.tachiyomi.widget.preference.IntListPreference
import eu.kanade.tachiyomi.widget.preference.LibraryColumnsDialog
class SettingsGeneralFragment : SettingsNestedFragment() {
companion object {
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsGeneralFragment {
val fragment = SettingsGeneralFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val columnsDialog = findPreference(
getString(R.string.pref_library_columns_dialog_key)) as LibraryColumnsDialog
columnsDialog.setPreferencesHelper(preferences)
val updateInterval = findPreference(
getString(R.string.pref_library_update_interval_key)) as IntListPreference
updateInterval.setOnPreferenceChangeListener { preference, newValue ->
LibraryUpdateAlarm.startAlarm(activity, (newValue as String).toInt())
true
}
}
}

View file

@ -1,55 +0,0 @@
package eu.kanade.tachiyomi.ui.setting;
import android.os.Bundle;
import android.preference.PreferenceFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity;
public class SettingsNestedFragment extends PreferenceFragment {
protected PreferencesHelper preferences;
private static final String RESOURCE_FILE = "resource_file";
private static final String TOOLBAR_TITLE = "toolbar_title";
public static SettingsNestedFragment newInstance(int resourcePreference, int resourceTitle) {
SettingsNestedFragment fragment = new SettingsNestedFragment();
fragment.setArgs(resourcePreference, resourceTitle);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(getArguments().getInt(RESOURCE_FILE));
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
preferences = getSettingsActivity().preferences;
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
((BaseActivity) getActivity())
.setToolbarTitle(getString(getArguments().getInt(TOOLBAR_TITLE)));
}
public void setArgs(int resourcePreference, int resourceTitle) {
Bundle args = new Bundle();
args.putInt(RESOURCE_FILE, resourcePreference);
args.putInt(TOOLBAR_TITLE, resourceTitle);
setArguments(args);
}
public SettingsActivity getSettingsActivity() {
return (SettingsActivity) getActivity();
}
}

View file

@ -0,0 +1,44 @@
package eu.kanade.tachiyomi.ui.setting
import android.os.Bundle
import android.preference.PreferenceFragment
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
open class SettingsNestedFragment : PreferenceFragment() {
companion object {
private val RESOURCE_FILE = "resource_file"
private val TOOLBAR_TITLE = "toolbar_title"
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
val fragment = SettingsNestedFragment()
fragment.setArgs(resourcePreference, resourceTitle)
return fragment
}
}
override fun onCreate(savedState: Bundle?) {
super.onCreate(savedState)
addPreferencesFromResource(arguments.getInt(RESOURCE_FILE))
}
override fun onResume() {
super.onResume()
settingsActivity.setToolbarTitle(getString(arguments.getInt(TOOLBAR_TITLE)))
}
fun setArgs(resourcePreference: Int, resourceTitle: Int) {
val args = Bundle()
args.putInt(RESOURCE_FILE, resourcePreference)
args.putInt(TOOLBAR_TITLE, resourceTitle)
arguments = args
}
val settingsActivity: SettingsActivity
get() = activity as SettingsActivity
val preferences: PreferencesHelper
get() = settingsActivity.preferences
}