Merge branch 'master' into unit-tests

This commit is contained in:
Brandon Presley 2023-01-01 13:57:01 +13:00
commit e43188ccdf
22 changed files with 207 additions and 169 deletions

View File

@ -1,10 +1,10 @@
import {ComponentProps, Ref} from 'react'
import React, {ComponentProps, Ref} from 'react'
import {TextInput} from 'react-native-paper'
import {CombinedDefaultTheme} from './App'
import {MARGIN} from './constants'
import useDark from './use-dark'
export default function AppInput(
function AppInput(
props: Partial<ComponentProps<typeof TextInput>> & {
innerRef?: Ref<any>
},
@ -14,7 +14,6 @@ export default function AppInput(
return (
<TextInput
selectionColor={dark ? '#2A2A2A' : CombinedDefaultTheme.colors.border}
mode="outlined"
style={{marginBottom: MARGIN, minWidth: 100}}
selectTextOnFocus
ref={props.innerRef}
@ -23,3 +22,5 @@ export default function AppInput(
/>
)
}
export default React.memo(AppInput)

View File

@ -80,9 +80,9 @@ export default function EditPlan() {
<Switch
key={day}
onChange={value => toggleDay(value, day)}
value={days.includes(day)}>
{day}
</Switch>
value={days.includes(day)}
title={day}
/>
))}
<Text style={[styles.title, {marginTop: MARGIN}]}>Workouts</Text>
{names.length === 0 ? (
@ -94,9 +94,9 @@ export default function EditPlan() {
<Switch
key={name}
onChange={value => toggleWorkout(value, name)}
value={workouts.includes(name)}>
{name}
</Switch>
value={workouts.includes(name)}
title={name}
/>
))
)}
</ScrollView>

View File

@ -162,7 +162,7 @@ export default function EditSet() {
<AppInput
label="Created"
disabled
value={format(new Date(set.created), settings.date)}
value={format(new Date(set.created), settings.date || 'P')}
/>
)}

View File

@ -44,7 +44,6 @@ export default function ListMenu({
}
const select = () => {
setShowMenu(false)
onSelect()
}

Binary file not shown.

View File

@ -1,6 +1,5 @@
import {createDrawerNavigator} from '@react-navigation/drawer'
import {useMemo} from 'react'
import {Platform} from 'react-native'
import {IconButton} from 'react-native-paper'
import BestPage from './BestPage'
import {DrawerParamList} from './drawer-param-list'
@ -36,22 +35,16 @@ export default function Routes() {
swipeEdgeWidth: 1000,
headerShown: false,
}}>
{}
{routes
.filter(route => {
if (Platform.OS === 'ios' && route.name === 'Timer') return false
return true
})
.map(route => (
<Drawer.Screen
key={route.name}
name={route.name}
component={route.component}
options={{
drawerIcon: () => <IconButton icon={route.icon} />,
}}
/>
))}
{routes.map(route => (
<Drawer.Screen
key={route.name}
name={route.name}
component={route.component}
options={{
drawerIcon: () => <IconButton icon={route.icon} />,
}}
/>
))}
</Drawer.Navigator>
)
}

View File

@ -1,4 +1,4 @@
import {useCallback, useMemo, useState} from 'react'
import React, {useCallback, useMemo, useState} from 'react'
import {View} from 'react-native'
import {Button, Menu, Subheading, useTheme} from 'react-native-paper'
import {ITEM_PADDING} from './constants'
@ -9,7 +9,7 @@ export interface Item {
color?: string
}
export default function Select({
function Select({
value,
onChange,
items,
@ -68,3 +68,5 @@ export default function Select({
</View>
)
}
export default React.memo(Select)

View File

@ -19,28 +19,32 @@ import Settings from './settings'
import Switch from './Switch'
import {toast} from './toast'
import {useTheme} from './use-theme'
import {useForm} from 'react-hook-form'
const defaultFormats = ['P', 'Pp', 'ccc p', 'p']
const twelveHours = ['P', 'Pp', 'ccc p', 'p', 'yyyy-MM-d', 'yyyy.MM.d']
const twentyFours = ['P', 'P, k:m', 'ccc k:m', 'k:m', 'yyyy-MM-d', 'yyyy.MM.d']
export default function SettingsPage() {
const [ignoring, setIgnoring] = useState(false)
const [term, setTerm] = useState('')
const [formatOptions, setFormatOptions] = useState<string[]>(defaultFormats)
const [formatOptions, setFormatOptions] = useState<string[]>(twelveHours)
const [importing, setImporting] = useState(false)
const [settings, setSettings] = useState(new Settings())
const {reset} = useNavigation<NavigationProp<DrawerParamList>>()
const today = new Date()
const {watch, setValue} = useForm<Settings>({
defaultValues: () => settingsRepo.findOne({where: {}}),
})
const settings = watch()
const {theme, setTheme, lightColor, setLightColor, darkColor, setDarkColor} =
useTheme()
useEffect(() => {
settingsRepo.findOne({where: {}}).then(setSettings)
NativeModules.SettingsModule.ignoringBattery(setIgnoring)
NativeModules.SettingsModule.is24().then((is24: boolean) => {
console.log(`${SettingsPage.name}.focus:`, {is24})
if (is24) setFormatOptions(['P', 'P, k:m', 'ccc k:m', 'k:m'])
else setFormatOptions(defaultFormats)
if (is24) setFormatOptions(twentyFours)
else setFormatOptions(twelveHours)
})
}, [])
@ -56,54 +60,34 @@ export default function SettingsPage() {
copyTo: 'documentDirectory',
})
if (!fileCopyUri) return
const updated = await settingsRepo.save({...settings, sound: fileCopyUri})
setSettings(updated)
setValue('sound', fileCopyUri)
await settingsRepo.save({...settings, sound: fileCopyUri})
toast('Sound will play after rest timers.')
}, [settings])
}, [settings, setValue])
const switches: Input<boolean>[] = [
{name: 'Rest timers', value: settings.alarm, key: 'alarm'},
{name: 'Vibrate', value: settings.vibrate, key: 'vibrate'},
{name: 'Disable sound', value: settings.noSound, key: 'noSound'},
{name: 'Notifications', value: settings.notify, key: 'notify'},
{name: 'Show images', value: settings.images, key: 'images'},
{name: 'Show unit', value: settings.showUnit, key: 'showUnit'},
{name: 'Show steps', value: settings.steps, key: 'steps'},
{name: 'Show date', value: settings.showDate, key: 'showDate'},
]
const switches: Input<boolean>[] = useMemo(
() => [
{name: 'Rest timers', value: settings.alarm, key: 'alarm'},
{name: 'Vibrate', value: settings.vibrate, key: 'vibrate'},
{name: 'Disable sound', value: settings.noSound, key: 'noSound'},
{name: 'Notifications', value: settings.notify, key: 'notify'},
{name: 'Show images', value: settings.images, key: 'images'},
{name: 'Show unit', value: settings.showUnit, key: 'showUnit'},
{name: 'Show steps', value: settings.steps, key: 'steps'},
{name: 'Show date', value: settings.showDate, key: 'showDate'},
],
[settings],
)
const changeString = useCallback(
async (key: keyof Settings, value: string) => {
const updated = await settingsRepo.save({...settings, [key]: value})
setSettings(updated)
switch (key) {
case 'date':
return toast('Changed date format')
case 'darkColor':
setDarkColor(value)
return toast('Set primary color for dark mode.')
case 'lightColor':
setLightColor(value)
return toast('Set primary color for light mode.')
case 'vibrate':
return toast('Set primary color for light mode.')
case 'sound':
return toast('Sound will play after rest timers.')
case 'theme':
setTheme(value as string)
if (value === 'dark') toast('Theme will always be dark.')
else if (value === 'light') toast('Theme will always be light.')
else if (value === 'system') toast('Theme will follow system.')
return
}
},
[settings, setTheme, setDarkColor, setLightColor],
const filter = useCallback(
({name}) => name.toLowerCase().includes(term.toLowerCase()),
[term],
)
const changeBoolean = useCallback(
async (key: keyof Settings, value: boolean) => {
const updated = await settingsRepo.save({...settings, [key]: value})
setSettings(updated)
setValue(key, value)
await settingsRepo.save({...settings, [key]: value})
switch (key) {
case 'alarm':
if (value) toast('Timers will now run after each set.')
@ -140,7 +124,7 @@ export default function SettingsPage() {
return
}
},
[settings, ignoring],
[settings, ignoring, setValue],
)
const renderSwitch = useCallback(
@ -148,37 +132,73 @@ export default function SettingsPage() {
<Switch
key={item.name}
value={item.value}
onChange={value => changeBoolean(item.key, value)}>
{item.name}
</Switch>
onChange={value => changeBoolean(item.key, value)}
title={item.name}
/>
),
[changeBoolean],
)
const selects: Input<string>[] = [
{name: 'Theme', value: theme, items: themeOptions, key: 'theme'},
{
name: 'Dark color',
value: darkColor,
items: lightOptions,
key: 'darkColor',
const switchesMarkup = useMemo(
() => switches.filter(filter).map(s => renderSwitch(s)),
[filter, switches, renderSwitch],
)
const changeString = useCallback(
async (key: keyof Settings, value: string) => {
setValue(key, value)
await settingsRepo.save({...settings, [key]: value})
switch (key) {
case 'date':
return toast('Changed date format')
case 'darkColor':
setDarkColor(value)
return toast('Set primary color for dark mode.')
case 'lightColor':
setLightColor(value)
return toast('Set primary color for light mode.')
case 'vibrate':
return toast('Set primary color for light mode.')
case 'sound':
return toast('Sound will play after rest timers.')
case 'theme':
setTheme(value as string)
if (value === 'dark') toast('Theme will always be dark.')
else if (value === 'light') toast('Theme will always be light.')
else if (value === 'system') toast('Theme will follow system.')
return
}
},
{
name: 'Light color',
value: lightColor,
items: darkOptions,
key: 'lightColor',
},
{
name: 'Date format',
value: settings.date,
items: formatOptions.map(option => ({
label: format(today, option),
value: option,
})),
key: 'date',
},
]
[settings, setTheme, setDarkColor, setLightColor, setValue],
)
const selects: Input<string>[] = useMemo(() => {
const today = new Date()
return [
{name: 'Theme', value: theme, items: themeOptions, key: 'theme'},
{
name: 'Dark color',
value: darkColor,
items: lightOptions,
key: 'darkColor',
},
{
name: 'Light color',
value: lightColor,
items: darkOptions,
key: 'lightColor',
},
{
name: 'Date format',
value: settings.date,
items: formatOptions.map(option => ({
label: format(today, option),
value: option,
})),
key: 'date',
},
]
}, [settings.date, darkColor, formatOptions, theme, lightColor])
const renderSelect = useCallback(
(item: Input<string>) => (
@ -193,6 +213,11 @@ export default function SettingsPage() {
[changeString],
)
const selectsMarkup = useMemo(
() => selects.filter(filter).map(renderSelect),
[filter, selects, renderSelect],
)
const confirmImport = useCallback(async () => {
setImporting(false)
await AppDataSource.destroy()
@ -215,47 +240,51 @@ export default function SettingsPage() {
}, [])
const buttons = useMemo(
() =>
[
{
name: 'Alarm sound',
element: (
<View
key="alarm-sound"
style={{
flexDirection: 'row',
alignItems: 'center',
paddingLeft: ITEM_PADDING,
}}>
<Subheading style={{width: 100}}>Alarm sound</Subheading>
<Button onPress={changeSound}>{soundString || 'Default'}</Button>
</View>
),
},
{
name: 'Export database',
element: (
<Button
key="export-db"
style={{alignSelf: 'flex-start'}}
onPress={exportDatabase}>
Export database
</Button>
),
},
{
name: 'Import database',
element: (
<Button
key="import-db"
style={{alignSelf: 'flex-start'}}
onPress={() => setImporting(true)}>
Import database
</Button>
),
},
].filter(({name}) => name.toLowerCase().includes(term.toLowerCase())),
[changeSound, exportDatabase, soundString, term],
() => [
{
name: 'Alarm sound',
element: (
<View
key="alarm-sound"
style={{
flexDirection: 'row',
alignItems: 'center',
paddingLeft: ITEM_PADDING,
}}>
<Subheading style={{width: 100}}>Alarm sound</Subheading>
<Button onPress={changeSound}>{soundString || 'Default'}</Button>
</View>
),
},
{
name: 'Export database',
element: (
<Button
key="export-db"
style={{alignSelf: 'flex-start'}}
onPress={exportDatabase}>
Export database
</Button>
),
},
{
name: 'Import database',
element: (
<Button
key="import-db"
style={{alignSelf: 'flex-start'}}
onPress={() => setImporting(true)}>
Import database
</Button>
),
},
],
[changeSound, exportDatabase, soundString],
)
const buttonsMarkup = useMemo(
() => buttons.filter(filter).map(b => b.element),
[buttons, filter],
)
return (
@ -264,9 +293,9 @@ export default function SettingsPage() {
<Page term={term} search={setTerm} style={{flexGrow: 0}}>
<View style={{marginTop: MARGIN}}>
{switches.map(s => renderSwitch(s))}
{selects.map(s => renderSelect(s))}
{buttons.map(b => b.element)}
{switchesMarkup}
{selectsMarkup}
{buttonsMarkup}
</View>
</Page>

View File

@ -1,15 +1,16 @@
import React from 'react'
import {Platform, Pressable} from 'react-native'
import {Switch as PaperSwitch, Text, useTheme} from 'react-native-paper'
import {MARGIN} from './constants'
export default function Switch({
function Switch({
value,
onChange,
children,
title,
}: {
value?: boolean
onChange: (value: boolean) => void
children: string
title: string
}) {
const {colors} = useTheme()
@ -29,7 +30,9 @@ export default function Switch({
onValueChange={onChange}
trackColor={{true: colors.primary + '80', false: colors.disabled}}
/>
<Text>{children}</Text>
<Text>{title}</Text>
</Pressable>
)
}
export default React.memo(Switch)

View File

@ -8,16 +8,16 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.657.0)
aws-sdk-core (3.166.0)
aws-partitions (1.686.0)
aws-sdk-core (3.168.4)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.59.0)
aws-sdk-kms (1.61.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.117.1)
aws-sdk-s3 (1.117.2)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
@ -36,7 +36,7 @@ GEM
unf (>= 0.0.5, < 1.0.0)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.93.1)
excon (0.95.0)
faraday (1.10.2)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.6)
fastlane (2.210.1)
fastlane (2.211.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@ -106,9 +106,9 @@ GEM
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.31.0)
google-apis-androidpublisher_v3 (0.32.0)
google-apis-core (>= 0.9.1, < 2.a)
google-apis-core (0.9.1)
google-apis-core (0.9.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@ -148,11 +148,11 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
jmespath (1.6.1)
json (2.6.2)
jwt (2.5.0)
jmespath (1.6.2)
json (2.6.3)
jwt (2.6.0)
memoist (0.16.2)
mini_magick (4.11.0)
mini_magick (4.12.0)
mini_mime (1.1.2)
multi_json (1.15.0)
multipart-post (2.0.0)
@ -161,7 +161,7 @@ GEM
optparse (0.1.1)
os (1.1.4)
plist (3.6.0)
public_suffix (5.0.0)
public_suffix (5.0.1)
rake (13.0.6)
representable (3.2.0)
declarative (< 0.1.0)

View File

@ -41,8 +41,8 @@ android {
missingDimensionStrategy "RNNotifications.reactNativeVersion", "reactNative60"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 36128
versionName "1.102"
versionCode 36133
versionName "1.107"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
if (isNewArchitectureEnabled()) {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 123 KiB

View File

@ -1,6 +1,6 @@
{
"name": "massive",
"version": "1.102",
"version": "1.107",
"private": true,
"license": "GPL-3.0-only",
"scripts": {
@ -30,6 +30,7 @@
"eslint-plugin-flowtype": "^8.0.3",
"jest": "^29.2.2",
"react": "^18.2.0",
"react-hook-form": "^7.41.2",
"react-native": "^0.70.5",
"react-native-document-picker": "^8.1.2",
"react-native-file-access": "^2.5.0",

View File

@ -7295,6 +7295,7 @@ __metadata:
jest: ^29.2.2
metro-react-native-babel-preset: ^0.73.3
react: ^18.2.0
react-hook-form: ^7.41.2
react-native: ^0.70.5
react-native-document-picker: ^8.1.2
react-native-file-access: ^2.5.0
@ -8752,6 +8753,15 @@ __metadata:
languageName: node
linkType: hard
"react-hook-form@npm:^7.41.2":
version: 7.41.2
resolution: "react-hook-form@npm:7.41.2"
peerDependencies:
react: ^16.8.0 || ^17 || ^18
checksum: bc923b74018d55289838f820d49e32043dbc683d97ea2f93a6f3b75ff58fea9ee4536d6487adcb02912b4bc90a09ea07a63c4c24f930ec59f598bdafd5e8c8d3
languageName: node
linkType: hard
"react-is@npm:^16.12.0 || ^17.0.0 || ^18.0.0, react-is@npm:^18.0.0, react-is@npm:^18.2.0":
version: 18.2.0
resolution: "react-is@npm:18.2.0"