feature/listening-history #39

Merged
EgorEast merged 22 commits from feature/listening-history into main 2026-08-20 12:56:30 +00:00
Owner

Сохранение истории и прогресса прослушивания проповедей в приложении, без бэкенда

Сохранение истории и прогресса прослушивания проповедей в приложении, без бэкенда
EgorEast added this to the MVP milestone 2026-08-19 08:43:18 +00:00
Signed-off-by: egoreast <egor.east@yandex.ru>
feat(player): resume playback from listening history and track progress
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m38s
9181069c64
Signed-off-by: egoreast <egor.east@yandex.ru>
docs: add lint-fix escalation workflow to AGENTS.md and conventions.md
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m39s
5bfdb9515c
Signed-off-by: egoreast <egor.east@yandex.ru>
Signed-off-by: egoreast <egor.east@yandex.ru>
feat(history): show listening progress in sermon lists
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m51s
4a435c8a80
Signed-off-by: egoreast <egor.east@yandex.ru>
feat(history): add listening history screen with progress and clear-all
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m41s
e783e8b3c8
Signed-off-by: egoreast <egor.east@yandex.ru>
Signed-off-by: egoreast <egor.east@yandex.ru>
Signed-off-by: egoreast <egor.east@yandex.ru>
docs: document listening history feature and ui structure rules
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m40s
7030efb07f
Signed-off-by: egoreast <egor.east@yandex.ru>
perf(history): split live progress snapshot from catalog writes
All checks were successful
CI / dco (pull_request) Successful in 15s
CI / checks (pull_request) Successful in 1m44s
a20c25b5f2
Signed-off-by: egoreast <egor.east@yandex.ru>
perf(ui): native equalizer animation, atom write guards, stable renderItem
All checks were successful
CI / dco (pull_request) Successful in 4s
CI / checks (pull_request) Successful in 1m41s
9c6368a253
Signed-off-by: egoreast <egor.east@yandex.ru>
chore: update dependencies
All checks were successful
CI / dco (pull_request) Successful in 3s
CI / checks (pull_request) Successful in 2m12s
cd0c73ae3e
Signed-off-by: egoreast <egor.east@yandex.ru>
Signed-off-by: egoreast <egor.east@yandex.ru>
docs: defer original-playlist playback from history
All checks were successful
CI / dco (pull_request) Successful in 4s
CI / checks (pull_request) Successful in 1m40s
ed843e31c4
Signed-off-by: egoreast <egor.east@yandex.ru>
feat(history): play from history in original playlist with full queue
All checks were successful
CI / dco (pull_request) Successful in 6s
CI / checks (pull_request) Successful in 1m48s
e3d6756228
Signed-off-by: egoreast <egor.east@yandex.ru>
EgorEast left a comment

Все неплохо, за исключением некоторых нюансов

Все неплохо, за исключением некоторых нюансов
@ -0,0 +29,4 @@
const raw = await AsyncStorage.getItem(LISTENING_PROGRESS_SNAPSHOT)
if (!raw) return undefined
const parsed = JSON.parse(raw) as unknown
Author
Owner

не лучше ли через zod схему валидировать?

не лучше ли через zod схему валидировать?
EgorEast marked this conversation as resolved
@ -0,0 +33,4 @@
? oldEntry.durationMs
: Math.max(params.oldPositionMs, oldEntry.positionMs)
if (finalPosition > oldEntry.positionMs || params.markOldCompleted) {
Author
Owner

надо чтобы новая позиция сохранялась, даже если я перекручу проповедь назад, а не только если она больше чем предыдущая сохраненная позиция

надо чтобы новая позиция сохранялась, даже если я перекручу проповедь назад, а не только если она больше чем предыдущая сохраненная позиция
EgorEast marked this conversation as resolved
@ -0,0 +41,4 @@
...overrides,
})
const renderWithCtx = async (
Author
Owner

у нас уже есть утилита renderHookWithProviders, использовать её

у нас уже есть утилита renderHookWithProviders, использовать её
EgorEast marked this conversation as resolved
@ -0,0 +103,4 @@
mockHistoryAtom(ctx, [])
})
test('(a) different sermon → replaceAudio called with resume ms', async () => {
Author
Owner

зачем буквы в начале тестов?

зачем буквы в начале тестов?
EgorEast marked this conversation as resolved
@ -2,0 +5,4 @@
historyAtom,
recordPlaybackStartAction,
recordSermonSwitchAction,
} from 'entities/listening-history'
Author
Owner

импорт должен быть через entities/listening-history/@x/player

импорт должен быть через entities/listening-history/@x/player
EgorEast marked this conversation as resolved
@ -0,0 +82,4 @@
getCachedSectionsMock.mockResolvedValue(undefined)
})
test('(a) found in live atom → returned, cache NOT read', async () => {
Author
Owner

тоже не понятно зачем их нумеровать буквами

тоже не понятно зачем их нумеровать буквами
EgorEast marked this conversation as resolved
@ -1,2 +1,3 @@
export * from './capitalizeString'
export * from './formatRelativeDate'
Author
Owner

тут должны быть все реэкспорты именованными, и реэкспортить только то что реально используется за границами этой папки или за границами shared

тут должны быть все реэкспорты именованными, и реэкспортить только то что реально используется за границами этой папки или за границами shared
EgorEast marked this conversation as resolved
@ -10,6 +10,7 @@ export * from './loading'
export * from './marquee-text/marquee-text'
export * from './modal'
export * from './MovingText'
export * from './progress-bar/ProgressBar'
Author
Owner

тут должны быть все реэкспорты именованными, и реэкспортить только то что реально используется за границами этой папки или за границами shared

тут должны быть все реэкспорты именованными, и реэкспортить только то что реально используется за границами этой папки или за границами shared
EgorEast marked this conversation as resolved
fix(player): restore background audio playback and media notification after long inactivity
All checks were successful
CI / dco (pull_request) Successful in 5s
CI / checks (pull_request) Successful in 1m47s
ec69eebf74
- AudioModeManager: removed one-time configured latch, added in-flight
  dedupe via configurePromise, unconditional re-assert on AppState active,
  .catch(console.warn) to avoid unhandled rejections.
- initializePlayer: unconditional configure() in isolated try/catch so a
  configure failure no longer skips track/playlist/volume/repeat restore.
- PlayerService.replaceAudio/unload: coordinated clear(old) ->
  releaseAndReset -> configure -> replaceAudio path; AudioLoader.releaseAndReset
  releases the native player and nulls its own reference to force the
  recreate path (fixes track-switch on a destroyed ExoPlayer/MediaSession).
- LockScreenControls: bounded retry (10x200ms) with version-counter to
  cancel stale retries; artwork fallback moved into applyMetadata; no more
  silent skip when player not yet loaded.
- Docs: player.md recovery section + upstream refs (expo#46137, expo#46957,
  androidx/media#1928); debt.md entries for bounded-retry limit and
  Android-15 wedged audio focus.
- Tests: split LockScreenControls.test.ts into setMetadata/retry/clear
  suites; new AudioModeManager.test.ts.

Signed-off-by: egoreast <egor.east@yandex.ru>
- Replace isValidSnapshot type guard with liveProgressSnapshotSchema (Zod safeParse)
- Derive LiveProgressSnapshot type via z.infer
- Parse-don't-validate: validate at storage boundary

Signed-off-by: egoreast <egor.east@yandex.ru>
- Remove Math.max and conditional write guard in recordSermonSwitch
- Remove monotonic-progress guard in flushHistoryProgress
- Remove monotonic-progress guard in reconcileOnHydration
- Position is now always saved even when user rewinds backward

Signed-off-by: egoreast <egor.east@yandex.ru>
- Create @x/player.ts re-exporting narrow API for entities/player
- Update all entities/player imports from entities/listening-history to @x/player
- Trim stale mock exports in usePlaybackProgressSaver.test.tsx
- FSD best practice: @x segments expose purpose-specific API

Signed-off-by: egoreast <egor.east@yandex.ru>
- Replace custom renderWithCtx with renderHookWithProviders
- Remove (a)-(i) letter prefixes from usePlaySermon test names
- Remove (a)-(g) letter prefixes from resolveEntryPlaylist test names

Signed-off-by: egoreast <egor.east@yandex.ru>
- Move shared/ui/themed.ts to shared/ui/theme/themed.ts
- Migrate ~80 files from 'shared/ui/themed' to 'shared/ui/theme' imports
- Rewrite shared/ui/index.ts with named exports only
- Remove theme symbols from shared/ui barrel (now in shared/ui/theme)
- Convert shared/lib/format barrel to named re-exports
- Remove unused capitalizeString from format barrel

Signed-off-by: egoreast <egor.east@yandex.ru>
docs: update documentation for review fixes and theme migration
All checks were successful
CI / dco (pull_request) Successful in 3s
CI / checks (pull_request) Successful in 1m51s
24f427d3df
- Document Zod validation in liveProgressStorage
- Document backward position saving behavior change
- Document @x/player cross-import pattern (architecture.md, conventions.md)
- Document barrel export rules (conventions.md, decisions.md)
- Document themed→theme migration
- Add technical debt entry for missing unit tests
- Update feature docs for listening-history and player

Signed-off-by: egoreast <egor.east@yandex.ru>
EgorEast changed title from WIP: feature/listening-history to feature/listening-history 2026-08-20 12:54:18 +00:00
EgorEast deleted branch feature/listening-history 2026-08-20 12:56:31 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Slovo_Propovedi/slovo-propovedi-mobile!39
No description provided.