parent
794504dee0
commit
b0b804eae1
|
@ -10,12 +10,13 @@ import {getBestReps, getBestWeights} from './best.service';
|
||||||
import {BestPageParams} from './BestPage';
|
import {BestPageParams} from './BestPage';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {settings} from './settings.service';
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
export default function BestList() {
|
export default function BestList() {
|
||||||
const [bests, setBests] = useState<Set[]>([]);
|
const [bests, setBests] = useState<Set[]>([]);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const navigation = useNavigation<NavigationProp<BestPageParams>>();
|
const navigation = useNavigation<NavigationProp<BestPageParams>>();
|
||||||
|
const {settings} = useSettings();
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
const refresh = useCallback(async () => {
|
||||||
const weights = await getBestWeights(search);
|
const weights = await getBestWeights(search);
|
||||||
|
|
39
EditSet.tsx
39
EditSet.tsx
|
@ -13,13 +13,15 @@ import {SnackbarContext} from './MassiveSnack';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {addSet, updateSet} from './set.service';
|
import {addSet, updateSet} from './set.service';
|
||||||
import SetForm from './SetForm';
|
import SetForm from './SetForm';
|
||||||
import {getSettings, settings, updateSettings} from './settings.service';
|
import {getSettings, updateSettings} from './settings.service';
|
||||||
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
export default function EditSet() {
|
export default function EditSet() {
|
||||||
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
|
const {params} = useRoute<RouteProp<HomePageParams, 'EditSet'>>();
|
||||||
const {set, count, workouts} = params;
|
const {set, count, workouts} = params;
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const {toast} = useContext(SnackbarContext);
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
const {settings, setSettings} = useSettings();
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
|
@ -35,23 +37,26 @@ export default function EditSet() {
|
||||||
headerRight: null,
|
headerRight: null,
|
||||||
title,
|
title,
|
||||||
});
|
});
|
||||||
}, [navigation, set, count]),
|
}, [navigation, set, count, settings.newSet]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const startTimer = useCallback(async (value: Set) => {
|
const startTimer = useCallback(
|
||||||
if (!settings.alarm) return;
|
async (value: Set) => {
|
||||||
const milliseconds =
|
if (!settings.alarm) return;
|
||||||
Number(value.minutes) * 60 * 1000 + Number(value.seconds) * 1000;
|
const milliseconds =
|
||||||
NativeModules.AlarmModule.timer(
|
Number(value.minutes) * 60 * 1000 + Number(value.seconds) * 1000;
|
||||||
milliseconds,
|
NativeModules.AlarmModule.timer(
|
||||||
!!settings.vibrate,
|
milliseconds,
|
||||||
settings.sound,
|
!!settings.vibrate,
|
||||||
);
|
settings.sound,
|
||||||
const next = new Date();
|
);
|
||||||
next.setTime(next.getTime() + milliseconds);
|
const next = new Date();
|
||||||
await updateSettings({...settings, nextAlarm: next.toISOString()});
|
next.setTime(next.getTime() + milliseconds);
|
||||||
await getSettings();
|
await updateSettings({...settings, nextAlarm: next.toISOString()});
|
||||||
}, []);
|
setSettings(await getSettings());
|
||||||
|
},
|
||||||
|
[settings, setSettings],
|
||||||
|
);
|
||||||
|
|
||||||
const update = useCallback(
|
const update = useCallback(
|
||||||
async (value: Set) => {
|
async (value: Set) => {
|
||||||
|
@ -75,7 +80,7 @@ export default function EditSet() {
|
||||||
toast("Great work King, that's a new record!", 3000);
|
toast("Great work King, that's a new record!", 3000);
|
||||||
navigation.goBack();
|
navigation.goBack();
|
||||||
},
|
},
|
||||||
[navigation, startTimer, set, toast],
|
[navigation, startTimer, set, toast, settings],
|
||||||
);
|
);
|
||||||
|
|
||||||
const save = useCallback(
|
const save = useCallback(
|
||||||
|
|
|
@ -14,7 +14,7 @@ import MassiveInput from './MassiveInput';
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import {updatePlanWorkouts} from './plan.service';
|
import {updatePlanWorkouts} from './plan.service';
|
||||||
import {addSet, updateManySet, updateSetImage} from './set.service';
|
import {addSet, updateManySet, updateSetImage} from './set.service';
|
||||||
import {settings} from './settings.service';
|
import {useSettings} from './use-settings';
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
import {WorkoutsPageParams} from './WorkoutsPage';
|
||||||
|
|
||||||
export default function EditWorkout() {
|
export default function EditWorkout() {
|
||||||
|
@ -37,6 +37,7 @@ export default function EditWorkout() {
|
||||||
const stepsRef = useRef<TextInput>(null);
|
const stepsRef = useRef<TextInput>(null);
|
||||||
const minutesRef = useRef<TextInput>(null);
|
const minutesRef = useRef<TextInput>(null);
|
||||||
const secondsRef = useRef<TextInput>(null);
|
const secondsRef = useRef<TextInput>(null);
|
||||||
|
const {settings} = useSettings();
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
|
|
53
Routes.tsx
53
Routes.tsx
|
@ -9,27 +9,28 @@ import {DrawerParamList} from './drawer-param-list';
|
||||||
import HomePage from './HomePage';
|
import HomePage from './HomePage';
|
||||||
import PlanPage from './PlanPage';
|
import PlanPage from './PlanPage';
|
||||||
import Route from './route';
|
import Route from './route';
|
||||||
import {getSettings, settings} from './settings.service';
|
import Settings from './settings';
|
||||||
|
import {getSettings} from './settings.service';
|
||||||
import SettingsPage from './SettingsPage';
|
import SettingsPage from './SettingsPage';
|
||||||
|
import {SettingsContext} from './use-settings';
|
||||||
import WorkoutsPage from './WorkoutsPage';
|
import WorkoutsPage from './WorkoutsPage';
|
||||||
|
|
||||||
const Drawer = createDrawerNavigator<DrawerParamList>();
|
const Drawer = createDrawerNavigator<DrawerParamList>();
|
||||||
|
|
||||||
export default function Routes() {
|
export default function Routes() {
|
||||||
const [migrated, setMigrated] = useState(false);
|
const [settings, setSettings] = useState<Settings>();
|
||||||
const dark = useColorScheme() === 'dark';
|
const dark = useColorScheme() === 'dark';
|
||||||
const {setColor} = useContext(CustomTheme);
|
const {setColor} = useContext(CustomTheme);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
runMigrations()
|
runMigrations().then(async () => {
|
||||||
.then(getSettings)
|
const gotSettings = await getSettings();
|
||||||
.then(() => {
|
setSettings(gotSettings);
|
||||||
setMigrated(true);
|
if (gotSettings.color) setColor(gotSettings.color);
|
||||||
if (settings.color) setColor(settings.color);
|
});
|
||||||
});
|
|
||||||
}, [setColor]);
|
}, [setColor]);
|
||||||
|
|
||||||
if (!migrated) return null;
|
if (!settings) return null;
|
||||||
|
|
||||||
const routes: Route[] = [
|
const routes: Route[] = [
|
||||||
{name: 'Home', component: HomePage, icon: 'home'},
|
{name: 'Home', component: HomePage, icon: 'home'},
|
||||||
|
@ -40,21 +41,23 @@ export default function Routes() {
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer.Navigator
|
<SettingsContext.Provider value={{settings, setSettings}}>
|
||||||
screenOptions={{
|
<Drawer.Navigator
|
||||||
headerTintColor: dark ? 'white' : 'black',
|
screenOptions={{
|
||||||
swipeEdgeWidth: 1000,
|
headerTintColor: dark ? 'white' : 'black',
|
||||||
}}>
|
swipeEdgeWidth: 1000,
|
||||||
{routes.map(route => (
|
}}>
|
||||||
<Drawer.Screen
|
{routes.map(route => (
|
||||||
key={route.name}
|
<Drawer.Screen
|
||||||
name={route.name}
|
key={route.name}
|
||||||
component={route.component}
|
name={route.name}
|
||||||
options={{
|
component={route.component}
|
||||||
drawerIcon: () => <IconButton icon={route.icon} />,
|
options={{
|
||||||
}}
|
drawerIcon: () => <IconButton icon={route.icon} />,
|
||||||
/>
|
}}
|
||||||
))}
|
/>
|
||||||
</Drawer.Navigator>
|
))}
|
||||||
|
</Drawer.Navigator>
|
||||||
|
</SettingsContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ import MassiveInput from './MassiveInput';
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {getSets} from './set.service';
|
import {getSets} from './set.service';
|
||||||
import {settings} from './settings.service';
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
export default function SetForm({
|
export default function SetForm({
|
||||||
save,
|
save,
|
||||||
|
@ -31,6 +31,7 @@ export default function SetForm({
|
||||||
});
|
});
|
||||||
const [removeImage, setRemoveImage] = useState(false);
|
const [removeImage, setRemoveImage] = useState(false);
|
||||||
const {toast} = useContext(SnackbarContext);
|
const {toast} = useContext(SnackbarContext);
|
||||||
|
const {settings} = useSettings();
|
||||||
const weightRef = useRef<TextInput>(null);
|
const weightRef = useRef<TextInput>(null);
|
||||||
const repsRef = useRef<TextInput>(null);
|
const repsRef = useRef<TextInput>(null);
|
||||||
const unitRef = useRef<TextInput>(null);
|
const unitRef = useRef<TextInput>(null);
|
||||||
|
|
14
SetItem.tsx
14
SetItem.tsx
|
@ -5,24 +5,22 @@ import {Divider, List, Menu, Text} from 'react-native-paper';
|
||||||
import {HomePageParams} from './home-page-params';
|
import {HomePageParams} from './home-page-params';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {deleteSet} from './set.service';
|
import {deleteSet} from './set.service';
|
||||||
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
export default function SetItem({
|
export default function SetItem({
|
||||||
item,
|
item,
|
||||||
onRemove,
|
onRemove,
|
||||||
dates,
|
dates,
|
||||||
setDates,
|
setDates,
|
||||||
images,
|
|
||||||
setImages,
|
|
||||||
}: {
|
}: {
|
||||||
item: Set;
|
item: Set;
|
||||||
onRemove: () => void;
|
onRemove: () => void;
|
||||||
dates: boolean;
|
dates: boolean;
|
||||||
setDates: (value: boolean) => void;
|
setDates: (value: boolean) => void;
|
||||||
images: boolean;
|
|
||||||
setImages: (value: boolean) => void;
|
|
||||||
}) {
|
}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
|
const {settings} = useSettings();
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
|
@ -51,11 +49,6 @@ export default function SetItem({
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
}, [dates, setDates]);
|
}, [dates, setDates]);
|
||||||
|
|
||||||
const toggleImages = useCallback(() => {
|
|
||||||
setImages(!images);
|
|
||||||
setShowMenu(false);
|
|
||||||
}, [images, setImages]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<List.Item
|
<List.Item
|
||||||
|
@ -66,7 +59,7 @@ export default function SetItem({
|
||||||
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
description={`${item.reps} x ${item.weight}${item.unit || 'kg'}`}
|
||||||
onLongPress={longPress}
|
onLongPress={longPress}
|
||||||
left={() =>
|
left={() =>
|
||||||
images &&
|
!!settings.images &&
|
||||||
item.image && (
|
item.image && (
|
||||||
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
||||||
)
|
)
|
||||||
|
@ -86,7 +79,6 @@ export default function SetItem({
|
||||||
visible={showMenu}
|
visible={showMenu}
|
||||||
onDismiss={() => setShowMenu(false)}>
|
onDismiss={() => setShowMenu(false)}>
|
||||||
<Menu.Item icon="content-copy" onPress={copy} title="Copy" />
|
<Menu.Item icon="content-copy" onPress={copy} title="Copy" />
|
||||||
<Menu.Item icon="image" onPress={toggleImages} title="Images" />
|
|
||||||
<Menu.Item icon="event" onPress={toggleDates} title="Dates" />
|
<Menu.Item icon="event" onPress={toggleDates} title="Dates" />
|
||||||
<Divider />
|
<Divider />
|
||||||
<Menu.Item icon="delete" onPress={remove} title="Delete" />
|
<Menu.Item icon="delete" onPress={remove} title="Delete" />
|
||||||
|
|
11
SetList.tsx
11
SetList.tsx
|
@ -14,7 +14,7 @@ import {getTodaysPlan} from './plan.service';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {countToday, defaultSet, getSets, getToday} from './set.service';
|
import {countToday, defaultSet, getSets, getToday} from './set.service';
|
||||||
import SetItem from './SetItem';
|
import SetItem from './SetItem';
|
||||||
import {settings} from './settings.service';
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
const limit = 15;
|
const limit = 15;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ export default function SetList() {
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
const [end, setEnd] = useState(false);
|
const [end, setEnd] = useState(false);
|
||||||
const [dates, setDates] = useState(false);
|
const [dates, setDates] = useState(false);
|
||||||
const [images, setImages] = useState(true);
|
const {settings} = useSettings();
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
||||||
|
|
||||||
const predict = useCallback(async () => {
|
const predict = useCallback(async () => {
|
||||||
|
@ -62,7 +62,7 @@ export default function SetList() {
|
||||||
if (best.name === '') setCount(0);
|
if (best.name === '') setCount(0);
|
||||||
else setCount(_count);
|
else setCount(_count);
|
||||||
setSet({...best, image});
|
setSet({...best, image});
|
||||||
}, []);
|
}, [settings]);
|
||||||
|
|
||||||
const refresh = useCallback(async () => {
|
const refresh = useCallback(async () => {
|
||||||
predict();
|
predict();
|
||||||
|
@ -80,7 +80,6 @@ export default function SetList() {
|
||||||
navigation.getParent()?.setOptions({
|
navigation.getParent()?.setOptions({
|
||||||
headerRight: () => <DrawerMenu name="Home" />,
|
headerRight: () => <DrawerMenu name="Home" />,
|
||||||
});
|
});
|
||||||
setImages(!!settings.images);
|
|
||||||
}, [refresh, navigation]),
|
}, [refresh, navigation]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -93,14 +92,12 @@ export default function SetList() {
|
||||||
<SetItem
|
<SetItem
|
||||||
dates={dates}
|
dates={dates}
|
||||||
setDates={setDates}
|
setDates={setDates}
|
||||||
images={images}
|
|
||||||
setImages={setImages}
|
|
||||||
item={item}
|
item={item}
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onRemove={refresh}
|
onRemove={refresh}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[refresh, dates, setDates, images, setImages],
|
[refresh, dates, setDates],
|
||||||
);
|
);
|
||||||
|
|
||||||
const next = useCallback(async () => {
|
const next = useCallback(async () => {
|
||||||
|
|
|
@ -11,13 +11,15 @@ import {MARGIN} from './constants';
|
||||||
import Input from './input';
|
import Input from './input';
|
||||||
import {SnackbarContext} from './MassiveSnack';
|
import {SnackbarContext} from './MassiveSnack';
|
||||||
import Page from './Page';
|
import Page from './Page';
|
||||||
import {getSettings, settings, updateSettings} from './settings.service';
|
import {getSettings, updateSettings} from './settings.service';
|
||||||
import Switch from './Switch';
|
import Switch from './Switch';
|
||||||
|
import {useSettings} from './use-settings';
|
||||||
|
|
||||||
export default function SettingsPage() {
|
export default function SettingsPage() {
|
||||||
const [battery, setBattery] = useState(false);
|
const [battery, setBattery] = useState(false);
|
||||||
const [ignoring, setIgnoring] = useState(false);
|
const [ignoring, setIgnoring] = useState(false);
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
|
const {settings, setSettings} = useSettings();
|
||||||
const [vibrate, setVibrate] = useState(!!settings.vibrate);
|
const [vibrate, setVibrate] = useState(!!settings.vibrate);
|
||||||
const [alarm, setAlarm] = useState(!!settings.alarm);
|
const [alarm, setAlarm] = useState(!!settings.alarm);
|
||||||
const [newSet, setNewSet] = useState(settings.newSet);
|
const [newSet, setNewSet] = useState(settings.newSet);
|
||||||
|
@ -49,7 +51,7 @@ export default function SettingsPage() {
|
||||||
workouts: +workouts,
|
workouts: +workouts,
|
||||||
steps: +steps,
|
steps: +steps,
|
||||||
});
|
});
|
||||||
getSettings();
|
getSettings().then(setSettings);
|
||||||
}, [
|
}, [
|
||||||
vibrate,
|
vibrate,
|
||||||
alarm,
|
alarm,
|
||||||
|
@ -61,6 +63,7 @@ export default function SettingsPage() {
|
||||||
color,
|
color,
|
||||||
workouts,
|
workouts,
|
||||||
steps,
|
steps,
|
||||||
|
setSettings,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const changeAlarmEnabled = useCallback(
|
const changeAlarmEnabled = useCallback(
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {List, Menu, Text} from 'react-native-paper';
|
||||||
import ConfirmDialog from './ConfirmDialog';
|
import ConfirmDialog from './ConfirmDialog';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {deleteSetsBy} from './set.service';
|
import {deleteSetsBy} from './set.service';
|
||||||
|
import {useSettings} from './use-settings';
|
||||||
import {WorkoutsPageParams} from './WorkoutsPage';
|
import {WorkoutsPageParams} from './WorkoutsPage';
|
||||||
|
|
||||||
export default function WorkoutItem({
|
export default function WorkoutItem({
|
||||||
|
@ -17,6 +18,7 @@ export default function WorkoutItem({
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
const [showRemove, setShowRemove] = useState('');
|
const [showRemove, setShowRemove] = useState('');
|
||||||
|
const {settings} = useSettings();
|
||||||
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
const navigation = useNavigation<NavigationProp<WorkoutsPageParams>>();
|
||||||
|
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
|
@ -44,6 +46,7 @@ export default function WorkoutItem({
|
||||||
description={`${item.sets} sets ${minutes}:${seconds} rest`}
|
description={`${item.sets} sets ${minutes}:${seconds} rest`}
|
||||||
onLongPress={longPress}
|
onLongPress={longPress}
|
||||||
left={() =>
|
left={() =>
|
||||||
|
!!settings.images &&
|
||||||
item.image && (
|
item.image && (
|
||||||
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
<Image source={{uri: item.image}} style={{height: 75, width: 75}} />
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
import {db} from './db';
|
import {db} from './db';
|
||||||
import Settings from './settings';
|
import Settings from './settings';
|
||||||
|
|
||||||
export let settings: Settings;
|
export const getSettings = async (): Promise<Settings> => {
|
||||||
|
|
||||||
export const getSettings = async () => {
|
|
||||||
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
|
const [result] = await db.executeSql(`SELECT * FROM settings LIMIT 1`);
|
||||||
settings = result.rows.item(0);
|
return result.rows.item(0);
|
||||||
return settings;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateSettings = async (value: Settings) => {
|
export const updateSettings = async (value: Settings) => {
|
||||||
|
|
|
@ -8,6 +8,6 @@ export default interface Settings {
|
||||||
showUnit?: number;
|
showUnit?: number;
|
||||||
color?: string;
|
color?: string;
|
||||||
workouts: number;
|
workouts: number;
|
||||||
steps: number;
|
|
||||||
nextAlarm?: string;
|
nextAlarm?: string;
|
||||||
|
steps?: number;
|
||||||
}
|
}
|
||||||
|
|
18
use-settings.ts
Normal file
18
use-settings.ts
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
import React, {useContext} from 'react';
|
||||||
|
import Settings from './settings';
|
||||||
|
|
||||||
|
export const SettingsContext = React.createContext<{
|
||||||
|
settings: Settings;
|
||||||
|
setSettings: (value: Settings) => void;
|
||||||
|
}>({
|
||||||
|
settings: {
|
||||||
|
alarm: 0,
|
||||||
|
vibrate: 1,
|
||||||
|
workouts: 0,
|
||||||
|
},
|
||||||
|
setSettings: () => null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useSettings() {
|
||||||
|
return useContext(SettingsContext);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user