Full Code of amir1376/ab-download-manager for AI

master 5ee92ecf4b90 cached
1054 files
3.9 MB
1.1M tokens
1 requests
Download .txt
Showing preview only (4,376K chars total). Download the full file or copy to clipboard to get everything.
Repository: amir1376/ab-download-manager
Branch: master
Commit: 5ee92ecf4b90
Files: 1054
Total size: 3.9 MB

Directory structure:
gitextract_5ho1xmu5/

├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.yml
│   └── workflows/
│       ├── brew-cask-auto-bump.yml
│       ├── publish.yml
│       └── winget.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── DONATE.md
├── LICENSE
├── README.md
├── REST-API.yml
├── android/
│   └── app/
│       ├── .gitignore
│       ├── build.gradle.kts
│       ├── filetypes.txt
│       └── src/
│           └── main/
│               ├── AndroidManifest.xml
│               ├── kotlin/
│               │   └── com/
│               │       └── abdownloadmanager/
│               │           └── android/
│               │               ├── ABDMApp.kt
│               │               ├── action/
│               │               │   └── Actions.kt
│               │               ├── di/
│               │               │   └── Di.kt
│               │               ├── pages/
│               │               │   ├── about/
│               │               │   │   └── AboutPage.kt
│               │               │   ├── add/
│               │               │   │   ├── AddDownloadActivity.kt
│               │               │   │   ├── multiple/
│               │               │   │   │   ├── AddMultiDownloadActivity.kt
│               │               │   │   │   ├── AddMultiDownloadList.kt
│               │               │   │   │   ├── AddMultiItemPage.kt
│               │               │   │   │   └── AndroidAddMultiDownloadComponent.kt
│               │               │   │   ├── shared/
│               │               │   │   │   ├── CategorySelect.kt
│               │               │   │   │   ├── ExtraConfig.kt
│               │               │   │   │   ├── LocationTextField.kt
│               │               │   │   │   └── SelectQueue.kt
│               │               │   │   └── single/
│               │               │   │       ├── AddSingleDownloadActivity.kt
│               │               │   │       ├── AddSingleDownloadPage.kt
│               │               │   │       └── AndroidAddSingleDownloadComponent.kt
│               │               │   ├── batchdownload/
│               │               │   │   ├── AndroidBatchDownloadComponent.kt
│               │               │   │   └── BatchDownloadPage.kt
│               │               │   ├── browser/
│               │               │   │   ├── BrowserActivity.kt
│               │               │   │   ├── BrowserComponent.kt
│               │               │   │   ├── BrowserUi.kt
│               │               │   │   ├── DownloadInterceptor.kt
│               │               │   │   ├── SearchEngines.kt
│               │               │   │   ├── WebView.kt
│               │               │   │   ├── WebViewHolder.kt
│               │               │   │   └── bookmark/
│               │               │   │       ├── Bookmarks.kt
│               │               │   │       └── EditBookmark.kt
│               │               │   ├── category/
│               │               │   │   ├── CategorySheet.kt
│               │               │   │   └── NewCategory.kt
│               │               │   ├── checksum/
│               │               │   │   ├── AndroidFileChecksumComponent.kt
│               │               │   │   └── FileChecksumPage.kt
│               │               │   ├── crashreport/
│               │               │   │   ├── CrashReportActivity.kt
│               │               │   │   ├── ErrorUi.kt
│               │               │   │   └── ThrowableData.kt
│               │               │   ├── credits/
│               │               │   │   ├── thirdpartylibraries/
│               │               │   │   │   ├── ExternalLibsPage.kt
│               │               │   │   │   └── LibraryDialog.kt
│               │               │   │   └── translators/
│               │               │   │       └── TranslatorsPage.kt
│               │               │   ├── directorypicker/
│               │               │   │   ├── ComposeExtension.kt
│               │               │   │   ├── DirectoryPickerActivity.kt
│               │               │   │   └── DirectoryPickerPage.kt
│               │               │   ├── editdownload/
│               │               │   │   ├── AndroidEditDownloadComponent.kt
│               │               │   │   └── EditDownload.kt
│               │               │   ├── enterurl/
│               │               │   │   ├── AndroidEnterNewURLComponent.kt
│               │               │   │   └── EnterURLPage.kt
│               │               │   ├── home/
│               │               │   │   ├── AndroidDownloadActions.kt
│               │               │   │   ├── BottomNavigation.kt
│               │               │   │   ├── DownloadList.kt
│               │               │   │   ├── FilterStatusIndicator.kt
│               │               │   │   ├── HomeComponent.kt
│               │               │   │   ├── HomePage.kt
│               │               │   │   ├── HomePageStateToPersist.kt
│               │               │   │   ├── Prompts.kt
│               │               │   │   ├── RenderAddMenu.kt
│               │               │   │   ├── RenderDownloadItem.kt
│               │               │   │   ├── RenderMainMenu.kt
│               │               │   │   ├── RenderStatusFilterMenu.kt
│               │               │   │   ├── SelectedQueueItemsOption.kt
│               │               │   │   ├── Selection.kt
│               │               │   │   ├── SimplePager.kt
│               │               │   │   └── sections/
│               │               │   │       ├── Categories.kt
│               │               │   │       ├── queues/
│               │               │   │       │   └── Queues.kt
│               │               │   │       └── sort/
│               │               │   │           ├── DownloadSortBy.kt
│               │               │   │           └── RenderSortMenu.kt
│               │               │   ├── newqueue/
│               │               │   │   └── NewQueue.kt
│               │               │   ├── onboarding/
│               │               │   │   ├── StartUpPageTemplate.kt
│               │               │   │   ├── initialsetup/
│               │               │   │   │   ├── InitialSetupComponent.kt
│               │               │   │   │   └── InitialSetupPage.kt
│               │               │   │   └── permissions/
│               │               │   │       ├── ABDMPermissions.kt
│               │               │   │       ├── AppPermission.kt
│               │               │   │       ├── BatteryOptimizationUtil.kt
│               │               │   │       ├── CustomPermissions.kt
│               │               │   │       ├── PermissionComponent.kt
│               │               │   │       ├── PermissionManager.kt
│               │               │   │       ├── PermissionsPage.kt
│               │               │   │       └── StoragePermissionUtil.kt
│               │               │   ├── perhostsettings/
│               │               │   │   ├── AndroidPerHostSettingsComponent.kt
│               │               │   │   └── PerHostSettingsPage.kt
│               │               │   ├── queue/
│               │               │   │   ├── QueueConfigurationComponent.kt
│               │               │   │   └── QueuesSheet.kt
│               │               │   ├── settings/
│               │               │   │   ├── AndroidSettings.kt
│               │               │   │   ├── AndroidSettingsComponent.kt
│               │               │   │   └── SettingsPage.kt
│               │               │   ├── singledownload/
│               │               │   │   ├── CompletedDownloadPage.kt
│               │               │   │   ├── DesktopSingleDownloadPageComponent.kt
│               │               │   │   ├── ProgressDownloadPage.kt
│               │               │   │   ├── ShowDownloadDialogs.kt
│               │               │   │   └── SingleDownloadPageActivity.kt
│               │               │   └── updater/
│               │               │       ├── NewUpdatePage.kt
│               │               │       └── UpdaterDialog.kt
│               │               ├── receiver/
│               │               │   └── StartOnBootBroadcastReceiver.kt
│               │               ├── repository/
│               │               │   └── AppRepository.kt
│               │               ├── service/
│               │               │   ├── DownloadSystemService.kt
│               │               │   └── KeepAliveServiceReason.kt
│               │               ├── storage/
│               │               │   ├── AndroidExtraDownloadItemSettings.kt
│               │               │   ├── AndroidExtraQueueSettings.kt
│               │               │   ├── AndroidOnBoardingStorage.kt
│               │               │   ├── AppSettingsStorage.kt
│               │               │   ├── BrowserBookmarksStorage.kt
│               │               │   └── HomePageStorage.kt
│               │               ├── ui/
│               │               │   ├── ABDownloadManagerApplicationContent.kt
│               │               │   ├── MainActivity.kt
│               │               │   ├── MainComponent.kt
│               │               │   ├── MainContent.kt
│               │               │   ├── SelectionControls.kt
│               │               │   ├── SheetUI.kt
│               │               │   ├── configurable/
│               │               │   │   ├── AndroidConfigurableUtils.kt
│               │               │   │   ├── ConfigurableSheet.kt
│               │               │   │   ├── SheetInput.kt
│               │               │   │   ├── SheetSpinner.kt
│               │               │   │   ├── android/
│               │               │   │   │   ├── AndroidConfigurableRenderers.kt
│               │               │   │   │   ├── item/
│               │               │   │   │   │   └── PermissionConfigurable.kt
│               │               │   │   │   └── renderer/
│               │               │   │   │       └── PermissionConfigurableRenderer.kt
│               │               │   │   └── comon/
│               │               │   │       ├── CommonConfigurableRenderersForAndroid.kt
│               │               │   │       ├── ConfigurableRenderersForAndroid.kt
│               │               │   │       └── renderer/
│               │               │   │           ├── BooleanConfigurableRenderer.kt
│               │               │   │           ├── DayOfWeekConfigurableRenderer.kt
│               │               │   │           ├── EnumConfigurableRenderer.kt
│               │               │   │           ├── FileChecksumConfigurableRenderer.kt
│               │               │   │           ├── FloatConfigurableRenderer.kt
│               │               │   │           ├── FolderConfigurableRenderer.kt
│               │               │   │           ├── IntConfigurableRenderer.kt
│               │               │   │           ├── LongConfigurableRenderer.kt
│               │               │   │           ├── NavigatableConfigurableRenderer.kt
│               │               │   │           ├── ProxyConfigurableRenderer.kt
│               │               │   │           ├── SpeedLimitConfigurableRenderer.kt
│               │               │   │           ├── StringConfigurableRenderer.kt
│               │               │   │           ├── ThemeConfigurableRenderer.kt
│               │               │   │           └── TimeConfigurableRenderer.kt
│               │               │   ├── menu/
│               │               │   │   ├── Menu.kt
│               │               │   │   ├── RenderMenuInSheet.kt
│               │               │   │   ├── RenderMenuInSinglePage.kt
│               │               │   │   └── StackedMenu.kt
│               │               │   ├── myCombinedClickable.kt
│               │               │   ├── page/
│               │               │   │   ├── PageUI.kt
│               │               │   │   └── PageUtils.kt
│               │               │   └── widget/
│               │               │       └── ComposeWebView.kt
│               │               └── util/
│               │                   ├── ABDMAppManager.kt
│               │                   ├── ABDMServiceNotificationManager.kt
│               │                   ├── AndroidConstants.kt
│               │                   ├── AndroidDefinedPaths.kt
│               │                   ├── AndroidDownloadItemOpener.kt
│               │                   ├── AndroidGlobalExceptionHandler.kt
│               │                   ├── AndroidIntentUtils.kt
│               │                   ├── AndroidUi.kt
│               │                   ├── AppInfo.kt
│               │                   ├── ApplicationBackgroundTracker.kt
│               │                   ├── HeadlessComposeRuntime.kt
│               │                   ├── activity/
│               │                   │   ├── ABDMActivity.kt
│               │                   │   ├── ActivityActions.kt
│               │                   │   ├── RetainedComponentContainer.kt
│               │                   │   └── SerializableExtra.kt
│               │                   ├── compose/
│               │                   │   ├── ObserveUiVisibility.kt
│               │                   │   └── useBack.kt
│               │                   ├── notification/
│               │                   │   └── playNotificationSoundIfAllowed.kt
│               │                   └── pagemanager/
│               │                       ├── BrowserPageManager.kt
│               │                       └── PermissionsPageManager.kt
│               └── res/
│                   ├── drawable/
│                   │   ├── ic_launcher_background.xml
│                   │   ├── ic_launcher_foreground.xml
│                   │   ├── ic_launcher_monochrome.xml
│                   │   └── ic_monochrome.xml
│                   ├── mipmap-anydpi-v26/
│                   │   ├── ic_launcher.xml
│                   │   └── ic_launcher_round.xml
│                   ├── values/
│                   │   ├── strings.xml
│                   │   └── theme.xml
│                   └── xml/
│                       └── provider_paths.xml
├── build.gradle.kts
├── buildSrc/
│   ├── build.gradle.kts
│   ├── settings.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               ├── Plugins.kt
│               ├── buildlogic/
│               │   ├── CiDirs.kt
│               │   ├── CiUtils.kt
│               │   ├── HashUtils.kt
│               │   └── versioning/
│               │       └── VersionUtil.kt
│               └── myPlugins/
│                   ├── composeAndroid.gradle.kts
│                   ├── composeBase.gradle.kts
│                   ├── composeDesktop.gradle.kts
│                   ├── kotlin.gradle.kts
│                   ├── kotlinAndroid.gradle.kts
│                   ├── kotlinMultiplatform.gradle.kts
│                   └── proguardDesktop.gradle.kts
├── compositeBuilds/
│   ├── plugins/
│   │   ├── common-android/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           ├── kotlin/
│   │   │           │   └── ir/
│   │   │           │       └── amirab/
│   │   │           │           └── plugin/
│   │   │           │               └── common_android/
│   │   │           │                   └── task/
│   │   │           │                       ├── EnableFileTypesGeneratorForManifest.kt
│   │   │           │                       ├── FileTypesIntentFilterGenerator.kt
│   │   │           │                       └── SignApkTask.kt
│   │   │           └── resources/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── plugin/
│   │   │                           └── common_android/
│   │   │                               └── AndroidManifest.xml.hbs
│   │   ├── git-version-plugin/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           └── kotlin/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── git_version/
│   │   │                           ├── GitVersionPlugin.kt
│   │   │                           └── core/
│   │   │                               ├── CiReferenceProvider.kt
│   │   │                               ├── GitStatus.kt
│   │   │                               ├── SemanticVersionSelector.kt
│   │   │                               ├── TagSelector.kt
│   │   │                               ├── Utils.kt
│   │   │                               └── extension.kt
│   │   ├── installer-plugin/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           └── kotlin/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── installer/
│   │   │                           ├── InstallerPlugin.kt
│   │   │                           ├── InstallerTargetFormat.kt
│   │   │                           ├── extensiion/
│   │   │                           │   └── InstallerPluginExtension.kt
│   │   │                           ├── tasks/
│   │   │                           │   ├── macos/
│   │   │                           │   │   └── CreateDmgTask.kt
│   │   │                           │   └── windows/
│   │   │                           │       └── NsisTask.kt
│   │   │                           └── utils/
│   │   │                               └── Contants.kt
│   │   └── settings.gradle.kts
│   └── shared/
│       ├── README.md
│       ├── build.gradle.kts
│       ├── platform/
│       │   ├── build.gradle.kts
│       │   └── src/
│       │       └── commonMain/
│       │           └── kotlin/
│       │               └── ir/
│       │                   └── amirab/
│       │                       └── util/
│       │                           └── platform/
│       │                               ├── Arch.kt
│       │                               └── Platform.kt
│       └── settings.gradle.kts
├── crowdin.yml
├── desktop/
│   ├── app/
│   │   ├── build.gradle.kts
│   │   ├── gradle.properties
│   │   ├── icons/
│   │   │   └── icon.icns
│   │   ├── proguard/
│   │   │   ├── decompose.pro
│   │   │   ├── main.pro
│   │   │   └── okhttp.pro
│   │   ├── resources/
│   │   │   ├── common/
│   │   │   │   └── app.properties
│   │   │   └── installer/
│   │   │       └── nsis-script-template.nsi
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── com/
│   │           │       └── abdownloadmanager/
│   │           │           └── desktop/
│   │           │               ├── App.kt
│   │           │               ├── AppArguments.kt
│   │           │               ├── AppComponent.kt
│   │           │               ├── SingleInstanceServerInitializer.kt
│   │           │               ├── actions/
│   │           │               │   ├── DesktopActionFactories.kt
│   │           │               │   ├── dev.kt
│   │           │               │   ├── main.kt
│   │           │               │   └── onevennts/
│   │           │               │       ├── CleanExtraSettingsOnDownloadFinish.kt
│   │           │               │       ├── getOnDownloadCompletionAction.kt
│   │           │               │       └── getOnQueueEventActions.kt
│   │           │               ├── di/
│   │           │               │   └── Di.kt
│   │           │               ├── integration/
│   │           │               │   └── IntegrationHandlerImp.kt
│   │           │               ├── pages/
│   │           │               │   ├── about/
│   │           │               │   │   ├── AboutDialog.kt
│   │           │               │   │   └── AboutPage.kt
│   │           │               │   ├── addDownload/
│   │           │               │   │   ├── ShowAddDownloadDialogs.kt
│   │           │               │   │   ├── multiple/
│   │           │               │   │   │   ├── AddMultiItemPage.kt
│   │           │               │   │   │   ├── AddMultiItemTable.kt
│   │           │               │   │   │   └── DesktopAddMultiDownloadComponent.kt
│   │           │               │   │   ├── shared/
│   │           │               │   │   │   ├── CategorySelect.kt
│   │           │               │   │   │   ├── DialogDropDown.kt
│   │           │               │   │   │   ├── ExtraConfig.kt
│   │           │               │   │   │   ├── LocationTextField.kt
│   │           │               │   │   │   └── SelectQueue.kt
│   │           │               │   │   └── single/
│   │           │               │   │       ├── AddDownloadPage.kt
│   │           │               │   │       └── DesktopAddSingleDownloadComponent.kt
│   │           │               │   ├── batchdownload/
│   │           │               │   │   ├── BatchDownloadWindow.kt
│   │           │               │   │   ├── BatchDownnload.kt
│   │           │               │   │   └── DesktopBatchDownloadComponent.kt
│   │           │               │   ├── category/
│   │           │               │   │   ├── DesktopCategoryDialogManager.kt
│   │           │               │   │   ├── NewCategoryPage.kt
│   │           │               │   │   └── ShowCategoryDialogs.kt
│   │           │               │   ├── checksum/
│   │           │               │   │   ├── DesktopFileChecksumComponent.kt
│   │           │               │   │   ├── FileChecksumPage.kt
│   │           │               │   │   └── FileChecksumWindow.kt
│   │           │               │   ├── confirmexit/
│   │           │               │   │   └── ConfirmExit.kt
│   │           │               │   ├── credits/
│   │           │               │   │   └── translators/
│   │           │               │   │       ├── TranslatorsPage.kt
│   │           │               │   │       ├── TranslatorsTable.kt
│   │           │               │   │       └── TranslatorsWindow.kt
│   │           │               │   ├── editdownload/
│   │           │               │   │   ├── DesktopEditDownloadComponent.kt
│   │           │               │   │   └── EditDownload.kt
│   │           │               │   ├── enterurl/
│   │           │               │   │   ├── DesktopEnterNewURLComponent.kt
│   │           │               │   │   ├── EnterNewDownloadWindow.kt
│   │           │               │   │   └── EnterNewURLPage.kt
│   │           │               │   ├── extenallibs/
│   │           │               │   │   ├── ExternalLibsPage.kt
│   │           │               │   │   ├── ExternalLibsWindow.kt
│   │           │               │   │   ├── LibraryDialog.kt
│   │           │               │   │   └── OpenSourceLibraryTable.kt
│   │           │               │   ├── home/
│   │           │               │   │   ├── Actions.kt
│   │           │               │   │   ├── DesktopDownloadActions.kt
│   │           │               │   │   ├── DownloadItemListDataFlavor.kt
│   │           │               │   │   ├── HomeComponent.kt
│   │           │               │   │   ├── HomePage.kt
│   │           │               │   │   ├── HomePersistedState.kt
│   │           │               │   │   ├── HomeWindow.kt
│   │           │               │   │   ├── dropDownloadItemsHere.kt
│   │           │               │   │   └── sections/
│   │           │               │   │       ├── DownloadList.kt
│   │           │               │   │       ├── Filters.kt
│   │           │               │   │       ├── TableDownloadItem.kt
│   │           │               │   │       ├── category/
│   │           │               │   │       │   └── Categories.kt
│   │           │               │   │       └── queue/
│   │           │               │   │           └── Queues.kt
│   │           │               │   ├── newQueue/
│   │           │               │   │   ├── NewQueueDialog.kt
│   │           │               │   │   └── NewQueuePage.kt
│   │           │               │   ├── perhostsettings/
│   │           │               │   │   ├── DesktopPerHostSettingsComponent.kt
│   │           │               │   │   ├── PerHostSettingsPage.kt
│   │           │               │   │   └── PerHostSettingsWindow.kt
│   │           │               │   ├── poweractionalert/
│   │           │               │   │   ├── PowerActionAlertWindow.kt
│   │           │               │   │   └── PowerActionComponent.kt
│   │           │               │   ├── queue/
│   │           │               │   │   ├── QueueInfoComponent.kt
│   │           │               │   │   ├── QueueWindow.kt
│   │           │               │   │   ├── QueuesComponent.kt
│   │           │               │   │   └── QueuesPage.kt
│   │           │               │   ├── settings/
│   │           │               │   │   ├── DesktopSettings.kt
│   │           │               │   │   ├── DesktopSettingsComponent.kt
│   │           │               │   │   ├── FontManager.kt
│   │           │               │   │   ├── SettingPageStateToPersist.kt
│   │           │               │   │   ├── SettingWindow.kt
│   │           │               │   │   └── SettingsPage.kt
│   │           │               │   ├── singleDownloadPage/
│   │           │               │   │   ├── CompletedDownloadPage.kt
│   │           │               │   │   ├── DesktopSingleDownloadPageComponent.kt
│   │           │               │   │   ├── ProgressDownloadPage.kt
│   │           │               │   │   ├── ShowDownloadDialogs.kt
│   │           │               │   │   └── SingleDownloadPageStateToPersist.kt
│   │           │               │   └── updater/
│   │           │               │       ├── NewUpdatePage.kt
│   │           │               │       └── UpdaterDialog.kt
│   │           │               ├── repository/
│   │           │               │   └── AppRepository.kt
│   │           │               ├── storage/
│   │           │               │   ├── AppSettingsStorage.kt
│   │           │               │   ├── DesktopDefinedPaths.kt
│   │           │               │   ├── DesktopExtraDownloadItemSettings.kt
│   │           │               │   ├── DesktopExtraQueueSettings.kt
│   │           │               │   └── PageStatesStorage.kt
│   │           │               ├── ui/
│   │           │               │   ├── Ui.kt
│   │           │               │   ├── configurable/
│   │           │               │   │   ├── DesktopConfigurableRendererUtils.kt
│   │           │               │   │   ├── comon/
│   │           │               │   │   │   ├── CommonConfigurableRenderersForDesktop.kt
│   │           │               │   │   │   └── renderer/
│   │           │               │   │   │       ├── BooleanConfigurableRenderer.kt
│   │           │               │   │   │       ├── DayOfWeekConfigurableRenderer.kt
│   │           │               │   │   │       ├── EnumConfigurableRenderer.kt
│   │           │               │   │   │       ├── FileChecksumConfigurableRenderer.kt
│   │           │               │   │   │       ├── FloatConfigurableRenderer.kt
│   │           │               │   │   │       ├── FolderConfigurableRenderer.kt
│   │           │               │   │   │       ├── IntConfigurableRenderer.kt
│   │           │               │   │   │       ├── LongConfigurableRenderer.kt
│   │           │               │   │   │       ├── PerHostSettingsConfigurableRenderer.kt
│   │           │               │   │   │       ├── ProxyConfigurableRenderer.kt
│   │           │               │   │   │       ├── SpeedLimitConfigurableRenderer.kt
│   │           │               │   │   │       ├── StringConfigurableRenderer.kt
│   │           │               │   │   │       ├── ThemeConfigurableRenderer.kt
│   │           │               │   │   │       └── TimeConfigurableRenderer.kt
│   │           │               │   │   └── platform/
│   │           │               │   │       ├── DesktopConfigurableRenderers.kt
│   │           │               │   │       ├── item/
│   │           │               │   │       │   └── FontConfigurable.kt
│   │           │               │   │       └── renderer/
│   │           │               │   │           └── FontConfigurableRenderer.kt
│   │           │               │   ├── error/
│   │           │               │   │   └── ErrorUi.kt
│   │           │               │   ├── util/
│   │           │               │   │   └── FilePickerUtils.kt
│   │           │               │   └── widget/
│   │           │               │       ├── ConfirmDialog.kt
│   │           │               │       ├── MessageDialogModel.kt
│   │           │               │       └── Tray.kt
│   │           │               └── utils/
│   │           │                   ├── AppInfo.kt
│   │           │                   ├── AppProperties.kt
│   │           │                   ├── DebugboardUtils.kt
│   │           │                   ├── DesktopEntryCreator.kt
│   │           │                   ├── DesktopShortcutManager.kt
│   │           │                   ├── GlobalAppExceptionHandler.kt
│   │           │                   ├── IntegrationUtil.kt
│   │           │                   ├── KeepAwakeManager.kt
│   │           │                   ├── OSFileIconProvider.kt
│   │           │                   ├── PortableUtil.kt
│   │           │                   ├── native_messaging/
│   │           │                   │   ├── NativeMessaging.kt
│   │           │                   │   └── NativeMessagingManifestApplier.kt
│   │           │                   ├── proxy/
│   │           │                   │   ├── AutoConfigurableProxyProviderForDesktop.kt
│   │           │                   │   ├── DesktopSystemProxySelectorProvider.kt
│   │           │                   │   └── ProxyCachingConfig.kt
│   │           │                   ├── renderapi/
│   │           │                   │   └── RenderApi.kt
│   │           │                   └── singleInstance/
│   │           │                       ├── Comunication.kt
│   │           │                       ├── MutableSingleInstanceServerHandler.kt
│   │           │                       ├── SingleAppInstanceLocker.kt
│   │           │                       ├── SingleInstanceServer.kt
│   │           │                       ├── SingleInstanceServerHandler.kt
│   │           │                       └── SingleInstanceUtil.kt
│   │           └── resources/
│   │               └── configs/
│   │                   └── app_default.properties
│   ├── app-utils/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── abdownloadmanager/
│   │                       └── desktop/
│   │                           └── window/
│   │                               ├── BrowserUtil.kt
│   │                               ├── custom/
│   │                               │   ├── CustomWindow.kt
│   │                               │   ├── DropDownTooltip.kt
│   │                               │   ├── OptionsDialog.kt
│   │                               │   ├── titlebar/
│   │                               │   │   ├── SystemButtonPositionProvider.kt
│   │                               │   │   ├── TitleBar.kt
│   │                               │   │   ├── TitleBarShared.kt
│   │                               │   │   ├── linux/
│   │                               │   │   │   ├── LinuxSystemButtonsProvider.kt
│   │                               │   │   │   ├── LinuxTitleBar.kt
│   │                               │   │   │   └── SystemButtons.Linux.kt
│   │                               │   │   ├── mac/
│   │                               │   │   │   ├── MacTitleBar.kt
│   │                               │   │   │   └── SystemButtons.MacOS.kt
│   │                               │   │   └── windows/
│   │                               │   │       ├── SystemButtons.Windows.kt
│   │                               │   │       └── WindowsTitleBar.kt
│   │                               │   └── utils.kt
│   │                               └── moveSafe.kt
│   ├── mac_utils/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               └── ir/
│   │                   └── amirab/
│   │                       └── util/
│   │                           └── desktop/
│   │                               └── mac/
│   │                                   └── event/
│   │                                       └── MacEventHandler.kt
│   └── shared/
│       ├── build.gradle.kts
│       └── src/
│           └── main/
│               └── kotlin/
│                   └── ir/
│                       └── amirab/
│                           └── util/
│                               └── desktop/
│                                   ├── DesktopUtils.kt
│                                   ├── GlobalKeyboardModifiers.kt
│                                   ├── OsUtils.kt
│                                   ├── PlatformAppActivator.kt
│                                   ├── PlatformDockToggler.kt
│                                   ├── WindowsRegistry.kt
│                                   ├── activator/
│                                   │   └── mac/
│                                   │       └── MacAppActivator.kt
│                                   ├── dock/
│                                   │   └── mac/
│                                   │       └── MacDockToggler.kt
│                                   ├── keepawake/
│                                   │   ├── KeepAwake.kt
│                                   │   ├── MacKeepAwake.kt
│                                   │   └── WindowsKeepAwake.kt
│                                   ├── poweraction/
│                                   │   ├── PowerAction.kt
│                                   │   ├── PowerActionConfig.kt
│                                   │   ├── PowerActionLinux.kt
│                                   │   ├── PowerActionMac.kt
│                                   │   └── PowerActionWindows.kt
│                                   ├── screen/
│                                   │   └── DesktopScreen.kt
│                                   └── utils/
│                                       ├── linux/
│                                       │   └── LinuxUtils.kt
│                                       ├── mac/
│                                       │   ├── FoundationLibrary.kt
│                                       │   └── MacOSUtils.kt
│                                       └── windows/
│                                           └── WindowsUtils.kt
├── downloader/
│   ├── core/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── androidMain/
│   │       │   └── kotlin/
│   │       │       └── ir/
│   │       │           └── amirab/
│   │       │               └── downloader/
│   │       │                   └── utils/
│   │       │                       └── SparseFile.android.kt
│   │       ├── commonMain/
│   │       │   └── kotlin/
│   │       │       └── ir/
│   │       │           └── amirab/
│   │       │               └── downloader/
│   │       │                   ├── DownloadManager.kt
│   │       │                   ├── DownloadManagerMinimalControl.kt
│   │       │                   ├── DownloadSettings.kt
│   │       │                   ├── Downloader.kt
│   │       │                   ├── DownloaderRegistry.kt
│   │       │                   ├── NewDownloadItemProps.kt
│   │       │                   ├── anntation/
│   │       │                   │   └── Markers.kt
│   │       │                   ├── connection/
│   │       │                   │   ├── Connection.kt
│   │       │                   │   ├── HttpDownloaderClient.kt
│   │       │                   │   ├── IResponseInfo.kt
│   │       │                   │   ├── OkHttpHttpDownloaderClient.kt
│   │       │                   │   ├── UserAgent.kt
│   │       │                   │   ├── UserAgentProvider.kt
│   │       │                   │   ├── proxy/
│   │       │                   │   │   ├── AutoConfigurableProxyProvider.kt
│   │       │                   │   │   ├── Proxy.kt
│   │       │                   │   │   ├── ProxyStrategy.kt
│   │       │                   │   │   ├── ProxyStrategyProvider.kt
│   │       │                   │   │   ├── ProxyType.kt
│   │       │                   │   │   └── SystemProxySelectorProvider.kt
│   │       │                   │   └── response/
│   │       │                   │       ├── HttpResponseInfo.kt
│   │       │                   │       └── headers/
│   │       │                   │           ├── RangeHeaderExtractor.kt
│   │       │                   │           └── fileNameExtractor.kt
│   │       │                   ├── db/
│   │       │                   │   ├── DownloadListFileStorage.kt
│   │       │                   │   ├── DownloadQueuePersistedDataAccess.kt
│   │       │                   │   ├── IDownloadListDb.kt
│   │       │                   │   ├── IDownloadPartListDb.kt
│   │       │                   │   ├── MemoryDownloadListDB.kt
│   │       │                   │   ├── MemoryDownloadPartStatesDB.kt
│   │       │                   │   ├── PartListFileStorage.kt
│   │       │                   │   ├── QueueFileStorage.kt
│   │       │                   │   └── TransactionalFileSaver.kt
│   │       │                   ├── destination/
│   │       │                   │   ├── DestWriter.kt
│   │       │                   │   ├── DownloadDestination.kt
│   │       │                   │   ├── IncompleteFileUtil.kt
│   │       │                   │   ├── SegmentedDownloadDestination.kt
│   │       │                   │   └── SimpleDownloadDestination.kt
│   │       │                   ├── downloaditem/
│   │       │                   │   ├── DownloadItemContext.kt
│   │       │                   │   ├── DownloadJob.kt
│   │       │                   │   ├── DownloadJobExtraConfig.kt
│   │       │                   │   ├── DownloadJobStatus.kt
│   │       │                   │   ├── DownloadStatus.kt
│   │       │                   │   ├── IDownloadCredentials.kt
│   │       │                   │   ├── IDownloadItem.kt
│   │       │                   │   ├── contexts/
│   │       │                   │   │   └── DefaultContexts.kt
│   │       │                   │   ├── hls/
│   │       │                   │   │   ├── HLSDownloadCredentials.kt
│   │       │                   │   │   ├── HLSDownloadItem.kt
│   │       │                   │   │   ├── HLSDownloadJob.kt
│   │       │                   │   │   ├── HLSDownloadJobExtraConfig.kt
│   │       │                   │   │   ├── HLSDownloader.kt
│   │       │                   │   │   ├── HLSPartDownloader.kt
│   │       │                   │   │   ├── HLSResponseInfo.kt
│   │       │                   │   │   └── IHLSCredentials.kt
│   │       │                   │   └── http/
│   │       │                   │       ├── HttpDownloadCredentials.kt
│   │       │                   │       ├── HttpDownloadItem.kt
│   │       │                   │       ├── HttpDownloadJob.kt
│   │       │                   │       ├── HttpDownloader.kt
│   │       │                   │       └── IHttpBasedDownloadCredentials.kt
│   │       │                   ├── exception/
│   │       │                   │   ├── DownloadNotSuccessFullException.kt
│   │       │                   │   ├── DownloadValidationException.kt
│   │       │                   │   ├── FileChangedException.kt
│   │       │                   │   ├── NoSpaceInStorageException.kt
│   │       │                   │   ├── PartTooManyErrorException.kt
│   │       │                   │   ├── PrepareDestinationFailedException.kt
│   │       │                   │   ├── ServerPartIsNotTheSameAsWeExpectException.kt
│   │       │                   │   ├── ServerResumeSupportChangeException.kt
│   │       │                   │   └── TooManyErrorException.kt
│   │       │                   ├── part/
│   │       │                   │   ├── DownloadPart.kt
│   │       │                   │   ├── HttpPartDownloader.kt
│   │       │                   │   ├── MediaSegment.kt
│   │       │                   │   ├── PartDownloadStatus.kt
│   │       │                   │   ├── PartDownloader.kt
│   │       │                   │   ├── PartSplitSupport.kt
│   │       │                   │   ├── Parts.kt
│   │       │                   │   └── RangedPart.kt
│   │       │                   ├── queue/
│   │       │                   │   ├── DownloadQueue.kt
│   │       │                   │   ├── ManualDownloadQueue.kt
│   │       │                   │   ├── QueueEvent.kt
│   │       │                   │   ├── QueueManager.kt
│   │       │                   │   └── ScheduleTimes.kt
│   │       │                   └── utils/
│   │       │                       ├── CallAwait.kt
│   │       │                       ├── CollectionUtils.kt
│   │       │                       ├── DuplicateFilter.kt
│   │       │                       ├── EmptyFileCreator.kt
│   │       │                       ├── ExceptionUtils.kt
│   │       │                       ├── FileNameUtil.kt
│   │       │                       ├── FlowUtils.kt
│   │       │                       ├── IDistStat.kt
│   │       │                       ├── LockList.kt
│   │       │                       ├── Logger.kt
│   │       │                       ├── NumUtil.kt
│   │       │                       ├── OnDuplicateStrategy.kt
│   │       │                       ├── SparseFile.kt
│   │       │                       ├── SplitToRange.kt
│   │       │                       └── TimeUtils.kt
│   │       └── desktopMain/
│   │           └── kotlin/
│   │               └── ir/
│   │                   └── amirab/
│   │                       └── downloader/
│   │                           └── utils/
│   │                               └── SparseFile.desktop.kt
│   └── monitor/
│       ├── build.gradle.kts
│       └── src/
│           └── commonMain/
│               └── kotlin/
│                   └── ir/
│                       └── amirab/
│                           └── downloader/
│                               └── monitor/
│                                   ├── CompletedDownloadItemState.kt
│                                   ├── DownloadItemStateFactory.kt
│                                   ├── DownloadMonitor.kt
│                                   ├── DownloadStateUtil.kt
│                                   ├── IDownloadItemState.kt
│                                   ├── IDownloadMonitor.kt
│                                   ├── ProcessingDownloadItemState.kt
│                                   └── UiPart.kt
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── integration/
│   └── server/
│       ├── build.gradle.kts
│       └── src/
│           └── main/
│               ├── kotlin/
│               │   └── com/
│               │       └── abdownloadmanager/
│               │           └── integration/
│               │               ├── ApiQueueModel.kt
│               │               ├── DownloadCredentialsFromIntegration.kt
│               │               ├── Integration.kt
│               │               ├── IntegrationHandler.kt
│               │               ├── MyRequestAndResponse.kt
│               │               ├── MyServer.kt
│               │               ├── MySunHttpServer.kt
│               │               ├── NewDownloadTask.kt
│               │               └── http4k/
│               │                   └── MyHttp4KServer.kt
│               └── resources/
│                   ├── logback.xml
│                   └── rules.pro
├── scripts/
│   ├── install.sh
│   └── uninstall.sh
├── settings.gradle.kts
└── shared/
    ├── app/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               └── shared/
    │       │                   ├── ui/
    │       │                   │   ├── modifier/
    │       │                   │   │   └── PointerHoverIcon.android.kt
    │       │                   │   ├── theme/
    │       │                   │   │   └── PlatformThemeDefinitions.android.kt
    │       │                   │   └── widget/
    │       │                   │       ├── Tooltip.android.kt
    │       │                   │       └── menu/
    │       │                   │           └── custom/
    │       │                   │               ├── Option.android.kt
    │       │                   │               └── WithContextMenu.android.kt
    │       │                   └── util/
    │       │                       ├── ClipboardUtil.android.kt
    │       │                       ├── DesktopDiskStat.android.kt
    │       │                       ├── PlatformThemeDetector.android.kt
    │       │                       ├── downloadlocation/
    │       │                       │   └── PlatformDownloadLocationProvider.android.kt
    │       │                       └── ui/
    │       │                           └── widget/
    │       │                               └── MPBackHandler.android.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               └── shared/
    │       │                   ├── action/
    │       │                   │   ├── CommonActionFactories.kt
    │       │                   │   └── DevActionFactories.kt
    │       │                   ├── downloaderinui/
    │       │                   │   ├── BasicDownloadItem.kt
    │       │                   │   ├── CredentialAndItemMapper.kt
    │       │                   │   ├── DownloadSize.kt
    │       │                   │   ├── DownloadUiChecker.kt
    │       │                   │   ├── DownloaderInUi.kt
    │       │                   │   ├── DownloaderInUiRegistry.kt
    │       │                   │   ├── LinkChecker.kt
    │       │                   │   ├── LinkCheckerFactory.kt
    │       │                   │   ├── add/
    │       │                   │   │   ├── AddDownloadChecker.kt
    │       │                   │   │   ├── CanAddResult.kt
    │       │                   │   │   ├── NewDownloadInputs.kt
    │       │                   │   │   └── NewDownloadInputsFactory.kt
    │       │                   │   ├── edit/
    │       │                   │   │   ├── CanEditDownloadResult.kt
    │       │                   │   │   ├── CanEditWarnings.kt
    │       │                   │   │   ├── DownloadConflictDetector.kt
    │       │                   │   │   ├── EditDownloadCheckerFactory.kt
    │       │                   │   │   ├── EditDownloadInputs.kt
    │       │                   │   │   └── EditDownloadInputsFactory.kt
    │       │                   │   ├── hls/
    │       │                   │   │   ├── HLSDownloaderInUi.kt
    │       │                   │   │   ├── HLSLinkChecker.kt
    │       │                   │   │   ├── HlsItemToCredentialMapper.kt
    │       │                   │   │   ├── UiProcessingItemForHSLFactory.kt
    │       │                   │   │   ├── add/
    │       │                   │   │   │   ├── HLSDownloadUIChecker.kt
    │       │                   │   │   │   └── HLSNewDownloadInputs.kt
    │       │                   │   │   └── edit/
    │       │                   │   │       ├── HLSEditDownloadChecker.kt
    │       │                   │   │       └── HLSEditDownloadInputs.kt
    │       │                   │   └── http/
    │       │                   │       ├── HttpCredentialsToItemMapper.kt
    │       │                   │       ├── HttpDownloaderInUi.kt
    │       │                   │       ├── add/
    │       │                   │       │   ├── HttpDownloadUiChecker.kt
    │       │                   │       │   ├── HttpLinkChecker.kt
    │       │                   │       │   └── HttpNewDownloadInputs.kt
    │       │                   │       ├── applyHostSettingsToExtraConfig.kt
    │       │                   │       └── edit/
    │       │                   │           ├── HttpEditDownloadChecker.kt
    │       │                   │           └── HttpEditDownloadInputs.kt
    │       │                   ├── pagemanager/
    │       │                   │   ├── AboutPageManager.kt
    │       │                   │   ├── AddDownloadDialogManager.kt
    │       │                   │   ├── BatchDownloadPageManager.kt
    │       │                   │   ├── CategoryDialogManager.kt
    │       │                   │   ├── DownloadDialogManager.kt
    │       │                   │   ├── EditDownloadDialogManager.kt
    │       │                   │   ├── EnterNewURLDialogManager.kt
    │       │                   │   ├── ExitApplicationRequestManager.kt
    │       │                   │   ├── FileChecksumDialogManager.kt
    │       │                   │   ├── NotificationSender.kt
    │       │                   │   ├── OpenSourceLibrariesPageManager.kt
    │       │                   │   ├── PerHostSettingsPageManager.kt
    │       │                   │   ├── QueuePageManager.kt
    │       │                   │   ├── SettingsPageManager.kt
    │       │                   │   └── TranslatorsPageManager.kt
    │       │                   ├── pages/
    │       │                   │   ├── adddownload/
    │       │                   │   │   ├── AddDownloadComponent.kt
    │       │                   │   │   ├── AddDownloadConfig.kt
    │       │                   │   │   ├── AddDownloadCredentialsInUiProps.kt
    │       │                   │   │   ├── ImportOptions.kt
    │       │                   │   │   ├── multiple/
    │       │                   │   │   │   ├── BaseAddMultiDownloadComponent.kt
    │       │                   │   │   │   └── OnRequestAdd.kt
    │       │                   │   │   └── single/
    │       │                   │   │       └── BaseAddSingleDownloadComponent.kt
    │       │                   │   ├── batchdownload/
    │       │                   │   │   └── BaseBatchDownloadComponent.kt
    │       │                   │   ├── category/
    │       │                   │   │   └── CategoryComponent.kt
    │       │                   │   ├── checksum/
    │       │                   │   │   └── BaseFileChecksumComponent.kt
    │       │                   │   ├── credits/
    │       │                   │   │   └── translators/
    │       │                   │   │       └── LanguageTranslationInfo.kt
    │       │                   │   ├── editdownload/
    │       │                   │   │   └── BaseEditDownloadComponent.kt
    │       │                   │   ├── enterurl/
    │       │                   │   │   ├── BaseEnterNewURLComponent.kt
    │       │                   │   │   └── DownloaderSelection.kt
    │       │                   │   ├── home/
    │       │                   │   │   ├── AbstractDownloadActions.kt
    │       │                   │   │   ├── BaseHomeComponent.kt
    │       │                   │   │   ├── CategoryActions.kt
    │       │                   │   │   ├── FilterState.kt
    │       │                   │   │   ├── PromptStates.kt
    │       │                   │   │   ├── category/
    │       │                   │   │   │   ├── DefinedStatusCategories.kt
    │       │                   │   │   │   ├── DownloadStatusCategoryFilter.kt
    │       │                   │   │   │   └── DownloadStatusCategoryFilterByList.kt
    │       │                   │   │   └── queue/
    │       │                   │   │       └── QueueActions.kt
    │       │                   │   ├── perhostsettings/
    │       │                   │   │   └── PerHostSettingsComponent.kt
    │       │                   │   └── updater/
    │       │                   │       ├── RenderUpdateNotifications.kt
    │       │                   │       └── UpdateComponent.kt
    │       │                   ├── repository/
    │       │                   │   └── BaseAppRepository.kt
    │       │                   ├── settings/
    │       │                   │   ├── BaseSettingsComponent.kt
    │       │                   │   └── CommonSettings.kt
    │       │                   ├── singledownloadpage/
    │       │                   │   ├── BaseSingleDownloadComponent.kt
    │       │                   │   ├── DownloadStatusStringSource.kt
    │       │                   │   └── SingleDownloadPagePropertyItem.kt
    │       │                   ├── storage/
    │       │                   │   ├── BaseAppSettingsStorage.kt
    │       │                   │   ├── ExtraDownloadSettingsStorage.kt
    │       │                   │   ├── ExtraQueueSettingsStorage.kt
    │       │                   │   ├── IExtraDownloadSettingsStorage.kt
    │       │                   │   ├── IExtraQueueSettingsStorage.kt
    │       │                   │   ├── ILastSavedLocationsStorage.kt
    │       │                   │   ├── PerHostSettingsDatastoreStorage.kt
    │       │                   │   ├── ProxyDatastoreStorage.kt
    │       │                   │   ├── SupportedSizeUnits.kt
    │       │                   │   └── impl/
    │       │                   │       └── LastSavedLocationStorage.kt
    │       │                   ├── ui/
    │       │                   │   ├── Bootstrap.kt
    │       │                   │   ├── configurable/
    │       │                   │   │   ├── BaseEnumConfigurable.kt
    │       │                   │   │   ├── BaseLongConfigurable.kt
    │       │                   │   │   ├── CommonConfigurableRenderers.kt
    │       │                   │   │   ├── Configurable.kt
    │       │                   │   │   ├── ConfigurableGroup.kt
    │       │                   │   │   ├── ConfigurableRendererRegistry.kt
    │       │                   │   │   ├── RenderConfigurable.kt
    │       │                   │   │   ├── RenderConfigurableGroup.kt
    │       │                   │   │   ├── Shared.kt
    │       │                   │   │   └── item/
    │       │                   │   │       ├── BooleanConfigurable.kt
    │       │                   │   │       ├── DayOfWeekConfigurable.kt
    │       │                   │   │       ├── EnumConfigurable.kt
    │       │                   │   │       ├── FileChecksumConfigurable.kt
    │       │                   │   │       ├── FloatConfigurable.kt
    │       │                   │   │       ├── FolderConfigurable.kt
    │       │                   │   │       ├── IntConfigurable.kt
    │       │                   │   │       ├── LongConfigurable.kt
    │       │                   │   │       ├── NavigatableConfigurable.kt
    │       │                   │   │       ├── ProxyConfigurable.kt
    │       │                   │   │       ├── SpeedLimitConfigurable.kt
    │       │                   │   │       ├── StringConfigurable.kt
    │       │                   │   │       ├── ThemeConfigurable.kt
    │       │                   │   │       └── TimeConfigurable.kt
    │       │                   │   ├── modifier/
    │       │                   │   │   └── PointerHoverIcon.kt
    │       │                   │   ├── theme/
    │       │                   │   │   ├── ABDownloaderTheme.kt
    │       │                   │   │   ├── DefaultThemes.kt
    │       │                   │   │   ├── Markdown.kt
    │       │                   │   │   ├── PlatformThemeDefinitions.kt
    │       │                   │   │   ├── ThemeManager.kt
    │       │                   │   │   └── ThemeSettingsStorage.kt
    │       │                   │   └── widget/
    │       │                   │       ├── ActionButton.kt
    │       │                   │       ├── ActionContainer.kt
    │       │                   │       ├── AddUrlButton.kt
    │       │                   │       ├── CheckBox.kt
    │       │                   │       ├── DashedBorder.kt
    │       │                   │       ├── ExpandableItem.kt
    │       │                   │       ├── Handle.kt
    │       │                   │       ├── Help.kt
    │       │                   │       ├── IconPick.kt
    │       │                   │       ├── Language.kt
    │       │                   │       ├── LinkText.kt
    │       │                   │       ├── LoadingIndicator.kt
    │       │                   │       ├── MainActionButton.kt
    │       │                   │       ├── MessageDialogType.kt
    │       │                   │       ├── Multiselect.kt
    │       │                   │       ├── MyIconButton.kt
    │       │                   │       ├── MyTextField.kt
    │       │                   │       ├── MyTextFieldWithIcons.kt
    │       │                   │       ├── NavigateableItem.kt
    │       │                   │       ├── Notification.kt
    │       │                   │       ├── NumberTextField.kt
    │       │                   │       ├── Popup.kt
    │       │                   │       ├── RadioButton.kt
    │       │                   │       ├── Switch.kt
    │       │                   │       ├── Tabs.kt
    │       │                   │       ├── Text.kt
    │       │                   │       ├── Tooltip.kt
    │       │                   │       ├── menu/
    │       │                   │       │   └── custom/
    │       │                   │       │       ├── DropDown.kt
    │       │                   │       │       ├── MenuColumn.kt
    │       │                   │       │       ├── Option.kt
    │       │                   │       │       ├── SiblingMenuPositionProvider.kt
    │       │                   │       │       ├── SubMenu.kt
    │       │                   │       │       └── WithContextMenu.kt
    │       │                   │       └── sort/
    │       │                   │           ├── ComparatorProvider.kt
    │       │                   │           ├── Sort.kt
    │       │                   │           ├── SortIndicatorMode.kt
    │       │                   │           └── sorted.kt
    │       │                   ├── updater/
    │       │                   │   └── UpdateDownloaderViaDownloadSystem.kt
    │       │                   └── util/
    │       │                       ├── AppHostNameVerifier.kt
    │       │                       ├── AppSSLFactoryProvider.kt
    │       │                       ├── AppVersion.kt
    │       │                       ├── AutoStartManager.kt
    │       │                       ├── BaseComponent.kt
    │       │                       ├── BaseConstants.kt
    │       │                       ├── BaseSettings.kt
    │       │                       ├── BottomSheet.kt
    │       │                       ├── BrowserIntegrationModel.kt
    │       │                       ├── ClipboardUtil.kt
    │       │                       ├── ColorUtils.kt
    │       │                       ├── ContainsShortcuts.kt
    │       │                       ├── CoroutineUtils.kt
    │       │                       ├── DefinedPaths.kt
    │       │                       ├── DesktopDiskStat.kt
    │       │                       ├── DownloadFoldersRegistry.kt
    │       │                       ├── DownloadItemOpener.kt
    │       │                       ├── DownloadSystem.kt
    │       │                       ├── DurationUtil.kt
    │       │                       ├── ExceptionToString.kt
    │       │                       ├── FileIconProvider.kt
    │       │                       ├── FilenameFixer.kt
    │       │                       ├── HashUtil.kt
    │       │                       ├── IPUtils.kt
    │       │                       ├── InstanceCheckUtils.kt
    │       │                       ├── LimitationsInUI.kt
    │       │                       ├── Platform.kt
    │       │                       ├── PlatformKeyStroke.kt
    │       │                       ├── PlatformThemeDetector.kt
    │       │                       ├── PopUpContainer.kt
    │       │                       ├── RememberDotLoading.kt
    │       │                       ├── Responsive.kt
    │       │                       ├── SharedConstants.kt
    │       │                       ├── ShortcutManager.kt
    │       │                       ├── ShouldValidate.kt
    │       │                       ├── SizeAndSpeedUnitProvider.kt
    │       │                       ├── SizeUtil.kt
    │       │                       ├── StateUtils.kt
    │       │                       ├── StringUtils.kt
    │       │                       ├── SystemDownloadLocationProvider.kt
    │       │                       ├── TimeUtil.kt
    │       │                       ├── UiConstants.kt
    │       │                       ├── UserAgentProviderFromSettings.kt
    │       │                       ├── ValueUtils.kt
    │       │                       ├── appinfo/
    │       │                       │   └── PreviousVersion.kt
    │       │                       ├── autoremove/
    │       │                       │   └── RemovedDownloadsFromDiskTracker.kt
    │       │                       ├── category/
    │       │                       │   ├── Category.kt
    │       │                       │   ├── CategoryFileStorage.kt
    │       │                       │   ├── CategoryItem.kt
    │       │                       │   ├── CategoryManager.kt
    │       │                       │   ├── CategoryManagerExtensions.kt
    │       │                       │   ├── CategorySelectionMode.kt
    │       │                       │   ├── CategoryStorage.kt
    │       │                       │   ├── DefaultCategories.kt
    │       │                       │   ├── DownloadManagerCategoryItemProvider.kt
    │       │                       │   ├── ICategoryItemProvider.kt
    │       │                       │   └── InMemoryCategoryStorage.kt
    │       │                       ├── downloadlocation/
    │       │                       │   └── PlatformDownloadLocationProvider.kt
    │       │                       ├── extractors/
    │       │                       │   ├── Extractor.kt
    │       │                       │   └── linkextractor/
    │       │                       │       ├── DownloadCredentialExtractor.kt
    │       │                       │       ├── DownloadCredentialsFromCurl.kt
    │       │                       │       └── URLExtractors.kt
    │       │                       ├── mvi/
    │       │                       │   ├── ContainsEffects.kt
    │       │                       │   ├── ContainsScreenState.kt
    │       │                       │   └── EventHandler.kt
    │       │                       ├── ondownloadcompletion/
    │       │                       │   ├── OnDownloadCompletionAction.kt
    │       │                       │   ├── OnDownloadCompletionActionProvider.kt
    │       │                       │   └── OnDownloadCompletionActionRunner.kt
    │       │                       ├── onqueuecompletion/
    │       │                       │   ├── OnQueueCompletionActionProvider.kt
    │       │                       │   ├── OnQueueEventAction.kt
    │       │                       │   └── OnQueueEventActionRunner.kt
    │       │                       ├── perhostsettings/
    │       │                       │   ├── PerHostSettingsItem.kt
    │       │                       │   ├── PerHostSettingsManager.kt
    │       │                       │   └── PerHostSettingsStorage.kt
    │       │                       ├── proxy/
    │       │                       │   ├── IProxyStorage.kt
    │       │                       │   ├── Proxy.kt
    │       │                       │   └── ProxyManager.kt
    │       │                       └── ui/
    │       │                           ├── BaseMyColors.kt
    │       │                           ├── IMyIcons.kt
    │       │                           ├── LocalIsDebugMode.kt
    │       │                           ├── LocalProviders.kt
    │       │                           ├── LocalTitleBarDirection.kt
    │       │                           ├── MyColors.kt
    │       │                           ├── ScrollbableContent.kt
    │       │                           ├── Scrollbar.kt
    │       │                           ├── icon/
    │       │                           │   └── MyIcons.kt
    │       │                           ├── theme/
    │       │                           │   ├── ISystemThemeDetector.kt
    │       │                           │   ├── MaterialRipple.kt
    │       │                           │   ├── MyShapes.kt
    │       │                           │   └── Sizing.kt
    │       │                           └── widget/
    │       │                               ├── Icon.kt
    │       │                               ├── MPBackHandler.kt
    │       │                               ├── ScreenSurface.kt
    │       │                               └── ScrolFade.kt
    │       └── desktopMain/
    │           └── kotlin/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── shared/
    │                           ├── ui/
    │                           │   ├── modifier/
    │                           │   │   └── PointerHoverIcon.desktop.kt
    │                           │   ├── theme/
    │                           │   │   ├── MyContextMenuRepresentation.kt
    │                           │   │   └── PlatformThemeDefinitions.desktop.kt
    │                           │   ├── util/
    │                           │   │   └── LocalWindow.desktop.kt
    │                           │   └── widget/
    │                           │       ├── Tooltip.desktop.kt
    │                           │       ├── menu/
    │                           │       │   ├── custom/
    │                           │       │   │   ├── MenuBar.kt
    │                           │       │   │   ├── Option.desktop.kt
    │                           │       │   │   └── WithContextMenu.desktop.kt
    │                           │       │   └── native/
    │                           │       │       └── NativeMenuBar.kt
    │                           │       └── table/
    │                           │           └── customtable/
    │                           │               ├── CellPadding.kt
    │                           │               ├── Table.kt
    │                           │               ├── TableUtils.kt
    │                           │               └── styled/
    │                           │                   └── MyStyledHeader.kt
    │                           └── util/
    │                               ├── ClipboardUtil.desktop.kt
    │                               ├── DesktopDiskStat.desktop.kt
    │                               ├── PlatformThemeDetector.desktop.kt
    │                               ├── downloadlocation/
    │                               │   ├── DesktopDownloadLocationProvider.kt
    │                               │   ├── LinuxDownloadLocationProvider.kt
    │                               │   ├── MacDownloadLocationProvider.kt
    │                               │   ├── PlatformDownloadLocationProvider.desktop.kt
    │                               │   └── WindowsDownloadLocationProvider.kt
    │                               └── ui/
    │                                   └── widget/
    │                                       └── MPBackHandler.desktop.kt
    ├── auto-start/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       └── ir/
    │       │           └── amirab/
    │       │               └── util/
    │       │                   └── startup/
    │       │                       ├── AndroidStartupManager.kt
    │       │                       └── Startup.android.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── ir/
    │       │           └── amirab/
    │       │               └── util/
    │       │                   └── startup/
    │       │                       ├── AbstractStartupManager.kt
    │       │                       └── Startup.kt
    │       └── desktopMain/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── startup/
    │                               ├── AbstractDesktopStartupManager.kt
    │                               ├── HeadlessStartupDesktop.kt
    │                               ├── MacOSStartupDesktop.kt
    │                               ├── Startup.kt
    │                               ├── UnixXDGStartupDesktop.kt
    │                               ├── Utils.kt
    │                               └── WindowsStartupDesktop.kt
    ├── compose-utils/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── commonMain/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── compose/
    │                               ├── Helpers.kt
    │                               ├── IIconResolver.kt
    │                               ├── IconSource.kt
    │                               ├── StringSource.kt
    │                               ├── action/
    │                               │   ├── AnAction.kt
    │                               │   ├── Extensions.kt
    │                               │   ├── MenuDsl.kt
    │                               │   └── MenuItem.kt
    │                               ├── contants/
    │                               │   └── Constants.kt
    │                               ├── layout/
    │                               │   └── RelativeAlignment.kt
    │                               ├── localizationmanager/
    │                               │   ├── ILanguageNameProvider.kt
    │                               │   ├── LanguageManager.kt
    │                               │   ├── LanguageSourceProvider.kt
    │                               │   ├── LanguageStorage.kt
    │                               │   ├── LocalLanguageManager.kt
    │                               │   ├── MyLocale.kt
    │                               │   └── StringVariableReplacer.kt
    │                               ├── modifiers/
    │                               │   ├── AutoMirror.kt
    │                               │   └── Clickables.kt
    │                               └── resources/
    │                                   └── Resources.kt
    ├── config/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── main/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── config/
    │                               ├── Config.kt
    │                               ├── ConfigKeyWithPrimitiveType.kt
    │                               ├── ConfigToJson.kt
    │                               ├── JsonMapper.kt
    │                               ├── NestedCreator.kt
    │                               ├── datastore/
    │                               │   ├── KotlinSerializationDataStore.kt
    │                               │   └── MapConfigDataStore.kt
    │                               └── extensions.kt
    ├── nanohttp4k/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── main/
    │           ├── kotlin/
    │           │   └── ir/
    │           │       └── amirab/
    │           │           └── util/
    │           │               └── http4k/
    │           │                   └── NanoHttpServer.kt
    │           └── resources/
    │               └── rules.pro
    ├── resources/
    │   ├── build.gradle.kts
    │   ├── contracts/
    │   │   ├── build.gradle.kts
    │   │   └── src/
    │   │       └── commonMain/
    │   │           └── kotlin/
    │   │               └── ir/
    │   │                   └── amirab/
    │   │                       └── resources/
    │   │                           └── contracts/
    │   │                               ├── MyLanguageResource.kt
    │   │                               └── MyStringResource.kt
    │   └── src/
    │       └── commonMain/
    │           ├── kotlin/
    │           │   └── com/
    │           │       └── abdownloadmanager/
    │           │           └── resources/
    │           │               ├── ABDMLanguageResources.kt
    │           │               └── icons/
    │           │                   ├── ABDMIcons.kt
    │           │                   ├── AddLink.kt
    │           │                   ├── Alphabet.kt
    │           │                   ├── AppIcon.kt
    │           │                   ├── Back.kt
    │           │                   ├── BrowserGoogleChrome.kt
    │           │                   ├── BrowserMicrosoftEdge.kt
    │           │                   ├── BrowserMozillaFirefox.kt
    │           │                   ├── BrowserOpera.kt
    │           │                   ├── Check.kt
    │           │                   ├── Clear.kt
    │           │                   ├── Clipboard.kt
    │           │                   ├── Clock.kt
    │           │                   ├── Colors.kt
    │           │                   ├── Copy.kt
    │           │                   ├── Data.kt
    │           │                   ├── Delete.kt
    │           │                   ├── Down.kt
    │           │                   ├── DownSpeed.kt
    │           │                   ├── DragAndDrop.kt
    │           │                   ├── Earth.kt
    │           │                   ├── Edit.kt
    │           │                   ├── Exit.kt
    │           │                   ├── ExternalLink.kt
    │           │                   ├── Fast.kt
    │           │                   ├── File.kt
    │           │                   ├── FileApplication.kt
    │           │                   ├── FileDocument.kt
    │           │                   ├── FileMusic.kt
    │           │                   ├── FilePicture.kt
    │           │                   ├── FileUnknown.kt
    │           │                   ├── FileVideo.kt
    │           │                   ├── FileZip.kt
    │           │                   ├── Flag.kt
    │           │                   ├── Folder.kt
    │           │                   ├── FolderFinished.kt
    │           │                   ├── FolderUnfinished.kt
    │           │                   ├── Grip.kt
    │           │                   ├── Group.kt
    │           │                   ├── Hearth.kt
    │           │                   ├── Info.kt
    │           │                   ├── Language.kt
    │           │                   ├── List.kt
    │           │                   ├── Lock.kt
    │           │                   ├── Menu.kt
    │           │                   ├── Minus.kt
    │           │                   ├── Network.kt
    │           │                   ├── Next.kt
    │           │                   ├── OpenSource.kt
    │           │                   ├── Pause.kt
    │           │                   ├── Permission.kt
    │           │                   ├── Plus.kt
    │           │                   ├── QuestionMark.kt
    │           │                   ├── Queue.kt
    │           │                   ├── QueueStart.kt
    │           │                   ├── QueueStop.kt
    │           │                   ├── Refresh.kt
    │           │                   ├── Resume.kt
    │           │                   ├── Scheduler.kt
    │           │                   ├── Search.kt
    │           │                   ├── SelectAll.kt
    │           │                   ├── SelectInside.kt
    │           │                   ├── SelectInvert.kt
    │           │                   ├── Settings.kt
    │           │                   ├── Share.kt
    │           │                   ├── Sort123.kt
    │           │                   ├── Sort321.kt
    │           │                   ├── Speaker.kt
    │           │                   ├── SpeedLimiter.kt
    │           │                   ├── Stop.kt
    │           │                   ├── StopAll.kt
    │           │                   ├── Telegram.kt
    │           │                   ├── Theme.kt
    │           │                   ├── Undo.kt
    │           │                   ├── Up.kt
    │           │                   ├── VerticalDirection.kt
    │           │                   ├── WindowClose.kt
    │           │                   ├── WindowFloating.kt
    │           │                   ├── WindowMaximize.kt
    │           │                   └── WindowMinimize.kt
    │           └── resources/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── resources/
    │                           ├── credits/
    │                           │   └── translators.json
    │                           └── locales/
    │                               ├── ar_SA.properties
    │                               ├── bn_BD.properties
    │                               ├── bqi_IR.properties
    │                               ├── ckb_IR.properties
    │                               ├── de_DE.properties
    │                               ├── en_US.properties
    │                               ├── es_ES.properties
    │                               ├── fa_IR.properties
    │                               ├── fi_FI.properties
    │                               ├── fr_FR.properties
    │                               ├── hu_HU.properties
    │                               ├── id_ID.properties
    │                               ├── it_IT.properties
    │                               ├── ja_JP.properties
    │                               ├── ka_GE.properties
    │                               ├── ko_KR.properties
    │                               ├── lt_LT.properties
    │                               ├── pl_PL.properties
    │                               ├── pt_BR.properties
    │                               ├── ru_RU.properties
    │                               ├── sq_AL.properties
    │                               ├── th_TH.properties
    │                               ├── tr_TR.properties
    │                               ├── uk_UA.properties
    │                               ├── vi_VN.properties
    │                               ├── zh_CN.properties
    │                               └── zh_TW.properties
    ├── updater/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       ├── AndroidDirectLinkUpdateApplier.kt
    │       │       └── ApkInstaller.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               ├── ArtifactUtil.kt
    │       │               ├── UpdateDownloadLocationProvider.kt
    │       │               ├── UpdateManager.kt
    │       │               ├── github/
    │       │               │   └── githubapi.kt
    │       │               ├── updateapplier/
    │       │               │   ├── BaseUpdateApplier.kt
    │       │               │   ├── UpdateApplier.kt
    │       │               │   ├── UpdateDownloader.kt
    │       │               │   └── UpdateInstaller.kt
    │       │               └── updatechecker/
    │       │                   ├── DummyUpdateChecker.kt
    │       │                   ├── GithubUpdateChecker.kt
    │       │                   ├── UpdateChecker.kt
    │       │                   └── UpdateInfo.kt
    │       └── desktopMain/
    │           ├── kotlin/
    │           │   └── com/
    │           │       └── abdownloadmanager/
    │           │           └── updateapplier/
    │           │               ├── DesktopDirectLinkUpdateApplier.kt
    │           │               ├── UpdateInstallerByWindowsExecutable.kt
    │           │               └── UpdateInstallerFromArchiveFile.kt
    │           └── resources/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── updater/
    │                           ├── updater_linux.sh
    │                           ├── updater_macos.sh
    │                           └── updater_windows.bat
    └── utils/
        ├── build.gradle.kts
        └── src/
            ├── androidMain/
            │   └── kotlin/
            │       └── ir/
            │           └── amirab/
            │               └── util/
            │                   ├── openUrl.android.kt
            │                   └── osfileutil/
            │                       ├── AndroidFileUtil.kt
            │                       └── FileUtils.android.kt
            ├── commonMain/
            │   └── kotlin/
            │       └── ir/
            │           └── amirab/
            │               ├── SelectionUtil.kt
            │               └── util/
            │                   ├── AppVersionTracker.kt
            │                   ├── CallAwait.kt
            │                   ├── CollectionUtils.kt
            │                   ├── Exec.kt
            │                   ├── FileExtensions.kt
            │                   ├── FileNameValidator.kt
            │                   ├── FilenameDecoder.kt
            │                   ├── GuardedEntry.kt
            │                   ├── HttpUrlUtils.kt
            │                   ├── IfThen.kt
            │                   ├── NullCheck.kt
            │                   ├── OkioUtils.kt
            │                   ├── PathValidator.kt
            │                   ├── StringUtil.kt
            │                   ├── ValueHolder.kt
            │                   ├── coroutines/
            │                   │   ├── CombineFlows.kt
            │                   │   ├── CoroutineUtils.kt
            │                   │   └── debounce.kt
            │                   ├── datasize/
            │                   │   ├── BaseSize.kt
            │                   │   ├── CommonSizeConvertConfigs.kt
            │                   │   ├── CommonSizeUnits.kt
            │                   │   ├── ConvertSizeConfig.kt
            │                   │   ├── SizeConverter.kt
            │                   │   ├── SizeFactors.kt
            │                   │   ├── SizeUnit.kt
            │                   │   ├── SizeWithUnit.kt
            │                   │   └── extensions.kt
            │                   ├── enumValueOrNull.kt
            │                   ├── flow/
            │                   │   ├── FlowOperators.kt
            │                   │   ├── FlowUtils.kt
            │                   │   └── StateFlowUtil.kt
            │                   ├── lock.kt
            │                   ├── openUrl.kt
            │                   └── osfileutil/
            │                       ├── FileUtils.kt
            │                       └── FileUtilsBase.kt
            └── desktopMain/
                └── kotlin/
                    └── ir/
                        └── amirab/
                            └── util/
                                ├── openUrl.desktop.kt
                                └── osfileutil/
                                    ├── DesktopFileUtils.kt
                                    ├── FileUtils.desktop.kt
                                    ├── JVMFileUtils.kt
                                    ├── LinuxFileUtils.kt
                                    ├── MacOsFileUtils.kt
                                    └── WindowsFileUtils.kt

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitattributes
================================================
#
# https://help.github.com/articles/dealing-with-line-endings/
#
# Linux start script should use lf
/gradlew        text eol=lf

# These are Windows script files and should use crlf
*.bat           text eol=crlf



================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: ["https://github.com/amir1376/ab-download-manager/blob/master/DONATE.md"] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']


================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.yml
================================================
name: 🐞 Bug Report
description: Report an issue or unexpected behavior in the app
title: "[Bug] Brief summary (keep it short)"
labels: []
body:
  - type: markdown
    attributes:
      value: |
        Thank you for taking the time to report a bug!
        **Before submitting, please [search the existing issues](./issues) to make sure this is not a duplicate.**
  - type: textarea
    id: description
    attributes:
      label: 📝 Description
      description: What happened? What were you trying to do? Please provide a clear and concise description of the problem.
      placeholder: Describe the bug you encountered.
    validations:
      required: true
  - type: input
    id: app-version
    attributes:
      label: 🏷️ App Version
      description: e.g., 1.2.3
      placeholder: "1.2.3"
    validations:
      required: true
  - type: input
    id: platform
    attributes:
      label: 💻 Platform
      description: e.g., Windows 11, macOS 14.2, Ubuntu 24.04
      placeholder: "Windows 11"
    validations:
      required: true
  - type: input
    id: installation-type
    attributes:
      label: 📦 Installation Type (optional)
      description: e.g., .exe installer, dmg file, package manager, installation script
      placeholder: ".exe installer"
    validations:
      required: false
  - type: input
    id: system-device-details
    attributes:
      label: ⚙️ System/Device Details (optional)
      description: e.g., CPU, RAM, device model
      placeholder: "CPU: i7-12700K; RAM: 32GB DDR5"
    validations:
      required: false
  - type: textarea
    id: steps-to-reproduce
    attributes:
      label: 🔁 Steps to Reproduce
      description: List all necessary steps to reproduce the bug.
      placeholder: |
        1. Go to '...'
        2. Click on '....'
        3. Scroll down to '....'
        4. See error
    validations:
      required: true
  - type: textarea
    id: expected-behavior
    attributes:
      label: ✅ Expected Behavior
      description: What did you expect to happen?
      placeholder: Describe the expected behavior.
    validations:
      required: true
  - type: textarea
    id: screenshots
    attributes:
      label: 📷 Screenshots or Recordings (optional)
      description: Drag and drop, paste images, or attach screen recordings here.
      placeholder: Attach screenshots or screen recordings if possible.
    validations:
      required: false
  - type: textarea
    id: additional-info
    attributes:
      label: 🗒️ Additional Information (optional)
      description: Any additional info, logs, context, or links to related issues.
      placeholder: Add any other context about the problem here.
    validations:
      required: false
  - type: textarea
    id: possible-solution
    attributes:
      label: 💡 Possible Solution (optional)
      description: Suggest a fix or reason for the bug, if you have one.
      placeholder: Suggest a possible solution or reason for the bug.
    validations:
      required: false


================================================
FILE: .github/workflows/brew-cask-auto-bump.yml
================================================
name: Auto bump ab-download-manager homebrew cask

on:
  release:
    types: [released]    
  workflow_dispatch: {}     
  
jobs:
  bump:
    runs-on: macos-latest
    env:
      HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.HOMEBREW_GITHUB_API_TOKEN }}
      CASK_NAME: ab-download-manager
      TAP_NAME: amir1376/tap
      GH_REPO: amir1376/homebrew-tap

    steps:
      - name: Tap homebrew cask repo
        run: |
          brew tap ${{ env.TAP_NAME }}

      - name: Extract version
        id: ver
        run: |
          TAG_RAW="${{ github.event.release.tag_name }}"
          TAG_VER="${TAG_RAW#v}"

          if [ -n "$TAG_VER" ]; then
            SRC="release tag"
            V="$TAG_VER"
          else
            SRC="livecheck"
            OUT="$(brew livecheck --cask --json ${{ env.TAP_NAME }}/${{ env.CASK_NAME }} || true)"
            V="$(ruby -rjson -e '
              j = JSON.parse(STDIN.read) rescue []
              if j.is_a?(Array) && j[0] && j[0]["version"]
                v = j[0]["version"]
                if v["latest"] && v["current"] && v["latest"] != v["current"]
                  puts v["latest"]
                end
              end
            ' <<< "$OUT" | tr -d "[:space:]")"
          fi                               
          echo "Source: $SRC"
          echo "Version: ${V:-<none>}"
          echo "version=$V" >> "$GITHUB_OUTPUT"

      - name: Bump cask
        if: ${{ steps.ver.outputs.version != '' }}
        run: |
          V="${{ steps.ver.outputs.version }}"
          echo "Bumping ${{ env.CASK_NAME }} to $V ..."
          brew bump-cask-pr --no-browse --version "$V" "${{ env.TAP_NAME }}/${{ env.CASK_NAME }}"

      - name: Skip (No new version)
        if: ${{ steps.ver.outputs.version == '' }}
        run: echo "No newer version detected; nothing to bump."


================================================
FILE: .github/workflows/publish.yml
================================================
on:
  push:
    tags:
      - "v[0-9]+.[0-9]+.[0-9]+*"
  workflow_dispatch:


permissions:
  contents: write

jobs:
  create-packages:
    strategy:
      matrix:
        os: [ "ubuntu-latest", "ubuntu-24.04-arm", "windows-2022", "windows-11-arm", "macos-15-intel", "macos-15" ]
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Set up JBR
        uses: actions/setup-java@v4
        with:
          distribution: "jetbrains"
          java-package: "jdk"
          java-version: "21"
          check-latest: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Cache Gradle Dependencies
        uses: actions/cache@v4
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ matrix.os }}-gradle
          enableCrossOsArchive: true

      - name: Skip Android build (build android only on Ubuntu)
        if: matrix.os != 'ubuntu-latest'
        shell: "bash"
        run: |
          echo "SKIP_ANDROID_BUILD=true" >> $GITHUB_ENV

      - name: Use Android Secrets
        if: matrix.os == 'ubuntu-latest'
        run: |
          echo "ABDM_KEYSTORE_FILE=${{ secrets.ABDM_KEYSTORE_FILE }}" >> $GITHUB_ENV
          echo "ABDM_KEYSTORE_FILE_PASSWORD=${{ secrets.ABDM_KEYSTORE_FILE_PASSWORD }}" >> $GITHUB_ENV
          echo "ABDM_KEYSTORE_KEY_ALIAS=${{ secrets.ABDM_KEYSTORE_KEY_ALIAS }}" >> $GITHUB_ENV
          echo "ABDM_KEYSTORE_KEY_PASSWORD=${{ secrets.ABDM_KEYSTORE_KEY_PASSWORD }}" >> $GITHUB_ENV

      # Steps specific to macOS (to create DMG for macOS)
      - name: Install create-dmg (for macOS)
        if: startsWith(matrix.os, 'macos-')
        run: |
          brew install create-dmg

      - name: Gradle
        run: |
          ./gradlew
        shell: "bash"

      - name: Build package for current OS using gradle
        shell: bash
        run: |
          ./gradlew createReleaseFolderForCi

      - name: Release Gradle to unlock cache files
        shell: bash
        run: |
          ./gradlew -stop

      - name: Upload output to artifacts
        uses: actions/upload-artifact@v4
        with:
          path: ./build/ci-release
          name: app-${{ matrix.os }}

  release:
    runs-on: "ubuntu-latest"
    needs: [ "create-packages" ]
    steps:
      - uses: "actions/download-artifact@v4"
        name: "Download All Artifacts Into One Directory"
        with:
          path: release
          pattern: app-*
          merge-multiple: true

      - name: Version Info
        id: version
        uses: nowsprinting/check-version-format-action@v3
        with:
          prefix: "v"

      - name: "Show the output tree of release"
        run: |
          tree .
      - uses: softprops/action-gh-release@v2
        with:
          prerelease: ${{ !steps.version.outputs.is_stable }}
          make_latest: legacy
          draft: true
          files: |
            release/binaries/*
          body_path: release/release-notes.md
      - name: "Remove artifacts to free space"
        uses: geekyeggo/delete-artifact@v5
        with:
          name: app-*


================================================
FILE: .github/workflows/winget.yml
================================================
name: Publish to Winget

on:
  release:
    types: [released]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: vedantmgoyal9/winget-releaser@main
        with:
          identifier: amir1376.ABDownloadManager
          token: ${{ secrets.WINGET_TOKEN }}


================================================
FILE: .gitignore
================================================
# Ignore Gradle project-specific cache directory
.gradle
.kotlin

# Ignore Gradle build output directory
build
.idea
local.properties

# Ignore android keystores
*.jks


================================================
FILE: CHANGELOG.md
================================================
# Changelog

## Unreleased

### Added

### Changed

### Deprecated

### Removed

### Fixed

### Security

## 1.8.7

### Added

- Ability to change the storage root when selecting the download location on Android (e.g., save to SD card) (#1101)
- Option to choose the render API on Desktop (#1103)

### Changed

- Default render API set to `SOFTWARE` on Linux

### Improved

- Updated translations
- Increment/decrement buttons in number fields are now more accessible (#1104)
- Minor UI improvements

## 1.8.6

### Added

- Linux ARM support (#1081)
- An option to set max concurrent downloads for manually resumed downloads (#1085)

### Fixed

- Do not reset the download if storage is not mounted yet (#1087)
- Error when assembling HLS media if destination folder was not created yet (#1089)
- Do not reset the download if server changes status code from 206 to 200 (#1088)

### Improved

- Updated translations
- Queue logic improvements (#1086)
- Linux Installation Script updated to support ARM devices (#1090)

## 1.8.5

### Added

- Windows ARM support (#1055)
- In-app browser bookmark feature on Android (#1072)
- In-app browser can be added to the launcher (App Menu)
- In-app browser can be used as the default browser

### Fixed

- System tray crash on some Linux environments (#1060)
- Black screen issue on some Linux environments (#1066)
- Notification sound playing even when notification sounds are muted on Android (#1064)

### Improved

- Updated translations
- In-app browser UI/UX improvements on Android
- System tray now uses native UI on Windows (#1060)
- Use a default User-Agent when no value is provided by the user (#1071)
- Small UI improvements

## 1.8.4

### Added

- In-app browser for Android
- The Android service now tells the user why it is running
- The Add-Multi-Download page can now filter downloads using search and wildcards

### Fixed

- Random app crashes on some Android devices caused by service-related issues
- Issues with the in-app update feature on some Android devices

### Improved

- Updated translations
- The Android Foreground Service is now only used when necessary (active downloads, active queues, scheduled queues) and
  automatically stops after inactivity
- Add-Multi-Download page UI/UX improvements

## 1.8.3

### Added

- Ability to sort and remove queue items on Android (#996)
- A new shortcut to open the download list from the download progress dialog (#1001)

### Fixed

- Download table state not saved properly on desktop (#999)
- Update related notifications appearing repeatedly on android (#998)

### Improved

- Updated translations
- Settings Page UI improvements on android (#990)

## 1.8.2

### Fixed

- Resolved issues with the In-App update feature on some android devices
- Disabled notification badges on the launcher icon on android
- The application crashes on some devices (desktops) because of an issue in system theme detection logic

### Improved

- Updated translations
- Added tooltips for action buttons
- Display selected count in the "Add Multi Download" page on desktop (#970)
- Reduced battery consumption
- Various UI/UX enhancements

## 1.8.1

### Fixed

- Android 10 storage access issue that caused download errors (#977)

### Improved

- Updated translations
- Better support for adaptive icons on Android (#978)
- Improved directory picker on Android (#979)
- Slightly reduced application size

## 1.8.0

### Added

- Android Support
- macOS users can now use homebrew to install/update the application

### Fixed

- Some HLS streams are not recognized properly

### Improved

- Updated translations
- UI improvements

## 1.7.1

### Added

- Support for custom data directory (#895)

### Fixed

- System shortcuts not working on the main page (#885)
- Segment info display issues
- Suggested file names from browsers are now automatically corrected before use (#896)

### Improved

- Translations updated
- Download list UI improvements (#897)
- Extra icon sizes added to the Windows `.ico` file

## 1.7.0

### Added

- Support for downloading media files: audio, video, non encrypted HLS streams from the browser (browser extension needs
  to be updated)
- Option to customize each item individually in the “Add Multiple Downloads” page (by right-clicking on each item) (
  #866)
- “Download Page” and “Custom User-Agent” options are now available in the “Add Download” > "Configs" dialog
- Ability to remove recently used save locations (#873)

### Changed

- Browser integration API updated; updating the browser extension is required to support new features

### Improved

- Updated translations
- The download creation time is now set to when the “Add Download” dialog is opened (#846)

## 1.6.14

### Fixed

- An issue causing slow download speeds on some websites

### Improved

- Updated translations
- Download Engine improvements
- Minor UI improvements

## 1.6.13

### Fixed

- **Access Denied** error could sometimes happen when adding a list of downloads (#826)

### Improved

- Updated translations
- Download engine improvements (#828)
- **Customize Table Columns** popup now supports drag to reorder (#830)

## 1.6.12

### Added

- **Per Host Settings** — save username, password, thread count, user-agent, and more for specific hosts (#820)
- Support for using **Move** action by holding **Shift** during drag & drop (#821)

### Changed

- UI scale is now relative to the system scale instead of using a fixed value (#814)

### Fixed

- Encoding issue with the default download folder on Linux (#810)

### Improved

- Updated translations
- Enhanced multi-display support (#814)
- Main window now remembers its maximized state (#815)

## 1.6.11

### Added

- Option to change the download size unit (#804)

### Fixed

- "Permission denied" error when starting a new download (#795)

### Improved

- Updated translations
- Improved settings page (#805)
- Automatically fix illegal characters in server-provided filenames (#781)
- Better handling of filenames received from the server (#780)
- Use the OS default download location on first launch (#789)

## 1.6.10

### Added

- New Black theme (#767)

### Fixed

- Restored missing executable permissions for files inside archives (macOS & Linux) (#765)
- Eliminated flickering on the "New Update" page (#770)

### Improved

- Updated translations
- Hovering between menus now works without closing the open one (#766)
- Better item selection and new keyboard shortcuts on the queue items page (#769)
- Small UI improvements

## 1.6.9

### Fixed

- "Keep System Awake" was not properly cancelled on Windows (#755)
- "Create Desktop Entry" had issue if the path contains spaces on Linux (#733)
- Application crash on systems that have invalid font names (#737)
- Some settings statuses were not updating correctly (#732)
- "Download Dialog" position shifted when multiple dialogs were open simultaneously (#758)
- "Add Download Dialog" position shifted when multiple dialogs were open simultaneously (#761)

### Improved

- Translations updated
- Better handling of filenames received from the server (#759)

## 1.6.8

### Fixed

- Can't change Auto Shutdown option if it was enabled

## 1.6.7

### Added

- Lithuanian language support
- Kurdish (Sorani) language support
- Option to automatically shut down the system when downloads or queues complete (#726)
- Option to delete partial files on download cancellation (#724)

### Changed

- App icon is now hidden from the Dock at runtime on macOS when the system tray is used (#710)
- Default max download retry count changed to 3

### Fixed

- Removable storages are no longer monitored on Windows (#705)

### Improved

- Translations updated
- System stays awake while downloads are in progress (#725)
- Confirm dialogs and buttons now have better focus behavior
- Dropdowns are now searchable (#706)
- IO Operations improvements

## 1.6.6

### Added

- Option to create desktop entry on Linux (#698)

### Changed

- Renamed Linux desktop and autostart files for better compatibility (#699)

### Fixed

- Removed duplicate UI Scale option in the Settings (#697)

### Improved

- Updated translations
- Pressing "Stop All" now closes all active download windows (#700)

## 1.6.5

### Added

- New themes (Deep Ocean, new Dark, new Light)
- Category accepted file types are now optional (#690)
- Option to change the app font (#692)
- Option to switch between relative and absolute date/time formats (#694)
- Option to clear all items in the queue at once

### Changed

- Renamed the previous Dark theme to **Obsidian**
- Renamed the previous Light theme to **Light Gray**

### Fixed

- Issue where the app wouldn’t start for some Windows users (#695)

### Improved

- Updated translations
- General UI Improvements
- Automatically scroll to new downloads on the main page (#672)
- Improved path validation for new downloads (#693)

## 1.6.4

### Added

- Queues are now visible on the home page, next to the categories (#661)
- In-app update is now supported on macOS (#627)
- New option to enable the native menu bar on macOS (#646)

### Fixed

- macOS: Window now activates properly when "Show Downloads" is clicked from the system tray (#632)
- Linux: Startup desktop entry now includes an icon (#634)
- An issue where the "Edit Download" page could unintentionally change the download status (#641)
- Queue status not updated properly sometimes (#663)

### Improved

- Translations updated
- Minor UI improvements

## 1.6.3

### Added

- Korean Language
- An option to append ".part" extension to incomplete downloads (disabled by default)

### Fixed

- Prevent freeze when opening a file or folder
- Some websites close the connection if we ask for resume support
- Some non-standard links not captured correctly
- Crash when opening browser integration links on macOS
- Multiselect with Meta key not working as expected on macOS
- Multiselect not stopped properly after window focus lost

### Improved

- Translations updated
- Minor UI/UX improvements

## 1.6.2

### Added

- Thai Language

### Fixed

- System Tray crashes sometimes in Linux
- Icons not rendered properly sometimes in Linux
- System Tray icon color in macOS
- Quit handler in macOS

### Improved

- Translations updated
- Respect user defined position of system buttons in Linux

## 1.6.1

### Fixed

- Application shortcut in Windows have no icon

### Improved

- Translations updated

## 1.6.0

### Added

- macOS support
- Polish Language
- Hungarian Language
- Luri Bakhtiari Language
- Silent Download option in the Browser Integration
- Donate button in the app to support the project

### Fixed

- Overriding an existing download sometimes didn't work as expected.
- "Start Queue" checkbox sometimes did not work as expected.

### Improved

- Translations updated
- Custom Window decorations
- Window dragging on Linux is now handled by the OS
- Each platform now uses its own system button style
- JVM updated to version 21

## 1.5.8

### Added

- An option to allow update existing download from "Add Download" page if a duplicate is detected

### Fixed

- Crash when opening "Items" section of "Queues" page

### Improved

- Translations updated
- Duplicate download detection
- Minor UI/UX improvements

## 1.5.7

### Added

- Drag and Drop files to other categories or external applications

### Fixed

- "Parts Info" section in the "Download Progress" window does not expand for the first time

### Improved

- Translations Updated
- Improved UI rendering on Windows, resulting in higher FPS.
- Minor UI/UX Improvements

## 1.5.6

### Added

- Finnish Language Support
- An option to make the start time of queues optional
- An ability to edit saved checksums on the "File Checksum Checker" page'

### Changed

- The "Close" button in the "Download Progress" window has been renamed to "Cancel" (this stops the download and closes
  the window). To close the window without stopping the download, use the "X" button.

### Fixed

- An issue where filenames in email attachments were not captured correctly
- The updater wouldn't resume after the download was stopped
- "Open Folder" doesn’t work properly on Linux when the file name contains special characters.
- Changing settings in the 'Download Progress' window also affects other download items!

### Improved

- Translations updated
- "Download Progress" and "Queues" windows UI improvements
- Pressing "Download Browser Integration" the download page will be opened in the corresponding browser

## 1.5.5

### Added

- Japanese Language
- An option to automatically "Retry Failed Downloads" (Disabled by default for now)
- An option to Import/Export download credentials as curl command

### Fixed

- The download progress sometimes shows incorrect speeds and ETAs
- Some unverified hostnames can't be used when the "Ignore SSL Certificate" is enabled
- Startup on Boot issue in macOS
- Drag And Drop of links issue in macOS
- Some shortcuts didn't work properly in macOS
- System Tray didn't work in macOS

### Improved

- Translations updated
- Minor UI improvements
- App Icon size in macOS
- Override "About" dialog in macOS

## 1.5.4

### Added

- The app now supports full portability by creating an empty `.abdm` directory in the installation folder.
- An option to delete user data (configuration files) when using Windows Uninstaller.

### Fixed

- Unchecked "Use Category" didn't work as expected.

### Improved

- Download engine improvements.
- Translation updated.

## 1.5.3

### Added

- Vietnamese language.
- An option to "Select Queue" dialog to start the queue immediately.
- An option to allow user set custom User-agent in the settings.
- An option to not "Use Category" by default.
- An option to disable SSL Certificate Verification.
- An option to show/hide icon labels in the main toolbar (you can hover over them to see their labels).
- An option to not use System Tray.

### Fixed

- Sometimes Thread count not applied correctly.
- The download completion dialog appeared even when its option is disabled.
- Some servers return 256 Bytes instead of full size

### Improved

- Translations updated
- Minor UI improvements
- Use system language as default language
- Proxy Settings page improved

## 1.5.2

### Added

- An ability to validate downloads with File Checksum
- System Proxy support
- Proxy Auto Configuration (pac) support

### Changed

- Maximum allowed thread count has been increased

### Fixed

- Fixed the incorrect System Tray name on Linux.

### Improved

- Translations Updated
- Settings window size will be remembered now

## 1.5.1

### Added

- Italian Language
- German Language
- Georgian Language
- Indonesian Language
- An option to change download speed unit
- An ability to start new download using Rest-Api

### Fixed

- System tray in Linux now has correct icon and native option menu
- App crashes when changing theme in Linux
- Open file/folder action fails sometimes in Windows

### Improved

- Translations updated
- Split category and location configuration options in multi download page
- Home page minor UI improvements

## 1.5.0

### Added

- In App Update feature.
- An option to track deleted files on disk and remove them from the download list (either manually or automatically).
- Delete option to the Main toolbar.

### Changed

- UI Scale maximum value increased to 3x.

### Fixed

- When you change "Default download Folder", the "Download Location" of categories also updated (if they are inside "
  Default Download Location").
- Issue on the "Add Multiple Download" page where the "Save Mode" set to "All in Same Location" was not functioning as
  expected.
- App does not start on boot when installation path contains space.

### Improved

- Redesigned "About" Page.
- Translations updated.
- "Extra Config" section on the "Add Download" page was not displaying correctly in some languages.

## 1.4.4

### Added

- UI Scale option

### Changed

- The "Selection" cell in download list table can be hidden (optional)

### Fixed

- Improved "Open Folder" in Windows
- Support third party file managers in Windows
- "Download Progress" Window shows up even if the "Auto Show Progress Window" option is disabled
- Improved "Confirm Delete Download" UX
- Improved the readability of shortcut text in menus
- Improved sort of download list by status
- Resize handle moves in opposite direction for RTL languages
- Improved "Home" page
- Improved "About" page
- Updated translations

## 1.4.3

### Added

- "Download Completion" window
- "Exit Confirmation" dialog when there is active download
- An Option to automatically show "Download Completion" window (Optional)
- An Option to automatically show "Download Progress" window when user presses on "Resume" (Optional)

### Changed

- Default thread count is now 8
- Shape of filename of release binaries changed (added arch name after platform name)

### Fixed

- "Delete entire list" task does not remove all downloads
- Filename not detected correctly from some download servers
- Rename download changes state to paused if it was finished
- Improved installation script for linux
- Improved "Settings" page
- Translations updated

## 1.4.2

### Added

- Edit Download Page (Rename, Refresh links/credentials etc…)
- Translators Credit Page
- Traditional Chinese Language
- Spanish Language
- French Language
- Turkish Language

### Changed

- Updated translations

## 1.4.1

### Added

- Portuguese (Brazilian) Language

### Changed

- Updated some languages

### Fixed

- Language names not shown by their native names
- Selected language not saved properly
- Wrong text for "Close" button in "Batch Download" page

## 1.4.0

### Added

- Localization Support
- Persian Language
- Arabic Language
- Chinese (Simplified) Language
- Ukrainian Language
- Russian Language
- Albanian Language
- Bengali Language

### Changed

- Category Download Location is now optional

### Fixed

- A bug in Download Engine
- "Add Queue" page will be shown properly when opened from "Import List" page

## 1.3.0

### Added

- Proxy Support
- Categories now can have URL patterns

### Fixed

- Application freezes a while when we drag(and drop) a large file on it
- Improved category section in the home screen

## 1.2.0

- in this version we replaced Wix installer with Nsis for better customization and more control over the installation
  process in Windows.
- if you use Windows in order to install this version please first uninstall the previous msi version (your settings and
  downloads will be safe)

### Added

- You can now create and customize categories
- Pause/Resume in header actions

### Changed

- Change installer in Windows from Wix to Nsis
- Improved import link page

## 1.1.0

### Added

- Added Batch Download
- Added an option to merge TitleBar with MenuBar (disabled by default)
- Added two cli options --version, --exit

### Fixed

- Fixed Opening downloaded file creates a subprocess in Windows
- Fixed that some non-standard links not imported correctly
- Improved window custom decoration logic and title bar position
- Improved settings page

## 1.0.10

### Fixed

- Improve home page
- Improve download page
- Opening Directory Picker cause the app to crash in Linux
- Folder opened two times when clicking on open folder in Linux

## 1.0.9

### Added

- Sparse File Allocation

### Fixed

- Improve directory picker
- Improve show help UX in settings
- Improve Download Engine

## 1.0.8

### Added

- Use server Last-Modified time option in settings
- Show Open File button if new download already exists and completed

### Fixed

- Improved custom window decoration in linux
- When we click on open folder in linux it opens the file instead!
- Some URLEncoded filenames are not decoded properly

## 1.0.7

### Added

- support follow system Dark/Light mode
- auto paste link (if any) from clipboard when opening add url page

### Fixed

- App is now open in center of screen
- Some settings doesn't persist after app restart
- Download speed shows a high value incorrectly when we reopen the app window after a while
- Some files not downloaded correctly now fixed

## 1.0.6

### Added

- Add Community and Browser Integration links to the app menu

### Changed

- Change default download folder

### Fixed

- Exception will not throw anymore if System Tray is not supported by the OS

## 1.0.5

- Improve Download Engine

## 1.0.4

- Improved UI/UX in Download Page

## 1.0.3

- Download Info Page now show users that a download file supports resuming or not

### Fixed

- Download links that does not support resume now handled correctly
- Some Web pages does not download correctly

## 1.0.2

- Error messages improvements

### Fixed

- handle some webservers does not respect requested range at first place

## 1.0.1

- UI improvements

### Changed

- repository url updated

## 1.0.0

- This is the first release of the app

### Added

- Multi Connection File Download
- Speed limiter
- Download Queues
- Download Scheduler
- DownloadManager Browser Integration Support
- Dark/Light themes


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to AB Download Manager

> ❌ **Important Notice:** The entire codebase is being completely rewritten. Pull requests are **not accepted** at this
> time, as incoming changes may be lost or conflict heavily with ongoing refactoring. Please wait until the refactor is
> complete before submitting any PRs.

Thank you for your interest in contributing to AB Download Manager! I appreciate any help you can offer.

## What Contributions Are Accepted?

I welcome the following types of contributions:

- **Bug Reports**: If you find a bug, please report it by opening an issue with details about the problem.

- **Feature Requests**: Have an idea for a new feature? Let me know by opening an issue or starting a discussion.

- **Translations**: You can translate AB Download Manager into other languages on Crowdin. See the Translations section
  below for more information.

- **Pull Requests**: If you’d like to contribute code, feel free to submit a pull request. Just make sure to read the guidelines below before you start.

## Translations

If you’d like to help translate AB Download Manager into another language, or improve existing translations, you can do
so on Crowdin. Here’s how:

- Visit the project in [Crowdin](https://crowdin.com/project/ab-download-manager)
- Please DO NOT submit translations via pull requests.
- If you want to add a new language, please see [here](https://github.com/amir1376/ab-download-manager/issues/144)

## Pull Requests

If you're ready to contribute code, that's awesome! Before you start, here’s what you need to know about creating a pull request (PR):

- **Discuss First**: Before you start working on a PR, please open an issue or discussion to explain what you want to do. This helps me understand your idea and make sure it's something that can be merged. It also saves time if changes are needed.

- **Fork the Repo**: Fork this repository to your own GitHub account. This creates your own copy where you can make changes.

- **Create a Branch**: In your forked repository, create a new branch for your changes. Give it a descriptive name, like feature/add-some-feature or fix/some-error.

- **Make Your Changes**: Now you can start coding! Make sure your changes follow the project’s coding standards.

- **Submit the PR**: Once you're happy with your changes, push your branch to your fork and submit a pull request. In the PR description, explain what changes you made and why.

- **Review & Feedback**: I’ll review your PR as soon as I can. There might be some feedback or requests for changes, so be ready to make adjustments if needed.

- **Merging**: If everything looks good, I’ll merge your PR into the master branch.


================================================
FILE: DONATE.md
================================================
# ❤️ Donate

Want to support the project? You can make a donation using these crypto addresses:

<a href="#ton" alt="Toncoin"><img src="https://img.shields.io/badge/Donate-Toncoin-0098EA?logo=ton" /></a>
<a href="#usdt" alt="USDT"><img src="https://img.shields.io/badge/Donate-USDT-26A17B?logo=tether" /></a>

## TON

Address (TON): `UQAAPTagY3Y9XWJc9IMYGFYdVHugoBV_Xa3OjdsBHax69eYg`

## USDT

Address (TRC-20): `TK8hMh24yGZGUAYwuSf8rRXncm6s9LJmAx`


If you make a contribution, please text me in [Telegram](https://t.me/Amir_Ai), so I can thank you personally. Thank you for your support!

================================================
FILE: LICENSE
================================================
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
<div align="center">
  <a href="https://abdownloadmanager.com" target="_blank">
    <img width="180" src="assets/logo/app_logo_with_background.svg" alt="AB Download Manager Logo">
  </a>
</div>
<h1 align="center">AB Download Manager</h1>
<p align="center">
    <a href="https://github.com/amir1376/ab-download-manager/releases/latest"><img alt="GitHub Release" src="https://img.shields.io/github/v/release/amir1376/ab-download-manager?color=greenlight&label=latest%20release"></a>
    <a href="https://abdownloadmanager.com"><img alt="AB Download Manager Website" src="https://img.shields.io/badge/project-website-purple?&labelColor=gray"></a>
    <a href="https://t.me/abdownloadmanager_discussion"><img alt="Telegram Group" src="https://img.shields.io/badge/Telegram-Group-blue?logo=telegram&labelColor=gray"></a>
    <a href="https://t.me/abdownloadmanager"><img alt="Telegram Channel" src="https://img.shields.io/badge/Telegram-Channel-blue?logo=telegram&labelColor=gray"></a>
    <a href="https://crowdin.com/project/ab-download-manager"><img alt="Crowdin" src="https://badges.crowdin.net/ab-download-manager/localized.svg"></a>
</p>

<a href="https://abdownloadmanager.com" target="_blank">
    <img alt="AB Download Manager Banner" src="assets/banners/app_banner.png"/>
</a>


## Description

[AB Download Manager](https://abdownloadmanager.com) is a desktop app that helps you manage and organize your downloads more efficiently than ever before.

## Features

- ⚡️ Faster Download Speed
- ⏰ Queues and Schedulers
- 🌐 Browser Extensions
- 💻 Multiplatform (Android / Windows / Linux / Mac)
- 🌙 Multiple Themes (Dark/Light/Black and more) with modern UI
- ❤️ Free and Open Source

Please visit [Project Website](https://abdownloadmanager.com) for more info.

## Installation

### Download and Install the App

<a href="https://abdownloadmanager.com"><img src="https://img.shields.io/badge/Official%20Website-897BFF?logo=abdownloadmanager&logoColor=fff&style=flat-square" alt="Official Website" height="32" /></a>
<a href="https://github.com/amir1376/ab-download-manager/releases/latest"><img src="https://img.shields.io/badge/GitHub%20Releases-2a2f36?logo=github&logoColor=fff&style=flat-square" alt="GitHub Releases" height="32" /></a>

#### Installation script (Linux)

```bash
bash <(curl -fsSL https://raw.githubusercontent.com/amir1376/ab-download-manager/master/scripts/install.sh)
```

#### Winget or Scoop (for Windows)

**winget**:

```bash
winget install amir1376.ABDownloadManager
```

**scoop**:

```bash
scoop install extras/abdownloadmanager
```

#### Homebrew (for macOS & Linux)

```bash
brew tap amir1376/tap && brew install --cask ab-download-manager
```

> ⚠️ **Warning:** This software is NOT on Google Play or other app stores unless listed here. Any version **claiming to be or related to this project** should be considered SCAM and UNSAFE.

For alternative installation methods, uninstallation instructions, and more details, please refer to the [wiki](https://github.com/amir1376/ab-download-manager/wiki/) page.

### Browser Extensions

You can download the browser extension to integrate the app with your browser.

<p align="left">
<a href="https://addons.mozilla.org/firefox/addon/ab-download-manager/">
    <picture>
        <img alt="Chrome Extension" src="./assets/banners/firefox-extension.png" height="48">
    </picture>
</a>
<a href="https://chromewebstore.google.com/detail/bbobopahenonfdgjgaleledndnnfhooj">
    <picture>
        <source media="(prefers-color-scheme: dark)" srcset="./assets/banners/chrome-extension_dark.png" height="48">
        <source media="(prefers-color-scheme: light)" srcset="./assets/banners/chrome-extension_light.png" height="48">
        <img alt="Chrome Extension" src="./assets/banners/chrome-extension_light.png" height="48">
    </picture>
</a>
</p>

## Screenshots

<div align="center">
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="./assets/screenshots/app-home_dark.png">
  <source media="(prefers-color-scheme: light)" srcset="./assets/screenshots/app-home_light.png">
  <img alt="App Home Section" src="./assets/screenshots/app-home_dark.png">
</picture>

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="./assets/screenshots/app-download_dark.png">
  <source media="(prefers-color-scheme: light)" srcset="./assets/screenshots/app-download_light.png">
  <img alt="App Download Section" src="./assets/screenshots/app-download_dark.png">
</picture>
</div>

## Project Status & Feedback

Please keep in mind that this project is in the beginning of its journey.
**Lots of features** are on the way!

**But**, in the meantime you may face **Bugs or Problems**. If you do, please report them to me via the [Community chat](#community) or through `GitHub Issues`, and I'll do my best to fix them ASAP.

## Community

You can join our [Telegram Group](https://t.me/abdownloadmanager_discussion) to:

- Report problems
- Suggest features
- Get help with the app

## Repositories And Source Code

There are multiple repositories related to the **AB Download Manager** project:

| Repository                                                                                 | Description                                                                   |
|--------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| [Main Application](https://github.com/amir1376/ab-download-manager) (You are here)         | Contains the  **Application** that runs on your  **device**                   |
| [Browser Integration](https://github.com/amir1376/ab-download-manager-browser-integration) | Contains the **Browser Extension** to be installed on your  **browser**       |
| [Website](https://github.com/amir1376/ab-download-manager-website)                         | Contains the **AB Download Manager** [website](https://abdownloadmanager.com) |

I've spent a lot of time to create this project.

If you like my work, please consider giving it a ⭐ — thanks! ❤️

## Bug Report

If you notice any bugs in the source code, please report them via the `GitHub Issues` section.

## Build From Source

To compile and test the desktop app on your local machine,
follow these steps:

1. Clone the project.
2. Download and extract the [JBR](https://github.com/JetBrains/JetBrainsRuntime/releases), and make it available by either:
    
    - Adding it to your `PATH`, or
    - Setting the `JAVA_HOME` environment variable to its installation path.
  
3. Navigate to the project directory, open your terminal and execute the following command:

    ```bash
    ./gradlew createReleaseFolderForCi
    ```

4. The output will be available at:

    ```
    <project_dir>/build/ci-release
    ```

> **Note**. This project is compiled and published by GitHub actions [here](./.github/workflows/publish.yml), so if you
> faced any problem you can check that too.

## Translations

If you’d like to help translate AB Download Manager into another language, or improve existing translations, you can do
so on Crowdin. Here’s how:

- Visit the project in [Crowdin](https://crowdin.com/project/ab-download-manager)
- Please DO NOT submit translations via pull requests.
- If you want to add a new language, please see [this](https://github.com/amir1376/ab-download-manager/issues/144).

## Contribution

If you want to contribute to this project, please read [Contributing Guide](CONTRIBUTING.md) first.

## Support the Project

If you'd like to support the project, you can find details on how to donate in the [DONATE.md](DONATE.md) file.


================================================
FILE: REST-API.yml
================================================
openapi: 3.0.0
info:
  title: Download Service API
  version: 1.0.0
  description: API for managing download tasks and queues.
servers:
  - url: http://localhost:15151
    description: Default server running on port 15151

paths:
  /add:
    post:
      summary: Add a new download source
      requestBody:
        description: Data for adding a download source
        content:
          application/json:
            schema:
              type: array
              items:
                type: object
                properties:
                  link:
                    type: string
                    description: The link to the download source
                  headers:
                    type: object
                    additionalProperties:
                      type: string
                    description: Optional headers for the request
                  downloadPage:
                    type: string
                    description: Optional download page URL
      responses:
        "200":
          description: Successfully added the download
          content:
            plain/text:
              schema:
                type: string
                description: OK on success

  /queues:
    get:
      summary: Get list of download queues
      responses:
        "200":
          description: List of download queues
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: integer
                      description: The unique ID of the queue
                    name:
                      type: string
                      description: The name of the queue
  /start-headless-download:
    post:
      summary: Add a new download task
      requestBody:
        description: Data for adding a download task
        content:
          application/json:
            schema:
              type: object
              properties:
                downloadSource:
                  type: object
                  properties:
                    link:
                      type: string
                      description: The link to the download source
                    headers:
                      type: object
                      additionalProperties:
                        type: string
                      description: Optional headers for the request
                    downloadPage:
                      type: string
                      description: Optional download page URL
                folder:
                  type: string
                  description: Optional folder to save the download (Unix style path)
                name:
                  type: string
                  description: Optional name for the download task
                queueId:
                  type: integer
                  description: Optional queue ID to associate the task with
      responses:
        "200":
          description: Successfully added the download task
          content:
            plain/text:
              schema:
                type: string
                description: OK on success


================================================
FILE: android/app/.gitignore
================================================
release


================================================
FILE: android/app/build.gradle.kts
================================================
import buildlogic.CiDirs
import buildlogic.CiUtils
import buildlogic.versioning.convertToVersionCode
import buildlogic.versioning.getAppName
import buildlogic.versioning.getAppVersion
import buildlogic.versioning.getAppVersionString
import buildlogic.versioning.getApplicationPackageName
import com.android.build.api.artifact.SingleArtifact
import ir.amirab.installer.InstallerTargetFormat
import ir.amirab.plugin.common_android.task.SignApkTask
import ir.amirab.plugin.common_android.task.androidEnableFileTypesGeneratorForManifest
import org.gradle.kotlin.dsl.registering
import org.gradle.kotlin.dsl.support.uppercaseFirstChar
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import java.util.Properties

plugins {
    id(Plugins.Android.application)
    id(MyPlugins.kotlinAndroid)
    id(MyPlugins.composeAndroid)
    id(Plugins.ksp)
    id(Plugins.Kotlin.serialization)
    id(Plugins.aboutLibraries)
    id(Plugins.aboutLibrariesAndroid)
}
android {
    defaultConfig {
        minSdk = 26
        targetSdk = 36
        applicationId = getApplicationPackageName()
        versionCode = getAppVersion().convertToVersionCode()
        versionName = getAppVersionString()
    }
    compileSdk = 36
    namespace = "com.abdownloadmanager.android"
    buildTypes {
        debug {
            applicationIdSuffix = ".debug"
            resValue("string", "app_short_name", "AB DM - Debug")
        }
    }
    buildFeatures {
        compose = true
        buildConfig = true
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_21
        targetCompatibility = JavaVersion.VERSION_21
    }
}
kotlin.compilerOptions {
    jvmTarget = JvmTarget.JVM_21
}
dependencies {
    implementation(libs.compose.runtime)
    implementation(libs.compose.foundation)
    implementation(libs.androidx.activity.compose)
    implementation(libs.decompose.jbCompose)
    implementation(libs.aboutLibraries.core)
    implementation(project(":shared:app"))
    ksp(libs.arrow.opticKsp)
}

androidEnableFileTypesGeneratorForManifest(
    targetActivityClass = ".pages.add.AddDownloadActivity",
    fileTypesFile = project.layout.projectDirectory.file("filetypes.txt")
)


// ======= begin of GitHub action stuff
val ciDir = CiUtils.getCiDir(project)
androidComponents.onVariants { variant ->
    tasks.register(
        "createReleaseSignedBinary${variant.name.uppercaseFirstChar()}",
        SignApkTask::class
    ) {
        inputDir.set(variant.artifacts.get(SingleArtifact.APK))
        outputDIr.set(project.layout.buildDirectory.dir("generatedSignedApks"))
        platformToolsVersion.set("36.1.0")
        keystoreUri.set(provider {
            getFromEnvOrProperties("ABDM_KEYSTORE_FILE")
        })
        keystorePassword.set(provider {
            getFromEnvOrProperties("ABDM_KEYSTORE_FILE_PASSWORD")
        })
        keyPassword.set(provider {
            getFromEnvOrProperties("ABDM_KEYSTORE_KEY_PASSWORD")
        })
        keyAlias.set(provider {
            getFromEnvOrProperties("ABDM_KEYSTORE_KEY_ALIAS")
        })
    }
}

val androidBinaries by tasks.registering {
    val signedApks = tasks.named("createReleaseSignedBinaryRelease")
        .map { task ->
            task.outputs.files.singleFile
        }
    inputs.dir(signedApks)
    outputs.dir(ciDir.binariesDir)
    doLast {
        // at the moment we only have one apk
        // if I decided to add multiple targets (arm64 x64 etc..)
        // ... I need to extract arch and use forEach instead of first
        val signedApk = signedApks.get().listFiles()
            .first { it.name.endsWith(".apk") }
        val outputFileName = CiUtils.getTargetFileName(
            getAppName(),
            getAppVersion(),
            InstallerTargetFormat.Apk,
            null,
        )
        CiUtils.copyAndHashToDestination(
            src = signedApk,
            destinationFolder = ciDir.binariesDir.get().asFile,
            name = outputFileName,
        )
    }
}

tasks.register(CiUtils.getCreateBinaryFolderForCiTaskName()) {
    dependsOn(androidBinaries)
}


private val localProperties by lazy {
    val file = project.rootProject.projectDir.resolve("local.properties")
    file.inputStream().use {
        Properties().apply { load(it) }
    }
}

fun getFromEnvOrProperties(key: String): String? {
    val string = (System.getenv(key)?.takeIf { it.isNotEmpty() }
        ?: localProperties.getProperty(key))
    return string
}


================================================
FILE: android/app/filetypes.txt
================================================
# music / audio
mp3
aac
m4a
wav
flac
ogg
wma
amr
opus
mid

# video
mp4
mkv
avi
mov
3gp
webm
wmv
flv
mpeg
mpg
m4v
ts

# image
jpg
jpeg
png
gif
bmp
webp
svg
tiff
ico
heic
raw

# documents / text formats
pdf
txt
doc
docx
xls
xlsx
ppt
pptx
rtf
odt
ods
odp
csv
json
xml
yaml
yml
ini
cfg
md
log

# compressed
zip
rar
7z
tar
gz
bz2
xz
iso

# executables
exe
msi
apk
jar
bat
cmd
sh
deb
rpm

# fonts
ttf
otf
woff
woff2

# ebooks
epub
mobi
azw3
djvu

# subtitles
srt
ass
vtt

# design / creative
psd
ai
eps

# miscellaneous
dat
bin


================================================
FILE: android/app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.INTERNET"/>
    <!--    Start on boot-->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"/>
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
    <application
            android:name=".ABDMApp"
            android:theme="@style/Theme.ABDownloadManager"
            android:icon="@mipmap/ic_launcher"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:usesCleartextTraffic="true"
            android:requestLegacyExternalStorage="true"
            android:label="@string/app_short_name"
    >
        <activity
                android:name=".ui.MainActivity"
                android:exported="true"
                android:launchMode="singleInstance"
                android:windowSoftInputMode="adjustResize"
        >
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity
                android:name=".pages.singledownload.SingleDownloadPageActivity"
                android:exported="true"
                android:theme="@style/Theme.ABDownloadManager.Transparent"
                android:windowSoftInputMode="adjustResize"
        />
        <activity
                android:name=".pages.browser.BrowserActivity"
                android:label="@string/app_browser"
                android:exported="true"
                android:theme="@style/Theme.ABDownloadManager"
                android:windowSoftInputMode="adjustResize"
                android:configChanges="orientation"
        >
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.BROWSABLE"/>
                <data android:scheme="http"/>
                <data android:scheme="https"/>
            </intent-filter>
        </activity>
        <activity-alias
                android:name="com.abdownloadmanager.browser.BrowserIconInLauncher"
                android:enabled="false"
                android:exported="true"
                android:targetActivity=".pages.browser.BrowserActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity-alias>

        <!--        Accept external download from browsers/send intents etc...-->
        <activity
                android:name=".pages.add.AddDownloadActivity"
                android:exported="true"
                android:theme="@style/Theme.ABDownloadManager.Transparent"
        />

        <activity
                android:name=".pages.add.single.AddSingleDownloadActivity"
                android:exported="false"
                android:theme="@style/Theme.ABDownloadManager.Transparent"
                android:windowSoftInputMode="adjustResize"
        />

        <activity
                android:name=".pages.add.multiple.AddMultiDownloadActivity"
                android:exported="false"
                android:theme="@style/Theme.ABDownloadManager"
                android:windowSoftInputMode="adjustResize"
        />

        <activity
                android:name=".pages.directorypicker.DirectoryPickerActivity"
                android:exported="false"
                android:theme="@style/Theme.ABDownloadManager.Transparent"
                android:windowSoftInputMode="adjustResize"
        />

        <activity
                android:name=".pages.crashreport.CrashReportActivity"
                android:exported="true"
                android:theme="@style/Theme.ABDownloadManager.Transparent"
                android:windowSoftInputMode="adjustResize"
        />

        <service
                android:name=".service.DownloadSystemService"
                android:exported="false"
                android:foregroundServiceType="specialUse"
        />

        <receiver
                android:name=".receiver.StartOnBootBroadcastReceiver"
                android:enabled="false"
                android:exported="false"
        >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>

        <provider
                android:name="androidx.core.content.FileProvider"
                android:authorities="${applicationId}.provider"
                android:exported="false"
                android:grantUriPermissions="true">
            <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
        </provider>

    </application>
</manifest>


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/ABDMApp.kt
================================================
package com.abdownloadmanager.android

import android.app.Application
import com.abdownloadmanager.android.di.Di
import com.abdownloadmanager.android.pages.onboarding.permissions.PermissionManager
import com.abdownloadmanager.android.util.ABDMAppManager
import com.abdownloadmanager.android.util.AndroidGlobalExceptionHandler
import com.abdownloadmanager.android.util.AppInfo
import com.abdownloadmanager.android.util.ApplicationBackgroundTracker
import com.abdownloadmanager.shared.repository.BaseAppRepository
import com.abdownloadmanager.shared.util.appinfo.PreviousVersion
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject

class ABDMApp : Application(), KoinComponent {
    val TAG_NAME = ABDMApp::class.simpleName!!
    val appManager: ABDMAppManager by inject()
    val appRepository: BaseAppRepository by inject()
    val previousVersion: PreviousVersion by inject()
    val scope: CoroutineScope by inject()
    override fun onCreate() {
        super.onCreate()
        AppInfo.init(this)
        Di.boot(this)
        ApplicationBackgroundTracker.startTracking(this)
        appRepository.boot()
        previousVersion.boot()
        Thread.setDefaultUncaughtExceptionHandler(
            AndroidGlobalExceptionHandler(
                this,
                Thread.getDefaultUncaughtExceptionHandler(),
            )
        )
        appManager.boot()
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/action/Actions.kt
================================================
package com.abdownloadmanager.android.action

import com.abdownloadmanager.android.util.pagemanager.IBrowserPageManager
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import ir.amirab.util.compose.action.AnAction
import ir.amirab.util.compose.action.simpleAction
import ir.amirab.util.compose.asStringSource

fun createOpenBrowserAction(
    browserPageManager: IBrowserPageManager,
): AnAction {
    return simpleAction(
        Res.string.browser.asStringSource(),
        MyIcons.earth,
    ) {
        browserPageManager.openBrowser(null)
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/di/Di.kt
================================================
package com.abdownloadmanager.android.di

import AndroidDirectLinkUpdateApplier
import android.app.Application
import android.content.Context
import com.abdownloadmanager.github.GithubApi
import com.abdownloadmanager.UpdateDownloadLocationProvider
import com.abdownloadmanager.UpdateManager
import com.abdownloadmanager.android.ABDMApp
import com.abdownloadmanager.android.pages.home.HomePageStateToPersist
import com.abdownloadmanager.android.pages.onboarding.permissions.ABDMPermissions
import com.abdownloadmanager.android.pages.onboarding.permissions.PermissionManager
import com.abdownloadmanager.android.receiver.StartOnBootBroadcastReceiver
import com.abdownloadmanager.android.repository.AppRepository
import com.abdownloadmanager.android.storage.AndroidExtraDownloadItemSettings
import com.abdownloadmanager.android.storage.AndroidExtraQueueSettings
import com.abdownloadmanager.android.storage.AndroidOnBoardingStorage
import com.abdownloadmanager.android.storage.AppSettingsStorage
import com.abdownloadmanager.android.storage.BrowserBookmarksStorage
import com.abdownloadmanager.android.storage.HomePageStorage
import com.abdownloadmanager.android.storage.OnBoardingData
import com.abdownloadmanager.android.util.ABDMAppManager
import com.abdownloadmanager.android.util.ABDMServiceNotificationManager
import com.abdownloadmanager.android.util.AndroidDefinedPaths
import com.abdownloadmanager.android.util.AndroidDownloadItemOpener
import com.abdownloadmanager.android.util.AppInfo
import com.abdownloadmanager.shared.util.SharedConstants
import com.abdownloadmanager.shared.ui.theme.ThemeManager
import ir.amirab.downloader.queue.QueueManager
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.theme.ISystemThemeDetector
import ir.amirab.downloader.DownloadManagerMinimalControl
import ir.amirab.downloader.DownloadSettings
import ir.amirab.downloader.connection.HttpDownloaderClient
import ir.amirab.downloader.connection.OkHttpHttpDownloaderClient
import ir.amirab.downloader.db.*
import ir.amirab.downloader.monitor.DownloadMonitor
import ir.amirab.downloader.utils.IDiskStat
import com.abdownloadmanager.resources.ABDMLanguageResources
import com.abdownloadmanager.shared.downloaderinui.DownloaderInUiRegistry
import com.abdownloadmanager.shared.downloaderinui.hls.HLSDownloaderInUi
import com.abdownloadmanager.shared.downloaderinui.http.HttpDownloaderInUi
import com.abdownloadmanager.shared.repository.BaseAppRepository
import com.abdownloadmanager.shared.storage.BaseAppSettingsStorage
import com.abdownloadmanager.shared.storage.ExtraDownloadSettingsStorage
import com.abdownloadmanager.shared.storage.ExtraQueueSettingsStorage
import com.abdownloadmanager.shared.storage.IExtraDownloadSettingsStorage
import com.abdownloadmanager.shared.storage.IExtraQueueSettingsStorage
import com.abdownloadmanager.shared.storage.ILastSavedLocationsStorage
import com.abdownloadmanager.shared.storage.PerHostSettingsDatastoreStorage
import com.abdownloadmanager.shared.storage.ProxyDatastoreStorage
import com.abdownloadmanager.shared.storage.impl.LastSavedLocationStorage
import com.abdownloadmanager.shared.ui.theme.ThemeSettingsStorage
import com.abdownloadmanager.shared.ui.widget.NotificationManager
import com.abdownloadmanager.shared.updater.UpdateDownloaderViaDownloadSystem
import com.abdownloadmanager.shared.util.AndroidDiskStat
import com.abdownloadmanager.shared.util.AndroidSystemThemeDetector
import com.abdownloadmanager.shared.util.AppVersion
import com.abdownloadmanager.shared.util.DefinedPaths
import com.abdownloadmanager.shared.util.SizeAndSpeedUnitProvider
import com.abdownloadmanager.shared.util.UserAgentProviderFromSettings
import com.abdownloadmanager.shared.util.*
import com.abdownloadmanager.updateapplier.UpdateApplier
import ir.amirab.downloader.DownloadManager
import ir.amirab.util.config.datastore.createMapConfigDatastore
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
import okhttp3.Dispatcher
import okhttp3.OkHttpClient
import org.koin.core.component.KoinComponent
import org.koin.core.context.startKoin
import org.koin.dsl.bind
import org.koin.dsl.module
import com.abdownloadmanager.updatechecker.GithubUpdateChecker
import com.abdownloadmanager.updatechecker.UpdateChecker
import ir.amirab.util.AppVersionTracker
import com.abdownloadmanager.shared.util.appinfo.PreviousVersion
import com.abdownloadmanager.shared.util.autoremove.RemovedDownloadsFromDiskTracker
import com.abdownloadmanager.shared.util.category.*
import com.abdownloadmanager.shared.util.ondownloadcompletion.NoOpOnDownloadCompletionActionProvider
import com.abdownloadmanager.shared.util.ondownloadcompletion.OnDownloadCompletionActionProvider
import com.abdownloadmanager.shared.util.ondownloadcompletion.OnDownloadCompletionActionRunner
import com.abdownloadmanager.shared.util.onqueuecompletion.NoopOnQueueCompletionActionProvider
import com.abdownloadmanager.shared.util.onqueuecompletion.OnQueueEventActionRunner
import com.abdownloadmanager.shared.util.onqueuecompletion.OnQueueCompletionActionProvider
import com.abdownloadmanager.shared.util.perhostsettings.IPerHostSettingsStorage
import com.abdownloadmanager.shared.util.perhostsettings.PerHostSettingsItem
import com.abdownloadmanager.shared.util.perhostsettings.PerHostSettingsManager
import com.abdownloadmanager.shared.util.ui.IMyIcons
import com.abdownloadmanager.shared.util.proxy.IProxyStorage
import com.abdownloadmanager.shared.util.proxy.ProxyData
import com.abdownloadmanager.shared.util.proxy.ProxyManager
import ir.amirab.downloader.DownloaderRegistry
import ir.amirab.downloader.connection.UserAgentProvider
import ir.amirab.downloader.connection.proxy.AutoConfigurableProxyProvider
import ir.amirab.downloader.connection.proxy.NoopSystemProxySelectorProvider
import ir.amirab.downloader.connection.proxy.ProxyStrategyProvider
import ir.amirab.downloader.connection.proxy.SystemProxySelectorProvider
import ir.amirab.downloader.downloaditem.DownloadJob
import ir.amirab.downloader.downloaditem.IDownloadCredentials
import ir.amirab.downloader.downloaditem.IDownloadItem
import ir.amirab.downloader.downloaditem.hls.HLSDownloader
import ir.amirab.downloader.downloaditem.http.HttpDownloadCredentials
import ir.amirab.downloader.downloaditem.http.HttpDownloadItem
import ir.amirab.downloader.downloaditem.http.HttpDownloader
import ir.amirab.downloader.monitor.DownloadItemStateFactory
import ir.amirab.downloader.monitor.IDownloadMonitor
import ir.amirab.downloader.queue.ManualDownloadQueue
import ir.amirab.downloader.utils.EmptyFileCreator
import ir.amirab.util.compose.IIconResolver
import ir.amirab.util.compose.localizationmanager.LanguageManager
import ir.amirab.util.compose.localizationmanager.LanguageSourceProvider
import ir.amirab.util.compose.localizationmanager.LanguageStorage
import ir.amirab.util.config.datastore.kotlinxSerializationDataStore
import ir.amirab.util.startup.AbstractStartupManager
import ir.amirab.util.startup.Startup
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import okhttp3.Protocol
import okhttp3.internal.tls.OkHostnameVerifier

val downloaderModule = module {
    single<IDownloadQueueDatabase> {
        val definedPaths = get<DefinedPaths>()

        DownloadQueueFileStorageDatabase(
            queueFolder = get<DownloadFoldersRegistry>().registerAndGet(
                definedPaths.queuesDir
            ),
            fileSaver = get(),
        )
    }
    single<IDownloadListDb> {
        val definedPaths = get<DefinedPaths>()
        DownloadListFileStorage(
            downloadListFolder = get<DownloadFoldersRegistry>().registerAndGet(
                definedPaths.downloadListDir
            ),
            fileSaver = get(),
        )
    }
    single {
        TransactionalFileSaver(get())
    }
    single<IDownloadPartListDb> {
        val definedPaths = get<DefinedPaths>()
        PartListFileStorage(
            get<DownloadFoldersRegistry>().registerAndGet(
                definedPaths.partsDir
            ),
            get()
        )
    }
    single<IDiskStat> {
        AndroidDiskStat()
    }
    single<ISystemThemeDetector> {
        AndroidSystemThemeDetector(get())
    }
    single {
        QueueManager(get(), get())
    }
    single {
        DownloadFoldersRegistry()
    }
    single {
        DownloadSettings(
            8,
        )
    }
    single {
        ProxyManager(
            get()
        )
    }.bind<ProxyStrategyProvider>()
    single<SystemProxySelectorProvider> {
        NoopSystemProxySelectorProvider()
    }
    single<AutoConfigurableProxyProvider> {
        AutoConfigurableProxyProvider.NoOp()
    }
    single<UserAgentProvider> {
        UserAgentProviderFromSettings(get())
    }
    single<HttpDownloaderClient> {
        OkHttpHttpDownloaderClient(
            get(),
            get(),
            get(),
            get(),
            get(),
        )
    }
    single {
        val downloadSettings: DownloadSettings = get()
        EmptyFileCreator(
            diskStat = get(),
            useSparseFile = { downloadSettings.useSparseFileAllocation }
        )
    }
    single {
        HLSDownloader(inject())
    }
    single {
        HLSDownloaderInUi(get(), get())
    }
    single {
        HttpDownloader(inject())
    }
    single {
        HttpDownloaderInUi(get(), get())
    }
    single {
        DownloaderInUiRegistry().apply {
            add(get<HttpDownloaderInUi>())
            add(get<HLSDownloaderInUi>())
        }
    }.bind<DownloadItemStateFactory<IDownloadItem, DownloadJob>>()
    single {
        DownloaderRegistry().apply {
            add(get<HttpDownloader>())
            add(get<HLSDownloader>())
        }
    }
    single {
        val definedPaths = get<DefinedPaths>()
        DownloadManager(
            get(),
            get(),
            get(),
            get(),
            get(),
            get<DownloadFoldersRegistry>().registerAndGet(
                definedPaths.downloadDataDir
            )
        )
    }.bind(DownloadManagerMinimalControl::class)
    single {
        ManualDownloadQueue(get(), get())
    }
    single<IDownloadMonitor> {
        DownloadMonitor(
            downloadManager = get(),
            manualDownloadQueue = get(),
            downloadItemStateFactory = inject(),
        )
    }
}
val downloadSystemModule = module {
    single {
        val definedPaths = get<DefinedPaths>()
        get<DownloadFoldersRegistry>().registerAndGet(definedPaths.categoriesDir)
        CategoryFileStorage(
            file = definedPaths.categoriesFile.toFile(),
            fileSaver = get()
        )
    }.bind<CategoryStorage>()
    single {
        FileIconProviderUsingCategoryIcons(
            get(),
            get(),
            get(),
            get(),
        )
    }.bind<FileIconProvider>()
    single {
        DefaultCategories(
            icons = get(),
            getDefaultDownloadFolder = {
                get<BaseAppSettingsStorage>().defaultDownloadFolder.value
            }
        )
    }
    single {
        DownloadManagerCategoryItemProvider(get())
    }.bind<ICategoryItemProvider>()
    single {
        CategoryManager(
            categoryStorage = get(),
            scope = get(),
            defaultCategoriesFactory = get(),
            categoryItemProvider = get(),
        )
    }

    single {
        DownloadSystem(
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
        )
    }
    single {
        val definedPaths = get<DefinedPaths>()
        val extraDownloadSettingsStorageFolder = get<DownloadFoldersRegistry>().registerAndGet(
            definedPaths.extraDownloadSettings
        )
        ExtraDownloadSettingsStorage(
            extraDownloadSettingsStorageFolder,
            get(),
            AndroidExtraDownloadItemSettings
        )
    }.bind<IExtraDownloadSettingsStorage<*>>()
    single {
        val definedPaths = get<DefinedPaths>()
        val extraQueueSettingsStorageFolder = get<DownloadFoldersRegistry>().registerAndGet(
            definedPaths.extraQueueSettings
        )
        ExtraQueueSettingsStorage(
            extraQueueSettingsStorageFolder,
            get(),
            AndroidExtraQueueSettings
        )
    }.apply {
        bind<IExtraQueueSettingsStorage<*>>()
    }
    single<OnDownloadCompletionActionProvider> {
        NoOpOnDownloadCompletionActionProvider()
    }
    single<OnQueueCompletionActionProvider> {
        NoopOnQueueCompletionActionProvider()
    }
    single {
        OnDownloadCompletionActionRunner(
            downloadManagerMinimalControl = get(),
            scope = get(),
            onDownloadCompletionActionProvider = get(),
        )
    }
    single {
        OnQueueEventActionRunner(
            queueManager = get(),
            scope = get(),
            onQueueCompletionActionProvider = get(),
        )
    }
    single {
        PermissionManager(
            ABDMPermissions.importantPermissions,
            get(),
        )
    }
}
val coroutineModule = module {
    single {
        CoroutineScope(SupervisorJob())
    }
}
val jsonModule = module {
    single {
        val downloaderRegistry: DownloaderRegistry by inject()
        Json {
            this.encodeDefaults = true
            this.prettyPrint = true
            this.ignoreUnknownKeys = true
            this.serializersModule = SerializersModule {
                polymorphic(IDownloadItem::class) {
                    downloaderRegistry.getAll().forEach {
                        subclass(it.downloadItemClass, it.downloadItemSerializer)
                    }
                    defaultDeserializer {
                        HttpDownloadItem.serializer()
                    }
                }
                polymorphic(IDownloadCredentials::class) {
                    downloaderRegistry.getAll().forEach {
                        subclass(it.downloadCredentialsClass, it.downloadCredentialsSerializer)
                    }
                    defaultDeserializer {
                        HttpDownloadCredentials.serializer()
                    }
                }
            }
        }
    }
}
val updaterModule = module {
    single {
        val definedPaths = get<DefinedPaths>()
        UpdateDownloadLocationProvider {
            definedPaths.updateDownloadLocation.toFile()
        }
    }
    single<UpdateApplier> {
        val definedPaths = get<DefinedPaths>()
        definedPaths.updateDownloadLocation
        AndroidDirectLinkUpdateApplier(
            updateDownloader = UpdateDownloaderViaDownloadSystem(
                get(),
                get(),
            ),
        )
    }
    single<UpdateChecker> {
        GithubUpdateChecker(
            AppVersion.get(),
            githubApi = GithubApi(
                owner = SharedConstants.projectGithubOwner,
                repo = SharedConstants.projectGithubRepo,
                client = OkHttpClient
                    .Builder()
                    .build()
            )
        )
    }
    single {
        UpdateManager(
            updateChecker = get(),
            updateApplier = get(),
            appVersionTracker = get(),
        )
    }
}
val startUpModule = module {
    single {
        Startup.getStartUpManager(get(), StartOnBootBroadcastReceiver::class.java)
    }.apply {
        bind<AbstractStartupManager>()
    }
}

fun getAppModule(context: ABDMApp) = module {
    includes(downloaderModule)
    includes(downloadSystemModule)
    includes(coroutineModule)
    includes(jsonModule)
    includes(updaterModule)
    includes(startUpModule)
//    single {
//        NetworkChecker(get())
//    }
    single {
        AppInfo.definedPaths
    }.apply {
        bind<DefinedPaths>()
        bind<AndroidDefinedPaths>()
    }
    single {
        AppRepository(
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
            get(),
        )
    }.apply {
        bind<BaseAppRepository>()
        bind<SizeAndSpeedUnitProvider>()
    }
    single {
        ThemeManager(get(), get(), get())
    }
//    single {
//        FontManager(get())
//    }
    single {
        LanguageManager(
            get(),
            LanguageSourceProvider(
                ABDMLanguageResources.defaultLanguageResource,
                ABDMLanguageResources.languages,
            )
        )
    }
    single {
        MyIcons
    }.apply {
        bind<IMyIcons>()
        bind<IIconResolver>()
    }
    single {
        val definedPaths = get<DefinedPaths>()
        ProxyDatastoreStorage(
            kotlinxSerializationDataStore(
                definedPaths.proxySettingsFile.toFile(),
                get(),
                ProxyData::default,
            )
        )
    }.bind<IProxyStorage>()
    single {
        val definedPaths = get<DefinedPaths>()
        AppSettingsStorage(
            createMapConfigDatastore(
                definedPaths.appSettingsFile.toFile(),
                get(),
            )
        )
    }.apply {
        bind<BaseAppSettingsStorage>()
        bind<LanguageStorage>()
        bind<ThemeSettingsStorage>()
    }
    single {
        RemovedDownloadsFromDiskTracker(
            get(), get(), get(),
        )
    }
    single {
        val definedPaths = get<DefinedPaths>()
        PreviousVersion(
            systemPath = definedPaths.systemDir.toFile(),
            currentVersion = AppVersion.get(),
        )
    }
    single {
        AppVersionTracker(
            previousVersion = {
                // it MUST be booted first
                get<PreviousVersion>().get()
            },
            currentVersion = AppVersion.get(),
        )
    }

    single {
        val appSettingsStorage: BaseAppSettingsStorage = get()
        AppSSLFactoryProvider(
            ignoreSSLCertificates = appSettingsStorage.ignoreSSLCertificates
        )
    }
    single {
        val appSettingsStorage: BaseAppSettingsStorage = get()
        AppHostNameVerifier(
            delegateHostnameVerifier = OkHostnameVerifier,
            ignoreHostNameVerification = appSettingsStorage.ignoreSSLCertificates
        )
    }
    single<OkHttpClient> {
        val appSSLFactoryProvider: AppSSLFactoryProvider = get()
        val appHostNameVerifier: AppHostNameVerifier = get()
        OkHttpClient
            .Builder()
            .protocols(listOf(Protocol.HTTP_1_1))
            .dispatcher(Dispatcher().apply {
                //bypass limit on concurrent connections!
                maxRequests = Int.MAX_VALUE
                maxRequestsPerHost = Int.MAX_VALUE
            })
            .sslSocketFactory(
                appSSLFactoryProvider.createSSLSocketFactory(),
                appSSLFactoryProvider.trustManager,
            )
            .hostnameVerifier(appHostNameVerifier)
            .build()
    }
    single<ILastSavedLocationsStorage> {
        val definedPaths = get<AndroidDefinedPaths>()
        LastSavedLocationStorage(
            kotlinxSerializationDataStore<List<String>>(
                definedPaths.lastSavedLocationFile.toFile(),
                get(),
                ::emptyList,
            )
        )
    }
    single<IPerHostSettingsStorage> {
        val definedPaths = get<DefinedPaths>()
        PerHostSettingsDatastoreStorage(
            kotlinxSerializationDataStore<List<PerHostSettingsItem>>(
                definedPaths.perHostSettingsFile.toFile(),
                get(),
                ::emptyList,
            )
        )
    }
    single {
        PerHostSettingsManager(get())
    }
    single { context }.apply {
        bind<ABDMApp>()
        bind<Application>()
        bind<Context>()
    }
    single {
        ABDMAppManager(get(), get(), get(), get(), get(), get(), get())
    }
    single {
        ABDMServiceNotificationManager(get(), get(), get(), get(), get())
    }
    single {
        AndroidDownloadItemOpener(get())
    }.apply {
        bind<DownloadItemOpener>()
    }
    single { NotificationManager() }
    single {
        val paths = get<AndroidDefinedPaths>()
        AndroidOnBoardingStorage(
            kotlinxSerializationDataStore(
                paths.onboardingFile.toFile(),
                get(),
                ::OnBoardingData,
            )
        )
    }
    single {
        val paths = get<AndroidDefinedPaths>()
        HomePageStorage(
            kotlinxSerializationDataStore(
                paths.homePageFile.toFile(),
                get(),
                ::HomePageStateToPersist,
            )
        )
    }
    single {
        val paths = get<AndroidDefinedPaths>()
        BrowserBookmarksStorage(
            kotlinxSerializationDataStore(
                paths.browserBookmarksFile.toFile(),
                get(),
                ::emptyList,
            )
        )
    }
}


object Di : KoinComponent {
    fun boot(applicationContext: ABDMApp) {
        startKoin {
            modules(getAppModule(applicationContext))
        }
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/about/AboutPage.kt
================================================
package com.abdownloadmanager.android.pages.about

import androidx.compose.runtime.Composable


import androidx.compose.foundation.*
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.ui.theme.myTextSizes
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.util.ui.WithContentAlpha
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.*
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.android.ui.page.PageFooter
import com.abdownloadmanager.android.ui.page.PageHeader
import com.abdownloadmanager.android.ui.page.PageTitle
import com.abdownloadmanager.android.ui.page.PageUi
import com.abdownloadmanager.android.ui.page.createAlphaForHeader
import com.abdownloadmanager.android.ui.page.rememberHeaderAlpha
import com.abdownloadmanager.android.util.compose.useBack
import com.abdownloadmanager.shared.util.SharedConstants
import com.abdownloadmanager.shared.util.ui.widget.MyIcon
import com.abdownloadmanager.shared.ui.widget.IconActionButton
import com.abdownloadmanager.shared.ui.widget.Tooltip
import com.abdownloadmanager.shared.util.div
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.ui.widget.ActionButton
import com.abdownloadmanager.shared.ui.widget.TransparentIconActionButton
import com.abdownloadmanager.shared.util.AppVersion
import com.abdownloadmanager.shared.util.ui.theme.myShapes
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import ir.amirab.util.URLOpener
import ir.amirab.util.HttpUrlUtils
import ir.amirab.util.compose.IconSource
import ir.amirab.util.compose.StringSource
import ir.amirab.util.compose.asStringSource
import ir.amirab.util.compose.dpToPx
import ir.amirab.util.compose.resources.myStringResource

@Composable
fun AboutPage(
    onRequestShowOpenSourceLibraries: () -> Unit,
    onRequestShowTranslators: () -> Unit,
) {
    val state = rememberScrollState()
    var paddings by remember { mutableStateOf(PaddingValues.Zero) }
    val headerAlpha =
        createAlphaForHeader(state.value.toFloat(), paddings.calculateTopPadding().dpToPx(LocalDensity.current))
    val shape = myShapes.defaultRounded
    PageUi(
        header = {
            val onBack = useBack()
            PageHeader(
                leadingIcon = {
                    TransparentIconActionButton(
                        icon = MyIcons.back,
                        contentDescription = Res.string.back.asStringSource()
                    ) {
                        onBack?.onBackPressed()
                    }
                },
                headerTitle = {
                    PageTitle(myStringResource(Res.string.about))
                },
                modifier = Modifier
                    .background(
                        myColors.background.copy(
                            alpha = headerAlpha * 0.75f
                        )
                    )
                    .statusBarsPadding(),

            )
        },
        footer = {
            PageFooter {
                Column(
                    Modifier
                        .fillMaxWidth()
                        .navigationBarsPadding()
                        .padding(horizontal = mySpacings.largeSpace)
                        .padding(bottom = mySpacings.largeSpace)
                        .border(1.dp, myColors.onBackground / 0.15f, shape)
                        .clip(shape)
                        .background(myColors.surface)
                ) {
                    Spacer(Modifier.height(mySpacings.largeSpace))
                    DevelopedWithLove(
                        Modifier
                            .fillMaxWidth()
                            .wrapContentWidth()
                    )
                    Spacer(Modifier.height(mySpacings.mediumSpace))
                    SocialAndLinks(
                        Modifier
                            .fillMaxWidth()
                            .wrapContentWidth(),
                        horizontalPadding = 8.dp,
                    )
                    Spacer(Modifier.height(mySpacings.mediumSpace))
                    Spacer(
                        Modifier
                            .fillMaxWidth()
                            .background(myColors.onBackground / 0.05f)
                            .height(1.dp)
                    )
                    MainWebsite(Modifier)
                }
            }
        }
    ) {
        paddings = it.paddingValues
        Column(
            Modifier
                .fillMaxSize()
                .verticalScroll(state)
                .padding(it.paddingValues),
            verticalArrangement = Arrangement.SpaceBetween,
        ) {
            Column(
                Modifier
                    .fillMaxWidth()
                    .padding(horizontal = mySpacings.largeSpace),
            ) {
                AppIconAndVersion(
                    Modifier
                        .fillMaxWidth()
                        .padding(vertical = 32.dp)
                )
            }
            CreditsSection(
                modifier = Modifier
                    .fillMaxWidth(),
                onRequestShowOpenSourceLibraries = onRequestShowOpenSourceLibraries,
                onRequestShowTranslators = onRequestShowTranslators,
            )
        }
    }
}

@Composable
private fun AppIconAndVersion(
    modifier: Modifier,
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = modifier.padding(
            horizontal = 24.dp,
            vertical = 8.dp,
        )
    ) {
        val shape = RoundedCornerShape(16.dp)
        Image(
            MyIcons.appIcon.rememberPainter(),
            null,
            Modifier
                .shadow(12.dp, shape, spotColor = myColors.primary)
                .clip(shape)
                .border(
                    1.dp,
                    Brush.linearGradient(
                        listOf(myColors.primary, myColors.secondary)
                    ),
                    shape
                )
                .background(myColors.surface)
                .padding(16.dp)
                .size(52.dp)
        )
        Spacer(Modifier.size(16.dp))
        Column(
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                SharedConstants.appDisplayName,
                fontSize = myTextSizes.lg,
                fontWeight = FontWeight.Bold,
            )
            Spacer(Modifier.height(2.dp))
            WithContentAlpha(0.75f) {
                Text(
                    myStringResource(
                        Res.string.version_n,
                        Res.string.version_n_createArgs(
                            value = AppVersion.get().toString(),
                        )
                    ),
                    fontSize = myTextSizes.base,
                )
            }
        }
    }
}


@Composable
fun MainWebsite(
    modifier: Modifier
) {
    val uriHandler = LocalUriHandler.current
    val websiteUrl = SharedConstants.projectWebsite
    val websiteDisplayName = remember(websiteUrl) {
        HttpUrlUtils.getHost(websiteUrl) ?: websiteUrl
    }
    Column(
        modifier
            .fillMaxWidth()
            .clickable {
                uriHandler.openUri(websiteUrl)
            }
            .padding(
                mySpacings.largeSpace
            ),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            text = websiteDisplayName,
            color = myColors.info,
        )
    }
}

@Composable
fun DevelopedWithLove(modifier: Modifier) {
    Column(
        modifier,
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Text(
            myStringResource(Res.string.developed_with_love_for_you),
            Modifier
                .fillMaxWidth()
                .wrapContentWidth()
        )
        Spacer(Modifier.height(mySpacings.largeSpace))
        DonateButton(Modifier)
    }
}

@Composable
private fun SocialAndLinks(
    modifier: Modifier = Modifier,
    horizontalPadding: Dp,
) {
    Row(
        horizontalArrangement = Arrangement.spacedBy(8.dp),
        modifier = modifier
            .padding(
                horizontal = horizontalPadding,
            )
    ) {
        SocialSmallButton(
            MyIcons.earth,
            Res.string.visit_the_project_website.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.projectWebsite)
            }
        )
        SocialSmallButton(
            MyIcons.openSource,
            Res.string.view_the_source_code.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.projectSourceCode)
            }
        )
        SocialSmallButton(
            MyIcons.speaker,
            Res.string.channel.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.telegramChannelUrl)
            }
        )
        SocialSmallButton(
            MyIcons.group,
            Res.string.group.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.telegramGroupUrl)
            }
        )
        SocialSmallButton(
            MyIcons.language,
            Res.string.translators_contribute_title.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.projectTranslations)
            }
        )
    }
}

@Composable
private fun CreditsSection(
    modifier: Modifier = Modifier,
    onRequestShowOpenSourceLibraries: () -> Unit,
    onRequestShowTranslators: () -> Unit,
) {
    Column(
        modifier
            .padding(horizontal = 16.dp)
            .padding(vertical = 8.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        val itemModifier = Modifier.fillMaxWidth()
        AboutPageListItemButton(
            itemModifier,
            icon = MyIcons.hearth,
            title = Res.string.this_is_a_free_and_open_source_software.asStringSource(),
            description = Res.string.view_the_source_code.asStringSource(),
            onClick = {
                URLOpener.openUrl(SharedConstants.projectSourceCode)
            }
        )
        AboutPageListItemButton(
            itemModifier,
            icon = MyIcons.openSource,
            title = Res.string.powered_by_open_source_software.asStringSource(),
            description = Res.string.view_the_open_source_licenses.asStringSource(),
            onClick = {
                onRequestShowOpenSourceLibraries()
            }
        )
        AboutPageListItemButton(
            itemModifier,
            icon = MyIcons.language,
            title = Res.string.localized_by_translators.asStringSource(),
            description = Res.string.meet_the_translators.asStringSource(),
            onClick = {
                onRequestShowTranslators()
            }
        )
    }
}

@Composable
private fun SocialSmallButton(
    icon: IconSource,
    title: StringSource,
    onClick: () -> Unit,
) {
    Tooltip(title) {
        IconActionButton(
            icon,
            contentDescription = title,
            onClick = onClick,
        )
    }
}

@Composable
private fun AboutPageListItemButton(
    modifier: Modifier,
    icon: IconSource,
    title: StringSource,
    description: StringSource,
    onClick: () -> Unit,
) {
    val shape = myShapes.defaultRounded
    Row(
        modifier
            .border(1.dp, myColors.onBackground / 0.15f, shape)
            .clip(shape)
            .clickable(onClick = onClick)
            .background(myColors.surface)
            .padding(
                horizontal = 8.dp,
                vertical = 8.dp,
            ),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        MyIcon(
            icon = icon,
            contentDescription = null,
            modifier = Modifier.size(24.dp)
        )
        Spacer(Modifier.width(8.dp))
        Column {
            Text(
                title.rememberString(),
                fontSize = myTextSizes.base,
                fontWeight = FontWeight.Bold,
            )
            Spacer(Modifier.height(4.dp))
            WithContentAlpha(0.75f) {
                Text(description.rememberString())
            }
        }
    }
}


@Composable
private fun DonateButton(
    modifier: Modifier,
) {
    ActionButton(
        modifier = modifier,
        start = {
            MyIcon(
                MyIcons.hearth,
                null,
                modifier = Modifier.size(24.dp),
                tint = myColors.error,
            )
            Spacer(Modifier.width(8.dp))
        },
        text = myStringResource(Res.string.donate),
        onClick = {
            URLOpener.openUrl(SharedConstants.donateLink)
        }
    )
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/AddDownloadActivity.kt
================================================
package com.abdownloadmanager.android.pages.add

import android.content.Intent
import android.os.Bundle
import arrow.core.firstOrNone
import arrow.core.getOrElse
import com.abdownloadmanager.android.pages.add.multiple.AddMultiDownloadActivity
import com.abdownloadmanager.android.pages.add.single.AddSingleDownloadActivity
import com.abdownloadmanager.android.pages.onboarding.permissions.PermissionManager
import com.abdownloadmanager.android.ui.MainActivity
import com.abdownloadmanager.android.util.activity.ABDMActivity
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadConfig
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadCredentialsInUiProps
import com.abdownloadmanager.shared.pages.adddownload.ImportOptions
import com.abdownloadmanager.shared.util.extractors.linkextractor.DownloadCredentialFromStringExtractor
import ir.amirab.downloader.downloaditem.IDownloadCredentials
import ir.amirab.downloader.downloaditem.http.HttpDownloadCredentials
import kotlinx.serialization.json.Json
import org.koin.core.component.inject

class AddDownloadActivity : ABDMActivity() {
    val json: Json by inject()
    val permissionManager: PermissionManager by inject()
    private fun createDownloaderInUiProps(
        credentials: IDownloadCredentials
    ): AddDownloadCredentialsInUiProps {
        return AddDownloadCredentialsInUiProps(
            credentials,
            AddDownloadCredentialsInUiProps.Configs(),
        )
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (!permissionManager.isReady()) {
            // user not opened the app at least once. we must redirect it to the permission page first
            val intent = Intent(this, MainActivity::class.java)
            startActivity(intent)
            finish()
            return
        }
        val credentials = getDownloadCredentialsFromIntent(intent)
        val intent = if (credentials.size > 1) {
            AddMultiDownloadActivity.createIntent(
                this,
                AddDownloadConfig.MultipleAddConfig(
                    newDownloads = credentials.map(::createDownloaderInUiProps),
                    importOptions = ImportOptions(),
                ),
                json = json,
            )
        } else {
            AddSingleDownloadActivity.createIntent(
                this,
                AddDownloadConfig.SingleAddConfig(
                    newDownload = credentials
                        .firstOrNone()
                        .getOrElse { HttpDownloadCredentials("") }
                        .let(::createDownloaderInUiProps),
                    importOptions = ImportOptions(),
                ),
                json = json,
            )
        }
        startActivity(intent)
        finish()
    }

    private fun getDownloadCredentialsFromIntent(intent: Intent): List<IDownloadCredentials> {
        val links = when (intent.action) {
            Intent.ACTION_SEND -> {
                intent.getStringExtra(Intent.EXTRA_TEXT).orEmpty()
            }

            else -> {
                // action view etc...
                intent.data?.toString().orEmpty()
            }
        }
        return DownloadCredentialFromStringExtractor
            .extract(links)
            .distinctBy { it.link }
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiDownloadActivity.kt
================================================
package com.abdownloadmanager.android.pages.add.multiple

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import com.abdownloadmanager.android.pages.category.CategorySheet
import com.abdownloadmanager.android.pages.newqueue.NewQueueSheet
import com.abdownloadmanager.android.util.ABDMAppManager
import com.abdownloadmanager.android.util.activity.ABDMActivity
import com.abdownloadmanager.android.util.activity.HandleActivityEffects
import com.abdownloadmanager.android.util.activity.getSerializedExtra
import com.abdownloadmanager.android.util.activity.putSerializedExtra
import com.abdownloadmanager.shared.downloaderinui.DownloaderInUiRegistry
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadConfig
import com.abdownloadmanager.shared.storage.ILastSavedLocationsStorage
import com.abdownloadmanager.shared.util.DownloadSystem
import com.abdownloadmanager.shared.util.FileIconProvider
import com.abdownloadmanager.shared.util.OnFullyDismissed
import com.abdownloadmanager.shared.util.ResponsiveDialog
import com.abdownloadmanager.shared.util.category.CategoryManager
import com.abdownloadmanager.shared.util.rememberChild
import com.abdownloadmanager.shared.util.rememberResponsiveDialogState
import ir.amirab.downloader.queue.QueueManager
import kotlinx.coroutines.delay
import kotlinx.serialization.json.Json
import org.koin.core.component.inject

class AddMultiDownloadActivity : ABDMActivity() {
    private val json: Json by inject()
    private val downloadSystem: DownloadSystem by inject()
    private val appManager: ABDMAppManager by inject()
    private val downloaderInUiRegistry: DownloaderInUiRegistry by inject()
    private val lastSavedLocationsStorage: ILastSavedLocationsStorage by inject()
    private val queueManager: QueueManager by inject()
    private val categoryManager: CategoryManager by inject()
    private val iconProvider: FileIconProvider by inject()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val myRetainedComponent = myRetainedComponent {
            val config = getComponentConfig(intent)
            val appManager = appManager
            val closeAddDownloadDialog = {
                this@myRetainedComponent.finishActivityAction()
            }
            AndroidAddMultiDownloadComponent(
                ctx = it,
                onRequestClose = closeAddDownloadDialog,
                lastSavedLocationsStorage = lastSavedLocationsStorage,
                id = config.id,
                queueManager = queueManager,
                categoryManager = categoryManager,
                downloadSystem = downloadSystem,
                onRequestAdd = { items, queueId, categorySelectionMode ->
                    appManager.addDownloads(
                        items = items,
                        categorySelectionMode = categorySelectionMode,
                        queueId = queueId,
                    )
                },
                perHostSettingsManager = perHostSettingsManager,
                fileIconProvider = iconProvider,
                appRepository = appRepository,
                downloaderInUiRegistry = downloaderInUiRegistry,
            ).apply { addItems(config.newDownloads) }
        }
        val addDownloadComponent = myRetainedComponent.component
        setABDMContent {
            myRetainedComponent.HandleActivityEffects()
            AddMultiItemPage(addDownloadComponent)
            CategorySheet(
                categoryComponent = addDownloadComponent.categorySlot.rememberChild(),
                onDismiss = addDownloadComponent::closeCategoryDialog
            )
            NewQueueSheet(
                onQueueCreate = addDownloadComponent::createQueueWithName,
                isOpened = addDownloadComponent.showAddQueue.collectAsState().value,
                onCloseRequest = { addDownloadComponent.setShowAddQueue(false) },
            )
        }
    }

    private fun getComponentConfig(intent: Intent): AddDownloadConfig.MultipleAddConfig {
        runCatching {
            with(json) {
                intent.getSerializedExtra<AddDownloadConfig.MultipleAddConfig>(COMPONENT_CONFIG_KEY)
            }
        }.onFailure {
            it.printStackTrace()
        }.getOrNull()?.let {
            return it
        }
        return AddDownloadConfig.MultipleAddConfig()
    }

    companion object {
        const val COMPONENT_CONFIG_KEY = "ComponentConfig"
        fun createIntent(
            context: Context,
            multipleAddConfig: AddDownloadConfig.MultipleAddConfig,
            json: Json,
        ): Intent {
            val intent = Intent(
                context,
                AddMultiDownloadActivity::class.java,
            )
            with(json) {
                intent.putSerializedExtra(COMPONENT_CONFIG_KEY, multipleAddConfig)
            }
            return intent
        }
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiDownloadList.kt
================================================
package com.abdownloadmanager.android.pages.add.multiple

import androidx.compose.foundation.background
import androidx.compose.foundation.basicMarquee
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.pages.adddownload.multiple.NewMultiDownloadState
import com.abdownloadmanager.shared.ui.widget.CheckBox
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.util.FileIconProvider
import com.abdownloadmanager.shared.util.div
import com.abdownloadmanager.shared.util.ui.LocalContentColor
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import com.abdownloadmanager.shared.util.ui.widget.MyIcon
import ir.amirab.util.compose.resources.myStringResource
import ir.amirab.util.ifThen

@Composable
fun AddMultiDownloadList(
    modifier: Modifier,
    component: AndroidAddMultiDownloadComponent,
    itePaddingValues: PaddingValues,
) {
    val dividerColor = myColors.onBackground / 0.5f
    val listState by component.filteredList.collectAsState()
    LazyColumn(modifier) {
        itemsIndexed(
            items = listState,
        ) { index, item ->
            val isSelected = remember(item, component.selectionList) {
                component.isSelected(item.id)
            }
            val isFirstItem = index == 0
            RenderAddDownloadItem(
                state = item,
                iconProvider = component.fileIconProvider,
                onSelectionChange = { selected ->
                    component.setSelect(item.id, selected)
                },
                onLongPress = {
                    component.openConfigurableList(
                        item.id
                    )
                },
                isSelected = isSelected,
                itemPadding = itePaddingValues,
                modifier = Modifier.ifThen(!isFirstItem) {
                    drawBehind {
                        drawLine(
                            brush = Brush.horizontalGradient(
                                listOf(
                                    Color.Transparent,
                                    dividerColor,
                                    Color.Transparent,
                                )
                            ),
                            start = Offset.Zero,
                            end = Offset(size.width, 0f)
                        )
                    }
                }
            )
        }
    }
}

@Composable
private fun RenderAddDownloadItem(
    state: NewMultiDownloadState,
    iconProvider: FileIconProvider,
    isSelected: Boolean,
    onLongPress: () -> Unit,
    onSelectionChange: (Boolean) -> Unit,
    itemPadding: PaddingValues,
    modifier: Modifier,
) {
    val name = state.name
    val icon = iconProvider.rememberIcon(name)
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = modifier
            .fillMaxWidth()
            .heightIn(mySpacings.thumbSize)
            .ifThen(isSelected) {
                background(
                    myColors.selectionGradient(1f, 0.5f)
                )
            }
            .combinedClickable(
                onClick = {
                    onSelectionChange(!isSelected)
                },
                onLongClick = {
                    onLongPress()
                }
            )
            .padding(itemPadding)

    ) {
        Column {
            Text(
                text = state.link,
                color = LocalContentColor.current / 0.75f,
                maxLines = 1,
                overflow = TextOverflow.MiddleEllipsis,
            )
            Spacer(Modifier.height(mySpacings.mediumSpace))
            Text(
                text = name.takeIf { it.isNotEmpty() } ?: "...",
                maxLines = 1,
                modifier = Modifier.basicMarquee(),
            )
            Spacer(Modifier.height(mySpacings.mediumSpace))
            val sizeTitle = myStringResource(Res.string.size)
            val sizeValue = state.sizeString.rememberString()
            Row(
                verticalAlignment = Alignment.CenterVertically,
            ) {
                CheckBox(
                    value = isSelected,
                    onValueChange = {
                        onSelectionChange(it)
                    },
                    size = 24.dp,
                )
                Spacer(Modifier.width(mySpacings.largeSpace))
                MyIcon(
                    icon = icon,
                    contentDescription = null,
                    modifier = Modifier
                        .size(24.dp)
                        .alpha(0.75f)
                )
                Spacer(Modifier.width(mySpacings.largeSpace))
                Text(
                    text = "$sizeTitle: $sizeValue",
                    maxLines = 1,
                )
            }
        }

    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiItemPage.kt
================================================
package com.abdownloadmanager.android.pages.add.multiple

import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.android.pages.add.shared.CategoryAddButton
import com.abdownloadmanager.android.pages.add.shared.CategorySelect
import com.abdownloadmanager.android.pages.add.shared.ExtraConfig
import com.abdownloadmanager.android.pages.add.shared.LocationTextField
import com.abdownloadmanager.android.pages.add.shared.ShowAddToQueueDialog
import com.abdownloadmanager.android.ui.RenderControlSelections
import com.abdownloadmanager.android.ui.SelectionControlButton
import com.abdownloadmanager.android.ui.page.PageHeader
import com.abdownloadmanager.android.ui.page.PageTitleWithDescription
import com.abdownloadmanager.android.ui.page.PageUi
import com.abdownloadmanager.shared.ui.widget.*
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.div
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.util.category.Category
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import ir.amirab.util.compose.asStringSource
import ir.amirab.util.compose.resources.myStringResource

@Composable
fun AddMultiItemPage(
    addMultiDownloadComponent: AndroidAddMultiDownloadComponent,
) {
    val hasSelection = addMultiDownloadComponent.selectionList.isNotEmpty()
    BackHandler(hasSelection) {
        addMultiDownloadComponent.selectAll(false)
    }
    val pageHorizontalPadding = 16.dp
    PageUi(
        modifier = Modifier
            .background(myColors.background)
            .statusBarsPadding(),
        header = {
            val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher
            PageHeader(
                leadingIcon = {
                    TransparentIconActionButton(
                        MyIcons.back,
                        contentDescription = Res.string.back.asStringSource()
                    ) {
                        backDispatcher?.onBackPressed()
                    }
                },
                headerTitle = {
                    PageTitleWithDescription(
                        title = myStringResource(
                            Res.string.add_download
                        ),
                        description = myStringResource(
                            Res.string.add_multi_download_page_header
                        )
                    )
                }
            )
        },
        footer = {
            Footer(
                Modifier,
                addMultiDownloadComponent,
            )
        },
    ) {
        Column(
            Modifier
                .fillMaxWidth()
                .background(myColors.background)
                .padding(it.paddingValues)
        ) {
            AddMultiDownloadList(
                Modifier.weight(1f),
                addMultiDownloadComponent,
                itePaddingValues = PaddingValues(
                    horizontal = pageHorizontalPadding,
                    vertical = 16.dp,
                )
            )
        }
    }
    val currentDownloadConfigurableList by addMultiDownloadComponent.currentDownloadConfigurableList.collectAsState()
    currentDownloadConfigurableList?.let {
        ExtraConfig(
            onDismiss = {
                addMultiDownloadComponent.openConfigurableList(null)
            },
            configurables = it,
            isOpened = true,
        )
    }
    ShowAddToQueueDialog(
        queueList = addMultiDownloadComponent.queueList.collectAsState().value,
        onQueueSelected = { queue, startQueue ->
            addMultiDownloadComponent.requestAddDownloads(
                queue, startQueue
            )
        },
        onClose = {
            addMultiDownloadComponent.closeAddToQueue()
        },
        isOpened = addMultiDownloadComponent.showAddToQueue,
        newQueueAction = addMultiDownloadComponent.newQueueAction,
    )
}


@Composable
fun Footer(
    modifier: Modifier = Modifier,
    component: AndroidAddMultiDownloadComponent,
) {
    Column(
        modifier
            .fillMaxWidth()
            .background(myColors.surface)
            .navigationBarsPadding()
            .imePadding()
    ) {
        Spacer(
            Modifier
                .fillMaxWidth()
                .height(1.dp)
                .background(myColors.onSurface / 0.15f)
        )
        Column(
            Modifier
                .padding(horizontal = 16.dp)
                .padding(vertical = 16.dp),
        ) {
            val total = component.totalList.size
            val showMoreOptions by component.showMoreOptions.collectAsState()
            RenderControlSelections(
                onRequestSelectAll = { component.selectAll(true) },
                onRequestSelectInside = { component.toggleSelectInside() },
                onRequestInvertSelection = { component.inverseSelection() },
                total = total,
                selectionCount = component.selectionList.size,
            ) {
                SelectionControlButton(
                    icon = if (showMoreOptions) {
                        MyIcons.down
                    } else {
                        MyIcons.up
                    },
                    contentDescription = Res.string.more_options.asStringSource(),
                    onClick = {
                        component.setShowMoreOptions(!showMoreOptions)
                    }
                )
            }
            AnimatedVisibility(
                showMoreOptions
            ) {
                Column {
                    Spacer(Modifier.height(8.dp))
                    SaveSettings(
                        modifier = Modifier
                            .fillMaxWidth(),
                        component = component,
                    )
                    val text = component.filterText.collectAsState().value
                    Spacer(Modifier.height(8.dp))
                    MyTextFieldWithIcons(
                        modifier = Modifier
                            .fillMaxWidth(),
                        text = text,
                        onTextChange = component::setFilterText,
                        placeholder = myStringResource(Res.string.search),
                        end = {
                            MyTextFieldIcon(
                                MyIcons.clear,
                                enabled = text.isNotEmpty(),
                            ) {
                                component.setFilterText("")
                            }
                        }
                    )
                    Spacer(Modifier.height(8.dp))
                }
            }
            Spacer(Modifier.height(8.dp))
            Row(
                Modifier
            ) {
                val buttonModifier = Modifier.weight(1f)
                PrimaryMainActionButton(
                    text = myStringResource(Res.string.add),
                    onClick = {
                        component.openAddToQueueDialog()
                    },
                    enabled = component.canClickAdd,
                    modifier = buttonModifier,
                )
//                ActionButton(
//                    text = myStringResource(Res.string.cancel),
//                    onClick = {
//                        component.requestClose()
//                    },
//                    modifier = buttonModifier,
//                )
            }
        }
    }
}

@Composable
private fun SaveSettings(
    modifier: Modifier,
    component: AndroidAddMultiDownloadComponent,
) {
    val selectedCategory by component.selectedCategory.collectAsState()

    val folder by component.folder.collectAsState()

    Column(modifier) {
        Text("${myStringResource(Res.string.save_to)}:")
        Spacer(Modifier.height(8.dp))
        Column(Modifier.fillMaxWidth()) {
            CategorySaveOption(selectedCategory, component)
            Spacer(Modifier.height(8.dp))
            LocationSaveOption(component, folder)
            Spacer(Modifier)
        }
    }
}

@Composable
private fun LocationSaveOption(
    component: AndroidAddMultiDownloadComponent,
    folder: String
) {
    val allItemsInSameLocation by component.allInSameLocation.collectAsState()
    SaveOption(
        title = myStringResource(Res.string.all_items_in_one_Location),
        selectedHelp = myStringResource(Res.string.all_items_in_one_Location_description),
        unselectedHelp = myStringResource(Res.string.unselected_all_items_in_specific_location_description),
        selected = allItemsInSameLocation,
        onSelectedChange = {
            component.setAllItemsInSameLocation(it)
        },
        selectedContent = {
            LocationTextField(
                text = folder,
                setText = {
                    component.setFolder(it)
                },
                modifier = Modifier.fillMaxWidth(),
                lastUsedLocations = component.lastUsedLocations.collectAsState().value,
                onRequestRemoveSaveLocation = component::removeFromLastDownloadLocation
            )
        }
    )
}

@Composable
private fun CategorySaveOption(
    selectedCategory: Category?,
    component: AndroidAddMultiDownloadComponent
) {

    SaveOption(
        title = myStringResource(Res.string.all_items_in_one_category),
        selectedHelp = myStringResource(Res.string.all_items_in_one_category_description),
        unselectedHelp = myStringResource(Res.string.each_item_on_its_own_category_description),
        selected = selectedCategory != null,
        onSelectedChange = {
            if (it) {
                component.setSelectedCategory(component.categories.value.firstOrNull())
            } else {
                component.setSelectedCategory(null)
            }
            component.setAlsoAutoCategorize(!it)
        },
        selectedContent = {
            Row(
                Modifier
                    .height(IntrinsicSize.Max)
                    .fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
            ) {
                CategorySelect(
                    categories = component.categories.collectAsState().value,
                    modifier = Modifier.weight(1f),
                    selectedCategory = component.selectedCategory.collectAsState().value,
                    onCategorySelected = {
                        component.setSelectedCategory(it)
                    }
                )
                Spacer(Modifier.width(8.dp))
                CategoryAddButton(
                    Modifier.fillMaxHeight(),
                    enabled = true,
                    onClick = {
                        component.onRequestAddCategory()
                    },
                )
            }
        }
    )
}

@Composable
private fun SaveOption(
    title: String,
    selectedHelp: String,
    unselectedHelp: String,
    selected: Boolean,
    onSelectedChange: (Boolean) -> Unit,
    selectedContent: @Composable () -> Unit
) {
    ExpandableItem(
        modifier = Modifier
            .fillMaxWidth(),
        isExpanded = selected,
        header = {
            Row(
                modifier = Modifier
                    .heightIn(mySpacings.thumbSize)
                    .clickable { onSelectedChange(!selected) },
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                CheckBox(
                    value = selected,
                    onValueChange = onSelectedChange,
                    size = 24.dp
                )
                Text(title)
                Help(if (selected) selectedHelp else unselectedHelp)
            }
        },
        body = {
            Column {
                Spacer(Modifier.height(8.dp))
                selectedContent()
            }
        }
    )
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AndroidAddMultiDownloadComponent.kt
================================================
package com.abdownloadmanager.android.pages.add.multiple

import com.abdownloadmanager.shared.action.createNewQueueAction
import com.abdownloadmanager.shared.util.DownloadSystem
import com.abdownloadmanager.shared.downloaderinui.DownloaderInUiRegistry
import com.abdownloadmanager.shared.pagemanager.CategoryDialogManager
import com.abdownloadmanager.shared.pagemanager.NewQueuePageManager
import com.abdownloadmanager.shared.pages.adddownload.multiple.BaseAddMultiDownloadComponent
import com.abdownloadmanager.shared.pages.adddownload.multiple.OnRequestAdd
import com.abdownloadmanager.shared.pages.category.CategoryComponent
import com.abdownloadmanager.shared.repository.BaseAppRepository
import com.abdownloadmanager.shared.storage.ILastSavedLocationsStorage
import com.abdownloadmanager.shared.util.FileIconProvider
import com.abdownloadmanager.shared.util.category.CategoryManager
import com.abdownloadmanager.shared.util.perhostsettings.PerHostSettingsManager
import com.abdownloadmanager.shared.util.subscribeAsStateFlow
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import ir.amirab.downloader.queue.QueueManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.builtins.serializer

class AndroidAddMultiDownloadComponent(
    ctx: ComponentContext,
    id: String,
    onRequestClose: () -> Unit,
    onRequestAdd: OnRequestAdd,
    lastSavedLocationsStorage: ILastSavedLocationsStorage,
    perHostSettingsManager: PerHostSettingsManager, downloadSystem: DownloadSystem,
    fileIconProvider: FileIconProvider,
    appRepository: BaseAppRepository,
    downloaderInUiRegistry: DownloaderInUiRegistry,
    queueManager: QueueManager,
    categoryManager: CategoryManager,
) : BaseAddMultiDownloadComponent(
    ctx = ctx,
    id = id,
    lastSavedLocationsStorage = lastSavedLocationsStorage,
    onRequestAdd = onRequestAdd,
    onRequestClose = onRequestClose,
    perHostSettingsManager = perHostSettingsManager,
    downloadSystem = downloadSystem,
    appRepository = appRepository,
    fileIconProvider = fileIconProvider,
    downloaderInUiRegistry = downloaderInUiRegistry,
    queueManager = queueManager,
    categoryManager = categoryManager,
), NewQueuePageManager, CategoryDialogManager {
    val categoryComponentNavigation = SlotNavigation<Long>()
    val categorySlot = childSlot(
        source = categoryComponentNavigation,
        childFactory = { config, ctx ->
            CategoryComponent(
                ctx = ctx,
                id = config,
                close = ::closeCategoryDialog,
                submit = { submittedCategory ->
                    if (submittedCategory.id < 0) {
                        categoryManager.addCustomCategory(submittedCategory)
                    } else {
                        categoryManager.updateCategory(
                            submittedCategory.id
                        ) {
                            submittedCategory.copy(
                                items = it.items
                            )
                        }
                    }
                    closeCategoryDialog()
                },
            )
        },
        serializer = Long.serializer(),
    ).subscribeAsStateFlow()
    val newQueueAction = createNewQueueAction(
        scope,
        this,
    )

    override fun openCategoryDialog(categoryId: Long) {
        scope.launch {
            categoryComponentNavigation.activate(categoryId)
        }
    }

    override fun closeCategoryDialog() {
        scope.launch {
            categoryComponentNavigation.dismiss()
        }
    }

    override fun getCategoryPageManager(): CategoryDialogManager {
        return this
    }

    private val _showMoreInputs = MutableStateFlow(false)
    val showMoreOptions = _showMoreInputs.asStateFlow()
    fun setShowMoreOptions(value: Boolean) {
        _showMoreInputs.value = value
    }

    private val _showAddQueue = MutableStateFlow(false)
    val showAddQueue = _showAddQueue.asStateFlow()
    fun setShowAddQueue(value: Boolean) {
        _showAddQueue.value = value
    }

    fun createQueueWithName(name: String) {
        scope.launch { queueManager.addQueue(name) }
        setShowAddQueue(false)
    }

    override fun closeNewQueueDialog() {
        setShowAddQueue(false)
    }

    override fun openNewQueueDialog() {
        setShowAddQueue(true)
    }
}



================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/CategorySelect.kt
================================================
package com.abdownloadmanager.android.pages.add.shared

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.*
import com.abdownloadmanager.android.ui.configurable.RenderSpinnerInSheet
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.ui.widget.IconActionButton
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.myColors
import ir.amirab.util.ifThen
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.util.div
import com.abdownloadmanager.shared.util.category.Category
import com.abdownloadmanager.shared.util.category.rememberIconPainter
import com.abdownloadmanager.shared.util.ui.theme.myShapes
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import com.abdownloadmanager.shared.util.ui.widget.MyIcon
import ir.amirab.util.compose.asStringSource
import ir.amirab.util.compose.resources.myStringResource

@Composable
fun CategorySelect(
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    categories: List<Category>,
    selectedCategory: Category?,
    onCategorySelected: (Category) -> Unit,
) {
    var isSelectionOpen by remember {
        mutableStateOf(false)
    }
    val closeDialog = {
        isSelectionOpen = false
    }
    RenderSelectedCategory(
        modifier = modifier,
        item = selectedCategory,
        enabled = enabled,
        onClick = {
            isSelectionOpen = true
        },
        renderItem = {
            RenderCategory(
                category = it,
                modifier = Modifier,
            )
        }
    )
    selectedCategory?.let {
        RenderSpinnerInSheet(
            title = Res.string.categories.asStringSource(),
            isOpened = isSelectionOpen,
            onDismiss = closeDialog,
            possibleValues = categories,
            render = {
                RenderCategory(
                    category = it,
                    modifier = Modifier,
                )
            },
            value = selectedCategory,
            onSelect = {
                onCategorySelected(it)
            },
//        renderEmpty = {
//            Column(
//                modifier = Modifier.fillMaxSize().wrapContentSize(),
//                horizontalAlignment = Alignment.CenterHorizontally,
//            ) {
//                MyIcon(MyIcons.info, null, Modifier.size(64.dp))
//                Spacer(Modifier.height(16.dp))
//                Text(
//                    myStringResource(Res.string.no_categories_found),
//                    fontWeight = FontWeight.Bold,
//                    fontSize = myTextSizes.lg,
//                )
//            }
//        }
        )
    }
}

@Composable
private fun RenderCategory(
    modifier: Modifier,
    category: Category,
) {
    Row(
        modifier,
        verticalAlignment = Alignment.CenterVertically,
    ) {
        val icon = category.rememberIconPainter()
        val iconModifier = Modifier.size(16.dp)
        if (icon != null) {
            MyIcon(
                icon,
                null,
                iconModifier,
            )
        } else {
            Spacer(iconModifier)
        }
        Spacer(Modifier.width(8.dp))
        Text(
            category.name,
            softWrap = false,
            maxLines = 1,
            modifier = Modifier.weight(1f)
        )
    }
}

@Composable
fun CategoryAddButton(
    modifier: Modifier,
    enabled: Boolean = true,
    onClick: () -> Unit,
) {
    IconActionButton(
        modifier = modifier,
        icon = MyIcons.add,
        contentDescription = Res.string.add_category.asStringSource(),
        enabled = enabled,
        onClick = onClick,
    )
}

@Composable
private fun <T> RenderSelectedCategory(
    item: T?,
    enabled: Boolean,
    onClick: () -> Unit,
    modifier: Modifier,
    renderItem: @Composable (T) -> Unit,
) {
    val borderColor = myColors.onBackground / 0.1f
//    val background = myColors.surface / 50
    val shape = myShapes.defaultRounded
    Row(
        modifier
            .height(IntrinsicSize.Max)
            .heightIn(mySpacings.thumbSize)
            .clip(shape)
            .ifThen(!enabled) {
                alpha(0.5f)
            }
            .border(1.dp, borderColor, shape)

//            .background(background)
            .clickable(
                enabled = enabled
            ) { onClick() }
            .padding(horizontal = 8.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        val contentModifier = Modifier
            .padding(vertical = 8.dp)
            .weight(1f)
        if (item != null) {
            Box(contentModifier) {
                renderItem(item)
            }
        } else {
            Text(
                myStringResource(Res.string.no_category_selected),
                contentModifier
            )
        }
        Spacer(
            Modifier
                .padding(horizontal = 8.dp)
                .fillMaxHeight()
                .padding(vertical = 1.dp)
                .width(1.dp)
                .background(borderColor)
        )
        MyIcon(
            MyIcons.down,
            null,
            Modifier
                .align(Alignment.CenterVertically)
                .size(16.dp),
        )
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/ExtraConfig.kt
================================================
package com.abdownloadmanager.android.pages.add.shared

import com.abdownloadmanager.shared.ui.configurable.RenderConfigurable
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.div
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.android.ui.SheetHeader
import com.abdownloadmanager.android.ui.SheetTitle
import com.abdownloadmanager.android.ui.SheetUI
import com.abdownloadmanager.shared.ui.configurable.Configurable
import com.abdownloadmanager.shared.ui.configurable.ConfigurableUiProps
import com.abdownloadmanager.shared.util.OnFullyDismissed
import com.abdownloadmanager.shared.util.ResponsiveDialog
import com.abdownloadmanager.shared.util.rememberResponsiveDialogState
import com.abdownloadmanager.shared.util.ui.MultiplatformVerticalScrollbar
import com.abdownloadmanager.shared.util.ui.theme.LocalUiScale
import com.abdownloadmanager.shared.util.ui.theme.myShapes
import io.github.oikvpqya.compose.fastscroller.rememberScrollbarAdapter

@Composable
fun ExtraConfig(
    isOpened: Boolean,
    onDismiss: () -> Unit,
    configurables: List<Configurable<*>>,
) {
    val dialogState = rememberResponsiveDialogState(false)
    LaunchedEffect(isOpened) {
        if (isOpened) {
            dialogState.show()
        } else {
            dialogState.hide()
        }
    }
    dialogState.OnFullyDismissed {
        onDismiss()
    }
    ResponsiveDialog(
        state = dialogState,
        onDismiss = {
            dialogState.hide()
        }
    ) {
        SheetUI(
            header = {
                SheetHeader(
                    headerTitle = {
                        SheetTitle("Extra Config")
                    },
                    headerActions = {}
                )
            }
        ) {
            Box {
                val scrollState = rememberScrollState()
                Column(
                    Modifier.verticalScroll(scrollState)
                ) {
                    for ((index, cfg) in configurables.withIndex()) {
                        RenderConfigurable(
                            cfg,
                            ConfigurableUiProps(
                                itemPaddingValues = PaddingValues(vertical = 8.dp, horizontal = 32.dp)
                            )
                        )
                        if (index != configurables.lastIndex) {
                            Divider()
                        }
                    }
                }
                MultiplatformVerticalScrollbar(
                    rememberScrollbarAdapter(scrollState),
                    Modifier
                        .matchParentSize()
                        .wrapContentWidth()
                        .align(Alignment.CenterEnd)
                )
            }
        }
    }
}

@Composable
private fun Divider() {
    Spacer(
        Modifier
            .fillMaxWidth()
            .height(1.dp)
            .background(myColors.onBackground / 10),
    )
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/LocationTextField.kt
================================================
package com.abdownloadmanager.android.pages.add.shared

import com.abdownloadmanager.shared.ui.widget.MyTextFieldWithIcons
import com.abdownloadmanager.shared.ui.widget.MyTextFieldIcon
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.ui.theme.myTextSizes
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.ui.widget.menu.custom.MyDropDown
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.android.pages.directorypicker.rememberAndroidDirectoryPickerLauncher
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.util.ui.theme.myShapes
import com.abdownloadmanager.shared.util.ui.widget.MyIcon
import ir.amirab.util.compose.resources.myStringResource
import ir.amirab.util.compose.asStringSource
import java.io.File

@Composable
fun LocationTextField(
    modifier: Modifier,
    text: String,
    setText: (String) -> Unit,
    errorText: String? = null,
    lastUsedLocations: List<String> = emptyList(),
    onRequestRemoveSaveLocation: (String) -> Unit,
) {
    var showLastUsedLocations by remember { mutableStateOf(false) }

    val downloadLauncherFolderPickerLauncher = rememberAndroidDirectoryPickerLauncher(
        title = Res.string.download_location.asStringSource(),
        initialDirectory = remember(text) {
            runCatching {
                File(text).canonicalPath
            }.getOrNull()
        },
    ) { directory ->
        directory?.let(setText)
    }

    var widthForDropDown by remember {
        mutableStateOf(0.dp)
    }
    val density = LocalDensity.current
    Box(modifier) {
        MyTextFieldWithIcons(
            text,
            setText,
            myStringResource(Res.string.location),
            modifier = Modifier
                .fillMaxWidth()
                .onGloballyPositioned {
                    widthForDropDown = with(density) {
                        it.size.width.toDp()
                    }
                },
            errorText = errorText,
            end = {
                Row {
                    MyTextFieldIcon(MyIcons.folder) {
                        downloadLauncherFolderPickerLauncher.launch()
                    }
                    MyTextFieldIcon(MyIcons.down) {
                        showLastUsedLocations = !showLastUsedLocations
                    }
                }
            }
        )
        if (showLastUsedLocations) {
            ShowSuggestions(
                width = { widthForDropDown },
                suggestions = lastUsedLocations,
                onSuggestionSelected = {
                    setText(it)
                    showLastUsedLocations = false
                },
                onDismiss = {
                    showLastUsedLocations = false
                },
                onRequestRemove = onRequestRemoveSaveLocation
            )
        }
    }
}

@Composable
private fun ShowSuggestions(
    width: () -> Dp,
    suggestions: List<String>,
    onRequestRemove: (String) -> Unit,
    onSuggestionSelected: (String) -> Unit,
    onDismiss: () -> Unit,
) {
    MyDropDown(onDismiss) {
        Column(
            Modifier
                .width(width())
                .clip(myShapes.defaultRounded)
                .background(myColors.surface)
                .verticalScroll(rememberScrollState())
        ) {
            for (l in suggestions) {
                Row(
                    Modifier.height(IntrinsicSize.Max)
                ) {
                    Text(
                        text = l,
                        modifier = Modifier
                            .weight(1f)
                            .clickable {
                                onSuggestionSelected(l)
                            }
                            .padding(vertical = 4.dp, horizontal = 4.dp),
                        fontSize = myTextSizes.sm
                    )
                    MyIcon(
                        MyIcons.clear,
                        null,
                        Modifier
                            .fillMaxHeight()
                            .clickable {
                                onRequestRemove(l)
                            }
                            .wrapContentHeight()
                            .padding(horizontal = 2.dp)
                            .size(12.dp)
                            .alpha(0.25f)
                    )
                }
            }
        }
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/SelectQueue.kt
================================================
package com.abdownloadmanager.android.pages.add.shared

import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.ui.theme.myTextSizes
import com.abdownloadmanager.shared.ui.widget.ActionButton
import com.abdownloadmanager.shared.ui.widget.IconActionButton
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.util.ui.WithContentColor
import com.abdownloadmanager.shared.util.div
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.abdownloadmanager.android.ui.SheetHeader
import com.abdownloadmanager.android.ui.SheetTitle
import com.abdownloadmanager.android.ui.SheetUI
import com.abdownloadmanager.shared.util.ui.theme.LocalUiScale
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.ui.widget.CheckBox
import com.abdownloadmanager.shared.util.OnFullyDismissed
import com.abdownloadmanager.shared.util.ResponsiveDialog
import com.abdownloadmanager.shared.util.rememberResponsiveDialogState
import com.abdownloadmanager.shared.util.ui.MultiplatformVerticalScrollbar
import com.abdownloadmanager.shared.util.ui.VerticalScrollableContent
import com.abdownloadmanager.shared.util.ui.theme.myShapes
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import io.github.oikvpqya.compose.fastscroller.rememberScrollbarAdapter
import ir.amirab.util.compose.resources.myStringResource
import ir.amirab.downloader.queue.DownloadQueue
import ir.amirab.util.compose.action.AnAction
import ir.amirab.util.compose.asStringSource

@Composable
fun ShowAddToQueueDialog(
    queueList: List<DownloadQueue>,
    isOpened: Boolean,
    onQueueSelected: (Long?, Boolean) -> Unit,
    newQueueAction: AnAction,
    onClose: () -> Unit,
) {
    val state = rememberResponsiveDialogState(false)
    LaunchedEffect(isOpened) {
        if (isOpened) {
            state.show()
        } else {
            state.hide()
        }
    }
    state.OnFullyDismissed {
        onClose()
    }
    val (startQueue, setStartQueue) = remember {
        mutableStateOf(false)
    }
    ResponsiveDialog(
        onDismiss = state::hide,
        state = state,
    ) {
        SheetUI(
            header = {
                SheetHeader(
                    headerTitle = {
                        SheetTitle(
                            myStringResource(Res.string.select_queue)
                        )
                    }
                )
            }
        ) {
            WithContentColor(myColors.onBackground) {
                Column(
                    Modifier.fillMaxWidth()
                ) {
                    Column(
                        Modifier
                            .padding(horizontal = 8.dp)
                            .padding(bottom = 8.dp)
                    ) {
                        val addToQueueModifier = Modifier.fillMaxWidth()
                        Spacer(Modifier.height(8.dp))
                            val scrollState = rememberScrollState()
                        VerticalScrollableContent(
                            scrollState,
                            Modifier
                                .border(1.dp, myColors.onBackground / 5, myShapes.defaultRounded)
                                .padding(1.dp),
                        ) {
                            Column(
                                modifier = Modifier
                                    .verticalScroll(scrollState)
                            ) {
                                for (q in queueList) {
                                    key(q.id) {
                                        val queueModel by q.queueModel.collectAsState()
                                        QueueItemToSelect(
                                            modifier = addToQueueModifier,
                                            name = queueModel.name,
                                            onSelect = {
                                                onQueueSelected(queueModel.id, startQueue)
                                            }
                                        )
                                    }
                                }
                            }
                        }
                        Spacer(Modifier.height(8.dp))
                        Row(
                            verticalAlignment = Alignment.CenterVertically,
                            modifier = Modifier
                                .clickable {
                                    setStartQueue(!startQueue)
                                }
                                .padding(vertical = 4.dp)
                                .padding(start = 2.dp)
                        ) {
                            CheckBox(
                                size = 24.dp,
                                value = startQueue,
                                onValueChange = setStartQueue
                            )
                            Spacer(Modifier.width(mySpacings.mediumSpace))
                            Text(myStringResource(Res.string.start_queue))
                        }
                        Row(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(vertical = 8.dp),
                            verticalAlignment = Alignment.CenterVertically,
                            horizontalArrangement = Arrangement.SpaceBetween
                        ) {
                            IconActionButton(
                                MyIcons.add,
                                contentDescription = Res.string.add_new_queue.asStringSource(),
                                onClick = newQueueAction
                            )
                            Spacer(Modifier.width(mySpacings.mediumSpace))
                            ActionButton(
                                text = myStringResource(Res.string.without_queue),
                                modifier = Modifier.weight(1f),
                                onClick = {
                                    onQueueSelected(null, startQueue)
                                }
                            )
                        }
                    }
                }
            }
        }
    }
}

@Composable
fun QueueItemToSelect(
    modifier: Modifier,
    name: String,
    onSelect: () -> Unit,
) {
    Row(
        modifier
            .clickable(onClick = onSelect)
            .heightIn(mySpacings.thumbSize)
            .padding(vertical = 4.dp)
            .padding(horizontal = 4.dp),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(
            name,
            fontSize = myTextSizes.base,
        )
    }
}

@Composable
private fun Divider() {
    Spacer(
        Modifier
            .fillMaxWidth()
            .height(1.dp)
            .background(myColors.onBackground / 10),
    )
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AddSingleDownloadActivity.kt
================================================
package com.abdownloadmanager.android.pages.add.single

import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import com.abdownloadmanager.android.pages.browser.BrowserActivity
import com.abdownloadmanager.android.pages.category.CategorySheet
import com.abdownloadmanager.android.pages.newqueue.NewQueueSheet
import com.abdownloadmanager.android.pages.singledownload.SingleDownloadPageActivity
import com.abdownloadmanager.android.util.ABDMAppManager
import com.abdownloadmanager.android.util.AndroidDownloadItemOpener
import com.abdownloadmanager.android.util.activity.ABDMActivity
import com.abdownloadmanager.android.util.activity.HandleActivityEffects
import com.abdownloadmanager.android.util.activity.getSerializedExtra
import com.abdownloadmanager.android.util.activity.putSerializedExtra
import com.abdownloadmanager.shared.downloaderinui.DownloaderInUiRegistry
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadConfig
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadCredentialsInUiProps
import com.abdownloadmanager.shared.pages.adddownload.single.BaseAddSingleDownloadComponent
import com.abdownloadmanager.shared.storage.ILastSavedLocationsStorage
import com.abdownloadmanager.shared.util.DownloadSystem
import com.abdownloadmanager.shared.util.FileIconProvider
import com.abdownloadmanager.shared.util.OnFullyDismissed
import com.abdownloadmanager.shared.util.ResponsiveDialog
import com.abdownloadmanager.shared.util.category.CategoryManager
import com.abdownloadmanager.shared.util.mvi.HandleEffects
import com.abdownloadmanager.shared.util.rememberChild
import com.abdownloadmanager.shared.util.rememberResponsiveDialogState
import ir.amirab.downloader.downloaditem.http.HttpDownloadCredentials
import ir.amirab.downloader.queue.QueueManager
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import org.koin.core.component.inject

class AddSingleDownloadActivity : ABDMActivity() {
    private val json: Json by inject()
    private val downloadSystem: DownloadSystem by inject()
    private val appManager: ABDMAppManager by inject()
    private val downloadItemOpener: AndroidDownloadItemOpener by inject()
    private val downloaderInUiRegistry: DownloaderInUiRegistry by inject()
    private val lastSavedLocationsStorage: ILastSavedLocationsStorage by inject()
    private val queueManager: QueueManager by inject()
    private val categoryManager: CategoryManager by inject()
    private val iconProvider: FileIconProvider by inject()
    private val appContext: Context by inject()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val myRetainedComponent = myRetainedComponent {
            // TODO consider use a factory to create AndroidAddSingleDownloadComponent
            // we may create memory leaks if we accidentally pass Activity::this into the component lambdas
            val config = getComponentConfig(intent)
            val appManager = appManager
            val appContext = this@AddSingleDownloadActivity.appContext
            val scope = applicationScope
            val downloadItemOpener = downloadItemOpener
            val appSettingsStorage = appSettingsStorage
            val downloadSystem = downloadSystem
            val closeAddDownloadDialog = {
                this@myRetainedComponent.finishActivityAction()
            }
            AndroidAddSingleDownloadComponent(
                ctx = it,
                onRequestClose = closeAddDownloadDialog,
                onRequestDownload = { item, categoryId ->
                    scope.launch {
                        val id = appManager.startNewDownload(item, categoryId).await()
                        if (appSettingsStorage.showDownloadProgressDialog.value) {
                            runCatching {
                                appContext.startActivity(
                                    SingleDownloadPageActivity.createIntent(
                                        appContext,
                                        id,
                                        true,
                                    ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                                )
                            }.onFailure {
                                it.printStackTrace()
                            }
                        }
                    }
                },
                onRequestAddToQueue = { item, queue, category ->
                    appManager.addDownload(item, queue, category)
                },
                openExistingDownload = {
                    scope.launch {
                        downloadItemOpener.openDownloadItem(it)
                    }
                },
                updateExistingDownloadCredentials = { id, newCredentials, downloadJobExtraConfig ->
                    scope.launch {
                        downloadSystem.downloadManager.updateDownloadItem(
                            id = id,
                            downloadJobExtraConfig = downloadJobExtraConfig,
                            updater = {
                                it.withCredentials(newCredentials)
                            }
                        )
//                        openDownloadDialog(id)
                    }
                },
                downloadItemOpener = downloadItemOpener,
                lastSavedLocationsStorage = lastSavedLocationsStorage,
                importOptions = config.importOptions,
                id = config.id,
                downloaderInUi = downloaderInUiRegistry.getDownloaderOf(config.newDownload.credentials)!!,
                initialCredentials = config.newDownload,
                queueManager = queueManager,
                categoryManager = categoryManager,
                downloadSystem = downloadSystem,
                appSettings = appSettingsStorage,
                iconProvider = iconProvider,
                appScope = applicationScope,
                appRepository = appRepository,
                perHostSettingsManager = perHostSettingsManager,
            )
        }
        val addDownloadComponent = myRetainedComponent.component
        setABDMContent {
            myRetainedComponent.HandleActivityEffects()
            HandleEffects(addDownloadComponent) {
                if (it is AndroidAddSingleDownloadComponent.Effects.OpenInBrowser) {
                    startActivity(
                        BrowserActivity.createIntent(this, it.link)
                    )
                    finish()
                }
            }
            val dialogState = rememberResponsiveDialogState(false)
            dialogState.OnFullyDismissed {
                addDownloadComponent.onRequestClose()
            }
            LaunchedEffect(Unit) {
                // animate open after activity becomes fully open
                // is there a better way?
                delay(10)
                dialogState.show()
            }
            val onDismiss = { dialogState.hide() }
            ResponsiveDialog(
                dialogState,
                onDismiss
            ) {
                AddSingleDownloadPage(addDownloadComponent, onDismiss)
            }
            CategorySheet(
                categoryComponent = addDownloadComponent.categorySlot.rememberChild(),
                onDismiss = addDownloadComponent::closeCategoryDialog
            )
            NewQueueSheet(
                onQueueCreate = addDownloadComponent::createQueueWithName,
                isOpened = addDownloadComponent.showAddQueue.collectAsState().value,
                onCloseRequest = { addDownloadComponent.setShowAddQueue(false) },
            )
        }
    }

    private fun getComponentConfig(intent: Intent): AddDownloadConfig.SingleAddConfig {
        runCatching {
            with(json) {
                intent.getSerializedExtra<AddDownloadConfig.SingleAddConfig>(COMPONENT_CONFIG_KEY)
            }
        }.onFailure {
            it.printStackTrace()
        }.getOrNull()?.let {
            return it
        }
        val link = intent.data?.toString().orEmpty()
        return AddDownloadConfig.SingleAddConfig(
            newDownload = AddDownloadCredentialsInUiProps(
                credentials = HttpDownloadCredentials(
                    link = link,
                )
            )
        )
    }

    companion object {
        const val COMPONENT_CONFIG_KEY = "ComponentConfig"
        const val LINK_KEY = "link"
        fun createIntent(
            context: Context,
            singleAddConfig: AddDownloadConfig.SingleAddConfig,
            json: Json,
        ): Intent {
            val intent = Intent(
                context,
                AddSingleDownloadActivity::class.java,
            )
            with(json) {
                intent.putSerializedExtra(COMPONENT_CONFIG_KEY, singleAddConfig)
            }
            return intent
        }
    }
}


================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AddSingleDownloadPage.kt
================================================
package com.abdownloadmanager.android.pages.add.single

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import arrow.core.Some
import com.abdownloadmanager.android.pages.add.shared.CategoryAddButton
import com.abdownloadmanager.android.pages.add.shared.CategorySelect
import com.abdownloadmanager.android.pages.add.shared.ExtraConfig
import com.abdownloadmanager.android.pages.add.shared.LocationTextField
import com.abdownloadmanager.android.pages.add.shared.ShowAddToQueueDialog
import com.abdownloadmanager.android.ui.SheetHeader
import com.abdownloadmanager.android.ui.SheetTitle
import com.abdownloadmanager.android.ui.SheetTitleWithDescription
import com.abdownloadmanager.android.ui.SheetUI
import com.abdownloadmanager.resources.Res
import com.abdownloadmanager.shared.ui.widget.ActionButton
import com.abdownloadmanager.shared.ui.widget.IconActionButton
import com.abdownloadmanager.shared.ui.widget.MyTextFieldWithIcons
import com.abdownloadmanager.shared.ui.widget.Text
import com.abdownloadmanager.shared.util.ResponsiveDialog
import com.abdownloadmanager.shared.util.mvi.HandleEffects
import com.abdownloadmanager.shared.util.rememberResponsiveDialogState
import com.abdownloadmanager.shared.util.ui.icon.MyIcons
import ir.amirab.util.compose.resources.myStringResource


import com.abdownloadmanager.shared.util.ui.WithContentAlpha
import com.abdownloadmanager.shared.util.ui.widget.MyIcon
import com.abdownloadmanager.shared.util.ui.myColors
import com.abdownloadmanager.shared.util.ui.theme.myTextSizes
import androidx.compose.animation.*
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.*
import com.abdownloadmanager.shared.ui.widget.*
import com.abdownloadmanager.shared.downloaderinui.add.CanAddResult
import com.abdownloadmanager.shared.pages.adddownload.single.BaseAddSingleDownloadComponent
import com.abdownloadmanager.shared.util.ClipboardUtil
import com.abdownloadmanager.shared.util.OnFullyDismissed
import com.abdownloadmanager.shared.util.ResponsiveDialogScope
import com.abdownloadmanager.shared.util.div
import com.abdownloadmanager.shared.util.ui.theme.mySpacings
import ir.amirab.downloader.utils.OnDuplicateStrategy
import ir.amirab.util.compose.asStringSource

@Composable
fun ResponsiveDialogScope.AddSingleDownloadPage(
    component: AndroidAddSingleDownloadComponent,
    onDismiss: () -> Unit,
) {
    SheetUI(
        header = {
            SheetHeader(
                headerTitle = {
                    SheetTitle(
                        myStringResource(Res.string.new_download)
                    )
                },
                headerActions = {
                    TransparentIconActionButton(
                        MyIcons.close,
                        contentDescription = Res.string.close.asStringSource(),
                        onClick = onDismiss,
                    )
                }
            )
        }
    ) {
        val onDuplicateStrategy by component.onDuplicateStrategy.collectAsState()
        Column(
            Modifier
                .padding(horizontal = mySpacings.mediumSpace)
        ) {
            Column(
                Modifier
                    .weight(1f, false)
                    .verticalScroll(rememberScrollState())
            ) {
                val credentials by component.credentials.collectAsState()
                fun setLink(link: String) {
                    component.setCredentials(
                        credentials.copy(link = Some(link))
                    )
                }

                val showMoreInputs by component.showMoreInputs.collectAsState()

                HandleEffects(component) {
                    when (it) {
                        is BaseAddSingleDownloadComponent.Effects.Common -> {
                            when (it) {
                                is BaseAddSingleDownloadComponent.Effects.Common.SuggestUrl -> {
                                    setLink(it.link)
                                }
                            }
                        }

                        is BaseAddSingleDownloadComponent.Effects.Platform -> {
                            //
                        }
                    }
                }

                val canAddResult by component.canAddResult.collectAsState()
                Column {
                    UrlTextField(
                        text = credentials.link,
                        setText = {
                            setLink(it)
                        },
                        modifier = Modifier
                    )
                    AnimatedVisibility(showMoreInputs) {
                        Column {
                            Space()
                            val useCategory by component.useCategory.collectAsState()
                            Column {
                                Row(
                                    verticalAlignment = Alignment.CenterVertically,
                                    modifier = Modifier
                                        .clickable {
                                            component.setUseCategory(!useCategory)
                                        }
                                        .padding(vertical = 4.dp)
                                ) {
                                    CheckBox(
                                        size = 16.dp,
                                        value = useCategory,
                                        onValueChange = { component.setUseCategory(it) }
                                    )
                                    Spacer(Modifier.width(8.dp))
                                    Text(myStringResource(Res.string.use_category))
                                }
                                Space()
                                Row {
                                    CategorySelect(
                                        modifier = Modifier.weight(1f),
                                        enabled = useCategory,
                                        categories = component.categories.collectAsState().value,
                                        selectedCategory = component.selectedCategory.collectAsState().value,
                                        onCategorySelected = {
                                            component.setSelectedCategory(it)
                                        },
                                    )
                                    Spacer(Modifier.width(8.dp))
                                    CategoryAddButton(
                                        enabled = useCategory,
                                        modifier = Modifier,
                                        onClick = {
                                            component.addNewCategory()
                                        },
                                    )
                                }
                            }
                            Spacer(Modifier.size(8.dp))
                            LocationTextField(
                                modifier = Modifier.fillMaxWidth(),
                                text = component.folder.collectAsState().value,
                                setText = {
                                    component.setFolder(it)
                                },
                                errorText = when (canAddResult) {
                                    CanAddResult.CantWriteInThisFolder -> myStringResource(Res.string.cant_write_to_this_folder)
                                    else -> null
                                },
                                lastUsedLocations = component.lastUsedLocations.collectAsState().value,
                                onRequestRemoveSaveLocation = component::removeFromLastDownloadLocation,
                            )
                        }
                    }
                    val name by component.name.collectAsState()
                    Spacer(Modifier.size(8.dp))
                    NameTextField(
                        text = name,
                        setText = {
                            component.setName(it)
                        },
                        errorText = when (canAddResult) {
                            is CanAddResult.DownloadAlreadyExists -> {
                                if (onDuplicateStrategy == null) {
                                    myStringResource(Res.string.download_already_exists)
                                } else {
                                    null
                                }
                            }

                            CanAddResult.InvalidFileName -> myStringResource(Res.string.invalid_file_name)
                            else -> null
                        }.takeIf { name.isNotEmpty() }
                    )
                }
            }
            Column {
                Space()
                Row(
                    verticalAlignment = Alignment.CenterVertically,
                ) {
                    RenderFileTypeAndSize(component)
                    RenderResumeSupport(component, Modifier.weight(1f))
                    ConfigActionsButtons(component)
                }
                Space()
                MainActionButtons(component)
                ShowSolutionsOnDuplicateDownload(component)
                ShowAddToQueueDialog(
                    isOpened = component.shouldShowAddToQueue,
                    queueList = component.queues.collectAsState().value,
                    onClose = { component.shouldShowAddToQueue = false },
                    onQueueSelected = { queue, startQueue ->
                        component.onRequestAddToQueue(queue, startQueue)
                    },
                    newQueueAction = component.newQueuesAction
                )
                ExtraConfig(
                    isOpened = component.showMoreSettings,
                    onDismiss = { component.showMoreSettings = false },
                    configurables = component.configurables,
                )
            }
        }
    }

}

@Composable
private fun Space() {
    Spacer(Modifier.size(mySpacings.mediumSpace))
}

@Composable
private fun ShowSolutionsOnDuplicateDownload(
    component: AndroidAddSingleDownloadComponent,
) {
    val state = rememberResponsiveDialogState(false)
    val isOpen = component.showSolutionsOnDuplicateDownloadUi
    val onRequestClose = {
        component.showSolutionsOnDuplicateDownloadUi = false
    }
    state.OnFullyDismissed(onRequestClose)
    LaunchedEffect(isOpen) {
        if (isOpen) {
            state.show()
        } else {
            state.hide()
        }
    }
    val onDuplicateStrategy by component.onDuplicateStrategy.collectAsState()
    ResponsiveDialog(
        onDismiss = state::hide,
        state = state,
    ) {
        SheetUI(
            header = {
                SheetHeader(
                    headerTitle = {
                        SheetTitleWithDescription(
                            myStringResource(Res.string.select_a_solution),
                            myStringResource(Res.string.select_download_strategy_description),
                        )
                    }
                )
            },
            content = {
                Column(
                    Modifier
                        .padding(horizontal = 8.dp)
                        .padding(bottom = 8.dp)
                ) {
                    Spacer(Modifier.height(4.dp))
                    Divider()
                    Spacer(Modifier.height(4.dp))
                    Column {
                        OnDuplicateStrategySolutionItem(
                            isSelected = onDuplicateStrategy == OnDuplicateStrategy.AddNumbered,
                            title = myStringResource(Res.string.download_strategy_add_a_numbered_file),
                            description = myStringResource(Res.string.download_strategy_add_a_numbered_file_description),
                        ) {
                            component.setOnDuplicateStrategy(OnDuplicateStrategy.AddNumbered)
                            onRequestClose()
                        }
                        OnDuplicateStrategySolutionItem(
                            isSelected = onDuplicateStrategy == OnDuplicateStrategy.OverrideDownload,
                            title = myStringResource(Res.string.download_strategy_override_existing_file),
                            description = myStringResource(Res.string.download_strategy_override_existing_file_description),
                        ) {
                            component.setOnDuplicateStrategy(OnDuplicateStrategy.OverrideDownload)
                            onRequestClose()
                        }
                        OnDuplicateStrategySolutionItem(
                            isSelected = null,
                            title = myStringResource(Res.string.download_strategy_update_download_link),
                            description = myStringResource(Res.string.download_strategy_update_download_link_description),
                        ) {
                            component.updateDownloadCredentialsOfOriginalDownload()
                            onRequestClose()
                        }
                        OnDuplicateStrategySolutionItem(
                            isSelected = null,
                            title = myStringResource(Res.string.download_strategy_show_downloaded_file),
                            description = myStringResource(Res.string.download_strategy_show_downloaded_file_description),
                        ) {
                            component.openDownloadFileForCurrentLink()
                            onRequestClose()
                        }
                    }
                }
            }
        )

    }
}

@Composable
private fun OnDuplicateStrategySolutionItem(
    title: String,
    description: String,
    isSelected: Boolean?,
    onClick: () -> Unit,
) {
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = Modifier
            .fillMaxWidth()
            .clickable(onClick = onClick)
            .padding(8.dp)
    ) {
        isSelected?.let {
            CheckBox(isSelected, { onClick() }, size = 12.dp)
        }
        Spacer(Modifier.width(8.dp))
        Column {
            Text(
                title,
                fontSize = myTextSizes.base,
                fontWeight = FontWeight.Bold
            )
            Spacer(Modifier.height(4.dp))
            WithContentAlpha(0.7f) {
                Text(
                    text = description,
                    fontSize = myTextSizes.sm,
                    modifier = Modifier
                )
            }
        }

    }
}


@Composable
private fun Divider() {
    Spacer(
        Modifier
            .fillMaxWidth()
            .height(1.dp)
            .background(myColors.onBackground / 10),
    )
}


@Composable
fun RenderResumeSupport(
    component: AndroidAddSingleDownloadComponent,
    modifier: Modifier,
) {
    val fileInfo by component.linkResponseInfo.collectAsState()
    Row(
        verticalAlignment = Alignment.CenterVertically,
        modifier = modifier
            .height(16.dp)
            .padding(horizontal = 8.dp)
    ) {
        val lineModifier = Modifier
            .weight(1f)
            .height(1.dp)
            .background(myColors.onBackground / 10)
        Box(lineModifier)
        val canAddToDownloads by component.canAddToDownloads.collectAsState()
        AnimatedVisibility(
            visible = canAddToDownloads && fileInfo != null,
        ) {
            fileInfo?.let { fileInfo ->
                if (fileInfo.resumeSupport) {
                    val iconModifier = Modifier
                        .padding(horizontal = 8.dp)
                        .size(16.dp)
                    if (fileInfo.resumeSupport) {
                        MyIcon(
                            icon = MyIcons.check,
                            contentDescription = null,
                            modifier = iconModifier,
                            tint = myColors.success
                        )
                    } else {
                        MyIcon(
                            icon = MyIcons.clear,
                            contentDescription = null,
                            modifier = iconModifier,
                            tint = myColors.error,
                        )
                    }
                }
            }
        }
        Box(lineModifier)


    }
}

@Composable
private fun MainConfigActionButton(
    text: String,
    modifier: Modifier,
    enabled: Boolean = true,
    onClick: () -> Unit,
) {
    ActionButton(text, modifier, enabled, onClick)
}


@Composable
fun ConfigActionsButtons(component: AndroidAddSingleDownloadComponent) {
    val responseInfo by component.linkResponseInfo.collectAsState()
    Row {
        IconActionButton(MyIcons.refresh, Res.string.refresh.asStringSource()) {
            component.refresh()
        }
        Spacer(Modifier.width(6.dp))
        val showMoreInputs by component.showMoreInputs.collectAsState()
        IconActionButton(
            if (showMoreInputs) {
                MyIcons.up
            } else {
                MyIcons.down
            },
            Res.string.more_options.asStringSource(),
        ) {
            component.setShowMoreInputs(!showMoreInputs)
        }
        Spacer(Modifier.width(6.dp))
        IconActionButton(
            MyIcons.settings,
            Res.string.settings.asStringSource(),
            indicateActive = component.showMoreSettings,
            requiresAttention = responseInfo?.requireBasicAuth ?: false
        ) {
            component.showMoreSettings = true
        }
    }
}

@Composable
private fun MainActionButtons(component: AndroidAddSingleDownloadComponent) {

    val onDuplicateStrategy by component.onDuplicateStrategy.collectAsState()
    val canAddResult by component.canAddResult.collectAsState()
    if (canAddResult is CanAddResult.DownloadAlreadyExists && onDuplicateStrategy == null) {
        Row {
            val buttonModifier = Modifier.weight(1f)
            MainConfigActionButton(
                text = myStringResource(Res.string.show_solutions),
                modifier = buttonModifier,
                onClick = { component.showSolutionsOnDuplicateDownloadUi = true },
            )
            if (component.shouldShowOpenFile.collectAsState().value) {
                Spacer(Modifier.width(8.dp))
                MainConfigActionButton(
                    text = myStringResource(Res.string.open_file),
                    modifier = buttonModifier,
                    onClick = { component.openExistingFile() },
                )
            }
        }
    } else {
        val canAddToDownloads by component.canAddToDownloads.collectAsState()
        Column {
            if (onDuplicateStrategy != null) {
                MainConfigActionButton(
                    text = myStringResource(Res.string.change_solution),
                    modifier = Modifier.fillMaxWidth(),
                    onClick = { component.showSolutionsOnDuplicateDownloadUi = true },
                )
                Space()
            }
            val isWebPage by component.isWebPage.collectAsState()
            if (isWebPage) {
                Row {
                    MainConfigActionButton(
                        text = myStringResource(Res.string.open_in_browser),
                        modifier = Modifier.fillMaxWidth(),
                        enabled = canAddToDownloads,
                        onClick = {
                            component.onRequestOpenLinkInBrowser()
                        },
                    )
                }
            } else {
                Row {
                    val buttonModifier = Modifier.weight(1f)
                    MainConfigActionButton(
                        text = myStringResource(Res.string.add),
                        modifier = buttonModifier,
                        enabled = canAddToDownloads,
                        onClick = {
                            component.shouldShowAddToQueue = true
                        },
                    )
                    Spacer(Modifier.width(8.dp))
                    PrimaryMainActionButton(
                        text = myStringResource(Res.string.download),
                        modifier = buttonModifier,
                        enabled = canAddToDownloads,
                        onClick = {
                            component.onRequestDownload()
                        },
                    )
                }

            }

        }
    }
}

@Composable
fun RenderFileTypeAndSize(
    component: AndroidAddSingleDownloadComponent,
) {
    val isLinkLoading by component.isLinkLoading.collectAsState()
    val fileInfo by component.linkResponseInfo.collectAsState()
    val fileIconProvider = component.iconProvider
    val iconModifier = Modifier.size(mySpacings.iconSize)
    Box(
        contentAlignment = Alignment.Center,
    ) {
        AnimatedContent(
            targetState = isLinkLoading,
            transitionSpec = {
                fadeIn() togetherWith fadeOut()
            }
        ) { loading ->
            if (loading) {
                LoadingIndicator(iconModifier)
            } else {
//                val extension = getExtension(fileInfo?.fileName ?: usersSetFileName) ?: "unknown"
                val downloadItem by component.downloadItem.collectAsState()
                val icon = fileIconProvider.rememberIcon(downloadItem.name)
                AnimatedContent(
                    fileInfo,
                ) { fileInfo ->
                    Row(
                        verticalAlignment = Alignment.CenterVertically,
                    ) {
                        WithContentAlpha(1f) {
                            if (fileInfo != null) {
                                if (fileInfo.requiresAuth) {
                                    MyIcon(
                                        MyIcons.lock,
                                        null,
                                        iconModifier,
                                        tint = myColors.error
                                    )
                                }
                                MyIcon(
                                    icon,
                                    null,
                                    iconModifier
                                )
                                val size = component.getLengthString()
                                Spacer(Modifier.width(8.dp))
                                Text(
                                    size.rememberString(),
                                    fontSize = myTextSizes.sm,
                                )
                            } else {
                                MyIcon(
                                    icon = MyIcons.question,
                                    contentDescription = null,
                                    modifier = iconModifier,
                                )
                            }
                        }
                    }
                }
            }
        }
    }
}

@Composable
private fun UrlTextField(
    text: String,
    setText: (String) -> Unit,
    errorText: String? = null,
    modifier: Modifier = Modifier,
) {
    MyTextFieldWithIcons(
        text,
        setText,
        myStringResource(Res.string.download_link),
        modifier = modifier.fillMaxWidth(),
        end = {
            MyTextFieldIcon(MyIcons.paste) {
                setText(
                    ClipboardUtil.read()
                        .orEmpty()
                )
            }
        },
        errorText = errorText
    )
}

@Composable
private fun NameTextField(
    text: String,
    setText: (String) -> Unit,
    errorText: String? = null,
) {
    MyTextFieldWithIcons(
        text,
        setText,
        myStringResource(Res.string.name),
        modifier = Modifier.fillMaxWidth(),
        errorText = errorText,
    )
}



================================================
FILE: android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AndroidAddSingleDownloadComponent.kt
================================================
package com.abdownloadmanager.android.pages.add.single

import com.abdownloadmanager.shared.action.createNewQueueAction
import com.abdownloadmanager.shared.downloaderinui.DownloaderInUi
import com.abdownloadmanager.shared.pagemanager.CategoryDialogManager
import com.abdownloadmanager.shared.pagemanager.NewQueuePageManager
import com.abdownloadmanager.shared.pages.adddownload.AddDownloadCredentialsInUiProps
import com.abdownloadmanager.shared.pages.adddownload.ImportOptions
import com.abdownloadmanager.shared.pages.adddownload.single.BaseAddSingleDownloadComponent
import com.abdownloadmanager.shared.pages.adddownload.single.OnRequestAddSingleItem
import com.abdownloadmanager.shared.pages.adddownload.single.OnRequestDownloadSingleItem
import com.abdownloadmanager.shared.pages.category.CategoryComponent
import com.abdownloadmanager.shared.repository.BaseAppRepository
import com.abdownloadmanager.shared.storage.BaseAppSettingsStorage
import com.abdownloadmanager.shared.storage.ILastSavedLocationsStorage
import com.abdownloadmanager.shared.util.DownloadItemOpener
import com.abdownloadmanager.shared.util.DownloadSystem
import com.abdownloadmanager.shared.util.FileIconProvider
import com.abdownloadmanager.shared.util.category.CategoryManager
import com.abdownloadmanager.shared.util.perhostsettings.PerHostSettingsManager
import com.abdownloadmanager.shared.util.subscribeAsStateFlow
import com.arkivanov.decompose.ComponentContext
import com.arkivanov.decompose.router.slot.SlotNavigation
import com.arkivanov.decompose.router.slot.activate
import com.arkivanov.decompose.router.slot.childSlot
import com.arkivanov.decompose.router.slot.dismiss
import ir.amirab.downloader.downloaditem.DownloadJobExtraConfig
import ir.amirab.downloader.downloaditem.IDownloadCredentials
import ir.amirab.downloader.queue.QueueManager
import ir.amirab.util.flow.mapStateFlow
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import kotlinx.serialization.builtins.serializer

class AndroidAddSingleDownloadComponent(
    ctx: ComponentContext,
    onRequestClose: () -> Unit,
    onRequestDownload: OnRequestDownloadSingleItem,
    onRequestAddToQueue: OnRequestAddSingleItem,
    openExistingDownload: (Long) -> Unit,
    updateExistingDownloadCredentials: (Long, IDownloadCredentials, DownloadJobExtraConfig?) -> Unit,
    downloadItemOpener: DownloadItemOpener,
    lastSavedLocationsStorage: ILastSavedLocationsStorage,
    queueManager: QueueManager,
    categoryManager: CategoryManager,
    downloadSystem: DownloadSystem,
    appSettings: BaseAppSettingsStorage,
    iconProvider: FileIconProvider,
    appScope: CoroutineScope,
    appRepository: BaseAppRepository,
    perHostSettingsManager: PerHostSettingsManager,
    importOptions: ImportOptions,
    id: String,
    downloaderInUi: DownloaderInUi<IDownloadCredentials, *, *, *, *, *, *, *, *, *>,
    initialCredentials: AddDownloadCredentialsInUiProps,
) : BaseAddSingleDownloadComponent(
    ctx = ctx,
    onRequestClose = onRequestClose,
    onRequestDownload = onRequestDownload,
    onRequestAddToQueue = onRequestAddToQueue,
    openExistingDownload = openExistingDownload,
    updateExistingDownloadCredentials = updateExistingDownloadCredentials,
    downloadItemOpener = downloadItemOpener,
    lastSavedLocationsStorage = lastSavedLocationsStorage,
    importOptions = importOptions,
    id = id,
    downloaderInUi = downloaderInUi,
    initialCredentials = initialCredentials,
    queueManager = queueManager,
    categoryManager = categoryManager,
    downloadSystem = downloadSystem,
    appSettings = appSettings,
    iconProvider = iconProvider,
    appScope = appScope,
    appRepository = appRepository,
    perHostSettingsManager = perHostSettingsManager,
), CategoryDialogManager, NewQueuePageManager {
    val categoryComponentNavigation = SlotNavigation<Long>()
    val categorySlot = childSlot(
        source = categoryComponentNavigation,
        childFactory = { config, ctx ->
            CategoryComponent(
         
Download .txt
gitextract_5ho1xmu5/

├── .gitattributes
├── .github/
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE/
│   │   └── bug_report.yml
│   └── workflows/
│       ├── brew-cask-auto-bump.yml
│       ├── publish.yml
│       └── winget.yml
├── .gitignore
├── CHANGELOG.md
├── CONTRIBUTING.md
├── DONATE.md
├── LICENSE
├── README.md
├── REST-API.yml
├── android/
│   └── app/
│       ├── .gitignore
│       ├── build.gradle.kts
│       ├── filetypes.txt
│       └── src/
│           └── main/
│               ├── AndroidManifest.xml
│               ├── kotlin/
│               │   └── com/
│               │       └── abdownloadmanager/
│               │           └── android/
│               │               ├── ABDMApp.kt
│               │               ├── action/
│               │               │   └── Actions.kt
│               │               ├── di/
│               │               │   └── Di.kt
│               │               ├── pages/
│               │               │   ├── about/
│               │               │   │   └── AboutPage.kt
│               │               │   ├── add/
│               │               │   │   ├── AddDownloadActivity.kt
│               │               │   │   ├── multiple/
│               │               │   │   │   ├── AddMultiDownloadActivity.kt
│               │               │   │   │   ├── AddMultiDownloadList.kt
│               │               │   │   │   ├── AddMultiItemPage.kt
│               │               │   │   │   └── AndroidAddMultiDownloadComponent.kt
│               │               │   │   ├── shared/
│               │               │   │   │   ├── CategorySelect.kt
│               │               │   │   │   ├── ExtraConfig.kt
│               │               │   │   │   ├── LocationTextField.kt
│               │               │   │   │   └── SelectQueue.kt
│               │               │   │   └── single/
│               │               │   │       ├── AddSingleDownloadActivity.kt
│               │               │   │       ├── AddSingleDownloadPage.kt
│               │               │   │       └── AndroidAddSingleDownloadComponent.kt
│               │               │   ├── batchdownload/
│               │               │   │   ├── AndroidBatchDownloadComponent.kt
│               │               │   │   └── BatchDownloadPage.kt
│               │               │   ├── browser/
│               │               │   │   ├── BrowserActivity.kt
│               │               │   │   ├── BrowserComponent.kt
│               │               │   │   ├── BrowserUi.kt
│               │               │   │   ├── DownloadInterceptor.kt
│               │               │   │   ├── SearchEngines.kt
│               │               │   │   ├── WebView.kt
│               │               │   │   ├── WebViewHolder.kt
│               │               │   │   └── bookmark/
│               │               │   │       ├── Bookmarks.kt
│               │               │   │       └── EditBookmark.kt
│               │               │   ├── category/
│               │               │   │   ├── CategorySheet.kt
│               │               │   │   └── NewCategory.kt
│               │               │   ├── checksum/
│               │               │   │   ├── AndroidFileChecksumComponent.kt
│               │               │   │   └── FileChecksumPage.kt
│               │               │   ├── crashreport/
│               │               │   │   ├── CrashReportActivity.kt
│               │               │   │   ├── ErrorUi.kt
│               │               │   │   └── ThrowableData.kt
│               │               │   ├── credits/
│               │               │   │   ├── thirdpartylibraries/
│               │               │   │   │   ├── ExternalLibsPage.kt
│               │               │   │   │   └── LibraryDialog.kt
│               │               │   │   └── translators/
│               │               │   │       └── TranslatorsPage.kt
│               │               │   ├── directorypicker/
│               │               │   │   ├── ComposeExtension.kt
│               │               │   │   ├── DirectoryPickerActivity.kt
│               │               │   │   └── DirectoryPickerPage.kt
│               │               │   ├── editdownload/
│               │               │   │   ├── AndroidEditDownloadComponent.kt
│               │               │   │   └── EditDownload.kt
│               │               │   ├── enterurl/
│               │               │   │   ├── AndroidEnterNewURLComponent.kt
│               │               │   │   └── EnterURLPage.kt
│               │               │   ├── home/
│               │               │   │   ├── AndroidDownloadActions.kt
│               │               │   │   ├── BottomNavigation.kt
│               │               │   │   ├── DownloadList.kt
│               │               │   │   ├── FilterStatusIndicator.kt
│               │               │   │   ├── HomeComponent.kt
│               │               │   │   ├── HomePage.kt
│               │               │   │   ├── HomePageStateToPersist.kt
│               │               │   │   ├── Prompts.kt
│               │               │   │   ├── RenderAddMenu.kt
│               │               │   │   ├── RenderDownloadItem.kt
│               │               │   │   ├── RenderMainMenu.kt
│               │               │   │   ├── RenderStatusFilterMenu.kt
│               │               │   │   ├── SelectedQueueItemsOption.kt
│               │               │   │   ├── Selection.kt
│               │               │   │   ├── SimplePager.kt
│               │               │   │   └── sections/
│               │               │   │       ├── Categories.kt
│               │               │   │       ├── queues/
│               │               │   │       │   └── Queues.kt
│               │               │   │       └── sort/
│               │               │   │           ├── DownloadSortBy.kt
│               │               │   │           └── RenderSortMenu.kt
│               │               │   ├── newqueue/
│               │               │   │   └── NewQueue.kt
│               │               │   ├── onboarding/
│               │               │   │   ├── StartUpPageTemplate.kt
│               │               │   │   ├── initialsetup/
│               │               │   │   │   ├── InitialSetupComponent.kt
│               │               │   │   │   └── InitialSetupPage.kt
│               │               │   │   └── permissions/
│               │               │   │       ├── ABDMPermissions.kt
│               │               │   │       ├── AppPermission.kt
│               │               │   │       ├── BatteryOptimizationUtil.kt
│               │               │   │       ├── CustomPermissions.kt
│               │               │   │       ├── PermissionComponent.kt
│               │               │   │       ├── PermissionManager.kt
│               │               │   │       ├── PermissionsPage.kt
│               │               │   │       └── StoragePermissionUtil.kt
│               │               │   ├── perhostsettings/
│               │               │   │   ├── AndroidPerHostSettingsComponent.kt
│               │               │   │   └── PerHostSettingsPage.kt
│               │               │   ├── queue/
│               │               │   │   ├── QueueConfigurationComponent.kt
│               │               │   │   └── QueuesSheet.kt
│               │               │   ├── settings/
│               │               │   │   ├── AndroidSettings.kt
│               │               │   │   ├── AndroidSettingsComponent.kt
│               │               │   │   └── SettingsPage.kt
│               │               │   ├── singledownload/
│               │               │   │   ├── CompletedDownloadPage.kt
│               │               │   │   ├── DesktopSingleDownloadPageComponent.kt
│               │               │   │   ├── ProgressDownloadPage.kt
│               │               │   │   ├── ShowDownloadDialogs.kt
│               │               │   │   └── SingleDownloadPageActivity.kt
│               │               │   └── updater/
│               │               │       ├── NewUpdatePage.kt
│               │               │       └── UpdaterDialog.kt
│               │               ├── receiver/
│               │               │   └── StartOnBootBroadcastReceiver.kt
│               │               ├── repository/
│               │               │   └── AppRepository.kt
│               │               ├── service/
│               │               │   ├── DownloadSystemService.kt
│               │               │   └── KeepAliveServiceReason.kt
│               │               ├── storage/
│               │               │   ├── AndroidExtraDownloadItemSettings.kt
│               │               │   ├── AndroidExtraQueueSettings.kt
│               │               │   ├── AndroidOnBoardingStorage.kt
│               │               │   ├── AppSettingsStorage.kt
│               │               │   ├── BrowserBookmarksStorage.kt
│               │               │   └── HomePageStorage.kt
│               │               ├── ui/
│               │               │   ├── ABDownloadManagerApplicationContent.kt
│               │               │   ├── MainActivity.kt
│               │               │   ├── MainComponent.kt
│               │               │   ├── MainContent.kt
│               │               │   ├── SelectionControls.kt
│               │               │   ├── SheetUI.kt
│               │               │   ├── configurable/
│               │               │   │   ├── AndroidConfigurableUtils.kt
│               │               │   │   ├── ConfigurableSheet.kt
│               │               │   │   ├── SheetInput.kt
│               │               │   │   ├── SheetSpinner.kt
│               │               │   │   ├── android/
│               │               │   │   │   ├── AndroidConfigurableRenderers.kt
│               │               │   │   │   ├── item/
│               │               │   │   │   │   └── PermissionConfigurable.kt
│               │               │   │   │   └── renderer/
│               │               │   │   │       └── PermissionConfigurableRenderer.kt
│               │               │   │   └── comon/
│               │               │   │       ├── CommonConfigurableRenderersForAndroid.kt
│               │               │   │       ├── ConfigurableRenderersForAndroid.kt
│               │               │   │       └── renderer/
│               │               │   │           ├── BooleanConfigurableRenderer.kt
│               │               │   │           ├── DayOfWeekConfigurableRenderer.kt
│               │               │   │           ├── EnumConfigurableRenderer.kt
│               │               │   │           ├── FileChecksumConfigurableRenderer.kt
│               │               │   │           ├── FloatConfigurableRenderer.kt
│               │               │   │           ├── FolderConfigurableRenderer.kt
│               │               │   │           ├── IntConfigurableRenderer.kt
│               │               │   │           ├── LongConfigurableRenderer.kt
│               │               │   │           ├── NavigatableConfigurableRenderer.kt
│               │               │   │           ├── ProxyConfigurableRenderer.kt
│               │               │   │           ├── SpeedLimitConfigurableRenderer.kt
│               │               │   │           ├── StringConfigurableRenderer.kt
│               │               │   │           ├── ThemeConfigurableRenderer.kt
│               │               │   │           └── TimeConfigurableRenderer.kt
│               │               │   ├── menu/
│               │               │   │   ├── Menu.kt
│               │               │   │   ├── RenderMenuInSheet.kt
│               │               │   │   ├── RenderMenuInSinglePage.kt
│               │               │   │   └── StackedMenu.kt
│               │               │   ├── myCombinedClickable.kt
│               │               │   ├── page/
│               │               │   │   ├── PageUI.kt
│               │               │   │   └── PageUtils.kt
│               │               │   └── widget/
│               │               │       └── ComposeWebView.kt
│               │               └── util/
│               │                   ├── ABDMAppManager.kt
│               │                   ├── ABDMServiceNotificationManager.kt
│               │                   ├── AndroidConstants.kt
│               │                   ├── AndroidDefinedPaths.kt
│               │                   ├── AndroidDownloadItemOpener.kt
│               │                   ├── AndroidGlobalExceptionHandler.kt
│               │                   ├── AndroidIntentUtils.kt
│               │                   ├── AndroidUi.kt
│               │                   ├── AppInfo.kt
│               │                   ├── ApplicationBackgroundTracker.kt
│               │                   ├── HeadlessComposeRuntime.kt
│               │                   ├── activity/
│               │                   │   ├── ABDMActivity.kt
│               │                   │   ├── ActivityActions.kt
│               │                   │   ├── RetainedComponentContainer.kt
│               │                   │   └── SerializableExtra.kt
│               │                   ├── compose/
│               │                   │   ├── ObserveUiVisibility.kt
│               │                   │   └── useBack.kt
│               │                   ├── notification/
│               │                   │   └── playNotificationSoundIfAllowed.kt
│               │                   └── pagemanager/
│               │                       ├── BrowserPageManager.kt
│               │                       └── PermissionsPageManager.kt
│               └── res/
│                   ├── drawable/
│                   │   ├── ic_launcher_background.xml
│                   │   ├── ic_launcher_foreground.xml
│                   │   ├── ic_launcher_monochrome.xml
│                   │   └── ic_monochrome.xml
│                   ├── mipmap-anydpi-v26/
│                   │   ├── ic_launcher.xml
│                   │   └── ic_launcher_round.xml
│                   ├── values/
│                   │   ├── strings.xml
│                   │   └── theme.xml
│                   └── xml/
│                       └── provider_paths.xml
├── build.gradle.kts
├── buildSrc/
│   ├── build.gradle.kts
│   ├── settings.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               ├── Plugins.kt
│               ├── buildlogic/
│               │   ├── CiDirs.kt
│               │   ├── CiUtils.kt
│               │   ├── HashUtils.kt
│               │   └── versioning/
│               │       └── VersionUtil.kt
│               └── myPlugins/
│                   ├── composeAndroid.gradle.kts
│                   ├── composeBase.gradle.kts
│                   ├── composeDesktop.gradle.kts
│                   ├── kotlin.gradle.kts
│                   ├── kotlinAndroid.gradle.kts
│                   ├── kotlinMultiplatform.gradle.kts
│                   └── proguardDesktop.gradle.kts
├── compositeBuilds/
│   ├── plugins/
│   │   ├── common-android/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           ├── kotlin/
│   │   │           │   └── ir/
│   │   │           │       └── amirab/
│   │   │           │           └── plugin/
│   │   │           │               └── common_android/
│   │   │           │                   └── task/
│   │   │           │                       ├── EnableFileTypesGeneratorForManifest.kt
│   │   │           │                       ├── FileTypesIntentFilterGenerator.kt
│   │   │           │                       └── SignApkTask.kt
│   │   │           └── resources/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── plugin/
│   │   │                           └── common_android/
│   │   │                               └── AndroidManifest.xml.hbs
│   │   ├── git-version-plugin/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           └── kotlin/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── git_version/
│   │   │                           ├── GitVersionPlugin.kt
│   │   │                           └── core/
│   │   │                               ├── CiReferenceProvider.kt
│   │   │                               ├── GitStatus.kt
│   │   │                               ├── SemanticVersionSelector.kt
│   │   │                               ├── TagSelector.kt
│   │   │                               ├── Utils.kt
│   │   │                               └── extension.kt
│   │   ├── installer-plugin/
│   │   │   ├── build.gradle.kts
│   │   │   └── src/
│   │   │       └── main/
│   │   │           └── kotlin/
│   │   │               └── ir/
│   │   │                   └── amirab/
│   │   │                       └── installer/
│   │   │                           ├── InstallerPlugin.kt
│   │   │                           ├── InstallerTargetFormat.kt
│   │   │                           ├── extensiion/
│   │   │                           │   └── InstallerPluginExtension.kt
│   │   │                           ├── tasks/
│   │   │                           │   ├── macos/
│   │   │                           │   │   └── CreateDmgTask.kt
│   │   │                           │   └── windows/
│   │   │                           │       └── NsisTask.kt
│   │   │                           └── utils/
│   │   │                               └── Contants.kt
│   │   └── settings.gradle.kts
│   └── shared/
│       ├── README.md
│       ├── build.gradle.kts
│       ├── platform/
│       │   ├── build.gradle.kts
│       │   └── src/
│       │       └── commonMain/
│       │           └── kotlin/
│       │               └── ir/
│       │                   └── amirab/
│       │                       └── util/
│       │                           └── platform/
│       │                               ├── Arch.kt
│       │                               └── Platform.kt
│       └── settings.gradle.kts
├── crowdin.yml
├── desktop/
│   ├── app/
│   │   ├── build.gradle.kts
│   │   ├── gradle.properties
│   │   ├── icons/
│   │   │   └── icon.icns
│   │   ├── proguard/
│   │   │   ├── decompose.pro
│   │   │   ├── main.pro
│   │   │   └── okhttp.pro
│   │   ├── resources/
│   │   │   ├── common/
│   │   │   │   └── app.properties
│   │   │   └── installer/
│   │   │       └── nsis-script-template.nsi
│   │   └── src/
│   │       └── main/
│   │           ├── kotlin/
│   │           │   └── com/
│   │           │       └── abdownloadmanager/
│   │           │           └── desktop/
│   │           │               ├── App.kt
│   │           │               ├── AppArguments.kt
│   │           │               ├── AppComponent.kt
│   │           │               ├── SingleInstanceServerInitializer.kt
│   │           │               ├── actions/
│   │           │               │   ├── DesktopActionFactories.kt
│   │           │               │   ├── dev.kt
│   │           │               │   ├── main.kt
│   │           │               │   └── onevennts/
│   │           │               │       ├── CleanExtraSettingsOnDownloadFinish.kt
│   │           │               │       ├── getOnDownloadCompletionAction.kt
│   │           │               │       └── getOnQueueEventActions.kt
│   │           │               ├── di/
│   │           │               │   └── Di.kt
│   │           │               ├── integration/
│   │           │               │   └── IntegrationHandlerImp.kt
│   │           │               ├── pages/
│   │           │               │   ├── about/
│   │           │               │   │   ├── AboutDialog.kt
│   │           │               │   │   └── AboutPage.kt
│   │           │               │   ├── addDownload/
│   │           │               │   │   ├── ShowAddDownloadDialogs.kt
│   │           │               │   │   ├── multiple/
│   │           │               │   │   │   ├── AddMultiItemPage.kt
│   │           │               │   │   │   ├── AddMultiItemTable.kt
│   │           │               │   │   │   └── DesktopAddMultiDownloadComponent.kt
│   │           │               │   │   ├── shared/
│   │           │               │   │   │   ├── CategorySelect.kt
│   │           │               │   │   │   ├── DialogDropDown.kt
│   │           │               │   │   │   ├── ExtraConfig.kt
│   │           │               │   │   │   ├── LocationTextField.kt
│   │           │               │   │   │   └── SelectQueue.kt
│   │           │               │   │   └── single/
│   │           │               │   │       ├── AddDownloadPage.kt
│   │           │               │   │       └── DesktopAddSingleDownloadComponent.kt
│   │           │               │   ├── batchdownload/
│   │           │               │   │   ├── BatchDownloadWindow.kt
│   │           │               │   │   ├── BatchDownnload.kt
│   │           │               │   │   └── DesktopBatchDownloadComponent.kt
│   │           │               │   ├── category/
│   │           │               │   │   ├── DesktopCategoryDialogManager.kt
│   │           │               │   │   ├── NewCategoryPage.kt
│   │           │               │   │   └── ShowCategoryDialogs.kt
│   │           │               │   ├── checksum/
│   │           │               │   │   ├── DesktopFileChecksumComponent.kt
│   │           │               │   │   ├── FileChecksumPage.kt
│   │           │               │   │   └── FileChecksumWindow.kt
│   │           │               │   ├── confirmexit/
│   │           │               │   │   └── ConfirmExit.kt
│   │           │               │   ├── credits/
│   │           │               │   │   └── translators/
│   │           │               │   │       ├── TranslatorsPage.kt
│   │           │               │   │       ├── TranslatorsTable.kt
│   │           │               │   │       └── TranslatorsWindow.kt
│   │           │               │   ├── editdownload/
│   │           │               │   │   ├── DesktopEditDownloadComponent.kt
│   │           │               │   │   └── EditDownload.kt
│   │           │               │   ├── enterurl/
│   │           │               │   │   ├── DesktopEnterNewURLComponent.kt
│   │           │               │   │   ├── EnterNewDownloadWindow.kt
│   │           │               │   │   └── EnterNewURLPage.kt
│   │           │               │   ├── extenallibs/
│   │           │               │   │   ├── ExternalLibsPage.kt
│   │           │               │   │   ├── ExternalLibsWindow.kt
│   │           │               │   │   ├── LibraryDialog.kt
│   │           │               │   │   └── OpenSourceLibraryTable.kt
│   │           │               │   ├── home/
│   │           │               │   │   ├── Actions.kt
│   │           │               │   │   ├── DesktopDownloadActions.kt
│   │           │               │   │   ├── DownloadItemListDataFlavor.kt
│   │           │               │   │   ├── HomeComponent.kt
│   │           │               │   │   ├── HomePage.kt
│   │           │               │   │   ├── HomePersistedState.kt
│   │           │               │   │   ├── HomeWindow.kt
│   │           │               │   │   ├── dropDownloadItemsHere.kt
│   │           │               │   │   └── sections/
│   │           │               │   │       ├── DownloadList.kt
│   │           │               │   │       ├── Filters.kt
│   │           │               │   │       ├── TableDownloadItem.kt
│   │           │               │   │       ├── category/
│   │           │               │   │       │   └── Categories.kt
│   │           │               │   │       └── queue/
│   │           │               │   │           └── Queues.kt
│   │           │               │   ├── newQueue/
│   │           │               │   │   ├── NewQueueDialog.kt
│   │           │               │   │   └── NewQueuePage.kt
│   │           │               │   ├── perhostsettings/
│   │           │               │   │   ├── DesktopPerHostSettingsComponent.kt
│   │           │               │   │   ├── PerHostSettingsPage.kt
│   │           │               │   │   └── PerHostSettingsWindow.kt
│   │           │               │   ├── poweractionalert/
│   │           │               │   │   ├── PowerActionAlertWindow.kt
│   │           │               │   │   └── PowerActionComponent.kt
│   │           │               │   ├── queue/
│   │           │               │   │   ├── QueueInfoComponent.kt
│   │           │               │   │   ├── QueueWindow.kt
│   │           │               │   │   ├── QueuesComponent.kt
│   │           │               │   │   └── QueuesPage.kt
│   │           │               │   ├── settings/
│   │           │               │   │   ├── DesktopSettings.kt
│   │           │               │   │   ├── DesktopSettingsComponent.kt
│   │           │               │   │   ├── FontManager.kt
│   │           │               │   │   ├── SettingPageStateToPersist.kt
│   │           │               │   │   ├── SettingWindow.kt
│   │           │               │   │   └── SettingsPage.kt
│   │           │               │   ├── singleDownloadPage/
│   │           │               │   │   ├── CompletedDownloadPage.kt
│   │           │               │   │   ├── DesktopSingleDownloadPageComponent.kt
│   │           │               │   │   ├── ProgressDownloadPage.kt
│   │           │               │   │   ├── ShowDownloadDialogs.kt
│   │           │               │   │   └── SingleDownloadPageStateToPersist.kt
│   │           │               │   └── updater/
│   │           │               │       ├── NewUpdatePage.kt
│   │           │               │       └── UpdaterDialog.kt
│   │           │               ├── repository/
│   │           │               │   └── AppRepository.kt
│   │           │               ├── storage/
│   │           │               │   ├── AppSettingsStorage.kt
│   │           │               │   ├── DesktopDefinedPaths.kt
│   │           │               │   ├── DesktopExtraDownloadItemSettings.kt
│   │           │               │   ├── DesktopExtraQueueSettings.kt
│   │           │               │   └── PageStatesStorage.kt
│   │           │               ├── ui/
│   │           │               │   ├── Ui.kt
│   │           │               │   ├── configurable/
│   │           │               │   │   ├── DesktopConfigurableRendererUtils.kt
│   │           │               │   │   ├── comon/
│   │           │               │   │   │   ├── CommonConfigurableRenderersForDesktop.kt
│   │           │               │   │   │   └── renderer/
│   │           │               │   │   │       ├── BooleanConfigurableRenderer.kt
│   │           │               │   │   │       ├── DayOfWeekConfigurableRenderer.kt
│   │           │               │   │   │       ├── EnumConfigurableRenderer.kt
│   │           │               │   │   │       ├── FileChecksumConfigurableRenderer.kt
│   │           │               │   │   │       ├── FloatConfigurableRenderer.kt
│   │           │               │   │   │       ├── FolderConfigurableRenderer.kt
│   │           │               │   │   │       ├── IntConfigurableRenderer.kt
│   │           │               │   │   │       ├── LongConfigurableRenderer.kt
│   │           │               │   │   │       ├── PerHostSettingsConfigurableRenderer.kt
│   │           │               │   │   │       ├── ProxyConfigurableRenderer.kt
│   │           │               │   │   │       ├── SpeedLimitConfigurableRenderer.kt
│   │           │               │   │   │       ├── StringConfigurableRenderer.kt
│   │           │               │   │   │       ├── ThemeConfigurableRenderer.kt
│   │           │               │   │   │       └── TimeConfigurableRenderer.kt
│   │           │               │   │   └── platform/
│   │           │               │   │       ├── DesktopConfigurableRenderers.kt
│   │           │               │   │       ├── item/
│   │           │               │   │       │   └── FontConfigurable.kt
│   │           │               │   │       └── renderer/
│   │           │               │   │           └── FontConfigurableRenderer.kt
│   │           │               │   ├── error/
│   │           │               │   │   └── ErrorUi.kt
│   │           │               │   ├── util/
│   │           │               │   │   └── FilePickerUtils.kt
│   │           │               │   └── widget/
│   │           │               │       ├── ConfirmDialog.kt
│   │           │               │       ├── MessageDialogModel.kt
│   │           │               │       └── Tray.kt
│   │           │               └── utils/
│   │           │                   ├── AppInfo.kt
│   │           │                   ├── AppProperties.kt
│   │           │                   ├── DebugboardUtils.kt
│   │           │                   ├── DesktopEntryCreator.kt
│   │           │                   ├── DesktopShortcutManager.kt
│   │           │                   ├── GlobalAppExceptionHandler.kt
│   │           │                   ├── IntegrationUtil.kt
│   │           │                   ├── KeepAwakeManager.kt
│   │           │                   ├── OSFileIconProvider.kt
│   │           │                   ├── PortableUtil.kt
│   │           │                   ├── native_messaging/
│   │           │                   │   ├── NativeMessaging.kt
│   │           │                   │   └── NativeMessagingManifestApplier.kt
│   │           │                   ├── proxy/
│   │           │                   │   ├── AutoConfigurableProxyProviderForDesktop.kt
│   │           │                   │   ├── DesktopSystemProxySelectorProvider.kt
│   │           │                   │   └── ProxyCachingConfig.kt
│   │           │                   ├── renderapi/
│   │           │                   │   └── RenderApi.kt
│   │           │                   └── singleInstance/
│   │           │                       ├── Comunication.kt
│   │           │                       ├── MutableSingleInstanceServerHandler.kt
│   │           │                       ├── SingleAppInstanceLocker.kt
│   │           │                       ├── SingleInstanceServer.kt
│   │           │                       ├── SingleInstanceServerHandler.kt
│   │           │                       └── SingleInstanceUtil.kt
│   │           └── resources/
│   │               └── configs/
│   │                   └── app_default.properties
│   ├── app-utils/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               └── com/
│   │                   └── abdownloadmanager/
│   │                       └── desktop/
│   │                           └── window/
│   │                               ├── BrowserUtil.kt
│   │                               ├── custom/
│   │                               │   ├── CustomWindow.kt
│   │                               │   ├── DropDownTooltip.kt
│   │                               │   ├── OptionsDialog.kt
│   │                               │   ├── titlebar/
│   │                               │   │   ├── SystemButtonPositionProvider.kt
│   │                               │   │   ├── TitleBar.kt
│   │                               │   │   ├── TitleBarShared.kt
│   │                               │   │   ├── linux/
│   │                               │   │   │   ├── LinuxSystemButtonsProvider.kt
│   │                               │   │   │   ├── LinuxTitleBar.kt
│   │                               │   │   │   └── SystemButtons.Linux.kt
│   │                               │   │   ├── mac/
│   │                               │   │   │   ├── MacTitleBar.kt
│   │                               │   │   │   └── SystemButtons.MacOS.kt
│   │                               │   │   └── windows/
│   │                               │   │       ├── SystemButtons.Windows.kt
│   │                               │   │       └── WindowsTitleBar.kt
│   │                               │   └── utils.kt
│   │                               └── moveSafe.kt
│   ├── mac_utils/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       └── main/
│   │           └── kotlin/
│   │               └── ir/
│   │                   └── amirab/
│   │                       └── util/
│   │                           └── desktop/
│   │                               └── mac/
│   │                                   └── event/
│   │                                       └── MacEventHandler.kt
│   └── shared/
│       ├── build.gradle.kts
│       └── src/
│           └── main/
│               └── kotlin/
│                   └── ir/
│                       └── amirab/
│                           └── util/
│                               └── desktop/
│                                   ├── DesktopUtils.kt
│                                   ├── GlobalKeyboardModifiers.kt
│                                   ├── OsUtils.kt
│                                   ├── PlatformAppActivator.kt
│                                   ├── PlatformDockToggler.kt
│                                   ├── WindowsRegistry.kt
│                                   ├── activator/
│                                   │   └── mac/
│                                   │       └── MacAppActivator.kt
│                                   ├── dock/
│                                   │   └── mac/
│                                   │       └── MacDockToggler.kt
│                                   ├── keepawake/
│                                   │   ├── KeepAwake.kt
│                                   │   ├── MacKeepAwake.kt
│                                   │   └── WindowsKeepAwake.kt
│                                   ├── poweraction/
│                                   │   ├── PowerAction.kt
│                                   │   ├── PowerActionConfig.kt
│                                   │   ├── PowerActionLinux.kt
│                                   │   ├── PowerActionMac.kt
│                                   │   └── PowerActionWindows.kt
│                                   ├── screen/
│                                   │   └── DesktopScreen.kt
│                                   └── utils/
│                                       ├── linux/
│                                       │   └── LinuxUtils.kt
│                                       ├── mac/
│                                       │   ├── FoundationLibrary.kt
│                                       │   └── MacOSUtils.kt
│                                       └── windows/
│                                           └── WindowsUtils.kt
├── downloader/
│   ├── core/
│   │   ├── build.gradle.kts
│   │   └── src/
│   │       ├── androidMain/
│   │       │   └── kotlin/
│   │       │       └── ir/
│   │       │           └── amirab/
│   │       │               └── downloader/
│   │       │                   └── utils/
│   │       │                       └── SparseFile.android.kt
│   │       ├── commonMain/
│   │       │   └── kotlin/
│   │       │       └── ir/
│   │       │           └── amirab/
│   │       │               └── downloader/
│   │       │                   ├── DownloadManager.kt
│   │       │                   ├── DownloadManagerMinimalControl.kt
│   │       │                   ├── DownloadSettings.kt
│   │       │                   ├── Downloader.kt
│   │       │                   ├── DownloaderRegistry.kt
│   │       │                   ├── NewDownloadItemProps.kt
│   │       │                   ├── anntation/
│   │       │                   │   └── Markers.kt
│   │       │                   ├── connection/
│   │       │                   │   ├── Connection.kt
│   │       │                   │   ├── HttpDownloaderClient.kt
│   │       │                   │   ├── IResponseInfo.kt
│   │       │                   │   ├── OkHttpHttpDownloaderClient.kt
│   │       │                   │   ├── UserAgent.kt
│   │       │                   │   ├── UserAgentProvider.kt
│   │       │                   │   ├── proxy/
│   │       │                   │   │   ├── AutoConfigurableProxyProvider.kt
│   │       │                   │   │   ├── Proxy.kt
│   │       │                   │   │   ├── ProxyStrategy.kt
│   │       │                   │   │   ├── ProxyStrategyProvider.kt
│   │       │                   │   │   ├── ProxyType.kt
│   │       │                   │   │   └── SystemProxySelectorProvider.kt
│   │       │                   │   └── response/
│   │       │                   │       ├── HttpResponseInfo.kt
│   │       │                   │       └── headers/
│   │       │                   │           ├── RangeHeaderExtractor.kt
│   │       │                   │           └── fileNameExtractor.kt
│   │       │                   ├── db/
│   │       │                   │   ├── DownloadListFileStorage.kt
│   │       │                   │   ├── DownloadQueuePersistedDataAccess.kt
│   │       │                   │   ├── IDownloadListDb.kt
│   │       │                   │   ├── IDownloadPartListDb.kt
│   │       │                   │   ├── MemoryDownloadListDB.kt
│   │       │                   │   ├── MemoryDownloadPartStatesDB.kt
│   │       │                   │   ├── PartListFileStorage.kt
│   │       │                   │   ├── QueueFileStorage.kt
│   │       │                   │   └── TransactionalFileSaver.kt
│   │       │                   ├── destination/
│   │       │                   │   ├── DestWriter.kt
│   │       │                   │   ├── DownloadDestination.kt
│   │       │                   │   ├── IncompleteFileUtil.kt
│   │       │                   │   ├── SegmentedDownloadDestination.kt
│   │       │                   │   └── SimpleDownloadDestination.kt
│   │       │                   ├── downloaditem/
│   │       │                   │   ├── DownloadItemContext.kt
│   │       │                   │   ├── DownloadJob.kt
│   │       │                   │   ├── DownloadJobExtraConfig.kt
│   │       │                   │   ├── DownloadJobStatus.kt
│   │       │                   │   ├── DownloadStatus.kt
│   │       │                   │   ├── IDownloadCredentials.kt
│   │       │                   │   ├── IDownloadItem.kt
│   │       │                   │   ├── contexts/
│   │       │                   │   │   └── DefaultContexts.kt
│   │       │                   │   ├── hls/
│   │       │                   │   │   ├── HLSDownloadCredentials.kt
│   │       │                   │   │   ├── HLSDownloadItem.kt
│   │       │                   │   │   ├── HLSDownloadJob.kt
│   │       │                   │   │   ├── HLSDownloadJobExtraConfig.kt
│   │       │                   │   │   ├── HLSDownloader.kt
│   │       │                   │   │   ├── HLSPartDownloader.kt
│   │       │                   │   │   ├── HLSResponseInfo.kt
│   │       │                   │   │   └── IHLSCredentials.kt
│   │       │                   │   └── http/
│   │       │                   │       ├── HttpDownloadCredentials.kt
│   │       │                   │       ├── HttpDownloadItem.kt
│   │       │                   │       ├── HttpDownloadJob.kt
│   │       │                   │       ├── HttpDownloader.kt
│   │       │                   │       └── IHttpBasedDownloadCredentials.kt
│   │       │                   ├── exception/
│   │       │                   │   ├── DownloadNotSuccessFullException.kt
│   │       │                   │   ├── DownloadValidationException.kt
│   │       │                   │   ├── FileChangedException.kt
│   │       │                   │   ├── NoSpaceInStorageException.kt
│   │       │                   │   ├── PartTooManyErrorException.kt
│   │       │                   │   ├── PrepareDestinationFailedException.kt
│   │       │                   │   ├── ServerPartIsNotTheSameAsWeExpectException.kt
│   │       │                   │   ├── ServerResumeSupportChangeException.kt
│   │       │                   │   └── TooManyErrorException.kt
│   │       │                   ├── part/
│   │       │                   │   ├── DownloadPart.kt
│   │       │                   │   ├── HttpPartDownloader.kt
│   │       │                   │   ├── MediaSegment.kt
│   │       │                   │   ├── PartDownloadStatus.kt
│   │       │                   │   ├── PartDownloader.kt
│   │       │                   │   ├── PartSplitSupport.kt
│   │       │                   │   ├── Parts.kt
│   │       │                   │   └── RangedPart.kt
│   │       │                   ├── queue/
│   │       │                   │   ├── DownloadQueue.kt
│   │       │                   │   ├── ManualDownloadQueue.kt
│   │       │                   │   ├── QueueEvent.kt
│   │       │                   │   ├── QueueManager.kt
│   │       │                   │   └── ScheduleTimes.kt
│   │       │                   └── utils/
│   │       │                       ├── CallAwait.kt
│   │       │                       ├── CollectionUtils.kt
│   │       │                       ├── DuplicateFilter.kt
│   │       │                       ├── EmptyFileCreator.kt
│   │       │                       ├── ExceptionUtils.kt
│   │       │                       ├── FileNameUtil.kt
│   │       │                       ├── FlowUtils.kt
│   │       │                       ├── IDistStat.kt
│   │       │                       ├── LockList.kt
│   │       │                       ├── Logger.kt
│   │       │                       ├── NumUtil.kt
│   │       │                       ├── OnDuplicateStrategy.kt
│   │       │                       ├── SparseFile.kt
│   │       │                       ├── SplitToRange.kt
│   │       │                       └── TimeUtils.kt
│   │       └── desktopMain/
│   │           └── kotlin/
│   │               └── ir/
│   │                   └── amirab/
│   │                       └── downloader/
│   │                           └── utils/
│   │                               └── SparseFile.desktop.kt
│   └── monitor/
│       ├── build.gradle.kts
│       └── src/
│           └── commonMain/
│               └── kotlin/
│                   └── ir/
│                       └── amirab/
│                           └── downloader/
│                               └── monitor/
│                                   ├── CompletedDownloadItemState.kt
│                                   ├── DownloadItemStateFactory.kt
│                                   ├── DownloadMonitor.kt
│                                   ├── DownloadStateUtil.kt
│                                   ├── IDownloadItemState.kt
│                                   ├── IDownloadMonitor.kt
│                                   ├── ProcessingDownloadItemState.kt
│                                   └── UiPart.kt
├── gradle/
│   ├── libs.versions.toml
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── integration/
│   └── server/
│       ├── build.gradle.kts
│       └── src/
│           └── main/
│               ├── kotlin/
│               │   └── com/
│               │       └── abdownloadmanager/
│               │           └── integration/
│               │               ├── ApiQueueModel.kt
│               │               ├── DownloadCredentialsFromIntegration.kt
│               │               ├── Integration.kt
│               │               ├── IntegrationHandler.kt
│               │               ├── MyRequestAndResponse.kt
│               │               ├── MyServer.kt
│               │               ├── MySunHttpServer.kt
│               │               ├── NewDownloadTask.kt
│               │               └── http4k/
│               │                   └── MyHttp4KServer.kt
│               └── resources/
│                   ├── logback.xml
│                   └── rules.pro
├── scripts/
│   ├── install.sh
│   └── uninstall.sh
├── settings.gradle.kts
└── shared/
    ├── app/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               └── shared/
    │       │                   ├── ui/
    │       │                   │   ├── modifier/
    │       │                   │   │   └── PointerHoverIcon.android.kt
    │       │                   │   ├── theme/
    │       │                   │   │   └── PlatformThemeDefinitions.android.kt
    │       │                   │   └── widget/
    │       │                   │       ├── Tooltip.android.kt
    │       │                   │       └── menu/
    │       │                   │           └── custom/
    │       │                   │               ├── Option.android.kt
    │       │                   │               └── WithContextMenu.android.kt
    │       │                   └── util/
    │       │                       ├── ClipboardUtil.android.kt
    │       │                       ├── DesktopDiskStat.android.kt
    │       │                       ├── PlatformThemeDetector.android.kt
    │       │                       ├── downloadlocation/
    │       │                       │   └── PlatformDownloadLocationProvider.android.kt
    │       │                       └── ui/
    │       │                           └── widget/
    │       │                               └── MPBackHandler.android.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               └── shared/
    │       │                   ├── action/
    │       │                   │   ├── CommonActionFactories.kt
    │       │                   │   └── DevActionFactories.kt
    │       │                   ├── downloaderinui/
    │       │                   │   ├── BasicDownloadItem.kt
    │       │                   │   ├── CredentialAndItemMapper.kt
    │       │                   │   ├── DownloadSize.kt
    │       │                   │   ├── DownloadUiChecker.kt
    │       │                   │   ├── DownloaderInUi.kt
    │       │                   │   ├── DownloaderInUiRegistry.kt
    │       │                   │   ├── LinkChecker.kt
    │       │                   │   ├── LinkCheckerFactory.kt
    │       │                   │   ├── add/
    │       │                   │   │   ├── AddDownloadChecker.kt
    │       │                   │   │   ├── CanAddResult.kt
    │       │                   │   │   ├── NewDownloadInputs.kt
    │       │                   │   │   └── NewDownloadInputsFactory.kt
    │       │                   │   ├── edit/
    │       │                   │   │   ├── CanEditDownloadResult.kt
    │       │                   │   │   ├── CanEditWarnings.kt
    │       │                   │   │   ├── DownloadConflictDetector.kt
    │       │                   │   │   ├── EditDownloadCheckerFactory.kt
    │       │                   │   │   ├── EditDownloadInputs.kt
    │       │                   │   │   └── EditDownloadInputsFactory.kt
    │       │                   │   ├── hls/
    │       │                   │   │   ├── HLSDownloaderInUi.kt
    │       │                   │   │   ├── HLSLinkChecker.kt
    │       │                   │   │   ├── HlsItemToCredentialMapper.kt
    │       │                   │   │   ├── UiProcessingItemForHSLFactory.kt
    │       │                   │   │   ├── add/
    │       │                   │   │   │   ├── HLSDownloadUIChecker.kt
    │       │                   │   │   │   └── HLSNewDownloadInputs.kt
    │       │                   │   │   └── edit/
    │       │                   │   │       ├── HLSEditDownloadChecker.kt
    │       │                   │   │       └── HLSEditDownloadInputs.kt
    │       │                   │   └── http/
    │       │                   │       ├── HttpCredentialsToItemMapper.kt
    │       │                   │       ├── HttpDownloaderInUi.kt
    │       │                   │       ├── add/
    │       │                   │       │   ├── HttpDownloadUiChecker.kt
    │       │                   │       │   ├── HttpLinkChecker.kt
    │       │                   │       │   └── HttpNewDownloadInputs.kt
    │       │                   │       ├── applyHostSettingsToExtraConfig.kt
    │       │                   │       └── edit/
    │       │                   │           ├── HttpEditDownloadChecker.kt
    │       │                   │           └── HttpEditDownloadInputs.kt
    │       │                   ├── pagemanager/
    │       │                   │   ├── AboutPageManager.kt
    │       │                   │   ├── AddDownloadDialogManager.kt
    │       │                   │   ├── BatchDownloadPageManager.kt
    │       │                   │   ├── CategoryDialogManager.kt
    │       │                   │   ├── DownloadDialogManager.kt
    │       │                   │   ├── EditDownloadDialogManager.kt
    │       │                   │   ├── EnterNewURLDialogManager.kt
    │       │                   │   ├── ExitApplicationRequestManager.kt
    │       │                   │   ├── FileChecksumDialogManager.kt
    │       │                   │   ├── NotificationSender.kt
    │       │                   │   ├── OpenSourceLibrariesPageManager.kt
    │       │                   │   ├── PerHostSettingsPageManager.kt
    │       │                   │   ├── QueuePageManager.kt
    │       │                   │   ├── SettingsPageManager.kt
    │       │                   │   └── TranslatorsPageManager.kt
    │       │                   ├── pages/
    │       │                   │   ├── adddownload/
    │       │                   │   │   ├── AddDownloadComponent.kt
    │       │                   │   │   ├── AddDownloadConfig.kt
    │       │                   │   │   ├── AddDownloadCredentialsInUiProps.kt
    │       │                   │   │   ├── ImportOptions.kt
    │       │                   │   │   ├── multiple/
    │       │                   │   │   │   ├── BaseAddMultiDownloadComponent.kt
    │       │                   │   │   │   └── OnRequestAdd.kt
    │       │                   │   │   └── single/
    │       │                   │   │       └── BaseAddSingleDownloadComponent.kt
    │       │                   │   ├── batchdownload/
    │       │                   │   │   └── BaseBatchDownloadComponent.kt
    │       │                   │   ├── category/
    │       │                   │   │   └── CategoryComponent.kt
    │       │                   │   ├── checksum/
    │       │                   │   │   └── BaseFileChecksumComponent.kt
    │       │                   │   ├── credits/
    │       │                   │   │   └── translators/
    │       │                   │   │       └── LanguageTranslationInfo.kt
    │       │                   │   ├── editdownload/
    │       │                   │   │   └── BaseEditDownloadComponent.kt
    │       │                   │   ├── enterurl/
    │       │                   │   │   ├── BaseEnterNewURLComponent.kt
    │       │                   │   │   └── DownloaderSelection.kt
    │       │                   │   ├── home/
    │       │                   │   │   ├── AbstractDownloadActions.kt
    │       │                   │   │   ├── BaseHomeComponent.kt
    │       │                   │   │   ├── CategoryActions.kt
    │       │                   │   │   ├── FilterState.kt
    │       │                   │   │   ├── PromptStates.kt
    │       │                   │   │   ├── category/
    │       │                   │   │   │   ├── DefinedStatusCategories.kt
    │       │                   │   │   │   ├── DownloadStatusCategoryFilter.kt
    │       │                   │   │   │   └── DownloadStatusCategoryFilterByList.kt
    │       │                   │   │   └── queue/
    │       │                   │   │       └── QueueActions.kt
    │       │                   │   ├── perhostsettings/
    │       │                   │   │   └── PerHostSettingsComponent.kt
    │       │                   │   └── updater/
    │       │                   │       ├── RenderUpdateNotifications.kt
    │       │                   │       └── UpdateComponent.kt
    │       │                   ├── repository/
    │       │                   │   └── BaseAppRepository.kt
    │       │                   ├── settings/
    │       │                   │   ├── BaseSettingsComponent.kt
    │       │                   │   └── CommonSettings.kt
    │       │                   ├── singledownloadpage/
    │       │                   │   ├── BaseSingleDownloadComponent.kt
    │       │                   │   ├── DownloadStatusStringSource.kt
    │       │                   │   └── SingleDownloadPagePropertyItem.kt
    │       │                   ├── storage/
    │       │                   │   ├── BaseAppSettingsStorage.kt
    │       │                   │   ├── ExtraDownloadSettingsStorage.kt
    │       │                   │   ├── ExtraQueueSettingsStorage.kt
    │       │                   │   ├── IExtraDownloadSettingsStorage.kt
    │       │                   │   ├── IExtraQueueSettingsStorage.kt
    │       │                   │   ├── ILastSavedLocationsStorage.kt
    │       │                   │   ├── PerHostSettingsDatastoreStorage.kt
    │       │                   │   ├── ProxyDatastoreStorage.kt
    │       │                   │   ├── SupportedSizeUnits.kt
    │       │                   │   └── impl/
    │       │                   │       └── LastSavedLocationStorage.kt
    │       │                   ├── ui/
    │       │                   │   ├── Bootstrap.kt
    │       │                   │   ├── configurable/
    │       │                   │   │   ├── BaseEnumConfigurable.kt
    │       │                   │   │   ├── BaseLongConfigurable.kt
    │       │                   │   │   ├── CommonConfigurableRenderers.kt
    │       │                   │   │   ├── Configurable.kt
    │       │                   │   │   ├── ConfigurableGroup.kt
    │       │                   │   │   ├── ConfigurableRendererRegistry.kt
    │       │                   │   │   ├── RenderConfigurable.kt
    │       │                   │   │   ├── RenderConfigurableGroup.kt
    │       │                   │   │   ├── Shared.kt
    │       │                   │   │   └── item/
    │       │                   │   │       ├── BooleanConfigurable.kt
    │       │                   │   │       ├── DayOfWeekConfigurable.kt
    │       │                   │   │       ├── EnumConfigurable.kt
    │       │                   │   │       ├── FileChecksumConfigurable.kt
    │       │                   │   │       ├── FloatConfigurable.kt
    │       │                   │   │       ├── FolderConfigurable.kt
    │       │                   │   │       ├── IntConfigurable.kt
    │       │                   │   │       ├── LongConfigurable.kt
    │       │                   │   │       ├── NavigatableConfigurable.kt
    │       │                   │   │       ├── ProxyConfigurable.kt
    │       │                   │   │       ├── SpeedLimitConfigurable.kt
    │       │                   │   │       ├── StringConfigurable.kt
    │       │                   │   │       ├── ThemeConfigurable.kt
    │       │                   │   │       └── TimeConfigurable.kt
    │       │                   │   ├── modifier/
    │       │                   │   │   └── PointerHoverIcon.kt
    │       │                   │   ├── theme/
    │       │                   │   │   ├── ABDownloaderTheme.kt
    │       │                   │   │   ├── DefaultThemes.kt
    │       │                   │   │   ├── Markdown.kt
    │       │                   │   │   ├── PlatformThemeDefinitions.kt
    │       │                   │   │   ├── ThemeManager.kt
    │       │                   │   │   └── ThemeSettingsStorage.kt
    │       │                   │   └── widget/
    │       │                   │       ├── ActionButton.kt
    │       │                   │       ├── ActionContainer.kt
    │       │                   │       ├── AddUrlButton.kt
    │       │                   │       ├── CheckBox.kt
    │       │                   │       ├── DashedBorder.kt
    │       │                   │       ├── ExpandableItem.kt
    │       │                   │       ├── Handle.kt
    │       │                   │       ├── Help.kt
    │       │                   │       ├── IconPick.kt
    │       │                   │       ├── Language.kt
    │       │                   │       ├── LinkText.kt
    │       │                   │       ├── LoadingIndicator.kt
    │       │                   │       ├── MainActionButton.kt
    │       │                   │       ├── MessageDialogType.kt
    │       │                   │       ├── Multiselect.kt
    │       │                   │       ├── MyIconButton.kt
    │       │                   │       ├── MyTextField.kt
    │       │                   │       ├── MyTextFieldWithIcons.kt
    │       │                   │       ├── NavigateableItem.kt
    │       │                   │       ├── Notification.kt
    │       │                   │       ├── NumberTextField.kt
    │       │                   │       ├── Popup.kt
    │       │                   │       ├── RadioButton.kt
    │       │                   │       ├── Switch.kt
    │       │                   │       ├── Tabs.kt
    │       │                   │       ├── Text.kt
    │       │                   │       ├── Tooltip.kt
    │       │                   │       ├── menu/
    │       │                   │       │   └── custom/
    │       │                   │       │       ├── DropDown.kt
    │       │                   │       │       ├── MenuColumn.kt
    │       │                   │       │       ├── Option.kt
    │       │                   │       │       ├── SiblingMenuPositionProvider.kt
    │       │                   │       │       ├── SubMenu.kt
    │       │                   │       │       └── WithContextMenu.kt
    │       │                   │       └── sort/
    │       │                   │           ├── ComparatorProvider.kt
    │       │                   │           ├── Sort.kt
    │       │                   │           ├── SortIndicatorMode.kt
    │       │                   │           └── sorted.kt
    │       │                   ├── updater/
    │       │                   │   └── UpdateDownloaderViaDownloadSystem.kt
    │       │                   └── util/
    │       │                       ├── AppHostNameVerifier.kt
    │       │                       ├── AppSSLFactoryProvider.kt
    │       │                       ├── AppVersion.kt
    │       │                       ├── AutoStartManager.kt
    │       │                       ├── BaseComponent.kt
    │       │                       ├── BaseConstants.kt
    │       │                       ├── BaseSettings.kt
    │       │                       ├── BottomSheet.kt
    │       │                       ├── BrowserIntegrationModel.kt
    │       │                       ├── ClipboardUtil.kt
    │       │                       ├── ColorUtils.kt
    │       │                       ├── ContainsShortcuts.kt
    │       │                       ├── CoroutineUtils.kt
    │       │                       ├── DefinedPaths.kt
    │       │                       ├── DesktopDiskStat.kt
    │       │                       ├── DownloadFoldersRegistry.kt
    │       │                       ├── DownloadItemOpener.kt
    │       │                       ├── DownloadSystem.kt
    │       │                       ├── DurationUtil.kt
    │       │                       ├── ExceptionToString.kt
    │       │                       ├── FileIconProvider.kt
    │       │                       ├── FilenameFixer.kt
    │       │                       ├── HashUtil.kt
    │       │                       ├── IPUtils.kt
    │       │                       ├── InstanceCheckUtils.kt
    │       │                       ├── LimitationsInUI.kt
    │       │                       ├── Platform.kt
    │       │                       ├── PlatformKeyStroke.kt
    │       │                       ├── PlatformThemeDetector.kt
    │       │                       ├── PopUpContainer.kt
    │       │                       ├── RememberDotLoading.kt
    │       │                       ├── Responsive.kt
    │       │                       ├── SharedConstants.kt
    │       │                       ├── ShortcutManager.kt
    │       │                       ├── ShouldValidate.kt
    │       │                       ├── SizeAndSpeedUnitProvider.kt
    │       │                       ├── SizeUtil.kt
    │       │                       ├── StateUtils.kt
    │       │                       ├── StringUtils.kt
    │       │                       ├── SystemDownloadLocationProvider.kt
    │       │                       ├── TimeUtil.kt
    │       │                       ├── UiConstants.kt
    │       │                       ├── UserAgentProviderFromSettings.kt
    │       │                       ├── ValueUtils.kt
    │       │                       ├── appinfo/
    │       │                       │   └── PreviousVersion.kt
    │       │                       ├── autoremove/
    │       │                       │   └── RemovedDownloadsFromDiskTracker.kt
    │       │                       ├── category/
    │       │                       │   ├── Category.kt
    │       │                       │   ├── CategoryFileStorage.kt
    │       │                       │   ├── CategoryItem.kt
    │       │                       │   ├── CategoryManager.kt
    │       │                       │   ├── CategoryManagerExtensions.kt
    │       │                       │   ├── CategorySelectionMode.kt
    │       │                       │   ├── CategoryStorage.kt
    │       │                       │   ├── DefaultCategories.kt
    │       │                       │   ├── DownloadManagerCategoryItemProvider.kt
    │       │                       │   ├── ICategoryItemProvider.kt
    │       │                       │   └── InMemoryCategoryStorage.kt
    │       │                       ├── downloadlocation/
    │       │                       │   └── PlatformDownloadLocationProvider.kt
    │       │                       ├── extractors/
    │       │                       │   ├── Extractor.kt
    │       │                       │   └── linkextractor/
    │       │                       │       ├── DownloadCredentialExtractor.kt
    │       │                       │       ├── DownloadCredentialsFromCurl.kt
    │       │                       │       └── URLExtractors.kt
    │       │                       ├── mvi/
    │       │                       │   ├── ContainsEffects.kt
    │       │                       │   ├── ContainsScreenState.kt
    │       │                       │   └── EventHandler.kt
    │       │                       ├── ondownloadcompletion/
    │       │                       │   ├── OnDownloadCompletionAction.kt
    │       │                       │   ├── OnDownloadCompletionActionProvider.kt
    │       │                       │   └── OnDownloadCompletionActionRunner.kt
    │       │                       ├── onqueuecompletion/
    │       │                       │   ├── OnQueueCompletionActionProvider.kt
    │       │                       │   ├── OnQueueEventAction.kt
    │       │                       │   └── OnQueueEventActionRunner.kt
    │       │                       ├── perhostsettings/
    │       │                       │   ├── PerHostSettingsItem.kt
    │       │                       │   ├── PerHostSettingsManager.kt
    │       │                       │   └── PerHostSettingsStorage.kt
    │       │                       ├── proxy/
    │       │                       │   ├── IProxyStorage.kt
    │       │                       │   ├── Proxy.kt
    │       │                       │   └── ProxyManager.kt
    │       │                       └── ui/
    │       │                           ├── BaseMyColors.kt
    │       │                           ├── IMyIcons.kt
    │       │                           ├── LocalIsDebugMode.kt
    │       │                           ├── LocalProviders.kt
    │       │                           ├── LocalTitleBarDirection.kt
    │       │                           ├── MyColors.kt
    │       │                           ├── ScrollbableContent.kt
    │       │                           ├── Scrollbar.kt
    │       │                           ├── icon/
    │       │                           │   └── MyIcons.kt
    │       │                           ├── theme/
    │       │                           │   ├── ISystemThemeDetector.kt
    │       │                           │   ├── MaterialRipple.kt
    │       │                           │   ├── MyShapes.kt
    │       │                           │   └── Sizing.kt
    │       │                           └── widget/
    │       │                               ├── Icon.kt
    │       │                               ├── MPBackHandler.kt
    │       │                               ├── ScreenSurface.kt
    │       │                               └── ScrolFade.kt
    │       └── desktopMain/
    │           └── kotlin/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── shared/
    │                           ├── ui/
    │                           │   ├── modifier/
    │                           │   │   └── PointerHoverIcon.desktop.kt
    │                           │   ├── theme/
    │                           │   │   ├── MyContextMenuRepresentation.kt
    │                           │   │   └── PlatformThemeDefinitions.desktop.kt
    │                           │   ├── util/
    │                           │   │   └── LocalWindow.desktop.kt
    │                           │   └── widget/
    │                           │       ├── Tooltip.desktop.kt
    │                           │       ├── menu/
    │                           │       │   ├── custom/
    │                           │       │   │   ├── MenuBar.kt
    │                           │       │   │   ├── Option.desktop.kt
    │                           │       │   │   └── WithContextMenu.desktop.kt
    │                           │       │   └── native/
    │                           │       │       └── NativeMenuBar.kt
    │                           │       └── table/
    │                           │           └── customtable/
    │                           │               ├── CellPadding.kt
    │                           │               ├── Table.kt
    │                           │               ├── TableUtils.kt
    │                           │               └── styled/
    │                           │                   └── MyStyledHeader.kt
    │                           └── util/
    │                               ├── ClipboardUtil.desktop.kt
    │                               ├── DesktopDiskStat.desktop.kt
    │                               ├── PlatformThemeDetector.desktop.kt
    │                               ├── downloadlocation/
    │                               │   ├── DesktopDownloadLocationProvider.kt
    │                               │   ├── LinuxDownloadLocationProvider.kt
    │                               │   ├── MacDownloadLocationProvider.kt
    │                               │   ├── PlatformDownloadLocationProvider.desktop.kt
    │                               │   └── WindowsDownloadLocationProvider.kt
    │                               └── ui/
    │                                   └── widget/
    │                                       └── MPBackHandler.desktop.kt
    ├── auto-start/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       └── ir/
    │       │           └── amirab/
    │       │               └── util/
    │       │                   └── startup/
    │       │                       ├── AndroidStartupManager.kt
    │       │                       └── Startup.android.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── ir/
    │       │           └── amirab/
    │       │               └── util/
    │       │                   └── startup/
    │       │                       ├── AbstractStartupManager.kt
    │       │                       └── Startup.kt
    │       └── desktopMain/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── startup/
    │                               ├── AbstractDesktopStartupManager.kt
    │                               ├── HeadlessStartupDesktop.kt
    │                               ├── MacOSStartupDesktop.kt
    │                               ├── Startup.kt
    │                               ├── UnixXDGStartupDesktop.kt
    │                               ├── Utils.kt
    │                               └── WindowsStartupDesktop.kt
    ├── compose-utils/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── commonMain/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── compose/
    │                               ├── Helpers.kt
    │                               ├── IIconResolver.kt
    │                               ├── IconSource.kt
    │                               ├── StringSource.kt
    │                               ├── action/
    │                               │   ├── AnAction.kt
    │                               │   ├── Extensions.kt
    │                               │   ├── MenuDsl.kt
    │                               │   └── MenuItem.kt
    │                               ├── contants/
    │                               │   └── Constants.kt
    │                               ├── layout/
    │                               │   └── RelativeAlignment.kt
    │                               ├── localizationmanager/
    │                               │   ├── ILanguageNameProvider.kt
    │                               │   ├── LanguageManager.kt
    │                               │   ├── LanguageSourceProvider.kt
    │                               │   ├── LanguageStorage.kt
    │                               │   ├── LocalLanguageManager.kt
    │                               │   ├── MyLocale.kt
    │                               │   └── StringVariableReplacer.kt
    │                               ├── modifiers/
    │                               │   ├── AutoMirror.kt
    │                               │   └── Clickables.kt
    │                               └── resources/
    │                                   └── Resources.kt
    ├── config/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── main/
    │           └── kotlin/
    │               └── ir/
    │                   └── amirab/
    │                       └── util/
    │                           └── config/
    │                               ├── Config.kt
    │                               ├── ConfigKeyWithPrimitiveType.kt
    │                               ├── ConfigToJson.kt
    │                               ├── JsonMapper.kt
    │                               ├── NestedCreator.kt
    │                               ├── datastore/
    │                               │   ├── KotlinSerializationDataStore.kt
    │                               │   └── MapConfigDataStore.kt
    │                               └── extensions.kt
    ├── nanohttp4k/
    │   ├── build.gradle.kts
    │   └── src/
    │       └── main/
    │           ├── kotlin/
    │           │   └── ir/
    │           │       └── amirab/
    │           │           └── util/
    │           │               └── http4k/
    │           │                   └── NanoHttpServer.kt
    │           └── resources/
    │               └── rules.pro
    ├── resources/
    │   ├── build.gradle.kts
    │   ├── contracts/
    │   │   ├── build.gradle.kts
    │   │   └── src/
    │   │       └── commonMain/
    │   │           └── kotlin/
    │   │               └── ir/
    │   │                   └── amirab/
    │   │                       └── resources/
    │   │                           └── contracts/
    │   │                               ├── MyLanguageResource.kt
    │   │                               └── MyStringResource.kt
    │   └── src/
    │       └── commonMain/
    │           ├── kotlin/
    │           │   └── com/
    │           │       └── abdownloadmanager/
    │           │           └── resources/
    │           │               ├── ABDMLanguageResources.kt
    │           │               └── icons/
    │           │                   ├── ABDMIcons.kt
    │           │                   ├── AddLink.kt
    │           │                   ├── Alphabet.kt
    │           │                   ├── AppIcon.kt
    │           │                   ├── Back.kt
    │           │                   ├── BrowserGoogleChrome.kt
    │           │                   ├── BrowserMicrosoftEdge.kt
    │           │                   ├── BrowserMozillaFirefox.kt
    │           │                   ├── BrowserOpera.kt
    │           │                   ├── Check.kt
    │           │                   ├── Clear.kt
    │           │                   ├── Clipboard.kt
    │           │                   ├── Clock.kt
    │           │                   ├── Colors.kt
    │           │                   ├── Copy.kt
    │           │                   ├── Data.kt
    │           │                   ├── Delete.kt
    │           │                   ├── Down.kt
    │           │                   ├── DownSpeed.kt
    │           │                   ├── DragAndDrop.kt
    │           │                   ├── Earth.kt
    │           │                   ├── Edit.kt
    │           │                   ├── Exit.kt
    │           │                   ├── ExternalLink.kt
    │           │                   ├── Fast.kt
    │           │                   ├── File.kt
    │           │                   ├── FileApplication.kt
    │           │                   ├── FileDocument.kt
    │           │                   ├── FileMusic.kt
    │           │                   ├── FilePicture.kt
    │           │                   ├── FileUnknown.kt
    │           │                   ├── FileVideo.kt
    │           │                   ├── FileZip.kt
    │           │                   ├── Flag.kt
    │           │                   ├── Folder.kt
    │           │                   ├── FolderFinished.kt
    │           │                   ├── FolderUnfinished.kt
    │           │                   ├── Grip.kt
    │           │                   ├── Group.kt
    │           │                   ├── Hearth.kt
    │           │                   ├── Info.kt
    │           │                   ├── Language.kt
    │           │                   ├── List.kt
    │           │                   ├── Lock.kt
    │           │                   ├── Menu.kt
    │           │                   ├── Minus.kt
    │           │                   ├── Network.kt
    │           │                   ├── Next.kt
    │           │                   ├── OpenSource.kt
    │           │                   ├── Pause.kt
    │           │                   ├── Permission.kt
    │           │                   ├── Plus.kt
    │           │                   ├── QuestionMark.kt
    │           │                   ├── Queue.kt
    │           │                   ├── QueueStart.kt
    │           │                   ├── QueueStop.kt
    │           │                   ├── Refresh.kt
    │           │                   ├── Resume.kt
    │           │                   ├── Scheduler.kt
    │           │                   ├── Search.kt
    │           │                   ├── SelectAll.kt
    │           │                   ├── SelectInside.kt
    │           │                   ├── SelectInvert.kt
    │           │                   ├── Settings.kt
    │           │                   ├── Share.kt
    │           │                   ├── Sort123.kt
    │           │                   ├── Sort321.kt
    │           │                   ├── Speaker.kt
    │           │                   ├── SpeedLimiter.kt
    │           │                   ├── Stop.kt
    │           │                   ├── StopAll.kt
    │           │                   ├── Telegram.kt
    │           │                   ├── Theme.kt
    │           │                   ├── Undo.kt
    │           │                   ├── Up.kt
    │           │                   ├── VerticalDirection.kt
    │           │                   ├── WindowClose.kt
    │           │                   ├── WindowFloating.kt
    │           │                   ├── WindowMaximize.kt
    │           │                   └── WindowMinimize.kt
    │           └── resources/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── resources/
    │                           ├── credits/
    │                           │   └── translators.json
    │                           └── locales/
    │                               ├── ar_SA.properties
    │                               ├── bn_BD.properties
    │                               ├── bqi_IR.properties
    │                               ├── ckb_IR.properties
    │                               ├── de_DE.properties
    │                               ├── en_US.properties
    │                               ├── es_ES.properties
    │                               ├── fa_IR.properties
    │                               ├── fi_FI.properties
    │                               ├── fr_FR.properties
    │                               ├── hu_HU.properties
    │                               ├── id_ID.properties
    │                               ├── it_IT.properties
    │                               ├── ja_JP.properties
    │                               ├── ka_GE.properties
    │                               ├── ko_KR.properties
    │                               ├── lt_LT.properties
    │                               ├── pl_PL.properties
    │                               ├── pt_BR.properties
    │                               ├── ru_RU.properties
    │                               ├── sq_AL.properties
    │                               ├── th_TH.properties
    │                               ├── tr_TR.properties
    │                               ├── uk_UA.properties
    │                               ├── vi_VN.properties
    │                               ├── zh_CN.properties
    │                               └── zh_TW.properties
    ├── updater/
    │   ├── build.gradle.kts
    │   └── src/
    │       ├── androidMain/
    │       │   └── kotlin/
    │       │       ├── AndroidDirectLinkUpdateApplier.kt
    │       │       └── ApkInstaller.kt
    │       ├── commonMain/
    │       │   └── kotlin/
    │       │       └── com/
    │       │           └── abdownloadmanager/
    │       │               ├── ArtifactUtil.kt
    │       │               ├── UpdateDownloadLocationProvider.kt
    │       │               ├── UpdateManager.kt
    │       │               ├── github/
    │       │               │   └── githubapi.kt
    │       │               ├── updateapplier/
    │       │               │   ├── BaseUpdateApplier.kt
    │       │               │   ├── UpdateApplier.kt
    │       │               │   ├── UpdateDownloader.kt
    │       │               │   └── UpdateInstaller.kt
    │       │               └── updatechecker/
    │       │                   ├── DummyUpdateChecker.kt
    │       │                   ├── GithubUpdateChecker.kt
    │       │                   ├── UpdateChecker.kt
    │       │                   └── UpdateInfo.kt
    │       └── desktopMain/
    │           ├── kotlin/
    │           │   └── com/
    │           │       └── abdownloadmanager/
    │           │           └── updateapplier/
    │           │               ├── DesktopDirectLinkUpdateApplier.kt
    │           │               ├── UpdateInstallerByWindowsExecutable.kt
    │           │               └── UpdateInstallerFromArchiveFile.kt
    │           └── resources/
    │               └── com/
    │                   └── abdownloadmanager/
    │                       └── updater/
    │                           ├── updater_linux.sh
    │                           ├── updater_macos.sh
    │                           └── updater_windows.bat
    └── utils/
        ├── build.gradle.kts
        └── src/
            ├── androidMain/
            │   └── kotlin/
            │       └── ir/
            │           └── amirab/
            │               └── util/
            │                   ├── openUrl.android.kt
            │                   └── osfileutil/
            │                       ├── AndroidFileUtil.kt
            │                       └── FileUtils.android.kt
            ├── commonMain/
            │   └── kotlin/
            │       └── ir/
            │           └── amirab/
            │               ├── SelectionUtil.kt
            │               └── util/
            │                   ├── AppVersionTracker.kt
            │                   ├── CallAwait.kt
            │                   ├── CollectionUtils.kt
            │                   ├── Exec.kt
            │                   ├── FileExtensions.kt
            │                   ├── FileNameValidator.kt
            │                   ├── FilenameDecoder.kt
            │                   ├── GuardedEntry.kt
            │                   ├── HttpUrlUtils.kt
            │                   ├── IfThen.kt
            │                   ├── NullCheck.kt
            │                   ├── OkioUtils.kt
            │                   ├── PathValidator.kt
            │                   ├── StringUtil.kt
            │                   ├── ValueHolder.kt
            │                   ├── coroutines/
            │                   │   ├── CombineFlows.kt
            │                   │   ├── CoroutineUtils.kt
            │                   │   └── debounce.kt
            │                   ├── datasize/
            │                   │   ├── BaseSize.kt
            │                   │   ├── CommonSizeConvertConfigs.kt
            │                   │   ├── CommonSizeUnits.kt
            │                   │   ├── ConvertSizeConfig.kt
            │                   │   ├── SizeConverter.kt
            │                   │   ├── SizeFactors.kt
            │                   │   ├── SizeUnit.kt
            │                   │   ├── SizeWithUnit.kt
            │                   │   └── extensions.kt
            │                   ├── enumValueOrNull.kt
            │                   ├── flow/
            │                   │   ├── FlowOperators.kt
            │                   │   ├── FlowUtils.kt
            │                   │   └── StateFlowUtil.kt
            │                   ├── lock.kt
            │                   ├── openUrl.kt
            │                   └── osfileutil/
            │                       ├── FileUtils.kt
            │                       └── FileUtilsBase.kt
            └── desktopMain/
                └── kotlin/
                    └── ir/
                        └── amirab/
                            └── util/
                                ├── openUrl.desktop.kt
                                └── osfileutil/
                                    ├── DesktopFileUtils.kt
                                    ├── FileUtils.desktop.kt
                                    ├── JVMFileUtils.kt
                                    ├── LinuxFileUtils.kt
                                    ├── MacOsFileUtils.kt
                                    └── WindowsFileUtils.kt
Condensed preview — 1054 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,329K chars).
[
  {
    "path": ".gitattributes",
    "chars": 214,
    "preview": "#\n# https://help.github.com/articles/dealing-with-line-endings/\n#\n# Linux start script should use lf\n/gradlew        tex"
  },
  {
    "path": ".github/FUNDING.yml",
    "chars": 995,
    "preview": "# These are supported funding model platforms\n\ngithub: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [u"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "chars": 2999,
    "preview": "name: 🐞 Bug Report\ndescription: Report an issue or unexpected behavior in the app\ntitle: \"[Bug] Brief summary (keep it s"
  },
  {
    "path": ".github/workflows/brew-cask-auto-bump.yml",
    "chars": 1823,
    "preview": "name: Auto bump ab-download-manager homebrew cask\n\non:\n  release:\n    types: [released]    \n  workflow_dispatch: {}     "
  },
  {
    "path": ".github/workflows/publish.yml",
    "chars": 3150,
    "preview": "on:\n  push:\n    tags:\n      - \"v[0-9]+.[0-9]+.[0-9]+*\"\n  workflow_dispatch:\n\n\npermissions:\n  contents: write\n\njobs:\n  cr"
  },
  {
    "path": ".github/workflows/winget.yml",
    "chars": 289,
    "preview": "name: Publish to Winget\r\n\r\non:\r\n  release:\r\n    types: [released]\r\n\r\njobs:\r\n  publish:\r\n    runs-on: ubuntu-latest\r\n    "
  },
  {
    "path": ".gitignore",
    "chars": 168,
    "preview": "# Ignore Gradle project-specific cache directory\n.gradle\n.kotlin\n\n# Ignore Gradle build output directory\nbuild\n.idea\nloc"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 21002,
    "preview": "# Changelog\n\n## Unreleased\n\n### Added\n\n### Changed\n\n### Deprecated\n\n### Removed\n\n### Fixed\n\n### Security\n\n## 1.8.7\n\n### "
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 2688,
    "preview": "# Contributing to AB Download Manager\n\n> ❌ **Important Notice:** The entire codebase is being completely rewritten. Pull"
  },
  {
    "path": "DONATE.md",
    "chars": 589,
    "preview": "# ❤️ Donate\n\nWant to support the project? You can make a donation using these crypto addresses:\n\n<a href=\"#ton\" alt=\"Ton"
  },
  {
    "path": "LICENSE",
    "chars": 11357,
    "preview": "                                 Apache License\n                           Version 2.0, January 2004\n                   "
  },
  {
    "path": "README.md",
    "chars": 7637,
    "preview": "<div align=\"center\">\n  <a href=\"https://abdownloadmanager.com\" target=\"_blank\">\n    <img width=\"180\" src=\"assets/logo/ap"
  },
  {
    "path": "REST-API.yml",
    "chars": 3227,
    "preview": "openapi: 3.0.0\ninfo:\n  title: Download Service API\n  version: 1.0.0\n  description: API for managing download tasks and q"
  },
  {
    "path": "android/app/.gitignore",
    "chars": 8,
    "preview": "release\n"
  },
  {
    "path": "android/app/build.gradle.kts",
    "chars": 4440,
    "preview": "import buildlogic.CiDirs\nimport buildlogic.CiUtils\nimport buildlogic.versioning.convertToVersionCode\nimport buildlogic.v"
  },
  {
    "path": "android/app/filetypes.txt",
    "chars": 522,
    "preview": "# music / audio\nmp3\naac\nm4a\nwav\nflac\nogg\nwma\namr\nopus\nmid\n\n# video\nmp4\nmkv\navi\nmov\n3gp\nwebm\nwmv\nflv\nmpeg\nmpg\nm4v\nts\n\n# i"
  },
  {
    "path": "android/app/src/main/AndroidManifest.xml",
    "chars": 5716,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    "
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ABDMApp.kt",
    "chars": 1480,
    "preview": "package com.abdownloadmanager.android\n\nimport android.app.Application\nimport com.abdownloadmanager.android.di.Di\nimport "
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/action/Actions.kt",
    "chars": 604,
    "preview": "package com.abdownloadmanager.android.action\n\nimport com.abdownloadmanager.android.util.pagemanager.IBrowserPageManager\n"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/di/Di.kt",
    "chars": 21278,
    "preview": "package com.abdownloadmanager.android.di\n\nimport AndroidDirectLinkUpdateApplier\nimport android.app.Application\nimport an"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/about/AboutPage.kt",
    "chars": 13403,
    "preview": "package com.abdownloadmanager.android.pages.about\n\nimport androidx.compose.runtime.Composable\n\n\nimport androidx.compose."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/AddDownloadActivity.kt",
    "chars": 3348,
    "preview": "package com.abdownloadmanager.android.pages.add\n\nimport android.content.Intent\nimport android.os.Bundle\nimport arrow.cor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiDownloadActivity.kt",
    "chars": 5049,
    "preview": "package com.abdownloadmanager.android.pages.add.multiple\n\nimport android.content.Context\nimport android.content.Intent\ni"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiDownloadList.kt",
    "chars": 6134,
    "preview": "package com.abdownloadmanager.android.pages.add.multiple\n\nimport androidx.compose.foundation.background\nimport androidx."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AddMultiItemPage.kt",
    "chars": 12430,
    "preview": "package com.abdownloadmanager.android.pages.add.multiple\n\nimport androidx.activity.compose.BackHandler\nimport androidx.a"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/multiple/AndroidAddMultiDownloadComponent.kt",
    "chars": 4676,
    "preview": "package com.abdownloadmanager.android.pages.add.multiple\n\nimport com.abdownloadmanager.shared.action.createNewQueueActio"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/CategorySelect.kt",
    "chars": 5645,
    "preview": "package com.abdownloadmanager.android.pages.add.shared\n\nimport androidx.compose.foundation.background\nimport androidx.co"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/ExtraConfig.kt",
    "chars": 3391,
    "preview": "package com.abdownloadmanager.android.pages.add.shared\n\nimport com.abdownloadmanager.shared.ui.configurable.RenderConfig"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/LocationTextField.kt",
    "chars": 5065,
    "preview": "package com.abdownloadmanager.android.pages.add.shared\n\nimport com.abdownloadmanager.shared.ui.widget.MyTextFieldWithIco"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/shared/SelectQueue.kt",
    "chars": 7387,
    "preview": "package com.abdownloadmanager.android.pages.add.shared\n\nimport com.abdownloadmanager.shared.util.ui.icon.MyIcons\nimport "
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AddSingleDownloadActivity.kt",
    "chars": 9110,
    "preview": "package com.abdownloadmanager.android.pages.add.single\n\nimport android.content.Context\nimport android.content.Intent\nimp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AddSingleDownloadPage.kt",
    "chars": 24698,
    "preview": "package com.abdownloadmanager.android.pages.add.single\n\nimport androidx.compose.foundation.layout.Column\nimport androidx"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/add/single/AndroidAddSingleDownloadComponent.kt",
    "chars": 6480,
    "preview": "package com.abdownloadmanager.android.pages.add.single\n\nimport com.abdownloadmanager.shared.action.createNewQueueAction\n"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/batchdownload/AndroidBatchDownloadComponent.kt",
    "chars": 544,
    "preview": "package com.abdownloadmanager.android.pages.batchdownload\n\nimport com.abdownloadmanager.shared.pages.batchdownload.BaseB"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/batchdownload/BatchDownloadPage.kt",
    "chars": 13097,
    "preview": "package com.abdownloadmanager.android.pages.batchdownload\n\nimport androidx.compose.animation.AnimatedVisibility\nimport a"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/BrowserActivity.kt",
    "chars": 3386,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport android.content.ComponentName\nimport android.content.Context"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/BrowserComponent.kt",
    "chars": 12962,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport android.content.Context\nimport android.content.Intent\nimport"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/BrowserUi.kt",
    "chars": 24035,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compos"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/DownloadInterceptor.kt",
    "chars": 4027,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport android.webkit.CookieManager\nimport com.abdownloadmanager.an"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/SearchEngines.kt",
    "chars": 1243,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport java.net.URLEncoder\nimport java.nio.charset.StandardCharsets"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/WebView.kt",
    "chars": 898,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/WebViewHolder.kt",
    "chars": 7857,
    "preview": "package com.abdownloadmanager.android.pages.browser\n\nimport android.content.Context\nimport android.content.Intent\nimport"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/bookmark/Bookmarks.kt",
    "chars": 5500,
    "preview": "package com.abdownloadmanager.android.pages.browser.bookmark\n\nimport androidx.compose.foundation.combinedClickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/browser/bookmark/EditBookmark.kt",
    "chars": 4268,
    "preview": "package com.abdownloadmanager.android.pages.browser.bookmark\n\nimport androidx.compose.foundation.layout.Column\nimport an"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/category/CategorySheet.kt",
    "chars": 14045,
    "preview": "package com.abdownloadmanager.android.pages.category\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/category/NewCategory.kt",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/checksum/AndroidFileChecksumComponent.kt",
    "chars": 1037,
    "preview": "package com.abdownloadmanager.android.pages.checksum\n\nimport com.abdownloadmanager.shared.pages.checksum.BaseFileChecksu"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/checksum/FileChecksumPage.kt",
    "chars": 18867,
    "preview": "package com.abdownloadmanager.android.pages.checksum\n\nimport androidx.compose.animation.core.*\nimport androidx.compose.f"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/crashreport/CrashReportActivity.kt",
    "chars": 1341,
    "preview": "package com.abdownloadmanager.android.pages.crashreport\n\nimport android.content.Context\nimport android.content.Intent\nim"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/crashreport/ErrorUi.kt",
    "chars": 4713,
    "preview": "package com.abdownloadmanager.android.pages.crashreport\n\nimport android.os.Build\nimport com.abdownloadmanager.shared.uti"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/crashreport/ThrowableData.kt",
    "chars": 539,
    "preview": "package com.abdownloadmanager.android.pages.crashreport\n\nimport kotlinx.serialization.Serializable\n\n@Serializable\ndata c"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/credits/thirdpartylibraries/ExternalLibsPage.kt",
    "chars": 8988,
    "preview": "package com.abdownloadmanager.android.pages.credits.thirdpartylibraries\n\nimport androidx.activity.OnBackPressedDispatche"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/credits/thirdpartylibraries/LibraryDialog.kt",
    "chars": 7882,
    "preview": "package com.abdownloadmanager.android.pages.credits.thirdpartylibraries\n\nimport com.abdownloadmanager.shared.util.ui.myC"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/credits/translators/TranslatorsPage.kt",
    "chars": 11334,
    "preview": "package com.abdownloadmanager.android.pages.credits.translators\n\nimport androidx.compose.animation.AnimatedContent\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/directorypicker/ComposeExtension.kt",
    "chars": 1292,
    "preview": "package com.abdownloadmanager.android.pages.directorypicker\n\nimport androidx.activity.compose.rememberLauncherForActivit"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/directorypicker/DirectoryPickerActivity.kt",
    "chars": 2797,
    "preview": "package com.abdownloadmanager.android.pages.directorypicker\n\nimport android.content.Context\nimport android.content.Inten"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/directorypicker/DirectoryPickerPage.kt",
    "chars": 16686,
    "preview": "package com.abdownloadmanager.android.pages.directorypicker\n\nimport android.content.Context\nimport android.os.Environmen"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/editdownload/AndroidEditDownloadComponent.kt",
    "chars": 1411,
    "preview": "package com.abdownloadmanager.android.pages.editdownload\n\nimport com.abdownloadmanager.shared.downloaderinui.DownloaderI"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/editdownload/EditDownload.kt",
    "chars": 17478,
    "preview": "package com.abdownloadmanager.android.pages.editdownload\n\nimport androidx.compose.runtime.Composable\n\nimport com.abdownl"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/enterurl/AndroidEnterNewURLComponent.kt",
    "chars": 880,
    "preview": "package com.abdownloadmanager.android.pages.enterurl\n\nimport com.abdownloadmanager.shared.downloaderinui.DownloaderInUiR"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/enterurl/EnterURLPage.kt",
    "chars": 8845,
    "preview": "package com.abdownloadmanager.android.pages.enterurl\n\nimport androidx.compose.foundation.background\nimport androidx.comp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/AndroidDownloadActions.kt",
    "chars": 3494,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport com.abdownloadmanager.resources.Res\nimport com.abdownloadmanage"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/BottomNavigation.kt",
    "chars": 14862,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.a"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/DownloadList.kt",
    "chars": 4735,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.f"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/FilterStatusIndicator.kt",
    "chars": 4367,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.foundation.clickable\nimport androidx.compose.f"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/HomeComponent.kt",
    "chars": 19006,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.runtime.derivedStateOf\nimport androidx.compose"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/HomePage.kt",
    "chars": 17563,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.animation.AnimatedContent\nimport androidx.comp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/HomePageStateToPersist.kt",
    "chars": 454,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport arrow.optics.optics\nimport com.abdownloadmanager.android.pages."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/Prompts.kt",
    "chars": 13842,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.foundation.background\nimport androidx.compose."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/RenderAddMenu.kt",
    "chars": 1558,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.foundation.layout.IntrinsicSize\nimport android"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/RenderDownloadItem.kt",
    "chars": 16301,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.c"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/RenderMainMenu.kt",
    "chars": 1562,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.foundation.layout.IntrinsicSize\nimport android"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/RenderStatusFilterMenu.kt",
    "chars": 3168,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.a"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/SelectedQueueItemsOption.kt",
    "chars": 1912,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.foundation.layout.Row\nimport androidx.compose."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/Selection.kt",
    "chars": 9770,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport androidx.compose.animation.AnimatedVisibility\nimport androidx.c"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/SimplePager.kt",
    "chars": 2415,
    "preview": "package com.abdownloadmanager.android.pages.home\n\nimport android.util.Log\nimport androidx.compose.foundation.horizontalS"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/sections/Categories.kt",
    "chars": 16315,
    "preview": "package com.abdownloadmanager.android.pages.home.sections\n\nimport androidx.compose.animation.*\nimport androidx.compose.f"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/sections/queues/Queues.kt",
    "chars": 14291,
    "preview": "package com.abdownloadmanager.android.pages.home.sections.queues\n\nimport androidx.compose.animation.AnimatedVisibility\ni"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/sections/sort/DownloadSortBy.kt",
    "chars": 1703,
    "preview": "package com.abdownloadmanager.android.pages.home.sections.sort\n\nimport com.abdownloadmanager.resources.Res\nimport com.ab"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/home/sections/sort/RenderSortMenu.kt",
    "chars": 6333,
    "preview": "package com.abdownloadmanager.android.pages.home.sections.sort\n\nimport androidx.activity.compose.BackHandler\nimport andr"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/newqueue/NewQueue.kt",
    "chars": 1023,
    "preview": "package com.abdownloadmanager.android.pages.newqueue\n\nimport androidx.compose.runtime.Composable\nimport com.abdownloadma"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/StartUpPageTemplate.kt",
    "chars": 4457,
    "preview": "package com.abdownloadmanager.android.pages.onboarding\n\nimport androidx.activity.compose.BackHandler\nimport androidx.com"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/initialsetup/InitialSetupComponent.kt",
    "chars": 867,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.initialsetup\n\nimport com.abdownloadmanager.shared.settings.Common"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/initialsetup/InitialSetupPage.kt",
    "chars": 5726,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.initialsetup\n\nimport androidx.compose.foundation.background\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/ABDMPermissions.kt",
    "chars": 3570,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.Manifest\nimport android.content.Conte"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/AppPermission.kt",
    "chars": 6127,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.app.Activity\nimport android.content.C"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/BatteryOptimizationUtil.kt",
    "chars": 1176,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.content.Context\nimport android.conten"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/CustomPermissions.kt",
    "chars": 801,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.content.Context\nimport androidx.compo"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/PermissionComponent.kt",
    "chars": 2805,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport com.abdownloadmanager.shared.util.BaseCompone"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/PermissionManager.kt",
    "chars": 671,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.content.Context\nimport android.conten"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/PermissionsPage.kt",
    "chars": 10733,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.app.Activity\nimport android.content.I"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/onboarding/permissions/StoragePermissionUtil.kt",
    "chars": 765,
    "preview": "package com.abdownloadmanager.android.pages.onboarding.permissions\n\nimport android.content.Context\nimport android.conten"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/perhostsettings/AndroidPerHostSettingsComponent.kt",
    "chars": 1252,
    "preview": "package com.abdownloadmanager.android.pages.perhostsettings\n\nimport com.abdownloadmanager.shared.pages.perhostsettings.B"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/perhostsettings/PerHostSettingsPage.kt",
    "chars": 12334,
    "preview": "package com.abdownloadmanager.android.pages.perhostsettings\n\nimport androidx.activity.compose.BackHandler\nimport android"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/queue/QueueConfigurationComponent.kt",
    "chars": 10802,
    "preview": "package com.abdownloadmanager.android.pages.queue\n\nimport com.abdownloadmanager.resources.Res\nimport com.abdownloadmanag"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/queue/QueuesSheet.kt",
    "chars": 2638,
    "preview": "package com.abdownloadmanager.android.pages.queue\n\nimport androidx.compose.foundation.layout.Column\nimport androidx.comp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/settings/AndroidSettings.kt",
    "chars": 2018,
    "preview": "package com.abdownloadmanager.android.pages.settings\n\nimport com.abdownloadmanager.android.pages.onboarding.permissions."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/settings/AndroidSettingsComponent.kt",
    "chars": 6401,
    "preview": "package com.abdownloadmanager.android.pages.settings\n\nimport com.abdownloadmanager.android.storage.AppSettingsStorage\nim"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/settings/SettingsPage.kt",
    "chars": 4991,
    "preview": "package com.abdownloadmanager.android.pages.settings\n\nimport androidx.activity.compose.LocalOnBackPressedDispatcherOwner"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/singledownload/CompletedDownloadPage.kt",
    "chars": 4516,
    "preview": "package com.abdownloadmanager.android.pages.singledownload\n\nimport androidx.compose.foundation.background\nimport android"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/singledownload/DesktopSingleDownloadPageComponent.kt",
    "chars": 3188,
    "preview": "package com.abdownloadmanager.android.pages.singledownload\n\nimport com.abdownloadmanager.android.storage.AndroidExtraDow"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/singledownload/ProgressDownloadPage.kt",
    "chars": 24661,
    "preview": "package com.abdownloadmanager.android.pages.singledownload\n\nimport androidx.compose.animation.AnimatedVisibility\nimport "
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/singledownload/ShowDownloadDialogs.kt",
    "chars": 4015,
    "preview": "package com.abdownloadmanager.android.pages.singledownload\n\nimport androidx.compose.animation.AnimatedContent\nimport and"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/singledownload/SingleDownloadPageActivity.kt",
    "chars": 3663,
    "preview": "package com.abdownloadmanager.android.pages.singledownload\n\nimport android.content.Context\nimport android.content.Intent"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/updater/NewUpdatePage.kt",
    "chars": 9929,
    "preview": "package com.abdownloadmanager.android.pages.updater\n\nimport androidx.compose.animation.animateColor\nimport androidx.comp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/pages/updater/UpdaterDialog.kt",
    "chars": 1603,
    "preview": "package com.abdownloadmanager.android.pages.updater\n\nimport androidx.compose.runtime.*\nimport com.abdownloadmanager.shar"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/receiver/StartOnBootBroadcastReceiver.kt",
    "chars": 988,
    "preview": "package com.abdownloadmanager.android.receiver\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\n"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/repository/AppRepository.kt",
    "chars": 1626,
    "preview": "package com.abdownloadmanager.android.repository\n\nimport com.abdownloadmanager.android.pages.browser.BrowserActivity\nimp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/service/DownloadSystemService.kt",
    "chars": 2115,
    "preview": "package com.abdownloadmanager.android.service\n\nimport android.app.Service\nimport android.content.Intent\nimport android.u"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/service/KeepAliveServiceReason.kt",
    "chars": 2337,
    "preview": "package com.abdownloadmanager.android.service\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtim"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/AndroidExtraDownloadItemSettings.kt",
    "chars": 693,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport com.abdownloadmanager.shared.storage.IExtraDownloadItemSettings\nim"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/AndroidExtraQueueSettings.kt",
    "chars": 592,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport com.abdownloadmanager.shared.storage.IExtraQueueSettings\nimport ko"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/AndroidOnBoardingStorage.kt",
    "chars": 725,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport androidx.datastore.core.DataStore\nimport arrow.optics.optics\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/AppSettingsStorage.kt",
    "chars": 14941,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport androidx.datastore.core.DataStore\nimport arrow.optics.Lens\nimport "
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/BrowserBookmarksStorage.kt",
    "chars": 515,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport androidx.compose.runtime.Immutable\nimport androidx.datastore.core."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/storage/HomePageStorage.kt",
    "chars": 494,
    "preview": "package com.abdownloadmanager.android.storage\n\nimport androidx.datastore.core.DataStore\nimport com.abdownloadmanager.and"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/ABDownloadManagerApplicationContent.kt",
    "chars": 3359,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.runtime.col"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/MainActivity.kt",
    "chars": 3719,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport android.content.Context\nimport android.content.Intent\nimport android.os"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/MainComponent.kt",
    "chars": 26641,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport android.content.Context\nimport android.content.Intent\nimport com.abdown"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/MainContent.kt",
    "chars": 7011,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport androidx.activity.compose.LocalActivity\nimport androidx.compose.foundat"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/SelectionControls.kt",
    "chars": 5125,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport androidx.compose.foundation.LocalIndication\nimport androidx.compose.fou"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/SheetUI.kt",
    "chars": 5393,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport androidx.compose.foundation.background\nimport androidx.compose.foundati"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/AndroidConfigurableUtils.kt",
    "chars": 5325,
    "preview": "package com.abdownloadmanager.android.ui.configurable\n\nimport androidx.compose.animation.AnimatedContent\nimport androidx"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/ConfigurableSheet.kt",
    "chars": 1586,
    "preview": "package com.abdownloadmanager.android.ui.configurable\n\nimport androidx.compose.foundation.layout.RowScope\nimport android"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/SheetInput.kt",
    "chars": 4414,
    "preview": "package com.abdownloadmanager.android.ui.configurable\n\nimport androidx.compose.foundation.layout.Column\nimport androidx."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/SheetSpinner.kt",
    "chars": 6827,
    "preview": "package com.abdownloadmanager.android.ui.configurable\n\nimport androidx.compose.foundation.background\nimport androidx.com"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/android/AndroidConfigurableRenderers.kt",
    "chars": 737,
    "preview": "package com.abdownloadmanager.android.ui.configurable.android\n\nimport com.abdownloadmanager.android.ui.configurable.andr"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/android/item/PermissionConfigurable.kt",
    "chars": 964,
    "preview": "package com.abdownloadmanager.android.ui.configurable.android.item\n\nimport com.abdownloadmanager.android.pages.onboardin"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/android/renderer/PermissionConfigurableRenderer.kt",
    "chars": 3132,
    "preview": "package com.abdownloadmanager.android.ui.configurable.android.renderer\n\nimport androidx.compose.foundation.clickable\nimp"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/CommonConfigurableRenderersForAndroid.kt",
    "chars": 2421,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon\n\nimport com.abdownloadmanager.android.ui.configurable.comon."
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/ConfigurableRenderersForAndroid.kt",
    "chars": 392,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon\n\nimport com.abdownloadmanager.android.ui.configurable.androi"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/BooleanConfigurableRenderer.kt",
    "chars": 2546,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/DayOfWeekConfigurableRenderer.kt",
    "chars": 6145,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.background\nimpo"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/EnumConfigurableRenderer.kt",
    "chars": 2968,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/FileChecksumConfigurableRenderer.kt",
    "chars": 4999,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.animation.AnimatedVisibili"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/FloatConfigurableRenderer.kt",
    "chars": 4015,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/FolderConfigurableRenderer.kt",
    "chars": 2308,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/IntConfigurableRenderer.kt",
    "chars": 4370,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/LongConfigurableRenderer.kt",
    "chars": 4423,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/NavigatableConfigurableRenderer.kt",
    "chars": 2067,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/ProxyConfigurableRenderer.kt",
    "chars": 23263,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.animation.core.animateDpAs"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/SpeedLimitConfigurableRenderer.kt",
    "chars": 6156,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.animation.AnimatedVisibili"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/StringConfigurableRenderer.kt",
    "chars": 3370,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/ThemeConfigurableRenderer.kt",
    "chars": 4967,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.background\nimpo"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/configurable/comon/renderer/TimeConfigurableRenderer.kt",
    "chars": 5528,
    "preview": "package com.abdownloadmanager.android.ui.configurable.comon.renderer\n\nimport androidx.compose.foundation.clickable\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/menu/Menu.kt",
    "chars": 9089,
    "preview": "package com.abdownloadmanager.android.ui.menu\n\nimport androidx.compose.foundation.background\nimport androidx.compose.fou"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/menu/RenderMenuInSheet.kt",
    "chars": 3008,
    "preview": "package com.abdownloadmanager.android.ui.menu\n\nimport androidx.compose.foundation.layout.fillMaxWidth\nimport androidx.co"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/menu/RenderMenuInSinglePage.kt",
    "chars": 4781,
    "preview": "package com.abdownloadmanager.android.ui.menu\n\nimport androidx.activity.compose.LocalOnBackPressedDispatcherOwner\nimport"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/menu/StackedMenu.kt",
    "chars": 2864,
    "preview": "package com.abdownloadmanager.android.ui.menu\n\nimport androidx.activity.compose.BackHandler\nimport androidx.compose.anim"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/myCombinedClickable.kt",
    "chars": 1689,
    "preview": "package com.abdownloadmanager.android.ui\n\nimport androidx.compose.foundation.Indication\nimport androidx.compose.foundati"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/page/PageUI.kt",
    "chars": 5887,
    "preview": "package com.abdownloadmanager.android.ui.page\n\nimport androidx.compose.foundation.basicMarquee\nimport androidx.compose.f"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/page/PageUtils.kt",
    "chars": 2530,
    "preview": "package com.abdownloadmanager.android.ui.page\n\nimport androidx.compose.foundation.background\nimport androidx.compose.fou"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/ui/widget/ComposeWebView.kt",
    "chars": 25280,
    "preview": "/*\n * Copyright 2021 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\""
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/ABDMAppManager.kt",
    "chars": 17421,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimpo"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/ABDMServiceNotificationManager.kt",
    "chars": 13432,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.app.Notification\nimport android.app.NotificationChannel\nimpor"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidConstants.kt",
    "chars": 897,
    "preview": "package com.abdownloadmanager.android.util\n\nobject AndroidConstants {\n    const val SERVICE_NOTIFICATION_ID = 1\n    cons"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidDefinedPaths.kt",
    "chars": 491,
    "preview": "package com.abdownloadmanager.android.util\n\nimport com.abdownloadmanager.shared.util.DefinedPaths\nimport okio.Path\n\nclas"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidDownloadItemOpener.kt",
    "chars": 1217,
    "preview": "package com.abdownloadmanager.android.util\n\nimport com.abdownloadmanager.shared.util.DownloadItemOpener\nimport com.abdow"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidGlobalExceptionHandler.kt",
    "chars": 3692,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.app.NotificationChannel\nimport android.app.NotificationManage"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidIntentUtils.kt",
    "chars": 1352,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.content.Context\nimport android.content.Intent\nimport androidx"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AndroidUi.kt",
    "chars": 588,
    "preview": "package com.abdownloadmanager.android.util\n\nimport com.abdownloadmanager.shared.ui.theme.ThemeManager\nimport ir.amirab.u"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/AppInfo.kt",
    "chars": 762,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.app.Application\nimport com.abdownloadmanager.android.BuildCon"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/ApplicationBackgroundTracker.kt",
    "chars": 1252,
    "preview": "package com.abdownloadmanager.android.util\n\nimport android.app.Activity\nimport android.app.Application\nimport android.os"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/HeadlessComposeRuntime.kt",
    "chars": 1501,
    "preview": "package com.abdownloadmanager.android.util\n\nimport androidx.compose.runtime.AbstractApplier\nimport androidx.compose.runt"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/activity/ABDMActivity.kt",
    "chars": 4649,
    "preview": "package com.abdownloadmanager.android.util.activity\n\nimport android.content.Context\nimport android.content.Intent\nimport"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/activity/ActivityActions.kt",
    "chars": 250,
    "preview": "package com.abdownloadmanager.android.util.activity\n\nimport android.content.Intent\nimport com.abdownloadmanager.shared.u"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/activity/RetainedComponentContainer.kt",
    "chars": 2144,
    "preview": "package com.abdownloadmanager.android.util.activity\n\nimport android.content.Intent\nimport androidx.activity.ComponentAct"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/activity/SerializableExtra.kt",
    "chars": 878,
    "preview": "package com.abdownloadmanager.android.util.activity\n\nimport android.content.Intent\nimport kotlinx.serialization.KSeriali"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/compose/ObserveUiVisibility.kt",
    "chars": 1360,
    "preview": "package com.abdownloadmanager.android.util.compose\n\nimport androidx.compose.runtime.Composable\nimport androidx.compose.r"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/compose/useBack.kt",
    "chars": 355,
    "preview": "package com.abdownloadmanager.android.util.compose\n\nimport androidx.activity.OnBackPressedDispatcher\nimport androidx.act"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/notification/playNotificationSoundIfAllowed.kt",
    "chars": 1441,
    "preview": "package com.abdownloadmanager.android.util.notification\n\nimport android.app.NotificationManager\nimport android.content.C"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/pagemanager/BrowserPageManager.kt",
    "chars": 124,
    "preview": "package com.abdownloadmanager.android.util.pagemanager\n\ninterface IBrowserPageManager {\n    fun openBrowser(url: String?"
  },
  {
    "path": "android/app/src/main/kotlin/com/abdownloadmanager/android/util/pagemanager/PermissionsPageManager.kt",
    "chars": 182,
    "preview": "package com.abdownloadmanager.android.util.pagemanager\n\ninterface PermissionsPageManager {\n    fun openPermissionsPage(o"
  },
  {
    "path": "android/app/src/main/res/drawable/ic_launcher_background.xml",
    "chars": 788,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n"
  },
  {
    "path": "android/app/src/main/res/drawable/ic_launcher_foreground.xml",
    "chars": 3155,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n"
  },
  {
    "path": "android/app/src/main/res/drawable/ic_launcher_monochrome.xml",
    "chars": 2220,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"512dp\"\n        android:height="
  },
  {
    "path": "android/app/src/main/res/drawable/ic_monochrome.xml",
    "chars": 2058,
    "preview": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"512dp\"\n        android:height="
  },
  {
    "path": "android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "chars": 341,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "chars": 341,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <b"
  },
  {
    "path": "android/app/src/main/res/values/strings.xml",
    "chars": 185,
    "preview": "<resources>\n    <string name=\"app_name\">AB Download Manager</string>\n    <string name=\"app_short_name\">AB DM</string>\n  "
  },
  {
    "path": "android/app/src/main/res/values/theme.xml",
    "chars": 771,
    "preview": "<resources>\n    <style name=\"Theme.ABDownloadManager\" parent=\"android:Theme.Material.NoActionBar\">\n        <item name=\"a"
  },
  {
    "path": "android/app/src/main/res/xml/provider_paths.xml",
    "chars": 178,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths>\n    <external-path name=\"external_files\" path=\".\"/>\n    <files-path name="
  },
  {
    "path": "build.gradle.kts",
    "chars": 2506,
    "preview": "import buildlogic.CiUtils\nimport buildlogic.versioning.getAppVersionString\nimport io.github.z4kn4fein.semver.toVersion\ni"
  },
  {
    "path": "buildSrc/build.gradle.kts",
    "chars": 810,
    "preview": "plugins{\n    `kotlin-dsl`\n}\nrepositories {\n    gradlePluginPortal()\n    mavenCentral()\n    google()\n}\ndependencies{\n    "
  },
  {
    "path": "buildSrc/settings.gradle.kts",
    "chars": 151,
    "preview": "dependencyResolutionManagement{\n    versionCatalogs {\n        create(\"libs\"){\n            from(files(\"../gradle/libs.ver"
  },
  {
    "path": "buildSrc/src/main/kotlin/Plugins.kt",
    "chars": 1431,
    "preview": "import ir.amirab.util.platform.Platform\n\nobject MyPlugins {\n    private const val namespace = \"myPlugins\"\n    const val "
  },
  {
    "path": "buildSrc/src/main/kotlin/buildlogic/CiDirs.kt",
    "chars": 336,
    "preview": "package buildlogic\n\nimport org.gradle.api.file.Directory\nimport org.gradle.api.provider.Provider\n\nclass CiDirs(baseDir: "
  },
  {
    "path": "buildSrc/src/main/kotlin/buildlogic/CiUtils.kt",
    "chars": 5805,
    "preview": "package buildlogic\n\nimport io.github.z4kn4fein.semver.Version\nimport ir.amirab.installer.InstallerTargetFormat\nimport ir"
  },
  {
    "path": "buildSrc/src/main/kotlin/buildlogic/HashUtils.kt",
    "chars": 432,
    "preview": "package buildlogic\n\nimport java.io.File\nimport java.security.MessageDigest\n\n// I should move these classes/objects somew"
  },
  {
    "path": "buildSrc/src/main/kotlin/buildlogic/versioning/VersionUtil.kt",
    "chars": 1807,
    "preview": "package buildlogic.versioning\n\nimport io.github.z4kn4fein.semver.Version\nimport ir.amirab.util.platform.Platform\nimport "
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/composeAndroid.gradle.kts",
    "chars": 97,
    "preview": "package myPlugins\n\nplugins {\n    id(\"myPlugins.kotlinAndroid\")\n    id(\"myPlugins.composeBase\")\n}\n"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/composeBase.gradle.kts",
    "chars": 92,
    "preview": "package myPlugins\n\nplugins {\n    kotlin(\"plugin.compose\")\n    id(\"org.jetbrains.compose\")\n}\n"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/composeDesktop.gradle.kts",
    "chars": 200,
    "preview": "package myPlugins\n\nplugins {\n    id(\"myPlugins.kotlin\")\n    id(\"myPlugins.composeBase\")\n}\n\ndependencies {\n    api(compos"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/kotlin.gradle.kts",
    "chars": 609,
    "preview": "package myPlugins\n\nplugins {\n    kotlin(\"jvm\")\n}\nrepositories {\n    mavenCentral()\n    google()\n    maven(\"https://jitpa"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/kotlinAndroid.gradle.kts",
    "chars": 613,
    "preview": "package myPlugins\n\nplugins {\n    kotlin(\"android\")\n}\nrepositories {\n    mavenCentral()\n    google()\n    maven(\"https://j"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/kotlinMultiplatform.gradle.kts",
    "chars": 620,
    "preview": "package myPlugins\n\nplugins {\n    kotlin(\"multiplatform\")\n}\n\nrepositories {\n    mavenCentral()\n    google()\n    maven(\"ht"
  },
  {
    "path": "buildSrc/src/main/kotlin/myPlugins/proguardDesktop.gradle.kts",
    "chars": 2223,
    "preview": "package myPlugins\n\nimport org.jetbrains.compose.desktop.application.tasks.AbstractProguardTask\nimport java.util.zip.ZipF"
  },
  {
    "path": "compositeBuilds/plugins/common-android/build.gradle.kts",
    "chars": 254,
    "preview": "plugins {\n    `kotlin-dsl`\n}\nrepositories {\n    mavenCentral()\n    google()\n}\nversion = 1\ngroup = \"ir.amirab.plugin\"\ndep"
  },
  {
    "path": "compositeBuilds/plugins/common-android/src/main/kotlin/ir/amirab/plugin/common_android/task/EnableFileTypesGeneratorForManifest.kt",
    "chars": 1089,
    "preview": "package ir.amirab.plugin.common_android.task\n\nimport org.gradle.api.Action\nimport org.gradle.api.Project\nimport org.grad"
  },
  {
    "path": "compositeBuilds/plugins/common-android/src/main/kotlin/ir/amirab/plugin/common_android/task/FileTypesIntentFilterGenerator.kt",
    "chars": 2315,
    "preview": "package ir.amirab.plugin.common_android.task\n\nimport com.github.jknack.handlebars.Context\nimport com.github.jknack.handl"
  }
]

// ... and 854 more files (download for full content)

About this extraction

This page contains the full source code of the amir1376/ab-download-manager GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 1054 files (3.9 MB), approximately 1.1M tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!