From 806276194da639943e3416067e52c4c750fad591 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Thu, 8 Jul 2021 14:59:36 -0300 Subject: [PATCH 1/9] Add Review Order picker --- src/components/List/ListItem.js | 2 ++ src/screens/Review/ReviewMenu.js | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/components/List/ListItem.js b/src/components/List/ListItem.js index 3d4203b..336c77f 100644 --- a/src/components/List/ListItem.js +++ b/src/components/List/ListItem.js @@ -6,6 +6,7 @@ import { ListItem, Icon } from 'react-native-elements'; import device, {isWeb} from 'src/utils/device'; import useColorScheme from 'src/hooks/useColorScheme';; import theme from 'src/common/theme'; +import RNPickerSelect from 'react-native-picker-select'; const ListItemComponent = props => { const colorScheme = useColorScheme(); @@ -27,6 +28,7 @@ const ListItemComponent = props => { {props.rightIcon && {props.rightIcon}} {!isWeb() && props.switch && } {isWeb() && props.switch && {props?.switch?.value ? "On" : "Off"}} + {props.picker && } ) }; diff --git a/src/screens/Review/ReviewMenu.js b/src/screens/Review/ReviewMenu.js index 1a9d886..d3a2d49 100644 --- a/src/screens/Review/ReviewMenu.js +++ b/src/screens/Review/ReviewMenu.js @@ -123,6 +123,21 @@ const ReviewMenu = ({ }, } }, + { + id: 'ses-review-order', + title: 'Review Order', + leftIcon: , + picker: { + onValueChange: (value, index) => console.log(value), + placeholder: {}, + value: "lowest_level_first", + items: + [ + { label: "Random order", value: "random_order" }, + { label: "Lowest level first", value: "lowest_level_first" }, + ], + }, + }, { id: 'ses-dark', title: 'Dark Mode', From 371a44d1a64fdb6ceeeda7d68c5a94ece1c589ba Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Thu, 8 Jul 2021 15:31:15 -0300 Subject: [PATCH 2/9] Save Review Order to user settings --- src/common/constants.js | 6 ++++++ src/screens/Review/ReviewMenu.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 09919ff..247b846 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -21,6 +21,12 @@ export const DARK_MODE = 'DARK_MODE'; export const BACK_TO_BACK_MODE = 'BACK_TO_BACK_MODE'; export const MEANING_FIRST = 'MEANING_FIRST'; +// review orders +export const REVIEW_ORDER = 'REVIEW_ORDER' +export const RANDOM_ORDER = 'RANDOM_ORDER' +export const LOWEST_LEVEL_FIRST = 'LOWEST_LEVEL_FIRST' + + export const TERMINOLOGY = { // subject types diff --git a/src/screens/Review/ReviewMenu.js b/src/screens/Review/ReviewMenu.js index d3a2d49..b935684 100644 --- a/src/screens/Review/ReviewMenu.js +++ b/src/screens/Review/ReviewMenu.js @@ -10,7 +10,7 @@ import List from 'src/components/List/List'; import Modal, { DURATION_SAFE } from 'src/components/Modal/Modal'; import dialog from 'src/utils/dialog'; import { isWeb } from 'src/utils/device'; -import { SKIP_MODE, QUICK_MODE, DARK_MODE, BACK_TO_BACK_MODE, MEANING_FIRST} +import { SKIP_MODE, QUICK_MODE, DARK_MODE, BACK_TO_BACK_MODE, MEANING_FIRST, REVIEW_ORDER, RANDOM_ORDER, LOWEST_LEVEL_FIRST } from 'src/common/constants'; const ReviewMenu = ({ @@ -33,6 +33,7 @@ const ReviewMenu = ({ const darkMode = _.get(userSettings, DARK_MODE); const backToBackMode = _.get(userSettings, BACK_TO_BACK_MODE); const meaningFirst = _.get(userSettings, MEANING_FIRST); + const reviewOrder = _.get(userSettings, REVIEW_ORDER, RANDOM_ORDER); return ( , picker: { - onValueChange: (value, index) => console.log(value), + onValueChange: (value) => { + saveSetting({ key: REVIEW_ORDER, value: value }); + }, placeholder: {}, - value: "lowest_level_first", + value: reviewOrder, items: [ - { label: "Random order", value: "random_order" }, - { label: "Lowest level first", value: "lowest_level_first" }, + { value: RANDOM_ORDER, label: "Random Order" }, + { value: LOWEST_LEVEL_FIRST, label: "Lowest Level First" }, ], }, }, From 5d6d0d83a412bfb6a7ee813a5f352663b17d9f99 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Thu, 8 Jul 2021 18:03:16 -0300 Subject: [PATCH 3/9] Add more Review Order options --- src/common/constants.js | 3 +++ src/features/reviews/useReviewSession.js | 12 +++++++----- src/features/reviews/utils/adjustQueue.js | 5 +++-- src/screens/Review/ReviewMenu.js | 5 ++++- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/common/constants.js b/src/common/constants.js index 247b846..0dac708 100644 --- a/src/common/constants.js +++ b/src/common/constants.js @@ -25,6 +25,9 @@ export const MEANING_FIRST = 'MEANING_FIRST'; export const REVIEW_ORDER = 'REVIEW_ORDER' export const RANDOM_ORDER = 'RANDOM_ORDER' export const LOWEST_LEVEL_FIRST = 'LOWEST_LEVEL_FIRST' +export const CURRENT_LEVEL_FIRST = 'CURRENT_LEVEL_FIRST' +export const ASCENDING_SRS_STAGE = 'ASCENDING_SRS_STAGE' +export const DESCENDING_SRS_STAGE = 'DESCENDING_SRS_STAGE' export const TERMINOLOGY = { diff --git a/src/features/reviews/useReviewSession.js b/src/features/reviews/useReviewSession.js index ba2fa78..1e997e5 100644 --- a/src/features/reviews/useReviewSession.js +++ b/src/features/reviews/useReviewSession.js @@ -8,7 +8,7 @@ import { MEANING, RADICAL } from 'src/common/constants'; import listToDict from 'src/utils/listToDict'; import queueReviews from 'src/features/reviews/utils/queueReviews'; -import { BACK_TO_BACK_MODE, MEANING_FIRST} from 'src/common/constants'; +import { BACK_TO_BACK_MODE, MEANING_FIRST, REVIEW_ORDER } from 'src/common/constants'; import { useStoreState } from 'easy-peasy'; import adjustQueue from 'src/features/reviews/utils/adjustQueue'; @@ -32,16 +32,18 @@ export default (reviews, subjects) => { const [ completedCards, setCompletedCards ] = useState({}); const [ incorrectCards, setIncorrectCards ] = useState({}); - // Sort reading-meaning card pairs back-to-back + // Sort reading-meaning card pairs back-to-back according to the review order const userSettings = useStoreState(state => state.session.userSettings); const backToBackMode = _.get(userSettings, BACK_TO_BACK_MODE); const meaningFirst = _.get(userSettings, MEANING_FIRST); + const reviewOrder = _.get(userSettings, REVIEW_ORDER); // Re-sort queue when the relevant user settings change useEffect(() => { - setQueue(adjustQueue(queue, backToBackMode, meaningFirst)) + setQueue(adjustQueue(queue, backToBackMode, meaningFirst, reviewOrder)) }, [ - backToBackMode, - meaningFirst, + backToBackMode, + meaningFirst, + reviewOrder, ]); // refresh & diff --git a/src/features/reviews/utils/adjustQueue.js b/src/features/reviews/utils/adjustQueue.js index d88becb..6535f69 100644 --- a/src/features/reviews/utils/adjustQueue.js +++ b/src/features/reviews/utils/adjustQueue.js @@ -9,12 +9,13 @@ import _ from 'lodash'; -import { MEANING, RADICAL } from 'src/common/constants'; +import { MEANING, RADICAL, RANDOM_ORDER } from 'src/common/constants'; const ALLOWED_MAX_DISTANCE = 10; const ALLOWED_MIN_DISTANCE = 3; -export default (queue, backToBackMode = false, meaningFirst = false) => { +export default (queue, backToBackMode = false, meaningFirst = false, reviewOrder = RANDOM_ORDER) => { + const newQueue = queue.slice(); let currentIndex = 0; diff --git a/src/screens/Review/ReviewMenu.js b/src/screens/Review/ReviewMenu.js index b935684..f2478ea 100644 --- a/src/screens/Review/ReviewMenu.js +++ b/src/screens/Review/ReviewMenu.js @@ -10,7 +10,7 @@ import List from 'src/components/List/List'; import Modal, { DURATION_SAFE } from 'src/components/Modal/Modal'; import dialog from 'src/utils/dialog'; import { isWeb } from 'src/utils/device'; -import { SKIP_MODE, QUICK_MODE, DARK_MODE, BACK_TO_BACK_MODE, MEANING_FIRST, REVIEW_ORDER, RANDOM_ORDER, LOWEST_LEVEL_FIRST } +import { SKIP_MODE, QUICK_MODE, DARK_MODE, BACK_TO_BACK_MODE, MEANING_FIRST, REVIEW_ORDER, RANDOM_ORDER, LOWEST_LEVEL_FIRST, CURRENT_LEVEL_FIRST, ASCENDING_SRS_STAGE, DESCENDING_SRS_STAGE } from 'src/common/constants'; const ReviewMenu = ({ @@ -138,6 +138,9 @@ const ReviewMenu = ({ [ { value: RANDOM_ORDER, label: "Random Order" }, { value: LOWEST_LEVEL_FIRST, label: "Lowest Level First" }, + { value: CURRENT_LEVEL_FIRST, label: "Current Level First" }, + { value: ASCENDING_SRS_STAGE, label: "Ascending SRS Stage" }, + { value: DESCENDING_SRS_STAGE, label: "Descending SRS Stage" }, ], }, }, From e4a84c633eba31a82558079c2ed528f0e2695f69 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Fri, 9 Jul 2021 00:08:31 -0300 Subject: [PATCH 4/9] Sort queue by Ascending and Descending SRS Stage --- src/features/reviews/utils/adjustQueue.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/features/reviews/utils/adjustQueue.js b/src/features/reviews/utils/adjustQueue.js index 6535f69..7dd8f98 100644 --- a/src/features/reviews/utils/adjustQueue.js +++ b/src/features/reviews/utils/adjustQueue.js @@ -9,7 +9,7 @@ import _ from 'lodash'; -import { MEANING, RADICAL, RANDOM_ORDER } from 'src/common/constants'; +import { MEANING, RADICAL, RANDOM_ORDER, ASCENDING_SRS_STAGE, DESCENDING_SRS_STAGE } from 'src/common/constants'; const ALLOWED_MAX_DISTANCE = 10; const ALLOWED_MIN_DISTANCE = 3; @@ -19,6 +19,16 @@ export default (queue, backToBackMode = false, meaningFirst = false, reviewOrder const newQueue = queue.slice(); let currentIndex = 0; + // sort new queue based on the selected review order + switch (reviewOrder) { + case ASCENDING_SRS_STAGE: + newQueue.sort((a, b) => a.review.data.srs_stage - b.review.data.srs_stage); + break; + case DESCENDING_SRS_STAGE: + newQueue.sort((a, b) => b.review.data.srs_stage - a.review.data.srs_stage); + break; + } + // avoid recursion to avoid exceeding maximum call stack size while (currentIndex < queue.length - 1) { From 2c960a15aae2017c3b71735a2add81bcad6b81dc Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Fri, 9 Jul 2021 00:11:46 -0300 Subject: [PATCH 5/9] Implement random review order --- src/features/reviews/utils/adjustQueue.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/features/reviews/utils/adjustQueue.js b/src/features/reviews/utils/adjustQueue.js index 7dd8f98..58f3168 100644 --- a/src/features/reviews/utils/adjustQueue.js +++ b/src/features/reviews/utils/adjustQueue.js @@ -21,6 +21,9 @@ export default (queue, backToBackMode = false, meaningFirst = false, reviewOrder // sort new queue based on the selected review order switch (reviewOrder) { + case RANDOM_ORDER: + newQueue.sort(() => Math.random() - 0.5); + break; case ASCENDING_SRS_STAGE: newQueue.sort((a, b) => a.review.data.srs_stage - b.review.data.srs_stage); break; From 9c481339ddc72303d67376dd14e295cfaf65b6c2 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Fri, 9 Jul 2021 15:39:55 -0300 Subject: [PATCH 6/9] Implement subject level order --- src/features/reviews/useReviewSession.js | 4 ++-- src/features/reviews/utils/adjustQueue.js | 8 +++++++- src/features/reviews/utils/queueReviews.js | 12 ++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/features/reviews/useReviewSession.js b/src/features/reviews/useReviewSession.js index 1e997e5..ee1a615 100644 --- a/src/features/reviews/useReviewSession.js +++ b/src/features/reviews/useReviewSession.js @@ -65,8 +65,8 @@ export default (reviews, subjects) => { setTotalReviews(reviews ? reviews.length : 0); // create queue - const _queue = queueReviews(reviews); - setQueue(adjustQueue(_queue, backToBackMode, meaningFirst)); + const _queue = queueReviews(reviews, subjects); + setQueue(adjustQueue(_queue, backToBackMode, meaningFirst, reviewOrder)); setTotalCards(_queue.length); }, [ diff --git a/src/features/reviews/utils/adjustQueue.js b/src/features/reviews/utils/adjustQueue.js index 58f3168..378f7e9 100644 --- a/src/features/reviews/utils/adjustQueue.js +++ b/src/features/reviews/utils/adjustQueue.js @@ -9,7 +9,7 @@ import _ from 'lodash'; -import { MEANING, RADICAL, RANDOM_ORDER, ASCENDING_SRS_STAGE, DESCENDING_SRS_STAGE } from 'src/common/constants'; +import { MEANING, RADICAL, RANDOM_ORDER, LOWEST_LEVEL_FIRST, CURRENT_LEVEL_FIRST, ASCENDING_SRS_STAGE, DESCENDING_SRS_STAGE } from 'src/common/constants'; const ALLOWED_MAX_DISTANCE = 10; const ALLOWED_MIN_DISTANCE = 3; @@ -24,6 +24,12 @@ export default (queue, backToBackMode = false, meaningFirst = false, reviewOrder case RANDOM_ORDER: newQueue.sort(() => Math.random() - 0.5); break; + case LOWEST_LEVEL_FIRST: + newQueue.sort((a, b) => a.subjectLevel - b.subjectLevel); + break; + case CURRENT_LEVEL_FIRST: + newQueue.sort((a, b) => b.subjectLevel - a.subjectLevel); + break; case ASCENDING_SRS_STAGE: newQueue.sort((a, b) => a.review.data.srs_stage - b.review.data.srs_stage); break; diff --git a/src/features/reviews/utils/queueReviews.js b/src/features/reviews/utils/queueReviews.js index 3dfbef6..c3ede33 100644 --- a/src/features/reviews/utils/queueReviews.js +++ b/src/features/reviews/utils/queueReviews.js @@ -6,8 +6,7 @@ import adjustQueue from 'src/features/reviews/utils/adjustQueue'; // pick multiple reviews from the list, respecting the // removed items from the list from the previous loop -const queueReviews = (reviews, reviewTypesHistory, queue) => { - +const queueReviews = (reviews, reviewTypesHistory, queue, subjects) => { let _reviews = reviews; let _reviewTypesHistory = reviewTypesHistory; @@ -22,11 +21,16 @@ const queueReviews = (reviews, reviewTypesHistory, queue) => { newReviewTypeHistory, ] = pickReviewAndType(_reviews, _reviewTypesHistory); + // find the review's subject + const subject = subjects.find(subject => subject.id === review.data.subject_id); + const subjectLevel = _.get(subject, "data.level"); + // add current pick to the queue queue.push({ id: randomId(), review, reviewType, + subjectLevel, }); _reviews = newReviews; @@ -37,7 +41,7 @@ const queueReviews = (reviews, reviewTypesHistory, queue) => { return queue; } -export default reviews => { - const queued = queueReviews(reviews, {}, []); +export default (reviews, subjects) => { + const queued = queueReviews(reviews, {}, [], subjects); return adjustQueue(queued); }; From 572f68cf8d766d8fe1eb7f7f1834ec479dfa1465 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Fri, 9 Jul 2021 18:55:38 -0300 Subject: [PATCH 7/9] Add react-native-picker-select dependency --- package.json | 1 + yarn.lock | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/package.json b/package.json index 6f65d84..7331cb2 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "react-native-easy-toast": "^1.2.0", "react-native-elements": "^3.0.0", "react-native-modal": "^11.5.6", + "react-native-picker-select": "^8.0.4", "react-native-safe-area-context": "3.1.9", "react-native-web": "~0.13.12", "react-redux": "^7.2.0", diff --git a/yarn.lock b/yarn.lock index 61c9b90..3126ec4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2795,6 +2795,11 @@ resolved "https://registry.yarnpkg.com/@react-native-community/netinfo/-/netinfo-5.9.7.tgz#769c6b306ea6bbaa1c4a3fffdd183d0cfc30ed7e" integrity sha512-NAkkT68oF+M9o6El2xeUqZK7magPjG/tAcEbvCbqyhlh3yElKWnI1e1vpbVvFXzTefy67FwYFWOJqBN6U7Mnkg== +"@react-native-picker/picker@^1.8.3": + version "1.16.3" + resolved "https://registry.yarnpkg.com/@react-native-picker/picker/-/picker-1.16.3.tgz#22750f8d44465432845fa59ce20e69761029b6ef" + integrity sha512-Qt40DBg7IEhBN5x2DYPV3B26j5fNhVZcpCestr1IuirneMNtOaIyA9+nPYniL/OBzd9YbpUKbS7XSy/MM9bP3w== + "@reduxjs/toolkit@^1.3.5": version "1.4.0" resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.4.0.tgz#ee2e2384cc3d1d76780d844b9c2da3580d32710d" @@ -14201,6 +14206,14 @@ react-native-modal@^11.5.6: prop-types "^15.6.2" react-native-animatable "1.3.3" +react-native-picker-select@^8.0.4: + version "8.0.4" + resolved "https://registry.yarnpkg.com/react-native-picker-select/-/react-native-picker-select-8.0.4.tgz#3f7f1f42df69b06e7d2c10338288332a6c40fd10" + integrity sha512-orBjPIwBkV5oipyVw263YNMI56f6Kj3p/ejabZoCYYNSG3AiLVVhC2RqsxMgDA7IayyURAW+AlV+mDJyVqLBkg== + dependencies: + "@react-native-picker/picker" "^1.8.3" + lodash.isequal "^4.5.0" + react-native-ratings@^7.3.0: version "7.3.0" resolved "https://registry.yarnpkg.com/react-native-ratings/-/react-native-ratings-7.3.0.tgz#32e11e4ed944ba8adbbc995d601df3f131619b6f" From 324e616f78b4ed49c374a3376be8081be9c87d10 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Sat, 10 Jul 2021 12:28:25 -0300 Subject: [PATCH 8/9] Use loadsh to implement the Review Order options --- src/features/reviews/utils/adjustQueue.js | 12 ++++++------ src/features/reviews/utils/queueReviews.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/features/reviews/utils/adjustQueue.js b/src/features/reviews/utils/adjustQueue.js index 378f7e9..3145224 100644 --- a/src/features/reviews/utils/adjustQueue.js +++ b/src/features/reviews/utils/adjustQueue.js @@ -16,25 +16,25 @@ const ALLOWED_MIN_DISTANCE = 3; export default (queue, backToBackMode = false, meaningFirst = false, reviewOrder = RANDOM_ORDER) => { - const newQueue = queue.slice(); + let newQueue = queue.slice(); let currentIndex = 0; // sort new queue based on the selected review order switch (reviewOrder) { case RANDOM_ORDER: - newQueue.sort(() => Math.random() - 0.5); + newQueue = _.shuffle(newQueue); break; case LOWEST_LEVEL_FIRST: - newQueue.sort((a, b) => a.subjectLevel - b.subjectLevel); + newQueue = _.orderBy(newQueue, 'subjectLevel', 'asc') break; case CURRENT_LEVEL_FIRST: - newQueue.sort((a, b) => b.subjectLevel - a.subjectLevel); + newQueue = _.orderBy(newQueue, 'subjectLevel', 'desc') break; case ASCENDING_SRS_STAGE: - newQueue.sort((a, b) => a.review.data.srs_stage - b.review.data.srs_stage); + newQueue = _.orderBy(newQueue, 'review.data.srs_stage', 'asc') break; case DESCENDING_SRS_STAGE: - newQueue.sort((a, b) => b.review.data.srs_stage - a.review.data.srs_stage); + newQueue = _.orderBy(newQueue, 'review.data.srs_stage', 'desc') break; } diff --git a/src/features/reviews/utils/queueReviews.js b/src/features/reviews/utils/queueReviews.js index c3ede33..a72fbeb 100644 --- a/src/features/reviews/utils/queueReviews.js +++ b/src/features/reviews/utils/queueReviews.js @@ -22,7 +22,7 @@ const queueReviews = (reviews, reviewTypesHistory, queue, subjects) => { ] = pickReviewAndType(_reviews, _reviewTypesHistory); // find the review's subject - const subject = subjects.find(subject => subject.id === review.data.subject_id); + const subject = subjects.find(subject => subject.id === _.get(review, 'data.subject_id')); const subjectLevel = _.get(subject, "data.level"); // add current pick to the queue From 7d978d61e1eb608a1d2f51d3413b466081c41863 Mon Sep 17 00:00:00 2001 From: Rafael Scarduelli Date: Sat, 10 Jul 2021 18:13:23 -0300 Subject: [PATCH 9/9] Style Review Order picker --- src/components/List/ListItem.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/components/List/ListItem.js b/src/components/List/ListItem.js index 336c77f..0d3be99 100644 --- a/src/components/List/ListItem.js +++ b/src/components/List/ListItem.js @@ -28,7 +28,7 @@ const ListItemComponent = props => { {props.rightIcon && {props.rightIcon}} {!isWeb() && props.switch && } {isWeb() && props.switch && {props?.switch?.value ? "On" : "Off"}} - {props.picker && } + {props.picker && } ) }; @@ -65,4 +65,12 @@ const styles = StyleSheet.create({ } }) +const pickerStyles = StyleSheet.create({ + inputWeb: { + borderWidth: 0, + textAlign: 'right', + fontSize: 14, + }, +}) + export default ListItemComponent;