mirror of
https://github.com/morten-olsen/bob-the-algorithm.git
synced 2026-02-08 00:46:25 +01:00
update
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Context, GraphNode } from "#/types/graph";
|
import { Context, GraphNode } from "#/types/graph";
|
||||||
import { UserLocation } from "#/types/location";
|
import { UserLocation } from "#/types/location";
|
||||||
import { Task } from "#/types/task";
|
import { Task } from "#/types/task";
|
||||||
import { getNext } from "./get-next";
|
import { getImpossible, getNext } from "./get-next";
|
||||||
|
|
||||||
enum Strategies {
|
enum Strategies {
|
||||||
all = 'all',
|
all = 'all',
|
||||||
@@ -13,6 +13,7 @@ type RunningStatus = {
|
|||||||
current: 'running';
|
current: 'running';
|
||||||
nodes: number;
|
nodes: number;
|
||||||
start: Date;
|
start: Date;
|
||||||
|
strategy: Strategies,
|
||||||
cancel: () => void;
|
cancel: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ type CompletedStatus = {
|
|||||||
start: Date;
|
start: Date;
|
||||||
end: Date;
|
end: Date;
|
||||||
nodes: number;
|
nodes: number;
|
||||||
|
strategy: Strategies,
|
||||||
}
|
}
|
||||||
|
|
||||||
type Status = RunningStatus | CompletedStatus;
|
type Status = RunningStatus | CompletedStatus;
|
||||||
@@ -65,38 +67,62 @@ const buildGraph = async ({
|
|||||||
sleepTime = 10,
|
sleepTime = 10,
|
||||||
}: BuildGraphOptions) => {
|
}: BuildGraphOptions) => {
|
||||||
const start = new Date();
|
const start = new Date();
|
||||||
let leafs: GraphNode[] = [{
|
let nodeCount = 0;
|
||||||
|
let running = true;
|
||||||
|
const { remaining, impossible } = getImpossible(tasks, time);
|
||||||
|
let leafList: GraphNode[] = [{
|
||||||
location,
|
location,
|
||||||
time: {
|
time: {
|
||||||
end: time,
|
end: time,
|
||||||
start: time,
|
start: time,
|
||||||
},
|
},
|
||||||
score: 0,
|
score: 0,
|
||||||
remainingTasks: tasks,
|
remainingTasks: remaining,
|
||||||
impossibeTasks: [],
|
impossibeTasks: impossible,
|
||||||
status: {
|
status: {
|
||||||
dead: false,
|
dead: false,
|
||||||
completed: false,
|
completed: false,
|
||||||
},
|
},
|
||||||
}];
|
}];
|
||||||
let nodes = 0;
|
const completedList: GraphNode[] = [];
|
||||||
let running = true;
|
const deadList: GraphNode[] = [];
|
||||||
const final: GraphNode[] = [];
|
|
||||||
|
const complete = (nodes: GraphNode[]) => {
|
||||||
|
if (callback) {
|
||||||
|
callback({
|
||||||
|
current: 'completed',
|
||||||
|
nodes: nodeCount,
|
||||||
|
start,
|
||||||
|
end: new Date(),
|
||||||
|
strategy,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return nodes.sort((a, b) => b.score - a.score);
|
||||||
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
nodes++;
|
nodeCount++;
|
||||||
if (!running) {
|
if (!running) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
const node = leafs.pop();
|
if (
|
||||||
|
leafList.length === 0
|
||||||
|
&& completedList.length === 0
|
||||||
|
&& strategy !== Strategies.all
|
||||||
|
) {
|
||||||
|
strategy = Strategies.all;
|
||||||
|
leafList.push(...deadList);
|
||||||
|
}
|
||||||
|
const node = leafList.pop();
|
||||||
if (!node) {
|
if (!node) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nodes % batchSize === 1) {
|
if (nodeCount % batchSize === 0) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback({
|
callback({
|
||||||
current: 'running',
|
current: 'running',
|
||||||
nodes,
|
nodes: nodeCount,
|
||||||
|
strategy,
|
||||||
start,
|
start,
|
||||||
cancel: () => {
|
cancel: () => {
|
||||||
running = false;
|
running = false;
|
||||||
@@ -106,38 +132,28 @@ const buildGraph = async ({
|
|||||||
await sleep(sleepTime);
|
await sleep(sleepTime);
|
||||||
}
|
}
|
||||||
const next = await getNext(node, context);
|
const next = await getNext(node, context);
|
||||||
const [alive, completed] = fil([
|
const [alive, completed, dead] = fil([
|
||||||
n => !n.status.dead && !n.status.completed,
|
n => (strategy === Strategies.all || !n.status.dead) && !n.status.completed,
|
||||||
n => !!n.status.completed && !n.status.dead
|
n => !!n.status.completed && (strategy === Strategies.all || !n.status.dead),
|
||||||
|
n => n.status.dead,
|
||||||
], next);
|
], next);
|
||||||
leafs.push(...alive);
|
leafList.push(...alive);
|
||||||
if (strategy === Strategies.firstValid && completed.length > 0) {
|
if (strategy === Strategies.firstValid && completed.length > 0) {
|
||||||
if (callback) {
|
return complete(completed);
|
||||||
callback({ current: 'completed', nodes, start, end: new Date() })
|
|
||||||
}
|
|
||||||
return completed;
|
|
||||||
}
|
}
|
||||||
if (completed.length > 0) {
|
if (completed.length > 0) {
|
||||||
final.push(...completed)
|
completedList.push(...completed)
|
||||||
}
|
}
|
||||||
if (strategy === Strategies.firstComplet) {
|
if (strategy === Strategies.firstComplet) {
|
||||||
const fullComplete = completed.find(c => c.impossibeTasks.length === 0);
|
const fullComplete = completed.find(c => c.impossibeTasks.length === 0);
|
||||||
if (fullComplete) {
|
if (fullComplete) {
|
||||||
if (callback) {
|
return complete([fullComplete]);
|
||||||
callback({ current: 'completed', nodes, start, end: new Date() })
|
|
||||||
}
|
|
||||||
return [fullComplete];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
deadList.push(...dead);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('nodes', nodes);
|
return complete(completedList);
|
||||||
if (callback) {
|
|
||||||
callback({ current: 'completed', nodes, start, end: new Date() })
|
|
||||||
}
|
|
||||||
return final
|
|
||||||
.filter(n => n.status.completed)
|
|
||||||
.sort((a, b) => b.score - a.score);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { Status, BuildGraphOptions };
|
export type { Status, BuildGraphOptions };
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type GetImpossibleResult = {
|
|||||||
impossible: Task[];
|
impossible: Task[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImpossible = (
|
export const getImpossible = (
|
||||||
tasks: Task[],
|
tasks: Task[],
|
||||||
time: Date,
|
time: Date,
|
||||||
) => {
|
) => {
|
||||||
@@ -50,15 +50,15 @@ const calculateScore = ({
|
|||||||
score += task.priority * 10;
|
score += task.priority * 10;
|
||||||
impossible.forEach((task) => {
|
impossible.forEach((task) => {
|
||||||
if (task.required) {
|
if (task.required) {
|
||||||
score -= 1000;
|
score -= 10000 + (1 * task.priority);
|
||||||
} else {
|
} else {
|
||||||
score -= task.priority;
|
score -= 100 + (1 * task.priority);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (transition) {
|
if (transition) {
|
||||||
const minutes = transition.time / 1000 / 60
|
const minutes = transition.time / 1000 / 60
|
||||||
score -= minutes;
|
score -= 10 + (1 * minutes);
|
||||||
}
|
}
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/features/planner/context.ts
Normal file
15
src/features/planner/context.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { createContext } from 'react';
|
||||||
|
import { Strategies } from "./algorithm/build-graph";
|
||||||
|
|
||||||
|
type PlannerOptions = {
|
||||||
|
strategy: Strategies;
|
||||||
|
}
|
||||||
|
type PlannerContextValue = {
|
||||||
|
options: PlannerOptions;
|
||||||
|
setOptions: (options: Partial<PlannerOptions>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const PlannerContext = createContext<PlannerContextValue>(undefined as any);
|
||||||
|
|
||||||
|
export type { PlannerContextValue, PlannerOptions };
|
||||||
|
export { PlannerContext };
|
||||||
@@ -5,9 +5,10 @@ import { useAsyncCallback } from "#/hooks/async";
|
|||||||
import { UserLocation } from "#/types/location";
|
import { UserLocation } from "#/types/location";
|
||||||
import { useDate } from "../calendar";
|
import { useDate } from "../calendar";
|
||||||
import { useTasksWithContext } from "../agenda-context";
|
import { useTasksWithContext } from "../agenda-context";
|
||||||
import { useMemo, useState } from "react";
|
import { useContext, useMemo, useState } from "react";
|
||||||
import { PlanItem } from "#/types/plans";
|
import { PlanItem } from "#/types/plans";
|
||||||
import { Task } from "#/types/task";
|
import { Task } from "#/types/task";
|
||||||
|
import { PlannerContext } from "./context";
|
||||||
|
|
||||||
export type UsePlanOptions = {
|
export type UsePlanOptions = {
|
||||||
location: UserLocation;
|
location: UserLocation;
|
||||||
@@ -23,10 +24,21 @@ export type UsePlan = [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const usePlanOptions = () => {
|
||||||
|
const { options } = useContext(PlannerContext);
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSetPlanOptions = () => {
|
||||||
|
const { setOptions } = useContext(PlannerContext);
|
||||||
|
return setOptions;
|
||||||
|
}
|
||||||
|
|
||||||
export const usePlan = ({
|
export const usePlan = ({
|
||||||
location,
|
location,
|
||||||
}: UsePlanOptions): UsePlan => {
|
}: UsePlanOptions): UsePlan => {
|
||||||
const today = useDate();
|
const today = useDate();
|
||||||
|
const planOptions = usePlanOptions();
|
||||||
const [status, setStatus] = useState<Status>();
|
const [status, setStatus] = useState<Status>();
|
||||||
const all = useTasksWithContext();
|
const all = useTasksWithContext();
|
||||||
const enabled = useMemo(() => all.filter(f => f.enabled), [all])
|
const enabled = useMemo(() => all.filter(f => f.enabled), [all])
|
||||||
@@ -37,7 +49,7 @@ export const usePlan = ({
|
|||||||
location,
|
location,
|
||||||
time: start || today,
|
time: start || today,
|
||||||
tasks: enabled,
|
tasks: enabled,
|
||||||
strategy: Strategies.firstComplet,
|
strategy: planOptions.strategy,
|
||||||
context: {
|
context: {
|
||||||
getTransition,
|
getTransition,
|
||||||
},
|
},
|
||||||
@@ -50,7 +62,7 @@ export const usePlan = ({
|
|||||||
agenda: day,
|
agenda: day,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[today, location, all, setStatus],
|
[today, location, all, setStatus, planOptions],
|
||||||
);
|
);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1 +1,4 @@
|
|||||||
|
export { PlannerProvider } from './provider';
|
||||||
|
export type { PlannerOptions } from './context';
|
||||||
|
export { Strategies } from './algorithm/build-graph';
|
||||||
export * from './hooks';
|
export * from './hooks';
|
||||||
|
|||||||
32
src/features/planner/provider.tsx
Normal file
32
src/features/planner/provider.tsx
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { ReactNode, useCallback, useState } from 'react';
|
||||||
|
import { Strategies } from './algorithm/build-graph';
|
||||||
|
import { PlannerContext, PlannerOptions } from './context';
|
||||||
|
|
||||||
|
type PlannerProviderProps = {
|
||||||
|
children: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlannerProvider: React.FC<PlannerProviderProps> = ({ children }) => {
|
||||||
|
const [options, setOwnOptions] = useState<PlannerOptions>({
|
||||||
|
strategy: Strategies.firstComplet,
|
||||||
|
})
|
||||||
|
|
||||||
|
const setOptions = useCallback(
|
||||||
|
(next: Partial<PlannerOptions>) => {
|
||||||
|
setOwnOptions(current => ({
|
||||||
|
...current,
|
||||||
|
...next,
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
[setOwnOptions],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PlannerContext.Provider value={{ options, setOptions }}>
|
||||||
|
{children}
|
||||||
|
</PlannerContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export type { PlannerProviderProps };
|
||||||
|
export { PlannerProvider };
|
||||||
@@ -3,6 +3,7 @@ import { ReactNode } from "react"
|
|||||||
import { AgendaContextProvider } from "./agenda-context"
|
import { AgendaContextProvider } from "./agenda-context"
|
||||||
import { CalendarProvider } from "./calendar"
|
import { CalendarProvider } from "./calendar"
|
||||||
import { LocationProvider } from "./location"
|
import { LocationProvider } from "./location"
|
||||||
|
import { PlannerProvider } from "./planner"
|
||||||
import { RoutinesProvider } from "./routines"
|
import { RoutinesProvider } from "./routines"
|
||||||
|
|
||||||
type SetupProps = {
|
type SetupProps = {
|
||||||
@@ -21,7 +22,9 @@ const Setup: React.FC<SetupProps> = ({
|
|||||||
<RoutinesProvider>
|
<RoutinesProvider>
|
||||||
<LocationProvider getTransition={getTransit} lookup={() => []}>
|
<LocationProvider getTransition={getTransit} lookup={() => []}>
|
||||||
<AgendaContextProvider day={day}>
|
<AgendaContextProvider day={day}>
|
||||||
{children}
|
<PlannerProvider>
|
||||||
|
{children}
|
||||||
|
</PlannerProvider>
|
||||||
</AgendaContextProvider>
|
</AgendaContextProvider>
|
||||||
</LocationProvider>
|
</LocationProvider>
|
||||||
</RoutinesProvider>
|
</RoutinesProvider>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { ReactNode } from 'react';
|
import React, { ReactNode } from 'react';
|
||||||
import styled from 'styled-components/native';
|
import styled from 'styled-components/native';
|
||||||
import { TouchableOpacity } from 'react-native';
|
import { TouchableOpacity } from 'react-native';
|
||||||
import { IconNames, Icon } from '#/ui/components';
|
import { IconNames, Icon } from '../icon';
|
||||||
import { Theme } from '#/ui/theme';
|
import { Theme } from '#/ui/theme';
|
||||||
import { Link } from '#/ui/typography';
|
import { Link } from '#/ui/typography';
|
||||||
|
|
||||||
|
|||||||
56
src/ui/components/form/selector/index.tsx
Normal file
56
src/ui/components/form/selector/index.tsx
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import { cmyk } from "chroma-js";
|
||||||
|
import { ReactNode, useCallback, useMemo, useState } from "react";
|
||||||
|
import { Modal } from "../../modal";
|
||||||
|
import { Row } from "../../row";
|
||||||
|
|
||||||
|
type SelectorProps<T> = {
|
||||||
|
label: string;
|
||||||
|
items: {
|
||||||
|
display: ReactNode;
|
||||||
|
value: T;
|
||||||
|
}[];
|
||||||
|
getId: (item: T) => string;
|
||||||
|
selected?: T;
|
||||||
|
setSelected: (item?: T) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Selector<T = any>({
|
||||||
|
items,
|
||||||
|
label,
|
||||||
|
getId,
|
||||||
|
selected,
|
||||||
|
setSelected,
|
||||||
|
}: SelectorProps<T>) {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const selectedItem = useMemo(
|
||||||
|
() => selected ? items.find(i => getId(i.value) === getId(selected)) : undefined,
|
||||||
|
[selected, items],
|
||||||
|
);
|
||||||
|
const select = useCallback(
|
||||||
|
(item: T) => {
|
||||||
|
setSelected(item);
|
||||||
|
setVisible(false);
|
||||||
|
},
|
||||||
|
[setSelected, setVisible],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal visible={visible} onClose={() => setVisible(false)}>
|
||||||
|
{items.map((item) => (
|
||||||
|
<Row
|
||||||
|
key={getId(item.value)}
|
||||||
|
onPress={() => select(item.value)}
|
||||||
|
title={item.display}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Modal>
|
||||||
|
<Row
|
||||||
|
overline={label}
|
||||||
|
onPress={() => setVisible(true)}
|
||||||
|
title={selectedItem?.display || 'Select'}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Selector };
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
export * from './icon';
|
export * from './icon';
|
||||||
|
export * from './modal';
|
||||||
|
export * from './icon';
|
||||||
export * from './form';
|
export * from './form';
|
||||||
export * from './page';
|
export * from './page';
|
||||||
export * from './popup';
|
export * from './popup';
|
||||||
|
|||||||
24
src/ui/components/modal/index.tsx
Normal file
24
src/ui/components/modal/index.tsx
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { Modal as Wrapper } from 'react-native';
|
||||||
|
import { Popup } from '../popup';
|
||||||
|
type ModalProps = {
|
||||||
|
visible: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Modal: React.FC<ModalProps> = ({ visible, onClose, children }) => (
|
||||||
|
<Wrapper
|
||||||
|
transparent
|
||||||
|
visible={visible}
|
||||||
|
animationType="slide"
|
||||||
|
onRequestClose={onClose}
|
||||||
|
onDismiss={onClose}
|
||||||
|
>
|
||||||
|
<Popup onClose={onClose}>
|
||||||
|
{children}
|
||||||
|
</Popup>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
|
||||||
|
export { Modal };
|
||||||
@@ -51,4 +51,4 @@ const Popup: React.FC<Props> = ({ visible, children, onClose }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Popup;
|
export { Popup };
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { RoutineSetScreen } from '../screens/routines/set';
|
|||||||
import { TaskListScreen } from '../screens/plan/tasks';
|
import { TaskListScreen } from '../screens/plan/tasks';
|
||||||
import { AgendaContextSetScreen } from '../screens/plan/set';
|
import { AgendaContextSetScreen } from '../screens/plan/set';
|
||||||
import { Icon } from '../components';
|
import { Icon } from '../components';
|
||||||
|
import { PlanSettingsScreen } from '../screens/plan/settings';
|
||||||
|
|
||||||
const MainTabsNvaigator = createBottomTabNavigator();
|
const MainTabsNvaigator = createBottomTabNavigator();
|
||||||
|
|
||||||
@@ -79,6 +80,7 @@ const Root: React.FC = () => (
|
|||||||
<RootNavigator.Screen name="locationSet" component={LocationSetScreen} />
|
<RootNavigator.Screen name="locationSet" component={LocationSetScreen} />
|
||||||
<RootNavigator.Screen name="routineSet" component={RoutineSetScreen} />
|
<RootNavigator.Screen name="routineSet" component={RoutineSetScreen} />
|
||||||
<RootNavigator.Screen name="agendaContextSet" component={AgendaContextSetScreen} />
|
<RootNavigator.Screen name="agendaContextSet" component={AgendaContextSetScreen} />
|
||||||
|
<RootNavigator.Screen name="planSettings" component={PlanSettingsScreen} />
|
||||||
</RootNavigator.Group>
|
</RootNavigator.Group>
|
||||||
</RootNavigator.Navigator>
|
</RootNavigator.Navigator>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { useLocations, useSetLocation } from "#/features/location";
|
import { useLocations, useSetLocation } from "#/features/location";
|
||||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||||
import { Button, TextInput } from "#/ui/components";
|
import { Popup, Button, TextInput } from "#/ui/components";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import Popup from "#/ui/components/popup";
|
|
||||||
|
|
||||||
const LocationSetScreen: React.FC = () => {
|
const LocationSetScreen: React.FC = () => {
|
||||||
const { params = {} } = useRoute() as any;
|
const { params = {} } = useRoute() as any;
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ import { useCommit, useDate } from "#/features/calendar";
|
|||||||
import { format, formatDistance, formatDistanceToNow, set } from "date-fns";
|
import { format, formatDistance, formatDistanceToNow, set } from "date-fns";
|
||||||
import styled from "styled-components/native";
|
import styled from "styled-components/native";
|
||||||
import { Status } from "#/features/planner/algorithm/build-graph";
|
import { Status } from "#/features/planner/algorithm/build-graph";
|
||||||
|
import { useNavigation } from "@react-navigation/native";
|
||||||
|
|
||||||
const Wrapper = styled.ScrollView`
|
const Wrapper = styled.ScrollView`
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const getStats = (status: Status) => {
|
const getStats = (status: Status) => {
|
||||||
console.log('status', status);
|
|
||||||
if (status.current === 'running') {
|
if (status.current === 'running') {
|
||||||
const runTime = formatDistanceToNow(status.start, { includeSeconds: true })
|
const runTime = formatDistanceToNow(status.start, { includeSeconds: true })
|
||||||
return `calulated ${status.nodes} nodes in ${runTime}`;
|
return `calulated ${status.nodes} nodes in ${runTime} using ${status.strategy}`;
|
||||||
}
|
}
|
||||||
const runTime = formatDistance(status.start, status.end, { includeSeconds: true })
|
const runTime = formatDistance(status.start, status.end, { includeSeconds: true })
|
||||||
return `calulated ${status.nodes} nodes in ${runTime}`;
|
return `calulated ${status.nodes} nodes in ${runTime} using ${status.strategy}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const PlanDayScreen: React.FC = () => {
|
const PlanDayScreen: React.FC = () => {
|
||||||
@@ -28,10 +28,11 @@ const PlanDayScreen: React.FC = () => {
|
|||||||
const [location] = useCurrentLocation();
|
const [location] = useCurrentLocation();
|
||||||
const [startTime, setStartTime] = useState('06:00');
|
const [startTime, setStartTime] = useState('06:00');
|
||||||
const [commit] = useCommit();
|
const [commit] = useCommit();
|
||||||
|
const { navigate } = useNavigation();
|
||||||
const current = useMemo(
|
const current = useMemo(
|
||||||
() => location || {
|
() => location || {
|
||||||
id: 'unknown',
|
id: 'unknown',
|
||||||
title: 'foo',
|
title: 'Unknown',
|
||||||
},
|
},
|
||||||
[location]
|
[location]
|
||||||
)
|
)
|
||||||
@@ -70,6 +71,9 @@ const PlanDayScreen: React.FC = () => {
|
|||||||
<Button onPress={() => commit(options.result?.agenda || [])} icon="download" />
|
<Button onPress={() => commit(options.result?.agenda || [])} icon="download" />
|
||||||
</Cell>
|
</Cell>
|
||||||
)}
|
)}
|
||||||
|
<Cell>
|
||||||
|
<Button onPress={() => navigate('planSettings')} icon="settings" />
|
||||||
|
</Cell>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useLocations, useSetLocation } from "#/features/location";
|
import { useLocations, useSetLocation } from "#/features/location";
|
||||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||||
import { Button, Checkbok, TextInput } from "#/ui/components";
|
import { Popup, Button, Checkbok, TextInput } from "#/ui/components";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { useAgendaContext, useSetAgendaContext } from "#/features/agenda-context";
|
import { useAgendaContext, useSetAgendaContext } from "#/features/agenda-context";
|
||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import Popup from "#/ui/components/popup";
|
|
||||||
|
|
||||||
const AgendaContextSetScreen: React.FC = () => {
|
const AgendaContextSetScreen: React.FC = () => {
|
||||||
const { params = {} } = useRoute() as any;
|
const { params = {} } = useRoute() as any;
|
||||||
|
|||||||
40
src/ui/screens/plan/settings.tsx
Normal file
40
src/ui/screens/plan/settings.tsx
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Strategies, usePlanOptions, useSetPlanOptions } from "#/features/planner"
|
||||||
|
import { Selector } from "#/ui/components/form/selector";
|
||||||
|
import { Popup } from "#/ui/components";
|
||||||
|
import { useNavigation } from "@react-navigation/native";
|
||||||
|
|
||||||
|
const items = [{
|
||||||
|
display: 'First valid',
|
||||||
|
value: Strategies.firstValid,
|
||||||
|
}, {
|
||||||
|
display: 'First complete',
|
||||||
|
value: Strategies.firstComplet,
|
||||||
|
}, {
|
||||||
|
display: 'All valid',
|
||||||
|
value: Strategies.allValid,
|
||||||
|
}, {
|
||||||
|
display: 'All',
|
||||||
|
value: Strategies.all,
|
||||||
|
}];
|
||||||
|
|
||||||
|
const PlanSettingsScreen: React.FC = () => {
|
||||||
|
const options = usePlanOptions();
|
||||||
|
const setOptions = useSetPlanOptions();
|
||||||
|
const { goBack } = useNavigation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popup onClose={goBack}>
|
||||||
|
<Selector
|
||||||
|
label="Strategy"
|
||||||
|
items={items}
|
||||||
|
getId={i => i}
|
||||||
|
selected={options.strategy}
|
||||||
|
setSelected={(strategy) => {
|
||||||
|
setOptions({ strategy: strategy || Strategies.firstComplet });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Popup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PlanSettingsScreen };
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
import { useNavigation, useRoute } from '@react-navigation/native';
|
import { useNavigation, useRoute } from '@react-navigation/native';
|
||||||
import { Button, Checkbok, TextInput } from "#/ui/components";
|
import { Popup, Button, Checkbok, TextInput } from "#/ui/components";
|
||||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||||
import { nanoid } from 'nanoid';
|
import { nanoid } from 'nanoid';
|
||||||
import { useRoutines, useSetRoutine } from '#/features/routines';
|
import { useRoutines, useSetRoutine } from '#/features/routines';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import { useLocations } from '#/features/location';
|
import { useLocations } from '#/features/location';
|
||||||
import Popup from '#/ui/components/popup';
|
|
||||||
|
|
||||||
const RoutineSetScreen: React.FC = () => {
|
const RoutineSetScreen: React.FC = () => {
|
||||||
const { params = {} } = useRoute() as any;
|
const { params = {} } = useRoute() as any;
|
||||||
|
|||||||
Reference in New Issue
Block a user