From 42e725189096627eafecf4af42a0327fe8486d3c Mon Sep 17 00:00:00 2001 From: Alexander Dimitrov Date: Wed, 18 Oct 2023 11:46:37 +0300 Subject: [PATCH 1/5] make mark as finished button dynamic --- js/components/Listen/ListenBody.react.tsx | 4 +++- .../Listen/ListenBottomSheet.react.tsx | 9 ++++++--- js/hooks/useIsLessonFinished.ts | 17 +++++++++++++++++ js/persistence.ts | 2 +- 4 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 js/hooks/useIsLessonFinished.ts diff --git a/js/components/Listen/ListenBody.react.tsx b/js/components/Listen/ListenBody.react.tsx index b28cf6d..10fd65e 100644 --- a/js/components/Listen/ListenBody.react.tsx +++ b/js/components/Listen/ListenBody.react.tsx @@ -18,6 +18,7 @@ import TrackPlayer, { } from 'react-native-track-player'; import {log} from '../../metrics'; import useIsLessonDownloaded from '../../hooks/useIsLessonDownloaded'; +import useIsLessonFinished from '../../hooks/useIsLessonFinished'; interface Props { course: Course, @@ -38,6 +39,7 @@ const ListenBody = ({course, lesson, setBottomSheetOpen, skipBack, seekTo, toggl const paused = playbackState === State.Paused; const bottomSheet = useRef(null); + const finished = useIsLessonFinished(course, lesson); const downloaded = useIsLessonDownloaded(course, lesson); if (downloaded === null) { return ( @@ -151,7 +153,7 @@ const ListenBody = ({course, lesson, setBottomSheetOpen, skipBack, seekTo, toggl }); setBottomSheetOpen(false); }}> - + ); diff --git a/js/components/Listen/ListenBottomSheet.react.tsx b/js/components/Listen/ListenBottomSheet.react.tsx index 58396a6..7fbc020 100644 --- a/js/components/Listen/ListenBottomSheet.react.tsx +++ b/js/components/Listen/ListenBottomSheet.react.tsx @@ -20,10 +20,11 @@ import { MainNavigationProp } from '../App.react'; interface Props { course: Course, lesson: number, - downloaded: boolean | null; + downloaded: boolean | null, + finished: boolean | null; } -const ListenBottomSheet = ({course, lesson, downloaded}: Props) => { +const ListenBottomSheet = ({course, lesson, downloaded, finished}: Props) => { const {position} = useProgress(); const {pop} = useNavigation>(); @@ -43,7 +44,9 @@ const ListenBottomSheet = ({course, lesson, downloaded}: Props) => { pop(); }}> - Mark as finished + + Mark as {finished ? 'unfinished' : 'finished'} + (null); + useEffect(() => { + async function checkIfFinished() { + const resp = await genProgressForLesson(course, lesson); + setFinished(resp?.finished || null); + } + + setFinished(null); + checkIfFinished(); + }, [course, lesson]); + + return finished; +} diff --git a/js/persistence.ts b/js/persistence.ts index 252670e..c27e944 100644 --- a/js/persistence.ts +++ b/js/persistence.ts @@ -103,7 +103,7 @@ export const genMarkLessonFinished = async ( `@activity/${course}/${lesson}`, JSON.stringify({ ...progressObject, - finished: true, + finished: !progressObject?.finished, }), ), AsyncStorage.setItem( From befcce0b1932ee331ddb37247e1afd91658de626 Mon Sep 17 00:00:00 2001 From: Alexander Dimitrov Date: Wed, 18 Oct 2023 21:36:44 +0300 Subject: [PATCH 2/5] add toggleLessonFinished operation --- .../Listen/ListenBottomSheet.react.tsx | 4 +-- js/persistence.ts | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/js/components/Listen/ListenBottomSheet.react.tsx b/js/components/Listen/ListenBottomSheet.react.tsx index 7fbc020..aba060c 100644 --- a/js/components/Listen/ListenBottomSheet.react.tsx +++ b/js/components/Listen/ListenBottomSheet.react.tsx @@ -9,7 +9,7 @@ import { import {Icon} from 'react-native-elements'; import CourseData from '../../course-data'; import DownloadManager from '../../download-manager'; -import {genMarkLessonFinished} from '../../persistence'; +import {genMarkLessonFinished, genToggleLessonFinished} from '../../persistence'; import {genStopPlaying} from '../../audio-service'; import {useNavigation} from '@react-navigation/native'; import {useProgress} from 'react-native-track-player'; @@ -40,7 +40,7 @@ const ListenBottomSheet = ({course, lesson, downloaded, finished}: Props) => { position, }); - await genMarkLessonFinished(course, lesson); + await genToggleLessonFinished(course, lesson); pop(); }}> diff --git a/js/persistence.ts b/js/persistence.ts index c27e944..c25a935 100644 --- a/js/persistence.ts +++ b/js/persistence.ts @@ -98,6 +98,35 @@ export const genMarkLessonFinished = async ( ): Promise => { const progressObject = await genProgressForLesson(course, lesson); + await Promise.all([ + AsyncStorage.setItem( + `@activity/${course}/${lesson}`, + JSON.stringify({ + ...progressObject, + finished: true, + }), + ), + AsyncStorage.setItem( + `@activity/${course}/most-recent-lesson`, + lesson.toString(), + ), + AsyncStorage.setItem('@activity/most-recent-course', course), + ]); + + if ( + (await genPreferenceAutoDeleteFinished()) && + (await DownloadManager.genIsDownloaded(course, lesson)) + ) { + await DownloadManager.genDeleteDownload(course, lesson); + } +}; + +export const genToggleLessonFinished = async ( + course: Course, + lesson: number, +): Promise => { + const progressObject = await genProgressForLesson(course, lesson); + await Promise.all([ AsyncStorage.setItem( `@activity/${course}/${lesson}`, From d7a694db4b8e392384291663fc9944adc5df2a11 Mon Sep 17 00:00:00 2001 From: Alexander Dimitrov Date: Thu, 19 Oct 2023 12:49:37 +0300 Subject: [PATCH 3/5] delete lesson only if finished --- js/persistence.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/js/persistence.ts b/js/persistence.ts index c25a935..badeb8d 100644 --- a/js/persistence.ts +++ b/js/persistence.ts @@ -143,6 +143,7 @@ export const genToggleLessonFinished = async ( ]); if ( + progressObject?.finished && (await genPreferenceAutoDeleteFinished()) && (await DownloadManager.genIsDownloaded(course, lesson)) ) { From 60962b167f5e9f5284376f36f622e00d1119b6b8 Mon Sep 17 00:00:00 2001 From: Alexander Dimitrov Date: Fri, 20 Oct 2023 00:00:23 +0300 Subject: [PATCH 4/5] add set course progress operation --- js/persistence.ts | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/js/persistence.ts b/js/persistence.ts index badeb8d..9bc2e5a 100644 --- a/js/persistence.ts +++ b/js/persistence.ts @@ -151,6 +151,52 @@ export const genToggleLessonFinished = async ( } }; +export const genSetProgressForCourse = async ( + course: Course, + lastLesson: number, +): Promise => { + const lastLessonIndex = lastLesson - 1; + const lessonCount = parseInt(CourseData.getFallbackLessonCount(course), 10); + + if (lastLessonIndex > lessonCount) { + return; + } + + for (let lesson = 0; lesson <= lastLessonIndex; lesson++) { + const progressObject = await genProgressForLesson(course, lesson); + + await AsyncStorage.setItem( + `@activity/${course}/${lesson}`, + JSON.stringify({ + ...progressObject, + finished: true, + }), + ); + } + + await Promise.all([ + AsyncStorage.setItem( + `@activity/${course}/most-recent-lesson`, + lastLessonIndex.toString(), + ), + AsyncStorage.setItem('@activity/most-recent-course', course), + ]); + + if (lastLessonIndex < lessonCount) { + for (let lesson = lastLessonIndex + 1; lesson < lessonCount; lesson++) { + const progressObject = await genProgressForLesson(course, lesson); + + await AsyncStorage.setItem( + `@activity/${course}/${lesson}`, + JSON.stringify({ + ...progressObject, + finished: false, + }), + ); + } + } +}; + export const genDeleteProgressForCourse = async ( course: Course, ): Promise => { From 703d76ecbea1a7a293a00cbc2897dfd1a70fe552 Mon Sep 17 00:00:00 2001 From: Alexander Dimitrov Date: Fri, 20 Oct 2023 15:43:46 +0300 Subject: [PATCH 5/5] add modal to set course progress --- .../DataManagement/DataManagement.react.tsx | 131 +++++++++++++++++- js/persistence.ts | 9 +- 2 files changed, 135 insertions(+), 5 deletions(-) diff --git a/js/components/DataManagement/DataManagement.react.tsx b/js/components/DataManagement/DataManagement.react.tsx index 2cba370..6dda324 100644 --- a/js/components/DataManagement/DataManagement.react.tsx +++ b/js/components/DataManagement/DataManagement.react.tsx @@ -1,22 +1,30 @@ -import React from 'react'; +import React, { useState } from 'react'; import { View, Text, StyleSheet, TouchableNativeFeedback, Alert, + Modal, + TextInput, + Button, } from 'react-native'; import {ScrollView} from 'react-native-gesture-handler'; import useStatusBarStyle from '../../hooks/useStatusBarStyle'; import CourseData from '../../course-data'; import DownloadManager from '../../download-manager'; -import {genDeleteProgressForCourse} from '../../persistence'; +import {genDeleteProgressForCourse, genSetProgressForCourse} from '../../persistence'; import {log} from '../../metrics'; import { useNavigation } from '@react-navigation/core'; import { MainNavigationProp } from '../App.react'; const DataManagement = ({route}: {route: any}) => { useStatusBarStyle('white', 'dark-content'); + const [modalVisible, setModalVisible] = useState(false); + const [lastLessonNumber, _setLastLessonNumber] = useState(''); + const setLastLessonNumber = (val: string) => { + _setLastLessonNumber(val.replace(/[^0-9]/g, '')); + }; const {navigate} = useNavigation>(); const {course} = route.params; @@ -66,6 +74,89 @@ const DataManagement = ({route}: {route: any}) => { + + setModalVisible(true)} + // TODO: Replace with modal with number input and guide text. Added this for testing purposes. + useForeground={true}> + + + Set {courseTitle} progress + + + This will set all the lessons up to the given lesson number as + completed. + + + + { + Alert.alert('Modal has been closed.'); + setModalVisible(!modalVisible); + // TODO: How do I do this better? I don't need the value of the input after the modal is closed so it can be discarded. A local variable would suffice. + setLastLessonNumber(''); + }}> + + + + Set the lesson number you wish to set your course progress to: + + + + + +