diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..b1b9eb9a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +# editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/README.md b/README.md index 5309aa4a..c16aef7c 100644 --- a/README.md +++ b/README.md @@ -1,89 +1,122 @@ Transdroid ========== -[www.transdroid.org](http://www.transdroid.org) +[www.transdroid.org](https://www.transdroid.org/) [Twitter](https://twitter.com/transdroid) - [transdroid@2312.nl](transdroid@2312.nl) -"Manage your torrents from your Android device" - - -Get it on transdroid.org - -Get it on F-Droid - -Get it on Google Play - -Screen shot of the main torrents listing screen - - -Manage your torrents from your Android device with Transdroid. All popular clients are supported: µTorrent, Transmission, rTorrent, Vuze, Deluge, BitTorrent 6, qBittorrent and many more. You can view and manage the running torrents and individual files. Adding is easy via the integrated search or RSS feeds (full version required). Monitor progress using the home screen widget or background alarm service. +Manage torrents from your Android device. + + + Get it on transdroid.org + + + Get it on F-Droid + + + Get it on Google Play + + +Screen shot of the main torrents listing screen + + +Manage your torrents from your Android device with Transdroid. +All popular clients are supported: µTorrent, Transmission, rTorrent, Vuze, Deluge, BitTorrent 6, qBittorrent, and many more. +You can view and manage running torrents and individual files. +Adding is easy via the integrated search or RSS feeds (full version required). +Monitor progress using the home screen widget or background alarm service. Contributions ============= -Code and design contributions are very welcome. You might want to contact me via social networks (G+, Twitter) or e-mail first. Please note all code will be GNU GPL v3 licensed. +Code and design contributions are very welcome. +You might want to contact me via social networks (Twitter) or e-mail first. +Please note that all code will be licensed in GNU GPLv3. -Please respect the coding standards for easier merging. master contains the current release version of Transdroid while dev contains the active development version. However, larger, new features are developed in their own branch. +Please respect the coding standards for easier merging. +`master` contains the current release version of Transdroid while `dev` contains the active development version. +However, larger and new features will be developed in their own branch. Code structure ============== -Starting with version 2.3.0, Transdroid is developed in Android Studio, fully integrating with the Gradle build system. It is (since version 2.5.0) compiled against Android 5.1 (API level 22) and (since version 2.2.0) supporting ICS (API level 15) and up only. To support lite (Transdrone, specially for the Play Store) and full (Transdroid) versions of the app, build flavours are defined in gradle, which contain version-specific resources. Dependencies are managed via JCentral et al. in the app's build.gradle file. +Starting with version 2.3.0, Transdroid is developed in Android Studio, fully integrating with the Gradle build system. +It is (since version 2.5.18) compiled against Android 10 (API level 29) and (since version 2.2.0) supporting Android ICS (API level 15) and up only. +To support lite (Transdrone, specially for the Play Store) and full (Transdroid) versions of the app, build flavours are defined in gradle, which contain version-specific resources. +Dependencies are managed via JCentral et al. in the app's build.gradle file. Developed By ============ -Designed and developed by [Eric Kok](eric@2312.nl) of [2312 development](http://2312.nl). Contributions by various others (see commit log). +Designed and developed by [Eric Kok](eric@2312.nl) of [2312 development](https://2312.nl/). +Contributions by various others (see commit log). License ======= - - Copyright 2010-2018 Eric Kok et al. - + + Copyright 2010-2020 Eric Kok et al. + Transdroid 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. - + Transdroid 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 Transdroid. If not, see . - -Some code/libraries/resources are used in the project: + along with Transdroid. If not, see . -* [AndroidAnnotations](http://androidannotations.org/) - Pierre-Yves Ricau (eBusinessInformations) et al. +Some code/libraries/resources are used in the project: +* [Android Jetpack (AndroidX)](https://developer.android.com/jetpack) + The Android Open Source Project Apache License, Version 2.0 -* [ActionBar-PullToRefresh](https://github.com/chrisbanes/ActionBar-PullToRefresh) - Chris Banes +* [AndroidAnnotations](http://androidannotations.org/) + Pierre-Yves Ricau (eBusinessInformations) et al. Apache License, Version 2.0 -* [Crouton](https://github.com/keyboardsurfer/Crouton) - Code: Benjamin Weiss (Neofonie Mobile Gmbh) et al. - Idea: Cyril Mottier +* [ORMLite](https://github.com/j256/ormlite-core) and [ORMLite Android](https://github.com/j256/ormlite-android) + Gray Watson + ISC License +* [Android Universal Image Loader](https://github.com/nostra13/Android-Universal-Image-Loader) + Sergey Tarasevich Apache License, Version 2.0 -* [Base16Encoder](http://openjpa.apache.org/) - Marc Prud'hommeaux - Apache OpenJPA -* MultipartEntity - Apache Software Foundation +* [FloatingActionButton](https://github.com/zendesk/android-floating-action-button) + Oleksandr Melnykov, Zendesk Apache License, Version 2.0 -* RssParser ([learning-android](http://github.com/digitalspaghetti/learning-android)) - Tane Piper - Public Domain -* [Base64](http://iharder.net/base64) - Robert Harder +* [Snackbar](https://github.com/nispok/snackbar) + William Mora + MIT License +* [Java implementation of Rencode](https://github.com/aegnor/rencode-java) + Daniel Dimovski + MIT License +* [OpenJPA's Base16Encoder](https://github.com/apache/openjpa) + Marc Prud'hommeaux + Apache OpenJPA +* [Base64](http://iharder.sourceforge.net/current/java/base64/) + Robert Harder Public Domain -* [aXMLRPC](https://github.com/timroes/aXMLRPC) - Tim Roes +* [aXMLRPC](https://github.com/gturri/aXMLRPC) + Tim Roes MIT License -* [android-ColorPickerPreference](https://github.com/attenzione/android-ColorPickerPreference) - Daniel Nilsson and Sergey Margaritov +* [Material Dialogs](https://github.com/afollestad/material-dialogs) + Aidan Follestad Apache License, Version 2.0 -* [Funnel icon](http://thenounproject.com/noun/funnel/#icon-No5608) - Naomi Atkinson from The Noun Project +* [Android-Job](https://github.com/evernote/android-job) + Evernote Corporation + Apache License, Version 2.0 +* [android-ColorPickerPreference](https://github.com/attenzione/android-ColorPickerPreference) + Daniel Nilsson and Sergey Margaritov + Apache License, Version 2.0 +* RssParser ([learning-android](https://github.com/tanepiper/learning-android)) + Tane Piper + Public Domain +* [Funnel icon](https://thenounproject.com/term/funnel/5608/) + Naomi Atkinson from The Noun Project Creative Commons Attribution 3.0 - diff --git a/app/build.gradle b/app/build.gradle index ce166215..3e302185 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,7 +79,7 @@ dependencies { // Android support implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.preference:preference:1.1.1' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' + implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'com.google.android.material:material:1.1.0' // Other diff --git a/app/src/full/res/values/bools.xml b/app/src/full/res/values/bools.xml index 427a2c88..68b5601f 100644 --- a/app/src/full/res/values/bools.xml +++ b/app/src/full/res/values/bools.xml @@ -1,29 +1,28 @@ - - - - true - - true - - true - - true + + true + + true + + true + + true diff --git a/app/src/full/res/values/strings.xml b/app/src/full/res/values/strings.xml index d50334ce..9ac8c21e 100644 --- a/app/src/full/res/values/strings.xml +++ b/app/src/full/res/values/strings.xml @@ -1,24 +1,24 @@ - Transdroid + Transdroid - Donate with PayPal - https://paypal.me/erickoknl + Donate with PayPal + https://paypal.me/erickoknl diff --git a/app/src/lite/res/values/bools.xml b/app/src/lite/res/values/bools.xml index be7fce50..389bb1d6 100644 --- a/app/src/lite/res/values/bools.xml +++ b/app/src/lite/res/values/bools.xml @@ -1,29 +1,28 @@ - - - - false - - false - - false - - true + + false + + false + + false + + true diff --git a/app/src/lite/res/values/strings.xml b/app/src/lite/res/values/strings.xml index 36912a08..631a0965 100644 --- a/app/src/lite/res/values/strings.xml +++ b/app/src/lite/res/values/strings.xml @@ -1,24 +1,24 @@ - Transdrone + Transdrone - - + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1fae5479..2873ea14 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,333 +1,331 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xmlns:tools="http://schemas.android.com/tools" + package="org.transdroid"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/androidx/preference/PreferenceManagerBinder.java b/app/src/main/java/androidx/preference/PreferenceManagerBinder.java index 63457113..0b5e962f 100644 --- a/app/src/main/java/androidx/preference/PreferenceManagerBinder.java +++ b/app/src/main/java/androidx/preference/PreferenceManagerBinder.java @@ -5,7 +5,8 @@ package androidx.preference; * around the protected visibility of {@link Preference#onAttachedToHierarchy(PreferenceManager)}. */ public class PreferenceManagerBinder { - private PreferenceManagerBinder() {} + private PreferenceManagerBinder() { + } public static void bind(Preference pref, PreferenceManager manager) { pref.onAttachedToHierarchy(manager); diff --git a/app/src/main/java/org/transdroid/core/app/search/SearchHelper.java b/app/src/main/java/org/transdroid/core/app/search/SearchHelper.java index fea93f02..9e381185 100644 --- a/app/src/main/java/org/transdroid/core/app/search/SearchHelper.java +++ b/app/src/main/java/org/transdroid/core/app/search/SearchHelper.java @@ -1,21 +1,30 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ package org.transdroid.core.app.search; +import android.content.ContentProviderClient; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; + +import org.androidannotations.annotations.EBean; +import org.androidannotations.annotations.EBean.Scope; +import org.androidannotations.annotations.RootContext; + import java.io.FileNotFoundException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -23,146 +32,141 @@ import java.net.URLEncoder; import java.util.ArrayList; import java.util.List; -import org.androidannotations.annotations.EBean; -import org.androidannotations.annotations.EBean.Scope; -import org.androidannotations.annotations.RootContext; - -import android.content.ContentProviderClient; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; - @EBean(scope = Scope.Singleton) public class SearchHelper { - static final int CURSOR_SEARCH_ID = 0; - static final int CURSOR_SEARCH_NAME = 1; - static final int CURSOR_SEARCH_TORRENTURL = 2; - static final int CURSOR_SEARCH_DETAILSURL = 3; - static final int CURSOR_SEARCH_SIZE = 4; - static final int CURSOR_SEARCH_ADDED = 5; - static final int CURSOR_SEARCH_SEEDERS = 6; - static final int CURSOR_SEARCH_LEECHERS = 7; - - static final int CURSOR_SITE_ID = 0; - static final int CURSOR_SITE_CODE = 1; - static final int CURSOR_SITE_NAME = 2; - static final int CURSOR_SITE_RSSURL = 3; - static final int CURSOR_SITE_ISPRIVATE = 4; - - @RootContext - protected Context context; - - public enum SearchSortOrder { - Combined, BySeeders - } - - /** - * Return whether the Torrent Search package is installed and available to query against - * @return True if the available sites can be retrieved from the content provider, false otherwise - */ - public boolean isTorrentSearchInstalled() { - return getAvailableSites() != null; - } - - /** - * Queries the Torrent Search package for all available in-app search sites. This method is synchronous. - * @return A list of available search sites as POJOs, or null if the Torrent Search package is not installed - */ - public List getAvailableSites() { - - // Try to access the TorrentSitesProvider of the Torrent Search app - Uri uri = Uri.parse("content://org.transdroid.search.torrentsitesprovider/sites"); - ContentProviderClient test = context.getContentResolver().acquireContentProviderClient(uri); - if (test == null) { - // Torrent Search package is not yet installed - return null; - } - - // Query the available in-app torrent search sites - Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); - if (cursor == null) { - // The installed Torrent Search version is corrupt or incompatible - return null; - } - List sites = new ArrayList<>(); - if (cursor.moveToFirst()) { - do { - // Read the cursor fields into the SearchSite object - sites.add(new SearchSite(cursor.getInt(CURSOR_SITE_ID), cursor.getString(CURSOR_SITE_CODE), cursor - .getString(CURSOR_SITE_NAME), cursor.getString(CURSOR_SITE_RSSURL), - cursor.getColumnNames().length > 4 && cursor.getInt(CURSOR_SITE_ISPRIVATE) == 1)); - } while (cursor.moveToNext()); - } - - cursor.close(); - return sites; - - } - - /** - * Queries the Torrent Search module to search for torrents on the web. This method is synchronous and should always - * be called in a background thread. - * @param query The search query to pass to the torrent site - * @param site The site to search, as retrieved from the TorrentSitesProvider, or null if the Torrent Search package - * @param sortBy The sort order to request from the torrent site, if supported - * @return A list of torrent search results as POJOs, or null if the Torrent Search package is not installed or - * there is no internet connection - */ - public ArrayList search(String query, SearchSite site, SearchSortOrder sortBy) { - - // Try to query the TorrentSearchProvider to search for torrents on the web - Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/search/" + query); - Cursor cursor; - if (site == null) { - // If no explicit site was supplied, rely on the Torrent Search package's default - cursor = context.getContentResolver().query(uri, null, null, null, sortBy.name()); - } else { - cursor = context.getContentResolver().query(uri, null, "SITE = ?", new String[] { site.getKey() }, - sortBy.name()); - } - if (cursor == null) { - // The content provider could not load any content (for example when there is no connection) - return null; - } - if (cursor.moveToFirst()) { - ArrayList results = new ArrayList<>(); - do { - // Read the cursor fields into the SearchResult object - results.add(new SearchResult(cursor.getInt(CURSOR_SEARCH_ID), cursor.getString(CURSOR_SEARCH_NAME), - cursor.getString(CURSOR_SEARCH_TORRENTURL), cursor.getString(CURSOR_SEARCH_DETAILSURL), cursor - .getString(CURSOR_SEARCH_SIZE), cursor.getLong(CURSOR_SEARCH_ADDED), cursor - .getString(CURSOR_SEARCH_SEEDERS), cursor.getString(CURSOR_SEARCH_LEECHERS))); - } while (cursor.moveToNext()); - cursor.close(); - return results; - } - - // Torrent Search package is not yet installed - cursor.close(); - return null; - - } - - /** - * Asks the Torrent Search module to download a torrent file given the provided url, while using the specifics of - * the supplied torrent search site to do so. This way the Search Module can take care of user credentials, for - * example. - * @param site The unique key of the search site that this url belongs to, which is used to create a connection - * specific to this (private) site - * @param url The full url of the torrent to download - * @return A file input stream handler that points to the locally downloaded file - * @throws FileNotFoundException Thrown when the requested url could not be downloaded or is not locally available - */ - public InputStream getFile(String site, String url) throws FileNotFoundException { - try { - Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/get/" + site + "/" - + URLEncoder.encode(url, "UTF-8")); - return context.getContentResolver().openInputStream(uri); - } catch (UnsupportedEncodingException e) { - // Ignore - return null; - } - } + static final int CURSOR_SEARCH_ID = 0; + static final int CURSOR_SEARCH_NAME = 1; + static final int CURSOR_SEARCH_TORRENTURL = 2; + static final int CURSOR_SEARCH_DETAILSURL = 3; + static final int CURSOR_SEARCH_SIZE = 4; + static final int CURSOR_SEARCH_ADDED = 5; + static final int CURSOR_SEARCH_SEEDERS = 6; + static final int CURSOR_SEARCH_LEECHERS = 7; + + static final int CURSOR_SITE_ID = 0; + static final int CURSOR_SITE_CODE = 1; + static final int CURSOR_SITE_NAME = 2; + static final int CURSOR_SITE_RSSURL = 3; + static final int CURSOR_SITE_ISPRIVATE = 4; + + @RootContext + protected Context context; + + /** + * Return whether the Torrent Search package is installed and available to query against + * + * @return True if the available sites can be retrieved from the content provider, false otherwise + */ + public boolean isTorrentSearchInstalled() { + return getAvailableSites() != null; + } + + /** + * Queries the Torrent Search package for all available in-app search sites. This method is synchronous. + * + * @return A list of available search sites as POJOs, or null if the Torrent Search package is not installed + */ + public List getAvailableSites() { + + // Try to access the TorrentSitesProvider of the Torrent Search app + Uri uri = Uri.parse("content://org.transdroid.search.torrentsitesprovider/sites"); + ContentProviderClient test = context.getContentResolver().acquireContentProviderClient(uri); + if (test == null) { + // Torrent Search package is not yet installed + return null; + } + + // Query the available in-app torrent search sites + Cursor cursor = context.getContentResolver().query(uri, null, null, null, null); + if (cursor == null) { + // The installed Torrent Search version is corrupt or incompatible + return null; + } + List sites = new ArrayList<>(); + if (cursor.moveToFirst()) { + do { + // Read the cursor fields into the SearchSite object + sites.add(new SearchSite(cursor.getInt(CURSOR_SITE_ID), cursor.getString(CURSOR_SITE_CODE), cursor + .getString(CURSOR_SITE_NAME), cursor.getString(CURSOR_SITE_RSSURL), + cursor.getColumnNames().length > 4 && cursor.getInt(CURSOR_SITE_ISPRIVATE) == 1)); + } while (cursor.moveToNext()); + } + + cursor.close(); + return sites; + + } + + /** + * Queries the Torrent Search module to search for torrents on the web. This method is synchronous and should always + * be called in a background thread. + * + * @param query The search query to pass to the torrent site + * @param site The site to search, as retrieved from the TorrentSitesProvider, or null if the Torrent Search package + * @param sortBy The sort order to request from the torrent site, if supported + * @return A list of torrent search results as POJOs, or null if the Torrent Search package is not installed or + * there is no internet connection + */ + public ArrayList search(String query, SearchSite site, SearchSortOrder sortBy) { + + // Try to query the TorrentSearchProvider to search for torrents on the web + Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/search/" + query); + Cursor cursor; + if (site == null) { + // If no explicit site was supplied, rely on the Torrent Search package's default + cursor = context.getContentResolver().query(uri, null, null, null, sortBy.name()); + } else { + cursor = context.getContentResolver().query(uri, null, "SITE = ?", new String[]{site.getKey()}, + sortBy.name()); + } + if (cursor == null) { + // The content provider could not load any content (for example when there is no connection) + return null; + } + if (cursor.moveToFirst()) { + ArrayList results = new ArrayList<>(); + do { + // Read the cursor fields into the SearchResult object + results.add(new SearchResult(cursor.getInt(CURSOR_SEARCH_ID), cursor.getString(CURSOR_SEARCH_NAME), + cursor.getString(CURSOR_SEARCH_TORRENTURL), cursor.getString(CURSOR_SEARCH_DETAILSURL), cursor + .getString(CURSOR_SEARCH_SIZE), cursor.getLong(CURSOR_SEARCH_ADDED), cursor + .getString(CURSOR_SEARCH_SEEDERS), cursor.getString(CURSOR_SEARCH_LEECHERS))); + } while (cursor.moveToNext()); + cursor.close(); + return results; + } + + // Torrent Search package is not yet installed + cursor.close(); + return null; + + } + + /** + * Asks the Torrent Search module to download a torrent file given the provided url, while using the specifics of + * the supplied torrent search site to do so. This way the Search Module can take care of user credentials, for + * example. + * + * @param site The unique key of the search site that this url belongs to, which is used to create a connection + * specific to this (private) site + * @param url The full url of the torrent to download + * @return A file input stream handler that points to the locally downloaded file + * @throws FileNotFoundException Thrown when the requested url could not be downloaded or is not locally available + */ + public InputStream getFile(String site, String url) throws FileNotFoundException { + try { + Uri uri = Uri.parse("content://org.transdroid.search.torrentsearchprovider/get/" + site + "/" + + URLEncoder.encode(url, "UTF-8")); + return context.getContentResolver().openInputStream(uri); + } catch (UnsupportedEncodingException e) { + // Ignore + return null; + } + } + + public enum SearchSortOrder { + Combined, BySeeders + } } diff --git a/app/src/main/java/org/transdroid/core/app/search/SearchResult.java b/app/src/main/java/org/transdroid/core/app/search/SearchResult.java index ba54524f..49b2144e 100644 --- a/app/src/main/java/org/transdroid/core/app/search/SearchResult.java +++ b/app/src/main/java/org/transdroid/core/app/search/SearchResult.java @@ -1,122 +1,122 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ package org.transdroid.core.app.search; -import java.util.Date; - import android.os.Parcel; import android.os.Parcelable; +import java.util.Date; + /** * Represents a search result as retrieved by querying the Torrent Search package. + * * @author Eric Kok */ public class SearchResult implements Parcelable { - private final int id; - private final String name; - private final String torrentUrl; - private final String detailsUrl; - private final String size; - private final Date addedOn; - private final String seeders; - private final String leechers; - - public SearchResult(int id, String name, String torrentUrl, String detailsUrl, String size, long addedOnTime, - String seeders, String leechers) { - this.id = id; - this.name = name; - this.torrentUrl = torrentUrl; - this.detailsUrl = detailsUrl; - this.size = size; - this.addedOn = (addedOnTime == -1L) ? null : new Date(addedOnTime); - this.seeders = seeders; - this.leechers = leechers; - } - - public int getId() { - return id; - } - - public String getName() { - return name; - } - - public String getTorrentUrl() { - return torrentUrl; - } - - public String getDetailsUrl() { - return detailsUrl; - } - - public String getSize() { - return size; - } - - public Date getAddedOn() { - return addedOn; - } - - public String getSeeders() { - return seeders; - } - - public String getLeechers() { - return leechers; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeInt(id); - out.writeString(name); - out.writeString(torrentUrl); - out.writeString(detailsUrl); - out.writeString(size); - out.writeLong(addedOn == null ? -1 : addedOn.getTime()); - out.writeString(seeders); - out.writeString(leechers); - } - - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public SearchResult createFromParcel(Parcel in) { - return new SearchResult(in); - } - - public SearchResult[] newArray(int size) { - return new SearchResult[size]; - } - }; - - public SearchResult(Parcel in) { - id = in.readInt(); - name = in.readString(); - torrentUrl = in.readString(); - detailsUrl = in.readString(); - size = in.readString(); - long addedOnIn = in.readLong(); - addedOn = addedOnIn == -1 ? null : new Date(addedOnIn); - seeders = in.readString(); - leechers = in.readString(); - } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public SearchResult createFromParcel(Parcel in) { + return new SearchResult(in); + } + + public SearchResult[] newArray(int size) { + return new SearchResult[size]; + } + }; + private final int id; + private final String name; + private final String torrentUrl; + private final String detailsUrl; + private final String size; + private final Date addedOn; + private final String seeders; + private final String leechers; + + public SearchResult(int id, String name, String torrentUrl, String detailsUrl, String size, long addedOnTime, + String seeders, String leechers) { + this.id = id; + this.name = name; + this.torrentUrl = torrentUrl; + this.detailsUrl = detailsUrl; + this.size = size; + this.addedOn = (addedOnTime == -1L) ? null : new Date(addedOnTime); + this.seeders = seeders; + this.leechers = leechers; + } + + public SearchResult(Parcel in) { + id = in.readInt(); + name = in.readString(); + torrentUrl = in.readString(); + detailsUrl = in.readString(); + size = in.readString(); + long addedOnIn = in.readLong(); + addedOn = addedOnIn == -1 ? null : new Date(addedOnIn); + seeders = in.readString(); + leechers = in.readString(); + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public String getTorrentUrl() { + return torrentUrl; + } + + public String getDetailsUrl() { + return detailsUrl; + } + + public String getSize() { + return size; + } + + public Date getAddedOn() { + return addedOn; + } + + public String getSeeders() { + return seeders; + } + + public String getLeechers() { + return leechers; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(id); + out.writeString(name); + out.writeString(torrentUrl); + out.writeString(detailsUrl); + out.writeString(size); + out.writeLong(addedOn == null ? -1 : addedOn.getTime()); + out.writeString(seeders); + out.writeString(leechers); + } } diff --git a/app/src/main/java/org/transdroid/core/app/search/SearchSite.java b/app/src/main/java/org/transdroid/core/app/search/SearchSite.java index bd7f02fb..cd21db43 100644 --- a/app/src/main/java/org/transdroid/core/app/search/SearchSite.java +++ b/app/src/main/java/org/transdroid/core/app/search/SearchSite.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -21,48 +21,49 @@ import org.transdroid.core.gui.search.SearchSetting; /** * Represents an available torrent site that can be searched using the Torrent Search package. + * * @author Eric Kok */ public class SearchSite implements SimpleListItem, SearchSetting { - private final int id; - private final String key; - private final String name; - private final String rssFeedUrl; - private final boolean isPrivate; - - public SearchSite(int id, String key, String name, String rssFeedUrl, boolean isPrivate) { - this.id = id; - this.key = key; - this.name = name; - this.rssFeedUrl = rssFeedUrl; - this.isPrivate = isPrivate; - } + private final int id; + private final String key; + private final String name; + private final String rssFeedUrl; + private final boolean isPrivate; - public int getId() { - return id; - } + public SearchSite(int id, String key, String name, String rssFeedUrl, boolean isPrivate) { + this.id = id; + this.key = key; + this.name = name; + this.rssFeedUrl = rssFeedUrl; + this.isPrivate = isPrivate; + } - public String getKey() { - return key; - } + public int getId() { + return id; + } - @Override - public String getName() { - return name; - } + public String getKey() { + return key; + } - public String getRssFeedUrl() { - return rssFeedUrl; - } + @Override + public String getName() { + return name; + } - @Override - public String getBaseUrl() { - return rssFeedUrl; - } + public String getRssFeedUrl() { + return rssFeedUrl; + } + + @Override + public String getBaseUrl() { + return rssFeedUrl; + } + + public boolean isPrivate() { + return isPrivate; + } - public boolean isPrivate() { - return isPrivate; - } - } diff --git a/app/src/main/java/org/transdroid/core/app/settings/ApplicationSettings.java b/app/src/main/java/org/transdroid/core/app/settings/ApplicationSettings.java index 9fe56f30..7c0bc0a0 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/ApplicationSettings.java +++ b/app/src/main/java/org/transdroid/core/app/settings/ApplicationSettings.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -49,724 +49,763 @@ import java.util.List; /** * Singleton object to access all application settings, including stored servers, web search sites and RSS feeds. + * * @author Eric Kok */ @EBean(scope = Scope.Singleton) public class ApplicationSettings { - public static final int DEFAULTSERVER_LASTUSED = -2; - public static final int DEFAULTSERVER_ASKONADD = -1; - - @RootContext - protected Context context; - private SharedPreferences prefs; - @Bean - protected SearchHelper searchHelper; - - protected ApplicationSettings(Context context) { - prefs = PreferenceManager.getDefaultSharedPreferences(context); - } - - /** - * Returns all available user-configured normal and seed servers - * @return A list of all stored server settings objects - */ - public List getAllServerSettings() { - List all = new ArrayList<>(); - all.addAll(getNormalServerSettings()); - for (SeedboxProvider provider : SeedboxProvider.values()) { - all.addAll(provider.getSettings().getAllServerSettings(prefs, all.size())); - } - return all; - } - - /** - * Returns the order number/identifying key of the last server, normal or seedbox configured - * @return The zero-based order number (index) of the last stored server settings - */ - public int getMaxOfAllServers() { - int max = getMaxNormalServer(); - for (SeedboxProvider provider : SeedboxProvider.values()) { - max += provider.getSettings().getMaxSeedboxOrder(prefs) + 1; - } - return max; - } - - /** - * Returns the server settings for either a normal or a seedbox server as the user configured. WARNING: This method - * does not check if the settings actually exist and may reply on empty default if called for a non-existing server. - * @param order The order number/identifying key of the server's settings to retrieve, where the normal servers are - * first and the seedboxes are numbers thereafter onwards - * @return The server settings object, loaded from shared preferences - */ - public ServerSetting getServerSetting(int order) { - int max = getMaxNormalServer() + 1; - if (order < max) { - return getNormalServerSetting(order); - } - for (SeedboxProvider provider : SeedboxProvider.values()) { - int offset = max; - max += provider.getSettings().getMaxSeedboxOrder(prefs) + 1; - if (order < max) { - return provider.getSettings().getServerSetting(prefs, offset, order - offset); - } - } - return null; - } - - /** - * Returns all available normal, user-configured servers (so no seedbox settings) - * @return A list of all stored server settings objects - */ - public List getNormalServerSettings() { - List servers = new ArrayList<>(); - for (int i = 0; i <= getMaxNormalServer(); i++) { - servers.add(getNormalServerSetting(i)); - } - return Collections.unmodifiableList(servers); - } - - /** - * Returns the order number/identifying key of the last normal server - * @return The zero-based order number (index) of the last stored normal server settings - */ - public int getMaxNormalServer() { - for (int i = 0; true; i++) { - if (prefs.getString("server_type_" + i, null) == null || prefs.getString("server_address_" + i, null) == null) - return i - 1; - } - } - - /** - * Returns the user-specified server settings for a normal (non-seedbox) server. WARNING: This method does not check - * if the settings actually exist and may rely on empty defaults if called for a non-existing server. - * @param order The order number/identifying key of the normal server's settings to retrieve - * @return The server settings object, loaded from shared preferences - */ - public ServerSetting getNormalServerSetting(int order) { - // @formatter:off - Daemon type = Daemon.fromCode(prefs.getString("server_type_" + order, null)); - boolean ssl = prefs.getBoolean("server_sslenabled_" + order, false); - boolean localSsl = prefs.getBoolean("server_localsslenabled_" + order, ssl); - - String port = prefs.getString("server_port_" + order, null); - if (TextUtils.isEmpty(port)) - port = Integer.toString(Daemon.getDefaultPortNumber(type, ssl)); - String localPort = prefs.getString("server_localport_" + order, null); - if (TextUtils.isEmpty(localPort)) - localPort = port; // Default to the normal (non-local) port - try { - parseInt(port, Daemon.getDefaultPortNumber(type, ssl)); - } catch (NumberFormatException e) { - port = Integer.toString(Daemon.getDefaultPortNumber(type, ssl)); - } - try { - parseInt(localPort, parseInt(port, Daemon.getDefaultPortNumber(type, ssl))); - } catch (NumberFormatException e) { - localPort = port; - } - - return new ServerSetting(order, - prefs.getString("server_name_" + order, null), - type, - trim(prefs.getString("server_address_" + order, null)), - trim(prefs.getString("server_localaddress_" + order, null)), - parseInt(localPort, parseInt(port, Daemon.getDefaultPortNumber(type, ssl))), - prefs.getString("server_localnetwork_" + order, null), - parseInt(port, Daemon.getDefaultPortNumber(type, ssl)), - ssl, localSsl, - prefs.getBoolean("server_ssltrustall_" + order, false), - prefs.getString("server_ssltrustkey_" + order, null), - prefs.getString("server_folder_" + order, null), - !prefs.getBoolean("server_disableauth_" + order, false), - prefs.getString("server_user_" + order, null), - prefs.getString("server_pass_" + order, null), - prefs.getString("server_extrapass_" + order, null), - OS.fromCode(prefs.getString("server_os_" + order, "type_linux")), - prefs.getString("server_downloaddir_" + order, null), - prefs.getString("server_ftpurl_" + order, null), - prefs.getString("server_ftppass_" + order, null), - parseInt(prefs.getString("server_timeout_" + order, "8"), 8), - prefs.getBoolean("server_alarmfinished_" + order, true), - prefs.getBoolean("server_alarmnew_" + order, false), - prefs.getString("server_alarmexclude_" + order, null), - prefs.getString("server_alarminclude_" + order, null), - false); - // @formatter:on - } - - /** - * Removes all settings related to a configured server. Since servers are ordered, the order of the remaining - * servers will be updated accordingly. - * @param order The identifying order number/key of the settings to remove - */ - public void removeNormalServerSettings(int order) { - if (prefs.getString("server_type_" + order, null) == null) - return; // The settings that were requested to be removed do not exist - - // Copy all settings higher than the supplied order number to the previous spot - Editor edit = prefs.edit(); - int max = getMaxNormalServer(); - for (int i = order; i < max; i++) { - edit.putString("server_name_" + i, prefs.getString("server_name_" + (i + 1), null)); - edit.putString("server_type_" + i, prefs.getString("server_type_" + (i + 1), null)); - edit.putString("server_address_" + i, prefs.getString("server_address_" + (i + 1), null)); - edit.putString("server_localaddress_" + i, prefs.getString("server_localaddress_" + (i + 1), null)); - edit.putString("server_localnetwork_" + i, prefs.getString("server_localnetwork_" + (i + 1), null)); - edit.putString("server_port_" + i, prefs.getString("server_port_" + (i + 1), null)); - edit.putBoolean("server_sslenabled_" + i, prefs.getBoolean("server_sslenabled_" + (i + 1), false)); - edit.putBoolean("server_localsslenabled_" + i, prefs.getBoolean("server_localsslenabled_" + (i + 1), false)); - edit.putBoolean("server_ssltrustall_" + i, prefs.getBoolean("server_ssltrustall_" + (i + 1), false)); - edit.putString("server_ssltrustkey_" + i, prefs.getString("server_ssltrustkey_" + (i + 1), null)); - edit.putString("server_folder_" + i, prefs.getString("server_folder_" + (i + 1), null)); - edit.putBoolean("server_disableauth_" + i, prefs.getBoolean("server_disableauth_" + (i + 1), false)); - edit.putString("server_user_" + i, prefs.getString("server_user_" + (i + 1), null)); - edit.putString("server_pass_" + i, prefs.getString("server_pass_" + (i + 1), null)); - edit.putString("server_extrapass_" + i, prefs.getString("server_extrapass_" + (i + 1), null)); - edit.putString("server_os_" + i, prefs.getString("server_os_" + (i + 1), null)); - edit.putString("server_downloaddir_" + i, prefs.getString("server_downloaddir_" + (i + 1), null)); - edit.putString("server_ftpurl_" + i, prefs.getString("server_ftpurl_" + (i + 1), null)); - edit.putString("server_ftppass_" + i, prefs.getString("server_ftppass_" + (i + 1), null)); - edit.putString("server_timeout_" + i, prefs.getString("server_timeout_" + (i + 1), null)); - edit.putBoolean("server_alarmfinished_" + i, prefs.getBoolean("server_alarmfinished_" + (i + 1), true)); - edit.putBoolean("server_alarmfinished_" + i, prefs.getBoolean("server_alarmfinished_" + (i + 1), false)); - } - - // Remove the last settings, of which we are now sure are no longer required - edit.remove("server_name_" + max); - edit.remove("server_type_" + max); - edit.remove("server_address_" + max); - edit.remove("server_localaddress_" + max); - edit.remove("server_localnetwork_" + max); - edit.remove("server_port_" + max); - edit.remove("server_sslenabled_" + max); - edit.remove("server_localsslenabled_" + max); - edit.remove("server_ssltrustall_" + max); - edit.remove("server_ssltrustkey_" + max); - edit.remove("server_folder_" + max); - edit.remove("server_disableauth_" + max); - edit.remove("server_user_" + max); - edit.remove("server_pass_" + max); - edit.remove("server_extrapass_" + max); - edit.remove("server_os_" + max); - edit.remove("server_downloaddir_" + max); - edit.remove("server_ftpurl_" + max); - edit.remove("server_ftppass_" + max); - edit.remove("server_timeout_" + max); - edit.remove("server_alarmfinished_" + max); - edit.remove("server_alarmfinished_" + max); - - // Perhaps we should also update the default server to match the server's new id or remove the default selection - // in case it was this server that was removed - int defaultServer = getDefaultServerKey(); - if (defaultServer == order) { - edit.remove("header_defaultserver"); - } else if (defaultServer > order) { - // Move 'up' one place to account for the removed server setting - edit.putString("header_defaultserver", String.valueOf(--order)); - } - - edit.apply(); - - } - - /** - * Returns the settings of the server that was explicitly selected by the user to select as default or, when no - * specific default server was selected, the last used server settings. As opposed to getDefaultServerKey(int), this - * method checks whether the particular server still exists (and returns the first server if not). If no servers are - * configured, null is returned. - * @return A server settings object of the server to use by default, or null if no server is yet configured - */ - public ServerSetting getDefaultServer() { - - int defaultServer = getDefaultServerKey(); - if (defaultServer == DEFAULTSERVER_LASTUSED || defaultServer == DEFAULTSERVER_ASKONADD) { - return getLastUsedServer(); - } - - // Use the explicitly selected default server - int max = getMaxOfAllServers(); // Zero-based index, so with max == 0 there is 1 server - if (max < 0) { - // No servers configured - return null; - } - if (defaultServer < 0 || defaultServer > max) { - // Last server was never set or no longer exists - return getServerSetting(0); - } - return getServerSetting(defaultServer); - - } - - /** - * Returns the unique key of the server setting that the user selected as their default server, or code indicating - * that the last used server should be selected by default; use with getDefaultServer directly. WARNING: the - * returned string may no longer refer to a known server setting key. - * @return An integer; if it is 0 or higher it represents the unique key of a configured server setting, -2 means - * the last used server should be selected as default instead and -1 means the last used server should be - * selected by default for viewing yet it should always ask when adding a new torrent - */ - public int getDefaultServerKey() { - String defaultServer = prefs.getString("header_defaultserver", Integer.toString(DEFAULTSERVER_LASTUSED)); - try { - return Integer.parseInt(defaultServer); - } catch (NumberFormatException e) { - // This should NEVER happen but if the setting somehow is not a number, return the default - return DEFAULTSERVER_LASTUSED; - } - } - - /** - * Returns the settings of the server that was last used by the user. As opposed to getLastUsedServerKey(int), this - * method checks whether a server was already registered as being last used and check whether the server still - * exists. It returns the first server if that fails. If no servers are configured, null is returned. - * @return A server settings object of the last used server (or, if not known, the first server), or null if no - * servers exist - */ - public ServerSetting getLastUsedServer() { - int max = getMaxOfAllServers(); // Zero-based index, so with max == 0 there is 1 server - if (max < 0) { - // No servers configured - return null; - } - int last = getLastUsedServerKey(); - if (last < 0 || last > max) { - // Last server was never set or no longer exists - return getServerSetting(0); - } - return getServerSetting(last); - } - - /** - * Returns the order number/unique key of the server that the used last used; use with getServerSettings(int) or - * call getLastUsedServer directly. WARNING: the returned integer may no longer refer to a known server settings - * object: check the bounds. - * @return An integer indicating the order number/key or the last used server, or -1 if it was not set - */ - public int getLastUsedServerKey() { - return prefs.getInt("system_lastusedserver", -1); - } - - /** - * Registers some server as being the last used by the user - * @param server The settings of the server that the user last used - */ - public void setLastUsedServer(ServerSetting server) { - setLastUsedServerKey(server.getOrder()); - } - - /** - * Registers the order number/unique key of some server as being last used by the user - * @param order The key identifying the specific server - */ - public void setLastUsedServerKey(int order) { - prefs.edit().putInt("system_lastusedserver", order).apply(); - } - - /** - * Returns the unique code that (should) uniquely identify a navigation filter, such as a label, in the list of all - * available filters - * @return A code that the last used navigation filter reported as uniquely identifying itself, or null if no last - * used filter is known - */ - public String getLastUsedNavigationFilter() { - return prefs.getString("system_lastusedfilter", null); - } - - /** - * Registers some navigation filter as being the last used by the user - * @param filter The navigation filter that the user last used in the interface - */ - public void setLastUsedNavigationFilter(NavigationFilter filter) { - prefs.edit().putString("system_lastusedfilter", filter.getCode()).apply(); - } - - /** - * Returns all available user-configured web-based (as opped to in-app) search sites - * @return A list of all stored web search site settings objects - */ - public List getWebsearchSettings() { - List websearches = new ArrayList<>(); - for (int i = 0; i <= getMaxWebsearch(); i++) { - websearches.add(getWebsearchSetting(i)); - } - return Collections.unmodifiableList(websearches); - } - - /** - * Returns the order number/identifying key of the last web search site - * @return The zero-based order number (index) of the last stored web search site - */ - public int getMaxWebsearch() { - for (int i = 0; true; i++) { - if (prefs.getString("websearch_baseurl_" + i, null) == null) - return i - 1; - } - } - - /** - * Returns the user-specified web-based search site setting for a specific site - * @param order The order number/identifying key of the settings to retrieve - * @return The web search site settings object, loaded from shared preferences - */ - public WebsearchSetting getWebsearchSetting(int order) { - // @formatter:off - return new WebsearchSetting(order, - prefs.getString("websearch_name_" + order, null), - prefs.getString("websearch_baseurl_" + order, null), - prefs.getString("websearch_cookies_" + order, null)); - // @formatter:on - } - - /** - * Removes all settings related to a configured web-based search site. Since sites are ordered, the order of the - * remaining sites will be updated accordingly. - * @param order The identifying order number/key of the settings to remove - */ - public void removeWebsearchSettings(int order) { - if (prefs.getString("websearch_baseurl_" + order, null) == null) - return; // The settings that were requested to be removed do not exist - - // Copy all settings higher than the supplied order number to the previous spot - Editor edit = prefs.edit(); - int max = getMaxWebsearch(); - for (int i = order; i < max; i++) { - edit.putString("websearch_name_" + i, prefs.getString("websearch_name_" + (i + 1), null)); - edit.putString("websearch_baseurl_" + i, prefs.getString("websearch_baseurl_" + (i + 1), null)); - edit.putString("websearch_cookies_" + i, prefs.getString("websearch_cookies_" + (i + 1), null)); - } - - // Remove the last settings, of which we are now sure are no longer required - edit.remove("websearch_name_" + max); - edit.remove("websearch_baseurl_" + max); - edit.remove("websearch_cookies_" + max); - edit.apply(); - - } - - /** - * Returns all available user-configured RSS feeds - * @return A list of all stored RSS feed settings objects - */ - public List getRssfeedSettings() { - List rssfeeds = new ArrayList<>(); - for (int i = 0; i <= getMaxRssfeed(); i++) { - rssfeeds.add(getRssfeedSetting(i)); - } - return Collections.unmodifiableList(rssfeeds); - } - - /** - * Returns the order number/identifying key of the last stored RSS feed - * @return The zero-based order number (index) of the last stored RSS feed - */ - public int getMaxRssfeed() { - for (int i = 0; true; i++) { - if (prefs.getString("rssfeed_url_" + i, null) == null) - return i - 1; - } - } - - /** - * Returns the user-specified RSS feed setting for a specific feed - * @param order The order number/identifying key of the settings to retrieve - * @return The RSS feed settings object, loaded from shared preferences - */ - public RssfeedSetting getRssfeedSetting(int order) { - // @formatter:off - long lastViewed = prefs.getLong("rssfeed_lastviewed_" + order, -1); - return new RssfeedSetting(order, - prefs.getString("rssfeed_name_" + order, null), - prefs.getString("rssfeed_url_" + order, null), - prefs.getBoolean("rssfeed_reqauth_" + order, false), - prefs.getBoolean("rssfeed_alarmnew_" + order, true), - prefs.getString("rssfeed_exclude_" + order, null), - prefs.getString("rssfeed_include_" + order, null), - lastViewed == -1L ? null : new Date(lastViewed), - prefs.getString("rssfeed_lastvieweditemurl_" + order, null)); - // @formatter:on - } - - /** - * Removes all settings related to a configured RSS feed. Since feeds are ordered, the order of the remaining feeds - * will be updated accordingly. - * @param order The identifying order number/key of the settings to remove - */ - public void removeRssfeedSettings(int order) { - if (prefs.getString("rssfeed_url_" + order, null) == null) - return; // The settings that were requested to be removed do not exist - - // Copy all settings higher than the supplied order number to the previous spot - Editor edit = prefs.edit(); - int max = getMaxRssfeed(); - for (int i = order; i < max; i++) { - edit.putString("rssfeed_name_" + i, prefs.getString("rssfeed_name_" + (i + 1), null)); - edit.putString("rssfeed_url_" + i, prefs.getString("rssfeed_url_" + (i + 1), null)); - edit.putBoolean("rssfeed_reqauth_" + i, prefs.getBoolean("rssfeed_reqauth_" + (i + 1), false)); - edit.putBoolean("rssfeed_alarmnew_" + i, prefs.getBoolean("rssfeed_alarmnew_" + (i + 1), true)); - edit.putString("rssfeed_exclude_" + i, prefs.getString("rssfeed_exclude_" + (i + 1), null)); - edit.putString("rssfeed_include_" + i, prefs.getString("rssfeed_include_" + (i + 1), null)); - edit.putLong("rssfeed_lastviewed_" + i, prefs.getLong("rssfeed_lastviewed_" + (i + 1), -1)); - edit.putString("rssfeed_lastvieweditemurl_" + i, prefs.getString("rssfeed_lastvieweditemurl_" + (i + 1), null)); - } - - // Remove the last settings, of which we are now sure are no longer required - edit.remove("rssfeed_name_" + max); - edit.remove("rssfeed_url_" + max); - edit.remove("rssfeed_reqauth_" + max); - edit.remove("rssfeed_alarmnew_" + max); - edit.remove("rssfeed_exclude_" + max); - edit.remove("rssfeed_include_" + max); - edit.remove("rssfeed_lastviewed_" + max); - edit.remove("rssfeed_lastvieweditemurl_" + max); - edit.apply(); - - } - - /** - * Registers for some RSS feed (as identified by its order numbe/key) the last date and time that it was viewed by - * the user. This is used to determine which items in an RSS feed are 'new'. Warning: any previously retrieved - * {@link RssfeedSetting} object is now no longer in sync, as this will not automatically be updated in the object. - * Use {@link #getRssfeedSetting(int)} to get fresh data. - * @param order The identifying order number/key of the settings of te RSS feed that was viewed - * @param lastViewed The date and time that the feed was last viewed; typically now - * @param lastViewedItemUrl The url of the last item the last time that the feed was viewed - */ - public void setRssfeedLastViewer(int order, Date lastViewed, String lastViewedItemUrl) { - if (prefs.getString("rssfeed_url_" + order, null) == null) - return; // The settings that were requested to be removed do not exist - Editor edit = prefs.edit(); - edit.putLong("rssfeed_lastviewed_" + order, lastViewed.getTime()); - edit.putString("rssfeed_lastvieweditemurl_" + order, lastViewedItemUrl); - edit.apply(); - } - - /** - * Registers the torrents list sort order as being last used by the user - * @param currentSortOrder The sort order property the user selected last - * @param currentSortAscending The sort order direction that was last used - */ - public void setLastUsedSortOrder(TorrentsSortBy currentSortOrder, boolean currentSortAscending) { - Editor edit = prefs.edit(); - edit.putInt("system_lastusedsortorder", currentSortOrder.getCode()); - edit.putBoolean("system_lastusedsortdirection", currentSortAscending); - edit.apply(); - } - - /** - * Returns the sort order property that the user last used. Use together with {@link #getLastUsedSortDescending()} - * to get the full last used sort settings. - * @return The last used sort order enumeration value - */ - public TorrentsSortBy getLastUsedSortOrder() { - return TorrentsSortBy - .getStatus(prefs.getInt("system_lastusedsortorder", TorrentsSortBy.Alphanumeric.getCode())); - } - - /** - * Registers the search list sort order as being last used by the user - * @param currentSortOrder The sort order property the user selected last - */ - public void setLastUsedSearchSortOrder(SearchSortOrder currentSortOrder) { - Editor edit = prefs.edit(); - edit.putInt("system_lastusedsearchsortorder", currentSortOrder.ordinal()); - edit.apply(); - } - - /** - * Returns the search sort order property that the user last used. - * @return The last used sort order enumeration value - */ - public SearchSortOrder getLastUsedSearchSortOrder() { - return SearchSortOrder.values()[(prefs.getInt("system_lastusedsearchsortorder", SearchSortOrder.BySeeders.ordinal()))]; - } - - /** - * Returns the sort order direction that the user last used. Use together with {@link #getLastUsedSortOrder()} to - * get the full last used sort settings. - * @return True if the last used sort direction was descending, false otherwise (i.e. the default ascending - * direction) - */ - public boolean getLastUsedSortDescending() { - return prefs.getBoolean("system_lastusedsortdirection", false); - } - - /** - * Returns the list of all available in-app search sites as well as all web searches that the user configured. - * @return A list of search settings, all of which are either a {@link SearchSite} or {@link WebsearchSetting} - */ - public List getSearchSettings() { - List all = new ArrayList<>(); - all.addAll(searchHelper.getAvailableSites()); - all.addAll(getWebsearchSettings()); - return Collections.unmodifiableList(all); - } - - /** - * Returns the settings of the search site that was last used by the user or was selected by the user as default - * site in the main settings. As opposed to getLastUsedSearchSiteKey(int), this method checks whether a site was - * already registered as being last used (or set as default) and checks whether the site still exists. It returns - * the first in-app search site if that fails. - * @return A site settings object of the last used server (or, if not known, the first server), or null if no - * servers exist - */ - public SearchSetting getLastUsedSearchSite() { - String lastKey = getLastUsedSearchSiteKey(); - List allsites = searchHelper.getAvailableSites(); - - if (lastKey == null) { - // No site yet set specified; return the first in-app one, if available - if (allsites != null) { - return allsites.get(0); - } - return null; - } - - int lastWebsearch = -1; - if (lastKey.startsWith(WebsearchSetting.KEY_PREFIX)) { - try { - lastWebsearch = Integer.parseInt(lastKey.substring(WebsearchSetting.KEY_PREFIX.length())); - } catch (Exception e) { - // Not an in-app search site, but probably an in-app search - } - } - if (lastWebsearch >= 0) { - // The last used site should be a user-configured web search site - int max = getMaxWebsearch(); // Zero-based index, so with max == 0 there is 1 server - if (max < 0 || lastWebsearch > max) { - // No web search sites configured - return null; - } - return getWebsearchSetting(lastWebsearch); - } - - // Should be an in-app search key - if (allsites != null && !allsites.isEmpty()) { - for (SearchSite searchSite : allsites) { - if (searchSite.getKey().equals(lastKey)) { - return searchSite; - } - } - // Not found at all; probably a no longer existing web search; return the first in-app one - return allsites.get(0); - } - - return null; - } - - /** - * Returns the unique key of the site that the used last used or selected as default form the main settings; use - * with getLastUsedSearchSite directly. WARNING: the returned string may no longer refer to a known web search site - * or in-app search settings object. - * @return A string indicating the key of the last used search site, or null if no site was yet used or set as - * default - */ - private String getLastUsedSearchSiteKey() { - return prefs.getString("header_setsearchsite", null); - } - - /** - * Registers the unique key of some web search or in-app search site as being last used by the user - * @param site The site settings to register as being last used - */ - public void setLastUsedSearchSite(SearchSetting site) { - prefs.edit().putString("header_setsearchsite", site.getKey()).apply(); - } - - /** - * Returns the statistics of this server as it was last seen by the background server checker service. - * @param server The server for which to retrieved the statistics from the stored preferences - * @return A JSON array of JSON objects, each which represent a since torrent - */ - public JSONArray getServerLastStats(ServerSetting server) { - String lastStats = prefs.getString(server.getUniqueIdentifier(), null); - if (lastStats == null) - return null; - try { - return new JSONArray(lastStats); - } catch (JSONException e) { - return null; - } - } - - /** - * Stores the now-last seen statistics of the supplied server by the background server checker service to the - * internal stored preferences. - * @param server The server to which the statistics apply to - * @param lastStats A JSON array of JSON objects that each represent a single seen torrent - */ - public void setServerLastStats(ServerSetting server, JSONArray lastStats) { - prefs.edit().putString(server.getUniqueIdentifier(), lastStats.toString()).apply(); - } - - /** - * Returns the user configuration for some specific app widget, if the widget is known at all. - * @param appWidgetId The unique ID of the app widget to retrieve settings for, as supplied by the AppWidgetManager - * @return A widget configuration object, or null if no settings were stored for the widget ID - */ - public ListWidgetConfig getWidgetConfig(int appWidgetId) { - if (!prefs.contains("widget_server_" + appWidgetId)) - return null; - // @formatter:off - return new ListWidgetConfig( - prefs.getInt("widget_server_" + appWidgetId, -1), - StatusType.valueOf(prefs.getString("widget_status_" + appWidgetId, StatusType.ShowAll.name())), - TorrentsSortBy.valueOf(prefs.getString("widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())), - prefs.getBoolean("widget_reverse_" + appWidgetId, false), - prefs.getBoolean("widget_showstatus_" + appWidgetId, false)); - // @formatter:on - } - - /** - * Stores the user settings for some specific app widget. Existing settings for the supplied app widget ID will be - * overridden. - * @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager - * @param settings A widget configuration object, which may not be null - */ - public void setWidgetConfig(int appWidgetId, ListWidgetConfig settings) { - if (settings == null) - throw new InvalidParameterException( - "The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget."); - Editor edit = prefs.edit(); - edit.putInt("widget_server_" + appWidgetId, settings.getServerId()); - edit.putString("widget_status_" + appWidgetId, settings.getStatusType().name()); - edit.putString("widget_sortby_" + appWidgetId, settings.getSortBy().name()); - edit.putBoolean("widget_reverse_" + appWidgetId, settings.shouldReserveSort()); - edit.putBoolean("widget_showstatus_" + appWidgetId, settings.shouldShowStatusView()); - edit.apply(); - } - - /** - * Remove the setting for some specific app widget. - * @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager - */ - public void removeWidgetConfig(int appWidgetId) { - Editor edit = prefs.edit(); - edit.remove("widget_server_" + appWidgetId); - edit.remove("widget_status_" + appWidgetId); - edit.remove("widget_sortby_" + appWidgetId); - edit.remove("widget_reverse_" + appWidgetId); - edit.remove("widget_showstatus_" + appWidgetId); - edit.remove("widget_darktheme_" + appWidgetId); - edit.apply(); - } - - /** - * Trims away whitespace around a string, or returns null if str is null - * @param str The string to trim, or null - * @return The trimmed string, or null if str is null - */ - private String trim(String str) { - if (str == null) return null; - return str.trim(); - } - - private int parseInt(String string, int defaultValue) { - try { - return Integer.parseInt(string); - } catch (NumberFormatException e) { - return defaultValue; - } - } + public static final int DEFAULTSERVER_LASTUSED = -2; + public static final int DEFAULTSERVER_ASKONADD = -1; + + @RootContext + protected Context context; + @Bean + protected SearchHelper searchHelper; + private SharedPreferences prefs; + + protected ApplicationSettings(Context context) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + } + + /** + * Returns all available user-configured normal and seed servers + * + * @return A list of all stored server settings objects + */ + public List getAllServerSettings() { + List all = new ArrayList<>(getNormalServerSettings()); + for (SeedboxProvider provider : SeedboxProvider.values()) { + all.addAll(provider.getSettings().getAllServerSettings(prefs, all.size())); + } + return all; + } + + /** + * Returns the order number/identifying key of the last server, normal or seedbox configured + * + * @return The zero-based order number (index) of the last stored server settings + */ + public int getMaxOfAllServers() { + int max = getMaxNormalServer(); + for (SeedboxProvider provider : SeedboxProvider.values()) { + max += provider.getSettings().getMaxSeedboxOrder(prefs) + 1; + } + return max; + } + + /** + * Returns the server settings for either a normal or a seedbox server as the user configured. WARNING: This method + * does not check if the settings actually exist and may reply on empty default if called for a non-existing server. + * + * @param order The order number/identifying key of the server's settings to retrieve, where the normal servers are + * first and the seedboxes are numbers thereafter onwards + * @return The server settings object, loaded from shared preferences + */ + public ServerSetting getServerSetting(int order) { + int max = getMaxNormalServer() + 1; + if (order < max) { + return getNormalServerSetting(order); + } + for (SeedboxProvider provider : SeedboxProvider.values()) { + int offset = max; + max += provider.getSettings().getMaxSeedboxOrder(prefs) + 1; + if (order < max) { + return provider.getSettings().getServerSetting(prefs, offset, order - offset); + } + } + return null; + } + + /** + * Returns all available normal, user-configured servers (so no seedbox settings) + * + * @return A list of all stored server settings objects + */ + public List getNormalServerSettings() { + List servers = new ArrayList<>(); + for (int i = 0; i <= getMaxNormalServer(); i++) { + servers.add(getNormalServerSetting(i)); + } + return Collections.unmodifiableList(servers); + } + + /** + * Returns the order number/identifying key of the last normal server + * + * @return The zero-based order number (index) of the last stored normal server settings + */ + public int getMaxNormalServer() { + for (int i = 0; true; i++) { + if (prefs.getString("server_type_" + i, null) == null || prefs.getString("server_address_" + i, null) == null) + return i - 1; + } + } + + /** + * Returns the user-specified server settings for a normal (non-seedbox) server. WARNING: This method does not check + * if the settings actually exist and may rely on empty defaults if called for a non-existing server. + * + * @param order The order number/identifying key of the normal server's settings to retrieve + * @return The server settings object, loaded from shared preferences + */ + public ServerSetting getNormalServerSetting(int order) { + // @formatter:off + Daemon type = Daemon.fromCode(prefs.getString("server_type_" + order, null)); + boolean ssl = prefs.getBoolean("server_sslenabled_" + order, false); + boolean localSsl = prefs.getBoolean("server_localsslenabled_" + order, ssl); + + String port = prefs.getString("server_port_" + order, null); + if (TextUtils.isEmpty(port)) + port = Integer.toString(Daemon.getDefaultPortNumber(type, ssl)); + String localPort = prefs.getString("server_localport_" + order, null); + if (TextUtils.isEmpty(localPort)) + localPort = port; // Default to the normal (non-local) port + try { + parseInt(port, Daemon.getDefaultPortNumber(type, ssl)); + } catch (NumberFormatException e) { + port = Integer.toString(Daemon.getDefaultPortNumber(type, ssl)); + } + try { + parseInt(localPort, parseInt(port, Daemon.getDefaultPortNumber(type, ssl))); + } catch (NumberFormatException e) { + localPort = port; + } + + return new ServerSetting(order, + prefs.getString("server_name_" + order, null), + type, + trim(prefs.getString("server_address_" + order, null)), + trim(prefs.getString("server_localaddress_" + order, null)), + parseInt(localPort, parseInt(port, Daemon.getDefaultPortNumber(type, ssl))), + prefs.getString("server_localnetwork_" + order, null), + parseInt(port, Daemon.getDefaultPortNumber(type, ssl)), + ssl, localSsl, + prefs.getBoolean("server_ssltrustall_" + order, false), + prefs.getString("server_ssltrustkey_" + order, null), + prefs.getString("server_folder_" + order, null), + !prefs.getBoolean("server_disableauth_" + order, false), + prefs.getString("server_user_" + order, null), + prefs.getString("server_pass_" + order, null), + prefs.getString("server_extrapass_" + order, null), + OS.fromCode(prefs.getString("server_os_" + order, "type_linux")), + prefs.getString("server_downloaddir_" + order, null), + prefs.getString("server_ftpurl_" + order, null), + prefs.getString("server_ftppass_" + order, null), + parseInt(prefs.getString("server_timeout_" + order, "8"), 8), + prefs.getBoolean("server_alarmfinished_" + order, true), + prefs.getBoolean("server_alarmnew_" + order, false), + prefs.getString("server_alarmexclude_" + order, null), + prefs.getString("server_alarminclude_" + order, null), + false); + // @formatter:on + } + + /** + * Removes all settings related to a configured server. Since servers are ordered, the order of the remaining + * servers will be updated accordingly. + * + * @param order The identifying order number/key of the settings to remove + */ + public void removeNormalServerSettings(int order) { + if (prefs.getString("server_type_" + order, null) == null) + return; // The settings that were requested to be removed do not exist + + // Copy all settings higher than the supplied order number to the previous spot + Editor edit = prefs.edit(); + int max = getMaxNormalServer(); + for (int i = order; i < max; i++) { + edit.putString("server_name_" + i, prefs.getString("server_name_" + (i + 1), null)); + edit.putString("server_type_" + i, prefs.getString("server_type_" + (i + 1), null)); + edit.putString("server_address_" + i, prefs.getString("server_address_" + (i + 1), null)); + edit.putString("server_localaddress_" + i, prefs.getString("server_localaddress_" + (i + 1), null)); + edit.putString("server_localnetwork_" + i, prefs.getString("server_localnetwork_" + (i + 1), null)); + edit.putString("server_port_" + i, prefs.getString("server_port_" + (i + 1), null)); + edit.putBoolean("server_sslenabled_" + i, prefs.getBoolean("server_sslenabled_" + (i + 1), false)); + edit.putBoolean("server_localsslenabled_" + i, prefs.getBoolean("server_localsslenabled_" + (i + 1), false)); + edit.putBoolean("server_ssltrustall_" + i, prefs.getBoolean("server_ssltrustall_" + (i + 1), false)); + edit.putString("server_ssltrustkey_" + i, prefs.getString("server_ssltrustkey_" + (i + 1), null)); + edit.putString("server_folder_" + i, prefs.getString("server_folder_" + (i + 1), null)); + edit.putBoolean("server_disableauth_" + i, prefs.getBoolean("server_disableauth_" + (i + 1), false)); + edit.putString("server_user_" + i, prefs.getString("server_user_" + (i + 1), null)); + edit.putString("server_pass_" + i, prefs.getString("server_pass_" + (i + 1), null)); + edit.putString("server_extrapass_" + i, prefs.getString("server_extrapass_" + (i + 1), null)); + edit.putString("server_os_" + i, prefs.getString("server_os_" + (i + 1), null)); + edit.putString("server_downloaddir_" + i, prefs.getString("server_downloaddir_" + (i + 1), null)); + edit.putString("server_ftpurl_" + i, prefs.getString("server_ftpurl_" + (i + 1), null)); + edit.putString("server_ftppass_" + i, prefs.getString("server_ftppass_" + (i + 1), null)); + edit.putString("server_timeout_" + i, prefs.getString("server_timeout_" + (i + 1), null)); + edit.putBoolean("server_alarmfinished_" + i, prefs.getBoolean("server_alarmfinished_" + (i + 1), true)); + edit.putBoolean("server_alarmfinished_" + i, prefs.getBoolean("server_alarmfinished_" + (i + 1), false)); + } + + // Remove the last settings, of which we are now sure are no longer required + edit.remove("server_name_" + max); + edit.remove("server_type_" + max); + edit.remove("server_address_" + max); + edit.remove("server_localaddress_" + max); + edit.remove("server_localnetwork_" + max); + edit.remove("server_port_" + max); + edit.remove("server_sslenabled_" + max); + edit.remove("server_localsslenabled_" + max); + edit.remove("server_ssltrustall_" + max); + edit.remove("server_ssltrustkey_" + max); + edit.remove("server_folder_" + max); + edit.remove("server_disableauth_" + max); + edit.remove("server_user_" + max); + edit.remove("server_pass_" + max); + edit.remove("server_extrapass_" + max); + edit.remove("server_os_" + max); + edit.remove("server_downloaddir_" + max); + edit.remove("server_ftpurl_" + max); + edit.remove("server_ftppass_" + max); + edit.remove("server_timeout_" + max); + edit.remove("server_alarmfinished_" + max); + edit.remove("server_alarmfinished_" + max); + + // Perhaps we should also update the default server to match the server's new id or remove the default selection + // in case it was this server that was removed + int defaultServer = getDefaultServerKey(); + if (defaultServer == order) { + edit.remove("header_defaultserver"); + } else if (defaultServer > order) { + // Move 'up' one place to account for the removed server setting + edit.putString("header_defaultserver", String.valueOf(--order)); + } + + edit.apply(); + + } + + /** + * Returns the settings of the server that was explicitly selected by the user to select as default or, when no + * specific default server was selected, the last used server settings. As opposed to getDefaultServerKey(int), this + * method checks whether the particular server still exists (and returns the first server if not). If no servers are + * configured, null is returned. + * + * @return A server settings object of the server to use by default, or null if no server is yet configured + */ + public ServerSetting getDefaultServer() { + + int defaultServer = getDefaultServerKey(); + if (defaultServer == DEFAULTSERVER_LASTUSED || defaultServer == DEFAULTSERVER_ASKONADD) { + return getLastUsedServer(); + } + + // Use the explicitly selected default server + int max = getMaxOfAllServers(); // Zero-based index, so with max == 0 there is 1 server + if (max < 0) { + // No servers configured + return null; + } + if (defaultServer < 0 || defaultServer > max) { + // Last server was never set or no longer exists + return getServerSetting(0); + } + return getServerSetting(defaultServer); + + } + + /** + * Returns the unique key of the server setting that the user selected as their default server, or code indicating + * that the last used server should be selected by default; use with getDefaultServer directly. WARNING: the + * returned string may no longer refer to a known server setting key. + * + * @return An integer; if it is 0 or higher it represents the unique key of a configured server setting, -2 means + * the last used server should be selected as default instead and -1 means the last used server should be + * selected by default for viewing yet it should always ask when adding a new torrent + */ + public int getDefaultServerKey() { + String defaultServer = prefs.getString("header_defaultserver", Integer.toString(DEFAULTSERVER_LASTUSED)); + try { + return Integer.parseInt(defaultServer); + } catch (NumberFormatException e) { + // This should NEVER happen but if the setting somehow is not a number, return the default + return DEFAULTSERVER_LASTUSED; + } + } + + /** + * Returns the settings of the server that was last used by the user. As opposed to getLastUsedServerKey(int), this + * method checks whether a server was already registered as being last used and check whether the server still + * exists. It returns the first server if that fails. If no servers are configured, null is returned. + * + * @return A server settings object of the last used server (or, if not known, the first server), or null if no + * servers exist + */ + public ServerSetting getLastUsedServer() { + int max = getMaxOfAllServers(); // Zero-based index, so with max == 0 there is 1 server + if (max < 0) { + // No servers configured + return null; + } + int last = getLastUsedServerKey(); + if (last < 0 || last > max) { + // Last server was never set or no longer exists + return getServerSetting(0); + } + return getServerSetting(last); + } + + /** + * Registers some server as being the last used by the user + * + * @param server The settings of the server that the user last used + */ + public void setLastUsedServer(ServerSetting server) { + setLastUsedServerKey(server.getOrder()); + } + + /** + * Returns the order number/unique key of the server that the used last used; use with getServerSettings(int) or + * call getLastUsedServer directly. WARNING: the returned integer may no longer refer to a known server settings + * object: check the bounds. + * + * @return An integer indicating the order number/key or the last used server, or -1 if it was not set + */ + public int getLastUsedServerKey() { + return prefs.getInt("system_lastusedserver", -1); + } + + /** + * Registers the order number/unique key of some server as being last used by the user + * + * @param order The key identifying the specific server + */ + public void setLastUsedServerKey(int order) { + prefs.edit().putInt("system_lastusedserver", order).apply(); + } + + /** + * Returns the unique code that (should) uniquely identify a navigation filter, such as a label, in the list of all + * available filters + * + * @return A code that the last used navigation filter reported as uniquely identifying itself, or null if no last + * used filter is known + */ + public String getLastUsedNavigationFilter() { + return prefs.getString("system_lastusedfilter", null); + } + + /** + * Registers some navigation filter as being the last used by the user + * + * @param filter The navigation filter that the user last used in the interface + */ + public void setLastUsedNavigationFilter(NavigationFilter filter) { + prefs.edit().putString("system_lastusedfilter", filter.getCode()).apply(); + } + + /** + * Returns all available user-configured web-based (as opped to in-app) search sites + * + * @return A list of all stored web search site settings objects + */ + public List getWebsearchSettings() { + List websearches = new ArrayList<>(); + for (int i = 0; i <= getMaxWebsearch(); i++) { + websearches.add(getWebsearchSetting(i)); + } + return Collections.unmodifiableList(websearches); + } + + /** + * Returns the order number/identifying key of the last web search site + * + * @return The zero-based order number (index) of the last stored web search site + */ + public int getMaxWebsearch() { + for (int i = 0; true; i++) { + if (prefs.getString("websearch_baseurl_" + i, null) == null) + return i - 1; + } + } + + /** + * Returns the user-specified web-based search site setting for a specific site + * + * @param order The order number/identifying key of the settings to retrieve + * @return The web search site settings object, loaded from shared preferences + */ + public WebsearchSetting getWebsearchSetting(int order) { + // @formatter:off + return new WebsearchSetting(order, + prefs.getString("websearch_name_" + order, null), + prefs.getString("websearch_baseurl_" + order, null), + prefs.getString("websearch_cookies_" + order, null)); + // @formatter:on + } + + /** + * Removes all settings related to a configured web-based search site. Since sites are ordered, the order of the + * remaining sites will be updated accordingly. + * + * @param order The identifying order number/key of the settings to remove + */ + public void removeWebsearchSettings(int order) { + if (prefs.getString("websearch_baseurl_" + order, null) == null) + return; // The settings that were requested to be removed do not exist + + // Copy all settings higher than the supplied order number to the previous spot + Editor edit = prefs.edit(); + int max = getMaxWebsearch(); + for (int i = order; i < max; i++) { + edit.putString("websearch_name_" + i, prefs.getString("websearch_name_" + (i + 1), null)); + edit.putString("websearch_baseurl_" + i, prefs.getString("websearch_baseurl_" + (i + 1), null)); + edit.putString("websearch_cookies_" + i, prefs.getString("websearch_cookies_" + (i + 1), null)); + } + + // Remove the last settings, of which we are now sure are no longer required + edit.remove("websearch_name_" + max); + edit.remove("websearch_baseurl_" + max); + edit.remove("websearch_cookies_" + max); + edit.apply(); + + } + + /** + * Returns all available user-configured RSS feeds + * + * @return A list of all stored RSS feed settings objects + */ + public List getRssfeedSettings() { + List rssfeeds = new ArrayList<>(); + for (int i = 0; i <= getMaxRssfeed(); i++) { + rssfeeds.add(getRssfeedSetting(i)); + } + return Collections.unmodifiableList(rssfeeds); + } + + /** + * Returns the order number/identifying key of the last stored RSS feed + * + * @return The zero-based order number (index) of the last stored RSS feed + */ + public int getMaxRssfeed() { + for (int i = 0; true; i++) { + if (prefs.getString("rssfeed_url_" + i, null) == null) + return i - 1; + } + } + + /** + * Returns the user-specified RSS feed setting for a specific feed + * + * @param order The order number/identifying key of the settings to retrieve + * @return The RSS feed settings object, loaded from shared preferences + */ + public RssfeedSetting getRssfeedSetting(int order) { + // @formatter:off + long lastViewed = prefs.getLong("rssfeed_lastviewed_" + order, -1); + return new RssfeedSetting(order, + prefs.getString("rssfeed_name_" + order, null), + prefs.getString("rssfeed_url_" + order, null), + prefs.getBoolean("rssfeed_reqauth_" + order, false), + prefs.getBoolean("rssfeed_alarmnew_" + order, true), + prefs.getString("rssfeed_exclude_" + order, null), + prefs.getString("rssfeed_include_" + order, null), + lastViewed == -1L ? null : new Date(lastViewed), + prefs.getString("rssfeed_lastvieweditemurl_" + order, null)); + // @formatter:on + } + + /** + * Removes all settings related to a configured RSS feed. Since feeds are ordered, the order of the remaining feeds + * will be updated accordingly. + * + * @param order The identifying order number/key of the settings to remove + */ + public void removeRssfeedSettings(int order) { + if (prefs.getString("rssfeed_url_" + order, null) == null) + return; // The settings that were requested to be removed do not exist + + // Copy all settings higher than the supplied order number to the previous spot + Editor edit = prefs.edit(); + int max = getMaxRssfeed(); + for (int i = order; i < max; i++) { + edit.putString("rssfeed_name_" + i, prefs.getString("rssfeed_name_" + (i + 1), null)); + edit.putString("rssfeed_url_" + i, prefs.getString("rssfeed_url_" + (i + 1), null)); + edit.putBoolean("rssfeed_reqauth_" + i, prefs.getBoolean("rssfeed_reqauth_" + (i + 1), false)); + edit.putBoolean("rssfeed_alarmnew_" + i, prefs.getBoolean("rssfeed_alarmnew_" + (i + 1), true)); + edit.putString("rssfeed_exclude_" + i, prefs.getString("rssfeed_exclude_" + (i + 1), null)); + edit.putString("rssfeed_include_" + i, prefs.getString("rssfeed_include_" + (i + 1), null)); + edit.putLong("rssfeed_lastviewed_" + i, prefs.getLong("rssfeed_lastviewed_" + (i + 1), -1)); + edit.putString("rssfeed_lastvieweditemurl_" + i, prefs.getString("rssfeed_lastvieweditemurl_" + (i + 1), null)); + } + + // Remove the last settings, of which we are now sure are no longer required + edit.remove("rssfeed_name_" + max); + edit.remove("rssfeed_url_" + max); + edit.remove("rssfeed_reqauth_" + max); + edit.remove("rssfeed_alarmnew_" + max); + edit.remove("rssfeed_exclude_" + max); + edit.remove("rssfeed_include_" + max); + edit.remove("rssfeed_lastviewed_" + max); + edit.remove("rssfeed_lastvieweditemurl_" + max); + edit.apply(); + + } + + /** + * Registers for some RSS feed (as identified by its order numbe/key) the last date and time that it was viewed by + * the user. This is used to determine which items in an RSS feed are 'new'. Warning: any previously retrieved + * {@link RssfeedSetting} object is now no longer in sync, as this will not automatically be updated in the object. + * Use {@link #getRssfeedSetting(int)} to get fresh data. + * + * @param order The identifying order number/key of the settings of te RSS feed that was viewed + * @param lastViewed The date and time that the feed was last viewed; typically now + * @param lastViewedItemUrl The url of the last item the last time that the feed was viewed + */ + public void setRssfeedLastViewer(int order, Date lastViewed, String lastViewedItemUrl) { + if (prefs.getString("rssfeed_url_" + order, null) == null) + return; // The settings that were requested to be removed do not exist + Editor edit = prefs.edit(); + edit.putLong("rssfeed_lastviewed_" + order, lastViewed.getTime()); + edit.putString("rssfeed_lastvieweditemurl_" + order, lastViewedItemUrl); + edit.apply(); + } + + /** + * Registers the torrents list sort order as being last used by the user + * + * @param currentSortOrder The sort order property the user selected last + * @param currentSortAscending The sort order direction that was last used + */ + public void setLastUsedSortOrder(TorrentsSortBy currentSortOrder, boolean currentSortAscending) { + Editor edit = prefs.edit(); + edit.putInt("system_lastusedsortorder", currentSortOrder.getCode()); + edit.putBoolean("system_lastusedsortdirection", currentSortAscending); + edit.apply(); + } + + /** + * Returns the sort order property that the user last used. Use together with {@link #getLastUsedSortDescending()} + * to get the full last used sort settings. + * + * @return The last used sort order enumeration value + */ + public TorrentsSortBy getLastUsedSortOrder() { + return TorrentsSortBy + .getStatus(prefs.getInt("system_lastusedsortorder", TorrentsSortBy.Alphanumeric.getCode())); + } + + /** + * Returns the search sort order property that the user last used. + * + * @return The last used sort order enumeration value + */ + public SearchSortOrder getLastUsedSearchSortOrder() { + return SearchSortOrder.values()[(prefs.getInt("system_lastusedsearchsortorder", SearchSortOrder.BySeeders.ordinal()))]; + } + + /** + * Registers the search list sort order as being last used by the user + * + * @param currentSortOrder The sort order property the user selected last + */ + public void setLastUsedSearchSortOrder(SearchSortOrder currentSortOrder) { + Editor edit = prefs.edit(); + edit.putInt("system_lastusedsearchsortorder", currentSortOrder.ordinal()); + edit.apply(); + } + + /** + * Returns the sort order direction that the user last used. Use together with {@link #getLastUsedSortOrder()} to + * get the full last used sort settings. + * + * @return True if the last used sort direction was descending, false otherwise (i.e. the default ascending + * direction) + */ + public boolean getLastUsedSortDescending() { + return prefs.getBoolean("system_lastusedsortdirection", false); + } + + /** + * Returns the list of all available in-app search sites as well as all web searches that the user configured. + * + * @return A list of search settings, all of which are either a {@link SearchSite} or {@link WebsearchSetting} + */ + public List getSearchSettings() { + List all = new ArrayList<>(); + all.addAll(searchHelper.getAvailableSites()); + all.addAll(getWebsearchSettings()); + return Collections.unmodifiableList(all); + } + + /** + * Returns the settings of the search site that was last used by the user or was selected by the user as default + * site in the main settings. As opposed to getLastUsedSearchSiteKey(int), this method checks whether a site was + * already registered as being last used (or set as default) and checks whether the site still exists. It returns + * the first in-app search site if that fails. + * + * @return A site settings object of the last used server (or, if not known, the first server), or null if no + * servers exist + */ + public SearchSetting getLastUsedSearchSite() { + String lastKey = getLastUsedSearchSiteKey(); + List allsites = searchHelper.getAvailableSites(); + + if (lastKey == null) { + // No site yet set specified; return the first in-app one, if available + if (allsites != null) { + return allsites.get(0); + } + return null; + } + + int lastWebsearch = -1; + if (lastKey.startsWith(WebsearchSetting.KEY_PREFIX)) { + try { + lastWebsearch = Integer.parseInt(lastKey.substring(WebsearchSetting.KEY_PREFIX.length())); + } catch (Exception e) { + // Not an in-app search site, but probably an in-app search + } + } + if (lastWebsearch >= 0) { + // The last used site should be a user-configured web search site + int max = getMaxWebsearch(); // Zero-based index, so with max == 0 there is 1 server + if (max < 0 || lastWebsearch > max) { + // No web search sites configured + return null; + } + return getWebsearchSetting(lastWebsearch); + } + + // Should be an in-app search key + if (allsites != null && !allsites.isEmpty()) { + for (SearchSite searchSite : allsites) { + if (searchSite.getKey().equals(lastKey)) { + return searchSite; + } + } + // Not found at all; probably a no longer existing web search; return the first in-app one + return allsites.get(0); + } + + return null; + } + + /** + * Registers the unique key of some web search or in-app search site as being last used by the user + * + * @param site The site settings to register as being last used + */ + public void setLastUsedSearchSite(SearchSetting site) { + prefs.edit().putString("header_setsearchsite", site.getKey()).apply(); + } + + /** + * Returns the unique key of the site that the used last used or selected as default form the main settings; use + * with getLastUsedSearchSite directly. WARNING: the returned string may no longer refer to a known web search site + * or in-app search settings object. + * + * @return A string indicating the key of the last used search site, or null if no site was yet used or set as + * default + */ + private String getLastUsedSearchSiteKey() { + return prefs.getString("header_setsearchsite", null); + } + + /** + * Returns the statistics of this server as it was last seen by the background server checker service. + * + * @param server The server for which to retrieved the statistics from the stored preferences + * @return A JSON array of JSON objects, each which represent a since torrent + */ + public JSONArray getServerLastStats(ServerSetting server) { + String lastStats = prefs.getString(server.getUniqueIdentifier(), null); + if (lastStats == null) + return null; + try { + return new JSONArray(lastStats); + } catch (JSONException e) { + return null; + } + } + + /** + * Stores the now-last seen statistics of the supplied server by the background server checker service to the + * internal stored preferences. + * + * @param server The server to which the statistics apply to + * @param lastStats A JSON array of JSON objects that each represent a single seen torrent + */ + public void setServerLastStats(ServerSetting server, JSONArray lastStats) { + prefs.edit().putString(server.getUniqueIdentifier(), lastStats.toString()).apply(); + } + + /** + * Returns the user configuration for some specific app widget, if the widget is known at all. + * + * @param appWidgetId The unique ID of the app widget to retrieve settings for, as supplied by the AppWidgetManager + * @return A widget configuration object, or null if no settings were stored for the widget ID + */ + public ListWidgetConfig getWidgetConfig(int appWidgetId) { + if (!prefs.contains("widget_server_" + appWidgetId)) + return null; + // @formatter:off + return new ListWidgetConfig( + prefs.getInt("widget_server_" + appWidgetId, -1), + StatusType.valueOf(prefs.getString("widget_status_" + appWidgetId, StatusType.ShowAll.name())), + TorrentsSortBy.valueOf(prefs.getString("widget_sortby_" + appWidgetId, TorrentsSortBy.Alphanumeric.name())), + prefs.getBoolean("widget_reverse_" + appWidgetId, false), + prefs.getBoolean("widget_showstatus_" + appWidgetId, false)); + // @formatter:on + } + + /** + * Stores the user settings for some specific app widget. Existing settings for the supplied app widget ID will be + * overridden. + * + * @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager + * @param settings A widget configuration object, which may not be null + */ + public void setWidgetConfig(int appWidgetId, ListWidgetConfig settings) { + if (settings == null) + throw new InvalidParameterException( + "The widget setting may not be null. Use removeWidgetConfig instead to remove existing settings for some app widget."); + Editor edit = prefs.edit(); + edit.putInt("widget_server_" + appWidgetId, settings.getServerId()); + edit.putString("widget_status_" + appWidgetId, settings.getStatusType().name()); + edit.putString("widget_sortby_" + appWidgetId, settings.getSortBy().name()); + edit.putBoolean("widget_reverse_" + appWidgetId, settings.shouldReserveSort()); + edit.putBoolean("widget_showstatus_" + appWidgetId, settings.shouldShowStatusView()); + edit.apply(); + } + + /** + * Remove the setting for some specific app widget. + * + * @param appWidgetId The unique ID of the app widget to store settings for, as supplied by the AppWidgetManager + */ + public void removeWidgetConfig(int appWidgetId) { + Editor edit = prefs.edit(); + edit.remove("widget_server_" + appWidgetId); + edit.remove("widget_status_" + appWidgetId); + edit.remove("widget_sortby_" + appWidgetId); + edit.remove("widget_reverse_" + appWidgetId); + edit.remove("widget_showstatus_" + appWidgetId); + edit.remove("widget_darktheme_" + appWidgetId); + edit.apply(); + } + + /** + * Trims away whitespace around a string, or returns null if str is null + * + * @param str The string to trim, or null + * @return The trimmed string, or null if str is null + */ + private String trim(String str) { + if (str == null) return null; + return str.trim(); + } + + private int parseInt(String string, int defaultValue) { + try { + return Integer.parseInt(string); + } catch (NumberFormatException e) { + return defaultValue; + } + } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java b/app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java index 6691d0d0..63a442e2 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java +++ b/app/src/main/java/org/transdroid/core/app/settings/NotificationSettings.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -30,103 +30,111 @@ import org.transdroid.R; /** * Allows instantiation of the settings specified in R.xml.pref_notifications. + * * @author Eric Kok */ @EBean(scope = Scope.Singleton) public class NotificationSettings { - private static final long MINIMUM_BACKGROUND_INTERVAL = 900_000; // 15 minutes - - @RootContext - protected Context context; - private SharedPreferences prefs; - - protected NotificationSettings(Context context) { - prefs = PreferenceManager.getDefaultSharedPreferences(context); - } - - /** - * Whether the background service is enabled and the user wants to receive RSS-related notifications - * @return True if the server should be checked for RSS feed updates - */ - public boolean isEnabledForRss() { - return prefs.getBoolean("notifications_enabledrss", true); - } - - /** - * Whether the background service is enabled and the user wants to receive torrent-related notifications - * @return True if the server should be checked for torrent status updates - */ - public boolean isEnabledForTorrents() { - return prefs.getBoolean("notifications_enabled", true); - } - - private String getRawInverval() { - return prefs.getString("notifications_interval", "10800"); - } - - /** - * Returns the interval between two server checks - * @return The interval, in milliseconds - */ - public Long getInvervalInMilliseconds() { - return Math.max(Long.parseLong(getRawInverval()) * 1000L, MINIMUM_BACKGROUND_INTERVAL); - } - - private String getRawSound() { - return prefs.getString("notifications_sound", null); - } - - /** - * Returns the sound (ring tone) to play on a new notification, or null if it should not play any - * @return Either the user-specified sound, null if the user specified 'Silent' or the system default notification sound - */ - public Uri getSound() { - String raw = getRawSound(); - if (raw == null) - return null; - if (raw.equals("")) - return Settings.System.DEFAULT_NOTIFICATION_URI; - return Uri.parse(raw); - } - - /** - * Whether the device should vibrate on a new notification - */ - public boolean shouldVibrate() { - return prefs.getBoolean("notifications_vibrate", false); - } - - /** - * Returns the default vibrate pattern to use if the user enabled notification vibrations; check - * {@link #shouldVibrate()}, - * @return A unique pattern for vibrations in Transdroid - */ - public long[] getDefaultVibratePattern() { - return new long[]{100, 100, 200, 300, 400, 700}; // Unique pattern? - } - - private int getRawLedColour() { - return prefs.getInt("notifications_ledcolour", -1); - } - - /** - * Returns the LED colour to use on a new notification - * @return The integer value of the user-specified or default colour - */ - public int getDesiredLedColour() { - int raw = getRawLedColour(); - if (raw <= 0) - return context.getResources().getColor(R.color.ledgreen); - return raw; - } - - /** - * Whether the background service should report to ADW Launcher - * @return True if the user want Transdroid to report to ADW Launcher - */ - public boolean shouldReportToAdwLauncher() { - return prefs.getBoolean("notifications_adwnotify", false); - } + private static final long MINIMUM_BACKGROUND_INTERVAL = 900_000; // 15 minutes + + @RootContext + protected Context context; + private SharedPreferences prefs; + + protected NotificationSettings(Context context) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + } + + /** + * Whether the background service is enabled and the user wants to receive RSS-related notifications + * + * @return True if the server should be checked for RSS feed updates + */ + public boolean isEnabledForRss() { + return prefs.getBoolean("notifications_enabledrss", true); + } + + /** + * Whether the background service is enabled and the user wants to receive torrent-related notifications + * + * @return True if the server should be checked for torrent status updates + */ + public boolean isEnabledForTorrents() { + return prefs.getBoolean("notifications_enabled", true); + } + + private String getRawInverval() { + return prefs.getString("notifications_interval", "10800"); + } + + /** + * Returns the interval between two server checks + * + * @return The interval, in milliseconds + */ + public Long getInvervalInMilliseconds() { + return Math.max(Long.parseLong(getRawInverval()) * 1000L, MINIMUM_BACKGROUND_INTERVAL); + } + + private String getRawSound() { + return prefs.getString("notifications_sound", null); + } + + /** + * Returns the sound (ring tone) to play on a new notification, or null if it should not play any + * + * @return Either the user-specified sound, null if the user specified 'Silent' or the system default notification sound + */ + public Uri getSound() { + String raw = getRawSound(); + if (raw == null) + return null; + if (raw.equals("")) + return Settings.System.DEFAULT_NOTIFICATION_URI; + return Uri.parse(raw); + } + + /** + * Whether the device should vibrate on a new notification + */ + public boolean shouldVibrate() { + return prefs.getBoolean("notifications_vibrate", false); + } + + /** + * Returns the default vibrate pattern to use if the user enabled notification vibrations; check + * {@link #shouldVibrate()}, + * + * @return A unique pattern for vibrations in Transdroid + */ + public long[] getDefaultVibratePattern() { + return new long[]{100, 100, 200, 300, 400, 700}; // Unique pattern? + } + + private int getRawLedColour() { + return prefs.getInt("notifications_ledcolour", -1); + } + + /** + * Returns the LED colour to use on a new notification + * + * @return The integer value of the user-specified or default colour + */ + public int getDesiredLedColour() { + int raw = getRawLedColour(); + if (raw <= 0) + return context.getResources().getColor(R.color.ledgreen); + return raw; + } + + /** + * Whether the background service should report to ADW Launcher + * + * @return True if the user want Transdroid to report to ADW Launcher + */ + public boolean shouldReportToAdwLauncher() { + return prefs.getBoolean("notifications_adwnotify", false); + } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/RssfeedSetting.java b/app/src/main/java/org/transdroid/core/app/settings/RssfeedSetting.java index 018dcb4d..22fd62d6 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/RssfeedSetting.java +++ b/app/src/main/java/org/transdroid/core/app/settings/RssfeedSetting.java @@ -1,122 +1,126 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ package org.transdroid.core.app.settings; -import java.util.Date; +import android.net.Uri; +import android.text.TextUtils; import org.transdroid.core.gui.lists.SimpleListItem; -import android.net.Uri; -import android.text.TextUtils; +import java.util.Date; /** * Represents a user-specified RSS feed. + * * @author Eric Kok */ public class RssfeedSetting implements SimpleListItem { - private static final String DEFAULT_NAME = "Default"; - - private final int order; - private final String name; - private final String url; - private final boolean requiresAuth; - private final boolean alarm; - private final String excludeFilter; - private final String includeFilter; - private Date lastViewed; - private final String lastViewedItemUrl; - - public RssfeedSetting(int order, String name, String baseUrl, boolean needsAuth, boolean alarm, String excludeFilter, String includeFilter, Date lastViewed, - String lastViewedItemUrl) { - this.order = order; - this.name = name; - this.url = baseUrl; - this.requiresAuth = needsAuth; - this.alarm = alarm; - this.excludeFilter = excludeFilter; - this.includeFilter = includeFilter; - this.lastViewed = lastViewed; - this.lastViewedItemUrl = lastViewedItemUrl; - } - - public int getOrder() { - return order; - } - - @Override - public String getName() { - if (!TextUtils.isEmpty(name)) - return name; - if (!TextUtils.isEmpty(url)) { - String host = Uri.parse(url).getHost(); - return host == null ? DEFAULT_NAME : host; - } - return DEFAULT_NAME; - } - - public String getUrl() { - return url; - } - - public boolean requiresExternalAuthentication() { - return requiresAuth; - } - - public boolean shouldAlarmOnNewItems() { - return alarm; - } - - public String getExcludeFilter() { - return excludeFilter; - } - - public String getIncludeFilter() { - return includeFilter; - } - - /** - * Returns the date on which we last checked this feed. Note that this is NOT updated automatically after the - * settings were loaded from {@link ApplicationSettings}; instead the settings have to be manually loaded again - * using {@link ApplicationSettings#getRssfeedSetting(int)}. - * @return The last new item's URL as URL-encoded string - */ - public Date getLastViewed() { - return this.lastViewed; - } - - /** - * Returns the URL of the item that was the newest last time we checked this feed. Note that this is NOT updated - * automatically after the settings were loaded from {@link ApplicationSettings}; instead the settings have to be - * manually loaded again using {@link ApplicationSettings#getRssfeedSetting(int)}. - * @return The last new item's URL as URL-encoded string - */ - public String getLastViewedItemUrl() { - return this.lastViewedItemUrl; - } - - /** - * Returns a nicely formatted identifier containing (a portion of) the feed URL - * @return A string to identify this feed's URL - */ - public String getHumanReadableIdentifier() { - String host = Uri.parse(url).getHost(); - String path = Uri.parse(url).getPath(); - return (host == null ? null : host + (path == null ? "" : path)); - } + private static final String DEFAULT_NAME = "Default"; + + private final int order; + private final String name; + private final String url; + private final boolean requiresAuth; + private final boolean alarm; + private final String excludeFilter; + private final String includeFilter; + private final String lastViewedItemUrl; + private Date lastViewed; + + public RssfeedSetting(int order, String name, String baseUrl, boolean needsAuth, boolean alarm, String excludeFilter, String includeFilter, Date lastViewed, + String lastViewedItemUrl) { + this.order = order; + this.name = name; + this.url = baseUrl; + this.requiresAuth = needsAuth; + this.alarm = alarm; + this.excludeFilter = excludeFilter; + this.includeFilter = includeFilter; + this.lastViewed = lastViewed; + this.lastViewedItemUrl = lastViewedItemUrl; + } + + public int getOrder() { + return order; + } + + @Override + public String getName() { + if (!TextUtils.isEmpty(name)) + return name; + if (!TextUtils.isEmpty(url)) { + String host = Uri.parse(url).getHost(); + return host == null ? DEFAULT_NAME : host; + } + return DEFAULT_NAME; + } + + public String getUrl() { + return url; + } + + public boolean requiresExternalAuthentication() { + return requiresAuth; + } + + public boolean shouldAlarmOnNewItems() { + return alarm; + } + + public String getExcludeFilter() { + return excludeFilter; + } + + public String getIncludeFilter() { + return includeFilter; + } + + /** + * Returns the date on which we last checked this feed. Note that this is NOT updated automatically after the + * settings were loaded from {@link ApplicationSettings}; instead the settings have to be manually loaded again + * using {@link ApplicationSettings#getRssfeedSetting(int)}. + * + * @return The last new item's URL as URL-encoded string + */ + public Date getLastViewed() { + return this.lastViewed; + } + + /** + * Returns the URL of the item that was the newest last time we checked this feed. Note that this is NOT updated + * automatically after the settings were loaded from {@link ApplicationSettings}; instead the settings have to be + * manually loaded again using {@link ApplicationSettings#getRssfeedSetting(int)}. + * + * @return The last new item's URL as URL-encoded string + */ + public String getLastViewedItemUrl() { + return this.lastViewedItemUrl; + } + + /** + * Returns a nicely formatted identifier containing (a portion of) the feed URL + * + * @return A string to identify this feed's URL + */ + public String getHumanReadableIdentifier() { + String host = Uri.parse(url).getHost(); + String path = Uri.parse(url).getPath(); + return (host == null ? null : host + (path == null ? "" : path)); + } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/ServerSetting.java b/app/src/main/java/org/transdroid/core/app/settings/ServerSetting.java index 5191b077..c3e061af 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/ServerSetting.java +++ b/app/src/main/java/org/transdroid/core/app/settings/ServerSetting.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -29,303 +29,309 @@ import org.transdroid.daemon.OS; /** * Represents a user-configured remote server. + * * @author Eric Kok */ public class ServerSetting implements SimpleListItem { - private static final String DEFAULT_NAME = "Default"; - - private final int key; - private final String name; - private final Daemon type; - private final String address; - private final String localAddress; - private final int localPort; - private final String localNetwork; - private final int port; - private final String folder; - private final boolean useAuthentication; - private final String username; - private final String password; - private final String extraPass; - private final OS os; - private final String downloadDir; - private final String ftpUrl; - private final String ftpPassword; - private final int timeout; - private final boolean alarmOnFinishedDownload; - private final boolean alarmOnNewTorrent; - private final boolean ssl; - private final boolean localSsl; - private final boolean sslTrustAll; - private final String sslTrustKey; - private final String excludeFilter; - private final String includeFilter; - private final boolean isAutoGenerated; - - /** - * Creates a daemon settings instance, providing full connection details - * @param name A name used to identify this server to the user - * @param type The server daemon type - * @param address The server domain name or IP address - * @param localAddress The server domain or IP address when connected to the server's local network - * @param localPort The port on which the server is running in the server's local network - * @param localNetwork The server's local network SSID - * @param port The port on which the server daemon is running - * @param sslTrustKey The specific key that will be accepted. - * @param folder The server folder (like a virtual sub-folder or an SCGI mount point) - * @param useAuthentication Whether to use basic authentication - * @param username The user name to provide during authentication - * @param password The password to provide during authentication - * @param extraPass The Deluge web interface password - * @param downloadDir The default download directory (which may also be used as base directory for file paths) - * @param ftpUrl The partial URL to connect to when requesting FTP-style transfers - * @param timeout The number of seconds to wait before timing out a connection attempt - * @param isAutoGenerated Whether this setting was generated rather than manually inputed by the user - */ - public ServerSetting(int key, String name, Daemon type, String address, String localAddress, int localPort, String localNetwork, int port, - boolean ssl, boolean localSsl, boolean sslTrustAll, String sslTrustKey, String folder, boolean useAuthentication, String username, - String password, String extraPass, OS os, String downloadDir, String ftpUrl, String ftpPassword, int timeout, - boolean alarmOnFinishedDownload, boolean alarmOnNewTorrent, String excludeFilter, String includeFilter, - boolean isAutoGenerated) { - this.key = key; - this.name = name; - this.type = type; - this.address = address; - this.localAddress = localAddress; - this.localPort = localPort; - this.localNetwork = localNetwork; - this.port = port; - this.ssl = ssl; - this.localSsl = localSsl; - this.sslTrustAll = sslTrustAll; - this.sslTrustKey = sslTrustKey; - this.folder = folder; - this.useAuthentication = useAuthentication; - this.username = username; - this.password = password; - this.extraPass = extraPass; - this.os = os; - this.downloadDir = downloadDir; - this.ftpUrl = ftpUrl; - this.ftpPassword = ftpPassword; - this.timeout = timeout; - this.alarmOnFinishedDownload = alarmOnFinishedDownload; - this.alarmOnNewTorrent = alarmOnNewTorrent; - this.excludeFilter = excludeFilter; - this.includeFilter = includeFilter; - this.isAutoGenerated = isAutoGenerated; - } - - @Override - public String getName() { - if (!TextUtils.isEmpty(name)) { - return name; - } - if (!TextUtils.isEmpty(address)) { - String host = Uri.parse(address).getHost(); - return host == null ? DEFAULT_NAME : host; - } - return DEFAULT_NAME; - } - - public Daemon getType() { - return type; - } - - public String getAddress() { - return address; - } - - public String getLocalAddress() { - return localAddress; - } - - public int getLocalPort() { - return localPort; - } - - public String getLocalNetwork() { - return localNetwork; - } - - public int getPort() { - return port; - } - - public boolean getSsl() { - return ssl; - } - - public boolean getLocalSsl() { - return localSsl; - } - - public boolean getSslTrustAll() { - return sslTrustAll; - } - - public String getSslTrustKey() { - return sslTrustKey; - } - - public String getFolder() { - return folder; - } - - public boolean shouldUseAuthentication() { - return useAuthentication; - } - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } - - public String getExtraPassword() { - return extraPass; - } - - public OS getOS() { - return os; - } - - public String getDownloadDir() { - return downloadDir; - } - - public String getFtpUrl() { - return ftpUrl; - } - - public String getFtpPassword() { - return ftpPassword; - } - - public int getTimeoutInMilliseconds() { - return timeout * 1000; - } - - public boolean shouldAlarmOnFinishedDownload() { - return alarmOnFinishedDownload; - } - - public boolean shouldAlarmOnNewTorrent() { - return alarmOnNewTorrent; - } - - public String getExcludeFilter() { - return excludeFilter; - } - - public String getIncludeFilter() { - return includeFilter; - } - - public boolean isAutoGenerated() { - return isAutoGenerated; - } - - public int getOrder() { - return this.key; - } - - /** - * Returns a string that the user can use to identify the server by internal settings (rather than the name). - * @return A human-readable identifier in the form [https://]username@address:port/folder - */ - public String getHumanReadableIdentifier() { - if (isAutoGenerated) { - // Hide the 'implementation details'; just give the username and server - return (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? - this.getUsername() + "@" : "") + getAddress(); - } - return (this.ssl ? "https://" : "http://") + - (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? this.getUsername() + "@" : - "") + getAddress() + ":" + getPort() + - (Daemon.supportsCustomFolder(getType()) && getFolder() != null ? getFolder() : ""); - } - - /** - * Returns a string that acts as a unique identifier for this server, non-depending on the internal storage - * order/index. THis may be used to store additional details about this server elsewhere. It may change if the user - * changes server settings, but not with name or notification settings. - * @return A unique identifying string, based primarily on the configured address, port number, SSL settings and - * user name; returns null if the server is not yet fully identifiable (during configuration, for example) - */ - public String getUniqueIdentifier() { - if (getType() == null || getAddress() == null || getAddress().equals("")) { - return null; - } - return getType().toString() + "|" + getHumanReadableIdentifier(); - } - - @Override - public boolean equals(Object o) { - if (o instanceof ServerSetting) { - // Directly compare order numbers/unique keys - return ((ServerSetting) o).getOrder() == this.key; - } else if (o instanceof DaemonSettings) { - // Old-style DaemonSettings objects can be equal if they were constructed from a ServerSettings object: - // idString should reflect the local key/order - return ((DaemonSettings) o).getIdString().equals(Integer.toString(this.key)); - } - // Other objects are never equal to this - return false; - } - - @Override - public String toString() { - return getUniqueIdentifier(); - } - - /** - * Returns the appropriate daemon adapter to which tasks can be executed, in accordance with this server's settings - * @param connectedToNetwork The name of the (wifi) network we are currently connected to, or null if this could not - * be determined - * @param context A context to access the logger - * @return An IDaemonAdapter instance of the specific torrent client daemon type - */ - public IDaemonAdapter createServerAdapter(String connectedToNetwork, Context context) { - return type.createAdapter(convertToDaemonSettings(connectedToNetwork, context)); - } - - /** - * Converts local server settings into an old-style {@link DaemonSettings} object. - * @param connectedToNetwork The name of the (wifi) network we are currently connected to, or null if this could not - * be determined - * @param caller A context to access the logger - * @return A {@link DaemonSettings} object to execute server commands against - */ - private DaemonSettings convertToDaemonSettings(String connectedToNetwork, Context caller) { - // The local integer key is converted to the idString string. - // The host name address used is dependent on the network that we are currently connected to (to allow a - // distinct connection IP or host name when connected to a local network). - if (!TextUtils.isEmpty(localNetwork)) { - Log_.getInstance_(caller) - .d("ServerSetting", "Creating adapter for " + name + " of type " + type.name() + ": connected to " + - connectedToNetwork + " and configured local network is " + localNetwork); - } - String addressToUse = address; - int portToUse = port; - boolean sslEnable = ssl; - if (!TextUtils.isEmpty(localNetwork) && !TextUtils.isEmpty(localAddress) && - !TextUtils.isEmpty(connectedToNetwork)) { - String[] localNetworks = localNetwork.split("\\|"); - for (String network : localNetworks) { - if (connectedToNetwork.equals(network)) { - addressToUse = localAddress; - portToUse = localPort; - sslEnable = localSsl; - break; - } - } - } - return new DaemonSettings(name, type, addressToUse, portToUse, sslEnable, sslTrustAll, sslTrustKey, folder, - useAuthentication, username, password, extraPass, os, downloadDir, ftpUrl, ftpPassword, timeout, - alarmOnFinishedDownload, alarmOnNewTorrent, Integer.toString(key), isAutoGenerated); - } + private static final String DEFAULT_NAME = "Default"; + + private final int key; + private final String name; + private final Daemon type; + private final String address; + private final String localAddress; + private final int localPort; + private final String localNetwork; + private final int port; + private final String folder; + private final boolean useAuthentication; + private final String username; + private final String password; + private final String extraPass; + private final OS os; + private final String downloadDir; + private final String ftpUrl; + private final String ftpPassword; + private final int timeout; + private final boolean alarmOnFinishedDownload; + private final boolean alarmOnNewTorrent; + private final boolean ssl; + private final boolean localSsl; + private final boolean sslTrustAll; + private final String sslTrustKey; + private final String excludeFilter; + private final String includeFilter; + private final boolean isAutoGenerated; + + /** + * Creates a daemon settings instance, providing full connection details + * + * @param name A name used to identify this server to the user + * @param type The server daemon type + * @param address The server domain name or IP address + * @param localAddress The server domain or IP address when connected to the server's local network + * @param localPort The port on which the server is running in the server's local network + * @param localNetwork The server's local network SSID + * @param port The port on which the server daemon is running + * @param sslTrustKey The specific key that will be accepted. + * @param folder The server folder (like a virtual sub-folder or an SCGI mount point) + * @param useAuthentication Whether to use basic authentication + * @param username The user name to provide during authentication + * @param password The password to provide during authentication + * @param extraPass The Deluge web interface password + * @param downloadDir The default download directory (which may also be used as base directory for file paths) + * @param ftpUrl The partial URL to connect to when requesting FTP-style transfers + * @param timeout The number of seconds to wait before timing out a connection attempt + * @param isAutoGenerated Whether this setting was generated rather than manually inputed by the user + */ + public ServerSetting(int key, String name, Daemon type, String address, String localAddress, int localPort, String localNetwork, int port, + boolean ssl, boolean localSsl, boolean sslTrustAll, String sslTrustKey, String folder, boolean useAuthentication, String username, + String password, String extraPass, OS os, String downloadDir, String ftpUrl, String ftpPassword, int timeout, + boolean alarmOnFinishedDownload, boolean alarmOnNewTorrent, String excludeFilter, String includeFilter, + boolean isAutoGenerated) { + this.key = key; + this.name = name; + this.type = type; + this.address = address; + this.localAddress = localAddress; + this.localPort = localPort; + this.localNetwork = localNetwork; + this.port = port; + this.ssl = ssl; + this.localSsl = localSsl; + this.sslTrustAll = sslTrustAll; + this.sslTrustKey = sslTrustKey; + this.folder = folder; + this.useAuthentication = useAuthentication; + this.username = username; + this.password = password; + this.extraPass = extraPass; + this.os = os; + this.downloadDir = downloadDir; + this.ftpUrl = ftpUrl; + this.ftpPassword = ftpPassword; + this.timeout = timeout; + this.alarmOnFinishedDownload = alarmOnFinishedDownload; + this.alarmOnNewTorrent = alarmOnNewTorrent; + this.excludeFilter = excludeFilter; + this.includeFilter = includeFilter; + this.isAutoGenerated = isAutoGenerated; + } + + @Override + public String getName() { + if (!TextUtils.isEmpty(name)) { + return name; + } + if (!TextUtils.isEmpty(address)) { + String host = Uri.parse(address).getHost(); + return host == null ? DEFAULT_NAME : host; + } + return DEFAULT_NAME; + } + + public Daemon getType() { + return type; + } + + public String getAddress() { + return address; + } + + public String getLocalAddress() { + return localAddress; + } + + public int getLocalPort() { + return localPort; + } + + public String getLocalNetwork() { + return localNetwork; + } + + public int getPort() { + return port; + } + + public boolean getSsl() { + return ssl; + } + + public boolean getLocalSsl() { + return localSsl; + } + + public boolean getSslTrustAll() { + return sslTrustAll; + } + + public String getSslTrustKey() { + return sslTrustKey; + } + + public String getFolder() { + return folder; + } + + public boolean shouldUseAuthentication() { + return useAuthentication; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getExtraPassword() { + return extraPass; + } + + public OS getOS() { + return os; + } + + public String getDownloadDir() { + return downloadDir; + } + + public String getFtpUrl() { + return ftpUrl; + } + + public String getFtpPassword() { + return ftpPassword; + } + + public int getTimeoutInMilliseconds() { + return timeout * 1000; + } + + public boolean shouldAlarmOnFinishedDownload() { + return alarmOnFinishedDownload; + } + + public boolean shouldAlarmOnNewTorrent() { + return alarmOnNewTorrent; + } + + public String getExcludeFilter() { + return excludeFilter; + } + + public String getIncludeFilter() { + return includeFilter; + } + + public boolean isAutoGenerated() { + return isAutoGenerated; + } + + public int getOrder() { + return this.key; + } + + /** + * Returns a string that the user can use to identify the server by internal settings (rather than the name). + * + * @return A human-readable identifier in the form [https://]username@address:port/folder + */ + public String getHumanReadableIdentifier() { + if (isAutoGenerated) { + // Hide the 'implementation details'; just give the username and server + return (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? + this.getUsername() + "@" : "") + getAddress(); + } + return (this.ssl ? "https://" : "http://") + + (this.shouldUseAuthentication() && !TextUtils.isEmpty(this.getUsername()) ? this.getUsername() + "@" : + "") + getAddress() + ":" + getPort() + + (Daemon.supportsCustomFolder(getType()) && getFolder() != null ? getFolder() : ""); + } + + /** + * Returns a string that acts as a unique identifier for this server, non-depending on the internal storage + * order/index. THis may be used to store additional details about this server elsewhere. It may change if the user + * changes server settings, but not with name or notification settings. + * + * @return A unique identifying string, based primarily on the configured address, port number, SSL settings and + * user name; returns null if the server is not yet fully identifiable (during configuration, for example) + */ + public String getUniqueIdentifier() { + if (getType() == null || getAddress() == null || getAddress().equals("")) { + return null; + } + return getType().toString() + "|" + getHumanReadableIdentifier(); + } + + @Override + public boolean equals(Object o) { + if (o instanceof ServerSetting) { + // Directly compare order numbers/unique keys + return ((ServerSetting) o).getOrder() == this.key; + } else if (o instanceof DaemonSettings) { + // Old-style DaemonSettings objects can be equal if they were constructed from a ServerSettings object: + // idString should reflect the local key/order + return ((DaemonSettings) o).getIdString().equals(Integer.toString(this.key)); + } + // Other objects are never equal to this + return false; + } + + @Override + public String toString() { + return getUniqueIdentifier(); + } + + /** + * Returns the appropriate daemon adapter to which tasks can be executed, in accordance with this server's settings + * + * @param connectedToNetwork The name of the (wifi) network we are currently connected to, or null if this could not + * be determined + * @param context A context to access the logger + * @return An IDaemonAdapter instance of the specific torrent client daemon type + */ + public IDaemonAdapter createServerAdapter(String connectedToNetwork, Context context) { + return type.createAdapter(convertToDaemonSettings(connectedToNetwork, context)); + } + + /** + * Converts local server settings into an old-style {@link DaemonSettings} object. + * + * @param connectedToNetwork The name of the (wifi) network we are currently connected to, or null if this could not + * be determined + * @param caller A context to access the logger + * @return A {@link DaemonSettings} object to execute server commands against + */ + private DaemonSettings convertToDaemonSettings(String connectedToNetwork, Context caller) { + // The local integer key is converted to the idString string. + // The host name address used is dependent on the network that we are currently connected to (to allow a + // distinct connection IP or host name when connected to a local network). + if (!TextUtils.isEmpty(localNetwork)) { + Log_.getInstance_(caller) + .d("ServerSetting", "Creating adapter for " + name + " of type " + type.name() + ": connected to " + + connectedToNetwork + " and configured local network is " + localNetwork); + } + String addressToUse = address; + int portToUse = port; + boolean sslEnable = ssl; + if (!TextUtils.isEmpty(localNetwork) && !TextUtils.isEmpty(localAddress) && + !TextUtils.isEmpty(connectedToNetwork)) { + String[] localNetworks = localNetwork.split("\\|"); + for (String network : localNetworks) { + if (connectedToNetwork.equals(network)) { + addressToUse = localAddress; + portToUse = localPort; + sslEnable = localSsl; + break; + } + } + } + return new DaemonSettings(name, type, addressToUse, portToUse, sslEnable, sslTrustAll, sslTrustKey, folder, + useAuthentication, username, password, extraPass, os, downloadDir, ftpUrl, ftpPassword, timeout, + alarmOnFinishedDownload, alarmOnNewTorrent, Integer.toString(key), isAutoGenerated); + } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java b/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java index 60781efa..6b639ec5 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java +++ b/app/src/main/java/org/transdroid/core/app/settings/SettingsPersistence.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -38,48 +38,50 @@ import java.io.OutputStream; /** * Singleton class that can persist user settings (servers, RSS feeds, etc.) to and from a plain text JSON file. - * + * * @author Eric Kok */ @EBean(scope = Scope.Singleton) public class SettingsPersistence { - @Bean - protected ApplicationSettings applicationSettings; - @Bean - protected SystemSettings systemSettings; - - public static final String DEFAULT_SETTINGS_DIR = Environment.getExternalStorageDirectory().toString() - + "/Transdroid/"; - public static final String DEFAULT_SETTINGS_FILENAME = "settings.json"; - public static final File DEFAULT_SETTINGS_FILE = new File(DEFAULT_SETTINGS_DIR + DEFAULT_SETTINGS_FILENAME); - - /** - * Reads the server, web searches, RSS feed, background service and system settings from a JSON-encoded String, such as when read via a QR code. - * @param prefs The application-global preferences object to write settings to - * @param contents The JSON-encoded settings as raw String - * @throws JSONException Thrown when the file did not contain valid JSON content - */ - public void importSettingsAsString(SharedPreferences prefs, String contents) throws JSONException { - importSettings(prefs, new JSONObject(contents)); - } - - /** - * Synchronously reads the server, web searches, RSS feed, background service and system settings from a file in - * JSON format. - * @param prefs The application-global preferences object to write settings to - * @param settingsFile The local file to read the settings from - * @throws FileNotFoundException Thrown when the settings file doesn't exist or couldn't be read - * @throws JSONException Thrown when the file did not contain valid JSON content - */ - public void importSettingsFromFile(SharedPreferences prefs, File settingsFile) throws FileNotFoundException, JSONException { + public static final String DEFAULT_SETTINGS_DIR = Environment.getExternalStorageDirectory().toString() + + "/Transdroid/"; + public static final String DEFAULT_SETTINGS_FILENAME = "settings.json"; + public static final File DEFAULT_SETTINGS_FILE = new File(DEFAULT_SETTINGS_DIR + DEFAULT_SETTINGS_FILENAME); + @Bean + protected ApplicationSettings applicationSettings; + @Bean + protected SystemSettings systemSettings; + + /** + * Reads the server, web searches, RSS feed, background service and system settings from a JSON-encoded String, such as when read via a QR code. + * + * @param prefs The application-global preferences object to write settings to + * @param contents The JSON-encoded settings as raw String + * @throws JSONException Thrown when the file did not contain valid JSON content + */ + public void importSettingsAsString(SharedPreferences prefs, String contents) throws JSONException { + importSettings(prefs, new JSONObject(contents)); + } + + /** + * Synchronously reads the server, web searches, RSS feed, background service and system settings from a file in + * JSON format. + * + * @param prefs The application-global preferences object to write settings to + * @param settingsFile The local file to read the settings from + * @throws FileNotFoundException Thrown when the settings file doesn't exist or couldn't be read + * @throws JSONException Thrown when the file did not contain valid JSON content + */ + public void importSettingsFromFile(SharedPreferences prefs, File settingsFile) throws FileNotFoundException, JSONException { importSettingsFromStream(prefs, new FileInputStream(settingsFile)); - } + } /** * Synchronously reads the server, web searches, RSS feed, background service and system settings from a stream (file) in * JSON format. - * @param prefs The application-global preferences object to write settings to + * + * @param prefs The application-global preferences object to write settings to * @param settingsStream The stream to read the settings from * @throws JSONException Thrown when the file did not contain valid JSON content */ @@ -88,287 +90,289 @@ public class SettingsPersistence { importSettings(prefs, new JSONObject(raw)); } - public void importSettings(SharedPreferences prefs, JSONObject json) throws JSONException { - - Editor editor = prefs.edit(); - - // Import servers - if (json.has("servers")) { - JSONArray servers = json.getJSONArray("servers"); - for (int i = 0; i < servers.length(); i++) { - JSONObject server = servers.getJSONObject(i); - String postfix = Integer.toString(applicationSettings.getMaxOfAllServers() + 1 + i); - - if (server.has("name")) - editor.putString("server_name_" + postfix, server.getString("name")); - if (server.has("type")) - editor.putString("server_type_" + postfix, server.getString("type")); - if (server.has("host")) - editor.putString("server_address_" + postfix, server.getString("host")); - if (server.has("local_network")) - editor.putString("server_localnetwork_" + postfix, server.getString("local_network")); - if (server.has("local_host")) - editor.putString("server_localaddress_" + postfix, server.getString("local_host")); - if (server.has("local_port")) - editor.putString("server_localport_" + postfix, server.getString("local_port")); - if (server.has("port")) - editor.putString("server_port_" + postfix, server.getString("port")); - if (server.has("ssl")) - editor.putBoolean("server_sslenabled_" + postfix, server.getBoolean("ssl")); - if (server.has("local_ssl")) - editor.putBoolean("server_localsslenabled_" + postfix, server.getBoolean("local_ssl")); - if (server.has("ssl_accept_all")) - editor.putBoolean("server_ssltrustall_" + postfix, server.getBoolean("ssl_accept_all")); - if (server.has("ssl_trust_key")) - editor.putString("server_ssltrustkey_" + postfix, server.getString("ssl_trust_key")); - if (server.has("folder")) - editor.putString("server_folder_" + postfix, server.getString("folder")); - if (server.has("use_auth")) - editor.putBoolean("server_disableauth_" + postfix, !server.getBoolean("use_auth")); - if (server.has("username")) - editor.putString("server_user_" + postfix, server.getString("username")); - if (server.has("password")) - editor.putString("server_pass_" + postfix, server.getString("password")); - if (server.has("extra_password")) - editor.putString("server_extrapass_" + postfix, server.getString("extra_password")); - if (server.has("os_type")) - editor.putString("server_os_" + postfix, server.getString("os_type")); - if (server.has("downloads_dir")) - editor.putString("server_downloaddir_" + postfix, server.getString("downloads_dir")); - if (server.has("base_ftp_url")) - editor.putString("server_ftpurl_" + postfix, server.getString("base_ftp_url")); - if (server.has("ftp_password")) - editor.putString("server_ftppass_" + postfix, server.getString("ftp_password")); - if (server.has("server_timeout")) - editor.putString("server_timeout_" + postfix, server.getString("server_timeout")); - if (server.has("download_alarm")) - editor.putBoolean("server_alarmfinished_" + postfix, server.getBoolean("download_alarm")); - if (server.has("new_torrent_alarm")) - editor.putBoolean("server_alarmnew_" + postfix, server.getBoolean("new_torrent_alarm")); - if (server.has("alarm_filter_exclude")) - editor.putString("server_alarmexclude_" + postfix, server.getString("alarm_filter_exclude")); - if (server.has("alarm_filter_include")) - editor.putString("server_alarminclude_" + postfix, server.getString("alarm_filter_include")); - - } - } - - // Import web search sites - if (json.has("websites")) { - JSONArray sites = json.getJSONArray("websites"); - for (int i = 0; i < sites.length(); i++) { - JSONObject site = sites.getJSONObject(i); - String postfix = Integer.toString(applicationSettings.getMaxWebsearch() + 1 + i); - - if (site.has("name")) - editor.putString("websearch_name_" + postfix, site.getString("name")); - if (site.has("url")) - editor.putString("websearch_baseurl_" + postfix, site.getString("url")); - if (site.has("cookies")) - editor.putString("websearch_cookies_" + postfix, site.getString("cookies")); - - } - } - - // Import RSS feeds - if (json.has("rssfeeds")) { - JSONArray feeds = json.getJSONArray("rssfeeds"); - for (int i = 0; i < feeds.length(); i++) { - JSONObject feed = feeds.getJSONObject(i); - String postfix = Integer.toString(applicationSettings.getMaxRssfeed() + 1 + i); - - if (feed.has("name")) - editor.putString("rssfeed_name_" + postfix, feed.getString("name")); - if (feed.has("url")) - editor.putString("rssfeed_url_" + postfix, feed.getString("url")); - if (feed.has("needs_auth")) - editor.putBoolean("rssfeed_reqauth_" + postfix, feed.getBoolean("needs_auth")); - if (feed.has("new_item_alarm")) - editor.putBoolean("rssfeed_alarmnew_" + postfix, feed.getBoolean("new_item_alarm")); - if (feed.has("alarm_filter_include")) - editor.putString("rssfeed_include_" + postfix, feed.getString("alarm_filter_include")); - if (feed.has("alarm_filter_exclude")) - editor.putString("rssfeed_exclude_" + postfix, feed.getString("alarm_filter_exclude")); - if (feed.has("last_seen_time")) - editor.putLong("rssfeed_lastviewed_" + postfix, feed.getLong("last_seen_time")); - if (feed.has("last_seen_item")) - editor.putString("rssfeed_lastvieweditemurl_" + postfix, feed.getString("last_seen_item")); - - } - } - - // Import background service and system settings - if (json.has("alarm_enabled_rss")) - editor.putBoolean("notifications_enabledrss", json.getBoolean("alarm_enabled_rss")); - if (json.has("alarm_enabled_torrents")) - editor.putBoolean("notifications_enabled", json.getBoolean("alarm_enabled_torrents")); - else if (json.has("alarm_enabled")) // Compat - editor.putBoolean("notifications_enabled", json.getBoolean("alarm_enabled")); - if (json.has("alarm_interval")) - editor.putString("notifications_interval", json.getString("alarm_interval")); - if (json.has("alarm_sound_uri")) - editor.putString("notifications_sound", json.getString("alarm_sound_uri")); - if (json.has("alarm_vibrate")) - editor.putBoolean("notifications_vibrate", json.getBoolean("alarm_vibrate")); - if (json.has("alarm_ledcolour")) - editor.putInt("notifications_ledcolour", json.getInt("alarm_ledcolour")); - if (json.has("alarm_adwnotifications")) - editor.putBoolean("notifications_adwnotify", json.getBoolean("alarm_adwnotifications")); - if (json.has("system_dormantasinactive")) - editor.putBoolean("system_dormantasinactive", json.getBoolean("system_dormantasinactive")); - if (json.has("system_autorefresh")) - editor.putString("system_autorefresh", json.getString("system_autorefresh")); - if (json.has("system_checkupdates")) - editor.putBoolean("system_checkupdates", json.getBoolean("system_checkupdates")); - if (json.has("system_usedarktheme")) - editor.putBoolean("system_usedarktheme", json.getBoolean("system_usedarktheme")); - - editor.apply(); - - } - - /** - * Returns encoded server, web searches, RSS feed, background service and system settings as a JSON data object structure, serialized to a String. - * @param prefs The application-global preferences object to read settings from - * @throws JSONException Thrown when the JSON content could not be constructed properly - */ - public String exportSettingsAsString(SharedPreferences prefs) throws JSONException { - return exportSettings(prefs).toString(); - } - - /** - * Synchronously writes the server, web searches, RSS feed, background service and system settings to a file in JSON - * format. - * @param prefs The application-global preferences object to read settings from - * @param settingsFile The local file to read the settings from - * @throws JSONException Thrown when the JSON content could not be constructed properly - * @throws IOException Thrown when the settings file could not be created or written to - */ - public void exportSettingsToFile(SharedPreferences prefs, File settingsFile) throws JSONException, IOException { - if (settingsFile.exists()) { - settingsFile.delete(); - } - settingsFile.getParentFile().mkdirs(); - settingsFile.createNewFile(); - exportSettingsToStream(prefs, new FileOutputStream(settingsFile)); - } - - /** - * Synchronously writes the server, web searches, RSS feed, background service and system settings to a stream (file) in JSON format. The stream - * will be closed regardless of success. - * - * @param prefs The application-global preferences object to read settings from - * @param settingsStream The stream to read the settings to - * @throws JSONException Thrown when the JSON content could not be constructed properly - * @throws IOException Thrown when the settings file could not be created or written to - */ - public void exportSettingsToStream(SharedPreferences prefs, OutputStream settingsStream) throws JSONException, IOException { - try { - JSONObject json = exportSettings(prefs); - settingsStream.write(json.toString(2).getBytes()); - } finally { - settingsStream.close(); - } - } - - private JSONObject exportSettings(SharedPreferences prefs) throws JSONException { - - // Create a single JSON object that will contain all settings - JSONObject json = new JSONObject(); - - // Convert server settings into JSON - JSONArray servers = new JSONArray(); - int i = 0; - String postfixi = "0"; - while (prefs.contains("server_type_" + postfixi)) { - - JSONObject server = new JSONObject(); - server.put("name", prefs.getString("server_name_" + postfixi, null)); - server.put("type", prefs.getString("server_type_" + postfixi, null)); - server.put("host", prefs.getString("server_address_" + postfixi, null)); - server.put("local_network", prefs.getString("server_localnetwork_" + postfixi, null)); - server.put("local_host", prefs.getString("server_localaddress_" + postfixi, null)); - server.put("local_port", prefs.getString("server_localport_" + postfixi, null)); - server.put("port", prefs.getString("server_port_" + postfixi, null)); - server.put("ssl", prefs.getBoolean("server_sslenabled_" + postfixi, false)); - server.put("local_ssl", prefs.getBoolean("server_localsslenabled_" + postfixi, false)); - server.put("ssl_accept_all", prefs.getBoolean("server_ssltrustall_" + postfixi, false)); - server.put("ssl_trust_key", prefs.getString("server_ssltrustkey_" + postfixi, null)); - server.put("folder", prefs.getString("server_folder_" + postfixi, null)); - server.put("use_auth", !prefs.getBoolean("server_disableauth_" + postfixi, false)); - server.put("username", prefs.getString("server_user_" + postfixi, null)); - server.put("password", prefs.getString("server_pass_" + postfixi, null)); - server.put("extra_password", prefs.getString("server_extrapass_" + postfixi, null)); - server.put("os_type", prefs.getString("server_os_" + postfixi, null)); - server.put("downloads_dir", prefs.getString("server_downloaddir_" + postfixi, null)); - server.put("base_ftp_url", prefs.getString("server_ftpurl_" + postfixi, null)); - server.put("ftp_password", prefs.getString("server_ftppass_" + postfixi, null)); - server.put("server_timeout", prefs.getString("server_timeout_" + postfixi, null)); - server.put("download_alarm", prefs.getBoolean("server_alarmfinished_" + postfixi, false)); - server.put("new_torrent_alarm", prefs.getBoolean("server_alarmnew_" + postfixi, false)); - server.put("alarm_filter_exclude", prefs.getString("server_alarmexclude_" + postfixi, null)); - server.put("alarm_filter_include", prefs.getString("server_alarminclude_" + postfixi, null)); - - servers.put(server); - i++; - postfixi = Integer.toString(i); - } - json.put("servers", servers); - - // Convert web search settings into JSON - JSONArray sites = new JSONArray(); - int j = 0; - String postfixj = "0"; - while (prefs.contains("websearch_baseurl_" + postfixj)) { - - JSONObject site = new JSONObject(); - site.put("name", prefs.getString("websearch_name_" + postfixj, null)); - site.put("url", prefs.getString("websearch_baseurl_" + postfixj, null)); - site.put("cookies", prefs.getString("websearch_cookies_" + postfixj, null)); - - sites.put(site); - j++; - postfixj = Integer.toString(j); - } - json.put("websites", sites); - - // Convert RSS feed settings into JSON - JSONArray feeds = new JSONArray(); - int k = 0; - String postfixk = "0"; - while (prefs.contains("rssfeed_url_" + postfixk)) { - - JSONObject feed = new JSONObject(); - feed.put("name", prefs.getString("rssfeed_name_" + postfixk, null)); - feed.put("url", prefs.getString("rssfeed_url_" + postfixk, null)); - feed.put("needs_auth", prefs.getBoolean("rssfeed_reqauth_" + postfixk, false)); - feed.put("new_item_alarm", prefs.getBoolean("rssfeed_alarmnew_" + postfixk, false)); - feed.put("alarm_filter_exclude", prefs.getString("rssfeed_exclude_" + postfixk, null)); - feed.put("alarm_filter_include", prefs.getString("rssfeed_include_" + postfixk, null)); - feed.put("last_seen_time", prefs.getLong("rssfeed_lastviewed_" + postfixk, -1)); - feed.put("last_seen_item", prefs.getString("rssfeed_lastvieweditemurl_" + postfixk, null)); - - feeds.put(feed); - k++; - postfixk = Integer.toString(k); - } - json.put("rssfeeds", feeds); - - // Convert background service and system settings into JSON - json.put("alarm_enabled_rss", prefs.getBoolean("notifications_enabledrss", true)); - json.put("alarm_enabled_torrents", prefs.getBoolean("notifications_enabled", true)); - json.put("alarm_interval", prefs.getString("notifications_interval", null)); - json.put("alarm_sound_uri", prefs.getString("notifications_sound", null)); - json.put("alarm_vibrate", prefs.getBoolean("notifications_vibrate", false)); - json.put("alarm_ledcolour", prefs.getInt("notifications_ledcolour", -1)); - json.put("alarm_adwnotifications", prefs.getBoolean("notifications_adwnotify", false)); - json.put("system_dormantasinactive", prefs.getBoolean("system_dormantasinactive", false)); - json.put("system_autorefresh", prefs.getString("system_autorefresh", "0")); - json.put("system_usedarktheme", prefs.getBoolean("system_usedarktheme", false)); - json.put("system_checkupdates", prefs.getBoolean("system_checkupdates", true)); - - return json; - - } - + public void importSettings(SharedPreferences prefs, JSONObject json) throws JSONException { + + Editor editor = prefs.edit(); + + // Import servers + if (json.has("servers")) { + JSONArray servers = json.getJSONArray("servers"); + for (int i = 0; i < servers.length(); i++) { + JSONObject server = servers.getJSONObject(i); + String postfix = Integer.toString(applicationSettings.getMaxOfAllServers() + 1 + i); + + if (server.has("name")) + editor.putString("server_name_" + postfix, server.getString("name")); + if (server.has("type")) + editor.putString("server_type_" + postfix, server.getString("type")); + if (server.has("host")) + editor.putString("server_address_" + postfix, server.getString("host")); + if (server.has("local_network")) + editor.putString("server_localnetwork_" + postfix, server.getString("local_network")); + if (server.has("local_host")) + editor.putString("server_localaddress_" + postfix, server.getString("local_host")); + if (server.has("local_port")) + editor.putString("server_localport_" + postfix, server.getString("local_port")); + if (server.has("port")) + editor.putString("server_port_" + postfix, server.getString("port")); + if (server.has("ssl")) + editor.putBoolean("server_sslenabled_" + postfix, server.getBoolean("ssl")); + if (server.has("local_ssl")) + editor.putBoolean("server_localsslenabled_" + postfix, server.getBoolean("local_ssl")); + if (server.has("ssl_accept_all")) + editor.putBoolean("server_ssltrustall_" + postfix, server.getBoolean("ssl_accept_all")); + if (server.has("ssl_trust_key")) + editor.putString("server_ssltrustkey_" + postfix, server.getString("ssl_trust_key")); + if (server.has("folder")) + editor.putString("server_folder_" + postfix, server.getString("folder")); + if (server.has("use_auth")) + editor.putBoolean("server_disableauth_" + postfix, !server.getBoolean("use_auth")); + if (server.has("username")) + editor.putString("server_user_" + postfix, server.getString("username")); + if (server.has("password")) + editor.putString("server_pass_" + postfix, server.getString("password")); + if (server.has("extra_password")) + editor.putString("server_extrapass_" + postfix, server.getString("extra_password")); + if (server.has("os_type")) + editor.putString("server_os_" + postfix, server.getString("os_type")); + if (server.has("downloads_dir")) + editor.putString("server_downloaddir_" + postfix, server.getString("downloads_dir")); + if (server.has("base_ftp_url")) + editor.putString("server_ftpurl_" + postfix, server.getString("base_ftp_url")); + if (server.has("ftp_password")) + editor.putString("server_ftppass_" + postfix, server.getString("ftp_password")); + if (server.has("server_timeout")) + editor.putString("server_timeout_" + postfix, server.getString("server_timeout")); + if (server.has("download_alarm")) + editor.putBoolean("server_alarmfinished_" + postfix, server.getBoolean("download_alarm")); + if (server.has("new_torrent_alarm")) + editor.putBoolean("server_alarmnew_" + postfix, server.getBoolean("new_torrent_alarm")); + if (server.has("alarm_filter_exclude")) + editor.putString("server_alarmexclude_" + postfix, server.getString("alarm_filter_exclude")); + if (server.has("alarm_filter_include")) + editor.putString("server_alarminclude_" + postfix, server.getString("alarm_filter_include")); + + } + } + + // Import web search sites + if (json.has("websites")) { + JSONArray sites = json.getJSONArray("websites"); + for (int i = 0; i < sites.length(); i++) { + JSONObject site = sites.getJSONObject(i); + String postfix = Integer.toString(applicationSettings.getMaxWebsearch() + 1 + i); + + if (site.has("name")) + editor.putString("websearch_name_" + postfix, site.getString("name")); + if (site.has("url")) + editor.putString("websearch_baseurl_" + postfix, site.getString("url")); + if (site.has("cookies")) + editor.putString("websearch_cookies_" + postfix, site.getString("cookies")); + + } + } + + // Import RSS feeds + if (json.has("rssfeeds")) { + JSONArray feeds = json.getJSONArray("rssfeeds"); + for (int i = 0; i < feeds.length(); i++) { + JSONObject feed = feeds.getJSONObject(i); + String postfix = Integer.toString(applicationSettings.getMaxRssfeed() + 1 + i); + + if (feed.has("name")) + editor.putString("rssfeed_name_" + postfix, feed.getString("name")); + if (feed.has("url")) + editor.putString("rssfeed_url_" + postfix, feed.getString("url")); + if (feed.has("needs_auth")) + editor.putBoolean("rssfeed_reqauth_" + postfix, feed.getBoolean("needs_auth")); + if (feed.has("new_item_alarm")) + editor.putBoolean("rssfeed_alarmnew_" + postfix, feed.getBoolean("new_item_alarm")); + if (feed.has("alarm_filter_include")) + editor.putString("rssfeed_include_" + postfix, feed.getString("alarm_filter_include")); + if (feed.has("alarm_filter_exclude")) + editor.putString("rssfeed_exclude_" + postfix, feed.getString("alarm_filter_exclude")); + if (feed.has("last_seen_time")) + editor.putLong("rssfeed_lastviewed_" + postfix, feed.getLong("last_seen_time")); + if (feed.has("last_seen_item")) + editor.putString("rssfeed_lastvieweditemurl_" + postfix, feed.getString("last_seen_item")); + + } + } + + // Import background service and system settings + if (json.has("alarm_enabled_rss")) + editor.putBoolean("notifications_enabledrss", json.getBoolean("alarm_enabled_rss")); + if (json.has("alarm_enabled_torrents")) + editor.putBoolean("notifications_enabled", json.getBoolean("alarm_enabled_torrents")); + else if (json.has("alarm_enabled")) // Compat + editor.putBoolean("notifications_enabled", json.getBoolean("alarm_enabled")); + if (json.has("alarm_interval")) + editor.putString("notifications_interval", json.getString("alarm_interval")); + if (json.has("alarm_sound_uri")) + editor.putString("notifications_sound", json.getString("alarm_sound_uri")); + if (json.has("alarm_vibrate")) + editor.putBoolean("notifications_vibrate", json.getBoolean("alarm_vibrate")); + if (json.has("alarm_ledcolour")) + editor.putInt("notifications_ledcolour", json.getInt("alarm_ledcolour")); + if (json.has("alarm_adwnotifications")) + editor.putBoolean("notifications_adwnotify", json.getBoolean("alarm_adwnotifications")); + if (json.has("system_dormantasinactive")) + editor.putBoolean("system_dormantasinactive", json.getBoolean("system_dormantasinactive")); + if (json.has("system_autorefresh")) + editor.putString("system_autorefresh", json.getString("system_autorefresh")); + if (json.has("system_checkupdates")) + editor.putBoolean("system_checkupdates", json.getBoolean("system_checkupdates")); + if (json.has("system_usedarktheme")) + editor.putBoolean("system_usedarktheme", json.getBoolean("system_usedarktheme")); + + editor.apply(); + + } + + /** + * Returns encoded server, web searches, RSS feed, background service and system settings as a JSON data object structure, serialized to a String. + * + * @param prefs The application-global preferences object to read settings from + * @throws JSONException Thrown when the JSON content could not be constructed properly + */ + public String exportSettingsAsString(SharedPreferences prefs) throws JSONException { + return exportSettings(prefs).toString(); + } + + /** + * Synchronously writes the server, web searches, RSS feed, background service and system settings to a file in JSON + * format. + * + * @param prefs The application-global preferences object to read settings from + * @param settingsFile The local file to read the settings from + * @throws JSONException Thrown when the JSON content could not be constructed properly + * @throws IOException Thrown when the settings file could not be created or written to + */ + public void exportSettingsToFile(SharedPreferences prefs, File settingsFile) throws JSONException, IOException { + if (settingsFile.exists()) { + settingsFile.delete(); + } + settingsFile.getParentFile().mkdirs(); + settingsFile.createNewFile(); + exportSettingsToStream(prefs, new FileOutputStream(settingsFile)); + } + + /** + * Synchronously writes the server, web searches, RSS feed, background service and system settings to a stream (file) in JSON format. The stream + * will be closed regardless of success. + * + * @param prefs The application-global preferences object to read settings from + * @param settingsStream The stream to read the settings to + * @throws JSONException Thrown when the JSON content could not be constructed properly + * @throws IOException Thrown when the settings file could not be created or written to + */ + public void exportSettingsToStream(SharedPreferences prefs, OutputStream settingsStream) throws JSONException, IOException { + try { + JSONObject json = exportSettings(prefs); + settingsStream.write(json.toString(2).getBytes()); + } finally { + settingsStream.close(); + } + } + + private JSONObject exportSettings(SharedPreferences prefs) throws JSONException { + + // Create a single JSON object that will contain all settings + JSONObject json = new JSONObject(); + + // Convert server settings into JSON + JSONArray servers = new JSONArray(); + int i = 0; + String postfixi = "0"; + while (prefs.contains("server_type_" + postfixi)) { + + JSONObject server = new JSONObject(); + server.put("name", prefs.getString("server_name_" + postfixi, null)); + server.put("type", prefs.getString("server_type_" + postfixi, null)); + server.put("host", prefs.getString("server_address_" + postfixi, null)); + server.put("local_network", prefs.getString("server_localnetwork_" + postfixi, null)); + server.put("local_host", prefs.getString("server_localaddress_" + postfixi, null)); + server.put("local_port", prefs.getString("server_localport_" + postfixi, null)); + server.put("port", prefs.getString("server_port_" + postfixi, null)); + server.put("ssl", prefs.getBoolean("server_sslenabled_" + postfixi, false)); + server.put("local_ssl", prefs.getBoolean("server_localsslenabled_" + postfixi, false)); + server.put("ssl_accept_all", prefs.getBoolean("server_ssltrustall_" + postfixi, false)); + server.put("ssl_trust_key", prefs.getString("server_ssltrustkey_" + postfixi, null)); + server.put("folder", prefs.getString("server_folder_" + postfixi, null)); + server.put("use_auth", !prefs.getBoolean("server_disableauth_" + postfixi, false)); + server.put("username", prefs.getString("server_user_" + postfixi, null)); + server.put("password", prefs.getString("server_pass_" + postfixi, null)); + server.put("extra_password", prefs.getString("server_extrapass_" + postfixi, null)); + server.put("os_type", prefs.getString("server_os_" + postfixi, null)); + server.put("downloads_dir", prefs.getString("server_downloaddir_" + postfixi, null)); + server.put("base_ftp_url", prefs.getString("server_ftpurl_" + postfixi, null)); + server.put("ftp_password", prefs.getString("server_ftppass_" + postfixi, null)); + server.put("server_timeout", prefs.getString("server_timeout_" + postfixi, null)); + server.put("download_alarm", prefs.getBoolean("server_alarmfinished_" + postfixi, false)); + server.put("new_torrent_alarm", prefs.getBoolean("server_alarmnew_" + postfixi, false)); + server.put("alarm_filter_exclude", prefs.getString("server_alarmexclude_" + postfixi, null)); + server.put("alarm_filter_include", prefs.getString("server_alarminclude_" + postfixi, null)); + + servers.put(server); + i++; + postfixi = Integer.toString(i); + } + json.put("servers", servers); + + // Convert web search settings into JSON + JSONArray sites = new JSONArray(); + int j = 0; + String postfixj = "0"; + while (prefs.contains("websearch_baseurl_" + postfixj)) { + + JSONObject site = new JSONObject(); + site.put("name", prefs.getString("websearch_name_" + postfixj, null)); + site.put("url", prefs.getString("websearch_baseurl_" + postfixj, null)); + site.put("cookies", prefs.getString("websearch_cookies_" + postfixj, null)); + + sites.put(site); + j++; + postfixj = Integer.toString(j); + } + json.put("websites", sites); + + // Convert RSS feed settings into JSON + JSONArray feeds = new JSONArray(); + int k = 0; + String postfixk = "0"; + while (prefs.contains("rssfeed_url_" + postfixk)) { + + JSONObject feed = new JSONObject(); + feed.put("name", prefs.getString("rssfeed_name_" + postfixk, null)); + feed.put("url", prefs.getString("rssfeed_url_" + postfixk, null)); + feed.put("needs_auth", prefs.getBoolean("rssfeed_reqauth_" + postfixk, false)); + feed.put("new_item_alarm", prefs.getBoolean("rssfeed_alarmnew_" + postfixk, false)); + feed.put("alarm_filter_exclude", prefs.getString("rssfeed_exclude_" + postfixk, null)); + feed.put("alarm_filter_include", prefs.getString("rssfeed_include_" + postfixk, null)); + feed.put("last_seen_time", prefs.getLong("rssfeed_lastviewed_" + postfixk, -1)); + feed.put("last_seen_item", prefs.getString("rssfeed_lastvieweditemurl_" + postfixk, null)); + + feeds.put(feed); + k++; + postfixk = Integer.toString(k); + } + json.put("rssfeeds", feeds); + + // Convert background service and system settings into JSON + json.put("alarm_enabled_rss", prefs.getBoolean("notifications_enabledrss", true)); + json.put("alarm_enabled_torrents", prefs.getBoolean("notifications_enabled", true)); + json.put("alarm_interval", prefs.getString("notifications_interval", null)); + json.put("alarm_sound_uri", prefs.getString("notifications_sound", null)); + json.put("alarm_vibrate", prefs.getBoolean("notifications_vibrate", false)); + json.put("alarm_ledcolour", prefs.getInt("notifications_ledcolour", -1)); + json.put("alarm_adwnotifications", prefs.getBoolean("notifications_adwnotify", false)); + json.put("system_dormantasinactive", prefs.getBoolean("system_dormantasinactive", false)); + json.put("system_autorefresh", prefs.getString("system_autorefresh", "0")); + json.put("system_usedarktheme", prefs.getBoolean("system_usedarktheme", false)); + json.put("system_checkupdates", prefs.getBoolean("system_checkupdates", true)); + + return json; + + } + } diff --git a/app/src/main/java/org/transdroid/core/app/settings/SettingsUtils.java b/app/src/main/java/org/transdroid/core/app/settings/SettingsUtils.java index 1c5a2834..bf54a1ce 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/SettingsUtils.java +++ b/app/src/main/java/org/transdroid/core/app/settings/SettingsUtils.java @@ -1,7 +1,6 @@ package org.transdroid.core.app.settings; -import android.content.Context; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; @@ -33,6 +32,6 @@ public class SettingsUtils { return builder; } - return builder.theme(settings.useDarkTheme() ? Theme.DARK: Theme.LIGHT); + return builder.theme(settings.useDarkTheme() ? Theme.DARK : Theme.LIGHT); } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java b/app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java index 23bc3af9..7ec5a9ae 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java +++ b/app/src/main/java/org/transdroid/core/app/settings/SystemSettings.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -29,58 +29,62 @@ import java.util.Date; /** * Allows instantiation of the settings specified in R.xml.pref_system. + * * @author Eric Kok */ @EBean(scope = Scope.Singleton) public class SystemSettings { - @RootContext - protected Context context; - private SharedPreferences prefs; + @RootContext + protected Context context; + private SharedPreferences prefs; - protected SystemSettings(Context context) { - prefs = PreferenceManager.getDefaultSharedPreferences(context); - } + protected SystemSettings(Context context) { + prefs = PreferenceManager.getDefaultSharedPreferences(context); + } - public boolean treatDormantAsInactive() { - return prefs.getBoolean("system_dormantasinactive", false); - } + public boolean treatDormantAsInactive() { + return prefs.getBoolean("system_dormantasinactive", false); + } - /** - * Returns the interval in which automatic screen refreshes should be scheduled. - * @return The selected refresh interval in milliseconds or 0 if automatic refreshes should be disabled - */ - public long getRefreshIntervalMilliseconds() { - return Integer.parseInt(prefs.getString("system_autorefresh", "0")) * 1000; - } + /** + * Returns the interval in which automatic screen refreshes should be scheduled. + * + * @return The selected refresh interval in milliseconds or 0 if automatic refreshes should be disabled + */ + public long getRefreshIntervalMilliseconds() { + return Integer.parseInt(prefs.getString("system_autorefresh", "0")) * 1000; + } - public boolean checkForUpdates() { - return prefs.getBoolean("system_checkupdates", true); - } + public boolean checkForUpdates() { + return prefs.getBoolean("system_checkupdates", true); + } - public boolean autoDarkTheme() { - return prefs.getBoolean("system_autodarktheme", true); - } + public boolean autoDarkTheme() { + return prefs.getBoolean("system_autodarktheme", true); + } - public boolean useDarkTheme() { - return prefs.getBoolean("system_usedarktheme", false); - } + public boolean useDarkTheme() { + return prefs.getBoolean("system_usedarktheme", false); + } - /** - * Returns the date when we last checked transdroid.org for the latest app version. - * @return The date/time when the {@link org.transdroid.core.service.AppUpdateJob} checked on the server for updates - */ - public Date getLastCheckedForAppUpdates() { - long lastChecked = prefs.getLong("system_lastappupdatecheck", -1L); - return lastChecked == -1 ? null : new Date(lastChecked); - } + /** + * Returns the date when we last checked transdroid.org for the latest app version. + * + * @return The date/time when the {@link org.transdroid.core.service.AppUpdateJob} checked on the server for updates + */ + public Date getLastCheckedForAppUpdates() { + long lastChecked = prefs.getLong("system_lastappupdatecheck", -1L); + return lastChecked == -1 ? null : new Date(lastChecked); + } - /** - * Stores the date at which was last successfully, fully checked for new updates to the app. - * @param lastChecked The date/time at which the {@link org.transdroid.core.service.AppUpdateJob} last checked the server for updates - */ - public void setLastCheckedForAppUpdates(Date lastChecked) { - prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).apply(); - } + /** + * Stores the date at which was last successfully, fully checked for new updates to the app. + * + * @param lastChecked The date/time at which the {@link org.transdroid.core.service.AppUpdateJob} last checked the server for updates + */ + public void setLastCheckedForAppUpdates(Date lastChecked) { + prefs.edit().putLong("system_lastappupdatecheck", lastChecked == null ? -1L : lastChecked.getTime()).apply(); + } } diff --git a/app/src/main/java/org/transdroid/core/app/settings/WebsearchSetting.java b/app/src/main/java/org/transdroid/core/app/settings/WebsearchSetting.java index 3e251c09..d1bfd2c3 100644 --- a/app/src/main/java/org/transdroid/core/app/settings/WebsearchSetting.java +++ b/app/src/main/java/org/transdroid/core/app/settings/WebsearchSetting.java @@ -1,81 +1,82 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ package org.transdroid.core.app.settings; -import org.transdroid.core.gui.lists.SimpleListItem; -import org.transdroid.core.gui.search.SearchSetting; - import android.net.Uri; import android.text.TextUtils; +import org.transdroid.core.gui.lists.SimpleListItem; +import org.transdroid.core.gui.search.SearchSetting; + /** * Represents a user-specified website that can be searched (by starting the browser, rather than in-app) + * * @author Eric Kok */ public class WebsearchSetting implements SimpleListItem, SearchSetting { - private static final String DEFAULT_NAME = "Default"; - public static final String KEY_PREFIX = "websearch_"; - - private final int order; - private final String name; - private final String baseUrl; - private final String cookies; + public static final String KEY_PREFIX = "websearch_"; + private static final String DEFAULT_NAME = "Default"; + private final int order; + private final String name; + private final String baseUrl; + private final String cookies; + + public WebsearchSetting(int order, String name, String baseUrl, String cookies) { + this.order = order; + this.name = name; + this.baseUrl = baseUrl; + this.cookies = cookies; + } + + public int getOrder() { + return order; + } + + @Override + public String getName() { + if (!TextUtils.isEmpty(name)) + return name; + if (!TextUtils.isEmpty(baseUrl)) { + String host = Uri.parse(baseUrl).getHost(); + return host == null ? DEFAULT_NAME : host; + } + return DEFAULT_NAME; + } - public WebsearchSetting(int order, String name, String baseUrl, String cookies) { - this.order = order; - this.name = name; - this.baseUrl = baseUrl; - this.cookies = cookies; - } + public String getBaseUrl() { + return baseUrl; + } - public int getOrder() { - return order; - } + public String getCookies() { + return cookies; + } - @Override - public String getName() { - if (!TextUtils.isEmpty(name)) - return name; - if (!TextUtils.isEmpty(baseUrl)) { - String host = Uri.parse(baseUrl).getHost(); - return host == null? DEFAULT_NAME: host; - } - return DEFAULT_NAME; - } - - public String getBaseUrl() { - return baseUrl; - } + public String getKey() { + return KEY_PREFIX + getOrder(); + } - public String getCookies() { - return cookies; - } - - public String getKey() { - return KEY_PREFIX + getOrder(); - } + /** + * Returns a nicely formatted identifier containing (a portion of) the search base URL + * + * @return A string to identify this site's search URL + */ + public String getHumanReadableIdentifier() { + return Uri.parse(baseUrl).getHost(); + } - /** - * Returns a nicely formatted identifier containing (a portion of) the search base URL - * @return A string to identify this site's search URL - */ - public String getHumanReadableIdentifier() { - return Uri.parse(baseUrl).getHost(); - } - } diff --git a/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java b/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java index 2dc28601..41fdd85f 100644 --- a/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java +++ b/app/src/main/java/org/transdroid/core/gui/DetailsActivity.java @@ -1,16 +1,16 @@ -/* +/* * Copyright 2010-2018 Eric Kok et al. - * + * * Transdroid 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. - * + * * Transdroid 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 Transdroid. If not, see . */ @@ -20,6 +20,7 @@ import android.annotation.TargetApi; import android.content.Intent; import android.os.Build; import android.os.Bundle; + import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; @@ -56,8 +57,6 @@ import org.transdroid.daemon.TorrentFile; import org.transdroid.daemon.task.DaemonTaskFailureResult; import org.transdroid.daemon.task.DaemonTaskResult; import org.transdroid.daemon.task.DaemonTaskSuccessResult; -import org.transdroid.daemon.task.ToggleSequentialDownloadTask; -import org.transdroid.daemon.task.ToggleFirstLastPieceDownloadTask; import org.transdroid.daemon.task.ForceRecheckTask; import org.transdroid.daemon.task.GetFileListTask; import org.transdroid.daemon.task.GetFileListTaskSuccessResult; @@ -74,6 +73,8 @@ import org.transdroid.daemon.task.SetLabelTask; import org.transdroid.daemon.task.SetTrackersTask; import org.transdroid.daemon.task.StartTask; import org.transdroid.daemon.task.StopTask; +import org.transdroid.daemon.task.ToggleFirstLastPieceDownloadTask; +import org.transdroid.daemon.task.ToggleSequentialDownloadTask; import java.util.ArrayList; import java.util.List; @@ -82,318 +83,318 @@ import java.util.List; * An activity that holds a single torrents details fragment. It is used on devices (i.e. phones) where there is no room to show details in the {@link * TorrentsActivity} directly. Task execution, such as loading of more details and updating file priorities, is performed in this activity via * background methods. + * * @author Eric Kok */ @EActivity(R.layout.activity_details) @OptionsMenu(R.menu.activity_details) public class DetailsActivity extends AppCompatActivity implements TorrentTasksExecutor, RefreshableActivity { - @Extra - @InstanceState - protected Torrent torrent; - @Extra - @InstanceState - protected ArrayList