shoko 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.bundle/config +4 -0
- data/.bundle/config.bak +3 -0
- data/.rspec_status +42 -0
- data/.rubocop.yml +124 -0
- data/Gemfile +19 -0
- data/LICENSE +21 -0
- data/README.md +82 -0
- data/Rakefile +29 -0
- data/bin/start +15 -0
- data/lib/shoko/adapters/book_sources/document_service.rb +201 -0
- data/lib/shoko/adapters/book_sources/download_service.rb +95 -0
- data/lib/shoko/adapters/book_sources/epub/epub_resource_loader.rb +137 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/html_processor.rb +151 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/metadata_extractor.rb +53 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/entry_reader.rb +77 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/metadata_extractor.rb +67 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_context.rb +86 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_document_index.rb +75 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_document_scanner.rb +47 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_extractor.rb +46 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_label_resolver.rb +83 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_list_item.rb +55 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_result.rb +8 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_selector.rb +100 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_source_locator.rb +93 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_traversal.rb +103 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf/navigation_walker.rb +56 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/opf_processor.rb +102 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/xhtml_content_parser.rb +661 -0
- data/lib/shoko/adapters/book_sources/epub/parsers/xml_text_normalizer.rb +41 -0
- data/lib/shoko/adapters/book_sources/epub_document.rb +253 -0
- data/lib/shoko/adapters/book_sources/epub_finder/directory_scanner.rb +134 -0
- data/lib/shoko/adapters/book_sources/epub_finder/scanner_context.rb +28 -0
- data/lib/shoko/adapters/book_sources/epub_finder.rb +161 -0
- data/lib/shoko/adapters/book_sources/epub_importer.rb +268 -0
- data/lib/shoko/adapters/book_sources/gutendex_client.rb +150 -0
- data/lib/shoko/adapters/book_sources/library_scanner.rb +93 -0
- data/lib/shoko/adapters/book_sources/source_fingerprint.rb +57 -0
- data/lib/shoko/adapters/input/annotations/mouse_handler.rb +84 -0
- data/lib/shoko/adapters/input/command_bridge.rb +148 -0
- data/lib/shoko/adapters/input/command_factory.rb +255 -0
- data/lib/shoko/adapters/input/commands.rb +60 -0
- data/lib/shoko/adapters/input/dispatcher.rb +69 -0
- data/lib/shoko/adapters/input/input_controller.rb +250 -0
- data/lib/shoko/adapters/input/key_definitions.rb +108 -0
- data/lib/shoko/adapters/input/validators/file_path_validator.rb +81 -0
- data/lib/shoko/adapters/input/validators/terminal_size_validator.rb +76 -0
- data/lib/shoko/adapters/monitoring/logger.rb +150 -0
- data/lib/shoko/adapters/monitoring/perf_tracer.rb +183 -0
- data/lib/shoko/adapters/monitoring/performance_monitor.rb +110 -0
- data/lib/shoko/adapters/output/clipboard/clipboard_service.rb +125 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/image_builder.rb +149 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/text_wrapper.rb +149 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler/tokenizer.rb +91 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/line_assembler.rb +144 -0
- data/lib/shoko/adapters/output/formatting/formatting_service/plain_lines_builder.rb +54 -0
- data/lib/shoko/adapters/output/formatting/formatting_service.rb +247 -0
- data/lib/shoko/adapters/output/formatting/wrapping_service.rb +228 -0
- data/lib/shoko/adapters/output/instrumentation_service.rb +52 -0
- data/lib/shoko/adapters/output/kitty/image_transcoder.rb +71 -0
- data/lib/shoko/adapters/output/kitty/kitty_graphics.rb +114 -0
- data/lib/shoko/adapters/output/kitty/kitty_image_renderer.rb +239 -0
- data/lib/shoko/adapters/output/kitty/kitty_unicode_placeholders.rb +139 -0
- data/lib/shoko/adapters/output/kitty/kitty_unicode_placeholders_diacritic_codepoints.txt +26 -0
- data/lib/shoko/adapters/output/notification_service.rb +58 -0
- data/lib/shoko/adapters/output/render_registry.rb +45 -0
- data/lib/shoko/adapters/output/rendering/models/line_geometry.rb +60 -0
- data/lib/shoko/adapters/output/rendering/models/page_rendering_context.rb +22 -0
- data/lib/shoko/adapters/output/rendering/models/render_params.rb +28 -0
- data/lib/shoko/adapters/output/rendering/models/rendering_context.rb +58 -0
- data/lib/shoko/adapters/output/terminal/buffer.rb +275 -0
- data/lib/shoko/adapters/output/terminal/constants/terminal_defaults.rb +11 -0
- data/lib/shoko/adapters/output/terminal/input/decoder.rb +347 -0
- data/lib/shoko/adapters/output/terminal/input.rb +161 -0
- data/lib/shoko/adapters/output/terminal/output.rb +105 -0
- data/lib/shoko/adapters/output/terminal/terminal.rb +167 -0
- data/lib/shoko/adapters/output/terminal/terminal_sanitizer.rb +243 -0
- data/lib/shoko/adapters/output/terminal/terminal_service.rb +138 -0
- data/lib/shoko/adapters/output/terminal/text_metrics.rb +273 -0
- data/lib/shoko/adapters/output/ui/builders/page_setup_builder.rb +47 -0
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/footer_renderer.rb +80 -0
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/geometry.rb +61 -0
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay/note_renderer.rb +86 -0
- data/lib/shoko/adapters/output/ui/components/annotation_editor_overlay_component.rb +234 -0
- data/lib/shoko/adapters/output/ui/components/annotations_overlay/list_renderer.rb +142 -0
- data/lib/shoko/adapters/output/ui/components/annotations_overlay_component.rb +185 -0
- data/lib/shoko/adapters/output/ui/components/base_component.rb +110 -0
- data/lib/shoko/adapters/output/ui/components/component_interface.rb +80 -0
- data/lib/shoko/adapters/output/ui/components/content_component.rb +61 -0
- data/lib/shoko/adapters/output/ui/components/enhanced_popup_menu.rb +191 -0
- data/lib/shoko/adapters/output/ui/components/footer_component.rb +120 -0
- data/lib/shoko/adapters/output/ui/components/header_component.rb +46 -0
- data/lib/shoko/adapters/output/ui/components/layouts/horizontal.rb +63 -0
- data/lib/shoko/adapters/output/ui/components/layouts/vertical.rb +73 -0
- data/lib/shoko/adapters/output/ui/components/main_menu_component.rb +103 -0
- data/lib/shoko/adapters/output/ui/components/reading/base_view_renderer.rb +199 -0
- data/lib/shoko/adapters/output/ui/components/reading/config_helpers.rb +42 -0
- data/lib/shoko/adapters/output/ui/components/reading/help_renderer.rb +62 -0
- data/lib/shoko/adapters/output/ui/components/reading/inline_segment_highlighter.rb +144 -0
- data/lib/shoko/adapters/output/ui/components/reading/kitty_image_line_renderer.rb +262 -0
- data/lib/shoko/adapters/output/ui/components/reading/line_content_composer.rb +114 -0
- data/lib/shoko/adapters/output/ui/components/reading/line_drawer.rb +87 -0
- data/lib/shoko/adapters/output/ui/components/reading/line_geometry_builder.rb +41 -0
- data/lib/shoko/adapters/output/ui/components/reading/rendered_lines_recorder.rb +64 -0
- data/lib/shoko/adapters/output/ui/components/reading/single_view_renderer.rb +156 -0
- data/lib/shoko/adapters/output/ui/components/reading/split_view_renderer.rb +221 -0
- data/lib/shoko/adapters/output/ui/components/reading/view_renderer_factory.rb +20 -0
- data/lib/shoko/adapters/output/ui/components/reading/wrapped_lines_fetcher.rb +139 -0
- data/lib/shoko/adapters/output/ui/components/rect.rb +15 -0
- data/lib/shoko/adapters/output/ui/components/render_style.rb +84 -0
- data/lib/shoko/adapters/output/ui/components/screen_component.rb +24 -0
- data/lib/shoko/adapters/output/ui/components/screens/annotation_detail_screen_component.rb +175 -0
- data/lib/shoko/adapters/output/ui/components/screens/annotation_edit_screen_component.rb +221 -0
- data/lib/shoko/adapters/output/ui/components/screens/annotation_editor_screen_component.rb +205 -0
- data/lib/shoko/adapters/output/ui/components/screens/annotation_rendering_helpers.rb +190 -0
- data/lib/shoko/adapters/output/ui/components/screens/annotations_screen_component.rb +266 -0
- data/lib/shoko/adapters/output/ui/components/screens/base_screen_component.rb +49 -0
- data/lib/shoko/adapters/output/ui/components/screens/browse_screen_component.rb +319 -0
- data/lib/shoko/adapters/output/ui/components/screens/download_books_screen_component.rb +340 -0
- data/lib/shoko/adapters/output/ui/components/screens/library_screen_component.rb +205 -0
- data/lib/shoko/adapters/output/ui/components/screens/loading_overlay_component.rb +49 -0
- data/lib/shoko/adapters/output/ui/components/screens/menu_screen_component.rb +107 -0
- data/lib/shoko/adapters/output/ui/components/screens/settings_screen_component.rb +238 -0
- data/lib/shoko/adapters/output/ui/components/sidebar/annotations_tab_renderer.rb +159 -0
- data/lib/shoko/adapters/output/ui/components/sidebar/bookmarks_tab_renderer.rb +139 -0
- data/lib/shoko/adapters/output/ui/components/sidebar/tab_header_component.rb +157 -0
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_renderer.rb +111 -0
- data/lib/shoko/adapters/output/ui/components/sidebar/toc_tab_support.rb +1606 -0
- data/lib/shoko/adapters/output/ui/components/sidebar_panel_component.rb +217 -0
- data/lib/shoko/adapters/output/ui/components/surface.rb +88 -0
- data/lib/shoko/adapters/output/ui/components/tooltip_overlay_component.rb +224 -0
- data/lib/shoko/adapters/output/ui/components/ui/box_drawer.rb +32 -0
- data/lib/shoko/adapters/output/ui/components/ui/list_helpers.rb +33 -0
- data/lib/shoko/adapters/output/ui/components/ui/overlay_layout.rb +79 -0
- data/lib/shoko/adapters/output/ui/components/ui/text_utils.rb +46 -0
- data/lib/shoko/adapters/output/ui/constants/highlighting.rb +21 -0
- data/lib/shoko/adapters/output/ui/constants/messages.rb +12 -0
- data/lib/shoko/adapters/output/ui/constants/themes.rb +79 -0
- data/lib/shoko/adapters/output/ui/constants/ui_constants.rb +85 -0
- data/lib/shoko/adapters/output/ui/rendering/frame_coordinator.rb +42 -0
- data/lib/shoko/adapters/output/ui/rendering/reader_render_coordinator.rb +169 -0
- data/lib/shoko/adapters/output/ui/rendering/render_pipeline.rb +55 -0
- data/lib/shoko/adapters/storage/atomic_file_writer.rb +43 -0
- data/lib/shoko/adapters/storage/background_worker.rb +66 -0
- data/lib/shoko/adapters/storage/book_cache_pipeline.rb +653 -0
- data/lib/shoko/adapters/storage/cache/epub/memory_cache.rb +99 -0
- data/lib/shoko/adapters/storage/cache/epub/persistence.rb +131 -0
- data/lib/shoko/adapters/storage/cache/epub/serializer/deserialize.rb +225 -0
- data/lib/shoko/adapters/storage/cache/epub/serializer/helpers.rb +63 -0
- data/lib/shoko/adapters/storage/cache/epub/serializer/serialize.rb +83 -0
- data/lib/shoko/adapters/storage/cache/epub/serializer.rb +5 -0
- data/lib/shoko/adapters/storage/cache/epub/source_reference.rb +58 -0
- data/lib/shoko/adapters/storage/cache_paths.rb +21 -0
- data/lib/shoko/adapters/storage/cache_pointer_manager.rb +60 -0
- data/lib/shoko/adapters/storage/config_paths.rb +30 -0
- data/lib/shoko/adapters/storage/epub_cache.rb +195 -0
- data/lib/shoko/adapters/storage/file_writer_service.rb +47 -0
- data/lib/shoko/adapters/storage/json_cache_store/chapters.rb +141 -0
- data/lib/shoko/adapters/storage/json_cache_store/layouts.rb +67 -0
- data/lib/shoko/adapters/storage/json_cache_store/manifest.rb +42 -0
- data/lib/shoko/adapters/storage/json_cache_store/payload_helpers.rb +113 -0
- data/lib/shoko/adapters/storage/json_cache_store/resources.rb +84 -0
- data/lib/shoko/adapters/storage/json_cache_store.rb +167 -0
- data/lib/shoko/adapters/storage/lazy_file_string.rb +65 -0
- data/lib/shoko/adapters/storage/pagination_cache.rb +127 -0
- data/lib/shoko/adapters/storage/recent_files.rb +78 -0
- data/lib/shoko/adapters/storage/repositories/annotation_repository.rb +182 -0
- data/lib/shoko/adapters/storage/repositories/base_repository.rb +81 -0
- data/lib/shoko/adapters/storage/repositories/bookmark_repository.rb +132 -0
- data/lib/shoko/adapters/storage/repositories/cached_library_repository.rb +129 -0
- data/lib/shoko/adapters/storage/repositories/config_repository.rb +262 -0
- data/lib/shoko/adapters/storage/repositories/progress_repository.rb +166 -0
- data/lib/shoko/adapters/storage/repositories/storage/annotation_file_store.rb +128 -0
- data/lib/shoko/adapters/storage/repositories/storage/bookmark_file_store.rb +109 -0
- data/lib/shoko/adapters/storage/repositories/storage/file_store_utils.rb +20 -0
- data/lib/shoko/adapters/storage/repositories/storage/progress_file_store.rb +59 -0
- data/lib/shoko/application/annotation_editor_overlay_session.rb +138 -0
- data/lib/shoko/application/cli.rb +134 -0
- data/lib/shoko/application/controllers/menu/input_controller.rb +189 -0
- data/lib/shoko/application/controllers/menu/state_controller.rb +642 -0
- data/lib/shoko/application/controllers/menu_controller.rb +469 -0
- data/lib/shoko/application/controllers/mouseable_reader.rb +377 -0
- data/lib/shoko/application/controllers/reader_controller.rb +449 -0
- data/lib/shoko/application/controllers/state_controller.rb +410 -0
- data/lib/shoko/application/controllers/ui_controller.rb +782 -0
- data/lib/shoko/application/dependency_container.rb +301 -0
- data/lib/shoko/application/infrastructure/event_bus.rb +80 -0
- data/lib/shoko/application/infrastructure/observer_state_store.rb +136 -0
- data/lib/shoko/application/infrastructure/state_store.rb +413 -0
- data/lib/shoko/application/main_menu/menu_progress_presenter.rb +83 -0
- data/lib/shoko/application/pending_jump_handler.rb +122 -0
- data/lib/shoko/application/reader_lifecycle.rb +65 -0
- data/lib/shoko/application/reader_startup_orchestrator.rb +113 -0
- data/lib/shoko/application/selectors/config_selectors.rb +62 -0
- data/lib/shoko/application/selectors/menu_selectors.rb +62 -0
- data/lib/shoko/application/selectors/reader_selectors.rb +186 -0
- data/lib/shoko/application/state/actions/base_action.rb +24 -0
- data/lib/shoko/application/state/actions/quit_to_menu_action.rb +16 -0
- data/lib/shoko/application/state/actions/switch_reader_mode_action.rb +22 -0
- data/lib/shoko/application/state/actions/toggle_view_mode_action.rb +31 -0
- data/lib/shoko/application/state/actions/update_annotation_editor_overlay_action.rb +27 -0
- data/lib/shoko/application/state/actions/update_annotations_action.rb +20 -0
- data/lib/shoko/application/state/actions/update_annotations_overlay_action.rb +27 -0
- data/lib/shoko/application/state/actions/update_bookmarks_action.rb +20 -0
- data/lib/shoko/application/state/actions/update_chapter_action.rb +24 -0
- data/lib/shoko/application/state/actions/update_config_action.rb +22 -0
- data/lib/shoko/application/state/actions/update_field_helpers.rb +26 -0
- data/lib/shoko/application/state/actions/update_menu_action.rb +21 -0
- data/lib/shoko/application/state/actions/update_message_action.rb +35 -0
- data/lib/shoko/application/state/actions/update_page_action.rb +21 -0
- data/lib/shoko/application/state/actions/update_pagination_state_action.rb +21 -0
- data/lib/shoko/application/state/actions/update_popup_menu_action.rb +27 -0
- data/lib/shoko/application/state/actions/update_reader_meta_action.rb +21 -0
- data/lib/shoko/application/state/actions/update_reader_mode_action.rb +20 -0
- data/lib/shoko/application/state/actions/update_rendered_lines_action.rb +40 -0
- data/lib/shoko/application/state/actions/update_selection_action.rb +27 -0
- data/lib/shoko/application/state/actions/update_selections_action.rb +21 -0
- data/lib/shoko/application/state/actions/update_sidebar_action.rb +34 -0
- data/lib/shoko/application/state/actions/update_ui_loading_action.rb +23 -0
- data/lib/shoko/application/ui/reader_view_model_builder.rb +74 -0
- data/lib/shoko/application/ui/view_models/reader_view_model.rb +177 -0
- data/lib/shoko/application/unified_application.rb +48 -0
- data/lib/shoko/application/use_cases/catalog_service.rb +117 -0
- data/lib/shoko/application/use_cases/commands/annotation_editor_commands.rb +105 -0
- data/lib/shoko/application/use_cases/commands/application_commands.rb +208 -0
- data/lib/shoko/application/use_cases/commands/base_command.rb +166 -0
- data/lib/shoko/application/use_cases/commands/bookmark_commands.rb +114 -0
- data/lib/shoko/application/use_cases/commands/conditional_navigation_commands.rb +57 -0
- data/lib/shoko/application/use_cases/commands/menu_commands.rb +170 -0
- data/lib/shoko/application/use_cases/commands/navigation_commands.rb +183 -0
- data/lib/shoko/application/use_cases/commands/reader_commands.rb +46 -0
- data/lib/shoko/application/use_cases/commands/sidebar_commands.rb +55 -0
- data/lib/shoko/application/use_cases/settings_service.rb +123 -0
- data/lib/shoko/core/events/annotation_events.rb +94 -0
- data/lib/shoko/core/events/base_domain_event.rb +169 -0
- data/lib/shoko/core/events/bookmark_events.rb +41 -0
- data/lib/shoko/core/events/domain_event_bus.rb +163 -0
- data/lib/shoko/core/events/progress_events.rb +108 -0
- data/lib/shoko/core/models/bookmark.rb +36 -0
- data/lib/shoko/core/models/bookmark_data.rb +10 -0
- data/lib/shoko/core/models/chapter.rb +25 -0
- data/lib/shoko/core/models/content_block.rb +44 -0
- data/lib/shoko/core/models/reader_settings.rb +20 -0
- data/lib/shoko/core/models/selection_anchor.rb +73 -0
- data/lib/shoko/core/models/toc_entry.rb +14 -0
- data/lib/shoko/core/ports/annotation_repository.rb +0 -0
- data/lib/shoko/core/ports/book_repository.rb +0 -0
- data/lib/shoko/core/ports/book_source.rb +0 -0
- data/lib/shoko/core/ports/bookmark_repository.rb +0 -0
- data/lib/shoko/core/ports/cache.rb +0 -0
- data/lib/shoko/core/ports/input_handler.rb +0 -0
- data/lib/shoko/core/ports/renderer.rb +0 -0
- data/lib/shoko/core/ports/storage.rb +0 -0
- data/lib/shoko/core/services/annotation_service.rb +102 -0
- data/lib/shoko/core/services/base_service.rb +60 -0
- data/lib/shoko/core/services/bookmark_service.rb +267 -0
- data/lib/shoko/core/services/coordinate_service.rb +265 -0
- data/lib/shoko/core/services/layout_service.rb +95 -0
- data/lib/shoko/core/services/navigation/absolute_change_applier.rb +96 -0
- data/lib/shoko/core/services/navigation/absolute_layout.rb +101 -0
- data/lib/shoko/core/services/navigation/absolute_strategy.rb +179 -0
- data/lib/shoko/core/services/navigation/context_builder.rb +52 -0
- data/lib/shoko/core/services/navigation/context_helpers.rb +63 -0
- data/lib/shoko/core/services/navigation/dynamic_change_applier.rb +50 -0
- data/lib/shoko/core/services/navigation/dynamic_strategy.rb +51 -0
- data/lib/shoko/core/services/navigation/image_offset_snapper.rb +150 -0
- data/lib/shoko/core/services/navigation/nav_context.rb +27 -0
- data/lib/shoko/core/services/navigation/state_updater.rb +29 -0
- data/lib/shoko/core/services/navigation/strategy_factory.rb +20 -0
- data/lib/shoko/core/services/navigation_service.rb +150 -0
- data/lib/shoko/core/services/page_calculator_service.rb +242 -0
- data/lib/shoko/core/services/pagination/internal/absolute_page_map_builder.rb +28 -0
- data/lib/shoko/core/services/pagination/internal/chapter_cache.rb +60 -0
- data/lib/shoko/core/services/pagination/internal/dynamic_page_map_builder.rb +157 -0
- data/lib/shoko/core/services/pagination/internal/layout_metrics_calculator.rb +73 -0
- data/lib/shoko/core/services/pagination/internal/page_hydrator.rb +145 -0
- data/lib/shoko/core/services/pagination/internal/pagination_workflow.rb +152 -0
- data/lib/shoko/core/services/pagination/page_info_calculator.rb +247 -0
- data/lib/shoko/core/services/pagination/pagination_cache_preloader.rb +173 -0
- data/lib/shoko/core/services/pagination/pagination_coordinator.rb +202 -0
- data/lib/shoko/core/services/pagination/pagination_orchestrator.rb +291 -0
- data/lib/shoko/core/services/pagination.rb +10 -0
- data/lib/shoko/core/services/progress_helper.rb +22 -0
- data/lib/shoko/core/services/selection_service.rb +126 -0
- data/lib/shoko/core/validator.rb +76 -0
- data/lib/shoko/shared/errors.rb +97 -0
- data/lib/shoko/shared/version.rb +5 -0
- data/lib/shoko/test_support/terminal_double.rb +175 -0
- data/lib/shoko/test_support/test_mode.rb +78 -0
- data/lib/shoko.rb +279 -0
- data/lib/zip.rb +732 -0
- data/zip.rb +5 -0
- metadata +370 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
# Orchestrates reader startup steps: terminal prep, progress restore,
|
|
6
|
+
# pagination preload, and background data loads.
|
|
7
|
+
class ReaderStartupOrchestrator
|
|
8
|
+
def initialize(dependencies)
|
|
9
|
+
@dependencies = dependencies
|
|
10
|
+
@terminal_service = @dependencies.resolve(:terminal_service)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Execute startup sequence using the controller as context
|
|
14
|
+
# @param controller [Shoko::ReaderController]
|
|
15
|
+
def start(controller)
|
|
16
|
+
instrumentation = instrumentation_service
|
|
17
|
+
wrap_with_instrumentation(instrumentation, 'startup.reader') do
|
|
18
|
+
state = controller.state
|
|
19
|
+
page_calculator = controller.page_calculator
|
|
20
|
+
doc = controller.doc
|
|
21
|
+
|
|
22
|
+
# Query terminal size (FrameCoordinator will update state during rendering)
|
|
23
|
+
height, width = begin
|
|
24
|
+
@terminal_service.size
|
|
25
|
+
rescue StandardError
|
|
26
|
+
[nil, nil]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Load progress after terminal is ready
|
|
30
|
+
sc = safe_resolve_state_controller
|
|
31
|
+
sc&.load_progress
|
|
32
|
+
|
|
33
|
+
if doc.respond_to?(:cached?) && doc.cached?
|
|
34
|
+
preloader = resolve_pagination_preloader(state, page_calculator)
|
|
35
|
+
result = preloader&.preload(doc, width:, height:)
|
|
36
|
+
controller.clear_defer_page_map! if result && result.status == :hit
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Perform initial calculations if needed
|
|
40
|
+
controller.perform_initial_calculations_if_needed if controller.pending_initial_calculation?
|
|
41
|
+
|
|
42
|
+
# Schedule background page-map build for instant-open path
|
|
43
|
+
controller.schedule_background_page_map_build if controller.defer_page_map?
|
|
44
|
+
|
|
45
|
+
# Background load bookmarks and annotations
|
|
46
|
+
submit_background_job(sc) do
|
|
47
|
+
svc = sc || safe_resolve_state_controller
|
|
48
|
+
if svc
|
|
49
|
+
svc.load_bookmarks
|
|
50
|
+
svc.refresh_annotations
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def wrap_with_instrumentation(instrumentation, metric, &)
|
|
59
|
+
if instrumentation
|
|
60
|
+
instrumentation.time(metric, &)
|
|
61
|
+
else
|
|
62
|
+
yield
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def instrumentation_service
|
|
67
|
+
@instrumentation_service ||= begin
|
|
68
|
+
@dependencies.resolve(:instrumentation_service)
|
|
69
|
+
rescue StandardError
|
|
70
|
+
nil
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def safe_resolve_state_controller
|
|
75
|
+
@dependencies.resolve(:state_controller)
|
|
76
|
+
rescue StandardError
|
|
77
|
+
nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def submit_background_job(_initial_state_controller, &)
|
|
81
|
+
worker = resolve_background_worker
|
|
82
|
+
if worker
|
|
83
|
+
worker.submit(&)
|
|
84
|
+
else
|
|
85
|
+
Thread.new do
|
|
86
|
+
yield
|
|
87
|
+
rescue StandardError
|
|
88
|
+
# ignore background failures
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
rescue StandardError
|
|
92
|
+
# ignore background failures
|
|
93
|
+
nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def resolve_background_worker
|
|
97
|
+
return nil unless @dependencies.respond_to?(:resolve)
|
|
98
|
+
|
|
99
|
+
@dependencies.resolve(:background_worker)
|
|
100
|
+
rescue StandardError
|
|
101
|
+
nil
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def resolve_pagination_preloader(_state, _page_calculator)
|
|
105
|
+
return nil unless @dependencies.respond_to?(:resolve)
|
|
106
|
+
|
|
107
|
+
@dependencies.resolve(:pagination_cache_preloader)
|
|
108
|
+
rescue StandardError
|
|
109
|
+
nil
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
module Selectors
|
|
6
|
+
# Selectors for configuration state
|
|
7
|
+
module ConfigSelectors
|
|
8
|
+
def self.view_mode(state)
|
|
9
|
+
state.get(%i[config view_mode])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.line_spacing(state)
|
|
13
|
+
state.get(%i[config line_spacing])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.page_numbering_mode(state)
|
|
17
|
+
state.get(%i[config page_numbering_mode])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.theme(state)
|
|
21
|
+
state.get(%i[config theme])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.show_page_numbers(state)
|
|
25
|
+
state.get(%i[config show_page_numbers])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.show_page_numbers?(state)
|
|
29
|
+
show_page_numbers(state)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.highlight_quotes(state)
|
|
33
|
+
state.get(%i[config highlight_quotes])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.highlight_quotes?(state)
|
|
37
|
+
highlight_quotes(state)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.highlight_keywords(state)
|
|
41
|
+
state.get(%i[config highlight_keywords])
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.highlight_keywords?(state)
|
|
45
|
+
highlight_keywords(state)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.kitty_images(state)
|
|
49
|
+
state.get(%i[config kitty_images])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.kitty_images?(state)
|
|
53
|
+
!!kitty_images(state)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.config_hash(state)
|
|
57
|
+
state.get([:config])
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
module Selectors
|
|
6
|
+
# Selectors for menu state - provides read-only access to state
|
|
7
|
+
module MenuSelectors
|
|
8
|
+
def self.selected(state)
|
|
9
|
+
state.get(%i[menu selected])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.selected_item(state)
|
|
13
|
+
selected(state)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.mode(state)
|
|
17
|
+
state.get(%i[menu mode])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.browse_selected(state)
|
|
21
|
+
state.get(%i[menu browse_selected])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.search_query(state)
|
|
25
|
+
state.get(%i[menu search_query]) || ''
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.search_cursor(state)
|
|
29
|
+
state.get(%i[menu search_cursor])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.search_active(state)
|
|
33
|
+
state.get(%i[menu search_active])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.search_active?(state)
|
|
37
|
+
search_active(state)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.download_query(state)
|
|
41
|
+
state.get(%i[menu download_query]) || ''
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def self.download_cursor(state)
|
|
45
|
+
state.get(%i[menu download_cursor])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def self.download_selected(state)
|
|
49
|
+
state.get(%i[menu download_selected])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.download_status(state)
|
|
53
|
+
state.get(%i[menu download_status])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def self.download_progress(state)
|
|
57
|
+
state.get(%i[menu download_progress])
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../../adapters/output/render_registry.rb'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Selectors
|
|
8
|
+
# Selectors for reader state - provides read-only access to state
|
|
9
|
+
# Replaces direct state access and convenience methods
|
|
10
|
+
module ReaderSelectors
|
|
11
|
+
# Chapter and page selectors
|
|
12
|
+
def self.current_chapter(state)
|
|
13
|
+
state.get(%i[reader current_chapter])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.current_page_index(state)
|
|
17
|
+
state.get(%i[reader current_page_index])
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.current_page(state)
|
|
21
|
+
current_page_index(state) + 1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.left_page(state)
|
|
25
|
+
state.get(%i[reader left_page])
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.right_page(state)
|
|
29
|
+
state.get(%i[reader right_page])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.single_page(state)
|
|
33
|
+
state.get(%i[reader single_page])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Mode and UI state selectors
|
|
37
|
+
def self.mode(state)
|
|
38
|
+
state.get(%i[reader mode])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.selection(state)
|
|
42
|
+
state.get(%i[reader selection])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.message(state)
|
|
46
|
+
state.get(%i[reader message])
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.running(state)
|
|
50
|
+
state.get(%i[reader running])
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.running?(state)
|
|
54
|
+
running(state)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# List selectors
|
|
58
|
+
def self.bookmarks(state)
|
|
59
|
+
state.get(%i[reader bookmarks]) || []
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.annotations(state)
|
|
63
|
+
state.get(%i[reader annotations]) || []
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Pagination selectors
|
|
67
|
+
def self.page_map(state)
|
|
68
|
+
state.get(%i[reader page_map]) || []
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def self.total_pages(state)
|
|
72
|
+
state.get(%i[reader total_pages])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.pages_per_chapter(state)
|
|
76
|
+
state.get(%i[reader pages_per_chapter]) || []
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Dynamic pagination selectors
|
|
80
|
+
def self.dynamic_page_map(state)
|
|
81
|
+
state.get(%i[reader dynamic_page_map])
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.dynamic_total_pages(state)
|
|
85
|
+
state.get(%i[reader dynamic_total_pages])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.dynamic_chapter_starts(state)
|
|
89
|
+
state.get(%i[reader dynamic_chapter_starts]) || []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Terminal sizing selectors
|
|
93
|
+
def self.last_width(state)
|
|
94
|
+
state.get(%i[reader last_width])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.last_height(state)
|
|
98
|
+
state.get(%i[reader last_height])
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def self.last_dynamic_width(state)
|
|
102
|
+
state.get(%i[reader last_dynamic_width])
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.last_dynamic_height(state)
|
|
106
|
+
state.get(%i[reader last_dynamic_height])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.terminal_size_changed?(state, width, height)
|
|
110
|
+
width != last_width(state) || height != last_height(state)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# UI state selectors
|
|
114
|
+
def self.rendered_lines(state)
|
|
115
|
+
registry = begin
|
|
116
|
+
state.resolve(:render_registry)
|
|
117
|
+
rescue StandardError
|
|
118
|
+
nil
|
|
119
|
+
end
|
|
120
|
+
registry ||= begin
|
|
121
|
+
Shoko::Adapters::Output::RenderRegistry.current
|
|
122
|
+
rescue StandardError
|
|
123
|
+
nil
|
|
124
|
+
end
|
|
125
|
+
lines = registry&.lines
|
|
126
|
+
return lines if lines && !lines.empty?
|
|
127
|
+
|
|
128
|
+
state.get(%i[reader rendered_lines]) || {}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def self.popup_menu(state)
|
|
132
|
+
state.get(%i[reader popup_menu])
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def self.annotations_overlay(state)
|
|
136
|
+
state.get(%i[reader annotations_overlay])
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def self.annotation_editor_overlay(state)
|
|
140
|
+
state.get(%i[reader annotation_editor_overlay])
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Sidebar selectors
|
|
144
|
+
def self.sidebar_visible(state)
|
|
145
|
+
state.get(%i[reader sidebar_visible])
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def self.sidebar_visible?(state)
|
|
149
|
+
sidebar_visible(state)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.sidebar_active_tab(state)
|
|
153
|
+
state.get(%i[reader sidebar_active_tab])
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def self.sidebar_toc_selected(state)
|
|
157
|
+
state.get(%i[reader sidebar_toc_selected])
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def self.sidebar_toc_collapsed(state)
|
|
161
|
+
state.get(%i[reader sidebar_toc_collapsed])
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def self.sidebar_annotations_selected(state)
|
|
165
|
+
state.get(%i[reader sidebar_annotations_selected])
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def self.sidebar_bookmarks_selected(state)
|
|
169
|
+
state.get(%i[reader sidebar_bookmarks_selected])
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def self.sidebar_toc_filter(state)
|
|
173
|
+
state.get(%i[reader sidebar_toc_filter])
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def self.sidebar_toc_filter_active(state)
|
|
177
|
+
state.get(%i[reader sidebar_toc_filter_active])
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def self.sidebar_toc_filter_active?(state)
|
|
181
|
+
sidebar_toc_filter_active(state)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
module Actions
|
|
6
|
+
# Base action for immutable-like state updates via StateStore#dispatch
|
|
7
|
+
class BaseAction
|
|
8
|
+
def initialize(payload = {})
|
|
9
|
+
@payload = payload
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Apply the action to the given StateStore instance
|
|
13
|
+
# Implement in subclasses
|
|
14
|
+
def apply(_state)
|
|
15
|
+
raise NotImplementedError, 'Action subclasses must implement #apply(state)'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
protected
|
|
19
|
+
|
|
20
|
+
attr_reader :payload
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Stop the reader loop (used to return to menu)
|
|
9
|
+
class QuitToMenuAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
state.update({ %i[reader running] => false })
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Switch reader mode: :read, :help
|
|
9
|
+
class SwitchReaderModeAction < BaseAction
|
|
10
|
+
VALID = %i[read help].freeze
|
|
11
|
+
|
|
12
|
+
def apply(state)
|
|
13
|
+
mode = (payload[:mode] || :read).to_sym
|
|
14
|
+
return state.get(%i[reader mode]) unless VALID.include?(mode)
|
|
15
|
+
|
|
16
|
+
state.update({ %i[reader mode] => mode })
|
|
17
|
+
mode
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Toggle reader view between :split and :single
|
|
9
|
+
class ToggleViewModeAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
current = state.get(%i[config view_mode]) || :split
|
|
12
|
+
new_mode = current == :split ? :single : :split
|
|
13
|
+
|
|
14
|
+
# Update all state changes atomically
|
|
15
|
+
state.update({
|
|
16
|
+
%i[config view_mode] => new_mode,
|
|
17
|
+
%i[reader last_width] => 0,
|
|
18
|
+
%i[reader last_height] => 0,
|
|
19
|
+
%i[reader dynamic_page_map] => nil,
|
|
20
|
+
%i[reader dynamic_total_pages] => 0,
|
|
21
|
+
%i[reader last_dynamic_width] => 0,
|
|
22
|
+
%i[reader last_dynamic_height] => 0,
|
|
23
|
+
})
|
|
24
|
+
state.save_config if state.respond_to?(:save_config)
|
|
25
|
+
|
|
26
|
+
new_mode
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Stores the annotation editor overlay component in state.
|
|
9
|
+
class UpdateAnnotationEditorOverlayAction < BaseAction
|
|
10
|
+
def initialize(overlay)
|
|
11
|
+
super(overlay: overlay)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader annotation_editor_overlay] => payload[:overlay] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Clears any active annotation editor overlay from state.
|
|
20
|
+
class ClearAnnotationEditorOverlayAction < UpdateAnnotationEditorOverlayAction
|
|
21
|
+
def initialize
|
|
22
|
+
super(nil)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Action for updating annotations list
|
|
9
|
+
class UpdateAnnotationsAction < BaseAction
|
|
10
|
+
def initialize(annotations)
|
|
11
|
+
super(annotations: annotations)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader annotations] => payload[:annotations] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Updates the reader annotations overlay component stored in state.
|
|
9
|
+
class UpdateAnnotationsOverlayAction < BaseAction
|
|
10
|
+
def initialize(overlay)
|
|
11
|
+
super(overlay: overlay)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader annotations_overlay] => payload[:overlay] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Clears any active annotations overlay.
|
|
20
|
+
class ClearAnnotationsOverlayAction < UpdateAnnotationsOverlayAction
|
|
21
|
+
def initialize
|
|
22
|
+
super(nil)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Action for updating the bookmarks list
|
|
9
|
+
class UpdateBookmarksAction < BaseAction
|
|
10
|
+
def initialize(bookmarks)
|
|
11
|
+
super(bookmarks: bookmarks)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader bookmarks] => payload[:bookmarks] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Action for updating the current chapter
|
|
9
|
+
class UpdateChapterAction < BaseAction
|
|
10
|
+
def initialize(chapter_index)
|
|
11
|
+
super(chapter_index: chapter_index)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
idx = payload[:chapter_index]
|
|
16
|
+
updates = {
|
|
17
|
+
%i[reader current_chapter] => idx,
|
|
18
|
+
}
|
|
19
|
+
state.update(updates)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Action for updating configuration values
|
|
9
|
+
class UpdateConfigAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
# Build update hash for atomic state update
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |config_field, value|
|
|
14
|
+
updates[[:config, config_field]] = value
|
|
15
|
+
end
|
|
16
|
+
state.update(updates)
|
|
17
|
+
state.save_config if state.respond_to?(:save_config)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
module Shoko
|
|
6
|
+
module Application
|
|
7
|
+
module Actions
|
|
8
|
+
# Shared helpers for applying whitelisted state update fields.
|
|
9
|
+
module UpdateFieldHelpers
|
|
10
|
+
module_function
|
|
11
|
+
|
|
12
|
+
# Apply only allowed fields under a namespaced state path
|
|
13
|
+
# e.g., namespace = :reader results in updates to [:reader, field]
|
|
14
|
+
def apply_allowed(state, payload, allowed, namespace: :reader)
|
|
15
|
+
updates = {}
|
|
16
|
+
payload.each do |field, value|
|
|
17
|
+
next unless allowed.include?(field)
|
|
18
|
+
|
|
19
|
+
updates[[namespace, field]] = value
|
|
20
|
+
end
|
|
21
|
+
state.update(updates) unless updates.empty?
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|