diff --git a/lib/migration/dao/repository/seforim_repository.dart b/lib/migration/dao/repository/seforim_repository.dart index 9e969fbe7..2a02d469f 100644 --- a/lib/migration/dao/repository/seforim_repository.dart +++ b/lib/migration/dao/repository/seforim_repository.dart @@ -1831,6 +1831,14 @@ class SeforimRepository { /// @param sql The SQL query to execute Future executeRawQuery(String sql) async { final db = await _database.database; + final normalizedSql = sql.trim().toUpperCase(); + final isPragma = normalizedSql.startsWith('PRAGMA '); + + if (isPragma && (Platform.isAndroid || Platform.isIOS)) { + await db.rawQuery(sql); + return; + } + await db.execute(sql); } @@ -2344,9 +2352,9 @@ class SeforimRepository { Future _executeRawQuery(String sql) async { final db = await _database.database; final normalizedSql = sql.trim().toUpperCase(); - final isJournalModePragma = normalizedSql.startsWith('PRAGMA JOURNAL_MODE'); + final isPragma = normalizedSql.startsWith('PRAGMA '); - if (isJournalModePragma && (Platform.isAndroid || Platform.isIOS)) { + if (isPragma && (Platform.isAndroid || Platform.isIOS)) { await db.rawQuery(sql); return; } diff --git a/lib/navigation/custom_title_bar.dart b/lib/navigation/custom_title_bar.dart index 1d2c09792..570e42444 100644 --- a/lib/navigation/custom_title_bar.dart +++ b/lib/navigation/custom_title_bar.dart @@ -42,16 +42,16 @@ class CustomTitleBar extends StatefulWidget { } const double _kAppBarControlsWidth = 125.0; -const double _kAppBarControlsWidthRightAligned = 105.0; -const int _kActionButtonsCount = 1; // settings בלבד +const double _kAppBarControlsWidthRightAligned = 125.0; const double _kActionButtonWidth = 56.0; const double _kWindowCaptionButtonsWidth = 138.0; const double _kWindowCaptionButtonWidth = 46.0; /// סגנון משותף לכפתורי האייקון בשורת הכותרת final ButtonStyle _kIconButtonStyle = IconButton.styleFrom( - minimumSize: const Size(32, 32), + minimumSize: const Size(28, 28), padding: EdgeInsets.zero, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), @@ -217,7 +217,7 @@ class _CustomTitleBarState extends State ? _kAppBarControlsWidthRightAligned : _kAppBarControlsWidth, child: Row( - mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.start, children: [ IconButton( icon: const Icon(FluentIcons.history_24_regular, size: 18), @@ -225,12 +225,14 @@ class _CustomTitleBarState extends State onPressed: () => _showHistoryDialog(context), style: _kIconButtonStyle, ), + const SizedBox(width: 4), IconButton( icon: const Icon(FluentIcons.bookmark_24_regular, size: 18), tooltip: 'הצג סימניות (${bookmarksShortcut.toUpperCase()})', onPressed: () => _showBookmarksDialog(context), style: _kIconButtonStyle, ), + const SizedBox(width: 4), IconButton( icon: const Icon(FluentIcons.add_square_24_regular, size: 18), tooltip: 'החלף שולחן עבודה (${workspaceShortcut.toUpperCase()})', @@ -248,13 +250,13 @@ class _CustomTitleBarState extends State navState.currentScreen == Screen.search) { return _buildReadingTabs(context, settingsState); } else if (navState.currentScreen == Screen.library) { - return _buildLibraryTitle(context); + return _buildLibraryTitle(context, settingsState); } else { - return _buildStandardTitle(context, navState); + return _buildStandardTitle(context, navState, settingsState); } } - Widget _buildLibraryTitle(BuildContext context) { + Widget _buildLibraryTitle(BuildContext context, SettingsState settingsState) { return BlocBuilder( buildWhen: (previous, current) => previous.currentCategory != current.currentCategory, @@ -278,14 +280,22 @@ class _CustomTitleBarState extends State ), Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: IconButton( - icon: const Icon(FluentIcons.settings_24_regular, size: 18), - tooltip: 'הגדרות ספרייה', - onPressed: () => showLibrarySettingsDialog(context), - style: _kIconButtonStyle.copyWith( - foregroundColor: WidgetStatePropertyAll( - Theme.of(context).colorScheme.onSurfaceVariant), - ), + child: Row( + mainAxisSize: MainAxisSize.min, + textDirection: TextDirection.ltr, + children: [ + if (!kIsWeb && Platform.isAndroid) + _buildAndroidFullscreenButton(context, settingsState), + IconButton( + icon: const Icon(FluentIcons.settings_24_regular, size: 18), + tooltip: 'הגדרות ספרייה', + onPressed: () => showLibrarySettingsDialog(context), + style: _kIconButtonStyle.copyWith( + foregroundColor: WidgetStatePropertyAll( + Theme.of(context).colorScheme.onSurfaceVariant), + ), + ), + ], ), ), ], @@ -294,7 +304,8 @@ class _CustomTitleBarState extends State ); } - Widget _buildStandardTitle(BuildContext context, NavigationState navState) { + Widget _buildStandardTitle(BuildContext context, NavigationState navState, + SettingsState settingsState) { String title = 'אוצריא'; switch (navState.currentScreen) { case Screen.find: @@ -310,17 +321,54 @@ class _CustomTitleBarState extends State break; } - return DragToMoveArea( - child: Center( - child: Text( - title, - style: Theme.of(context).textTheme.titleMedium, + return Row( + children: [ + Expanded( + child: DragToMoveArea( + child: Center( + child: Text( + title, + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + ), + if (!kIsWeb && Platform.isAndroid) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: _buildAndroidFullscreenButton(context, settingsState), + ), + ], + ); + } + + Widget _buildAndroidFullscreenButton( + BuildContext context, SettingsState settingsState) { + return IconButton( + icon: Icon( + settingsState.isFullscreen + ? FluentIcons.full_screen_minimize_24_regular + : FluentIcons.full_screen_maximize_24_regular, + size: 18, + ), + tooltip: settingsState.isFullscreen ? 'צא ממסך מלא' : 'מסך מלא', + onPressed: () async { + final newFullscreenState = !settingsState.isFullscreen; + await FullscreenHelper.toggleFullscreen( + context, + newFullscreenState, + ); + }, + style: _kIconButtonStyle.copyWith( + foregroundColor: WidgetStatePropertyAll( + Theme.of(context).colorScheme.onSurfaceVariant, ), ), ); } Widget _buildReadingTabs(BuildContext context, SettingsState settingsState) { + final showAndroidFullscreenButton = !kIsWeb && Platform.isAndroid; return BlocBuilder( builder: (context, state) { if (!state.hasOpenTabs) { @@ -341,13 +389,20 @@ class _CustomTitleBarState extends State double rightSpacerWidth = 0; if (!settingsState.alignTabsToRight) { + final showAndroidFullscreenButton = !kIsWeb && Platform.isAndroid; bool showWindowControls = !kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS); + final int readingActionButtonsCount = + 1 + (showAndroidFullscreenButton ? 1 : 0); double windowControlsWidth = showWindowControls ? _kWindowCaptionButtonsWidth + _kWindowCaptionButtonWidth : 0.0; - double actionButtonsWidth = _kAppBarControlsWidth; - double extraButtonsWidth = _kActionButtonsCount * _kActionButtonWidth; + double actionButtonsWidth = (settingsState.alignTabsToRight + ? _kAppBarControlsWidthRightAligned + : _kAppBarControlsWidth) + + (showAndroidFullscreenButton ? _kActionButtonWidth : 0); + double extraButtonsWidth = + readingActionButtonsCount * _kActionButtonWidth; double totalLeft = actionButtonsWidth; double totalRight = extraButtonsWidth + windowControlsWidth; @@ -357,6 +412,12 @@ class _CustomTitleBarState extends State } else { rightSpacerWidth = totalLeft - totalRight; } + + // באנדרואיד אנחנו רוצים את כפתורי ההגדרות/מסך מלא צמודים לשמאל + // בלי spacer נוסף בצד שמאל. + if (showAndroidFullscreenButton) { + rightSpacerWidth = 0; + } } return Row( @@ -417,17 +478,48 @@ class _CustomTitleBarState extends State ), ), - // כפתורים נוספים (הגדרות) + // כפתורים נוספים (הגדרות/מסך מלא באנדרואיד) Padding( padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: IconButton( - icon: const Icon(FluentIcons.settings_24_regular, size: 18), - tooltip: 'הגדרות תצוגת הספרים', - onPressed: () => showReadingSettingsDialog(context), - style: _kIconButtonStyle.copyWith( - foregroundColor: WidgetStatePropertyAll( - Theme.of(context).colorScheme.onSurfaceVariant), - ), + child: Row( + mainAxisSize: MainAxisSize.min, + textDirection: TextDirection.ltr, + children: [ + if (showAndroidFullscreenButton) + IconButton( + icon: Icon( + settingsState.isFullscreen + ? FluentIcons.full_screen_minimize_24_regular + : FluentIcons.full_screen_maximize_24_regular, + size: 18, + ), + tooltip: settingsState.isFullscreen + ? 'צא ממסך מלא' + : 'מסך מלא', + onPressed: () async { + final newFullscreenState = !settingsState.isFullscreen; + await FullscreenHelper.toggleFullscreen( + context, + newFullscreenState, + ); + }, + style: _kIconButtonStyle.copyWith( + foregroundColor: WidgetStatePropertyAll( + Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + IconButton( + icon: const Icon(FluentIcons.settings_24_regular, size: 18), + tooltip: 'הגדרות תצוגת הספרים', + onPressed: () => showReadingSettingsDialog(context), + style: _kIconButtonStyle.copyWith( + foregroundColor: WidgetStatePropertyAll( + Theme.of(context).colorScheme.onSurfaceVariant, + ), + ), + ), + ], ), ), if (rightSpacerWidth > 0) SizedBox(width: rightSpacerWidth), diff --git a/lib/settings/engine/settings_repository.dart b/lib/settings/engine/settings_repository.dart index 13e73b848..e380bce89 100644 --- a/lib/settings/engine/settings_repository.dart +++ b/lib/settings/engine/settings_repository.dart @@ -209,7 +209,7 @@ class SettingsRepository { ), 'libraryShowPreview': _settings.getValue( keyLibraryShowPreview, - defaultValue: true, + defaultValue: false, ), 'shortcuts': await getShortcuts(), 'enablePerBookSettings': _settings.getValue( @@ -652,7 +652,7 @@ class SettingsRepository { await _settings.setValue(keyCopyHeaderFormat, 'same_line_after_brackets'); await _settings.setValue(keyIsFullscreen, false); await _settings.setValue(keyLibraryViewMode, 'grid'); - await _settings.setValue(keyLibraryShowPreview, true); + await _settings.setValue(keyLibraryShowPreview, false); await _settings.setValue(keyEnablePerBookSettings, true); await _settings.setValue(keyAlignTabsToRight, false); await _settings.setValue(keyPersonalNotesCollapsedByDefault, true); diff --git a/lib/settings/engine/settings_state.dart b/lib/settings/engine/settings_state.dart index 85ed45eff..fcb1615fd 100644 --- a/lib/settings/engine/settings_state.dart +++ b/lib/settings/engine/settings_state.dart @@ -110,7 +110,7 @@ class SettingsState extends Equatable { copyHeaderFormat: 'same_line_after_brackets', isFullscreen: false, libraryViewMode: 'grid', - libraryShowPreview: true, + libraryShowPreview: false, shortcuts: {}, enablePerBookSettings: true, isOfflineMode: false, diff --git a/lib/text_book/bloc/text_book_bloc.dart b/lib/text_book/bloc/text_book_bloc.dart index 80d522d6e..5f06ebc4e 100644 --- a/lib/text_book/bloc/text_book_bloc.dart +++ b/lib/text_book/bloc/text_book_bloc.dart @@ -49,6 +49,7 @@ class TextBookBloc extends Bloc { on(_onToggleNikud); on(_onUpdateVisibleIndecies); on(_onUpdateSelectedIndex); + on(_onSelectAndScrollToIndex); on(_onHighlightLine); on(_onClearHighlightedLine); on(_onTogglePinLeftPane); @@ -249,6 +250,9 @@ class TextBookBloc extends Bloc { selectedTextEnd: state is TextBookLoaded ? (state as TextBookLoaded).selectedTextEnd : null, + pageShapeAnchorIndex: + visibleIndices.isNotEmpty ? visibleIndices.first : null, + pageShapePreferSelectedNextSync: false, )); // ── שלב 5: טעינות ברקע - לא חוסמות את ה-UI ── @@ -447,11 +451,21 @@ class TextBookBloc extends Bloc { selectedIndex: index, ); + final shouldUseSelected = + currentState.pageShapePreferSelectedNextSync && index != null; + final pageShapeAnchorIndex = shouldUseSelected + ? index + : (event.visibleIndecies.isNotEmpty + ? event.visibleIndecies.first + : index); + emit(currentState.copyWith( visibleIndices: event.visibleIndecies, currentTitle: newTitle, selectedIndex: index, visibleLinks: visibleLinks, + pageShapeAnchorIndex: pageShapeAnchorIndex, + pageShapePreferSelectedNextSync: false, )); } } @@ -469,20 +483,62 @@ class TextBookBloc extends Bloc { UpdateSelectedIndex event, Emitter emit, ) { - if (state is TextBookLoaded) { - final currentState = state as TextBookLoaded; - final visibleLinks = _getVisibleLinks( - links: currentState.links, - visibleIndices: currentState.visibleIndices, - selectedIndex: event.index, + if (state is! TextBookLoaded) return; + final currentState = state as TextBookLoaded; + _emitSelectedIndex( + currentState, + emit, + event.index, + preferForPageShape: true, + ); + } + + void _onSelectAndScrollToIndex( + SelectAndScrollToIndex event, + Emitter emit, + ) { + if (state is! TextBookLoaded) return; + final currentState = state as TextBookLoaded; + if (currentState.content.isEmpty) return; + + final boundedIndex = event.index.clamp(0, currentState.content.length - 1); + + _emitSelectedIndex( + currentState, + emit, + boundedIndex, + preferForPageShape: true, + ); + + if (scrollController.isAttached) { + scrollController.scrollTo( + index: boundedIndex, + duration: Duration(milliseconds: event.durationMs), + alignment: event.alignment ?? 0.0, ); - emit(currentState.copyWith( - selectedIndex: event.index, - visibleLinks: visibleLinks, - )); } } + void _emitSelectedIndex( + TextBookLoaded currentState, + Emitter emit, + int? index, { + required bool preferForPageShape, + }) { + final visibleLinks = _getVisibleLinks( + links: currentState.links, + visibleIndices: currentState.visibleIndices, + selectedIndex: index, + ); + + emit(currentState.copyWith( + selectedIndex: index, + visibleLinks: visibleLinks, + pageShapeAnchorIndex: index ?? currentState.pageShapeAnchorIndex, + pageShapePreferSelectedNextSync: preferForPageShape && index != null, + )); + } + void _onHighlightLine( HighlightLine event, Emitter emit, diff --git a/lib/text_book/bloc/text_book_event.dart b/lib/text_book/bloc/text_book_event.dart index 7303861a9..3cc26012a 100644 --- a/lib/text_book/bloc/text_book_event.dart +++ b/lib/text_book/bloc/text_book_event.dart @@ -117,6 +117,21 @@ class UpdateSelectedIndex extends TextBookEvent { List get props => [index]; } +class SelectAndScrollToIndex extends TextBookEvent { + final int index; + final int durationMs; + final double? alignment; + + const SelectAndScrollToIndex( + this.index, { + this.durationMs = 300, + this.alignment, + }); + + @override + List get props => [index, durationMs, alignment]; +} + class HighlightLine extends TextBookEvent { final int lineIndex; diff --git a/lib/text_book/bloc/text_book_state.dart b/lib/text_book/bloc/text_book_state.dart index d4419b38d..0f396f94a 100644 --- a/lib/text_book/bloc/text_book_state.dart +++ b/lib/text_book/bloc/text_book_state.dart @@ -101,6 +101,8 @@ class TextBookLoaded extends TextBookState { final int? selectedTextStart; final int? selectedTextEnd; final int? highlightedLine; + final int? pageShapeAnchorIndex; + final bool pageShapePreferSelectedNextSync; // Editor state final bool isEditorOpen; @@ -144,6 +146,8 @@ class TextBookLoaded extends TextBookState { this.selectedTextStart, this.selectedTextEnd, this.highlightedLine, + this.pageShapeAnchorIndex, + this.pageShapePreferSelectedNextSync = false, this.isEditorOpen = false, this.editorIndex, this.editorSectionId, @@ -183,6 +187,8 @@ class TextBookLoaded extends TextBookState { selectedTextStart: null, selectedTextEnd: null, highlightedLine: null, + pageShapeAnchorIndex: index, + pageShapePreferSelectedNextSync: false, isEditorOpen: false, editorIndex: null, editorSectionId: null, @@ -222,6 +228,8 @@ class TextBookLoaded extends TextBookState { int? selectedTextStart, int? selectedTextEnd, int? highlightedLine, + int? pageShapeAnchorIndex, + bool? pageShapePreferSelectedNextSync, bool clearHighlight = false, bool? isEditorOpen, int? editorIndex, @@ -262,6 +270,9 @@ class TextBookLoaded extends TextBookState { selectedTextEnd: selectedTextEnd ?? this.selectedTextEnd, highlightedLine: clearHighlight ? null : (highlightedLine ?? this.highlightedLine), + pageShapeAnchorIndex: pageShapeAnchorIndex ?? this.pageShapeAnchorIndex, + pageShapePreferSelectedNextSync: pageShapePreferSelectedNextSync ?? + this.pageShapePreferSelectedNextSync, isEditorOpen: isEditorOpen ?? this.isEditorOpen, editorIndex: editorIndex ?? this.editorIndex, editorSectionId: editorSectionId ?? this.editorSectionId, @@ -296,6 +307,8 @@ class TextBookLoaded extends TextBookState { selectedTextStart, selectedTextEnd, highlightedLine, + pageShapeAnchorIndex, + pageShapePreferSelectedNextSync, isEditorOpen, editorIndex, editorSectionId, diff --git a/lib/text_book/view/page_shape/page_shape_screen.dart b/lib/text_book/view/page_shape/page_shape_screen.dart index 5b2ca223f..8637fc207 100644 --- a/lib/text_book/view/page_shape/page_shape_screen.dart +++ b/lib/text_book/view/page_shape/page_shape_screen.dart @@ -662,12 +662,27 @@ class _CommentaryPaneState extends State<_CommentaryPane> { _blocSubscription = context.read().stream.listen((state) { if (state is TextBookLoaded && mounted) { + // עדכון קישורים רלוונטיים כשנטענים קישורים חדשים ב-Bloc + _refreshRelevantLinks(state); _syncWithMainText(state); _updateHighlights(state); } }); } + /// עדכון קישורים רלוונטיים מה-state (נקרא בכל שינוי state) + void _refreshRelevantLinks(TextBookLoaded state) { + if (state.links.length == _relevantLinks.length && + _relevantLinks.isNotEmpty) { + return; // הקישורים לא השתנו + } + _relevantLinks = state.links.where((link) { + final linkTitle = utils.getTitleFromPath(link.path2); + return linkTitle == widget.commentatorName && + LinkTypes.isCommentaryOrTargum(link.connectionType); + }).toList(); + } + void _updateHighlights(TextBookLoaded state) { if (!_highlightEnabled || state.selectedIndex == null) { if (_highlightedIndices.isNotEmpty) { @@ -724,12 +739,7 @@ class _CommentaryPaneState extends State<_CommentaryPane> { if (!mounted) return; if (state is TextBookLoaded) { - // סינון קישורים לפי שם המפרש ולפי סוג הקישור (COMMENTARY/TARGUM) - _relevantLinks = state.links.where((link) { - final linkTitle = utils.getTitleFromPath(link.path2); - return linkTitle == widget.commentatorName && - LinkTypes.isCommentaryOrTargum(link.connectionType); - }).toList(); + _refreshRelevantLinks(state); } // מציאת הספר המלא של המפרש עם categoryId @@ -890,14 +900,12 @@ class _CommentaryPaneState extends State<_CommentaryPane> { return; } - // קביעת האינדקס הנוכחי בטקסט הראשי - // נעדיף את visibleIndices כי זה המיקום האמיתי בגלילה - int currentMainIndex; - if (state.visibleIndices.isNotEmpty) { - currentMainIndex = state.visibleIndices.first; - } else if (state.selectedIndex != null) { - currentMainIndex = state.selectedIndex!; - } else { + final currentMainIndex = state.pageShapeAnchorIndex ?? + (state.visibleIndices.isNotEmpty + ? state.visibleIndices.first + : state.selectedIndex); + + if (currentMainIndex == null) { return; // אין מידע על מיקום נוכחי } @@ -963,15 +971,6 @@ class _CommentaryPaneState extends State<_CommentaryPane> { return TextBookStateBuilder( loadingWidget: const SizedBox(), builder: (context, state) { - // ניסיון סנכרון נוסף כשה-widget נבנה (במקרה שהסנכרון הראשוני נכשל) - if (_lastSyncedIndex == null && _scrollController.isAttached) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (mounted) { - _syncWithMainText(state); - } - }); - } - return BlocBuilder( builder: (context, settingsState) { // מפרשים תחתונים משתמשים בגופן מההגדרות, עליונים בגופן הרגיל diff --git a/lib/text_book/view/page_shape/simple_text_viewer.dart b/lib/text_book/view/page_shape/simple_text_viewer.dart index af7211432..950cc5ff7 100644 --- a/lib/text_book/view/page_shape/simple_text_viewer.dart +++ b/lib/text_book/view/page_shape/simple_text_viewer.dart @@ -107,14 +107,26 @@ class _SimpleTextViewerState extends State { void _scrollToCurrentPosition() { final bloc = context.read(); final state = bloc.state; - if (state is TextBookLoaded && _scrollController.isAttached) { - final targetIndex = state.selectedIndex ?? - (state.visibleIndices.isNotEmpty ? state.visibleIndices.first : null); + if (state is! TextBookLoaded) return; - if (targetIndex != null && targetIndex < widget.content.length) { - _scrollController.jumpTo(index: targetIndex); - } - } + final targetIndex = state.selectedIndex ?? + (state.visibleIndices.isNotEmpty ? state.visibleIndices.first : null); + if (targetIndex == null || targetIndex >= widget.content.length) return; + + bloc.add(SelectAndScrollToIndex( + targetIndex, + durationMs: 1, + )); + } + + void _selectAndScrollTo(int index, {int durationMs = 300, double? alignment}) { + context.read().add( + SelectAndScrollToIndex( + index, + durationMs: durationMs, + alignment: alignment, + ), + ); } /// טיפול באירועי מקלדת - חיצים לניווט @@ -130,14 +142,7 @@ class _SimpleTextViewerState extends State { final currentIndex = state.selectedIndex ?? 0; final nextIndex = (currentIndex + 1).clamp(0, widget.content.length - 1); if (nextIndex != currentIndex) { - context.read().add(UpdateSelectedIndex(nextIndex)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: nextIndex, - duration: const Duration(milliseconds: 200), - alignment: 0.5, - ); - } + _selectAndScrollTo(nextIndex, durationMs: 200, alignment: 0.5); } return true; } @@ -146,14 +151,7 @@ class _SimpleTextViewerState extends State { final currentIndex = state.selectedIndex ?? 0; final prevIndex = (currentIndex - 1).clamp(0, widget.content.length - 1); if (prevIndex != currentIndex) { - context.read().add(UpdateSelectedIndex(prevIndex)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: prevIndex, - duration: const Duration(milliseconds: 200), - alignment: 0.5, - ); - } + _selectAndScrollTo(prevIndex, durationMs: 200, alignment: 0.5); } return true; } @@ -162,14 +160,7 @@ class _SimpleTextViewerState extends State { if (event.logicalKey == LogicalKeyboardKey.pageDown) { final currentIndex = state.selectedIndex ?? 0; final nextIndex = (currentIndex + 10).clamp(0, widget.content.length - 1); - context.read().add(UpdateSelectedIndex(nextIndex)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: nextIndex, - duration: const Duration(milliseconds: 300), - alignment: 0.5, - ); - } + _selectAndScrollTo(nextIndex, alignment: 0.5); return true; } @@ -177,27 +168,14 @@ class _SimpleTextViewerState extends State { if (event.logicalKey == LogicalKeyboardKey.pageUp) { final currentIndex = state.selectedIndex ?? 0; final prevIndex = (currentIndex - 10).clamp(0, widget.content.length - 1); - context.read().add(UpdateSelectedIndex(prevIndex)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: prevIndex, - duration: const Duration(milliseconds: 300), - alignment: 0.5, - ); - } + _selectAndScrollTo(prevIndex, alignment: 0.5); return true; } // Home - תחילת הספר if (event.logicalKey == LogicalKeyboardKey.home && HardwareKeyboard.instance.isControlPressed) { - context.read().add(const UpdateSelectedIndex(0)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: 0, - duration: const Duration(milliseconds: 300), - ); - } + _selectAndScrollTo(0); return true; } @@ -205,13 +183,7 @@ class _SimpleTextViewerState extends State { if (event.logicalKey == LogicalKeyboardKey.end && HardwareKeyboard.instance.isControlPressed) { final lastIndex = widget.content.length - 1; - context.read().add(UpdateSelectedIndex(lastIndex)); - if (_scrollController.isAttached) { - _scrollController.scrollTo( - index: lastIndex, - duration: const Duration(milliseconds: 300), - ); - } + _selectAndScrollTo(lastIndex); return true; } diff --git a/lib/utils/fullscreen_helper.dart b/lib/utils/fullscreen_helper.dart index d285aaae2..6fe6cdd35 100644 --- a/lib/utils/fullscreen_helper.dart +++ b/lib/utils/fullscreen_helper.dart @@ -1,4 +1,7 @@ +import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:window_manager/window_manager.dart'; import 'package:otzaria/settings/engine/settings_bloc.dart'; @@ -11,21 +14,31 @@ class FullscreenHelper { BuildContext context, bool isFullscreen, ) async { - // עדכון ה-state ב-Bloc final settingsBloc = context.read(); if (settingsBloc.state.isFullscreen != isFullscreen) { settingsBloc.add(UpdateIsFullscreen(isFullscreen)); } - // פעולות על מנהל החלונות - // חשוב: להסתיר את ה-title bar לפני המעבר למסך מלא כדי למנוע הבהוב - if (isFullscreen) { - await windowManager.setTitleBarStyle(TitleBarStyle.hidden); - await windowManager.setFullScreen(true); - } else { - await windowManager.setFullScreen(false); - // אנחנו משתמשים ב-CustomTitleBar ולכן תמיד רוצים להסתיר את הכותרת המקורית - await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) { + if (isFullscreen) { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); + } else { + await SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge); + } + return; + } + + if (!kIsWeb && + (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) { + // חשוב: להסתיר את ה-title bar לפני המעבר למסך מלא כדי למנוע הבהוב + if (isFullscreen) { + await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + await windowManager.setFullScreen(true); + } else { + await windowManager.setFullScreen(false); + // אנחנו משתמשים ב-CustomTitleBar ולכן תמיד רוצים להסתיר את הכותרת המקורית + await windowManager.setTitleBarStyle(TitleBarStyle.hidden); + } } } } diff --git a/test/unit/settings/settings_bloc_test.dart b/test/unit/settings/settings_bloc_test.dart index 9063cd4ca..befc35e6f 100644 --- a/test/unit/settings/settings_bloc_test.dart +++ b/test/unit/settings/settings_bloc_test.dart @@ -57,7 +57,7 @@ void main() { 'copyHeaderFormat': 'same_line_after_brackets', 'isFullscreen': false, 'libraryViewMode': 'grid', - 'libraryShowPreview': true, + 'libraryShowPreview': false, 'enablePerBookSettings': true, 'shortcuts': {}, 'isOfflineMode': false,