BioFlow Requirements
lib\application\view_models\bottom_bar_notifier.dart
Source file coverage
Path:
lib/application/view_models/bottom_bar_notifier.dart
Lines:
166
Non-empty lines:
136
Non-empty lines covered with requirements:
136 / 136 (100.0%)
Functions:
0
Functions covered by requirements:
0 / 0 (0.0%)
1
import 'package:bioflow_pro/domain/value_objects/ui/bottom_bar_mode.dart';
2
import 'package:flutter_riverpod/flutter_riverpod.dart';
3
 
4
// @relation(ARCH-009, scope=file)
5
/// Notifier for managing bottom bar mode and animation timing
6
/// Note: Bottom bar mode is not persisted - always starts with signal mode on app launch
7
class BottomBarNotifier extends Notifier<BottomBarMode> {
8
  int? _lastSelectedOverlayIndex;
9
 
10
  @override
11
  BottomBarMode build() {
12
    // Always start with signal mode on app launch
13
    return BottomBarMode.signal;
14
  }
15
 
16
  /// Toggle between signal and menu modes with animation timing
17
  void toggleMode({int? currentOverlayIndex}) {
18
    final newMode = state.toggle();
19
 
20
    // Save overlay state when switching to signal mode
21
    if (newMode.isSignalMode && currentOverlayIndex != null) {
22
      _lastSelectedOverlayIndex = currentOverlayIndex;
23
    }
24
 
25
    state = newMode;
26
  }
27
 
28
  /// Get the last selected overlay index to restore
29
  int? get lastSelectedOverlayIndex => _lastSelectedOverlayIndex;
30
 
31
  /// Save an overlay index for later restoration
32
  // ignore: use_setters_to_change_properties
33
  void saveOverlayIndex(int index) {
34
    _lastSelectedOverlayIndex = index;
35
  }
36
 
37
  /// Clear the saved overlay index
38
  void clearSavedOverlayIndex() {
39
    _lastSelectedOverlayIndex = null;
40
  }
41
 
42
  /// Set specific mode with validation
43
  // ignore: avoid_setters_without_getters
44
  set mode(BottomBarMode mode) {
45
    if (state != mode) {
46
      state = mode;
47
    }
48
  }
49
 
50
  /// Get current mode (for explicit access, though state is directly accessible)
51
  BottomBarMode getMode() {
52
    return state;
53
  }
54
 
55
  /// Set to signal mode
56
  void setSignalMode() {
57
    mode = BottomBarMode.signal;
58
  }
59
 
60
  /// Set to menu mode
61
  void setMenuMode() {
62
    mode = BottomBarMode.menu;
63
  }
64
 
65
  /// Check if current mode is signal mode
66
  bool get isSignalMode => state.isSignalMode;
67
 
68
  /// Check if current mode is menu mode
69
  bool get isMenuMode => state.isMenuMode;
70
 
71
  /// Get animation duration for UI transitions
72
  Duration get animationDuration => BottomBarMode.animationDuration;
73
 
74
  /// Get display items for current mode
75
  List<String> get currentModeItems => state.displayedItems;
76
 
77
  /// Get display name for current mode
78
  String get currentModeDisplayName => state.displayName;
79
 
80
  /// Get description for current mode
81
  String get currentModeDescription => state.description;
82
 
83
  /// Check if mode is valid for given context
84
  bool isModeValidForContext({
85
    bool isRecording = false,
86
    bool hasSignalData = false,
87
  }) {
88
    return state.isValidForContext(
89
      isRecording: isRecording,
90
      hasSignalData: hasSignalData,
91
    );
92
  }
93
 
94
  /// Get suggested mode for current context
95
  BottomBarMode getSuggestedMode({
96
    bool isRecording = false,
97
    bool hasSignalData = false,
98
    bool userPreference = false,
99
  }) {
100
    return BottomBarMode.suggestModeForContext(
101
      isRecording: isRecording,
102
      hasSignalData: hasSignalData,
103
      userPreference: userPreference,
104
    );
105
  }
106
 
107
  /// Auto-switch to suggested mode if different from current
108
  void autoSwitchToSuggestedMode({
109
    bool isRecording = false,
110
    bool hasSignalData = false,
111
    bool userPreference = false,
112
  }) {
113
    final suggestedMode = getSuggestedMode(
114
      isRecording: isRecording,
115
      hasSignalData: hasSignalData,
116
      userPreference: userPreference,
117
    );
118
 
119
    if (suggestedMode != state) {
120
      mode = suggestedMode;
121
    }
122
  }
123
 
124
  /// Check if current mode supports a specific feature
125
  bool supportsFeature(String feature) {
126
    return state.supportsFeature(feature);
127
  }
128
 
129
  /// Get keyboard shortcut for current mode
130
  String get currentModeShortcut => state.keyboardShortcut;
131
 
132
  /// Get accessibility label for current mode
133
  String get accessibilityLabel => state.accessibilityLabel;
134
 
135
  /// Reset to default mode (signal)
136
  void resetToDefault() {
137
    mode = BottomBarMode.signal;
138
  }
139
 
140
  /// Handle mode change with context validation
141
  bool trySetModeWithValidation(
142
    BottomBarMode newMode, {
143
    bool isRecording = false,
144
    bool hasSignalData = false,
145
  }) {
146
    // Check if the new mode is valid for the current context
147
    if (newMode.isValidForContext(
148
      isRecording: isRecording,
149
      hasSignalData: hasSignalData,
150
    )) {
151
      mode = newMode;
152
      return true;
153
    }
154
 
155
    // Return false if mode is not valid for context
156
    return false;
157
  }
158
 
159
  /// Get the opposite mode of current state
160
  BottomBarMode get oppositeMode => state.opposite;
161
 
162
  /// Switch to opposite mode
163
  void switchToOpposite() {
164
    mode = oppositeMode;
165
  }
166
}