Skip to content

Commit

Permalink
feat: Persist Scale Selections through sessions
Browse files Browse the repository at this point in the history
- Add Logic for persisting scale selections on Random and Advanced screens
- Update many JSDocs throughout the project
- Update react-native-popover-view library to prevent crashes on simple random view
  • Loading branch information
aburdiss committed Dec 28, 2024
1 parent 4db34de commit 56f5a64
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 57 deletions.
14 changes: 4 additions & 10 deletions ios/ScalePractice.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -979,10 +979,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
Expand Down Expand Up @@ -1048,10 +1045,7 @@
"-DFOLLY_CFG_NO_COROUTINES=1",
"-DFOLLY_HAVE_CLOCK_GETTIME=1",
);
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
OTHER_LDFLAGS = "$(inherited) ";
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
USE_HERMES = true;
Expand Down Expand Up @@ -1079,7 +1073,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = ScalePracticeWatch_Extension;
INFOPLIST_FILE = ScalePracticeWatch/Info.plist;
MARKETING_VERSION = 2.7.2;
MARKETING_VERSION = 2.8.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.AlexanderBurdiss.ScalePractice.watchkitapp;
Expand Down Expand Up @@ -1115,7 +1109,7 @@
GCC_C_LANGUAGE_STANDARD = gnu11;
IBSC_MODULE = ScalePracticeWatch_Extension;
INFOPLIST_FILE = ScalePracticeWatch/Info.plist;
MARKETING_VERSION = 2.7.2;
MARKETING_VERSION = 2.8.0;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.AlexanderBurdiss.ScalePractice.watchkitapp;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "scale-practice",
"version": "2.7.2",
"version": "2.8.0",
"private": true,
"scripts": {
"prepare": "git config core.hooksPath ./scripts/hooks",
Expand Down Expand Up @@ -32,7 +32,7 @@
"react-native-idle-timer": "^2.1.7",
"react-native-linear-gradient": "^2.6.2",
"react-native-localize": "^2.2.4",
"react-native-popover-view": "^5.1.6",
"react-native-popover-view": "6.0.1",
"react-native-reanimated": "3.16.1",
"react-native-safe-area-context": "^4.4.1",
"react-native-screens": "^3.18.2",
Expand Down
81 changes: 64 additions & 17 deletions src/Model/Preferences.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,84 @@
import React, { createContext, useReducer, useEffect } from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';

const RANDOM_TYPES = {
/**
* @namespace Preferences
* @description The namespace for all logic related to global saved
* preferences
*/

/**
* @name RANDOM_TYPES
* @memberof Preferences
*/
const RANDOM_TYPES = Object.freeze({
SCALE: 'SCALE',
ARPEGGIO: 'ARPEGGIO',
};
});

const ADVANCED_TYPES = {
/**
* @name ADVANCED_TYPES
* @memberof Preferences
*/
const ADVANCED_TYPES = Object.freeze({
SCALE: 'SCALE',
ARPEGGIO: 'ARPEGGIO',
};
});

const RESOURCES_TYPES = {
/**
* @name RESOURCES_TYPES
* @memberof Preferences
*/
const RESOURCES_TYPES = Object.freeze({
SCALE: 'SCALE',
ARPEGGIO: 'ARPEGGIO',
};
});

const INITIAL_PREFERENCES_STATE = {
/**
* @name INITIAL_PREFERENCES_STATE
* @memberof Preferences
*/
const INITIAL_PREFERENCES_STATE = Object.freeze({
repeat: true,
simpleRandom: false,
disableScreenSleep: false,
randomType: RANDOM_TYPES.SCALE,
resourcesType: RESOURCES_TYPES.SCALE,
advancedType: ADVANCED_TYPES.SCALE,
};
});

const ACTIONS = {
/**
* @name ACTIONS
* @memberof Preferences
*/
const ACTIONS = Object.freeze({
SET_ALL_PREFERENCES: 'SET_ALL_PREFERENCES',
SET_SETTING: 'SET_SETTING',
RESET_PREFERENCES: 'RESET_PREFERENCES',
};
});

/**
* @name STORAGE_KEY
* @memberof Preferences
*/
const STORAGE_KEY = 'preferences';

/**
* @function load
* @memberof Preferences
* @description Loads Data from Local Storage
* Created 12/11/20
* @copyright 2024 Alexander Burdiss
* @author Alexander Burdiss
* @since 12/11/20
* @version 1.0.2
* @since 12/28/24
* @version 1.0.3
* @param {string} type Type of data to load.
* @returns {JSON|null} The stored value or null, depending on if the data is
* successfully retrieved.
*/
export async function load() {
try {
const jsonValue = await AsyncStorage.getItem('preferences');
const jsonValue = await AsyncStorage.getItem(STORAGE_KEY);
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
console.log(e);
Expand All @@ -52,22 +87,29 @@ export async function load() {

/**
* @function save
* @memberof Preferences
* @description Stores Data in Local Storage
* Created 12/11/20
* @copyright 2024 Alexander Burdiss
* @author Alexander Burdiss
* @since 12/11/20
* @version 1.0.1
* @since 12/28/24
* @version 1.0.2
* @param {string} type Type of data to store.
* @param {Object} data Data to be stored in local storage
*/
export async function save(data) {
try {
const jsonValue = JSON.stringify(data);
await AsyncStorage.setItem('preferences', jsonValue);
await AsyncStorage.setItem(STORAGE_KEY, jsonValue);
} catch (e) {
console.log(e);
}
}

/**
* @name PreferencesContext
* @memberof Preferences
*/
const PreferencesContext = createContext();

PreferencesContext.advancedTypes = ADVANCED_TYPES;
Expand All @@ -77,6 +119,7 @@ PreferencesContext.actions = ACTIONS;

/**
* @function preferencesReducer
* @memberof Preferences
* @description A reducer that handles updating the state stored in context,
* and updates the same state in local storage on the device.
* @author Alexander Burdiss
Expand Down Expand Up @@ -105,11 +148,15 @@ const preferencesReducer = (state, action) => {
};

/**
* @function PreferencesProvider
* @memberof Preferences
* @description Provides the user preferences throughout the app.
* @author Alexander Burdiss
* @since 12/14/20
* @version 1.0.0
* @param {*} props
* @param {Object} props The JSX props passed to this React component
* @param {*} props.children React children to render inside this Provider
* @returns {JSX.Element} JSX render instructions
*
* @example
* <PreferencesProvider>
Expand Down
110 changes: 103 additions & 7 deletions src/Screens/Advanced/Advanced.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useContext, useEffect, useReducer } from 'react';
import { Alert, View, Text, FlatList } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

import {
AddToListButton,
Expand All @@ -21,18 +22,75 @@ import { translate } from '../../Translations/TranslationModel';

import { getIsSmallScreen, useIdleScreen, useDarkMode } from '../../utils';
import { getAdvancedReducer } from './utils/getAdvancedReducer';
import { StatisticsDispatchContext } from '../../Model/Statistics';

/**
* @namespace Advanced
* The namespace for the Advance screen and all its sub components and methods
*/

/**
* @name STORAGE_KEY
* @memberof Advanced
*/
const STORAGE_KEY = 'advanced';

/**
* @function load
* @memberof Advanced
* @description Loads Advanced reducer data from local storage
* @copyright 2024 Alexander Burdiss
* @author Alexander Burdiss
* @since 12/28/24
* @version 1.0.0
* @param {string} type Type of data to load.
* @returns {JSON|null} The stored value or null, depending on if the data is
* successfully retrieved.
*/
async function load() {
try {
const jsonValue = await AsyncStorage.getItem(STORAGE_KEY);
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
console.log(e);
}
}

/**
* @function save
* @memberof Advanced
* @description Stores Advanced reducer Data in Local Storage
* @copyright 2024 Alexander Burdiss
* @author Alexander Burdiss
* @since 12/28/24
* @version 1.0.0
* @param {string} type Type of data to store.
* @param {Object} data Data to be stored in local storage
*/
async function save(data) {
try {
const jsonValue = JSON.stringify(data);
await AsyncStorage.setItem(STORAGE_KEY, jsonValue);
} catch (e) {
console.log(e);
}
}

/**
* @function Advanced
* @memberof Advanced
* @description A view that allows the user to randomize between a list of
* selected scales.
* Created by Alexander Burdiss 10/10/20
* @copyright 2024 Alexander Burdiss
* @author Alexander Burdiss
* @since 10/15/22
* @version 3.1.0
* @since 12/28/24
* @version 3.2.0
*
* @example
* <Advanced />
*/
const AdvancedScale = () => {
export default function AdvancedScale() {
useIdleScreen();

const DARKMODE = useDarkMode();
Expand Down Expand Up @@ -94,8 +152,9 @@ const AdvancedScale = () => {
},
};
const { state } = useContext(PreferencesContext);
const dispatchStatistics = useContext(StatisticsDispatchContext);

const advancedReducer = getAdvancedReducer(state);
const advancedReducer = getAdvancedReducer(state, dispatchStatistics);
const ADVANCED_ACTIONS = advancedReducer.actions;
const [advancedState, dispatchAdvancedState] = useReducer(advancedReducer, {
...advancedReducer.initialState,
Expand All @@ -104,6 +163,45 @@ const AdvancedScale = () => {

const isScale = state?.advancedType == PreferencesContext.advancedTypes.SCALE;

useEffect(
function loadSavedState() {
load().then((data) => {
if (data !== null) {
const dataToSet = {};
if (data.possibleScales) {
dataToSet.possibleScales = data.possibleScales;
}
if (data.possibleArpeggios) {
dataToSet.possibleArpeggios = data.possibleArpeggios;
}

// Set loaded data to global store
dispatchAdvancedState({
type: ADVANCED_ACTIONS.SET_STATE_FROM_STORAGE,
payload: dataToSet,
});
}
});
},
[ADVANCED_ACTIONS.SET_STATE_FROM_STORAGE],
);

useEffect(
function saveUserSelections() {
if (advancedState) {
save({
possibleScales: advancedState.possibleScales,
possibleArpeggios: advancedState.possibleArpeggios,
});
}
},
[
advancedState,
advancedState?.possibleScales,
advancedState?.possibleArpeggios,
],
);

useEffect(
function handleStateChange() {
if (state) {
Expand Down Expand Up @@ -276,6 +374,4 @@ const AdvancedScale = () => {
)}
</View>
);
};

export default AdvancedScale;
}
Loading

0 comments on commit 56f5a64

Please sign in to comment.