From df99231a033fd7f2ee3acb6ae954f340f10f6f98 Mon Sep 17 00:00:00 2001 From: Iliya Lyan <68940374+12ya@users.noreply.github.com> Date: Thu, 19 Oct 2023 21:16:01 +0900 Subject: [PATCH 1/5] chore: components/Listen/Listen.react.tsx :: add types --- js/components/Listen/Listen.react.tsx | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/js/components/Listen/Listen.react.tsx b/js/components/Listen/Listen.react.tsx index 7cead30..a918621 100644 --- a/js/components/Listen/Listen.react.tsx +++ b/js/components/Listen/Listen.react.tsx @@ -15,8 +15,21 @@ import {genProgressForLesson} from '../../persistence'; import {log} from '../../metrics'; import {useSetStatusBarStyle} from '../../hooks/useStatusBarStyle'; -const Listen = (props: any) => { +interface Props { + route: { + params: { + course: Course; + lesson: number; + }; + }; + navigation: { + pop: () => void; + }; +} + +const Listen = (props: Props) => { const {course, lesson} = props.route.params; + const [bottomSheetOpen, setBottomSheetOpen] = useState(false); const playbackState = usePlaybackState(); @@ -24,9 +37,7 @@ const Listen = (props: any) => { // go back to the previous screen when the user stops // the music from outside the app - useTrackPlayerEvents([Event.RemoteStop], () => - props.navigation.pop(), - ); + useTrackPlayerEvents([Event.RemoteStop], () => props.navigation.pop()); // adjust the status bar style according to the course colors, // and the bottom sheet visibility @@ -39,11 +50,7 @@ const Listen = (props: any) => { ((navBarLight ? 'dark' : 'light') + '-content') as StatusBarStyle, navBarLight, ); - }, [ - setStatusBarStyle, - bottomSheetOpen, - course, - ]); + }, [setStatusBarStyle, bottomSheetOpen, course]); // load & queue audio file, find the last heard offset, and start // the lesson @@ -114,7 +121,7 @@ const Listen = (props: any) => { position: await TrackPlayer.getPosition(), }); - TrackPlayer.seekTo(Math.max(0, await TrackPlayer.getPosition() - 10)); + TrackPlayer.seekTo(Math.max(0, (await TrackPlayer.getPosition()) - 10)); }; return ( From 3e0207663bceb5081ef4493b144cf8d6bc13429b Mon Sep 17 00:00:00 2001 From: Iliya Lyan <68940374+12ya@users.noreply.github.com> Date: Thu, 19 Oct 2023 21:34:33 +0900 Subject: [PATCH 2/5] chore: audio-service :: cleanup & add types --- js/audio-service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/audio-service.ts b/js/audio-service.ts index 44dc4a8..1849379 100644 --- a/js/audio-service.ts +++ b/js/audio-service.ts @@ -1,5 +1,5 @@ -import {Platform} from 'react-native'; -import TrackPlayer, {State, Event, Capability, IOSCategory} from 'react-native-track-player'; +import {Platform, EmitterSubscription} from 'react-native'; +import TrackPlayer, {State, Event, Capability} from 'react-native-track-player'; import BackgroundTimer, {IntervalId} from 'react-native-background-timer'; import { genAutopause, @@ -19,7 +19,7 @@ type CurrentPlaying = { let currentlyPlaying: CurrentPlaying | null = null; let updateInterval: IntervalId | null = null; -let audioServiceSubscriptions: any[] = []; +let audioServiceSubscriptions: EmitterSubscription[] = []; // when we enqueue then skip, it acts like we skipped from track 1 to track n. suppress the event let suppressTrackChange = false; From cf2aa14c8da50a033893c07df4bcfa4f895ad04e Mon Sep 17 00:00:00 2001 From: Iliya Lyan <68940374+12ya@users.noreply.github.com> Date: Thu, 19 Oct 2023 21:48:00 +0900 Subject: [PATCH 3/5] chore: audio-service & metrics :: add types --- js/audio-service.ts | 10 +++++++++- js/metrics.ts | 12 +++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/js/audio-service.ts b/js/audio-service.ts index 1849379..b4dd07d 100644 --- a/js/audio-service.ts +++ b/js/audio-service.ts @@ -24,6 +24,12 @@ let audioServiceSubscriptions: EmitterSubscription[] = []; // when we enqueue then skip, it acts like we skipped from track 1 to track n. suppress the event let suppressTrackChange = false; +interface PlaybackTrackChangedEventParams { + track: string | null; + position: number; + nextTrack: string | null; +} + export const genEnqueueFile = async ( course: Course, lesson: number, @@ -119,6 +125,7 @@ export const genStopPlaying = async () => { await TrackPlayer.destroy(); }; + export default async () => { audioServiceSubscriptions.forEach((s) => s.remove()); @@ -246,12 +253,13 @@ export default async () => { }, ), + // welcome! you've found it. the worst code in the codebase. // I have a personal policy of including explicit blame whenever I write code I know someone will curse me for one day. // contact me@timothyaveni.com with your complaints. TrackPlayer.addEventListener( Event.PlaybackTrackChanged, - async (params) => { + async (params: PlaybackTrackChangedEventParams) => { const wasPlaying = currentlyPlaying; if (params.track == null || wasPlaying === null) { diff --git a/js/metrics.ts b/js/metrics.ts index 9fc9962..b6c0331 100644 --- a/js/metrics.ts +++ b/js/metrics.ts @@ -5,7 +5,17 @@ import CourseData from './course-data'; const LOG_ENDPOINT = 'https://metrics.languagetransfer.org/log'; -export const log = async (data: any): Promise => { +interface Data { + action: string; + surface?: string; + lesson?: number; + event?: string; + course?: Course; + metadata_version?: number; + position?: number; +} + +export const log = async (data: Data): Promise => { const [permitted, user_token] = await Promise.all([ genPreferenceAllowDataCollection(), genMetricsToken(), From 05eee5973d1c4e845c1b6fb491ceb8fc60349253 Mon Sep 17 00:00:00 2001 From: Iliya Lyan <68940374+12ya@users.noreply.github.com> Date: Thu, 19 Oct 2023 22:02:22 +0900 Subject: [PATCH 4/5] chore: persistence :: add enum for preference 1st parameter --- js/persistence.ts | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/js/persistence.ts b/js/persistence.ts index 252670e..52e690d 100644 --- a/js/persistence.ts +++ b/js/persistence.ts @@ -11,6 +11,17 @@ import {log} from './metrics'; // haven't gone to the effort of adding a mutex. mostly because I don't like // the API for the most popular library. +enum Preference { + AUTO_DELETE_FINISHED = 'auto-delete-finished', + STREAM_QUALITY = 'stream-quality', + DOWNLOAD_QUALITY = 'download-quality', + DOWNLOAD_ONLY_ON_WIFI = 'download-only-on-wifi', + ALLOW_DATA_COLLECTION = 'allow-data-collection', + IS_FIRST_LOAD = 'is-first-load', + RATING_BUTTON_DISMISSED = 'rating-button-dismissed', + KILLSWITCH_COURSE_VERSION_V1 = 'killswitch-course-version-v1', +} + export interface Progress { finished: boolean; progress: number | null; @@ -183,42 +194,42 @@ const preference = ( export const [ genPreferenceAutoDeleteFinished, genSetPreferenceAutoDeleteFinished, -] = preference('auto-delete-finished', false, (b) => b === 'true'); +] = preference(Preference.AUTO_DELETE_FINISHED, false, (b) => b === 'true'); -export const [ - genPreferenceStreamQuality, - genSetPreferenceStreamQuality, -] = preference('stream-quality', 'low', (b) => b); +export const [genPreferenceStreamQuality, genSetPreferenceStreamQuality] = + preference(Preference.STREAM_QUALITY, 'low', (b) => b); -export const [ - genPreferenceDownloadQuality, - genSetPreferenceDownloadQuality, -] = preference('download-quality', 'high', (b) => b); +export const [genPreferenceDownloadQuality, genSetPreferenceDownloadQuality] = + preference(Preference.DOWNLOAD_QUALITY, 'high', (b) => b); export const [ genPreferenceDownloadOnlyOnWifi, genSetPreferenceDownloadOnlyOnWifi, -] = preference('download-only-on-wifi', true, (b) => b === 'true'); +] = preference(Preference.DOWNLOAD_ONLY_ON_WIFI, true, (b) => b === 'true'); export const [ genPreferenceAllowDataCollection, genSetPreferenceAllowDataCollection, -] = preference('allow-data-collection', true, (b) => b === 'true'); +] = preference(Preference.ALLOW_DATA_COLLECTION, true, (b) => b === 'true'); -export const [ - genPreferenceIsFirstLoad, - genSetPreferenceIsFirstLoad, -] = preference('is-first-load', true, (b) => b === 'true'); +export const [genPreferenceIsFirstLoad, genSetPreferenceIsFirstLoad] = + preference(Preference.IS_FIRST_LOAD, true, (b) => b === 'true'); export const [ genPreferenceRatingButtonDismissed, genSetPreferenceRatingButtonDismissed, -] = preference('rating-button-dismissed', { dismissed: false }, (o) => JSON.parse(o)); +] = preference(Preference.RATING_BUTTON_DISMISSED, {dismissed: false}, (o) => + JSON.parse(o), +); export const [ genPreferenceKillswitchCourseVersionV1, genSetPreferenceKillswitchCourseVersionV1, -] = preference('killswitch-course-version-v1', false, (b) => b === 'true'); +] = preference( + Preference.KILLSWITCH_COURSE_VERSION_V1, + false, + (b) => b === 'true', +); export function usePreference(key: Preference, defaultValue: any) { const [value, setValue] = useState(null!); From 897898492327e34c2f0bb12c1256b56e6b135895 Mon Sep 17 00:00:00 2001 From: Iliya Lyan <68940374+12ya@users.noreply.github.com> Date: Thu, 19 Oct 2023 22:03:39 +0900 Subject: [PATCH 5/5] chore: metrics Data interface add missed param --- js/metrics.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/js/metrics.ts b/js/metrics.ts index b6c0331..e84e2d8 100644 --- a/js/metrics.ts +++ b/js/metrics.ts @@ -13,6 +13,7 @@ interface Data { course?: Course; metadata_version?: number; position?: number; + setting_value?: number; } export const log = async (data: Data): Promise => {