Skip to content

Commit 96635db

Browse files
committed
Remove redundant state
1 parent 146a627 commit 96635db

File tree

25 files changed

+335
-346
lines changed

25 files changed

+335
-346
lines changed

src/Bible.Alarm/Stores/Effects/ScheduleEffects.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,9 @@ public async Task HandleRemoveScheduleSuccess(RemoveScheduleSuccessAction action
245245
[EffectMethod]
246246
public async Task HandleBiblePublicationTrackSelected(Bible.Alarm.Stores.Actions.BiblePublications.TrackSelectedAction action, IDispatcher dispatcher)
247247
{
248-
await trackSyncHandler.HandleTrackSelected(action, dispatcher);
248+
// No-op: Reducer OnBiblePublicationTrackSelected now directly updates CurrentSchedule
249+
// No sync needed - CurrentSchedule is the single source of truth
250+
await Task.CompletedTask;
249251
}
250252

251253
/// <summary>
@@ -256,7 +258,9 @@ public async Task HandleBiblePublicationTrackSelected(Bible.Alarm.Stores.Actions
256258
[EffectMethod]
257259
public async Task HandleMusicTrackSelected(Bible.Alarm.Stores.Actions.Music.TrackSelectedAction action, IDispatcher dispatcher)
258260
{
259-
await trackSyncHandler.HandleTrackSelected(action, dispatcher);
261+
// No-op: Reducer OnMusicTrackSelected now directly updates CurrentSchedule
262+
// No sync needed - CurrentSchedule is the single source of truth
263+
await Task.CompletedTask;
260264
}
261265
}
262266

src/Bible.Alarm/Stores/Effects/Services/TrackSelectionSyncHandler.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,21 @@ public async Task HandleTrackSelected(BiblePublicationTrackSelectedAction action
9494
var currentSchedule = currentState.CurrentSchedule;
9595
var biblePub = action.CurrentBiblePublicationSchedule;
9696

97+
// The reducer OnBiblePublicationTrackSelected now updates CurrentSchedule synchronously,
98+
// so we should check if CurrentSchedule already has the action's values.
99+
// If everything is already in sync, skip the redundant dispatch to avoid extra state updates.
100+
var alreadyInSync =
101+
currentSchedule.BiblePublicationLanguageCode == biblePub.LanguageCode &&
102+
currentSchedule.BiblePublicationCode == biblePub.PublicationCode &&
103+
currentSchedule.BiblePublicationSectionNumber == biblePub.SectionNumber &&
104+
currentSchedule.BiblePublicationTrackNumber == biblePub.TrackNumber;
105+
106+
if (alreadyInSync)
107+
{
108+
Log.Debug("TrackSelectionSyncHandler: HandleTrackSelected (BiblePublication) - CurrentSchedule already in sync with action, skipping dispatch.");
109+
return;
110+
}
111+
97112
// Detect if language or publication changed - if so, we should NOT preserve old names
98113
var languageChanged = !string.IsNullOrEmpty(biblePub.LanguageCode) &&
99114
biblePub.LanguageCode != currentSchedule.BiblePublicationLanguageCode;

src/Bible.Alarm/Stores/Reducers/ApplicationReducer.cs

Lines changed: 64 additions & 117 deletions
Large diffs are not rendered by default.

src/Bible.Alarm/Stores/Reducers/ContainerReadinessReducer.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ public static ApplicationState OnContainerReady(ApplicationState state, Containe
6060
return new ApplicationState(
6161
schedules: state.Schedules,
6262
currentSchedule: state.CurrentSchedule,
63-
currentMusic: state.CurrentMusic,
64-
currentBiblePublicationSchedule: state.CurrentBiblePublicationSchedule,
6563
isHomePageOverlayVisible: state.IsHomePageOverlayVisible,
6664
isSchedulePageOverlayVisible: state.IsSchedulePageOverlayVisible,
6765
containerReadiness: updatedReadiness);
@@ -76,8 +74,6 @@ public static ApplicationState OnResetContainerReadiness(ApplicationState state,
7674
return new ApplicationState(
7775
schedules: state.Schedules,
7876
currentSchedule: state.CurrentSchedule,
79-
currentMusic: state.CurrentMusic,
80-
currentBiblePublicationSchedule: state.CurrentBiblePublicationSchedule,
8177
isHomePageOverlayVisible: state.IsHomePageOverlayVisible,
8278
isSchedulePageOverlayVisible: state.IsSchedulePageOverlayVisible,
8379
containerReadiness: ContainerReadiness.NotReady);

src/Bible.Alarm/Stores/Reducers/Services/ScheduleCrudReducer.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,6 @@ public static ApplicationState OnUpdateScheduleSuccess(ApplicationState state, U
305305
return new ApplicationState(
306306
schedules: newSchedules,
307307
currentSchedule: updatedCurrentSchedule,
308-
currentMusic: state.CurrentMusic,
309-
currentBiblePublicationSchedule: state.CurrentBiblePublicationSchedule,
310308
isHomePageOverlayVisible: state.IsHomePageOverlayVisible,
311309
isSchedulePageOverlayVisible: state.IsSchedulePageOverlayVisible,
312310
containerReadiness: state.ContainerReadiness);

src/Bible.Alarm/Stores/Reducers/Services/StateFactory.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,21 @@ namespace Bible.Alarm.Stores.Reducers.Services;
1313
/// </summary>
1414
public static class StateFactory
1515
{
16+
/// <summary>
17+
/// Creates updated state with only CurrentSchedule (single source of truth).
18+
/// Removed separate CurrentMusic and CurrentBiblePublicationSchedule - all data is in CurrentSchedule.
19+
/// </summary>
1620
public static ApplicationState CreateUpdatedState(
1721
ApplicationState state,
18-
ScheduleStateItem? updatedCurrentSchedule,
19-
MusicStateItem? updatedCurrentMusic,
20-
BiblePublicationStateItem? updatedCurrentBiblePublicationSchedule)
22+
ScheduleStateItem? updatedCurrentSchedule)
2123
{
2224
return new ApplicationState(
2325
schedules: state.Schedules,
2426
currentSchedule: updatedCurrentSchedule,
25-
currentMusic: updatedCurrentMusic,
26-
currentBiblePublicationSchedule: updatedCurrentBiblePublicationSchedule,
2727
isHomePageOverlayVisible: state.IsHomePageOverlayVisible,
2828
isSchedulePageOverlayVisible: state.IsSchedulePageOverlayVisible,
29-
containerReadiness: state.ContainerReadiness);
29+
containerReadiness: state.ContainerReadiness,
30+
pendingScheduleLoad: state.PendingScheduleLoad);
3031
}
3132

3233
public static ApplicationState CreateStateWithSchedules(
@@ -37,11 +38,10 @@ public static ApplicationState CreateStateWithSchedules(
3738
return new ApplicationState(
3839
schedules: newSchedules,
3940
currentSchedule: updatedCurrentSchedule ?? state.CurrentSchedule,
40-
currentMusic: state.CurrentMusic,
41-
currentBiblePublicationSchedule: state.CurrentBiblePublicationSchedule,
4241
isHomePageOverlayVisible: state.IsHomePageOverlayVisible,
4342
isSchedulePageOverlayVisible: state.IsSchedulePageOverlayVisible,
44-
containerReadiness: state.ContainerReadiness);
43+
containerReadiness: state.ContainerReadiness,
44+
pendingScheduleLoad: state.PendingScheduleLoad);
4545
}
4646
}
4747

src/Bible.Alarm/Stores/Selectors/ApplicationSelectors.cs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,30 +35,44 @@ public static class ApplicationSelectors
3535

3636
/// <summary>
3737
/// Selector: Get current music as AlarmMusic entity (for ViewModel use).
38-
/// Maps MusicStateItem (domain model) → AlarmMusic (entity for ViewModel).
38+
/// Derives from CurrentSchedule (single source of truth).
3939
/// </summary>
4040
public static AlarmMusic? GetCurrentMusicEntity(ApplicationState state, IMapper mapper)
4141
{
42-
if (state.CurrentMusic == null)
42+
if (state.CurrentSchedule == null)
43+
{
44+
return null;
45+
}
46+
47+
// Extract music from CurrentSchedule (flattened properties)
48+
var schedule = state.CurrentSchedule;
49+
if (!schedule.MusicId.HasValue && !schedule.MusicType.HasValue)
4350
{
4451
return null;
4552
}
4653

47-
return mapper.Map<AlarmMusic>(state.CurrentMusic);
54+
return mapper.Map<AlarmSchedule>(schedule)?.Music;
4855
}
4956

5057
/// <summary>
5158
/// Selector: Get current Bible reading schedule as BiblePublicationSchedule entity (for ViewModel use).
52-
/// Maps BiblePublicationStateItem (domain model) → BiblePublicationSchedule (entity for ViewModel).
59+
/// Derives from CurrentSchedule (single source of truth).
5360
/// </summary>
5461
public static BiblePublicationSchedule? GetCurrentBiblePublicationEntity(ApplicationState state, IMapper mapper)
5562
{
56-
if (state.CurrentBiblePublicationSchedule == null)
63+
if (state.CurrentSchedule == null)
64+
{
65+
return null;
66+
}
67+
68+
// Extract Bible publication from CurrentSchedule (flattened properties)
69+
var schedule = state.CurrentSchedule;
70+
if (!schedule.BiblePublicationScheduleId.HasValue && string.IsNullOrEmpty(schedule.BiblePublicationLanguageCode))
5771
{
5872
return null;
5973
}
6074

61-
return mapper.Map<BiblePublicationSchedule>(state.CurrentBiblePublicationSchedule);
75+
return mapper.Map<AlarmSchedule>(schedule)?.BiblePublicationSchedule;
6276
}
6377

6478
/// <summary>

src/Bible.Alarm/Stores/State.cs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ public class ApplicationState
1111
{
1212
public ObservableHashSet<ScheduleStateItem> Schedules { get; set; }
1313

14+
/// <summary>
15+
/// Single source of truth for the current schedule being edited.
16+
/// Contains all schedule properties including bible publication and music properties (flattened).
17+
/// </summary>
1418
public ScheduleStateItem? CurrentSchedule { get; set; }
1519

16-
public MusicStateItem? CurrentMusic { get; set; }
17-
18-
public BiblePublicationStateItem? CurrentBiblePublicationSchedule { get; set; }
19-
2020
public bool IsHomePageOverlayVisible { get; set; }
2121
public bool IsSchedulePageOverlayVisible { get; set; }
2222
public ContainerReadiness ContainerReadiness { get; set; }
@@ -38,17 +38,13 @@ public ApplicationState()
3838
public ApplicationState(
3939
ObservableHashSet<ScheduleStateItem> schedules,
4040
ScheduleStateItem? currentSchedule = null,
41-
MusicStateItem? currentMusic = null,
42-
BiblePublicationStateItem? currentBiblePublicationSchedule = null,
4341
bool isHomePageOverlayVisible = false,
4442
bool isSchedulePageOverlayVisible = false,
4543
ContainerReadiness? containerReadiness = null,
4644
PendingScheduleLoad? pendingScheduleLoad = null)
4745
{
4846
Schedules = schedules ?? [];
4947
CurrentSchedule = currentSchedule;
50-
CurrentMusic = currentMusic;
51-
CurrentBiblePublicationSchedule = currentBiblePublicationSchedule;
5248
IsHomePageOverlayVisible = isHomePageOverlayVisible;
5349
IsSchedulePageOverlayVisible = isSchedulePageOverlayVisible;
5450
ContainerReadiness = containerReadiness ?? Models.ContainerReadiness.NotReady;

src/Bible.Alarm/ViewModels/BiblePublications/BiblePublicationSelectionViewModel.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,11 @@ public BiblePublicationSelectionViewModel(
5454
propertyManager = new BiblePublicationSelectionPropertyManager(state, dataProvider, stateHandler);
5555

5656
// Initialize current from state if available (map DTO to entity)
57-
// Use CurrentSchedule as the source of truth, with CurrentBiblePublicationSchedule as fallback
57+
// Use CurrentSchedule as the source of truth
5858
var currentState = state.Value;
5959
BiblePublicationSchedule? initialCurrent = null;
6060
string? initialLanguageCode = null;
61-
if (currentState.CurrentBiblePublicationSchedule != null)
62-
{
63-
initialCurrent = mapper.Map<BiblePublicationSchedule>(currentState.CurrentBiblePublicationSchedule);
64-
initialLanguageCode = initialCurrent.LanguageCode;
65-
}
66-
else if (currentState.CurrentSchedule != null && !string.IsNullOrEmpty(currentState.CurrentSchedule.BiblePublicationLanguageCode))
61+
if (currentState.CurrentSchedule != null && !string.IsNullOrEmpty(currentState.CurrentSchedule.BiblePublicationLanguageCode))
6762
{
6863
// Create a minimal BiblePublicationSchedule from CurrentSchedule
6964
var currentSchedule = currentState.CurrentSchedule;

src/Bible.Alarm/ViewModels/BiblePublications/BibleSelectionViewModelHelpers/BiblePublicationSelectionStateHandler.cs

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,25 @@ public async Task HandleBiblePublicationInitializedAsync(Action<bool> setIsBusy,
6969
lastLanguageCode = newLanguageCode;
7070
}
7171

72-
// Update current if we have CurrentBiblePublicationSchedule (for other properties like PublicationCode)
73-
if (stateValue.CurrentBiblePublicationSchedule != null)
72+
// Derive from CurrentSchedule (single source of truth)
73+
var currentSchedule = stateValue.CurrentSchedule;
74+
if (currentSchedule != null && !string.IsNullOrEmpty(currentSchedule.BiblePublicationLanguageCode))
7475
{
75-
current = mapper.Map<BiblePublicationSchedule>(stateValue.CurrentBiblePublicationSchedule);
76+
// Create BiblePublicationSchedule from CurrentSchedule
77+
current = new BiblePublicationSchedule
78+
{
79+
LanguageCode = currentSchedule.BiblePublicationLanguageCode,
80+
PublicationCode = currentSchedule.BiblePublicationCode ?? string.Empty,
81+
SectionNumber = currentSchedule.BiblePublicationSectionNumber,
82+
TrackNumber = currentSchedule.BiblePublicationTrackNumber ?? 0,
83+
FinishedDuration = currentSchedule.BiblePublicationFinishedDuration ?? TimeSpan.Zero
84+
};
7685
if (string.IsNullOrEmpty(lastLanguageCode))
7786
{
7887
lastLanguageCode = current.LanguageCode;
7988
}
8089
}
81-
else if (stateValue.CurrentSchedule != null && !string.IsNullOrEmpty(newLanguageCode))
90+
else if (currentSchedule != null && !string.IsNullOrEmpty(newLanguageCode))
8291
{
8392
// Create a minimal BiblePublicationSchedule from CurrentSchedule
8493
current = new BiblePublicationSchedule
@@ -204,10 +213,19 @@ public async Task HandleBiblePublicationChangedAsync(Action<bool> setIsBusy, Act
204213
// Update tracking variable
205214
lastLanguageCode = newLanguageCode;
206215

207-
// Update current if we have CurrentBiblePublicationSchedule (for other properties like PublicationCode)
208-
if (stateValue.CurrentBiblePublicationSchedule != null)
216+
// Derive from CurrentSchedule (single source of truth)
217+
// currentSchedule is already declared above
218+
if (currentSchedule != null && !string.IsNullOrEmpty(currentSchedule.BiblePublicationLanguageCode))
209219
{
210-
current = mapper.Map<BiblePublicationSchedule>(stateValue.CurrentBiblePublicationSchedule);
220+
// Create BiblePublicationSchedule from CurrentSchedule
221+
current = new BiblePublicationSchedule
222+
{
223+
LanguageCode = currentSchedule.BiblePublicationLanguageCode,
224+
PublicationCode = currentSchedule.BiblePublicationCode ?? string.Empty,
225+
SectionNumber = currentSchedule.BiblePublicationSectionNumber,
226+
TrackNumber = currentSchedule.BiblePublicationTrackNumber ?? 0,
227+
FinishedDuration = currentSchedule.BiblePublicationFinishedDuration ?? TimeSpan.Zero
228+
};
211229
lastCurrent = current;
212230
}
213231
else
@@ -274,18 +292,6 @@ public async Task RefreshFromStateAsync(Action<bool> setIsBusy, ObservableCollec
274292
}
275293
}
276294

277-
// Fall back to CurrentBiblePublicationSchedule if CurrentSchedule isn't updated yet
278-
// This handles the case where BiblePublicationSelectionAction updates CurrentBiblePublicationSchedule
279-
// but the effect that syncs to CurrentSchedule hasn't run yet
280-
if (string.IsNullOrEmpty(newLanguageCode) && stateValue.CurrentBiblePublicationSchedule != null)
281-
{
282-
newLanguageCode = stateValue.CurrentBiblePublicationSchedule.LanguageCode;
283-
if (!string.IsNullOrEmpty(newLanguageCode))
284-
{
285-
break;
286-
}
287-
}
288-
289295
// Wait a bit and retry if language code is not set yet
290296
await Task.Delay(delayMs);
291297
}
@@ -305,10 +311,18 @@ public async Task RefreshFromStateAsync(Action<bool> setIsBusy, ObservableCollec
305311
// Update tracking variable
306312
lastLanguageCode = newLanguageCode;
307313

308-
// Update current from CurrentSchedule
309-
if (finalStateValue.CurrentBiblePublicationSchedule != null)
314+
// Update current from CurrentSchedule (single source of truth)
315+
if (currentSchedule != null && !string.IsNullOrEmpty(currentSchedule.BiblePublicationLanguageCode))
310316
{
311-
current = mapper.Map<BiblePublicationSchedule>(finalStateValue.CurrentBiblePublicationSchedule);
317+
// Create BiblePublicationSchedule from CurrentSchedule
318+
current = new BiblePublicationSchedule
319+
{
320+
LanguageCode = currentSchedule.BiblePublicationLanguageCode,
321+
PublicationCode = currentSchedule.BiblePublicationCode ?? string.Empty,
322+
SectionNumber = currentSchedule.BiblePublicationSectionNumber,
323+
TrackNumber = currentSchedule.BiblePublicationTrackNumber ?? 0,
324+
FinishedDuration = currentSchedule.BiblePublicationFinishedDuration ?? TimeSpan.Zero
325+
};
312326
}
313327
else if (!string.IsNullOrEmpty(newLanguageCode))
314328
{

0 commit comments

Comments
 (0)