├── .githooks
└── pre-commit
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── workflows
│ ├── publish.yml
│ └── web.yml
├── .gitignore
├── .metadata
├── .sdkmanrc
├── .vscode
├── launch.json
├── settings.json
└── sorayomi.code-snippets
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── analysis_options.yaml
├── android
├── .gitignore
├── app
│ ├── build.gradle
│ └── src
│ │ ├── debug
│ │ └── AndroidManifest.xml
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── kotlin
│ │ │ └── com
│ │ │ │ └── suwayomi
│ │ │ │ └── tachidesk_sorayomi
│ │ │ │ └── MainActivity.kt
│ │ └── res
│ │ │ ├── drawable-hdpi
│ │ │ ├── android12splash.png
│ │ │ ├── branding.png
│ │ │ └── splash.png
│ │ │ ├── drawable-mdpi
│ │ │ ├── android12splash.png
│ │ │ ├── branding.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night-hdpi
│ │ │ ├── android12splash.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night-mdpi
│ │ │ ├── android12splash.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night-v21
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-night-xhdpi
│ │ │ ├── android12splash.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night-xxhdpi
│ │ │ ├── android12splash.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night-xxxhdpi
│ │ │ ├── android12splash.png
│ │ │ └── splash.png
│ │ │ ├── drawable-night
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-v21
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── drawable-xhdpi
│ │ │ ├── android12splash.png
│ │ │ ├── branding.png
│ │ │ └── splash.png
│ │ │ ├── drawable-xxhdpi
│ │ │ ├── android12splash.png
│ │ │ ├── branding.png
│ │ │ └── splash.png
│ │ │ ├── drawable-xxxhdpi
│ │ │ ├── android12splash.png
│ │ │ ├── branding.png
│ │ │ └── splash.png
│ │ │ ├── drawable
│ │ │ ├── background.png
│ │ │ └── launch_background.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── launcher_icon.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── launcher_icon.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── launcher_icon.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── launcher_icon.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── launcher_icon.png
│ │ │ ├── values-night-v31
│ │ │ └── styles.xml
│ │ │ ├── values-night
│ │ │ └── styles.xml
│ │ │ ├── values-v31
│ │ │ └── styles.xml
│ │ │ ├── values
│ │ │ └── styles.xml
│ │ │ └── xml
│ │ │ └── network_security_config.xml
│ │ └── profile
│ │ └── AndroidManifest.xml
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
└── settings.gradle
├── assets
└── icons
│ ├── dark_icon.png
│ ├── launcher
│ ├── from_suwayomi.png
│ ├── ios_sorayomi_icon.png
│ ├── sorayomi_icon.ico
│ ├── sorayomi_icon.png
│ └── sorayomi_preview_icon.png
│ ├── light_icon.png
│ └── previous_done.png
├── build.yaml
├── devtools_options.yaml
├── graphql.config.yml
├── ios
├── .gitignore
├── Flutter
│ ├── AppFrameworkInfo.plist
│ ├── Debug.xcconfig
│ └── Release.xcconfig
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon-App-1024x1024@1x.png
│ │ ├── Icon-App-20x20@1x.png
│ │ ├── Icon-App-20x20@2x.png
│ │ ├── Icon-App-20x20@3x.png
│ │ ├── Icon-App-29x29@1x.png
│ │ ├── Icon-App-29x29@2x.png
│ │ ├── Icon-App-29x29@3x.png
│ │ ├── Icon-App-40x40@1x.png
│ │ ├── Icon-App-40x40@2x.png
│ │ ├── Icon-App-40x40@3x.png
│ │ ├── Icon-App-50x50@1x.png
│ │ ├── Icon-App-50x50@2x.png
│ │ ├── Icon-App-57x57@1x.png
│ │ ├── Icon-App-57x57@2x.png
│ │ ├── Icon-App-60x60@2x.png
│ │ ├── Icon-App-60x60@3x.png
│ │ ├── Icon-App-72x72@1x.png
│ │ ├── Icon-App-72x72@2x.png
│ │ ├── Icon-App-76x76@1x.png
│ │ ├── Icon-App-76x76@2x.png
│ │ └── Icon-App-83.5x83.5@2x.png
│ ├── BrandingImage.imageset
│ │ ├── BrandingImage.png
│ │ ├── BrandingImage@2x.png
│ │ ├── BrandingImage@3x.png
│ │ └── Contents.json
│ ├── LaunchBackground.imageset
│ │ ├── Contents.json
│ │ ├── background.png
│ │ └── darkbackground.png
│ └── LaunchImage.imageset
│ │ ├── Contents.json
│ │ ├── LaunchImage.png
│ │ ├── LaunchImage@2x.png
│ │ ├── LaunchImage@3x.png
│ │ ├── LaunchImageDark.png
│ │ ├── LaunchImageDark@2x.png
│ │ ├── LaunchImageDark@3x.png
│ │ └── README.md
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ └── Runner-Bridging-Header.h
├── l10n.yaml
├── lib
├── main.dart
└── src
│ ├── abstracts
│ ├── locale_enum.dart
│ └── value_enum.dart
│ ├── constants
│ ├── app_constants.dart
│ ├── app_sizes.dart
│ ├── db_keys.dart
│ ├── endpoints.dart
│ ├── enum.dart
│ ├── gen
│ │ └── assets.gen.dart
│ ├── language_list.dart
│ ├── navigation_bar_data.dart
│ ├── quick_open_help_text.dart
│ ├── reader_keyboard_shortcuts.dart
│ └── urls.dart
│ ├── features
│ ├── about
│ │ ├── data
│ │ │ ├── about_repository.dart
│ │ │ └── graphql
│ │ │ │ └── query.graphql
│ │ ├── domain
│ │ │ ├── about
│ │ │ │ ├── about_dto.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ └── server_update
│ │ │ │ ├── graphql
│ │ │ │ └── fragment.graphql
│ │ │ │ └── server_update.dart
│ │ └── presentation
│ │ │ └── about
│ │ │ ├── about_screen.dart
│ │ │ ├── controllers
│ │ │ └── about_controller.dart
│ │ │ └── widget
│ │ │ ├── app_update_dialog.dart
│ │ │ ├── clipboard_list_tile.dart
│ │ │ └── media_launch_button.dart
│ ├── browse_center
│ │ ├── data
│ │ │ ├── extension_repository
│ │ │ │ ├── extension_repository.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── query.graphql
│ │ │ └── source_repository
│ │ │ │ ├── graphql
│ │ │ │ └── query.graphql
│ │ │ │ └── source_repository.dart
│ │ ├── domain
│ │ │ ├── extension
│ │ │ │ ├── extension_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── filter
│ │ │ │ ├── filter_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── language
│ │ │ │ └── language_model.dart
│ │ │ ├── manga_page
│ │ │ │ ├── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ │ └── manga_page.dart
│ │ │ ├── source
│ │ │ │ ├── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ │ └── source_model.dart
│ │ │ └── source_preference
│ │ │ │ ├── graphql
│ │ │ │ └── fragment.graphql
│ │ │ │ └── source_preference.dart
│ │ └── presentation
│ │ │ ├── browse
│ │ │ └── browse_screen.dart
│ │ │ ├── extension
│ │ │ ├── controller
│ │ │ │ └── extension_controller.dart
│ │ │ ├── extension_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── extension_language_filter_dialog.dart
│ │ │ │ ├── extension_list_tile.dart
│ │ │ │ └── install_extension_file.dart
│ │ │ ├── global_search
│ │ │ ├── controller
│ │ │ │ └── source_quick_search_controller.dart
│ │ │ ├── global_search_screen.dart
│ │ │ └── widgets
│ │ │ │ └── source_short_search.dart
│ │ │ ├── source
│ │ │ ├── controller
│ │ │ │ └── source_controller.dart
│ │ │ ├── source_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── source_language_filter.dart
│ │ │ │ └── source_list_tile.dart
│ │ │ ├── source_manga_list
│ │ │ ├── controller
│ │ │ │ └── source_manga_controller.dart
│ │ │ ├── source_manga_list_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── filter_to_widget.dart
│ │ │ │ ├── source_manga_display_icon_popup.dart
│ │ │ │ ├── source_manga_display_view.dart
│ │ │ │ ├── source_manga_filter.dart
│ │ │ │ ├── source_manga_grid_view.dart
│ │ │ │ ├── source_manga_list_view.dart
│ │ │ │ └── source_type_selectable_chip.dart
│ │ │ └── source_preference
│ │ │ ├── controller
│ │ │ └── source_preference_controller.dart
│ │ │ ├── source_preference_screen.dart
│ │ │ └── widgets
│ │ │ └── source_preference_to_widget.dart
│ ├── library
│ │ ├── data
│ │ │ ├── category_repository.dart
│ │ │ └── graphql
│ │ │ │ └── query.graphql
│ │ ├── domain
│ │ │ └── category
│ │ │ │ ├── category_model.dart
│ │ │ │ └── graphql
│ │ │ │ └── fragment.graphql
│ │ └── presentation
│ │ │ ├── category
│ │ │ ├── controller
│ │ │ │ └── edit_category_controller.dart
│ │ │ ├── edit_category_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── category_create_fab.dart
│ │ │ │ ├── category_tile.dart
│ │ │ │ └── edit_category_dialog.dart
│ │ │ └── library
│ │ │ ├── category_manga_list.dart
│ │ │ ├── controller
│ │ │ └── library_controller.dart
│ │ │ ├── library_screen.dart
│ │ │ └── widgets
│ │ │ ├── library_manga_display.dart
│ │ │ ├── library_manga_filter.dart
│ │ │ ├── library_manga_organizer.dart
│ │ │ └── library_manga_sort_tile.dart
│ ├── manga_book
│ │ ├── data
│ │ │ ├── downloads
│ │ │ │ ├── downloads_repository.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── query.graphql
│ │ │ ├── manga_book
│ │ │ │ ├── manga_book_repository.dart
│ │ │ │ └── query.graphql
│ │ │ └── updates
│ │ │ │ ├── graphql
│ │ │ │ └── query.graphql
│ │ │ │ └── updates_repository.dart
│ │ ├── domain
│ │ │ ├── chapter
│ │ │ │ ├── chapter_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── chapter_batch
│ │ │ │ └── chapter_batch_model.dart
│ │ │ ├── chapter_page
│ │ │ │ ├── chapter_page_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── chapter_patch
│ │ │ │ └── chapter_put_model.dart
│ │ │ ├── downloads
│ │ │ │ ├── downloads_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── downloads_queue
│ │ │ │ ├── downloads_queue_model.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ ├── manga
│ │ │ │ ├── graphql
│ │ │ │ │ └── fragment.graphql
│ │ │ │ └── manga_model.dart
│ │ │ └── update_status
│ │ │ │ ├── graphql
│ │ │ │ └── fragment.graphql
│ │ │ │ └── update_status_model.dart
│ │ ├── presentation
│ │ │ ├── downloads
│ │ │ │ ├── controller
│ │ │ │ │ └── downloads_controller.dart
│ │ │ │ ├── downloads_screen.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── download_progress_list_tile.dart
│ │ │ │ │ └── downloads_fab.dart
│ │ │ ├── manga_details
│ │ │ │ ├── controller
│ │ │ │ │ └── manga_details_controller.dart
│ │ │ │ ├── manga_details_screen.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── big_screen_manga_details.dart
│ │ │ │ │ ├── chapter_list_tile.dart
│ │ │ │ │ ├── edit_manga_category_dialog.dart
│ │ │ │ │ ├── manga_chapter_filter.dart
│ │ │ │ │ ├── manga_chapter_organizer.dart
│ │ │ │ │ ├── manga_chapter_sort.dart
│ │ │ │ │ ├── manga_chapter_sort_tile.dart
│ │ │ │ │ ├── manga_description.dart
│ │ │ │ │ └── small_screen_manga_details.dart
│ │ │ ├── manga_thumbnail_viewer
│ │ │ │ └── manga_thumbnail_viewer.dart
│ │ │ ├── reader
│ │ │ │ ├── controller
│ │ │ │ │ └── reader_controller.dart
│ │ │ │ ├── reader_screen.dart
│ │ │ │ └── widgets
│ │ │ │ │ ├── chapter_separator.dart
│ │ │ │ │ ├── page_number_slider.dart
│ │ │ │ │ ├── reader_mode
│ │ │ │ │ ├── continuous_reader_mode.dart
│ │ │ │ │ └── single_page_reader_mode.dart
│ │ │ │ │ ├── reader_navigation_layout
│ │ │ │ │ ├── layouts
│ │ │ │ │ │ ├── edge_layout.dart
│ │ │ │ │ │ ├── kindlish_layout.dart
│ │ │ │ │ │ ├── l_shaped_layout.dart
│ │ │ │ │ │ └── right_and_left_layout.dart
│ │ │ │ │ └── reader_navigation_layout.dart
│ │ │ │ │ └── reader_wrapper.dart
│ │ │ └── updates
│ │ │ │ ├── updates_screen.dart
│ │ │ │ └── widgets
│ │ │ │ └── chapter_manga_list_tile.dart
│ │ └── widgets
│ │ │ ├── chapter_actions
│ │ │ ├── multi_chapters_action_icon.dart
│ │ │ ├── multi_chapters_actions_bottom_app_bar.dart
│ │ │ └── single_chapter_action_icon.dart
│ │ │ ├── download_status_icon.dart
│ │ │ ├── update_status_fab.dart
│ │ │ ├── update_status_popup_menu.dart
│ │ │ └── update_status_summary_sheet.dart
│ ├── quick_open
│ │ ├── domain
│ │ │ └── quick_search_result.dart
│ │ └── presentation
│ │ │ ├── quick_search
│ │ │ ├── controller
│ │ │ │ └── quick_search_controller.dart
│ │ │ ├── quick_search_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── category_query_list_tile.dart
│ │ │ │ ├── quick_query_result.dart
│ │ │ │ ├── quick_search_bar.dart
│ │ │ │ ├── search_result_to_widget.dart
│ │ │ │ └── source_query_list_tile.dart
│ │ │ └── search_stack
│ │ │ └── search_stack_screen.dart
│ └── settings
│ │ ├── controller
│ │ └── server_controller.dart
│ │ ├── data
│ │ ├── graphql
│ │ │ └── query.graphql
│ │ └── settings_repository.dart
│ │ ├── domain
│ │ └── settings
│ │ │ ├── graphql
│ │ │ └── fragment.graphql
│ │ │ └── settings.dart
│ │ ├── presentation
│ │ ├── appearance
│ │ │ ├── appearance_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── app_theme_selector
│ │ │ │ └── app_theme_selector.dart
│ │ │ │ ├── grid_cover_width_slider
│ │ │ │ └── grid_cover_width_slider.dart
│ │ │ │ └── is_true_black
│ │ │ │ └── is_true_black_tile.dart
│ │ ├── backup
│ │ │ ├── backup_screen.dart
│ │ │ ├── controllers
│ │ │ │ └── backup_controller.dart
│ │ │ ├── data
│ │ │ │ ├── backup_settings_repository.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── query.graphql
│ │ │ └── widgets
│ │ │ │ ├── automatic_backup
│ │ │ │ └── automatic_backup_section.dart
│ │ │ │ └── backup_and_restore
│ │ │ │ ├── backup_and_restore_section.dart
│ │ │ │ └── widgets
│ │ │ │ ├── backup_missing_dialog.dart
│ │ │ │ ├── create_backup_dialog.dart
│ │ │ │ └── restore_status_progress.dart
│ │ ├── browse
│ │ │ ├── browse_settings_screen.dart
│ │ │ ├── data
│ │ │ │ ├── browse_settings_repository.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── query.graphql
│ │ │ └── widgets
│ │ │ │ ├── extension_repository
│ │ │ │ └── extension_repository_screen.dart
│ │ │ │ └── show_nsfw_switch
│ │ │ │ └── show_nsfw_switch.dart
│ │ ├── downloads
│ │ │ ├── data
│ │ │ │ ├── downloads_settings_repository.dart
│ │ │ │ └── graphql
│ │ │ │ │ └── query.graphql
│ │ │ └── downloads_settings_screen.dart
│ │ ├── general
│ │ │ ├── general_screen.dart
│ │ │ └── quick_search_toggle
│ │ │ │ └── quick_search_toggle_tile.dart
│ │ ├── library
│ │ │ ├── data
│ │ │ │ ├── graphql
│ │ │ │ │ └── query.graphql
│ │ │ │ └── library_settings_repository.dart
│ │ │ ├── library_settings_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── hide_empty_category
│ │ │ │ └── hide_empty_category.dart
│ │ │ │ └── skip_updating_entries_popup.dart
│ │ ├── more
│ │ │ └── more_screen.dart
│ │ ├── reader
│ │ │ ├── reader_settings_screen.dart
│ │ │ └── widgets
│ │ │ │ ├── reader_initial_overlay_tile
│ │ │ │ └── reader_initial_overlay_tile.dart
│ │ │ │ ├── reader_invert_tap_tile
│ │ │ │ └── reader_invert_tap_tile.dart
│ │ │ │ ├── reader_magnifier_size_slider
│ │ │ │ └── reader_magnifier_size_slider.dart
│ │ │ │ ├── reader_mode_tile
│ │ │ │ └── reader_mode_tile.dart
│ │ │ │ ├── reader_navigation_layout_tile
│ │ │ │ └── reader_navigation_layout_tile.dart
│ │ │ │ ├── reader_padding_slider
│ │ │ │ └── reader_padding_slider.dart
│ │ │ │ ├── reader_pinch_to_zoom
│ │ │ │ └── reader_pinch_to_zoom.dart
│ │ │ │ ├── reader_scroll_animation_tile
│ │ │ │ └── reader_scroll_animation_tile.dart
│ │ │ │ ├── reader_swipe_toggle_tile
│ │ │ │ └── reader_swipe_chapter_toggle_tile.dart
│ │ │ │ ├── reader_volume_tap_invert_tile
│ │ │ │ └── reader_volume_tap_invert_tile.dart
│ │ │ │ └── reader_volume_tap_tile
│ │ │ │ └── reader_volume_tap_tile.dart
│ │ ├── server
│ │ │ ├── data
│ │ │ │ ├── graphql
│ │ │ │ │ └── query.graphql
│ │ │ │ └── server_settings_repository.dart
│ │ │ ├── server_screen.dart
│ │ │ └── widget
│ │ │ │ ├── authentication
│ │ │ │ ├── auth_type
│ │ │ │ │ └── auth_type_tile.dart
│ │ │ │ └── authentication_section.dart
│ │ │ │ ├── client
│ │ │ │ ├── client_section.dart
│ │ │ │ ├── server_port_tile
│ │ │ │ │ └── server_port_tile.dart
│ │ │ │ └── server_url_tile
│ │ │ │ │ ├── server_search_button.dart
│ │ │ │ │ └── server_url_tile.dart
│ │ │ │ ├── cloud_flare
│ │ │ │ └── cloud_flare_section.dart
│ │ │ │ ├── credential_popup
│ │ │ │ └── credentials_popup.dart
│ │ │ │ ├── misc_settings
│ │ │ │ └── misc_settings_section.dart
│ │ │ │ ├── server_binding
│ │ │ │ └── server_binding_section.dart
│ │ │ │ └── socks_proxy
│ │ │ │ └── socks_proxy_section.dart
│ │ └── settings
│ │ │ └── settings_screen.dart
│ │ └── widgets
│ │ ├── app_theme_mode_tile
│ │ └── app_theme_mode_tile.dart
│ │ └── slider_setting_tile
│ │ └── slider_setting_tile.dart
│ ├── global_providers
│ └── global_providers.dart
│ ├── graphql
│ ├── domain
│ │ └── page_info.dart
│ ├── fragments.graphql
│ └── schema.graphql
│ ├── l10n
│ ├── app_ar.arb
│ ├── app_de.arb
│ ├── app_en.arb
│ ├── app_es.arb
│ ├── app_fil.arb
│ ├── app_fr.arb
│ ├── app_id.arb
│ ├── app_it.arb
│ ├── app_ja.arb
│ ├── app_ko.arb
│ ├── app_nl.arb
│ ├── app_pt.arb
│ ├── app_pt_PT.arb
│ ├── app_ru.arb
│ ├── app_th.arb
│ ├── app_tr.arb
│ ├── app_uk.arb
│ ├── app_vi.arb
│ ├── app_zh.arb
│ ├── app_zh_Hans.arb
│ └── app_zh_Hant.arb
│ ├── routes
│ ├── router_config.dart
│ └── sub_routes
│ │ ├── browser_routes.dart
│ │ ├── common_routes.dart
│ │ ├── downloads_routes.dart
│ │ ├── library_routes.dart
│ │ ├── more_routes.dart
│ │ └── updates_routes.dart
│ ├── sorayomi.dart
│ ├── utils
│ ├── callbacks.dart
│ ├── extensions
│ │ ├── cache_manager_extensions.dart
│ │ ├── custom_extensions.dart
│ │ └── custom_extensions
│ │ │ ├── async_value_extensions.dart
│ │ │ ├── bool_extensions.dart
│ │ │ ├── context_extensions.dart
│ │ │ ├── date_time_extensions.dart
│ │ │ ├── double_extensions.dart
│ │ │ ├── generic_extensions.dart
│ │ │ ├── graphql_extensions.dart
│ │ │ ├── int_extensions.dart
│ │ │ ├── iterable_extensions.dart
│ │ │ ├── logger_extensions.dart
│ │ │ ├── map_extensions.dart
│ │ │ └── string_extensions.dart
│ ├── freezed_converters
│ │ └── language_json_converter.dart
│ ├── hooks
│ │ ├── paging_controller_hook.dart
│ │ └── polling_hook.dart
│ ├── launch_url_in_web.dart
│ ├── logger
│ │ ├── logger.dart
│ │ ├── logger_link.dart
│ │ └── provider_state_logger.dart
│ ├── misc
│ │ ├── app_utils.dart
│ │ ├── file_picker_utils.dart
│ │ ├── number_range_formatter.dart
│ │ ├── scalars.dart
│ │ └── toast
│ │ │ └── toast.dart
│ └── mixin
│ │ ├── shared_preferences_client_mixin.dart
│ │ └── state_provider_mixin.dart
│ └── widgets
│ ├── async_buttons
│ ├── async_checkbox_list_tile.dart
│ ├── async_elevated_button.dart
│ ├── async_list_tile.dart
│ ├── async_outline_button.dart
│ ├── async_text_button.dart
│ └── async_text_button_icon.dart
│ ├── custom_checkbox_list_tile.dart
│ ├── custom_circular_progress_indicator.dart
│ ├── emoticons.dart
│ ├── input_popup
│ ├── domain
│ │ └── settings_prop_type.dart
│ ├── settings_prop_pop_up.dart
│ ├── settings_prop_tile.dart
│ └── widgets
│ │ ├── number_picker_dialog.dart
│ │ ├── number_slider_dialog.dart
│ │ └── text_field_dialog.dart
│ ├── manga_cover
│ ├── grid
│ │ └── manga_cover_grid_tile.dart
│ ├── list
│ │ ├── manga_cover_descriptive_list_tile.dart
│ │ └── manga_cover_list_tile.dart
│ ├── providers
│ │ └── manga_cover_providers.dart
│ └── widgets
│ │ ├── manga_badges.dart
│ │ └── manga_chips.dart
│ ├── number_picker
│ ├── number_picker.dart
│ └── number_picker_with_label.dart
│ ├── popup_widgets
│ ├── multi_select_popup.dart
│ ├── pop_button.dart
│ ├── radio_list_popup.dart
│ ├── slider_popup.dart
│ └── text_field_popup.dart
│ ├── search_field.dart
│ ├── section_title.dart
│ ├── server_image.dart
│ ├── shell
│ ├── big_screen_navigation_bar.dart
│ ├── navigation_shell_screen.dart
│ └── small_screen_navigation_bar.dart
│ └── sort_list_tile.dart
├── linux
├── .gitignore
├── CMakeLists.txt
├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
├── main.cc
├── my_application.cc
└── my_application.h
├── macos
├── .gitignore
├── Flutter
│ ├── Flutter-Debug.xcconfig
│ ├── Flutter-Release.xcconfig
│ └── GeneratedPluginRegistrant.swift
├── Podfile
├── Podfile.lock
├── Runner.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ └── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── Runner.xcscheme
├── Runner.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── Runner
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── app_icon_1024.png
│ │ │ ├── app_icon_128.png
│ │ │ ├── app_icon_16.png
│ │ │ ├── app_icon_256.png
│ │ │ ├── app_icon_32.png
│ │ │ ├── app_icon_512.png
│ │ │ └── app_icon_64.png
│ ├── Base.lproj
│ │ └── MainMenu.xib
│ ├── Configs
│ │ ├── AppInfo.xcconfig
│ │ ├── Debug.xcconfig
│ │ ├── Release.xcconfig
│ │ └── Warnings.xcconfig
│ ├── DebugProfile.entitlements
│ ├── Info.plist
│ ├── MainFlutterWindow.swift
│ └── Release.entitlements
└── build
│ └── .last_build_id
├── pubspec.lock
├── pubspec.yaml
├── scripts
├── debian
│ ├── changelog
│ ├── control
│ ├── copyright
│ ├── install
│ ├── package.dirs
│ ├── rules
│ ├── source
│ │ ├── format
│ │ └── include-binaries
│ └── tachidesk-sorayomi.links
├── tachidesk-sorayomi-arm64.wxs
├── tachidesk-sorayomi-x64.wxs
└── tachidesk-sorayomi.desktop
├── web
├── favicon.png
├── icons
│ ├── Icon-192.png
│ ├── Icon-512.png
│ ├── Icon-maskable-192.png
│ └── Icon-maskable-512.png
├── index.html
├── manifest.json
└── splash
│ ├── img
│ ├── branding-1x.png
│ ├── branding-2x.png
│ ├── branding-3x.png
│ ├── branding-4x.png
│ ├── branding-dark-1x.png
│ ├── branding-dark-2x.png
│ ├── branding-dark-3x.png
│ ├── branding-dark-4x.png
│ ├── dark-1x.png
│ ├── dark-2x.png
│ ├── dark-3x.png
│ ├── dark-4x.png
│ ├── light-1x.png
│ ├── light-2x.png
│ ├── light-3x.png
│ └── light-4x.png
│ ├── splash.js
│ └── style.css
└── windows
├── .gitignore
├── CMakeLists.txt
├── flutter
├── CMakeLists.txt
├── generated_plugin_registrant.cc
├── generated_plugin_registrant.h
└── generated_plugins.cmake
└── runner
├── CMakeLists.txt
├── Runner.rc
├── flutter_window.cpp
├── flutter_window.h
├── main.cpp
├── resource.h
├── resources
└── app_icon.ico
├── runner.exe.manifest
├── utils.cpp
├── utils.h
├── win32_window.cpp
└── win32_window.h
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **PLEASE READ THIS**
11 |
12 | I acknowledge that:
13 |
14 | - I have updated to the latest version of the app.
15 | - I have tried the troubleshooting guide described in `README.md`
16 | - If this is a request for adding/changing an extension it should be brought up to Tachiyomi: https://github.com/tachiyomiorg/tachiyomi-extensions/issues/new/choose
17 | - If this is an issue with some extension not working properly, It does work in Tachiyomi application as intended.
18 | - I have searched the existing issues and this is a new ticket **NOT** a duplicate or related to another open issue
19 | - I will fill out the title and the information in this template
20 |
21 | Note that the issue will be automatically closed if you do not fill out the title or requested information.
22 |
23 | **DELETE THIS SECTION IF YOU HAVE READ AND ACKNOWLEDGED IT**
24 |
25 | ---
26 |
27 | **Is your feature request related to a problem? Please describe.**
28 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
29 |
30 | **Describe the solution you'd like**
31 | A clear and concise description of what you want to happen.
32 |
33 | **Describe alternatives you've considered**
34 | A clear and concise description of any alternative solutions or features you've considered.
35 |
36 | **Additional context**
37 | Add any other context or screenshots about the feature request here.
38 |
--------------------------------------------------------------------------------
/.github/workflows/web.yml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022 Contributors to the Suwayomi project
2 | #
3 | # This Source Code Form is subject to the terms of the Mozilla Public
4 | # License, v. 2.0. If a copy of the MPL was not distributed with this
5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | name: gh-Pages
8 |
9 | on:
10 | workflow_dispatch:
11 | push:
12 | tags:
13 | - "*.*.*"
14 |
15 | jobs:
16 | build:
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v3 # Only works with v2
21 | - uses: subosito/flutter-action@v2
22 | with:
23 | channel: 'stable'
24 |
25 | # Recreating the project
26 | - run: flutter doctor -v
27 | - uses: actions/checkout@v3
28 | # - run: flutter create .
29 | - run: flutter pub get
30 | - run: flutter gen-l10n
31 | - run: dart run build_runner build --delete-conflicting-outputs
32 |
33 | - uses: bluefireteam/flutter-gh-pages@v9
34 | with:
35 | baseHref: /Tachidesk-Sorayomi/
36 | webRenderer: canvaskit
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | lib/util_scripts
3 | sym_*
4 | *.class
5 | *.log
6 | *.pyc
7 | *.swp
8 | .DS_Store
9 | .atom/
10 | .build/
11 | .buildlog/
12 | .history
13 | .svn/
14 | .swiftpm/
15 | migrate_working_dir/
16 |
17 | # IntelliJ related
18 | *.iml
19 | *.ipr
20 | *.iws
21 | .idea/
22 |
23 | # The .vscode folder contains launch configuration and tasks you configure in
24 | # VS Code which you may wish to be included in version control, so this line
25 | # is commented out by default.
26 | #.vscode/
27 |
28 | # Flutter/Dart/Pub related
29 | **/doc/api/
30 | **/ios/Flutter/.last_build_id
31 | .dart_tool/
32 | .flutter-plugins
33 | .flutter-plugins-dependencies
34 | .packages
35 | .pub-cache/
36 | .pub/
37 | /build/
38 |
39 | # Symbolication related
40 | app.*.symbols
41 |
42 | # Obfuscation related
43 | app.*.map.json
44 |
45 | # Android Studio will place build artifacts here
46 | /android/app/debug
47 | /android/app/profile
48 | /android/app/release
49 |
50 |
51 | *.g.dart
52 | *.freezed.dart
53 | *.graphql.dart
54 | **/__generated__
55 | lib/src/l10n/generated
56 |
--------------------------------------------------------------------------------
/.sdkmanrc:
--------------------------------------------------------------------------------
1 | # Enable auto-env through the sdkman_auto_env config
2 | # Add key=value pairs of SDKs to use below
3 | java=17.0.13-zulu
4 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "tachidesk_sorayomi",
9 | "request": "launch",
10 | "type": "dart"
11 | },
12 | {
13 | "name": "tachidesk_sorayomi (profile mode)",
14 | "request": "launch",
15 | "type": "dart",
16 | "flutterMode": "profile"
17 | },
18 | {
19 | "name": "tachidesk_sorayomi (release mode)",
20 | "request": "launch",
21 | "type": "dart",
22 | "flutterMode": "release"
23 | }
24 | ]
25 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "cSpell.words": [
3 | "behaviour",
4 | "canonicalized",
5 | "Compat",
6 | "dattatreya",
7 | "Gdefault",
8 | "Gupdate",
9 | "Gvalues",
10 | "horiz",
11 | "keydown",
12 | "kindlish",
13 | "localsourcelang",
14 | "Mangas",
15 | "metas",
16 | "microtask",
17 | "phonelink",
18 | "proto",
19 | "pubspec",
20 | "readmore",
21 | "reddy",
22 | "Scanlator",
23 | "scanlators",
24 | "Solverr",
25 | "sublist",
26 | "suwayomi",
27 | "tachidesk",
28 | "Tachiyomi",
29 | "tekartik",
30 | "vals",
31 | "Webtoon",
32 | "webtoons",
33 | "WEBUI"
34 | ],
35 | "licenser.license": "MPLv2",
36 | "licenser.projectName": "Tachidesk-Sorayomi",
37 | "licenser.author": "Contributors to the Suwayomi project",
38 | "editor.wordSeparators": "`~!@#%^&*()-=+[{]}\\|;:'\",.<>/?",
39 | "files.exclude": {
40 | // "**/__generated__": true,
41 | // "**/*.graphql.dart": true,
42 | // "**/*.freezed.dart": true,
43 | "**/*.g.dart": true,
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/.vscode/sorayomi.code-snippets:
--------------------------------------------------------------------------------
1 | {
2 | // Place your sorayomi workspace snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and
3 | // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope
4 | // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is
5 | // used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
6 | // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
7 | // Placeholders with the same ids are connected.
8 | // Example:
9 | "Basic Dart Graphql Query Request": {
10 | "scope": "dart",
11 | "prefix": "req",
12 | "body": [
13 | "static G${1:query}Req ${1/^(.)(.*)$/${1:/downcase}${2}/}() => G${1:query}Req();"
14 | ],
15 | "description": "Creates graphql query",
16 | },
17 | }
18 |
--------------------------------------------------------------------------------
/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 | **/*.keystore
13 | **/*.jks
14 |
--------------------------------------------------------------------------------
/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/app/src/main/kotlin/com/suwayomi/tachidesk_sorayomi/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.suwayomi.tachidesk_sorayomi
2 |
3 | import io.flutter.embedding.android.FlutterActivity
4 |
5 | import dev.darttools.flutter_android_volume_keydown.FlutterAndroidVolumeKeydownActivity;
6 |
7 | class MainActivity: FlutterAndroidVolumeKeydownActivity() {
8 | }
9 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-hdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/branding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-hdpi/branding.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-mdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/branding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-mdpi/branding.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-hdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-hdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-hdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-hdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-mdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-mdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-mdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-mdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xxhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xxxhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-night/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-night/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-v21/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/branding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xhdpi/branding.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/branding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxhdpi/branding.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/android12splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxxhdpi/android12splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/branding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxxhdpi/branding.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable-xxxhdpi/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable-xxxhdpi/splash.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/drawable/background.png
--------------------------------------------------------------------------------
/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 | -
7 |
8 |
9 | -
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-hdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-hdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-mdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-mdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values-v31/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
19 |
22 |
23 |
--------------------------------------------------------------------------------
/android/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 | allprojects {
2 | repositories {
3 | google()
4 | mavenCentral()
5 | }
6 | }
7 |
8 | rootProject.buildDir = '../build'
9 | subprojects {
10 | project.buildDir = "${rootProject.buildDir}/${project.name}"
11 | }
12 | subprojects {
13 | project.evaluationDependsOn(':app')
14 | }
15 |
16 | tasks.register("clean", Delete) {
17 | delete rootProject.buildDir
18 | }
19 |
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx1536M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/android/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | def flutterSdkPath = {
3 | def properties = new Properties()
4 | file("local.properties").withInputStream { properties.load(it) }
5 | def flutterSdkPath = properties.getProperty("flutter.sdk")
6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
7 | return flutterSdkPath
8 | }
9 | settings.ext.flutterSdkPath = flutterSdkPath()
10 |
11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle")
12 |
13 | repositories {
14 | google()
15 | mavenCentral()
16 | gradlePluginPortal()
17 | }
18 | }
19 |
20 | plugins {
21 | id "dev.flutter.flutter-plugin-loader" version "1.0.0"
22 | id "com.android.application" version "8.8.0" apply false
23 | id "org.jetbrains.kotlin.android" version "2.1.10" apply false
24 | id "com.google.gms.google-services" version "4.4.0" apply false
25 | id "com.google.firebase.crashlytics" version "2.9.9" apply false
26 | }
27 |
28 | include ":app"
29 |
--------------------------------------------------------------------------------
/assets/icons/dark_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/dark_icon.png
--------------------------------------------------------------------------------
/assets/icons/launcher/from_suwayomi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/launcher/from_suwayomi.png
--------------------------------------------------------------------------------
/assets/icons/launcher/ios_sorayomi_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/launcher/ios_sorayomi_icon.png
--------------------------------------------------------------------------------
/assets/icons/launcher/sorayomi_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/launcher/sorayomi_icon.ico
--------------------------------------------------------------------------------
/assets/icons/launcher/sorayomi_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/launcher/sorayomi_icon.png
--------------------------------------------------------------------------------
/assets/icons/launcher/sorayomi_preview_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/launcher/sorayomi_preview_icon.png
--------------------------------------------------------------------------------
/assets/icons/light_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/light_icon.png
--------------------------------------------------------------------------------
/assets/icons/previous_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/assets/icons/previous_done.png
--------------------------------------------------------------------------------
/build.yaml:
--------------------------------------------------------------------------------
1 | targets:
2 | $default:
3 | builders:
4 | json_serializable:
5 | options:
6 | explicit_to_json: true
7 | graphql_codegen:
8 | options:
9 | addTypenameExcludedPaths:
10 | - subscription
11 | outputDirectory: __generated__
12 | clients:
13 | - graphql
14 | - graphql_flutter
15 | scalars:
16 | ISODateTime:
17 | type: DateTime
18 | JSON:
19 | type: Map
20 | Upload:
21 | type: MultipartFile
22 | fromJsonFunctionName: fileFromJson
23 | toJsonFunctionName: fileToJson
24 | import: package:tachidesk_sorayomi/src/utils/misc/scalars.dart
25 | LongString:
26 | type: String
27 | fromJsonFunctionName: longStringFromJson
28 | toJsonFunctionName: longStringToJson
29 | import: package:tachidesk_sorayomi/src/utils/misc/scalars.dart
30 | Cursor:
31 | type: int
32 | fromJsonFunctionName: cursorFromJson
33 | toJsonFunctionName: cursorToJson
34 | import: package:tachidesk_sorayomi/src/utils/misc/scalars.dart
35 |
--------------------------------------------------------------------------------
/devtools_options.yaml:
--------------------------------------------------------------------------------
1 | description: This file stores settings for Dart & Flutter DevTools.
2 | documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3 | extensions:
4 |
--------------------------------------------------------------------------------
/graphql.config.yml:
--------------------------------------------------------------------------------
1 | schema: "lib/src/graphql/schema.graphql"
2 | documents: "lib/**/*.{graphql,js,ts,jsx,tsx}"
3 |
--------------------------------------------------------------------------------
/ios/.gitignore:
--------------------------------------------------------------------------------
1 | **/dgph
2 | *.mode1v3
3 | *.mode2v3
4 | *.moved-aside
5 | *.pbxuser
6 | *.perspectivev3
7 | **/*sync/
8 | .sconsign.dblite
9 | .tags*
10 | **/.vagrant/
11 | **/DerivedData/
12 | Icon?
13 | **/Pods/
14 | **/.symlinks/
15 | profile
16 | xcuserdata
17 | **/.generated/
18 | Flutter/App.framework
19 | Flutter/Flutter.framework
20 | Flutter/Flutter.podspec
21 | Flutter/Generated.xcconfig
22 | Flutter/ephemeral/
23 | Flutter/app.flx
24 | Flutter/app.zip
25 | Flutter/flutter_assets/
26 | Flutter/flutter_export_environment.sh
27 | ServiceDefinitions.json
28 | Runner/GeneratedPluginRegistrant.*
29 |
30 | # Exceptions to above rules.
31 | !default.mode1v3
32 | !default.mode2v3
33 | !default.pbxuser
34 | !default.perspectivev3
35 |
--------------------------------------------------------------------------------
/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | App
9 | CFBundleIdentifier
10 | io.flutter.flutter.app
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | App
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1.0
23 | MinimumOSVersion
24 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Flutter/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment this line to define a global platform for your project
2 | # platform :ios, '11.0'
3 |
4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6 |
7 | project 'Runner', {
8 | 'Debug' => :debug,
9 | 'Profile' => :release,
10 | 'Release' => :release,
11 | }
12 |
13 | def flutter_root
14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15 | unless File.exist?(generated_xcode_build_settings_path)
16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17 | end
18 |
19 | File.foreach(generated_xcode_build_settings_path) do |line|
20 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
21 | return matches[1].strip if matches
22 | end
23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24 | end
25 |
26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27 |
28 | flutter_ios_podfile_setup
29 |
30 | target 'Runner' do
31 | use_frameworks!
32 | use_modular_headers!
33 |
34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35 | end
36 |
37 | post_install do |installer|
38 | installer.pods_project.targets.each do |target|
39 | flutter_additional_ios_build_settings(target)
40 | end
41 | end
42 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/BrandingImage.imageset/BrandingImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/BrandingImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "BrandingImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "BrandingImage@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "BrandingImage@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "background.png",
5 | "idiom" : "universal"
6 | },
7 | {
8 | "appearances" : [
9 | {
10 | "appearance" : "luminosity",
11 | "value" : "dark"
12 | }
13 | ],
14 | "filename" : "darkbackground.png",
15 | "idiom" : "universal"
16 | }
17 | ],
18 | "info" : {
19 | "author" : "xcode",
20 | "version" : 1
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchBackground.imageset/darkbackground.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "LaunchImage.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "appearances" : [
10 | {
11 | "appearance" : "luminosity",
12 | "value" : "dark"
13 | }
14 | ],
15 | "filename" : "LaunchImageDark.png",
16 | "idiom" : "universal",
17 | "scale" : "1x"
18 | },
19 | {
20 | "filename" : "LaunchImage@2x.png",
21 | "idiom" : "universal",
22 | "scale" : "2x"
23 | },
24 | {
25 | "appearances" : [
26 | {
27 | "appearance" : "luminosity",
28 | "value" : "dark"
29 | }
30 | ],
31 | "filename" : "LaunchImageDark@2x.png",
32 | "idiom" : "universal",
33 | "scale" : "2x"
34 | },
35 | {
36 | "filename" : "LaunchImage@3x.png",
37 | "idiom" : "universal",
38 | "scale" : "3x"
39 | },
40 | {
41 | "appearances" : [
42 | {
43 | "appearance" : "luminosity",
44 | "value" : "dark"
45 | }
46 | ],
47 | "filename" : "LaunchImageDark@3x.png",
48 | "idiom" : "universal",
49 | "scale" : "3x"
50 | }
51 | ],
52 | "info" : {
53 | "author" : "xcode",
54 | "version" : 1
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@2x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImageDark@3x.png
--------------------------------------------------------------------------------
/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md:
--------------------------------------------------------------------------------
1 | # Launch Screen Assets
2 |
3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory.
4 |
5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
--------------------------------------------------------------------------------
/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
2 |
--------------------------------------------------------------------------------
/l10n.yaml:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2023 Contributors to the Suwayomi project
2 | #
3 | # This Source Code Form is subject to the terms of the Mozilla Public
4 | # License, v. 2.0. If a copy of the MPL was not distributed with this
5 | # file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | synthetic-package: false
8 | arb-dir: lib/src/l10n
9 | template-arb-file: app_en.arb
10 | output-localization-file: app_localizations.dart
11 | output-dir: lib/src/l10n/generated
12 |
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter/services.dart';
9 | import 'package:go_router/go_router.dart';
10 | import 'package:graphql_flutter/graphql_flutter.dart';
11 | import 'package:hooks_riverpod/hooks_riverpod.dart';
12 | import 'package:package_info_plus/package_info_plus.dart';
13 | import 'package:shared_preferences/shared_preferences.dart';
14 |
15 | import 'src/features/about/presentation/about/controllers/about_controller.dart';
16 | import 'src/global_providers/global_providers.dart';
17 | import 'src/sorayomi.dart';
18 |
19 | Future main() async {
20 | WidgetsFlutterBinding.ensureInitialized();
21 | final packageInfo = await PackageInfo.fromPlatform();
22 | final sharedPreferences = await SharedPreferences.getInstance();
23 | await initHiveForFlutter();
24 |
25 | SystemChrome.setPreferredOrientations(DeviceOrientation.values);
26 | GoRouter.optionURLReflectsImperativeAPIs = true;
27 | runApp(
28 | ProviderScope(
29 | overrides: [
30 | packageInfoProvider.overrideWithValue(packageInfo),
31 | sharedPreferencesProvider.overrideWithValue(sharedPreferences),
32 | hiveStoreProvider.overrideWithValue(HiveStore())
33 | ],
34 | child: const Sorayomi(),
35 | ),
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/abstracts/locale_enum.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'value_enum.dart';
4 |
5 | abstract interface class LocaleEnum implements ValueEnum {
6 | LocaleEnum(this.value);
7 |
8 | @override
9 | final String value;
10 |
11 | String toLocale(BuildContext context);
12 | }
13 |
--------------------------------------------------------------------------------
/lib/src/abstracts/value_enum.dart:
--------------------------------------------------------------------------------
1 | abstract interface class ValueEnum implements Enum {
2 | ValueEnum(this.value);
3 |
4 | final String value;
5 | }
6 |
--------------------------------------------------------------------------------
/lib/src/constants/app_constants.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | const Duration kDuration = Duration(milliseconds: 500);
10 | const Duration kInstantDuration = Duration(microseconds: 1);
11 | const Duration kLongDuration = Duration(seconds: 2);
12 |
13 | const Curve kCurve = Curves.easeIn;
14 | const Size kMagnifierSize = Size(77.37, 37.9);
15 | const MagnifierDecoration kMagnifierDecoration = MagnifierDecoration(
16 | shape: RoundedRectangleBorder(
17 | borderRadius: BorderRadius.all(Radius.circular(40))),
18 | shadows: [
19 | BoxShadow(
20 | blurRadius: 1.5,
21 | offset: Offset(0, 2),
22 | spreadRadius: 0.75,
23 | color: Color.fromARGB(25, 0, 0, 0))
24 | ],
25 | );
26 |
27 | const kDebounceDuration = Duration(milliseconds: 500);
28 |
29 | const kPositionPlaceholder = -1;
30 |
--------------------------------------------------------------------------------
/lib/src/constants/navigation_bar_data.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../utils/extensions/custom_extensions.dart';
10 |
11 | class NavigationBarData {
12 | final String Function(BuildContext context) label;
13 | final IconData icon;
14 | final IconData activeIcon;
15 | static final navList = [
16 | NavigationBarData(
17 | icon: Icons.collections_bookmark_outlined,
18 | activeIcon: Icons.collections_bookmark_rounded,
19 | label: (context) => context.l10n.library,
20 | ),
21 | NavigationBarData(
22 | icon: Icons.new_releases_outlined,
23 | activeIcon: Icons.new_releases_rounded,
24 | label: (context) => context.l10n.updates,
25 | ),
26 | NavigationBarData(
27 | icon: Icons.explore_outlined,
28 | activeIcon: Icons.explore_rounded,
29 | label: (context) => context.l10n.browse,
30 | ),
31 | NavigationBarData(
32 | icon: Icons.download_outlined,
33 | activeIcon: Icons.download_rounded,
34 | label: (context) => context.l10n.downloads,
35 | ),
36 | NavigationBarData(
37 | icon: Icons.more_horiz_outlined,
38 | activeIcon: Icons.more_horiz_rounded,
39 | label: (context) => context.l10n.more,
40 | ),
41 | ];
42 |
43 | NavigationBarData({
44 | required this.label,
45 | required this.icon,
46 | required this.activeIcon,
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/lib/src/constants/quick_open_help_text.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../features/quick_open/domain/quick_search_result.dart';
10 | import '../utils/extensions/custom_extensions.dart';
11 |
12 | List getQuickShowHintTextList(BuildContext context) {
13 | return [
14 | QuickSearchResult.helpText(
15 | prefill: '@S',
16 | pattern: '@',
17 | hintText: context.l10n.quickSearchSource,
18 | ),
19 | QuickSearchResult.helpText(
20 | prefill: '@S/M',
21 | pattern: '@/',
22 | hintText: context.l10n.quickSearchSourceManga,
23 | ),
24 | QuickSearchResult.helpText(
25 | prefill: '#C',
26 | pattern: '#',
27 | hintText: context.l10n.quickSearchCategory,
28 | ),
29 | QuickSearchResult.helpText(
30 | prefill: '#C/M',
31 | pattern: '#/',
32 | hintText: context.l10n.quickSearchCategoryManga,
33 | ),
34 | QuickSearchResult.helpText(
35 | prefill: '#C/M:CN',
36 | pattern: '#/:',
37 | hintText: context.l10n.quickSearchCategoryMangaChapter,
38 | ),
39 | QuickSearchResult.helpText(
40 | prefill: 'X',
41 | hintText: context.l10n.quickSearchContext,
42 | ),
43 | ];
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/constants/urls.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | enum AppUrls {
8 | sorayomiGithubUrl(url: "https://github.com/Suwayomi/Tachidesk-Sorayomi"),
9 | sorayomiLatestReleaseUrl(
10 | url: "https://github.com/Suwayomi/Tachidesk-Sorayomi/releases/latest"),
11 | tachideskHelp(url: "https://github.com/Suwayomi/suwayomi-Server/wiki"),
12 | tachideskReddit(url: "https://www.reddit.com/r/Tachidesk"),
13 | sorayomiWhatsNew(
14 | url: "https://github.com/Suwayomi/Tachidesk-Sorayomi/releases/tag/"),
15 | sorayomiLatestReleaseApiUrl(
16 | url:
17 | "https://api.github.com/repos/Suwayomi/Tachidesk-Sorayomi/releases/latest",
18 | ),
19 | flareSolverr(
20 | url:
21 | "https://github.com/FlareSolverr/FlareSolverr?tab=readme-ov-file#installation");
22 |
23 | const AppUrls({required this.url});
24 |
25 | final String url;
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/features/about/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | query GetServerUpdate {
5 | checkForServerUpdates {
6 | ...ServerUpdateDto
7 | }
8 | }
9 |
10 | query GetAbout {
11 | aboutServer {
12 | ...AboutDto
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/features/about/domain/about/about_dto.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'graphql/__generated__/fragment.graphql.dart';
8 |
9 | typedef AboutDto = Fragment$AboutDto;
10 |
--------------------------------------------------------------------------------
/lib/src/features/about/domain/about/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment AboutDto on AboutServerPayload {
2 | buildTime
3 | buildType
4 | discord
5 | github
6 | name
7 | revision
8 | version
9 | }
10 |
--------------------------------------------------------------------------------
/lib/src/features/about/domain/server_update/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 | fragment ServerUpdateDto on CheckForServerUpdatesPayload {
3 | channel
4 | tag
5 | url
6 | }
7 |
--------------------------------------------------------------------------------
/lib/src/features/about/domain/server_update/server_update.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:freezed_annotation/freezed_annotation.dart';
8 |
9 | import 'graphql/__generated__/fragment.graphql.dart';
10 |
11 | part 'server_update.freezed.dart';
12 |
13 | @freezed
14 | class ServerUpdate with _$ServerUpdate {
15 | factory ServerUpdate({
16 | String? channel,
17 | String? tag,
18 | String? url,
19 | }) = _ServerUpdate;
20 | }
21 |
22 | extension ServerUpdateConverter on Fragment$ServerUpdateDto {
23 | ServerUpdate get toDto => ServerUpdate(channel: channel, tag: tag, url: url);
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/features/about/presentation/about/controllers/about_controller.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'dart:async';
8 |
9 | import 'package:hooks_riverpod/hooks_riverpod.dart';
10 | import 'package:package_info_plus/package_info_plus.dart';
11 | import 'package:riverpod_annotation/riverpod_annotation.dart';
12 |
13 | import '../../../data/about_repository.dart';
14 | import '../../../domain/about/about_dto.dart';
15 |
16 | part 'about_controller.g.dart';
17 |
18 | @riverpod
19 | Future about(Ref ref) =>
20 | ref.watch(aboutRepositoryProvider).getAbout();
21 |
22 | @riverpod
23 | PackageInfo packageInfo(ref) => throw UnimplementedError();
24 |
--------------------------------------------------------------------------------
/lib/src/features/about/presentation/about/widget/clipboard_list_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter/services.dart';
9 | import 'package:hooks_riverpod/hooks_riverpod.dart';
10 |
11 | import '../../../../../utils/extensions/custom_extensions.dart';
12 | import '../../../../../utils/misc/toast/toast.dart';
13 |
14 | class ClipboardListTile extends ConsumerWidget {
15 | const ClipboardListTile({
16 | super.key,
17 | required this.title,
18 | required this.value,
19 | });
20 | final String title;
21 | final String? value;
22 | @override
23 | Widget build(BuildContext context, WidgetRef ref) => ListTile(
24 | title: Text(title),
25 | subtitle: value.isNotBlank ? Text(value!) : null,
26 | onTap: value.isNotBlank
27 | ? () {
28 | final msg = "$title: $value";
29 | Clipboard.setData(ClipboardData(text: msg));
30 | ref
31 | .read(toastProvider)
32 | ?.show(context.l10n.copyMsg(msg), instantShow: true);
33 | }
34 | : null,
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/about/presentation/about/widget/media_launch_button.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../../../../../utils/extensions/custom_extensions.dart';
10 | import '../../../../../utils/launch_url_in_web.dart';
11 | import '../../../../../utils/misc/toast/toast.dart';
12 |
13 | class MediaLaunchButton extends StatelessWidget {
14 | const MediaLaunchButton({
15 | super.key,
16 | required this.toast,
17 | required this.title,
18 | required this.iconData,
19 | required this.url,
20 | });
21 |
22 | final Toast? toast;
23 | final String title;
24 | final IconData iconData;
25 | final String url;
26 |
27 | @override
28 | Widget build(BuildContext context) {
29 | return url.isNotBlank
30 | ? context.isSmallTabletOrLess
31 | ? IconButton(
32 | tooltip: title,
33 | onPressed: () => launchUrlInWeb(context, url, toast),
34 | icon: Icon(iconData),
35 | )
36 | : TextButton.icon(
37 | label: Text(title),
38 | onPressed: () => launchUrlInWeb(context, url, toast),
39 | icon: Icon(iconData),
40 | )
41 | : const SizedBox.shrink();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/data/extension_repository/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | mutation UpdateExtension($id: String!, $install: Boolean = false, $uninstall: Boolean = false, $update: Boolean = false) {
4 | updateExtension(
5 | input: {id: $id, patch: {install: $install, uninstall: $uninstall, update: $update}}
6 | ) {
7 | clientMutationId
8 | extension {
9 | ...ExtensionDto
10 | }
11 | }
12 | }
13 |
14 | mutation InstallExternalExtension($extensionFile: Upload!) {
15 | installExternalExtension(input: {extensionFile: $extensionFile}) {
16 | clientMutationId
17 | extension {
18 | ...ExtensionDto
19 | }
20 | }
21 | }
22 |
23 | mutation FetchExtensionList {
24 | fetchExtensions(input: {}) {
25 | clientMutationId
26 | extensions {
27 | ...ExtensionDto
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/data/source_repository/graphql/query.graphql:
--------------------------------------------------------------------------------
1 | query SourceList {
2 | sources {
3 | nodes {
4 | ...SourceDto
5 | }
6 | }
7 | }
8 |
9 | query SourceFilterById($id: LongString!) {
10 | source(id: $id) {
11 | filters {
12 | ...FilterDto
13 | }
14 | }
15 | }
16 |
17 | query SourceById($id: LongString!) {
18 | source(id: $id) {
19 | ...SourceDto
20 | }
21 | }
22 |
23 | mutation FetchSourceManga($input: FetchSourceMangaInput!) {
24 | fetchSourceManga(input: $input) {
25 | ...SourceMangaPage
26 | }
27 | }
28 |
29 | query SourcePreferenceById($id: LongString!) {
30 | source(id: $id) {
31 | preferences {
32 | ...SourcePreference
33 | }
34 | }
35 | }
36 |
37 | mutation UpdateSourcePreference($input: UpdateSourcePreferenceInput!) {
38 | updateSourcePreference(input: $input) {
39 | __typename
40 | preferences {
41 | ...SourcePreference
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/extension/extension_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../../../utils/freezed_converters/language_json_converter.dart';
8 | import '../language/language_model.dart';
9 | import 'graphql/__generated__/fragment.graphql.dart';
10 |
11 | typedef Extension = Fragment$ExtensionDto;
12 |
13 | extension ExtensionExtensions on Extension {
14 | Language? get language => LanguageJsonConverter.fromJson(lang);
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/extension/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 | fragment ExtensionDto on ExtensionType {
3 | apkName
4 | hasUpdate
5 | iconUrl
6 | isInstalled
7 | isNsfw
8 | isObsolete
9 | lang
10 | name
11 | pkgName
12 | repo
13 | versionCode
14 | versionName
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/filter/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 | fragment PrimitiveFilterDto on Filter {
3 | __typename
4 | ... on CheckBoxFilter {
5 | __typename
6 | checkBoxState: default
7 | name
8 | }
9 | ... on HeaderFilter {
10 | __typename
11 | name
12 | }
13 | ... on SelectFilter {
14 | __typename
15 | selectState: default
16 | name
17 | displayValues: values
18 | }
19 | ... on TriStateFilter {
20 | __typename
21 | tristate: default
22 | name
23 | }
24 | ... on TextFilter {
25 | __typename
26 | textState: default
27 | name
28 | }
29 | ... on SortFilter {
30 | __typename
31 | sortState: default {
32 | ...SortSelectionDto
33 | }
34 | name
35 | displayValues: values
36 | }
37 | ... on SeparatorFilter {
38 | __typename
39 | name
40 | }
41 | }
42 | fragment FilterDto on Filter {
43 | ...PrimitiveFilterDto
44 | ... on GroupFilter {
45 | __typename
46 | name
47 | groupState: filters {
48 | ...PrimitiveFilterDto
49 | }
50 | }
51 | }
52 |
53 | fragment SortSelectionDto on SortSelection {
54 | ascending
55 | index
56 | }
57 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/language/language_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:freezed_annotation/freezed_annotation.dart';
8 |
9 | part 'language_model.freezed.dart';
10 | part 'language_model.g.dart';
11 |
12 | @freezed
13 | class Language with _$Language {
14 | Language._();
15 | factory Language({
16 | String? code,
17 | String? name,
18 | String? nativeName,
19 | }) = _Language;
20 |
21 | String? get displayName => nativeName ?? name ?? code;
22 |
23 | factory Language.fromJson(Map json) =>
24 | _$LanguageFromJson(json);
25 | }
26 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/manga_page/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment SourceMangaPage on FetchSourceMangaPayload {
2 | hasNextPage
3 | mangas {
4 | ...MangaDto
5 | }
6 | }
7 |
8 | fragment MangaPageDto on MangaNodeList {
9 | nodes {
10 | ...MangaDto
11 | }
12 | pageInfo {
13 | ...PageInfoDto
14 | }
15 | totalCount
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/manga_page/manga_page.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'graphql/__generated__/fragment.graphql.dart';
8 |
9 | typedef MangaPage = Fragment$SourceMangaPage;
10 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/source/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment SourceDto on SourceType {
2 | displayName
3 | iconUrl
4 | id
5 | isConfigurable
6 | isNsfw
7 | lang
8 | name
9 | supportsLatest
10 | extension {
11 | pkgName
12 | repo
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/source_preference/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment SourcePreference on Preference {
2 | __typename
3 | ... on CheckBoxPreference {
4 | checkBoxValue: currentValue
5 | summary
6 | checkBoxDefaultValue: default
7 | key
8 | checkBoxTitle: title
9 | }
10 | ... on EditTextPreference {
11 | editTextValue: currentValue
12 | EditTextDefaultValue: default
13 | editTextTitle: title
14 | text
15 | summary
16 | key
17 | dialogTitle
18 | dialogMessage
19 | }
20 | ... on SwitchPreference {
21 | switchValue: currentValue
22 | summary
23 | key
24 | switchDefaultValue: default
25 | switchTitle: title
26 | }
27 | ... on MultiSelectListPreference {
28 | dialogMessage
29 | dialogTitle
30 | multiSelectTitle: title
31 | summary
32 | key
33 | entryValues
34 | entries
35 | multiSelectDefaultValue: default
36 | multiSelectValue:currentValue
37 | }
38 | ... on ListPreference {
39 | listValue:currentValue
40 | listDefaultValue: default
41 | listTitle: title
42 | summary
43 | key
44 | entryValues
45 | entries
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/domain/source_preference/source_preference.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../../../graphql/__generated__/schema.graphql.dart';
8 | import 'graphql/__generated__/fragment.graphql.dart';
9 |
10 | typedef SourcePreference = Fragment$SourcePreference;
11 |
12 | typedef CheckBoxPreference = Fragment$SourcePreference$$CheckBoxPreference;
13 |
14 | typedef SwitchPreferenceCompat = Fragment$SourcePreference$$SwitchPreference;
15 |
16 | typedef ListPreference = Fragment$SourcePreference$$ListPreference;
17 |
18 | typedef MultiSelectListPreference
19 | = Fragment$SourcePreference$$MultiSelectListPreference;
20 |
21 | typedef EditTextPreference = Fragment$SourcePreference$$EditTextPreference;
22 |
23 | typedef SourcePreferenceChange = Input$SourcePreferenceChangeInput;
24 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/presentation/source_manga_list/controller/source_manga_controller.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:hooks_riverpod/hooks_riverpod.dart';
8 | import 'package:riverpod_annotation/riverpod_annotation.dart';
9 |
10 | import '../../../../../constants/db_keys.dart';
11 | import '../../../../../constants/enum.dart';
12 | import '../../../../../utils/mixin/shared_preferences_client_mixin.dart';
13 | import '../../../data/source_repository/source_repository.dart';
14 | import '../../../domain/filter/filter_model.dart';
15 | import '../../../domain/source/source_model.dart';
16 |
17 | part 'source_manga_controller.g.dart';
18 |
19 | @riverpod
20 | Future source(Ref ref, String sourceId) =>
21 | ref.watch(sourceRepositoryProvider).getSource(sourceId);
22 |
23 | @riverpod
24 | Future?> baseSourceMangaFilterList(Ref ref, String sourceId) =>
25 | ref.read(sourceRepositoryProvider).getSourceFilter(sourceId);
26 |
27 | @riverpod
28 | class SourceDisplayMode extends _$SourceDisplayMode
29 | with SharedPreferenceEnumClientMixin {
30 | @override
31 | DisplayMode? build() => initialize(
32 | DBKeys.sourceDisplayMode,
33 | enumList: DisplayMode.sourceDisplayList,
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/presentation/source_manga_list/widgets/source_type_selectable_chip.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../../../../../constants/app_sizes.dart';
10 | import '../../../../../utils/extensions/custom_extensions.dart';
11 | import '../../../domain/source/source_model.dart';
12 |
13 | class SourceTypeSelectableChip extends StatelessWidget {
14 | const SourceTypeSelectableChip({
15 | super.key,
16 | required this.value,
17 | required this.groupValue,
18 | required this.onSelected,
19 | });
20 | final SourceType value;
21 | final SourceType groupValue;
22 | final ValueChanged onSelected;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | final selected = value == groupValue;
27 | return Padding(
28 | padding: KEdgeInsets.h4v8.size,
29 | child: ChoiceChip(
30 | label: Text(value.toLocale(context)),
31 | selected: selected,
32 | avatar: selected
33 | ? null
34 | : Icon(
35 | selected ? value.selectedIcon : value.icon,
36 | color: context.theme.colorScheme.onSurface
37 | .withValues(alpha: selected ? .5 : 1),
38 | ),
39 | onSelected: onSelected,
40 | ),
41 | );
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/lib/src/features/browse_center/presentation/source_preference/controller/source_preference_controller.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:hooks_riverpod/hooks_riverpod.dart';
8 | import 'package:riverpod_annotation/riverpod_annotation.dart';
9 |
10 | import '../../../data/source_repository/source_repository.dart';
11 | import '../../../domain/source_preference/source_preference.dart';
12 |
13 | part 'source_preference_controller.g.dart';
14 |
15 | @riverpod
16 | Future?> baseSourcePreferenceList(
17 | Ref ref, String sourceId) =>
18 | ref.read(sourceRepositoryProvider).getSourcePreference(sourceId);
19 |
--------------------------------------------------------------------------------
/lib/src/features/library/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | query AllCategories($condition: CategoryConditionInput, $filter: CategoryFilterInput, $first: Int, $offset: Int) {
5 | categories(
6 | condition: $condition
7 | filter: $filter
8 | first: $first
9 | orderBy: ORDER
10 | orderByType: ASC
11 | offset: $offset
12 | ) {
13 | nodes {
14 | ...CategoryDto
15 | }
16 | pageInfo {
17 | ...PageInfoDto
18 | }
19 | totalCount
20 | }
21 | }
22 |
23 | mutation CreateCategory($input: CreateCategoryInput!) {
24 | createCategory(input: $input) {
25 | __typename
26 | }
27 | }
28 |
29 | mutation UpdateCategory($input: UpdateCategoryInput!) {
30 | updateCategory(input: $input) {
31 | __typename
32 | }
33 | }
34 |
35 | mutation DeleteCategory($input: DeleteCategoryInput!) {
36 | deleteCategory(input: $input) {
37 | __typename
38 | }
39 | }
40 |
41 | mutation UpdateCategoryOrder($input: UpdateCategoryOrderInput!) {
42 | updateCategoryOrder(input: $input) {
43 | categories {
44 | ...CategoryDto
45 | }
46 | }
47 | }
48 |
49 | query GetCategoryMangas($id: Int!) {
50 | category(id: $id) {
51 | id
52 | mangas {
53 | nodes {
54 | ...MangaDto
55 | __typename
56 | }
57 | pageInfo {
58 | ...PageInfoDto
59 | __typename
60 | }
61 | totalCount
62 | __typename
63 | }
64 | __typename
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/src/features/library/domain/category/category_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | import '../../../../graphql/__generated__/schema.graphql.dart';
7 | import './graphql/__generated__/fragment.graphql.dart';
8 |
9 | typedef CategoryDto = Fragment$CategoryDto;
10 |
11 | typedef CategoryCreate = Input$CreateCategoryInput;
12 |
13 | typedef CategoryUpdate = Input$UpdateCategoryPatchInput;
14 |
--------------------------------------------------------------------------------
/lib/src/features/library/domain/category/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 | fragment CategoryDto on CategoryType {
3 | defaultCategory : default
4 | id
5 | includeInDownload
6 | includeInUpdate
7 | name
8 | order
9 | mangas {
10 | totalCount
11 | }
12 | meta {
13 | key
14 | value
15 | }
16 | }
17 |
18 | fragment CategoryPageDto on CategoryNodeList {
19 | nodes {
20 | ...CategoryDto
21 | }
22 | pageInfo {
23 | ...PageInfoDto
24 | }
25 | totalCount
26 | }
27 |
--------------------------------------------------------------------------------
/lib/src/features/library/presentation/library/widgets/library_manga_filter.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../../utils/extensions/custom_extensions.dart';
11 | import '../../../../../widgets/custom_checkbox_list_tile.dart';
12 | import '../controller/library_controller.dart';
13 |
14 | class LibraryMangaFilter extends ConsumerWidget {
15 | const LibraryMangaFilter({super.key});
16 |
17 | @override
18 | Widget build(BuildContext context, WidgetRef ref) {
19 | return ListView(
20 | children: [
21 | CustomCheckboxListTile(
22 | title: context.l10n.unread,
23 | provider: libraryMangaFilterUnreadProvider,
24 | onChanged: ref.read(libraryMangaFilterUnreadProvider.notifier).update,
25 | ),
26 | CustomCheckboxListTile(
27 | title: context.l10n.completed,
28 | provider: libraryMangaFilterCompletedProvider,
29 | onChanged:
30 | ref.read(libraryMangaFilterCompletedProvider.notifier).update,
31 | ),
32 | CustomCheckboxListTile(
33 | title: context.l10n.downloaded,
34 | provider: libraryMangaFilterDownloadedProvider,
35 | onChanged:
36 | ref.read(libraryMangaFilterDownloadedProvider.notifier).update,
37 | ),
38 | ],
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/features/library/presentation/library/widgets/library_manga_organizer.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../../../../../constants/enum.dart';
10 | import '../../../../../utils/extensions/custom_extensions.dart';
11 | import 'library_manga_display.dart';
12 | import 'library_manga_filter.dart';
13 | import 'library_manga_sort_tile.dart';
14 |
15 | class LibraryMangaOrganizer extends StatelessWidget {
16 | const LibraryMangaOrganizer({
17 | super.key,
18 | /* required this.controller */
19 | });
20 | // final ScrollController controller;
21 | @override
22 | Widget build(BuildContext context) {
23 | return DefaultTabController(
24 | length: 3,
25 | child: Scaffold(
26 | appBar: TabBar(
27 | tabs: [
28 | Tab(text: context.l10n.filter),
29 | Tab(text: context.l10n.sort),
30 | Tab(text: context.l10n.display),
31 | ],
32 | ),
33 | body: TabBarView(
34 | children: [
35 | const LibraryMangaFilter(),
36 | ListView(
37 | children: [
38 | for (MangaSort sortType in MangaSort.values)
39 | LibraryMangaSortTile(sortType: sortType),
40 | ],
41 | ),
42 | const LibraryMangaDisplay(),
43 | ],
44 | ),
45 | ),
46 | );
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/lib/src/features/library/presentation/library/widgets/library_manga_sort_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../../constants/enum.dart';
11 | import '../../../../../utils/extensions/custom_extensions.dart';
12 | import '../../../../../widgets/sort_list_tile.dart';
13 | import '../controller/library_controller.dart';
14 |
15 | class LibraryMangaSortTile extends ConsumerWidget {
16 | const LibraryMangaSortTile({
17 | super.key,
18 | required this.sortType,
19 | });
20 | final MangaSort sortType;
21 | @override
22 | Widget build(BuildContext context, WidgetRef ref) {
23 | final sortedBy = ref.watch(libraryMangaSortProvider);
24 | final sortedDirection = ref.watch(libraryMangaSortDirectionProvider);
25 | return SortListTile(
26 | selected: sortType == sortedBy,
27 | title: Text(sortType.toLocale(context)),
28 | ascending: sortedDirection.ifNull(true),
29 | onChanged: (bool? value) => ref
30 | .read(libraryMangaSortDirectionProvider.notifier)
31 | .update(!(sortedDirection.ifNull())),
32 | onSelected: () =>
33 | ref.read(libraryMangaSortProvider.notifier).update(sortType),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/data/downloads/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | mutation EnqueueChapterDownloads($input: EnqueueChapterDownloadsInput!) {
4 | enqueueChapterDownloads(input: $input) {
5 | __typename
6 | }
7 | }
8 |
9 | mutation DequeueChapterDownloads($input: DequeueChapterDownloadInput!) {
10 | dequeueChapterDownload(input: $input) {
11 | __typename
12 | }
13 | }
14 |
15 | mutation StopDownloader($input: StopDownloaderInput!) {
16 | stopDownloader(input: $input) {
17 | __typename
18 | }
19 | }
20 | mutation StartDownloader($input: StartDownloaderInput!) {
21 | startDownloader(input: $input) {
22 | __typename
23 | }
24 | }
25 |
26 | mutation ClearDownloader($input: ClearDownloaderInput!) {
27 | clearDownloader(input: $input) {
28 | __typename
29 | }
30 | }
31 |
32 | mutation ReorderChapterDownload($input: ReorderChapterDownloadInput!) {
33 | reorderChapterDownload(input: $input) {
34 | __typename
35 | downloadStatus {
36 | ...DownloadStatusDto
37 | }
38 | }
39 | }
40 |
41 | subscription DownloadStatusChanged($input: DownloadChangedInput!) {
42 | downloadStatusChanged(input: $input) {
43 | ...DownloadUpdatesDto
44 | }
45 | }
46 |
47 | query GetDownloadStatus {
48 | downloadStatus {
49 | ...DownloadStatusDto
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/data/updates/graphql/query.graphql:
--------------------------------------------------------------------------------
1 | query GetChapterWithMangaPage($after: Cursor, $before: Cursor, $condition: ChapterConditionInput, $filter: ChapterFilterInput, $first: Int, $last: Int, $offset: Int, $order: [ChapterOrderInput!]) {
2 | chapters(
3 | after: $after
4 | before: $before
5 | condition: $condition
6 | filter: $filter
7 | first: $first
8 | last: $last
9 | offset: $offset
10 | order: $order
11 | ) {
12 | ...ChapterPageWithMangaDto
13 | }
14 | }
15 |
16 |
17 | mutation UpdateLibraryMangas($input: UpdateLibraryMangaInput!) {
18 | updateLibraryManga(input: $input) {
19 | updateStatus {
20 | ...UpdateStatusBaseDto
21 | }
22 | }
23 | }
24 |
25 | mutation UpdateCategoryMangas($input: UpdateCategoryMangaInput!) {
26 | updateCategoryManga(input: $input) {
27 | updateStatus {
28 | ...UpdateStatusBaseDto
29 | }
30 | }
31 | }
32 |
33 | mutation StopCategoryUpdate($input: UpdateStopInput!) {
34 | updateStop(input: $input) {
35 | __typename
36 | }
37 | }
38 |
39 | query UpdateStatusDto {
40 | updateStatus {
41 | ...UpdateStatusDto
42 | }
43 | }
44 |
45 | subscription UpdateStatusChange {
46 | updateStatusChanged {
47 | ...UpdateStatusDto
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter/chapter_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../../../utils/extensions/custom_extensions.dart';
8 | import 'graphql/__generated__/fragment.graphql.dart';
9 |
10 | typedef ChapterDto = Fragment$ChapterDto;
11 |
12 | typedef ChapterWithMangaDto = Fragment$ChapterWithMangaDto;
13 |
14 | extension ChapterExtension on Fragment$ChapterDto {
15 | bool query([String? query]) {
16 | return name.query(query) || index == int.tryParse(query ?? '');
17 | }
18 |
19 | int get index => sourceOrder;
20 |
21 | Map get metaData =>
22 | {for (final metaItem in meta) metaItem.key: metaItem.value};
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment ChapterDto on ChapterType {
2 | chapterNumber
3 | fetchedAt
4 | id
5 | isBookmarked
6 | isDownloaded
7 | isRead
8 | lastPageRead
9 | lastReadAt
10 | mangaId
11 | name
12 | pageCount
13 | realUrl
14 | scanlator
15 | sourceOrder
16 | uploadDate
17 | url
18 | meta {
19 | key
20 | value
21 | }
22 | }
23 | fragment ChapterWithMangaDto on ChapterType {
24 | ...ChapterDto,
25 | manga {
26 | ...MangaBaseDto,
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter_batch/chapter_batch_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../../../graphql/__generated__/schema.graphql.dart';
8 |
9 | typedef ChapterBatch = Input$UpdateChaptersInput;
10 |
11 | typedef ChapterChange = Input$UpdateChapterPatchInput;
12 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter_page/chapter_page_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import './graphql/__generated__/fragment.graphql.dart';
8 |
9 | typedef ChapterPageDto = Fragment$ChapterPageDto;
10 |
11 | typedef ChapterPageWithMangaDto = Fragment$ChapterPageWithMangaDto;
12 |
13 | typedef ChapterPagesDto = Fragment$ChapterPagesDto;
14 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter_page/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment ChapterPageDto on ChapterNodeList {
2 | nodes {
3 | ...ChapterDto
4 | }
5 | pageInfo {
6 | ...PageInfoDto
7 | }
8 | totalCount
9 | }
10 |
11 | fragment ChapterPageWithMangaDto on ChapterNodeList {
12 | nodes {
13 | ...ChapterWithMangaDto
14 | }
15 | pageInfo {
16 | ...PageInfoDto
17 | }
18 | totalCount
19 | }
20 |
21 | fragment ChapterPagesDto on FetchChapterPagesPayload {
22 | chapter {
23 | id
24 | pageCount
25 | __typename
26 | }
27 | pages
28 | __typename
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/chapter_patch/chapter_put_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:freezed_annotation/freezed_annotation.dart';
8 |
9 | part 'chapter_put_model.freezed.dart';
10 | part 'chapter_put_model.g.dart';
11 |
12 | @freezed
13 | class ChapterPut with _$ChapterPut {
14 | factory ChapterPut({
15 | bool? read,
16 | bool? bookmarked,
17 | bool? markPrevRead,
18 | int? lastPageRead,
19 | }) = _ChapterPut;
20 |
21 | factory ChapterPut.fromJson(Map json) =>
22 | _$ChapterPutFromJson(json);
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/downloads/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment DownloadDto on DownloadType {
2 | chapter {
3 | id
4 | name
5 | sourceOrder
6 | isDownloaded
7 | }
8 |
9 | manga {
10 | id
11 | title
12 | downloadCount
13 | thumbnailUrl
14 | }
15 | progress
16 | state
17 | tries
18 | position
19 | }
20 |
21 | fragment DownloadUpdateDto on DownloadUpdate {
22 | type
23 | download {
24 | ...DownloadDto
25 | }
26 | }
27 |
28 | fragment DownloadUpdatesDto on DownloadUpdates {
29 | state
30 | omittedUpdates
31 | updates {
32 | ...DownloadUpdateDto
33 | }
34 | initial {
35 | ...DownloadDto
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/downloads_queue/downloads_queue_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import './graphql/__generated__/fragment.graphql.dart';
8 |
9 | typedef DownloadStatusDto = Fragment$DownloadStatusDto;
10 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/downloads_queue/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | fragment DownloadStatusDto on DownloadStatus {
4 | state
5 | queue {
6 | ...DownloadDto
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/manga/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 | fragment MangaDto on MangaType {
2 | age
3 | artist
4 | author
5 | chaptersAge
6 | chaptersLastFetchedAt
7 | description
8 | downloadCount
9 | genre
10 | id
11 | inLibrary
12 | inLibraryAt
13 | initialized
14 | lastFetchedAt
15 | lastReadChapter {
16 | ...ChapterDto
17 | }
18 | latestFetchedChapter {
19 | ...ChapterDto
20 | }
21 | latestReadChapter {
22 | ...ChapterDto
23 | }
24 | latestUploadedChapter {
25 | ...ChapterDto
26 | }
27 | meta {
28 | key
29 | value
30 | }
31 | realUrl
32 | source {
33 | ...SourceDto
34 | }
35 | sourceId
36 | status
37 | thumbnailUrl
38 | thumbnailUrlLastFetched
39 | title
40 | unreadCount
41 | updateStrategy
42 | url
43 | }
44 |
45 | fragment MangaMetaDto on MangaMetaType {
46 | key,
47 | value,
48 | mangaId,
49 | }
50 |
51 |
52 | fragment MangaBaseDto on MangaType {
53 | age
54 | artist
55 | author
56 | chaptersLastFetchedAt
57 | description
58 | genre
59 | id
60 | inLibrary
61 | inLibraryAt
62 | initialized
63 | lastFetchedAt
64 | meta {
65 | key
66 | value
67 | }
68 | realUrl
69 | sourceId
70 | status
71 | thumbnailUrl
72 | thumbnailUrlLastFetched
73 | title
74 | unreadCount
75 | updateStrategy
76 | url
77 | }
78 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/update_status/graphql/fragment.graphql:
--------------------------------------------------------------------------------
1 |
2 | fragment UpdateStatusBaseDto on UpdateStatus {
3 | isRunning
4 | }
5 | fragment UpdateStatusJobDto on UpdateStatusType {
6 | mangas {
7 | ...MangaPageDto
8 | }
9 | }
10 |
11 | fragment UpdateStatusDto on UpdateStatus {
12 | ...UpdateStatusBaseDto
13 | completeJobs {
14 | ...UpdateStatusJobDto
15 | }
16 | failedJobs {
17 | ...UpdateStatusJobDto
18 | }
19 | pendingJobs {
20 | ...UpdateStatusJobDto
21 | }
22 | runningJobs {
23 | ...UpdateStatusJobDto
24 | }
25 | skippedCategories {
26 | categories {
27 | ...CategoryPageDto
28 | }
29 | }
30 | skippedJobs {
31 | ...UpdateStatusJobDto
32 | }
33 | updatingCategories {
34 | categories {
35 | ...CategoryPageDto
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/domain/update_status/update_status_model.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../../../utils/extensions/custom_extensions.dart';
8 | import '../manga/manga_model.dart';
9 | import 'graphql/__generated__/fragment.graphql.dart';
10 |
11 | typedef UpdateStatusDto = Fragment$UpdateStatusDto;
12 |
13 | extension UpdateStatusExt on UpdateStatusDto {
14 | int get total =>
15 | (pendingJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative() +
16 | (runningJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative() +
17 | (completeJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative() +
18 | (failedJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative();
19 |
20 | int get updateChecked =>
21 | (completeJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative() +
22 | (failedJobs.mangas.totalCount.toInt()).getValueOnNullOrNegative();
23 |
24 | bool get isUpdateCheckCompleted => total == updateChecked;
25 |
26 | bool get isUpdateChecking =>
27 | (total).isGreaterThan(0) && !(isUpdateCheckCompleted);
28 | }
29 |
30 | extension U on Fragment$UpdateStatusJobDto {
31 | bool get isNotBlank => mangas.nodes.isNotBlank;
32 |
33 | List get mangaList => mangas.nodes;
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/manga_details/widgets/manga_chapter_organizer.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../../../../../utils/extensions/custom_extensions.dart';
10 | import 'manga_chapter_filter.dart';
11 | import 'manga_chapter_sort.dart';
12 |
13 | class MangaChapterOrganizer extends StatelessWidget {
14 | const MangaChapterOrganizer({super.key, required this.mangaId});
15 | final int mangaId;
16 | @override
17 | Widget build(BuildContext context) {
18 | return DefaultTabController(
19 | length: 2,
20 | child: Scaffold(
21 | appBar: TabBar(
22 | tabs: [
23 | Tab(text: context.l10n.filter),
24 | Tab(text: context.l10n.sort),
25 | ],
26 | ),
27 | body: TabBarView(
28 | children: [
29 | MangaChapterFilter(mangaId: mangaId),
30 | const MangaChapterSort(),
31 | ],
32 | ),
33 | ),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/manga_details/widgets/manga_chapter_sort.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import 'package:hooks_riverpod/hooks_riverpod.dart';
10 |
11 | import '../../../../../constants/enum.dart';
12 | import 'manga_chapter_sort_tile.dart';
13 |
14 | class MangaChapterSort extends ConsumerWidget {
15 | const MangaChapterSort({super.key});
16 |
17 | @override
18 | Widget build(BuildContext context, WidgetRef ref) {
19 | return ListView(
20 | children: [
21 | const Divider(height: .5),
22 | for (ChapterSort chapterSort in ChapterSort.values)
23 | MangaChapterSortTile(sortType: chapterSort),
24 | ],
25 | );
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/manga_details/widgets/manga_chapter_sort_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../../constants/enum.dart';
11 | import '../../../../../utils/extensions/custom_extensions.dart';
12 | import '../../../../../widgets/sort_list_tile.dart';
13 | import '../controller/manga_details_controller.dart';
14 |
15 | class MangaChapterSortTile extends ConsumerWidget {
16 | const MangaChapterSortTile({
17 | super.key,
18 | required this.sortType,
19 | });
20 | final ChapterSort sortType;
21 | @override
22 | Widget build(BuildContext context, WidgetRef ref) {
23 | final sortedBy = ref.watch(mangaChapterSortProvider);
24 | final sortedDirection = ref.watch(mangaChapterSortDirectionProvider);
25 | return SortListTile(
26 | selected: sortType == sortedBy,
27 | title: Text(sortType.toLocale(context)),
28 | ascending: sortedDirection.ifNull(true),
29 | onChanged: (bool? value) => ref
30 | .read(mangaChapterSortDirectionProvider.notifier)
31 | .update(!(sortedDirection.ifNull())),
32 | onSelected: () =>
33 | ref.read(mangaChapterSortProvider.notifier).update(sortType),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/manga_thumbnail_viewer/manga_thumbnail_viewer.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'dart:ui';
8 |
9 | import 'package:flutter/material.dart';
10 | import 'package:go_router/go_router.dart';
11 |
12 | import '../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../widgets/server_image.dart';
14 |
15 | class MangaThumbnailViewer extends StatelessWidget {
16 | const MangaThumbnailViewer({
17 | super.key,
18 | required this.imageUrl,
19 | });
20 | final String imageUrl;
21 | @override
22 | Widget build(BuildContext context) {
23 | return GestureDetector(
24 | onTap: () => context.pop(),
25 | child: Scaffold(
26 | appBar: AppBar(backgroundColor: Colors.transparent),
27 | backgroundColor: Colors.transparent,
28 | body: BackdropFilter(
29 | filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
30 | child: Container(
31 | decoration: BoxDecoration(
32 | color: context.colorScheme.surface.withValues(alpha: 0.1),
33 | ),
34 | child: InteractiveViewer(
35 | maxScale: 4,
36 | child: Center(
37 | child: ServerImage(imageUrl: imageUrl),
38 | ),
39 | ),
40 | ),
41 | ),
42 | ),
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/reader/controller/reader_controller.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:hooks_riverpod/hooks_riverpod.dart';
8 | import 'package:riverpod_annotation/riverpod_annotation.dart';
9 |
10 | import '../../../data/manga_book/manga_book_repository.dart';
11 | import '../../../domain/chapter/chapter_model.dart';
12 | import '../../../domain/chapter_page/chapter_page_model.dart';
13 |
14 | part 'reader_controller.g.dart';
15 |
16 | @riverpod
17 | FutureOr chapter(
18 | Ref ref, {
19 | required int chapterId,
20 | }) =>
21 | ref.watch(mangaBookRepositoryProvider).getChapter(chapterId: chapterId);
22 |
23 | @riverpod
24 | Future chapterPages(Ref ref, {required int chapterId}) => ref
25 | .watch(mangaBookRepositoryProvider)
26 | .getChapterPages(chapterId: chapterId);
27 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/presentation/reader/widgets/reader_navigation_layout/layouts/right_and_left_layout.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | class RightAndLeftLayout extends StatelessWidget {
10 | const RightAndLeftLayout({
11 | super.key,
12 | this.onLeftTap,
13 | this.onRightTap,
14 | this.leftColor,
15 | this.rightColor,
16 | });
17 | final VoidCallback? onLeftTap;
18 | final VoidCallback? onRightTap;
19 | final Color? leftColor;
20 | final Color? rightColor;
21 | @override
22 | Widget build(BuildContext context) {
23 | return Row(
24 | mainAxisAlignment: MainAxisAlignment.spaceBetween,
25 | children: [
26 | Expanded(
27 | child: GestureDetector(
28 | behavior: HitTestBehavior.translucent,
29 | onTap: onLeftTap,
30 | child: Container(color: leftColor),
31 | ),
32 | ),
33 | const Expanded(child: SizedBox.expand()),
34 | Expanded(
35 | child: GestureDetector(
36 | behavior: HitTestBehavior.translucent,
37 | onTap: onRightTap,
38 | child: Container(color: rightColor),
39 | ),
40 | ),
41 | ],
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/features/manga_book/widgets/update_status_fab.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../routes/router_config.dart';
11 | import '../../../utils/extensions/custom_extensions.dart';
12 | import '../data/updates/updates_repository.dart';
13 | import '../domain/update_status/update_status_model.dart';
14 |
15 | class UpdateStatusFab extends ConsumerWidget {
16 | const UpdateStatusFab({super.key});
17 |
18 | @override
19 | Widget build(BuildContext context, WidgetRef ref) {
20 | final updateStatus = ref.watch(updatesSocketProvider);
21 | final showStatus = (updateStatus.valueOrNull?.isUpdateChecking).ifNull();
22 | return FloatingActionButton.extended(
23 | icon: showStatus ? null : const Icon(Icons.refresh_rounded),
24 | onPressed: () => showStatus
25 | ? const UpdateStatusRoute().push(context)
26 | : ref.read(updatesRepositoryProvider).fetchUpdates(),
27 | label: showStatus
28 | ? Text("${updateStatus.valueOrNull?.updateChecked.padLeft()}"
29 | "/${updateStatus.valueOrNull?.total.padLeft()}")
30 | : Text(context.l10n.update),
31 | );
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/lib/src/features/quick_open/presentation/quick_search/widgets/quick_query_result.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../../utils/extensions/custom_extensions.dart';
11 | import '../controller/quick_search_controller.dart';
12 | import 'search_result_to_widget.dart';
13 |
14 | class QuickQueryResult extends ConsumerWidget {
15 | const QuickQueryResult({
16 | super.key,
17 | required this.afterClick,
18 | this.controller,
19 | });
20 | final VoidCallback afterClick;
21 | final TextEditingController? controller;
22 | @override
23 | Widget build(BuildContext context, WidgetRef ref) {
24 | final results = ref.watch(processesQuickSearchProvider(context: context));
25 | if (results.isBlank) return const SizedBox.shrink();
26 | return Card(
27 | clipBehavior: Clip.hardEdge,
28 | child: SingleChildScrollView(
29 | child: Column(
30 | mainAxisSize: MainAxisSize.min,
31 | children: results!
32 | .map(
33 | (e) => SearchResultToWidget(
34 | result: e,
35 | afterClick: afterClick,
36 | controller: controller,
37 | ),
38 | )
39 | .toList(),
40 | ),
41 | ),
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/features/settings/controller/server_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:riverpod_annotation/riverpod_annotation.dart';
2 |
3 | import '../../../utils/extensions/custom_extensions.dart';
4 | import '../data/settings_repository.dart';
5 | import '../domain/settings/settings.dart';
6 |
7 | part 'server_controller.g.dart';
8 |
9 | @riverpod
10 | class Settings extends _$Settings {
11 | @override
12 | Future build() =>
13 | ref.watch(settingsRepositoryProvider).getServerSettings();
14 |
15 | void updateState(SettingsDto value) =>
16 | state = state.copyWithData((_) => value);
17 | }
18 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | query ServerSettings {
4 | settings {
5 | ...SettingsDto
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/lib/src/features/settings/data/settings_repository.dart:
--------------------------------------------------------------------------------
1 | import 'package:graphql/client.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 | import 'package:riverpod_annotation/riverpod_annotation.dart';
4 |
5 | import '../../../global_providers/global_providers.dart';
6 | import '../../../utils/extensions/custom_extensions.dart';
7 | import '../domain/settings/settings.dart';
8 | import './graphql/__generated__/query.graphql.dart';
9 |
10 | part 'settings_repository.g.dart';
11 |
12 | class SettingsRepository {
13 | const SettingsRepository(this.ferryClient);
14 |
15 | final GraphQLClient ferryClient;
16 |
17 | Future getServerSettings() => ferryClient
18 | .query$ServerSettings(Options$Query$ServerSettings())
19 | .getData((data) => data.settings);
20 | }
21 |
22 | @riverpod
23 | SettingsRepository settingsRepository(Ref ref) =>
24 | SettingsRepository(ref.watch(graphQlClientProvider));
25 |
--------------------------------------------------------------------------------
/lib/src/features/settings/domain/settings/settings.dart:
--------------------------------------------------------------------------------
1 | import '../../../../graphql/__generated__/schema.graphql.dart';
2 | import 'graphql/__generated__/fragment.graphql.dart';
3 |
4 | typedef SettingsDto = Fragment$SettingsDto;
5 | typedef AutomaticBackupSettingsDto = Fragment$AutomaticBackupSettingsDto;
6 | typedef BrowserSettingsDto = Fragment$BrowserSettingsDto;
7 | typedef CloudFlareBypassDto = Fragment$CloudFlareBypassDto;
8 | typedef DownloadsSettingsDto = Fragment$DownloadsSettingsDto;
9 | typedef LibrarySettingsDto = Fragment$LibrarySettingsDto;
10 | typedef MiscSettingsDto = Fragment$MiscSettingsDto;
11 | typedef RestoreStatusDto = Fragment$RestoreStatusDto;
12 | typedef ServerBindingDto = Fragment$ServerBindingDto;
13 | typedef SocksProxyDto = Fragment$SocksProxyDto;
14 | typedef RestoreState = Enum$BackupRestoreState;
15 |
16 | extension RestoreStateExtension on RestoreState {
17 | bool get isFinalState =>
18 | this == RestoreState.SUCCESS || this == RestoreState.FAILURE;
19 | }
20 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/appearance/appearance_screen.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../utils/extensions/custom_extensions.dart';
11 | import '../../widgets/app_theme_mode_tile/app_theme_mode_tile.dart';
12 | import 'widgets/app_theme_selector/app_theme_selector.dart';
13 | import 'widgets/grid_cover_width_slider/grid_cover_width_slider.dart';
14 | import 'widgets/is_true_black/is_true_black_tile.dart';
15 |
16 | class AppearanceScreen extends ConsumerWidget {
17 | const AppearanceScreen({super.key});
18 |
19 | @override
20 | Widget build(context, ref) {
21 | final themeMode = ref.watch(appThemeModeProvider);
22 | return Scaffold(
23 | appBar: AppBar(title: Text(context.l10n.appearance)),
24 | body: ListView(
25 | children: [
26 | const AppThemeModeTile(),
27 | if (themeMode != ThemeMode.light) const IsTrueBlackTile(),
28 | const AppThemeSelector(),
29 | const GridCoverWidthSlider(),
30 | ],
31 | ),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/appearance/widgets/is_true_black/is_true_black_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'is_true_black_tile.g.dart';
16 |
17 | @riverpod
18 | class IsTrueBlack extends _$IsTrueBlack with SharedPreferenceClientMixin {
19 | @override
20 | bool? build() => initialize(DBKeys.isTrueBlack);
21 | }
22 |
23 | class IsTrueBlackTile extends HookConsumerWidget {
24 | const IsTrueBlackTile({super.key});
25 | @override
26 | Widget build(BuildContext context, WidgetRef ref) {
27 | return SwitchListTile(
28 | controlAffinity: ListTileControlAffinity.trailing,
29 | secondary: const Icon(Icons.circle_rounded, color: Colors.black),
30 | title: Text(context.l10n.isTrueBlack),
31 | onChanged: ref.read(isTrueBlackProvider.notifier).update,
32 | value: ref.watch(isTrueBlackProvider).ifNull(),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/backup/backup_screen.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | import '../../../../utils/extensions/custom_extensions.dart';
11 | import '../../controller/server_controller.dart';
12 | import 'widgets/automatic_backup/automatic_backup_section.dart';
13 | import 'widgets/backup_and_restore/backup_and_restore_section.dart';
14 |
15 | class BackupScreen extends ConsumerWidget {
16 | const BackupScreen({super.key});
17 |
18 | @override
19 | Widget build(context, ref) {
20 | return Scaffold(
21 | appBar: AppBar(title: Text(context.l10n.backup)),
22 | body: RefreshIndicator(
23 | onRefresh: () => ref.refresh(settingsProvider.future),
24 | child: ListTileTheme(
25 | data: const ListTileThemeData(
26 | subtitleTextStyle: TextStyle(color: Colors.grey),
27 | ),
28 | child: ListView(
29 | children: const [
30 | BackupAndRestoreSection(),
31 | AutomaticBackupSection(),
32 | ],
33 | ),
34 | ),
35 | ),
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/backup/controllers/backup_controller.dart:
--------------------------------------------------------------------------------
1 | import 'package:hooks_riverpod/hooks_riverpod.dart';
2 | import 'package:riverpod_annotation/riverpod_annotation.dart';
3 |
4 | import '../../../domain/settings/settings.dart';
5 | import '../data/backup_settings_repository.dart';
6 |
7 | part 'backup_controller.g.dart';
8 |
9 | @riverpod
10 | Future restoreStatus(Ref ref, String restoreId) =>
11 | ref.watch(backupSettingsRepositoryProvider).getRestoreStatus(restoreId);
12 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/backup/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 | mutation UpdateBackupTTL($backupTTL: Int = 14) {
3 | setSettings(input: {settings: {backupTTL: $backupTTL}}) {
4 | settings {
5 | ...SettingsDto
6 | }
7 | }
8 | }
9 |
10 | mutation UpdateBackupTime($backupTime: String = "12:00") {
11 | setSettings(input: {settings: {backupTime: $backupTime}}) {
12 | settings {
13 | ...SettingsDto
14 | }
15 | }
16 | }
17 |
18 | mutation UpdateBackupPath($backupPath: String!) {
19 | setSettings(input: {settings: {backupPath: $backupPath}}) {
20 | settings {
21 | ...SettingsDto
22 | }
23 | }
24 | }
25 |
26 | mutation UpdateBackupInterval($backupInterval: Int = 1) {
27 | setSettings(input: {settings: {backupInterval: $backupInterval}}) {
28 | settings {
29 | ...SettingsDto
30 | }
31 | }
32 | }
33 |
34 | query RestoreStatus($restoreId: String!) {
35 | restoreStatus(id: $restoreId) {
36 | ...RestoreStatusDto
37 | }
38 | }
39 |
40 | mutation RestoreBackup($backup: Upload!) {
41 | restoreBackup(input: { backup: $backup }) {
42 | clientMutationId
43 | id
44 | status {
45 | ...RestoreStatusDto
46 | }
47 | }
48 | }
49 |
50 | mutation CreateBackup($includeCategories: Boolean = true, $includeChapters: Boolean = true) {
51 | createBackup(
52 | input: {includeCategories: $includeCategories, includeChapters: $includeChapters}
53 | ) {
54 | clientMutationId
55 | url
56 | }
57 | }
58 |
59 | query ValidateBackup($backup: Upload!) {
60 | validateBackup(input: { backup: $backup }) {
61 | missingSources {
62 | name
63 | id
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/browse/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | mutation UpdateSourceInParallel($maxSourcesInParallel: Int = 6) {
4 | setSettings(input: {settings: {maxSourcesInParallel: $maxSourcesInParallel}}) {
5 | settings {
6 | ...SettingsDto
7 | }
8 | }
9 | }
10 |
11 | mutation UpdateLocalSourcePath($localSourcePath: String!) {
12 | setSettings(input: {settings: {localSourcePath: $localSourcePath}}) {
13 | settings {
14 | ...SettingsDto
15 | }
16 | }
17 | }
18 |
19 | mutation UpdateExtensionRepos($extensionRepos: [String!]!) {
20 | setSettings(input: {settings: {extensionRepos: $extensionRepos}}) {
21 | settings {
22 | ...SettingsDto
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/browse/widgets/show_nsfw_switch/show_nsfw_switch.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'show_nsfw_switch.g.dart';
16 |
17 | @riverpod
18 | class ShowNSFW extends _$ShowNSFW with SharedPreferenceClientMixin {
19 | @override
20 | bool? build() => initialize(DBKeys.showNSFW);
21 | }
22 |
23 | class ShowNSFWTile extends ConsumerWidget {
24 | const ShowNSFWTile({super.key});
25 | @override
26 | Widget build(BuildContext context, WidgetRef ref) {
27 | return SwitchListTile(
28 | controlAffinity: ListTileControlAffinity.trailing,
29 | secondary: const Icon(Icons.eighteen_up_rating_rounded),
30 | title: Text(context.l10n.nsfw),
31 | onChanged: ref.read(showNSFWProvider.notifier).update,
32 | value: ref.watch(showNSFWProvider).ifNull(),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/downloads/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | mutation UpdateDownloadsLocation($downloadsPath: String!) {
4 | setSettings(input: {settings: {downloadsPath: $downloadsPath}}) {
5 | settings {
6 | ...SettingsDto
7 | }
8 | }
9 | }
10 |
11 | mutation UpdateDownloadAsCbz($downloadAsCbz: Boolean = false) {
12 | setSettings(input: {settings: {downloadAsCbz: $downloadAsCbz}}) {
13 | settings {
14 | ...SettingsDto
15 | }
16 | }
17 | }
18 |
19 | mutation UpdateAutoDownloadNewChaptersLimit($autoDownloadNewChaptersLimit: Int = 3) {
20 | setSettings(input: {settings: {autoDownloadNewChaptersLimit: $autoDownloadNewChaptersLimit}}) {
21 | settings {
22 | ...SettingsDto
23 | }
24 | }
25 | }
26 |
27 | mutation ToggleExcludeEntryWithUnreadChapters($excludeEntryWithUnreadChapters: Boolean = false) {
28 | setSettings(input: {settings: {excludeEntryWithUnreadChapters: $excludeEntryWithUnreadChapters}}) {
29 | settings {
30 | ...SettingsDto
31 | }
32 | }
33 | }
34 |
35 | mutation ToggleAutoDownloadNewChapters($autoDownloadNewChapters: Boolean = false) {
36 | setSettings(input: {settings: {autoDownloadNewChapters: $autoDownloadNewChapters}}) {
37 | settings {
38 | ...SettingsDto
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/general/quick_search_toggle/quick_search_toggle_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../constants/db_keys.dart';
12 | import '../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'quick_search_toggle_tile.g.dart';
16 |
17 | @riverpod
18 | class QuickSearchToggle extends _$QuickSearchToggle
19 | with SharedPreferenceClientMixin {
20 | @override
21 | bool? build() => initialize(DBKeys.quickSearchToggle);
22 | }
23 |
24 | class QuickSearchToggleTile extends HookConsumerWidget {
25 | const QuickSearchToggleTile({super.key});
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | return SwitchListTile(
29 | controlAffinity: ListTileControlAffinity.trailing,
30 | secondary: const Icon(Icons.search_rounded),
31 | title: Text(context.l10n.quickSearch),
32 | onChanged: ref.read(quickSearchToggleProvider.notifier).update,
33 | value: ref.watch(quickSearchToggleProvider).ifNull(),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/library/data/graphql/query.graphql:
--------------------------------------------------------------------------------
1 |
2 |
3 | mutation UpdateMangaMetaData($updateMangas: Boolean = false) {
4 | setSettings(input: {settings: {updateMangas: $updateMangas}}) {
5 | settings {
6 | ...SettingsDto
7 | }
8 | }
9 | }
10 |
11 | mutation UpdateGlobalUpdateInterval($globalUpdateInterval: Float = 12) {
12 | setSettings(input: {settings: {globalUpdateInterval: $globalUpdateInterval}}) {
13 | settings {
14 | ...SettingsDto
15 | }
16 | }
17 | }
18 |
19 | mutation ToggleExcludeNotStarted($excludeNotStarted: Boolean = false) {
20 | setSettings(input: {settings: {excludeNotStarted: $excludeNotStarted}}) {
21 | settings {
22 | ...SettingsDto
23 | }
24 | }
25 | }
26 |
27 | mutation ToggleExcludeUnreadChapters($excludeUnreadChapters: Boolean = false) {
28 | setSettings(input: {settings: {excludeUnreadChapters: $excludeUnreadChapters}}) {
29 | settings {
30 | ...SettingsDto
31 | }
32 | }
33 | }
34 |
35 | mutation ToggleExcludeCompleted($excludeCompleted: Boolean = false) {
36 | setSettings(input: {settings: {excludeCompleted: $excludeCompleted}}) {
37 | settings {
38 | ...SettingsDto
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/library/widgets/hide_empty_category/hide_empty_category.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'hide_empty_category.g.dart';
16 |
17 | @riverpod
18 | class HideEmptyCategory extends _$HideEmptyCategory
19 | with SharedPreferenceClientMixin {
20 | @override
21 | bool? build() => initialize(DBKeys.hideEmptyCategory);
22 | }
23 |
24 | class HideEmptyCategoryTile extends HookConsumerWidget {
25 | const HideEmptyCategoryTile({super.key});
26 |
27 | @override
28 | Widget build(BuildContext context, WidgetRef ref) {
29 | return SwitchListTile(
30 | controlAffinity: ListTileControlAffinity.trailing,
31 | secondary: const Icon(Icons.category_rounded),
32 | title: Text(context.l10n.hideEmptyCategory),
33 | onChanged: ref.read(hideEmptyCategoryProvider.notifier).update,
34 | value: ref.watch(hideEmptyCategoryProvider).ifNull(),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/reader/widgets/reader_initial_overlay_tile/reader_initial_overlay_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'reader_initial_overlay_tile.g.dart';
16 |
17 | @riverpod
18 | class ReaderInitialOverlay extends _$ReaderInitialOverlay
19 | with SharedPreferenceClientMixin {
20 | @override
21 | bool? build() => initialize(DBKeys.readerOverlay);
22 | }
23 |
24 | class ReaderInitialOverlayTile extends HookConsumerWidget {
25 | const ReaderInitialOverlayTile({super.key});
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | return SwitchListTile(
29 | controlAffinity: ListTileControlAffinity.trailing,
30 | secondary: const Icon(Icons.layers_outlined),
31 | title: Text(context.l10n.readerOverlay),
32 | subtitle: Text(context.l10n.readerOverlaySubtitle),
33 | onChanged: ref.read(readerInitialOverlayProvider.notifier).update,
34 | value: ref.watch(readerInitialOverlayProvider).ifNull(),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/reader/widgets/reader_invert_tap_tile/reader_invert_tap_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'reader_invert_tap_tile.g.dart';
16 |
17 | @riverpod
18 | class InvertTap extends _$InvertTap with SharedPreferenceClientMixin {
19 | @override
20 | bool? build() => initialize(DBKeys.invertTap);
21 | }
22 |
23 | class ReaderInvertTapTile extends HookConsumerWidget {
24 | const ReaderInvertTapTile({super.key});
25 | @override
26 | Widget build(BuildContext context, WidgetRef ref) {
27 | return SwitchListTile(
28 | controlAffinity: ListTileControlAffinity.trailing,
29 | secondary: const Icon(Icons.switch_left_rounded),
30 | title: Text(context.l10n.readerNavigationLayoutInvert),
31 | onChanged: ref.read(invertTapProvider.notifier).update,
32 | value: ref.watch(invertTapProvider).ifNull(),
33 | );
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/reader/widgets/reader_pinch_to_zoom/reader_pinch_to_zoom.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | import 'package:flutter/material.dart';
7 | import 'package:hooks_riverpod/hooks_riverpod.dart';
8 | import 'package:riverpod_annotation/riverpod_annotation.dart';
9 |
10 | import '../../../../../../constants/db_keys.dart';
11 | import '../../../../../../utils/extensions/custom_extensions.dart';
12 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
13 |
14 | part 'reader_pinch_to_zoom.g.dart';
15 |
16 | @riverpod
17 | class PinchToZoom extends _$PinchToZoom with SharedPreferenceClientMixin {
18 | @override
19 | bool? build() => initialize(DBKeys.pinchToZoom);
20 | }
21 |
22 | class ReaderPinchToZoom extends HookConsumerWidget {
23 | const ReaderPinchToZoom({super.key});
24 | @override
25 | Widget build(BuildContext context, WidgetRef ref) {
26 | return SwitchListTile(
27 | controlAffinity: ListTileControlAffinity.trailing,
28 | secondary: const Icon(Icons.pinch_rounded),
29 | title: Text(context.l10n.pinchToZoom),
30 | onChanged: ref.read(pinchToZoomProvider.notifier).update,
31 | value: ref.watch(pinchToZoomProvider).ifNull(),
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/reader/widgets/reader_scroll_animation_tile/reader_scroll_animation_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'reader_scroll_animation_tile.g.dart';
16 |
17 | @riverpod
18 | class ReaderScrollAnimation extends _$ReaderScrollAnimation
19 | with SharedPreferenceClientMixin {
20 | @override
21 | bool? build() => initialize(DBKeys.scrollAnimation);
22 | }
23 |
24 | class ReaderScrollAnimationTile extends HookConsumerWidget {
25 | const ReaderScrollAnimationTile({super.key});
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | return SwitchListTile(
29 | controlAffinity: ListTileControlAffinity.trailing,
30 | secondary: const Icon(Icons.animation_rounded),
31 | title: Text(context.l10n.readerScrollAnimation),
32 | onChanged: ref.read(readerScrollAnimationProvider.notifier).update,
33 | value: ref.watch(readerScrollAnimationProvider).ifNull(),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/reader/widgets/reader_swipe_toggle_tile/reader_swipe_chapter_toggle_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 | import 'package:riverpod_annotation/riverpod_annotation.dart';
10 |
11 | import '../../../../../../constants/db_keys.dart';
12 | import '../../../../../../utils/extensions/custom_extensions.dart';
13 | import '../../../../../../utils/mixin/shared_preferences_client_mixin.dart';
14 |
15 | part 'reader_swipe_chapter_toggle_tile.g.dart';
16 |
17 | @riverpod
18 | class SwipeChapterToggle extends _$SwipeChapterToggle
19 | with SharedPreferenceClientMixin {
20 | @override
21 | bool? build() => initialize(DBKeys.swipeToggle);
22 | }
23 |
24 | class SwipeChapterToggleTile extends HookConsumerWidget {
25 | const SwipeChapterToggleTile({super.key});
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | return SwitchListTile(
29 | controlAffinity: ListTileControlAffinity.trailing,
30 | secondary: const Icon(Icons.swipe_rounded),
31 | title: Text(context.l10n.readerSwipeChapterToggle),
32 | subtitle: Text(context.l10n.readerSwipeChapterToggleDescription),
33 | onChanged: ref.read(swipeChapterToggleProvider.notifier).update,
34 | value: ref.watch(swipeChapterToggleProvider).ifNull(),
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/server/widget/authentication/authentication_section.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:hooks_riverpod/hooks_riverpod.dart';
3 |
4 | import '../../../../../../constants/enum.dart';
5 | import '../../../../../../global_providers/global_providers.dart';
6 | import '../../../../../../utils/extensions/custom_extensions.dart';
7 | import '../../../../../../widgets/section_title.dart';
8 | import '../credential_popup/credentials_popup.dart';
9 | import 'auth_type/auth_type_tile.dart';
10 |
11 | class AuthenticationSection extends ConsumerWidget {
12 | const AuthenticationSection({super.key});
13 |
14 | @override
15 | Widget build(context, ref) {
16 | final authType = ref.watch(authTypeKeyProvider);
17 | return Column(
18 | crossAxisAlignment: CrossAxisAlignment.start,
19 | children: [
20 | SectionTitle(title: context.l10n.authentication),
21 | const AuthTypeTile(),
22 | if (authType != null && authType != AuthType.none)
23 | ListTile(
24 | leading: const Icon(Icons.password_rounded),
25 | title: Text(context.l10n.credentials),
26 | onTap: () {
27 | showDialog(
28 | context: context,
29 | builder: (context) => const CredentialsPopup(),
30 | );
31 | },
32 | ),
33 | ],
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/lib/src/features/settings/presentation/server/widget/client/client_section.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | import '../../../../../../utils/extensions/custom_extensions.dart';
4 | import '../../../../../../widgets/section_title.dart';
5 | import 'server_port_tile/server_port_tile.dart';
6 | import 'server_url_tile/server_url_tile.dart';
7 |
8 | class ClientSection extends StatelessWidget {
9 | const ClientSection({super.key});
10 |
11 | @override
12 | Widget build(BuildContext context) {
13 | return Column(
14 | crossAxisAlignment: CrossAxisAlignment.start,
15 | children: [
16 | SectionTitle(title: context.l10n.client),
17 | const ServerUrlTile(),
18 | const ServerPortTile(),
19 | ],
20 | );
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/lib/src/graphql/domain/page_info.dart:
--------------------------------------------------------------------------------
1 | import '../__generated__/fragments.graphql.dart';
2 |
3 | typedef PageInfo = Fragment$PageInfoDto;
4 |
--------------------------------------------------------------------------------
/lib/src/graphql/fragments.graphql:
--------------------------------------------------------------------------------
1 | fragment PageInfoDto on PageInfo {
2 | endCursor
3 | hasNextPage
4 | hasPreviousPage
5 | startCursor
6 | }
7 |
--------------------------------------------------------------------------------
/lib/src/l10n/app_fil.arb:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/lib/src/l10n/app_nl.arb:
--------------------------------------------------------------------------------
1 | {}
2 |
--------------------------------------------------------------------------------
/lib/src/l10n/app_th.arb:
--------------------------------------------------------------------------------
1 | {
2 | "appTheme": "โหมดธีมแอป",
3 | "@appTheme": {
4 | "description": "Popup title and Button text to change App Theme Mode"
5 | },
6 | "addToLibrary": "เพิ่มเข้าในไลบรารี",
7 | "@addToLibrary": {
8 | "description": "Button text to add Manga to Library in Manga Details Screen"
9 | },
10 | "about": "เกี่ยวกับ",
11 | "@about": {
12 | "description": "Screen title and Button text of About screen"
13 | },
14 | "addCategory": "เพิ่มหมวดหมู่",
15 | "@addCategory": {
16 | "description": "Popup title and Button text to add new category in Edit Category Screen"
17 | },
18 | "allScanlators": "ตัวสแกนแปลทั้งหมด",
19 | "@allScanlators": {
20 | "description": "Text for all Scanlators in manga description screen chapter filter"
21 | },
22 | "appTitle": "ทาจิเดสก์ โซราโยมิ",
23 | "@appTitle": {
24 | "description": "Name of the app (Tachidesk Sorayomi in native script)"
25 | },
26 | "appearance": "รูปร่าง",
27 | "@appearance": {
28 | "description": "Screen title and Button text of Appearance screen"
29 | },
30 | "authType": "ประเภทการรับรองความถูกต้อง",
31 | "@authType": {
32 | "description": "Popup title and Button text to change App Authentication"
33 | },
34 | "appLanguage": "ภาษาแอป",
35 | "@appLanguage": {
36 | "description": "Popup title and Button text to change App Language"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/routes/sub_routes/downloads_routes.dart:
--------------------------------------------------------------------------------
1 | part of '../router_config.dart';
2 |
3 | class DownloadsBranch extends StatefulShellBranchData {
4 | const DownloadsBranch();
5 | }
6 |
7 | class DownloadsRoute extends GoRouteData {
8 | const DownloadsRoute();
9 | @override
10 | Widget build(context, state) => const DownloadsScreen();
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/routes/sub_routes/library_routes.dart:
--------------------------------------------------------------------------------
1 | part of '../router_config.dart';
2 |
3 | // Library Branch
4 | class LibraryBranch extends StatefulShellBranchData {
5 | static final $initialLocation = const LibraryRoute(categoryId: 0).location;
6 | const LibraryBranch();
7 | }
8 |
9 | class LibraryRoute extends GoRouteData {
10 | const LibraryRoute({required this.categoryId});
11 | final int categoryId;
12 | @override
13 | Widget build(context, state) => LibraryScreen(categoryId: categoryId);
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/routes/sub_routes/updates_routes.dart:
--------------------------------------------------------------------------------
1 | part of '../router_config.dart';
2 |
3 | class UpdatesBranch extends StatefulShellBranchData {
4 | const UpdatesBranch();
5 | }
6 |
7 | class UpdatesRoute extends GoRouteData {
8 | const UpdatesRoute();
9 | @override
10 | Widget build(context, state) => const UpdatesScreen();
11 | }
12 |
--------------------------------------------------------------------------------
/lib/src/utils/callbacks.dart:
--------------------------------------------------------------------------------
1 | typedef Convert = O Function(I);
2 |
3 | typedef ConvertO = O? Function(I);
4 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'dart:math';
8 |
9 | import 'package:flutter/foundation.dart';
10 | import 'package:flutter/material.dart';
11 | import 'package:go_router/go_router.dart';
12 | import "package:gql/language.dart" show printNode;
13 | import 'package:graphql/client.dart';
14 | import 'package:hooks_riverpod/hooks_riverpod.dart';
15 | import 'package:intl/intl.dart';
16 |
17 | import '../../l10n/generated/app_localizations.dart';
18 | import '../../widgets/custom_circular_progress_indicator.dart';
19 | import '../../widgets/emoticons.dart';
20 | import '../callbacks.dart';
21 | import '../logger/logger.dart';
22 | import '../misc/app_utils.dart';
23 | import '../misc/toast/toast.dart';
24 |
25 | part 'custom_extensions/async_value_extensions.dart';
26 | part 'custom_extensions/bool_extensions.dart';
27 | part 'custom_extensions/context_extensions.dart';
28 | part 'custom_extensions/date_time_extensions.dart';
29 | part 'custom_extensions/double_extensions.dart';
30 | part 'custom_extensions/generic_extensions.dart';
31 | part 'custom_extensions/graphql_extensions.dart';
32 | part 'custom_extensions/int_extensions.dart';
33 | part 'custom_extensions/iterable_extensions.dart';
34 | part 'custom_extensions/logger_extensions.dart';
35 | part 'custom_extensions/map_extensions.dart';
36 | part 'custom_extensions/string_extensions.dart';
37 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions/bool_extensions.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | part of '../custom_extensions.dart';
8 |
9 | extension BoolExtensions on bool? {
10 | bool get isNull => this == null;
11 | bool get isNotNull => !isNull;
12 | bool ifNull([bool alternative = false]) => this ?? alternative;
13 | int get toInt => this != null ? (this! ? 1 : 2) : 0;
14 | int get toIntWithNegative => this != null ? (this! ? 1 : -1) : 0;
15 | }
16 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions/double_extensions.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | part of '../custom_extensions.dart';
8 |
9 | extension DoubleExtensions on double? {
10 | bool liesBetween({double lower = 0, double upper = 1}) =>
11 | this != null ? this! >= lower && this! <= upper : false;
12 | bool get isZero => this != null ? this! == 0 : true;
13 | bool get isNotZero => !isZero;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions/generic_extensions.dart:
--------------------------------------------------------------------------------
1 | part of '../custom_extensions.dart';
2 |
3 | extension ApplyExtension on T? {
4 | U? apply(Convert convert) {
5 | if (this != null) return convert(this as T);
6 | return null;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions/iterable_extensions.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | part of '../custom_extensions.dart';
8 |
9 | extension IterableExtensions on Iterable? {
10 | bool get isNull => this == null;
11 |
12 | bool get isBlank => isNull || this!.isEmpty;
13 |
14 | bool get isNotBlank => !isBlank;
15 |
16 | bool get isSingletonList => isNotBlank && this!.length == 1;
17 |
18 | T? get firstOrNull {
19 | if (isNull) return null;
20 | var iterator = this!.iterator;
21 | if (iterator.moveNext()) return iterator.current;
22 | return null;
23 | }
24 |
25 | String get toPath => isNotBlank ? this!.join("/") : "/";
26 |
27 | T? lastWhereOrNull(bool Function(T element) test, {T Function()? orElse}) {
28 | if (isNull) return null;
29 | try {
30 | return this!.lastWhere(test, orElse: orElse);
31 | } catch (e) {
32 | return null;
33 | }
34 | }
35 |
36 | T? firstWhereOrNull(bool Function(T element) test, {T Function()? orElse}) {
37 | if (isNull) return null;
38 | try {
39 | return this!.firstWhere(test, orElse: orElse);
40 | } catch (e) {
41 | return null;
42 | }
43 | }
44 |
45 | T? get getRandom =>
46 | isNull ? null : this!.elementAt(Random().nextInt(this!.length));
47 |
48 | Iterable? get filterOutNulls => this?.where((element) => element != null);
49 | }
50 |
--------------------------------------------------------------------------------
/lib/src/utils/extensions/custom_extensions/map_extensions.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 | part of '../custom_extensions.dart';
7 |
8 | extension MapExtensions on Map {
9 | Map get filterOutNulls {
10 | final Map filtered = {};
11 | forEach((K key, V value) {
12 | if (value != null) filtered[key] = value;
13 | });
14 | return filtered;
15 | }
16 |
17 | Map toggleKey(K key, V value) {
18 | if (containsKey(key)) {
19 | return {...this}..remove(key);
20 | } else {
21 | return {...this, key: value};
22 | }
23 | }
24 | }
25 |
26 | extension NullableMapExtensions on Map? {
27 | bool get isNull => this == null;
28 |
29 | bool get isBlank => isNull || this!.isEmpty;
30 |
31 | bool get isNotBlank => !isBlank;
32 |
33 | String get toToastString {
34 | String result = "";
35 | this?.forEach((key, value) {
36 | if (value == null) return;
37 | if (result.isNotBlank) {
38 | result += "\n";
39 | }
40 | result += value.toString();
41 | });
42 | return result;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/lib/src/utils/freezed_converters/language_json_converter.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import '../../constants/language_list.dart';
8 | import '../../features/browse_center/domain/language/language_model.dart';
9 |
10 | class LanguageJsonConverter {
11 | static Language? fromJson(String? langCode) => langCode != null
12 | ? languageMap[langCode.toLowerCase()] ??
13 | Language(code: langCode.toLowerCase())
14 | : null;
15 | static String? toJson(Language? lang) => lang?.code;
16 | }
17 |
--------------------------------------------------------------------------------
/lib/src/utils/hooks/polling_hook.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 |
5 | T? usePolling({
6 | required Duration pollingInterval,
7 | required FutureOr Function() pollFunction,
8 | bool delayedStart = false,
9 | }) {
10 | final data = useState(null);
11 |
12 | useEffect(() {
13 | Future poll() async {
14 | while (true) {
15 | if (delayedStart) {
16 | await Future.delayed(pollingInterval);
17 | }
18 | final result = await pollFunction();
19 | data.value = result;
20 | if (!delayedStart) {
21 | await Future.delayed(pollingInterval);
22 | }
23 | }
24 | }
25 |
26 | poll();
27 |
28 | // Cleanup function
29 | return () {
30 | // No cleanup needed for this simple example
31 | };
32 | }, []);
33 |
34 | return data.value;
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/utils/launch_url_in_web.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter/services.dart';
9 | import 'package:url_launcher/url_launcher.dart';
10 |
11 | import 'extensions/custom_extensions.dart';
12 | import 'misc/toast/toast.dart';
13 |
14 | Future launchUrlInWeb(BuildContext context, String url,
15 | [Toast? toast]) async {
16 | if (!await launchUrl(
17 | Uri.parse(url),
18 | mode: LaunchMode.externalApplication,
19 | webOnlyWindowName: "_blank",
20 | )) {
21 | await Clipboard.setData(ClipboardData(text: url));
22 | if (context.mounted) toast?.showError(context.l10n.errorLaunchURL(url));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/lib/src/utils/logger/logger.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:logger/logger.dart' as l;
3 | import 'package:logger/web.dart';
4 |
5 | class Logger {
6 | static final l.Logger _logger = l.Logger(
7 | printer: l.PrettyPrinter(
8 | errorMethodCount: 30,
9 | printEmojis: false,
10 | dateTimeFormat: DateTimeFormat.onlyTimeAndSinceStart,
11 | ),
12 | output: MyConsoleOutput(),
13 | );
14 |
15 | const Logger._();
16 |
17 | static l.Logger get instance => _logger;
18 | }
19 |
20 | l.Logger get logger => Logger.instance;
21 |
22 | class MyConsoleOutput extends ConsoleOutput {
23 | @override
24 | void output(OutputEvent event) {
25 | for (int i = 0; i < event.lines.length; i++) {
26 | debugPrint(event.lines[i]);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/src/utils/logger/logger_link.dart:
--------------------------------------------------------------------------------
1 | import 'package:graphql/client.dart';
2 |
3 | class LoggerLink extends Link {
4 | @override
5 | Stream request(
6 | Request request, [
7 | NextLink? forward,
8 | ]) {
9 | Stream response = forward!(request).map((Response fetchResult) {
10 | // if (kDebugMode) {
11 | // request.log();
12 | // logger.i(fetchResult.response);
13 | // }
14 | return fetchResult;
15 | }).handleError((error) {
16 | throw error;
17 | });
18 |
19 | return response;
20 | }
21 |
22 | LoggerLink();
23 | }
24 |
--------------------------------------------------------------------------------
/lib/src/utils/logger/provider_state_logger.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/rendering.dart';
8 | import 'package:hooks_riverpod/hooks_riverpod.dart';
9 |
10 | /// Useful to log state change in our application
11 | /// Read the logs and you'll better understand what's going on under the hood
12 | class ProviderStateLogger extends ProviderObserver {
13 | const ProviderStateLogger();
14 | @override
15 | void didUpdateProvider(
16 | ProviderBase provider,
17 | Object? previousValue,
18 | Object? newValue,
19 | ProviderContainer container,
20 | ) {
21 | debugPrint('''
22 | {
23 | provider: ${provider.name ?? provider.runtimeType},
24 | oldValue: $previousValue,
25 | newValue: $newValue
26 | }
27 | ''');
28 | super.didUpdateProvider(provider, previousValue, newValue, container);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/lib/src/utils/misc/number_range_formatter.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/services.dart';
2 |
3 | class NumberRangeFormatter extends TextInputFormatter {
4 | final int maxValue;
5 |
6 | NumberRangeFormatter({required this.maxValue});
7 |
8 | @override
9 | TextEditingValue formatEditUpdate(
10 | TextEditingValue oldValue,
11 | TextEditingValue newValue,
12 | ) {
13 | if (newValue.text.isEmpty) {
14 | return const TextEditingValue(
15 | text: "",
16 | selection: TextSelection.collapsed(offset: 0),
17 | );
18 | }
19 | String truncated = newValue.text;
20 | TextSelection newSelection = newValue.selection;
21 |
22 | int parsedValue = int.tryParse(newValue.text) ?? 0;
23 | if (parsedValue > maxValue) {
24 | truncated = oldValue.text;
25 | newSelection = oldValue.selection;
26 | }
27 |
28 | return TextEditingValue(
29 | text: truncated,
30 | selection: newSelection,
31 | composing: TextRange.empty,
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/utils/misc/scalars.dart:
--------------------------------------------------------------------------------
1 | import "package:http/http.dart" show MultipartFile;
2 |
3 | export "package:http/http.dart" show MultipartFile;
4 |
5 | MultipartFile fileFromJson(dynamic data) {
6 | return data as MultipartFile;
7 | }
8 |
9 | dynamic fileToJson(MultipartFile data) {
10 | return data;
11 | }
12 |
13 | dynamic dateTimeToJson(DateTime data) {
14 | return data.millisecondsSinceEpoch ~/ 1000;
15 | }
16 |
17 | DateTime dateTimeFromJson(dynamic data) {
18 | return DateTime.fromMillisecondsSinceEpoch(data & 1000);
19 | }
20 |
21 | dynamic longStringToJson(String data) {
22 | return data;
23 | }
24 |
25 | String longStringFromJson(dynamic data) {
26 | return data.toString();
27 | }
28 |
29 | dynamic cursorToJson(int data) {
30 | return data;
31 | }
32 |
33 | int cursorFromJson(dynamic data) {
34 | return int.tryParse(data) ?? 0;
35 | }
36 |
--------------------------------------------------------------------------------
/lib/src/utils/mixin/state_provider_mixin.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | mixin StateProviderMixin {
10 | @protected
11 | set state(State value);
12 |
13 | void update(State state) => this.state = state;
14 | }
15 |
--------------------------------------------------------------------------------
/lib/src/widgets/async_buttons/async_checkbox_list_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_hooks/flutter_hooks.dart';
9 |
10 | import '../../utils/extensions/custom_extensions.dart';
11 |
12 | class AsyncCheckboxListTile extends HookWidget {
13 | const AsyncCheckboxListTile({
14 | super.key,
15 | required this.value,
16 | this.onChanged,
17 | required this.title,
18 | });
19 |
20 | final bool value;
21 | final ValueChanged? onChanged;
22 | final Widget title;
23 | @override
24 | Widget build(BuildContext context) {
25 | final localValue = useState(value);
26 | useEffect(() {
27 | localValue.value = value;
28 | return null;
29 | }, [value]);
30 | return CheckboxListTile(
31 | value: localValue.value,
32 | onChanged: onChanged != null
33 | ? (val) {
34 | localValue.value = (val.ifNull());
35 | onChanged!(val.ifNull());
36 | }
37 | : null,
38 | title: title,
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/lib/src/widgets/async_buttons/async_elevated_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 |
5 | import '../custom_circular_progress_indicator.dart';
6 |
7 | class AsyncElevatedButton extends HookWidget {
8 | const AsyncElevatedButton({
9 | super.key,
10 | required this.onPressed,
11 | required this.child,
12 | this.style,
13 | });
14 | final AsyncCallback? onPressed;
15 | final Widget child;
16 | final ButtonStyle? style;
17 | @override
18 | Widget build(BuildContext context) {
19 | final isLoading = useState(false);
20 | return ElevatedButton(
21 | onPressed: onPressed == null || isLoading.value
22 | ? null
23 | : () async {
24 | isLoading.value = (true);
25 | await onPressed?.call();
26 | isLoading.value = (false);
27 | },
28 | style: style,
29 | child: isLoading.value
30 | ? const MiniCircularProgressIndicator(color: Colors.white)
31 | : child,
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/lib/src/widgets/async_buttons/async_list_tile.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 |
5 | import '../custom_circular_progress_indicator.dart';
6 |
7 | class AsyncListTile extends HookWidget {
8 | const AsyncListTile({
9 | super.key,
10 | this.leading,
11 | this.title,
12 | this.subtitle,
13 | this.trailing,
14 | this.onTap,
15 | this.showInLeading = true,
16 | });
17 | final Widget? leading;
18 | final Widget? title;
19 | final Widget? subtitle;
20 | final Widget? trailing;
21 | final AsyncValueSetter>? onTap;
22 | final bool showInLeading;
23 | @override
24 | Widget build(BuildContext context) {
25 | final isLoading = useState(false);
26 | return ListTile(
27 | leading: showInLeading && isLoading.value
28 | ? const MiniCircularProgressIndicator()
29 | : leading,
30 | title: title,
31 | subtitle: subtitle,
32 | trailing: trailing,
33 | onTap: onTap == null
34 | ? null
35 | : () async {
36 | isLoading.value = true;
37 | await onTap?.call(isLoading);
38 | isLoading.value = false;
39 | },
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/lib/src/widgets/async_buttons/async_outline_button.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/foundation.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_hooks/flutter_hooks.dart';
4 |
5 | import '../custom_circular_progress_indicator.dart';
6 |
7 | class AsyncOutlineButton extends HookWidget {
8 | const AsyncOutlineButton({
9 | super.key,
10 | required this.onPressed,
11 | required this.child,
12 | this.style,
13 | });
14 | final AsyncCallback? onPressed;
15 | final Widget child;
16 | final ButtonStyle? style;
17 | @override
18 | Widget build(BuildContext context) {
19 | final isLoading = useState(false);
20 | return OutlinedButton(
21 | onPressed: onPressed == null || isLoading.value
22 | ? null
23 | : () async {
24 | isLoading.value = (true);
25 | await onPressed?.call();
26 | isLoading.value = (false);
27 | },
28 | style: style,
29 | child: isLoading.value ? const MiniCircularProgressIndicator() : child,
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/lib/src/widgets/async_buttons/async_text_button.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2023 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/foundation.dart';
8 | import 'package:flutter/material.dart';
9 | import 'package:flutter_hooks/flutter_hooks.dart';
10 |
11 | import '../custom_circular_progress_indicator.dart';
12 |
13 | class AsyncTextButton extends HookWidget {
14 | const AsyncTextButton({
15 | super.key,
16 | required this.onPressed,
17 | required this.child,
18 | this.icon,
19 | });
20 |
21 | final AsyncCallback? onPressed;
22 | final Widget child;
23 | final Widget? icon;
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | final isLoading = useState(false);
28 | return TextButton.icon(
29 | onPressed: (!isLoading.value && onPressed != null)
30 | ? () async {
31 | isLoading.value = (true);
32 | await onPressed!();
33 | isLoading.value = (false);
34 | }
35 | : null,
36 | icon: isLoading.value ? const SizedBox.shrink() : icon,
37 | label: isLoading.value ? const MiniCircularProgressIndicator() : child,
38 | );
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/lib/src/widgets/custom_checkbox_list_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import 'package:hooks_riverpod/hooks_riverpod.dart';
10 |
11 | import '../utils/extensions/custom_extensions.dart';
12 |
13 | class CustomCheckboxListTile>
14 | extends ConsumerWidget {
15 | const CustomCheckboxListTile({
16 | super.key,
17 | required this.title,
18 | required this.provider,
19 | required this.onChanged,
20 | this.tristate = true,
21 | });
22 | final String title;
23 | final AutoDisposeNotifierProvider provider;
24 | final ValueChanged onChanged;
25 | final bool tristate;
26 | @override
27 | Widget build(BuildContext context, WidgetRef ref) {
28 | final val = ref.watch(provider);
29 | return CheckboxListTile(
30 | controlAffinity: ListTileControlAffinity.leading,
31 | activeColor: context.theme.indicatorColor,
32 | value: tristate ? val : val.ifNull(true),
33 | title: Text(title),
34 | tristate: tristate,
35 | onChanged: onChanged,
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/lib/src/widgets/input_popup/domain/settings_prop_type.dart:
--------------------------------------------------------------------------------
1 | import 'package:freezed_annotation/freezed_annotation.dart';
2 |
3 | part 'settings_prop_type.freezed.dart';
4 |
5 | typedef SettingsUpdateRequest = Future Function(V);
6 |
7 | @freezed
8 | sealed class SettingsPropType with _$SettingsPropType {
9 | const factory SettingsPropType.textField({
10 | String? hintText,
11 | String? value,
12 | SettingsUpdateRequest? onChanged,
13 | @Default(false) bool canObscure,
14 | }) = TextFieldProp;
15 | const factory SettingsPropType.numberPicker({
16 | required int min,
17 | required int max,
18 | int? value,
19 | SettingsUpdateRequest? onChanged,
20 | }) = NumberPickerProp;
21 | const factory SettingsPropType.numberSlider({
22 | required int min,
23 | required int max,
24 | int? value,
25 | SettingsUpdateRequest? onChanged,
26 | }) = NumberSliderProp;
27 | const factory SettingsPropType.switchTile({
28 | bool? value,
29 | SettingsUpdateRequest? onChanged,
30 | }) = SwitchProp;
31 | }
32 |
--------------------------------------------------------------------------------
/lib/src/widgets/manga_cover/providers/manga_cover_providers.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:riverpod_annotation/riverpod_annotation.dart';
8 |
9 | import '../../../constants/db_keys.dart';
10 | import '../../../utils/mixin/shared_preferences_client_mixin.dart';
11 |
12 | part 'manga_cover_providers.g.dart';
13 |
14 | @riverpod
15 | class DownloadedBadge extends _$DownloadedBadge
16 | with SharedPreferenceClientMixin {
17 | @override
18 | bool? build() => initialize(DBKeys.downloadedBadge);
19 | }
20 |
21 | @riverpod
22 | class UnreadBadge extends _$UnreadBadge with SharedPreferenceClientMixin {
23 | @override
24 | bool? build() => initialize(DBKeys.unreadBadge);
25 | }
26 |
27 | // @riverpod
28 | // class LanguageBadge extends _$LanguageBadge
29 | // with SharedPreferenceClient {
30 | // @override
31 | // bool? build() => initialize(
32 | //
33 | // key: DBKeys.languageBadge.name,
34 | // initial: DBKeys.languageBadge.initial,
35 | // );
36 | // }
37 |
--------------------------------------------------------------------------------
/lib/src/widgets/number_picker/number_picker_with_label.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_hooks/flutter_hooks.dart';
3 |
4 | import 'number_picker.dart';
5 |
6 | class NumberPickerWithLabel extends HookWidget {
7 | const NumberPickerWithLabel({
8 | super.key,
9 | required this.label,
10 | required this.min,
11 | required this.max,
12 | required this.value,
13 | required this.onChanged,
14 | this.textFieldWidth = 24,
15 | });
16 | final String label;
17 |
18 | final int min;
19 | final int max;
20 | final int value;
21 | final ValueChanged onChanged;
22 | final double textFieldWidth;
23 |
24 | @override
25 | Widget build(BuildContext context) {
26 | useEffect(() {
27 | Future.microtask(() => onChanged(value));
28 | return null;
29 | }, []);
30 | return Row(
31 | children: [
32 | Expanded(
33 | child: Text(label),
34 | ),
35 | NumberPicker(
36 | value: value,
37 | min: min,
38 | max: max,
39 | onChanged: onChanged,
40 | textFieldWidth: textFieldWidth,
41 | ),
42 | ],
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/lib/src/widgets/popup_widgets/pop_button.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../../utils/extensions/custom_extensions.dart';
10 |
11 | class PopButton extends StatelessWidget {
12 | const PopButton({super.key, this.popText});
13 | final String? popText;
14 | @override
15 | Widget build(BuildContext context) {
16 | return TextButton(
17 | onPressed: () => Navigator.pop(context),
18 | child: Text(popText ?? context.l10n.cancel),
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/src/widgets/section_title.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import '../constants/app_sizes.dart';
4 | import '../utils/extensions/custom_extensions.dart';
5 |
6 | class SectionTitle extends StatelessWidget {
7 | const SectionTitle({super.key, required this.title});
8 | final String title;
9 | @override
10 | Widget build(BuildContext context) => Padding(
11 | padding: KEdgeInsets.h16.size + KEdgeInsets.v4.size,
12 | child: Text(
13 | title,
14 | style: context.textTheme.titleSmall
15 | ?.copyWith(color: context.theme.primaryColor),
16 | ),
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/lib/src/widgets/sort_list_tile.dart:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2022 Contributors to the Suwayomi project
2 | //
3 | // This Source Code Form is subject to the terms of the Mozilla Public
4 | // License, v. 2.0. If a copy of the MPL was not distributed with this
5 | // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 |
7 | import 'package:flutter/material.dart';
8 |
9 | import '../utils/extensions/custom_extensions.dart';
10 |
11 | class SortListTile extends StatelessWidget {
12 | const SortListTile({
13 | super.key,
14 | required this.ascending,
15 | required this.selected,
16 | required this.onChanged,
17 | required this.onSelected,
18 | this.title,
19 | this.subtitle,
20 | });
21 | final bool ascending;
22 | final bool selected;
23 | final ValueChanged onChanged;
24 | final VoidCallback onSelected;
25 | final Widget? title;
26 | final Widget? subtitle;
27 | @override
28 | Widget build(BuildContext context) {
29 | IconData icon =
30 | ascending ? Icons.arrow_upward_rounded : Icons.arrow_downward_rounded;
31 |
32 | return ListTile(
33 | leading: selected
34 | ? Icon(icon, color: context.theme.indicatorColor)
35 | : SizedBox(width: context.theme.iconTheme.size),
36 | title: title,
37 | subtitle: subtitle,
38 | onTap: () => selected ? onChanged(!ascending) : onSelected(),
39 | );
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/linux/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral
2 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 |
11 | void fl_register_plugins(FlPluginRegistry* registry) {
12 | g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
13 | fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
14 | url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
15 | }
16 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void fl_register_plugins(FlPluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/linux/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | url_launcher_linux
7 | )
8 |
9 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
10 | )
11 |
12 | set(PLUGIN_BUNDLED_LIBRARIES)
13 |
14 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
15 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
16 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
18 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
19 | endforeach(plugin)
20 |
21 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
22 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
23 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
24 | endforeach(ffi_plugin)
25 |
--------------------------------------------------------------------------------
/linux/main.cc:
--------------------------------------------------------------------------------
1 | #include "my_application.h"
2 |
3 | int main(int argc, char** argv) {
4 | g_autoptr(MyApplication) app = my_application_new();
5 | return g_application_run(G_APPLICATION(app), argc, argv);
6 | }
7 |
--------------------------------------------------------------------------------
/linux/my_application.h:
--------------------------------------------------------------------------------
1 | #ifndef FLUTTER_MY_APPLICATION_H_
2 | #define FLUTTER_MY_APPLICATION_H_
3 |
4 | #include
5 |
6 | G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
7 | GtkApplication)
8 |
9 | /**
10 | * my_application_new:
11 | *
12 | * Creates a new Flutter-based application.
13 | *
14 | * Returns: a new #MyApplication.
15 | */
16 | MyApplication* my_application_new();
17 |
18 | #endif // FLUTTER_MY_APPLICATION_H_
19 |
--------------------------------------------------------------------------------
/macos/.gitignore:
--------------------------------------------------------------------------------
1 | # Flutter-related
2 | **/Flutter/ephemeral/
3 | **/Pods/
4 |
5 | # Xcode-related
6 | **/dgph
7 | **/xcuserdata/
8 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/Flutter-Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "ephemeral/Flutter-Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Flutter/GeneratedPluginRegistrant.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | import FlutterMacOS
6 | import Foundation
7 |
8 | import connectivity_plus
9 | import file_picker
10 | import network_info_plus
11 | import package_info_plus
12 | import path_provider_foundation
13 | import shared_preferences_foundation
14 | import sqflite_darwin
15 | import url_launcher_macos
16 |
17 | func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
18 | ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
19 | FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
20 | NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin"))
21 | FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
22 | PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
23 | SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
24 | SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
25 | UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
26 | }
27 |
--------------------------------------------------------------------------------
/macos/Podfile:
--------------------------------------------------------------------------------
1 | platform :osx, '10.15'
2 |
3 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
4 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
5 |
6 | project 'Runner', {
7 | 'Debug' => :debug,
8 | 'Profile' => :release,
9 | 'Release' => :release,
10 | }
11 |
12 | def flutter_root
13 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'ephemeral', 'Flutter-Generated.xcconfig'), __FILE__)
14 | unless File.exist?(generated_xcode_build_settings_path)
15 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure \"flutter pub get\" is executed first"
16 | end
17 |
18 | File.foreach(generated_xcode_build_settings_path) do |line|
19 | matches = line.match(/FLUTTER_ROOT\=(.*)/)
20 | return matches[1].strip if matches
21 | end
22 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Flutter-Generated.xcconfig, then run \"flutter pub get\""
23 | end
24 |
25 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
26 |
27 | flutter_macos_podfile_setup
28 |
29 | target 'Runner' do
30 | use_frameworks!
31 | use_modular_headers!
32 |
33 | flutter_install_all_macos_pods File.dirname(File.realpath(__FILE__))
34 | end
35 |
36 | post_install do |installer|
37 | installer.pods_project.targets.each do |target|
38 | flutter_additional_macos_build_settings(target)
39 | target.build_configurations.each do |config|
40 | config.build_settings['MACOSX_DEPLOYMENT_TARGET'] = '10.15'
41 | end
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/macos/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | @main
5 | class AppDelegate: FlutterAppDelegate {
6 | override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
7 | return true
8 | }
9 |
10 | override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
11 | return true
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png
--------------------------------------------------------------------------------
/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png
--------------------------------------------------------------------------------
/macos/Runner/Configs/AppInfo.xcconfig:
--------------------------------------------------------------------------------
1 | // Application-level settings for the Runner target.
2 | //
3 | // This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
4 | // future. If not, the values below would default to using the project name when this becomes a
5 | // 'flutter create' template.
6 |
7 | // The application's name. By default this is also the title of the Flutter window.
8 | PRODUCT_NAME = Sorayomi
9 |
10 | // The application's bundle identifier
11 | PRODUCT_BUNDLE_IDENTIFIER = com.suwayomi.tachideskSorayomi
12 |
13 | // The copyright displayed in application information
14 | PRODUCT_COPYRIGHT = Copyright © 2022 com.suwayomi. All rights reserved.
15 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Debug.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "../../Flutter/Flutter-Release.xcconfig"
2 | #include "Warnings.xcconfig"
3 |
--------------------------------------------------------------------------------
/macos/Runner/Configs/Warnings.xcconfig:
--------------------------------------------------------------------------------
1 | WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
2 | GCC_WARN_UNDECLARED_SELECTOR = YES
3 | CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
4 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
5 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
6 | CLANG_WARN_PRAGMA_PACK = YES
7 | CLANG_WARN_STRICT_PROTOTYPES = YES
8 | CLANG_WARN_COMMA = YES
9 | GCC_WARN_STRICT_SELECTOR_MATCH = YES
10 | CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
11 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
12 | GCC_WARN_SHADOW = YES
13 | CLANG_WARN_UNREACHABLE_CODE = YES
14 |
--------------------------------------------------------------------------------
/macos/Runner/DebugProfile.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.cs.allow-jit
8 |
9 | com.apple.security.network.server
10 |
11 | com.apple.security.network.client
12 |
13 | com.apple.security.files.user-selected.read-only
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/macos/Runner/MainFlutterWindow.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import FlutterMacOS
3 |
4 | class MainFlutterWindow: NSWindow {
5 | override func awakeFromNib() {
6 | let flutterViewController = FlutterViewController.init()
7 | let windowFrame = self.frame
8 | self.contentViewController = flutterViewController
9 | self.setFrame(windowFrame, display: true)
10 |
11 | RegisterGeneratedPlugins(registry: flutterViewController)
12 |
13 | super.awakeFromNib()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/macos/Runner/Release.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.network.client
8 |
9 | com.apple.security.files.user-selected.read-only
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/macos/build/.last_build_id:
--------------------------------------------------------------------------------
1 | b18191054b7e296b4379e9085d256a59
--------------------------------------------------------------------------------
/scripts/debian/changelog:
--------------------------------------------------------------------------------
1 | tachidesk-sorayomi ($pkgver-$pkgrel) unstable; urgency=medium
2 |
3 | * See https://github.com/Suwayomi/Tachidesk-Sorayomi
4 |
5 | -- Mahor Fri, 17 Feb 2022 00:00:00 +0000
6 |
--------------------------------------------------------------------------------
/scripts/debian/control:
--------------------------------------------------------------------------------
1 | Source: tachidesk-sorayomi
2 | Section: web
3 | Priority: optional
4 | Maintainer: Mahor
5 | Build-Depends: debhelper-compat (= 12)
6 | Standards-Version: 4.5.1
7 | Homepage: https://github.com/Suwayomi/Tachidesk-Sorayomi
8 |
9 | Package: tachidesk-sorayomi
10 | Architecture: amd64
11 | Depends: ${misc:Depends}, zenity
12 | Description: Manga Reader
13 | A free and open source manga reader server that runs extensions built for Tachiyomi.
14 | Tachidesk is an independent Tachiyomi compatible software and is not a Fork of Tachiyomi.
15 |
--------------------------------------------------------------------------------
/scripts/debian/install:
--------------------------------------------------------------------------------
1 | #!/usr/bin/dh-exec
2 |
3 | data opt/tachidesk-sorayomi/
4 | lib opt/tachidesk-sorayomi/
5 | tachidesk_sorayomi opt/tachidesk-sorayomi/
6 | tachidesk-sorayomi.png usr/share/pixmaps/
7 | tachidesk-sorayomi.desktop usr/share/applications/
8 |
--------------------------------------------------------------------------------
/scripts/debian/package.dirs:
--------------------------------------------------------------------------------
1 | opt/tachidesk-sorayomi/
2 |
3 |
--------------------------------------------------------------------------------
/scripts/debian/rules:
--------------------------------------------------------------------------------
1 | #!/usr/bin/make -f
2 | # See debhelper(7) (uncomment to enable)
3 | # output every command that modifies files on the build system.
4 | #export DH_VERBOSE = 1
5 |
6 | %:
7 | dh $@
8 |
9 | override_dh_strip_nondeterminism:
10 | true
11 |
--------------------------------------------------------------------------------
/scripts/debian/source/format:
--------------------------------------------------------------------------------
1 | 3.0 (quilt)
2 |
--------------------------------------------------------------------------------
/scripts/debian/source/include-binaries:
--------------------------------------------------------------------------------
1 | tachidesk-sorayomi.png
2 |
--------------------------------------------------------------------------------
/scripts/debian/tachidesk-sorayomi.links:
--------------------------------------------------------------------------------
1 | opt/tachidesk-sorayomi/tachidesk_sorayomi usr/bin/tachidesk-sorayomi
2 |
--------------------------------------------------------------------------------
/scripts/tachidesk-sorayomi.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Sorayomi
3 | Comment=Tachidesk UI flutter
4 | Exec=tachidesk-sorayomi
5 | Icon=tachidesk-sorayomi
6 | Terminal=false
7 | Type=Application
8 | Categories=Network;
9 |
--------------------------------------------------------------------------------
/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/favicon.png
--------------------------------------------------------------------------------
/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/icons/Icon-maskable-192.png
--------------------------------------------------------------------------------
/web/icons/Icon-maskable-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/icons/Icon-maskable-512.png
--------------------------------------------------------------------------------
/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tachidesk_sorayomi",
3 | "short_name": "tachidesk_sorayomi",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#54C5F8",
7 | "theme_color": "#54C5F8",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | },
22 | {
23 | "src": "icons/Icon-maskable-192.png",
24 | "sizes": "192x192",
25 | "type": "image/png",
26 | "purpose": "maskable"
27 | },
28 | {
29 | "src": "icons/Icon-maskable-512.png",
30 | "sizes": "512x512",
31 | "type": "image/png",
32 | "purpose": "maskable"
33 | }
34 | ]
35 | }
--------------------------------------------------------------------------------
/web/splash/img/branding-1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-1x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-2x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-3x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-4x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-dark-1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-dark-1x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-dark-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-dark-2x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-dark-3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-dark-3x.png
--------------------------------------------------------------------------------
/web/splash/img/branding-dark-4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/branding-dark-4x.png
--------------------------------------------------------------------------------
/web/splash/img/dark-1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/dark-1x.png
--------------------------------------------------------------------------------
/web/splash/img/dark-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/dark-2x.png
--------------------------------------------------------------------------------
/web/splash/img/dark-3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/dark-3x.png
--------------------------------------------------------------------------------
/web/splash/img/dark-4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/dark-4x.png
--------------------------------------------------------------------------------
/web/splash/img/light-1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/light-1x.png
--------------------------------------------------------------------------------
/web/splash/img/light-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/light-2x.png
--------------------------------------------------------------------------------
/web/splash/img/light-3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/light-3x.png
--------------------------------------------------------------------------------
/web/splash/img/light-4x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/web/splash/img/light-4x.png
--------------------------------------------------------------------------------
/web/splash/splash.js:
--------------------------------------------------------------------------------
1 | function removeSplashFromWeb() {
2 | document.getElementById("splash")?.remove();
3 | document.getElementById("splash-branding")?.remove();
4 | document.body.style.background = "transparent";
5 | }
6 |
--------------------------------------------------------------------------------
/web/splash/style.css:
--------------------------------------------------------------------------------
1 | html {
2 | height: 100%
3 | }
4 |
5 | body {
6 | margin: 0;
7 | min-height: 100%;
8 | background-color: #54C5F8;
9 | background-size: 100% 100%;
10 | }
11 |
12 | .center {
13 | margin: 0;
14 | position: absolute;
15 | top: 50%;
16 | left: 50%;
17 | -ms-transform: translate(-50%, -50%);
18 | transform: translate(-50%, -50%);
19 | }
20 |
21 | .contain {
22 | display:block;
23 | width:100%; height:100%;
24 | object-fit: contain;
25 | }
26 |
27 | .stretch {
28 | display:block;
29 | width:100%; height:100%;
30 | }
31 |
32 | .cover {
33 | display:block;
34 | width:100%; height:100%;
35 | object-fit: cover;
36 | }
37 |
38 | .bottom {
39 | position: absolute;
40 | bottom: 0;
41 | left: 50%;
42 | -ms-transform: translate(-50%, 0);
43 | transform: translate(-50%, 0);
44 | }
45 |
46 | .bottomLeft {
47 | position: absolute;
48 | bottom: 0;
49 | left: 0;
50 | }
51 |
52 | .bottomRight {
53 | position: absolute;
54 | bottom: 0;
55 | right: 0;
56 | }
57 |
58 | @media (prefers-color-scheme: dark) {
59 | body {
60 | background-color: #01579B;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 | #include
10 | #include
11 | #include
12 |
13 | void RegisterPlugins(flutter::PluginRegistry* registry) {
14 | ConnectivityPlusWindowsPluginRegisterWithRegistrar(
15 | registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
16 | PermissionHandlerWindowsPluginRegisterWithRegistrar(
17 | registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
18 | UrlLauncherWindowsRegisterWithRegistrar(
19 | registry->GetRegistrarForPlugin("UrlLauncherWindows"));
20 | }
21 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | connectivity_plus
7 | permission_handler_windows
8 | url_launcher_windows
9 | )
10 |
11 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
12 | )
13 |
14 | set(PLUGIN_BUNDLED_LIBRARIES)
15 |
16 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
17 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
18 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
19 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
20 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
21 | endforeach(plugin)
22 |
23 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
24 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
25 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
26 | endforeach(ffi_plugin)
27 |
--------------------------------------------------------------------------------
/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "win32_window.h"
10 |
11 | // A window that does nothing but host a Flutter view.
12 | class FlutterWindow : public Win32Window {
13 | public:
14 | // Creates a new FlutterWindow hosting a Flutter view running |project|.
15 | explicit FlutterWindow(const flutter::DartProject& project);
16 | virtual ~FlutterWindow();
17 |
18 | protected:
19 | // Win32Window:
20 | bool OnCreate() override;
21 | void OnDestroy() override;
22 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
23 | LPARAM const lparam) noexcept override;
24 |
25 | private:
26 | // The project to run.
27 | flutter::DartProject project_;
28 |
29 | // The Flutter instance hosted by this window.
30 | std::unique_ptr flutter_controller_;
31 | };
32 |
33 | #endif // RUNNER_FLUTTER_WINDOW_H_
34 |
--------------------------------------------------------------------------------
/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "utils.h"
7 |
8 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
9 | _In_ wchar_t *command_line, _In_ int show_command) {
10 | // Attach to console when present (e.g., 'flutter run') or create a
11 | // new console when running with a debugger.
12 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
13 | CreateAndAttachConsole();
14 | }
15 |
16 | // Initialize COM, so that it is available for use in the library and/or
17 | // plugins.
18 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
19 |
20 | flutter::DartProject project(L"data");
21 |
22 | std::vector command_line_arguments =
23 | GetCommandLineArguments();
24 |
25 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
26 |
27 | FlutterWindow window(project);
28 | Win32Window::Point origin(10, 10);
29 | Win32Window::Size size(1280, 720);
30 | if (!window.CreateAndShow(L"Sorayomi", origin, size)) {
31 | return EXIT_FAILURE;
32 | }
33 | window.SetQuitOnClose(true);
34 |
35 | ::MSG msg;
36 | while (::GetMessage(&msg, nullptr, 0, 0)) {
37 | ::TranslateMessage(&msg);
38 | ::DispatchMessage(&msg);
39 | }
40 |
41 | ::CoUninitialize();
42 | return EXIT_SUCCESS;
43 | }
44 |
--------------------------------------------------------------------------------
/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suwayomi/Tachidesk-Sorayomi/c4a3fd23cb90fa5c928e20e6e2ad10323134c767/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------