Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
555 changes: 236 additions & 319 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@electron/notarize": "^2.3.1",
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.1",
"@fingerprintjs/fingerprintjs": "^5.0.1",
"@fingerprintjs/fingerprintjs": "^5.1.0",
"@fontsource/roboto": "^5.2.6",
"@fortawesome/fontawesome-svg-core": "^7.0.1",
"@fortawesome/free-regular-svg-icons": "^7.0.1",
Expand Down
5 changes: 4 additions & 1 deletion src/renderer/src/business/player/usePlayerLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@ export const usePlayerLogic = (props: PlayerLogicProps) => {
const loadSegments = () => {
const segs = mediafileRef.current?.attributes?.segments || '{}';
if (allowSegment) {
segmentsRef.current = getSegments(allowSegment, segs);
segmentsRef.current =
suggestedSegments && suggestedSegments.length > 0
? suggestedSegments
: getSegments(allowSegment, segs);
Comment on lines +58 to +61
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadSegments() now prefers suggestedSegments whenever it’s a non-empty string. Several callers pass placeholder values like '{}' (or a stale value from a previous render), so this can prevent loading the mediafile’s saved segments and show the wrong segments on initial load. Prefer always loading from getSegments(allowSegment, segs) on mediafile change, and keep the separate effect that applies suggestedSegments only when the user actually provides an override.

Suggested change
segmentsRef.current =
suggestedSegments && suggestedSegments.length > 0
? suggestedSegments
: getSegments(allowSegment, segs);
// On mediafile change, always load segments from the mediafile itself.
// Any suggestedSegments override is applied separately in the effect
// that watches [allowSegment, suggestedSegments].
segmentsRef.current = getSegments(allowSegment, segs);

Copilot uses AI. Check for mistakes.
setSegmentToWhole();
}
setDefaultSegments(segmentsRef.current);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
import {
Box,
Button,
Checkbox,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
FormControlLabel,
NativeSelect,
Typography,
} from '@mui/material';
import type { ChangeEvent } from 'react';
import { useEffect, useState } from 'react';

const suffixOptions = ['', 'a', 'b', 'c', 'd', 'e'];
const selectSx = {
minWidth: 64,
'& .MuiNativeSelect-select': {
fontSize: 40,
lineHeight: 1.1,
textAlign: 'center',
pr: 3,
},
'& .MuiNativeSelect-icon': {
fontSize: 24,
right: 0,
},
};
const verseSelectSx = {
...selectSx,
'& .MuiNativeSelect-select': {
...selectSx['& .MuiNativeSelect-select'],
fontSize: 28,
},
};
const suffixOptionStyle = {
fontSize: 50,
};
const verseOptionStyle = {
fontSize: 48,
};

export interface EditReferenceValue {
splitVerse: boolean;
canSplit: boolean;
startChapter: number;
startVerse: number;
startSuffix: string;
endChapter: number;
endVerse: number;
endSuffix: string;
}

interface EditReferenceDropdownProps {
open: boolean;
limits: string;
maxVerse: number;
verseOptions: number[];
title: string;
cancelLabel: string;
saveLabel: string;
splitVerseLabel: string;
value: EditReferenceValue;
onCancel: () => void;
onSave: (value: EditReferenceValue) => void;
}

export default function EditReferenceDropdown({
open,
limits,
maxVerse,
verseOptions,
title,
cancelLabel,
saveLabel,
splitVerseLabel,
value,
onCancel,
onSave,
}: EditReferenceDropdownProps) {
const [draft, setDraft] = useState<EditReferenceValue>(value);
const verseNumberOptions = Array.from(
new Set([...verseOptions, draft.startVerse, draft.endVerse, maxVerse])
).sort((left, right) => left - right);

useEffect(() => {
setDraft(value);
}, [value]);

const handleSplitChange = (
event: ChangeEvent<HTMLInputElement>,
checked: boolean
) => {
setDraft((current) => ({
...current,
splitVerse: checked,
}));
};

const handleSuffixChange =
(key: 'startSuffix' | 'endSuffix') =>
(event: ChangeEvent<HTMLSelectElement>) => {
const nextSuffix = event.target.value.toLowerCase();
setDraft((current) => ({
...current,
[key]: nextSuffix,
}));
};

const handleVerseChange =
(key: 'startVerse' | 'endVerse') =>
(event: ChangeEvent<HTMLSelectElement>) => {
const nextVerse = parseInt(event.target.value, 10);
if (Number.isNaN(nextVerse)) return;

setDraft((current) => ({
...current,
[key]: nextVerse,
}));
};

const displayEndChapter = draft.endChapter;
const displayEndVerse = draft.endVerse;
const canEditEndSuffix = draft.canSplit || draft.splitVerse;

return (
<Dialog
open={open}
onClose={onCancel}
aria-labelledby="edit-reference-dialog-title"
fullWidth
maxWidth="xs"
>
<DialogTitle id="edit-reference-dialog-title">
{`${title} ${limits}`}
</DialogTitle>
<DialogContent sx={{ pt: 1 }}>
<Box
sx={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
gap: 1.5,
mb: 2,
fontVariantNumeric: 'tabular-nums',
}}
>
<Box sx={{ textAlign: 'center' }}>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: 0.5,
}}
>
<Typography
sx={{ fontSize: 28 }}
>{`${draft.startChapter}:`}</Typography>
<NativeSelect
value={draft.startVerse}
onChange={handleVerseChange('startVerse')}
inputProps={{ 'aria-label': 'start verse number' }}
sx={verseSelectSx}
>
{verseNumberOptions.map((option) => (
<option
key={`start-verse-${option}`}
value={option}
style={verseOptionStyle}
>
{option}
</option>
))}
</NativeSelect>
</Box>
<NativeSelect
value={draft.startSuffix}
onChange={handleSuffixChange('startSuffix')}
inputProps={{ 'aria-label': 'start verse suffix' }}
sx={selectSx}
>
{suffixOptions.map((option) => (
<option
key={option || 'none-start'}
value={option}
style={suffixOptionStyle}
>
{option || ' '}
</option>
))}
</NativeSelect>
</Box>
<Typography variant="h6">-</Typography>
<Box sx={{ textAlign: 'center' }}>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
gap: 0.5,
}}
>
<Typography
sx={{ fontSize: 24 }}
>{`${displayEndChapter}:`}</Typography>
<NativeSelect
value={displayEndVerse}
onChange={handleVerseChange('endVerse')}
disabled={!draft.splitVerse}
inputProps={{ 'aria-label': 'end verse number' }}
sx={verseSelectSx}
>
{verseNumberOptions.map((option) => (
<option
key={`end-verse-${option}`}
value={option}
style={verseOptionStyle}
>
{option}
</option>
))}
</NativeSelect>
</Box>
<NativeSelect
value={draft.endSuffix}
onChange={handleSuffixChange('endSuffix')}
disabled={!canEditEndSuffix}
inputProps={{ 'aria-label': 'end verse suffix' }}
sx={selectSx}
>
{suffixOptions.map((option) => (
<option
key={option || 'none-end'}
value={option}
style={suffixOptionStyle}
>
{option || ' '}
</option>
))}
</NativeSelect>
</Box>
</Box>

<FormControlLabel
control={
<Checkbox checked={draft.splitVerse} onChange={handleSplitChange} />
}
label={splitVerseLabel}
/>
</DialogContent>
<DialogActions sx={{ px: 3, pb: 2 }}>
<Button onClick={onCancel}>{cancelLabel}</Button>
<Button variant="contained" onClick={() => onSave(draft)}>
{saveLabel}
</Button>
</DialogActions>
</Dialog>
);
}
// test
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the trailing // test comment before merge; it looks like leftover debug text and adds noise.

Suggested change
// test

Copilot uses AI. Check for mistakes.
Loading