├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── config.yml │ └── feature-request.md └── workflows │ ├── android.yml │ ├── dependencies.yml │ ├── lint.yml │ └── translations.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE_rcloneExplorer-1.7.4 ├── README.md ├── SECURITY.md ├── app ├── .gitignore ├── build.gradle ├── lint-baseline.xml ├── proguard-rules.pro └── src │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── changelog.md │ │ └── contributors.md │ ├── ic_launcher-playstore.png │ ├── java │ │ ├── ca │ │ │ └── pkay │ │ │ │ └── rcloneexplorer │ │ │ │ ├── Activities │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── AboutLibsActivity.java │ │ │ │ ├── ChangelogActivity.java │ │ │ │ ├── ContributorActivity.java │ │ │ │ ├── FilterActivity.kt │ │ │ │ ├── MainActivity.java │ │ │ │ ├── OnboardingActivity.kt │ │ │ │ ├── SettingsActivity.java │ │ │ │ ├── SharingActivity.java │ │ │ │ ├── ShortcutServiceActivity.kt │ │ │ │ ├── TaskActivity.kt │ │ │ │ └── TriggerActivity.kt │ │ │ │ ├── AppShortcutsHelper.java │ │ │ │ ├── BroadcastReceivers │ │ │ │ ├── BootReciever.java │ │ │ │ ├── ClearReportBroadcastReciever.kt │ │ │ │ ├── ServeCancelAction.java │ │ │ │ ├── SyncRestartAction.java │ │ │ │ └── TriggerReciever.java │ │ │ │ ├── Database │ │ │ │ ├── DatabaseHandler.kt │ │ │ │ ├── DatabaseInfo.kt │ │ │ │ └── json │ │ │ │ │ ├── Exporter.java │ │ │ │ │ ├── Importer.java │ │ │ │ │ └── SharedPreferencesBackup.java │ │ │ │ ├── Dialogs │ │ │ │ ├── Dialogs.java │ │ │ │ ├── FilePropertiesDialog.java │ │ │ │ ├── GoToDialog.java │ │ │ │ ├── InputDialog.java │ │ │ │ ├── LinkDialog.java │ │ │ │ ├── LoadingDialog.java │ │ │ │ ├── NumberPickerDialog.java │ │ │ │ ├── OpenAsDialog.java │ │ │ │ ├── PasswordGeneratorDialog.java │ │ │ │ ├── RemoteDestinationDialog.java │ │ │ │ ├── RemotePropertiesDialog.java │ │ │ │ ├── ServeDialog.java │ │ │ │ └── SortDialog.java │ │ │ │ ├── FileComparators.java │ │ │ │ ├── FilePicker.java │ │ │ │ ├── Fragments │ │ │ │ ├── FileExplorerFragment.java │ │ │ │ ├── FolderSelectorCallback.java │ │ │ │ ├── LogFragment.java │ │ │ │ ├── PermissionFragment.kt │ │ │ │ ├── RemoteFolderPickerFragment.java │ │ │ │ ├── RemotesFragment.java │ │ │ │ ├── ShareFragment.java │ │ │ │ ├── ShareRemotesFragment.java │ │ │ │ ├── TasksFragment.java │ │ │ │ └── TriggerFragment.java │ │ │ │ ├── InteractiveRunner.java │ │ │ │ ├── Items │ │ │ │ ├── DirectoryObject.java │ │ │ │ ├── FileItem.java │ │ │ │ ├── Filter.kt │ │ │ │ ├── FilterEntry.java │ │ │ │ ├── RemoteItem.java │ │ │ │ ├── SyncDirectionObject.java │ │ │ │ ├── Task.kt │ │ │ │ └── Trigger.kt │ │ │ │ ├── Log2File.java │ │ │ │ ├── Rclone.java │ │ │ │ ├── RcloneRcd.java │ │ │ │ ├── RecyclerViewAdapters │ │ │ │ ├── AboutLibrariesAdapter.java │ │ │ │ ├── FileExplorerRecyclerViewAdapter.java │ │ │ │ ├── FilePickerAdapter.java │ │ │ │ ├── FilterEntryRecyclerViewAdapter.java │ │ │ │ ├── LogRecyclerViewAdapter.java │ │ │ │ ├── RemoteConfigListItemAdapter.kt │ │ │ │ ├── RemotesRecyclerViewAdapter.java │ │ │ │ ├── ShareRemotesRecyclerViewAdapter.java │ │ │ │ ├── TasksRecyclerViewAdapter.java │ │ │ │ └── TriggerRecyclerViewAdapter.java │ │ │ │ ├── RemoteConfig │ │ │ │ ├── ConfigCreate.kt │ │ │ │ ├── DynamicRemoteConfigFragment.kt │ │ │ │ ├── OauthHelper.java │ │ │ │ ├── ProviderListFragment.kt │ │ │ │ ├── RemoteConfig.kt │ │ │ │ └── RemoteConfigHelper.java │ │ │ │ ├── RuntimeConfiguration.java │ │ │ │ ├── Services │ │ │ │ ├── RcdService.java │ │ │ │ ├── StreamingService.java │ │ │ │ ├── SyncService.kt │ │ │ │ ├── ThumbnailsLoadingService.java │ │ │ │ └── TriggerService.java │ │ │ │ ├── Settings │ │ │ │ ├── FileAccessPreferencesFragment.kt │ │ │ │ ├── FileAccessSettingsFragment.java │ │ │ │ ├── GeneralPreferencesFragment.kt │ │ │ │ ├── LogPreferencesFragment.kt │ │ │ │ ├── NotificationPreferencesFragment.kt │ │ │ │ ├── SettingsFragment.java │ │ │ │ └── ThemingPreferencesFragment.kt │ │ │ │ ├── SpinnerAdapters │ │ │ │ └── FilterSpinnerAdapter.kt │ │ │ │ ├── VirtualContentProvider.java │ │ │ │ ├── notifications │ │ │ │ ├── AppErrorNotificationManager.kt │ │ │ │ ├── GenericSyncNotification.kt │ │ │ │ ├── ReportNotifications.kt │ │ │ │ ├── SyncServiceNotifications.kt │ │ │ │ ├── prototypes │ │ │ │ │ └── WorkerNotification.kt │ │ │ │ └── support │ │ │ │ │ ├── ErrorObject.kt │ │ │ │ │ ├── GenericNotification.kt │ │ │ │ │ └── StatusObject.kt │ │ │ │ ├── rclone │ │ │ │ ├── OptionExampleItem.kt │ │ │ │ ├── Provider.kt │ │ │ │ └── ProviderOption.kt │ │ │ │ ├── util │ │ │ │ ├── ActivityHelper.java │ │ │ │ ├── FLog.java │ │ │ │ ├── FlagsUtil.kt │ │ │ │ ├── LargeParcel.java │ │ │ │ ├── MarkdownView.java │ │ │ │ ├── NotificationUtils.kt │ │ │ │ ├── PermissionManager.kt │ │ │ │ ├── Rfc3339Deserializer.java │ │ │ │ ├── SharedPreferencesUtil.kt │ │ │ │ ├── SyncLog.java │ │ │ │ └── WifiConnectivitiyUtil.kt │ │ │ │ └── workmanager │ │ │ │ ├── EphemeralTaskManager.kt │ │ │ │ ├── EphemeralWorker.kt │ │ │ │ ├── SyncManager.kt │ │ │ │ ├── SyncWorker.kt │ │ │ │ └── Type.kt │ │ └── de │ │ │ └── felixnuesse │ │ │ ├── extract │ │ │ ├── extensions │ │ │ │ └── TAG.kt │ │ │ ├── notifications │ │ │ │ ├── AppUpdateNotification.kt │ │ │ │ ├── DiscardChannels.kt │ │ │ │ └── implementations │ │ │ │ │ ├── DeleteWorkerNotification.kt │ │ │ │ │ ├── DownloadWorkerNotification.kt │ │ │ │ │ ├── MoveWorkerNotification.kt │ │ │ │ │ └── UploadWorkerNotification.kt │ │ │ ├── onboarding │ │ │ │ ├── IdentifiableAppIntroFragment.kt │ │ │ │ ├── IdentifiableSwitchAppIntroFragment.kt │ │ │ │ ├── SlideLeaveInterface.kt │ │ │ │ └── SlideSwitchCallback.kt │ │ │ ├── settings │ │ │ │ ├── language │ │ │ │ │ ├── LanguagePicker.kt │ │ │ │ │ └── LocaleAdapter.kt │ │ │ │ └── preferences │ │ │ │ │ ├── ButtonPreference.kt │ │ │ │ │ ├── EditIntPreference.kt │ │ │ │ │ ├── FilesizePreference.kt │ │ │ │ │ └── dialogs │ │ │ │ │ └── FilesizeDialog.kt │ │ │ └── updates │ │ │ │ ├── UpdateChecker.kt │ │ │ │ ├── UpdateUserchoiceReceiver.kt │ │ │ │ └── workmanager │ │ │ │ ├── UpdateManager.kt │ │ │ │ └── UpdateWorker.kt │ │ │ └── ui │ │ │ ├── BreadcrumbView.kt │ │ │ └── CrumbView.kt │ └── res │ │ ├── anim │ │ ├── fade_in_animation.xml │ │ └── fade_out_animation.xml │ │ ├── drawable │ │ ├── appicon.xml │ │ ├── ic_add.xml │ │ ├── ic_amazon.xml │ │ ├── ic_amazon_foreground.xml │ │ ├── ic_arrow_back.xml │ │ ├── ic_arrow_right.xml │ │ ├── ic_azure_storage_blob_logo.xml │ │ ├── ic_backblaze_b2_black.xml │ │ ├── ic_baseline_stop_24.xml │ │ ├── ic_box.xml │ │ ├── ic_box_foreground.xml │ │ ├── ic_bug_report.xml │ │ ├── ic_cancel.xml │ │ ├── ic_cancel_download.xml │ │ ├── ic_cancel_white.xml │ │ ├── ic_changelog.xml │ │ ├── ic_check.xml │ │ ├── ic_circle.xml │ │ ├── ic_close.xml │ │ ├── ic_cloud.xml │ │ ├── ic_cloud_download_black_24dp.xml │ │ ├── ic_cloud_foreground.xml │ │ ├── ic_contributor.xml │ │ ├── ic_create_new_folder.xml │ │ ├── ic_delete.xml │ │ ├── ic_delete_black.xml │ │ ├── ic_dino2.xml │ │ ├── ic_drive_foreground.xml │ │ ├── ic_dropbox.xml │ │ ├── ic_dropbox_foreground.xml │ │ ├── ic_edit.xml │ │ ├── ic_edit_black.xml │ │ ├── ic_empty_box.xml │ │ ├── ic_export.xml │ │ ├── ic_file.xml │ │ ├── ic_file_alert.xml │ │ ├── ic_file_black.xml │ │ ├── ic_file_download.xml │ │ ├── ic_file_upload.xml │ │ ├── ic_folder.xml │ │ ├── ic_folder_move.xml │ │ ├── ic_folder_open.xml │ │ ├── ic_google.xml │ │ ├── ic_google_drive.xml │ │ ├── ic_google_foreground.xml │ │ ├── ic_google_photos.xml │ │ ├── ic_heart_red_24dp.xml │ │ ├── ic_home.xml │ │ ├── ic_import.xml │ │ ├── ic_info_outline.xml │ │ ├── ic_intro_notifications.xml │ │ ├── ic_intro_storage.png │ │ ├── ic_koofr.xml │ │ ├── ic_launcher_background_debug.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_launcher_foreground_debug.xml │ │ ├── ic_libraries.xml │ │ ├── ic_local_foreground.xml │ │ ├── ic_lock.xml │ │ ├── ic_lock_black.xml │ │ ├── ic_lock_foreground.xml │ │ ├── ic_look_and_feel.xml │ │ ├── ic_mark_github.xml │ │ ├── ic_mega_logo_black.xml │ │ ├── ic_menu.xml │ │ ├── ic_more_vert.xml │ │ ├── ic_notifications.xml │ │ ├── ic_onedrive.xml │ │ ├── ic_onedrive_foreground.xml │ │ ├── ic_open_drive.xml │ │ ├── ic_pcloud.xml │ │ ├── ic_person_outline.xml │ │ ├── ic_pin.xml │ │ ├── ic_pound.xml │ │ ├── ic_rclone_logo.xml │ │ ├── ic_refresh.xml │ │ ├── ic_round_av_timer_24.xml │ │ ├── ic_round_list_24.xml │ │ ├── ic_round_swap_vert_24.xml │ │ ├── ic_sd_storage.xml │ │ ├── ic_search.xml │ │ ├── ic_search_black_24dp.xml │ │ ├── ic_select_all.xml │ │ ├── ic_settings.xml │ │ ├── ic_sort.xml │ │ ├── ic_streaming.xml │ │ ├── ic_tablet_cellphone.xml │ │ ├── ic_terminal.xml │ │ ├── ic_terminal_foreground.xml │ │ ├── ic_twotone_cancel_24.xml │ │ ├── ic_twotone_check_circle_24.xml │ │ ├── ic_twotone_cloud_24.xml │ │ ├── ic_twotone_cloud_done_24.xml │ │ ├── ic_twotone_cloud_download_24.xml │ │ ├── ic_twotone_cloud_error_24.xml │ │ ├── ic_twotone_cloud_upload_24.xml │ │ ├── ic_twotone_error_24.xml │ │ ├── ic_twotone_info_24.xml │ │ ├── ic_twotone_rounded_cloud_sync_24.xml │ │ ├── ic_twotone_save_24.xml │ │ ├── ic_twotone_settings_24.xml │ │ ├── ic_union_24dp.xml │ │ ├── ic_webdav.xml │ │ ├── ic_yandex_mono.xml │ │ ├── nav_header_background_rounded.xml │ │ ├── nav_item_background_rounded.xml │ │ ├── nav_item_color_state.xml │ │ ├── nav_item_textcolor_state.xml │ │ ├── pill.xml │ │ ├── shape_circle.xml │ │ ├── twotone_home_24.xml │ │ ├── undraw_completion.xml │ │ ├── undraw_electricity.xml │ │ ├── undraw_hello.xml │ │ ├── undraw_post_online.xml │ │ ├── undraw_sync.xml │ │ ├── undraw_the_world_is_mine.xml │ │ ├── undraw_time_management.xml │ │ └── undraw_update.xml │ │ ├── layout-sw720dp │ │ ├── activity_about.xml │ │ ├── activity_changelog.xml │ │ ├── app_bar_main.xml │ │ ├── content_about_libs.xml │ │ ├── dialog_remote_dest.xml │ │ ├── file_picker_list.xml │ │ ├── fragment_config_list.xml │ │ ├── fragment_file_explorer_list.xml │ │ ├── fragment_share_list.xml │ │ └── remote_config_form.xml │ │ ├── layout │ │ ├── about_icon_item.xml │ │ ├── about_libraries_item.xml │ │ ├── activity_about.xml │ │ ├── activity_about_libs.xml │ │ ├── activity_changelog.xml │ │ ├── activity_contributors.xml │ │ ├── activity_file_picker.xml │ │ ├── activity_filter.xml │ │ ├── activity_main.xml │ │ ├── activity_remote_config.xml │ │ ├── activity_settings.xml │ │ ├── activity_sharing.xml │ │ ├── activity_task.xml │ │ ├── activity_trigger.xml │ │ ├── app_bar_main.xml │ │ ├── appintro_fragment_intro_switch.xml │ │ ├── auth_screen.xml │ │ ├── bottom_bar.xml │ │ ├── config_list_item_template.xml │ │ ├── content_about.xml │ │ ├── content_about_libs.xml │ │ ├── content_changelog.xml │ │ ├── content_contributors.xml │ │ ├── content_filter.xml │ │ ├── content_main.xml │ │ ├── content_remote_config.xml │ │ ├── content_settings.xml │ │ ├── content_sharing.xml │ │ ├── content_task.xml │ │ ├── content_trigger.xml │ │ ├── customui_breadcrumbview.xml │ │ ├── customui_crumbview.xml │ │ ├── dialog_file_properties.xml │ │ ├── dialog_go_to.xml │ │ ├── dialog_input.xml │ │ ├── dialog_link.xml │ │ ├── dialog_loading_indicator.xml │ │ ├── dialog_number_picker.xml │ │ ├── dialog_open_as.xml │ │ ├── dialog_password_generator.xml │ │ ├── dialog_remote_dest.xml │ │ ├── dialog_remote_properties.xml │ │ ├── dialog_serve.xml │ │ ├── dialog_sort.xml │ │ ├── empty_directory_state.xml │ │ ├── empty_state_config_file.xml │ │ ├── file_picker_item.xml │ │ ├── file_picker_list.xml │ │ ├── fragment_config_list.xml │ │ ├── fragment_file_explorer_item.xml │ │ ├── fragment_file_explorer_list.xml │ │ ├── fragment_filter_item.xml │ │ ├── fragment_log_item.xml │ │ ├── fragment_logs.xml │ │ ├── fragment_permission_item.xml │ │ ├── fragment_permissions.xml │ │ ├── fragment_remote_folder_picker_list.xml │ │ ├── fragment_remotes_item.xml │ │ ├── fragment_remotes_list.xml │ │ ├── fragment_share_list.xml │ │ ├── fragment_share_remotes_item.xml │ │ ├── fragment_share_remotes_list.xml │ │ ├── fragment_tasks.xml │ │ ├── fragment_tasks_item.xml │ │ ├── fragment_trigger.xml │ │ ├── fragment_trigger_item_interval.xml │ │ ├── fragment_trigger_item_schedule.xml │ │ ├── locked_config.xml │ │ ├── move_bar.xml │ │ ├── nav_header_main.xml │ │ ├── no_search_results.xml │ │ ├── preference_button.xml │ │ ├── preference_filesize.xml │ │ ├── remote_config_form.xml │ │ ├── settings_fragment.xml │ │ ├── settings_fragment_file_access_settings.xml │ │ ├── settings_fragment_general.xml │ │ └── spinner_dropdown_item.xml │ │ ├── menu │ │ ├── activity_main_drawer.xml │ │ ├── file_explorer_folder_menu.xml │ │ ├── file_explorer_menu.xml │ │ ├── file_picker_menu.xml │ │ ├── filter_item_menu.xml │ │ ├── fragment_config_menu.xml │ │ ├── fragment_share_menu.xml │ │ ├── remote_config_menu.xml │ │ ├── remote_folder_picker_menu.xml │ │ ├── remote_fragment_menu.xml │ │ ├── remote_options.xml │ │ ├── task_item_menu.xml │ │ └── trigger_item_menu.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ ├── ic_launcher_debug.xml │ │ ├── ic_launcher_debug_round.xml │ │ ├── ic_launcher_round.xml │ │ ├── ic_shortcut_amazon.xml │ │ ├── ic_shortcut_box.xml │ │ ├── ic_shortcut_cloud.xml │ │ ├── ic_shortcut_drive.xml │ │ ├── ic_shortcut_dropbox.xml │ │ ├── ic_shortcut_google.xml │ │ ├── ic_shortcut_local.xml │ │ ├── ic_shortcut_lock.xml │ │ ├── ic_shortcut_onedrive.xml │ │ └── ic_shortcut_terminal.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_shortcut_amazon.png │ │ ├── ic_shortcut_box.png │ │ ├── ic_shortcut_cloud.png │ │ ├── ic_shortcut_drive.png │ │ ├── ic_shortcut_dropbox.png │ │ ├── ic_shortcut_google.png │ │ ├── ic_shortcut_local.png │ │ ├── ic_shortcut_lock.png │ │ ├── ic_shortcut_onedrive.png │ │ └── ic_shortcut_terminal.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_shortcut_amazon.png │ │ ├── ic_shortcut_box.png │ │ ├── ic_shortcut_cloud.png │ │ ├── ic_shortcut_drive.png │ │ ├── ic_shortcut_dropbox.png │ │ ├── ic_shortcut_google.png │ │ ├── ic_shortcut_local.png │ │ ├── ic_shortcut_lock.png │ │ ├── ic_shortcut_onedrive.png │ │ └── ic_shortcut_terminal.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_shortcut_amazon.png │ │ ├── ic_shortcut_box.png │ │ ├── ic_shortcut_cloud.png │ │ ├── ic_shortcut_drive.png │ │ ├── ic_shortcut_dropbox.png │ │ ├── ic_shortcut_google.png │ │ ├── ic_shortcut_local.png │ │ ├── ic_shortcut_lock.png │ │ ├── ic_shortcut_onedrive.png │ │ └── ic_shortcut_terminal.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_shortcut_amazon.png │ │ ├── ic_shortcut_box.png │ │ ├── ic_shortcut_cloud.png │ │ ├── ic_shortcut_drive.png │ │ ├── ic_shortcut_dropbox.png │ │ ├── ic_shortcut_google.png │ │ ├── ic_shortcut_local.png │ │ ├── ic_shortcut_lock.png │ │ ├── ic_shortcut_onedrive.png │ │ └── ic_shortcut_terminal.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_shortcut_amazon.png │ │ ├── ic_shortcut_box.png │ │ ├── ic_shortcut_cloud.png │ │ ├── ic_shortcut_drive.png │ │ ├── ic_shortcut_dropbox.png │ │ ├── ic_shortcut_google.png │ │ ├── ic_shortcut_local.png │ │ ├── ic_shortcut_lock.png │ │ ├── ic_shortcut_onedrive.png │ │ └── ic_shortcut_terminal.png │ │ ├── resources.properties │ │ ├── values-de │ │ └── strings.xml │ │ ├── values-night-v31 │ │ └── colors.xml │ │ ├── values-night │ │ ├── styles.xml │ │ └── themes.xml │ │ ├── values-sw720dp │ │ └── isTabletMode.xml │ │ ├── values-v31 │ │ ├── colors.xml │ │ └── styles.xml │ │ ├── values-zh-rCN │ │ └── strings.xml │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── defaults.xml │ │ ├── dimens.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_shortcut_background.xml │ │ ├── ids.xml │ │ ├── isTabletMode.xml │ │ ├── prefkeys.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ ├── sync_direction_array.xml │ │ └── themes.xml │ │ └── xml │ │ ├── file_provider_paths.xml │ │ ├── network_security_config.xml │ │ ├── paths.xml │ │ ├── settings_fileaccess_preferences.xml │ │ ├── settings_general_preferences.xml │ │ ├── settings_logging_preferences.xml │ │ ├── settings_notification_preferences.xml │ │ ├── settings_theming_preferences.xml │ │ └── virtual_content_provider_paths.xml │ ├── rcx │ └── java │ │ └── ca │ │ └── pkay │ │ └── rcloneexplorer │ │ └── util │ │ └── CrashLogger.java │ └── test │ └── java │ └── ca │ └── pkay │ └── rcloneexplorer │ ├── ExampleUnitTest.java │ └── VirtualContentProviderTest.java ├── build.gradle ├── crowdin.yml ├── docs ├── cloud-computing.png ├── locked-padlock.png └── smartphone.png ├── fastlane └── metadata │ └── android │ └── en-US │ ├── full_description.txt │ ├── images │ ├── featureGraphic.jpg │ ├── icon.png │ └── phoneScreenshots │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ └── 4.jpg │ ├── short_description.txt │ └── title.txt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── rclone ├── .gitignore └── build.gradle ├── safdav ├── .gitignore ├── build.gradle ├── lint-baseline.xml ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── io │ │ └── github │ │ └── x0b │ │ └── safdav │ │ ├── SafAccessProvider.java │ │ ├── SafDAVServer.java │ │ ├── SafDirectServer.java │ │ ├── file │ │ ├── FileAccessError.java │ │ ├── ItemAccess.java │ │ ├── ItemExistsException.java │ │ ├── ItemNotFoundException.java │ │ ├── SafConstants.java │ │ ├── SafException.java │ │ └── SafItem.java │ │ ├── package-info.java │ │ ├── provider │ │ └── SingleRootProvider.java │ │ ├── saf │ │ ├── DocumentsContractAccess.java │ │ ├── ProviderPaths.java │ │ ├── SafFastItem.java │ │ ├── SafFileAccess.java │ │ ├── SafFileItem.java │ │ └── SafPermissionItem.java │ │ └── xml │ │ └── XmlResponseSerialization.java │ └── res │ └── values │ └── strings.xml ├── scripts ├── checkProfanity.py └── generateFilelist.sh └── settings.gradle /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: newhinton 4 | custom: ["https://www.paypal.com/paypalme/felixnuesse"] 5 | liberapay: newhinton 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Rclone Forum 4 | url: https://forum.rclone.org/ 5 | about: For questions around rclone itself. 6 | - name: Rclone Issue Tracker 7 | url: https://github.com/rclone/rclone/issues 8 | about: When you are sure rclone does not work correctly. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest a new feature or enhancement for Round Sync 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | --- 11 | **If this is your first feature request, read our [contribution guidelines](../blob/master/CONTRIBUTING.md#requesting-a-new-feature).** 12 | 13 | --- 14 | 15 | #### Pre-Submission checklist 16 | 17 | 18 | - [ ] There is no existing issue that already asks for this feature.
19 | - [ ] The feature already exists in rclone (on your PC or in Termux) 20 | - [ ] I am prepared to help make this feature 21 | 22 | #### What version of Round Sync are you using (About -> App version)? 23 | 24 | 25 | 26 | #### What problem are you trying to solve? 27 | 28 | 29 | 30 | #### What should Round Sync be able to do differently to help with this problem? 31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Android Lint 2 | 3 | on: 4 | push: 5 | pull_request: 6 | branches-ignore: 7 | - 'master' 8 | 9 | jobs: 10 | checkLint: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up JDK 17 15 | uses: actions/setup-java@v3 16 | with: 17 | java-version: '17' 18 | distribution: 'temurin' 19 | cache: gradle 20 | - name: Run Linter 21 | run: ./gradlew lint -x :rclone:buildAll 22 | - name: Upload Reports 23 | if: always() 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: Lint Reports 27 | path: ~/**/build/reports/ 28 | retention-days: 30 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/assetWizardSettings.xml 38 | .idea/workspace.xml 39 | .idea/tasks.xml 40 | .idea/gradle.xml 41 | .idea/dictionaries 42 | .idea/libraries 43 | .idea/caches 44 | 45 | # Keystore files 46 | *.jks 47 | 48 | # External native build folder generated in Android Studio 2.2 and later 49 | .externalNativeBuild 50 | 51 | # Google Services (e.g. APIs or Firebase) 52 | google-services.json 53 | 54 | # Freeline 55 | freeline.py 56 | freeline/ 57 | freeline_project_description.json 58 | 59 | # Don't version native libraries or IDE artifacts. Module config should be done in gradle. 60 | # Generated artifacts (apks, libraries) just slow down cloning and can be recreated from source 61 | # anyways. 62 | release/ 63 | debug/ 64 | 65 | .idea/encodings.xml 66 | .idea/caches/build_file_checksums.ser 67 | .idea/misc.xml 68 | .idea/modules.xml 69 | .idea/codeStyles/Project.xml 70 | .idea/codeStyles/codeStyleConfig.xml 71 | .idea/inspectionProfiles/Project_Default.xml 72 | .idea/ 73 | -------------------------------------------------------------------------------- /LICENSE_rcloneExplorer-1.7.4: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Patryk Kaczmarkiewicz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /lib 3 | -------------------------------------------------------------------------------- /app/lint-baseline.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | 23 | # don't change names - this is open source anyways, and the biggest size 24 | # contributor are native libs which we can't shrink. 25 | -dontobfuscate 26 | 27 | # ignore okhttp conscrypt warning 28 | -dontwarn okhttp3.internal.platform.ConscryptPlatform 29 | 30 | # keep model classes 31 | # -keep public class ca.pkay.rcloneexplorer.RcloneRcd.* 32 | -keep class ca.pkay.rcloneexplorer.** { *; } 33 | 34 | 35 | -dontwarn org.bouncycastle.jsse.BCSSLParameters 36 | -dontwarn org.bouncycastle.jsse.BCSSLSocket 37 | -dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider 38 | -dontwarn org.conscrypt.Conscrypt$Version 39 | -dontwarn org.conscrypt.Conscrypt 40 | -dontwarn org.conscrypt.ConscryptHostnameVerifier 41 | -dontwarn org.openjsse.javax.net.ssl.SSLParameters 42 | -dontwarn org.openjsse.javax.net.ssl.SSLSocket 43 | -dontwarn org.openjsse.net.ssl.OpenJSSE 44 | -------------------------------------------------------------------------------- /app/src/main/assets/contributors.md: -------------------------------------------------------------------------------- 1 | ### Intro 2 | This application was created by [Patryk Kaczmarkiewicz](https://github.com/kaczmarkiewiczp). Your current build is maintained by [x0b](https://github.com/x0b). 3 | 4 | ### Github contributors 5 | Additionally, these people have contributed towards making RCX better: 6 | 7 | * [buywetwok](https://github.com/buywetwok) 8 | * [davsinghm](https://github.com/davsinghm) 9 | * [alyssadev](https://github.com/alyssadev) 10 | 11 | [Join us now on Github.](https://github.com/x0b/rcx) 12 | 13 | ## License 14 | 15 | Copyright (C) 2018-2020 x0b 16 | 17 | This program is free software: you can redistribute it and/or modify 18 | it under the terms of the GNU General Public License as published by 19 | the Free Software Foundation, either version 3 of the License, or 20 | (at your option) any later version. 21 | 22 | This program is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | 27 | You should have received a copy of the GNU General Public License 28 | along with this program. If not, see . 29 | -------------------------------------------------------------------------------- /app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/newhinton/Round-Sync/56d446a9a57854b51e087dfa0da63f65641eb712/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Activities/ChangelogActivity.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Activities; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.ActionBar; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.appcompat.widget.Toolbar; 7 | 8 | import ca.pkay.rcloneexplorer.util.ActivityHelper; 9 | import ca.pkay.rcloneexplorer.R; 10 | import ca.pkay.rcloneexplorer.util.MarkdownView; 11 | 12 | public class ChangelogActivity extends AppCompatActivity { 13 | 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | super.onCreate(savedInstanceState); 17 | ActivityHelper.applyTheme(this); 18 | try { 19 | setContentView(R.layout.activity_changelog); 20 | } catch (Exception e) { 21 | MarkdownView.closeOnMissingWebView(this, e); 22 | } 23 | Toolbar toolbar = findViewById(R.id.toolbar); 24 | setSupportActionBar(toolbar); 25 | ActionBar actionBar = getSupportActionBar(); 26 | if (actionBar != null) { 27 | actionBar.setDisplayHomeAsUpEnabled(true); 28 | actionBar.setDisplayShowHomeEnabled(true); 29 | } 30 | 31 | MarkdownView markdownView = findViewById(R.id.markdownView); 32 | markdownView.loadAsset("changelog.md"); 33 | } 34 | 35 | @Override 36 | public boolean onSupportNavigateUp() { 37 | onBackPressed(); 38 | return true; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Activities/ContributorActivity.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Activities; 2 | 3 | import android.os.Bundle; 4 | import androidx.appcompat.app.ActionBar; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.appcompat.widget.Toolbar; 7 | 8 | import ca.pkay.rcloneexplorer.util.ActivityHelper; 9 | import ca.pkay.rcloneexplorer.R; 10 | import ca.pkay.rcloneexplorer.util.MarkdownView; 11 | 12 | 13 | public class ContributorActivity extends AppCompatActivity { 14 | 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | ActivityHelper.applyTheme(this); 19 | try { 20 | setContentView(R.layout.activity_contributors); 21 | } catch (Exception e) { 22 | MarkdownView.closeOnMissingWebView(this, e); 23 | } 24 | Toolbar toolbar = findViewById(R.id.toolbar); 25 | setSupportActionBar(toolbar); 26 | ActionBar actionBar = getSupportActionBar(); 27 | if (actionBar != null) { 28 | actionBar.setDisplayHomeAsUpEnabled(true); 29 | actionBar.setDisplayShowHomeEnabled(true); 30 | } 31 | 32 | MarkdownView markdownView = findViewById(R.id.markdownView); 33 | markdownView.loadAsset("contributors.md"); 34 | } 35 | 36 | @Override 37 | public boolean onSupportNavigateUp() { 38 | onBackPressed(); 39 | return true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Activities/ShortcutServiceActivity.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Activities 2 | 3 | import android.os.Bundle 4 | import android.util.Log 5 | import android.widget.Toast 6 | import androidx.appcompat.app.AppCompatActivity 7 | import ca.pkay.rcloneexplorer.R 8 | import ca.pkay.rcloneexplorer.workmanager.SyncManager 9 | import ca.pkay.rcloneexplorer.workmanager.SyncWorker.Companion.EXTRA_TASK_ID 10 | import ca.pkay.rcloneexplorer.workmanager.SyncWorker.Companion.TASK_SYNC_ACTION 11 | 12 | class ShortcutServiceActivity : AppCompatActivity() { 13 | 14 | private val TAG = "ShortcutServiceActivity" 15 | 16 | override fun onCreate(savedInstanceState: Bundle?) { 17 | super.onCreate(savedInstanceState) 18 | moveTaskToBack(true) 19 | 20 | Log.e(TAG, "Recieved start signal!") 21 | 22 | if(intent.action == TASK_SYNC_ACTION) { 23 | Log.e(TAG, "Recieved valid intent.") 24 | val id = intent.extras?.getLong(EXTRA_TASK_ID) 25 | if(id != null) { 26 | SyncManager(this.baseContext).queue(id) 27 | Toast.makeText(this, getString(R.string.shortcut_start_service), Toast.LENGTH_SHORT).show() 28 | } else { 29 | Toast.makeText(this, getString(R.string.shortcut_missing_id), Toast.LENGTH_SHORT).show() 30 | } 31 | } 32 | 33 | Log.e(TAG, "Finish up.") 34 | finish() 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/BroadcastReceivers/BootReciever.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.BroadcastReceivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import ca.pkay.rcloneexplorer.Services.TriggerService; 8 | 9 | public class BootReciever extends BroadcastReceiver { 10 | 11 | @Override 12 | public void onReceive(Context context, Intent intent) { 13 | if (intent.getAction().equals("android.intent.action.BOOT_COMPLETED")) { 14 | new TriggerService(context).queueTrigger(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/BroadcastReceivers/ClearReportBroadcastReciever.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.BroadcastReceivers 2 | 3 | import android.content.BroadcastReceiver 4 | import android.content.Context 5 | import android.content.Intent 6 | import androidx.datastore.preferences.core.edit 7 | import ca.pkay.rcloneexplorer.notifications.ReportNotifications 8 | import ca.pkay.rcloneexplorer.notifications.dataStore 9 | import kotlinx.coroutines.runBlocking 10 | 11 | 12 | class ClearReportBroadcastReciever: BroadcastReceiver() { 13 | 14 | override fun onReceive(context: Context?, intent: Intent) { 15 | val action = intent.action 16 | if (action == ReportNotifications.REPORT_SUCCESS_DELETE_INTENT) { 17 | if(context != null){ 18 | runBlocking { 19 | context.dataStore.edit { settings -> 20 | settings[ReportNotifications.NOTIFICATION_CACHE_SUCCESS_PREFERENCE] = "" 21 | } 22 | } 23 | } 24 | } 25 | if (action == ReportNotifications.REPORT_FAIL_DELETE_INTENT) { 26 | if(context != null){ 27 | runBlocking { 28 | context.dataStore.edit { settings -> 29 | settings[ReportNotifications.NOTIFICATION_CACHE_FAIL_PREFERENCE] = "" 30 | } 31 | } 32 | } 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/BroadcastReceivers/ServeCancelAction.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.BroadcastReceivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | 7 | import ca.pkay.rcloneexplorer.Services.StreamingService; 8 | 9 | public class ServeCancelAction extends BroadcastReceiver { 10 | 11 | @Override 12 | public void onReceive(Context context, Intent intent) { 13 | Intent serveIntent = new Intent(context, StreamingService.class); 14 | context.stopService(serveIntent); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/BroadcastReceivers/SyncRestartAction.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.BroadcastReceivers; 2 | 3 | import static ca.pkay.rcloneexplorer.workmanager.SyncWorker.EXTRA_TASK_ID; 4 | 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | 9 | import ca.pkay.rcloneexplorer.workmanager.SyncManager; 10 | 11 | /** 12 | * This class requires a receiver declaration in the manifest 13 | */ 14 | public class SyncRestartAction extends BroadcastReceiver { 15 | 16 | @Override 17 | public void onReceive(Context context, Intent intent) { 18 | SyncManager sm = new SyncManager(context); 19 | sm.queue(intent.getLongExtra(EXTRA_TASK_ID, -1)); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/BroadcastReceivers/TriggerReciever.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.BroadcastReceivers; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Build; 7 | 8 | import ca.pkay.rcloneexplorer.Services.TriggerService; 9 | import ca.pkay.rcloneexplorer.util.FLog; 10 | 11 | public class TriggerReciever extends BroadcastReceiver { 12 | 13 | private static final String TAG = "TriggerReciever"; 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | FLog.e(TAG, "Recieved Intent"); 18 | 19 | assert intent != null; 20 | if(intent.getAction().equals(TriggerService.TRIGGER_RECIEVE)){ 21 | long i = intent.getLongExtra(TriggerService.TRIGGER_ID, -1); 22 | FLog.e(TAG, "Start Trigger: "+i); 23 | if(i==-1) 24 | return; 25 | 26 | Intent service = new Intent(context, TriggerService.class); 27 | service.setAction(TriggerService.TRIGGER_RECIEVE); 28 | service.putExtra(TriggerService.TRIGGER_ID, i); 29 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 30 | context.startForegroundService(service); 31 | }else{ 32 | context.startService(service); 33 | } 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Database/json/Exporter.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Database.json; 2 | 3 | import android.content.Context; 4 | 5 | import org.json.JSONArray; 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | 9 | import ca.pkay.rcloneexplorer.Database.DatabaseHandler; 10 | import ca.pkay.rcloneexplorer.Items.Filter; 11 | import ca.pkay.rcloneexplorer.Items.Task; 12 | import ca.pkay.rcloneexplorer.Items.Trigger; 13 | 14 | public class Exporter { 15 | 16 | public static String create(Context context) throws JSONException { 17 | 18 | DatabaseHandler dbHandler = new DatabaseHandler(context); 19 | JSONObject main = new JSONObject(); 20 | 21 | JSONArray tasks = new JSONArray(); 22 | for(Task task : dbHandler.getAllTasks()){ 23 | tasks.put(task.asJSON()); 24 | } 25 | main.put("tasks", tasks); 26 | 27 | JSONArray triggers = new JSONArray(); 28 | for(Trigger trigger : dbHandler.getAllTrigger()){ 29 | triggers.put(trigger.asJSON()); 30 | } 31 | main.put("trigger", triggers); 32 | 33 | JSONArray filters = new JSONArray(); 34 | for(Filter filter : dbHandler.getAllFilters()){ 35 | filters.put(filter.asJSON()); 36 | } 37 | main.put("filters", filters); 38 | 39 | 40 | return main.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Dialogs/Dialogs.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Dialogs; 2 | 3 | import androidx.annotation.Nullable; 4 | import androidx.fragment.app.DialogFragment; 5 | 6 | public class Dialogs { 7 | 8 | /** 9 | * Dismiss a dialog, but only if it is still attached to a host activity. 10 | *

11 | * This should be used especially in callbacks, since they have a higher 12 | * chance of being executed in a different lifecycle phase and thus an 13 | * elevated propability of calling DialogFrament.dismiss() on an invalid 14 | * fragment. 15 | * @param dialog the dialog to dismiss 16 | */ 17 | public static void dismissSilently(@Nullable DialogFragment dialog) { 18 | if(dialog != null) { 19 | if(dialog.isStateSaved()){ 20 | dialog.dismissAllowingStateLoss(); 21 | } else if(dialog.isAdded()) { 22 | dialog.dismiss(); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Fragments/FolderSelectorCallback.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Fragments; 2 | 3 | public interface FolderSelectorCallback { 4 | public void selectFolder(String path); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Items/FilterEntry.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Items; 2 | 3 | import android.content.Context; 4 | 5 | import ca.pkay.rcloneexplorer.R; 6 | 7 | public class FilterEntry { 8 | 9 | public static final int FILTER_INCLUDE = 0; 10 | public static final int FILTER_EXCLUDE = 1; 11 | 12 | public int filterType = FILTER_EXCLUDE; 13 | 14 | public String filter; 15 | 16 | 17 | public FilterEntry(int filterType, String filter) { 18 | this.filterType = filterType; 19 | this.filter = filter; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Services/SyncService.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Services 2 | 3 | import android.app.IntentService 4 | import android.content.Intent 5 | import android.util.Log 6 | import ca.pkay.rcloneexplorer.Database.DatabaseHandler 7 | import ca.pkay.rcloneexplorer.workmanager.SyncManager 8 | import de.felixnuesse.extract.extensions.tag 9 | 10 | 11 | /** 12 | * This service is only meant to provide other apps 13 | * the ability to start a task. 14 | * Do not actually implement any sync changes, they only belong in the SyncManager/Worker! 15 | */ 16 | class SyncService: IntentService("ca.pkay.rcexplorer.SYNC_SERCVICE"){ 17 | override fun onHandleIntent(intent: Intent?) { 18 | if(intent == null){ 19 | return 20 | } 21 | 22 | val action = intent.action 23 | val taskId = intent.getIntExtra("task", -1) 24 | // Todo: Allow SyncWorker to run in silent mode, or remove this! 25 | val silentRun = intent.getBooleanExtra("notification", true) 26 | 27 | 28 | if (action.equals("START_TASK")) { 29 | val db = DatabaseHandler(this) 30 | for (task in db.allTasks) { 31 | if (task.id == taskId.toLong()) { 32 | SyncManager(this).queue(task) 33 | } 34 | } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Settings/FileAccessPreferencesFragment.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Settings 2 | 3 | import android.content.SharedPreferences 4 | import android.os.Bundle 5 | import androidx.preference.PreferenceFragmentCompat 6 | import androidx.preference.PreferenceManager 7 | import ca.pkay.rcloneexplorer.R 8 | 9 | class FileAccessPreferencesFragment : PreferenceFragmentCompat() { 10 | 11 | 12 | private lateinit var sharedPreferences: SharedPreferences 13 | 14 | 15 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 16 | setPreferencesFromResource(R.xml.settings_fileaccess_preferences, rootKey) 17 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) 18 | requireActivity().title = getString(R.string.pref_header_file_access) 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/Settings/ThemingPreferencesFragment.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.Settings 2 | 3 | import android.app.Activity 4 | import android.content.SharedPreferences 5 | import android.os.Bundle 6 | import androidx.preference.PreferenceFragmentCompat 7 | import androidx.preference.PreferenceManager 8 | import ca.pkay.rcloneexplorer.R 9 | 10 | class ThemingPreferencesFragment : PreferenceFragmentCompat(), 11 | SharedPreferences.OnSharedPreferenceChangeListener { 12 | 13 | private lateinit var sharedPreferences: SharedPreferences 14 | 15 | override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { 16 | setPreferencesFromResource(R.xml.settings_theming_preferences, rootKey) 17 | sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) 18 | requireActivity().title = getString(R.string.look_and_feel) 19 | 20 | val new = getString(R.string.pref_key_theme) 21 | val old = getString(R.string.pref_key_theme_old) 22 | 23 | if(sharedPreferences.contains(old)) { 24 | sharedPreferences.edit() 25 | .putString(new, sharedPreferences.getString(new, "0")) 26 | .remove(old) 27 | .apply() 28 | } 29 | 30 | sharedPreferences.registerOnSharedPreferenceChangeListener(this) 31 | } 32 | 33 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { 34 | if(key == activity?.getString(R.string.pref_key_theme)) { 35 | requireActivity().recreate() 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/SpinnerAdapters/FilterSpinnerAdapter.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.SpinnerAdapters 2 | 3 | import android.content.Context 4 | import android.graphics.Typeface 5 | import android.view.LayoutInflater 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.ArrayAdapter 9 | import android.widget.TextView 10 | import androidx.core.content.ContextCompat 11 | import ca.pkay.rcloneexplorer.R 12 | 13 | class FilterSpinnerAdapter(context: Context, resource: Int, objects: List) : 14 | ArrayAdapter(context, resource, objects) { 15 | 16 | override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { 17 | val view = convertView ?: LayoutInflater.from(context).inflate(android.R.layout.simple_spinner_dropdown_item, parent, false) 18 | val textView = view.findViewById(android.R.id.text1) 19 | 20 | // Set special styling for "No Filter" option 21 | if (getItem(position) == context.getString(R.string.task_edit_filter_nofilter)) { 22 | textView.setTextColor(ContextCompat.getColor(context, R.color.textColorTertiary)) 23 | textView.setTypeface(null, Typeface.BOLD_ITALIC) 24 | } else { 25 | textView.setTextColor(ContextCompat.getColor(context, R.color.textColorPrimary)) 26 | textView.setTypeface(null, Typeface.NORMAL) 27 | } 28 | 29 | textView.text = getItem(position) 30 | return view 31 | } 32 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/notifications/support/ErrorObject.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.notifications.support 2 | 3 | class ErrorObject(var mErrorObject: String, var mErrorMessage: String) {} -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/rclone/OptionExampleItem.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.rclone 2 | 3 | class OptionExampleItem(var Value: String, var Help: String, var Provider: String){} -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/util/FlagsUtil.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.util 2 | 3 | import android.app.PendingIntent 4 | import android.os.Build 5 | 6 | class FlagsUtil { 7 | 8 | companion object { 9 | 10 | fun getFlagImmutable() : Int { 11 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 12 | PendingIntent.FLAG_IMMUTABLE 13 | } else { 14 | 0 15 | } 16 | } 17 | 18 | fun getFlagImmutable(flag: Int) : Int { 19 | return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 20 | PendingIntent.FLAG_IMMUTABLE and flag 21 | } else { 22 | flag 23 | } 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/util/LargeParcel.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.util; 2 | 3 | import android.os.Bundle; 4 | import android.os.Parcel; 5 | 6 | import androidx.annotation.NonNull; 7 | 8 | public class LargeParcel { 9 | 10 | public static int calculateBundleSize(@NonNull Bundle bundle) { 11 | Parcel parcel = Parcel.obtain(); 12 | parcel.writeBundle(bundle); 13 | int size = parcel.dataSize(); 14 | parcel.recycle(); 15 | return size; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/util/Rfc3339Deserializer.java: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.util; 2 | 3 | import com.fasterxml.jackson.core.JsonParser; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.DeserializationContext; 6 | import com.fasterxml.jackson.databind.JsonNode; 7 | import com.fasterxml.jackson.databind.deser.std.StdDeserializer; 8 | 9 | import java.io.IOException; 10 | import java.text.ParseException; 11 | 12 | import ca.pkay.rcloneexplorer.RcloneRcd; 13 | import io.github.x0b.rfc3339parser.Rfc3339Parser; 14 | import io.github.x0b.rfc3339parser.Rfc3339Strict; 15 | 16 | public class Rfc3339Deserializer extends StdDeserializer { 17 | 18 | private Rfc3339Parser rfc3339Parser; 19 | 20 | protected Rfc3339Deserializer() { 21 | super(Rfc3339Deserializer.class); 22 | rfc3339Parser = new Rfc3339Strict(); 23 | } 24 | 25 | @Override 26 | public Long deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException, JsonProcessingException { 27 | JsonNode timeNode = parser.getCodec().readTree(parser); 28 | try { 29 | return rfc3339Parser.parseCalendar(timeNode.asText()).getTimeInMillis(); 30 | } catch (ParseException e) { 31 | return 0L; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/util/SharedPreferencesUtil.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.util 2 | 3 | import android.content.Context 4 | import androidx.preference.PreferenceManager 5 | 6 | class SharedPreferencesUtil { 7 | 8 | 9 | companion object { 10 | public fun setLastOpenFragment(context: Context, lastFragmentId: Int) { 11 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context).edit() 12 | sharedPreferences.putInt("last_open_fragment", lastFragmentId) 13 | sharedPreferences.apply() 14 | } 15 | 16 | public fun getLastOpenFragment(context: Context, defaultSelection: Int): Int { 17 | val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) 18 | return sharedPreferences.getInt("last_open_fragment", defaultSelection) 19 | } 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /app/src/main/java/ca/pkay/rcloneexplorer/workmanager/Type.kt: -------------------------------------------------------------------------------- 1 | package ca.pkay.rcloneexplorer.workmanager 2 | 3 | enum class Type { 4 | DOWNLOAD, 5 | UPLOAD, 6 | MOVE, 7 | DELETE 8 | } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/extensions/TAG.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.extensions 2 | 3 | fun Any.tag(): String { return this::class.java.simpleName } 4 | 5 | // fragments do have a tag() function. Use TAG() instead. 6 | fun Any.TAG(): String { return this::class.java.simpleName } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/notifications/DiscardChannels.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.notifications 2 | 3 | import android.app.NotificationManager 4 | import android.content.Context 5 | import android.os.Build 6 | 7 | class DiscardChannels { 8 | companion object { 9 | fun discard(context: Context) { 10 | val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager 11 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { 12 | notificationManager.deleteNotificationChannel("ca.pkay.rcexplorer.UPLOAD_CHANNEL") 13 | notificationManager.deleteNotificationChannel("ca.pkay.rcexplorer.DOWNLOAD_CHANNEL") 14 | } 15 | 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/onboarding/SlideLeaveInterface.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.onboarding 2 | 3 | interface SlideLeaveInterface { 4 | 5 | fun allowSlideLeave(id: String): Boolean 6 | 7 | fun onSlideLeavePrevented(id: String) 8 | } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/onboarding/SlideSwitchCallback.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.onboarding 2 | 3 | interface SlideSwitchCallback { 4 | 5 | fun switchChanged(id: String, isChecked: Boolean) 6 | 7 | } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/settings/language/LocaleAdapter.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.settings.language 2 | 3 | import java.util.Locale 4 | 5 | 6 | class LocaleAdapter(private var mLocale: Locale) { 7 | 8 | override fun toString(): String { 9 | return mLocale.displayLanguage 10 | } 11 | 12 | fun getLocale(): Locale { 13 | return mLocale 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/java/de/felixnuesse/extract/settings/preferences/ButtonPreference.kt: -------------------------------------------------------------------------------- 1 | package de.felixnuesse.extract.settings.preferences 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import android.widget.Button 7 | import androidx.preference.Preference 8 | import androidx.preference.PreferenceViewHolder 9 | import ca.pkay.rcloneexplorer.R 10 | 11 | 12 | /** 13 | * https://stackoverflow.com/a/70795847 14 | */ 15 | 16 | 17 | class ButtonPreference(context: Context, attrs: AttributeSet): Preference(context, attrs) { 18 | 19 | private lateinit var holder: PreferenceViewHolder 20 | private var clickListener: View.OnClickListener? = null 21 | private var text: String? = null 22 | 23 | init { 24 | widgetLayoutResource = R.layout.preference_button; 25 | } 26 | 27 | override fun onBindViewHolder(holder: PreferenceViewHolder) { 28 | super.onBindViewHolder(holder) 29 | this.holder = holder 30 | updateViews() 31 | } 32 | 33 | fun setButtonOnClick(listener: View.OnClickListener) { 34 | clickListener = listener 35 | updateViews() 36 | } 37 | 38 | fun setButtonText(text: String) { 39 | this.text = text 40 | updateViews() 41 | } 42 | 43 | private fun updateViews() { 44 | if(this::holder.isInitialized) { 45 | val button = holder.itemView.findViewById