From 8204bd56a761e867b950f9788f1a32716d1ad5c5 Mon Sep 17 00:00:00 2001 From: TacoTheDank Date: Fri, 10 Jul 2020 16:16:00 -0400 Subject: [PATCH] Adjust codestyle to an .editorconfig --- .editorconfig | 9 + app/src/main/AndroidManifest.xml | 633 +++-- .../preference/PreferenceManagerBinder.java | 3 +- .../core/app/search/SearchHelper.java | 270 +- .../core/app/search/SearchResult.java | 191 +- .../core/app/search/SearchSite.java | 77 +- .../app/settings/ApplicationSettings.java | 1476 +++++----- .../app/settings/NotificationSettings.java | 202 +- .../core/app/settings/RssfeedSetting.java | 190 +- .../core/app/settings/ServerSetting.java | 604 ++-- .../app/settings/SettingsPersistence.java | 643 ++--- .../core/app/settings/SettingsUtils.java | 3 +- .../core/app/settings/SystemSettings.java | 92 +- .../core/app/settings/WebsearchSetting.java | 100 +- .../transdroid/core/gui/DetailsActivity.java | 624 ++--- .../transdroid/core/gui/DetailsFragment.java | 1230 ++++---- .../core/gui/ServerPickerDialog.java | 62 +- .../core/gui/ServerSelectionView.java | 62 +- .../transdroid/core/gui/ServerStatusView.java | 173 +- .../core/gui/TorrentTasksExecutor.java | 37 +- .../transdroid/core/gui/TorrentsActivity.java | 2483 +++++++++-------- .../transdroid/core/gui/TorrentsFragment.java | 872 +++--- .../transdroid/core/gui/TransdroidApp.java | 35 +- .../core/gui/lists/DetailsAdapter.java | 392 +-- .../core/gui/lists/LocalTorrent.java | 443 +-- .../core/gui/lists/MergeAdapter.java | 562 ++-- .../core/gui/lists/PiecesMapView.java | 15 +- .../core/gui/lists/SimpleListItem.java | 11 +- .../core/gui/lists/SimpleListItemAdapter.java | 179 +- .../lists/SimpleListItemSpinnerAdapter.java | 72 +- .../core/gui/lists/SimpleListItemView.java | 31 +- .../core/gui/lists/SortByListItem.java | 105 +- .../core/gui/lists/TorrentDetailsView.java | 118 +- .../gui/lists/TorrentFilePriorityLayout.java | 113 +- .../core/gui/lists/TorrentFileView.java | 31 +- .../core/gui/lists/TorrentProgressBar.java | 186 +- .../core/gui/lists/TorrentStatusLayout.java | 134 +- .../core/gui/lists/TorrentView.java | 93 +- .../core/gui/lists/TorrentsAdapter.java | 98 +- .../core/gui/lists/ViewHolderAdapter.java | 166 +- .../core/gui/log/DatabaseHelper.java | 63 +- .../core/gui/log/ErrorLogEntry.java | 155 +- .../core/gui/log/ErrorLogSender.java | 106 +- .../java/org/transdroid/core/gui/log/Log.java | 71 +- .../gui/log/LogUncaughtExceptionHandler.java | 54 +- .../core/gui/navigation/DialogHelper.java | 140 +- .../gui/navigation/FilterListAdapter.java | 148 +- .../gui/navigation/FilterListItemAdapter.java | 83 +- .../gui/navigation/FilterListItemView.java | 25 +- .../gui/navigation/FilterSeparatorView.java | 48 +- .../transdroid/core/gui/navigation/Label.java | 229 +- .../core/gui/navigation/NavigationFilter.java | 48 +- .../core/gui/navigation/NavigationHelper.java | 498 ++-- .../gui/navigation/RefreshableActivity.java | 11 +- .../gui/navigation/SelectionManagerMode.java | 203 +- .../SelectionModificationSpinner.java | 176 +- .../core/gui/navigation/SetLabelDialog.java | 125 +- .../navigation/SetStorageLocationDialog.java | 69 +- .../gui/navigation/SetTrackersDialog.java | 63 +- .../navigation/SetTransferRatesDialog.java | 169 +- .../core/gui/navigation/StatusType.java | 269 +- .../core/gui/remoterss/RemoteRssFragment.java | 197 +- .../core/gui/remoterss/RemoteRssItemView.java | 39 +- .../gui/remoterss/RemoteRssItemsAdapter.java | 85 +- .../core/gui/rss/RssFeedsActivity.java | 732 ++--- .../core/gui/rss/RssFeedsFragment.java | 130 +- .../core/gui/rss/RssItemsActivity.java | 75 +- .../core/gui/rss/RssItemsFragment.java | 352 +-- .../core/gui/rss/RssfeedLoader.java | 143 +- .../transdroid/core/gui/rss/RssfeedView.java | 67 +- .../core/gui/rss/RssfeedsAdapter.java | 98 +- .../core/gui/rss/RssitemStatusLayout.java | 79 +- .../transdroid/core/gui/rss/RssitemView.java | 35 +- .../core/gui/rss/RssitemsAdapter.java | 98 +- .../core/gui/search/BarcodeHelper.java | 108 +- .../core/gui/search/FilePickerHelper.java | 75 +- .../core/gui/search/SearchActivity.java | 562 ++-- .../gui/search/SearchHistoryProvider.java | 27 +- .../core/gui/search/SearchResultView.java | 39 +- .../core/gui/search/SearchResultsAdapter.java | 98 +- .../gui/search/SearchResultsFragment.java | 331 +-- .../core/gui/search/SearchSetting.java | 30 +- .../search/SearchSettingSelectionView.java | 25 +- .../search/SearchSettingsDropDownAdapter.java | 59 +- .../core/gui/search/SearchSiteView.java | 47 +- .../core/gui/search/SearchSitesAdapter.java | 98 +- .../core/gui/search/SendIntentHelper.java | 96 +- .../core/gui/search/UrlEntryDialog.java | 69 +- .../core/gui/settings/AboutDialog.java | 49 +- .../core/gui/settings/ChangelogDialog.java | 49 +- .../gui/settings/HelpSettingsActivity.java | 166 +- .../InterceptableEditTextPreference.java | 70 +- .../settings/KeyBoundPreferencesActivity.java | 392 +-- .../gui/settings/MainSettingsActivity.java | 460 +-- .../NotificationSettingsActivity.java | 108 +- .../settings/PreferenceCompatActivity.java | 76 +- .../core/gui/settings/RingtonePreference.java | 2 +- .../core/gui/settings/RssfeedPreference.java | 99 +- .../gui/settings/RssfeedSettingsActivity.java | 89 +- .../core/gui/settings/ServerPreference.java | 83 +- .../gui/settings/ServerSettingsActivity.java | 233 +- .../gui/settings/SystemSettingsActivity.java | 458 +-- .../gui/settings/WebsearchPreference.java | 91 +- .../settings/WebsearchSettingsActivity.java | 77 +- .../transdroid/core/rssparser/Channel.java | 278 +- .../org/transdroid/core/rssparser/Item.java | 308 +- .../transdroid/core/rssparser/RssParser.java | 519 ++-- .../core/seedbox/DediseedboxSettings.java | 121 +- .../seedbox/DediseedboxSettingsActivity.java | 85 +- .../core/seedbox/SeedboxPreference.java | 131 +- .../core/seedbox/SeedboxProvider.java | 77 +- .../core/seedbox/SeedboxSettings.java | 103 +- .../core/seedbox/SeedboxSettingsImpl.java | 126 +- .../core/seedbox/SeedstuffSettings.java | 121 +- .../seedbox/SeedstuffSettingsActivity.java | 85 +- .../core/seedbox/XirvikDediSettings.java | 125 +- .../seedbox/XirvikDediSettingsActivity.java | 89 +- .../core/seedbox/XirvikSemiSettings.java | 121 +- .../seedbox/XirvikSemiSettingsActivity.java | 87 +- .../core/seedbox/XirvikSharedSettings.java | 125 +- .../seedbox/XirvikSharedSettingsActivity.java | 213 +- .../transdroid/core/service/AppUpdateJob.java | 52 +- .../core/service/AppUpdateJobRunner.java | 263 +- .../transdroid/core/service/BootReceiver.java | 15 +- .../core/service/ConnectivityHelper.java | 94 +- .../core/service/ControlService.java | 260 +- .../core/service/RssCheckerJob.java | 55 +- .../core/service/RssCheckerJobRunner.java | 191 +- .../core/service/ScheduledJobCreator.java | 29 +- .../core/service/ServerCheckerJob.java | 55 +- .../core/service/ServerCheckerJobRunner.java | 392 +-- .../core/widget/ListWidgetConfig.java | 77 +- .../core/widget/ListWidgetConfigActivity.java | 458 +-- .../core/widget/ListWidgetPreviewAdapter.java | 132 +- .../core/widget/ListWidgetProvider.java | 264 +- .../core/widget/ListWidgetViewsService.java | 369 +-- .../transdroid/daemon/AlphanumComparator.java | 144 +- .../daemon/Aria2c/Aria2Adapter.java | 853 +++--- .../daemon/BitComet/BitCometAdapter.java | 1384 ++++----- .../daemon/Bitflu/BitfluAdapter.java | 475 ++-- .../daemon/BuffaloNas/BuffaloNasAdapter.java | 593 ++-- .../DLinkRouterBT/DLinkRouterBTAdapter.java | 751 ++--- .../java/org/transdroid/daemon/Daemon.java | 775 ++--- .../transdroid/daemon/DaemonException.java | 73 +- .../org/transdroid/daemon/DaemonMethod.java | 94 +- .../org/transdroid/daemon/DaemonSettings.java | 352 +-- .../daemon/Deluge/DelugeAdapter.java | 1115 ++++---- .../daemon/Deluge/DelugeCommon.java | 335 +-- .../daemon/Deluge/DelugeRemoteRssChannel.java | 117 +- .../daemon/Deluge/DelugeRemoteRssItem.java | 58 +- .../daemon/Deluge/DelugeRpcAdapter.java | 1027 +++---- .../daemon/Deluge/DelugeRpcClient.java | 302 +- .../org/transdroid/daemon/DummyAdapter.java | 511 ++-- .../org/transdroid/daemon/Finishable.java | 27 +- .../org/transdroid/daemon/IDaemonAdapter.java | 23 +- .../transdroid/daemon/IDaemonCallback.java | 27 +- .../daemon/Ktorrent/FileListParser.java | 204 +- .../daemon/Ktorrent/KtorrentAdapter.java | 804 +++--- .../daemon/Ktorrent/LoggedOutException.java | 2 +- .../daemon/Ktorrent/StatsParser.java | 470 ++-- .../java/org/transdroid/daemon/Label.java | 162 +- .../main/java/org/transdroid/daemon/OS.java | 91 +- .../java/org/transdroid/daemon/Priority.java | 71 +- .../daemon/Rtorrent/RtorrentAdapter.java | 1197 ++++---- .../daemon/Synology/SynologyAdapter.java | 939 +++---- .../transdroid/daemon/Tfb4rt/StatsParser.java | 450 +-- .../daemon/Tfb4rt/Tfb4rtAdapter.java | 457 +-- .../java/org/transdroid/daemon/Torrent.java | 805 +++--- .../org/transdroid/daemon/TorrentDetails.java | 187 +- .../org/transdroid/daemon/TorrentFile.java | 384 +-- .../daemon/TorrentFilesComparator.java | 88 +- .../transdroid/daemon/TorrentFilesSortBy.java | 56 +- .../org/transdroid/daemon/TorrentStatus.java | 76 +- .../transdroid/daemon/TorrentsComparator.java | 172 +- .../org/transdroid/daemon/TorrentsSortBy.java | 68 +- .../Transmission/TransmissionAdapter.java | 1183 ++++---- .../daemon/Ttorrent/TtorrentAdapter.java | 685 ++--- .../daemon/Utorrent/UtorrentAdapter.java | 1174 ++++---- .../data/UTorrentRemoteRssChannel.java | 13 +- .../Utorrent/data/UTorrentRemoteRssItem.java | 10 +- .../transdroid/daemon/Vuze/VuzeAdapter.java | 903 +++--- .../daemon/Vuze/VuzeXmlOverHttpClient.java | 513 ++-- .../transdroid/daemon/task/AddByFileTask.java | 34 +- .../daemon/task/AddByMagnetUrlTask.java | 34 +- .../transdroid/daemon/task/AddByUrlTask.java | 43 +- .../transdroid/daemon/task/DaemonTask.java | 164 +- .../daemon/task/DaemonTaskFailureResult.java | 55 +- .../daemon/task/DaemonTaskResult.java | 109 +- .../daemon/task/DaemonTaskSuccessResult.java | 23 +- .../daemon/task/ForceRecheckTask.java | 23 +- .../daemon/task/GetFileListTask.java | 23 +- .../task/GetFileListTaskSuccessResult.java | 37 +- .../transdroid/daemon/task/GetStatsTask.java | 23 +- .../task/GetStatsTaskSuccessResult.java | 45 +- .../daemon/task/GetTorrentDetailsTask.java | 23 +- .../GetTorrentDetailsTaskSuccessResult.java | 37 +- .../transdroid/daemon/task/PauseAllTask.java | 23 +- .../org/transdroid/daemon/task/PauseTask.java | 23 +- .../transdroid/daemon/task/RemoveTask.java | 36 +- .../transdroid/daemon/task/ResumeAllTask.java | 23 +- .../transdroid/daemon/task/ResumeTask.java | 23 +- .../transdroid/daemon/task/RetrieveTask.java | 23 +- .../task/RetrieveTaskSuccessResult.java | 47 +- .../daemon/task/SetAlternativeModeTask.java | 34 +- .../daemon/task/SetDownloadLocationTask.java | 34 +- .../daemon/task/SetFilePriorityTask.java | 54 +- .../transdroid/daemon/task/SetLabelTask.java | 34 +- .../daemon/task/SetTrackersTask.java | 34 +- .../daemon/task/SetTransferRatesTask.java | 47 +- .../transdroid/daemon/task/StartAllTask.java | 34 +- .../org/transdroid/daemon/task/StartTask.java | 34 +- .../transdroid/daemon/task/StopAllTask.java | 23 +- .../org/transdroid/daemon/task/StopTask.java | 23 +- .../ToggleFirstLastPieceDownloadTask.java | 23 +- .../task/ToggleSequentialDownloadTask.java | 23 +- .../transdroid/daemon/util/Collections2.java | 24 +- .../daemon/util/FileSizeConverter.java | 172 +- .../transdroid/daemon/util/HttpHelper.java | 424 +-- .../daemon/util/IgnoreSSLTrustManager.java | 24 +- .../daemon/util/SelfSignedTrustManager.java | 134 +- .../daemon/util/TimespanConverter.java | 90 +- .../daemon/util/TlsSniSocketFactory.java | 172 +- .../multipart/BitCometFilePart.java | 96 +- .../transdroid/multipart/Utf8StringPart.java | 28 +- .../details_list_background.xml | 19 +- .../res/drawable-night/loading_progress.xml | 15 +- .../res/drawable/activatable_background.xml | 22 +- .../res/drawable/details_list_background.xml | 19 +- .../main/res/drawable/elevation_shadow.xml | 12 +- .../res/drawable/elevation_shadow_reverse.xml | 12 +- .../main/res/drawable/ic_cloud_download.xml | 10 +- .../main/res/drawable/loading_progress.xml | 15 +- .../res/layout-w600dp/activity_search.xml | 107 +- .../res/layout-w600dp/activity_torrents.xml | 177 +- .../res/layout-w900dp/activity_rssfeeds.xml | 125 +- .../res/layout-w900dp/activity_torrents.xml | 263 +- .../main/res/layout/actionbar_addbutton.xml | 47 +- .../main/res/layout/actionbar_donebutton.xml | 46 +- .../main/res/layout/actionbar_searchsite.xml | 35 +- .../res/layout/actionbar_serverselection.xml | 75 +- .../res/layout/actionbar_serverstatus.xml | 195 +- app/src/main/res/layout/activity_details.xml | 45 +- app/src/main/res/layout/activity_rssfeeds.xml | 113 +- app/src/main/res/layout/activity_rssitems.xml | 49 +- app/src/main/res/layout/activity_search.xml | 93 +- app/src/main/res/layout/activity_torrents.xml | 210 +- .../main/res/layout/activity_widgetconfig.xml | 195 +- app/src/main/res/layout/dialog_about.xml | 133 +- app/src/main/res/layout/dialog_changelog.xml | 29 +- app/src/main/res/layout/dialog_setlabel.xml | 81 +- .../res/layout/dialog_storagelocation.xml | 25 +- app/src/main/res/layout/dialog_trackers.xml | 27 +- .../main/res/layout/dialog_transferrates.xml | 593 ++-- app/src/main/res/layout/dialog_url.xml | 29 +- app/src/main/res/layout/fragment_details.xml | 158 +- .../res/layout/fragment_details_header.xml | 357 ++- .../main/res/layout/fragment_remoterss.xml | 48 +- app/src/main/res/layout/fragment_rssfeeds.xml | 55 +- app/src/main/res/layout/fragment_rssitems.xml | 49 +- .../res/layout/fragment_searchresults.xml | 73 +- app/src/main/res/layout/fragment_torrents.xml | 139 +- app/src/main/res/layout/list_item_filter.xml | 33 +- .../res/layout/list_item_remoterssitem.xml | 80 +- app/src/main/res/layout/list_item_rssfeed.xml | 95 +- app/src/main/res/layout/list_item_rssitem.xml | 61 +- .../res/layout/list_item_searchresult.xml | 129 +- .../main/res/layout/list_item_searchsite.xml | 59 +- .../main/res/layout/list_item_separator.xml | 29 +- app/src/main/res/layout/list_item_simple.xml | 33 +- app/src/main/res/layout/list_item_torrent.xml | 193 +- .../main/res/layout/list_item_torrentfile.xml | 87 +- app/src/main/res/layout/list_item_widget.xml | 101 +- .../main/res/layout/list_item_widget_dark.xml | 103 +- app/src/main/res/layout/pref_withoverflow.xml | 24 +- app/src/main/res/layout/widget_torrents.xml | 397 ++- .../res/menu/activity_deleteableprefs.xml | 18 +- app/src/main/res/menu/activity_details.xml | 20 +- app/src/main/res/menu/activity_search.xml | 71 +- .../main/res/menu/activity_torrents_main.xml | 46 +- .../res/menu/activity_torrents_secondary.xml | 113 +- app/src/main/res/menu/dialog_about.xml | 18 +- app/src/main/res/menu/fragment_details.xml | 198 +- .../res/menu/fragment_details_cab_main.xml | 58 +- .../menu/fragment_details_cab_secondary.xml | 18 +- app/src/main/res/menu/fragment_rssfeeds.xml | 24 +- .../main/res/menu/fragment_rssitems_cab.xml | 56 +- .../res/menu/fragment_searchresults_cab.xml | 28 +- .../main/res/menu/fragment_torrents_cab.xml | 86 +- app/src/main/res/values-ar/strings.xml | 113 +- app/src/main/res/values-bg/strings.xml | 465 ++- app/src/main/res/values-cs/strings.xml | 623 +++-- app/src/main/res/values-da/strings.xml | 655 +++-- app/src/main/res/values-de/strings.xml | 687 +++-- app/src/main/res/values-el/strings.xml | 243 +- app/src/main/res/values-es/strings.xml | 565 ++-- app/src/main/res/values-et/strings.xml | 367 ++- app/src/main/res/values-fa/strings.xml | 665 +++-- app/src/main/res/values-fi/strings.xml | 277 +- app/src/main/res/values-fr/strings.xml | 655 +++-- app/src/main/res/values-h400dp/dimens.xml | 12 +- app/src/main/res/values-h600dp/dimens.xml | 12 +- app/src/main/res/values-he/strings.xml | 533 ++-- app/src/main/res/values-hu/strings.xml | 687 +++-- app/src/main/res/values-it/strings.xml | 687 +++-- app/src/main/res/values-ja/strings.xml | 671 +++-- app/src/main/res/values-ko/strings.xml | 671 +++-- app/src/main/res/values-land/dimens.xml | 26 +- .../res/values-night/colors_transdroid.xml | 7 +- app/src/main/res/values-nl/strings.xml | 679 +++-- app/src/main/res/values-no-rNB/strings.xml | 11 +- app/src/main/res/values-pl/strings.xml | 613 ++-- app/src/main/res/values-pt-rBR/strings.xml | 687 +++-- app/src/main/res/values-pt/strings.xml | 687 +++-- app/src/main/res/values-ro/strings.xml | 109 +- app/src/main/res/values-ru/strings.xml | 721 +++-- app/src/main/res/values-sl/strings.xml | 719 +++-- app/src/main/res/values-sr/strings.xml | 11 +- app/src/main/res/values-sv/strings.xml | 687 +++-- app/src/main/res/values-sw500dp/bools.xml | 13 +- app/src/main/res/values-sw600dp/dimens.xml | 52 +- app/src/main/res/values-tr/strings.xml | 685 +++-- app/src/main/res/values-uk/strings.xml | 339 ++- app/src/main/res/values-v16/styles.xml | 70 +- app/src/main/res/values-v21/styles.xml | 28 +- app/src/main/res/values-vi/strings.xml | 523 ++-- app/src/main/res/values-w600dp/dimens.xml | 6 +- app/src/main/res/values-zh-rCN/strings.xml | 639 +++-- app/src/main/res/values-zh-rHK/strings.xml | 295 +- app/src/main/res/values/attrs.xml | 31 +- app/src/main/res/values/bools.xml | 29 +- app/src/main/res/values/changelog.xml | 9 +- app/src/main/res/values/colors.xml | 31 +- app/src/main/res/values/colors_transdroid.xml | 7 +- app/src/main/res/values/dimens.xml | 86 +- .../main/res/values/integer_colorpicker.xml | 6 +- app/src/main/res/values/strings.xml | 879 +++--- .../main/res/values/strings_colorpicker.xml | 8 +- app/src/main/res/values/styles.xml | 184 +- app/src/main/res/xml/listwidget_info.xml | 31 +- app/src/main/res/xml/pref_system.xml | 117 +- app/src/main/res/xml/pref_websearch.xml | 55 +- app/src/main/res/xml/searchable.xml | 19 +- 342 files changed, 36967 insertions(+), 36514 deletions(-) create mode 100644 .editorconfig 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/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1fae5479..86468441 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,333 +1,330 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 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..c63aa763 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,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 . */ @@ -35,134 +35,138 @@ 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; + + 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; + } + } } 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..353e80f1 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,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 . */ @@ -23,100 +23,101 @@ import android.os.Parcelable; /** * 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(); - } + 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(); + } } 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..bc4f5c28 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,764 @@ 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; + 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; + } + } } 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..79c83dce 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,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 . */ @@ -25,98 +25,102 @@ import android.text.TextUtils; /** * 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 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)); + } } 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..3ca52134 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,51 @@ 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 { + @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 { 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 +91,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..3d8d7b16 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 @@ -2,6 +2,7 @@ package org.transdroid.core.app.settings; import android.content.Context; + import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; @@ -33,6 +34,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..d17d31a5 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,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 . */ @@ -24,58 +24,60 @@ import android.text.TextUtils; /** * 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; + private static final String DEFAULT_NAME = "Default"; + public static final String KEY_PREFIX = "websearch_"; - public WebsearchSetting(int order, String name, String baseUrl, String cookies) { - this.order = order; - this.name = name; - this.baseUrl = baseUrl; - this.cookies = cookies; - } + private final int order; + private final String name; + private final String baseUrl; + private final String cookies; - public int getOrder() { - return order; - } + public WebsearchSetting(int order, String name, String baseUrl, String cookies) { + this.order = order; + this.name = name; + this.baseUrl = baseUrl; + this.cookies = 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 int getOrder() { + return order; + } - public String getCookies() { - return cookies; - } - - public String getKey() { - return KEY_PREFIX + getOrder(); - } + @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 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..87a9386f 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; @@ -82,318 +83,319 @@ 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