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,21 @@
|
|
|
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 menu-related state under [:menu, *]
|
|
9
|
+
class UpdateMenuAction < BaseAction
|
|
10
|
+
# Payload is a hash of menu_field => value
|
|
11
|
+
def apply(state)
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |field, value|
|
|
14
|
+
updates[[:menu, field]] = value
|
|
15
|
+
end
|
|
16
|
+
state.update(updates)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
require_relative '../../../adapters/output/terminal/terminal_sanitizer.rb'
|
|
5
|
+
|
|
6
|
+
module Shoko
|
|
7
|
+
module Application
|
|
8
|
+
module Actions
|
|
9
|
+
# Action for updating the status message
|
|
10
|
+
class UpdateMessageAction < BaseAction
|
|
11
|
+
def initialize(message)
|
|
12
|
+
super(message: message)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply(state)
|
|
16
|
+
msg = payload[:message]
|
|
17
|
+
safe = if msg.nil?
|
|
18
|
+
nil
|
|
19
|
+
else
|
|
20
|
+
Shoko::Adapters::Output::Terminal::TerminalSanitizer.sanitize(msg.to_s, preserve_newlines: false,
|
|
21
|
+
preserve_tabs: false)
|
|
22
|
+
end
|
|
23
|
+
state.update({ %i[reader message] => safe })
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Convenience action for clearing message
|
|
28
|
+
class ClearMessageAction < UpdateMessageAction
|
|
29
|
+
def initialize
|
|
30
|
+
super(nil)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
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 page positions (current_page_index, left_page, right_page, single_page)
|
|
9
|
+
class UpdatePageAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
# Build update hash for atomic state update
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |page_field, value|
|
|
14
|
+
updates[[:reader, page_field]] = value
|
|
15
|
+
end
|
|
16
|
+
state.update(updates)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
require_relative 'update_field_helpers'
|
|
6
|
+
|
|
7
|
+
module Shoko
|
|
8
|
+
module Application
|
|
9
|
+
module Actions
|
|
10
|
+
# Action to update pagination-related reader state in a single, consistent way.
|
|
11
|
+
# Allowed fields: :page_map, :total_pages, :last_width, :last_height, :total_chapters
|
|
12
|
+
class UpdatePaginationStateAction < BaseAction
|
|
13
|
+
ALLOWED = %i[page_map total_pages last_width last_height total_chapters].freeze
|
|
14
|
+
|
|
15
|
+
def apply(state)
|
|
16
|
+
UpdateFieldHelpers.apply_allowed(state, payload, ALLOWED, namespace: :reader)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
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
|
+
# Action for updating popup menu state
|
|
9
|
+
class UpdatePopupMenuAction < BaseAction
|
|
10
|
+
def initialize(popup_menu)
|
|
11
|
+
super(popup_menu: popup_menu)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader popup_menu] => payload[:popup_menu] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Convenience action for clearing popup menu
|
|
20
|
+
class ClearPopupMenuAction < UpdatePopupMenuAction
|
|
21
|
+
def initialize
|
|
22
|
+
super(nil)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
|
|
5
|
+
require_relative 'update_field_helpers'
|
|
6
|
+
|
|
7
|
+
module Shoko
|
|
8
|
+
module Application
|
|
9
|
+
module Actions
|
|
10
|
+
# Action to update reader meta fields that are not pagination specific
|
|
11
|
+
# Allowed fields: :book_path, :running
|
|
12
|
+
class UpdateReaderMetaAction < BaseAction
|
|
13
|
+
ALLOWED = %i[book_path running].freeze
|
|
14
|
+
|
|
15
|
+
def apply(state)
|
|
16
|
+
UpdateFieldHelpers.apply_allowed(state, payload, ALLOWED, namespace: :reader)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
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 reader mode (read/help/annotation editor).
|
|
9
|
+
class UpdateReaderModeAction < BaseAction
|
|
10
|
+
def initialize(new_mode)
|
|
11
|
+
super(mode: new_mode)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader mode] => payload[:mode] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'base_action'
|
|
4
|
+
require_relative '../../../adapters/output/render_registry.rb'
|
|
5
|
+
|
|
6
|
+
module Shoko
|
|
7
|
+
module Application
|
|
8
|
+
module Actions
|
|
9
|
+
# Action for updating rendered lines cache
|
|
10
|
+
class UpdateRenderedLinesAction < BaseAction
|
|
11
|
+
def initialize(rendered_lines)
|
|
12
|
+
super(rendered_lines: rendered_lines)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def apply(state)
|
|
16
|
+
registry = begin
|
|
17
|
+
state.resolve(:render_registry) if state.respond_to?(:resolve)
|
|
18
|
+
rescue StandardError
|
|
19
|
+
nil
|
|
20
|
+
end
|
|
21
|
+
registry ||= begin
|
|
22
|
+
Shoko::Adapters::Output::RenderRegistry.current
|
|
23
|
+
rescue StandardError
|
|
24
|
+
nil
|
|
25
|
+
end
|
|
26
|
+
registry&.write(payload[:rendered_lines])
|
|
27
|
+
# Keep state entry lightweight for observers; avoid storing the large hash
|
|
28
|
+
state.update({ %i[reader rendered_lines] => :render_registry })
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Convenience action for clearing rendered lines
|
|
33
|
+
class ClearRenderedLinesAction < UpdateRenderedLinesAction
|
|
34
|
+
def initialize
|
|
35
|
+
super({})
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
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
|
+
# Action for updating text selection state
|
|
9
|
+
class UpdateSelectionAction < BaseAction
|
|
10
|
+
def initialize(selection)
|
|
11
|
+
super(selection: selection)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def apply(state)
|
|
15
|
+
state.update({ %i[reader selection] => payload[:selection] })
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Convenience action for clearing selection
|
|
20
|
+
class ClearSelectionAction < UpdateSelectionAction
|
|
21
|
+
def initialize
|
|
22
|
+
super(nil)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
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 various selection states
|
|
9
|
+
class UpdateSelectionsAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
# Build update hash for atomic state update
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |field, value|
|
|
14
|
+
updates[[:reader, field]] = value
|
|
15
|
+
end
|
|
16
|
+
state.update(updates)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
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 sidebar state
|
|
9
|
+
class UpdateSidebarAction < BaseAction
|
|
10
|
+
def apply(state)
|
|
11
|
+
# Build update hash for atomic state update
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |field, value|
|
|
14
|
+
case field
|
|
15
|
+
when :visible
|
|
16
|
+
updates[%i[reader sidebar_visible]] = value
|
|
17
|
+
when :active_tab
|
|
18
|
+
updates[%i[reader sidebar_active_tab]] = value
|
|
19
|
+
when :toc_selected
|
|
20
|
+
updates[%i[reader sidebar_toc_selected]] = value
|
|
21
|
+
when :toc_collapsed
|
|
22
|
+
updates[%i[reader sidebar_toc_collapsed]] = value
|
|
23
|
+
when :annotations_selected
|
|
24
|
+
updates[%i[reader sidebar_annotations_selected]] = value
|
|
25
|
+
when :bookmarks_selected
|
|
26
|
+
updates[%i[reader sidebar_bookmarks_selected]] = value
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
state.update(updates)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
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 UI loading indicators
|
|
9
|
+
# Accepts any of: :loading_active, :loading_message, :loading_progress
|
|
10
|
+
class UpdateUILoadingAction < BaseAction
|
|
11
|
+
def apply(state)
|
|
12
|
+
updates = {}
|
|
13
|
+
payload.each do |field, value|
|
|
14
|
+
next unless %i[loading_active loading_message loading_progress].include?(field)
|
|
15
|
+
|
|
16
|
+
updates[[:ui, field]] = value
|
|
17
|
+
end
|
|
18
|
+
state.update(updates) unless updates.empty?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
module UI
|
|
6
|
+
# Builds ReaderViewModel from state and document, keeping controller lean.
|
|
7
|
+
class ReaderViewModelBuilder
|
|
8
|
+
def initialize(state, doc)
|
|
9
|
+
@state = state
|
|
10
|
+
@doc = doc
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def build(page_info)
|
|
14
|
+
ViewModels::ReaderViewModel.new(**attributes(page_info))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def attributes(page_info)
|
|
20
|
+
base_attributes.merge(page_info: page_info)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def base_attributes
|
|
24
|
+
{
|
|
25
|
+
current_chapter: current_chapter_index,
|
|
26
|
+
total_chapters: total_chapter_count,
|
|
27
|
+
current_page: state_value(%i[reader current_page]),
|
|
28
|
+
total_pages: state_value(%i[reader total_pages]),
|
|
29
|
+
chapter_title: chapter_title(current_chapter_index),
|
|
30
|
+
document_title: @doc&.title || '',
|
|
31
|
+
view_mode: state_value(%i[config view_mode], :split),
|
|
32
|
+
sidebar_visible: state_value(%i[reader sidebar_visible]),
|
|
33
|
+
mode: state_value(%i[reader mode]),
|
|
34
|
+
message: state_value(%i[reader message]),
|
|
35
|
+
bookmarks: state_value(%i[reader bookmarks], []),
|
|
36
|
+
toc_entries: doc_toc_entries,
|
|
37
|
+
show_page_numbers: state_value(%i[config show_page_numbers], true),
|
|
38
|
+
page_numbering_mode: state_value(%i[config page_numbering_mode], :dynamic),
|
|
39
|
+
line_spacing: state_value(%i[config line_spacing], Shoko::Core::Models::ReaderSettings::DEFAULT_LINE_SPACING),
|
|
40
|
+
language: @doc&.language || 'en',
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def current_chapter_index
|
|
45
|
+
state_value(%i[reader current_chapter])
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def total_chapter_count
|
|
49
|
+
Array(@doc&.chapters).length
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def chapter_title(index)
|
|
53
|
+
chapter = @doc&.get_chapter(index)
|
|
54
|
+
chapter&.title || ''
|
|
55
|
+
rescue StandardError
|
|
56
|
+
''
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def doc_toc_entries
|
|
60
|
+
return [] unless @doc.respond_to?(:toc_entries)
|
|
61
|
+
|
|
62
|
+
Array(@doc.toc_entries)
|
|
63
|
+
rescue StandardError
|
|
64
|
+
[]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def state_value(path, default = nil)
|
|
68
|
+
value = @state.get(path)
|
|
69
|
+
value.nil? ? default : value
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application::UI
|
|
5
|
+
module ViewModels
|
|
6
|
+
# Pure data structure for reader view rendering.
|
|
7
|
+
# Eliminates component coupling to controllers and services.
|
|
8
|
+
class ReaderViewModel
|
|
9
|
+
attr_reader :current_chapter, :total_chapters, :current_page, :total_pages,
|
|
10
|
+
:chapter_title, :document_title, :view_mode, :sidebar_visible, :mode, :message,
|
|
11
|
+
:bookmarks, :toc_entries, :content_lines, :page_info, :show_page_numbers,
|
|
12
|
+
:page_numbering_mode, :line_spacing, :language
|
|
13
|
+
|
|
14
|
+
def initialize(
|
|
15
|
+
current_chapter: 0,
|
|
16
|
+
total_chapters: 0,
|
|
17
|
+
current_page: 0,
|
|
18
|
+
total_pages: 0,
|
|
19
|
+
chapter_title: '',
|
|
20
|
+
document_title: '',
|
|
21
|
+
view_mode: :split,
|
|
22
|
+
sidebar_visible: false,
|
|
23
|
+
mode: :read,
|
|
24
|
+
message: nil,
|
|
25
|
+
bookmarks: [],
|
|
26
|
+
toc_entries: [],
|
|
27
|
+
content_lines: [],
|
|
28
|
+
page_info: {},
|
|
29
|
+
show_page_numbers: true,
|
|
30
|
+
page_numbering_mode: :dynamic,
|
|
31
|
+
line_spacing: :compact,
|
|
32
|
+
language: 'en'
|
|
33
|
+
)
|
|
34
|
+
@current_chapter = current_chapter
|
|
35
|
+
@total_chapters = total_chapters
|
|
36
|
+
@current_page = current_page
|
|
37
|
+
@total_pages = total_pages
|
|
38
|
+
@chapter_title = chapter_title
|
|
39
|
+
@document_title = document_title
|
|
40
|
+
@view_mode = view_mode
|
|
41
|
+
@sidebar_visible = sidebar_visible
|
|
42
|
+
@mode = mode
|
|
43
|
+
@message = message
|
|
44
|
+
@bookmarks = bookmarks
|
|
45
|
+
@toc_entries = toc_entries
|
|
46
|
+
@content_lines = content_lines
|
|
47
|
+
@page_info = page_info
|
|
48
|
+
@show_page_numbers = show_page_numbers
|
|
49
|
+
@page_numbering_mode = page_numbering_mode
|
|
50
|
+
@line_spacing = line_spacing
|
|
51
|
+
@language = language
|
|
52
|
+
freeze
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Derived properties
|
|
56
|
+
def progress_percentage
|
|
57
|
+
return 0 if total_pages.zero?
|
|
58
|
+
|
|
59
|
+
((current_page.to_f / total_pages) * 100).round(1)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def chapter_progress
|
|
63
|
+
return '0/0' if total_chapters.zero?
|
|
64
|
+
|
|
65
|
+
"#{current_chapter + 1}/#{total_chapters}"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def page_progress
|
|
69
|
+
return '0/0' if total_pages.zero?
|
|
70
|
+
|
|
71
|
+
"#{current_page + 1}/#{total_pages}"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def split_mode?
|
|
75
|
+
view_mode == :split
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def single_mode?
|
|
79
|
+
view_mode == :single
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def message?
|
|
83
|
+
!message.nil? && !message.empty?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def bookmarks?
|
|
87
|
+
!bookmarks.empty?
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def toc?
|
|
91
|
+
!toc_entries.empty?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Create new instance with updates
|
|
95
|
+
def with(**changes)
|
|
96
|
+
current_attributes = {
|
|
97
|
+
current_chapter: current_chapter,
|
|
98
|
+
total_chapters: total_chapters,
|
|
99
|
+
current_page: current_page,
|
|
100
|
+
total_pages: total_pages,
|
|
101
|
+
chapter_title: chapter_title,
|
|
102
|
+
document_title: document_title,
|
|
103
|
+
view_mode: view_mode,
|
|
104
|
+
sidebar_visible: sidebar_visible,
|
|
105
|
+
mode: mode,
|
|
106
|
+
message: message,
|
|
107
|
+
bookmarks: bookmarks,
|
|
108
|
+
toc_entries: toc_entries,
|
|
109
|
+
content_lines: content_lines,
|
|
110
|
+
page_info: page_info,
|
|
111
|
+
show_page_numbers: show_page_numbers,
|
|
112
|
+
page_numbering_mode: page_numbering_mode,
|
|
113
|
+
line_spacing: line_spacing,
|
|
114
|
+
language: language,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
self.class.new(**current_attributes, **changes)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# View model for menu screens (main/browse/settings/annotations).
|
|
122
|
+
class MenuViewModel
|
|
123
|
+
attr_reader :mode, :selected_index, :items, :search_query, :search_active,
|
|
124
|
+
:message, :title
|
|
125
|
+
|
|
126
|
+
def initialize(
|
|
127
|
+
mode: :main,
|
|
128
|
+
selected_index: 0,
|
|
129
|
+
items: [],
|
|
130
|
+
search_query: '',
|
|
131
|
+
search_active: false,
|
|
132
|
+
message: nil,
|
|
133
|
+
title: 'Shoko'
|
|
134
|
+
)
|
|
135
|
+
@mode = mode
|
|
136
|
+
@selected_index = selected_index
|
|
137
|
+
@items = items
|
|
138
|
+
@search_query = search_query
|
|
139
|
+
@search_active = search_active
|
|
140
|
+
@message = message
|
|
141
|
+
@title = title
|
|
142
|
+
freeze
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def selected_item
|
|
146
|
+
items[selected_index]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def items?
|
|
150
|
+
!items.empty?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def message?
|
|
154
|
+
!message.nil? && !message.empty?
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def searching?
|
|
158
|
+
search_active
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def with(**changes)
|
|
162
|
+
current_attributes = {
|
|
163
|
+
mode: mode,
|
|
164
|
+
selected_index: selected_index,
|
|
165
|
+
items: items,
|
|
166
|
+
search_query: search_query,
|
|
167
|
+
search_active: search_active,
|
|
168
|
+
message: message,
|
|
169
|
+
title: title,
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
self.class.new(**current_attributes, **changes)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shoko
|
|
4
|
+
module Application
|
|
5
|
+
# Unified application entry point that handles both file and menu scenarios
|
|
6
|
+
class UnifiedApplication
|
|
7
|
+
def initialize(epub_path = nil)
|
|
8
|
+
@epub_path = epub_path
|
|
9
|
+
@dependencies = Shoko::Application::ContainerFactory.create_default_container
|
|
10
|
+
@instrumentation = begin
|
|
11
|
+
@dependencies.resolve(:instrumentation_service)
|
|
12
|
+
rescue StandardError
|
|
13
|
+
nil
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def run
|
|
18
|
+
if @epub_path
|
|
19
|
+
reader_mode
|
|
20
|
+
else
|
|
21
|
+
menu_mode
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def reader_mode
|
|
28
|
+
# Ensure alternate screen is entered before any heavy work for instant-open UX
|
|
29
|
+
term = @dependencies.resolve(:terminal_service)
|
|
30
|
+
term.setup
|
|
31
|
+
@instrumentation&.start_trace(@epub_path)
|
|
32
|
+
begin
|
|
33
|
+
# Pass dependencies to MouseableReader
|
|
34
|
+
Controllers::MouseableReader.new(@epub_path, nil, @dependencies).run
|
|
35
|
+
ensure
|
|
36
|
+
# Balance setup to avoid lingering session depth
|
|
37
|
+
term.cleanup
|
|
38
|
+
@instrumentation&.cancel_trace
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def menu_mode
|
|
43
|
+
# Pass dependencies to MenuController
|
|
44
|
+
Controllers::MenuController.new(@dependencies).run
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|