Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ const config: ExpoConfig = {
backgroundImage: "./assets/images/android-icon-background.png",
monochromeImage: "./assets/images/android-icon-monochrome.png",
},
predictiveBackGestureEnabled: false,
},
locales: {
en: "./assets/locales/app-meta-en.json",
Expand Down
16 changes: 16 additions & 0 deletions app/(pages)/settings/calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export default function CalendarSettingsScreen() {
const setScrollWeekend = useScheduleStore((s) => s.setScrollWeekend);
const showMidday = useScheduleStore((s) => s.showMiddaySections);
const setShowMidday = useScheduleStore((s) => s.setShowMiddaySections);
const showOtherWeekCourses = useScheduleStore((s) => s.showOtherWeekCourses);
const setShowOtherWeekCourses = useScheduleStore(
(s) => s.setShowOtherWeekCourses,
);
const colorPalette = useScheduleStore((s) => s.colorPalette);
const backgroundImageUri = useScheduleStore((s) => s.backgroundImageUri);
const setBackgroundImageUri = useScheduleStore(
Expand Down Expand Up @@ -220,6 +224,18 @@ export default function CalendarSettingsScreen() {
showArrow={false}
right={<Switch value={showMidday} onValueChange={setShowMidday} />}
/>
<MenuItem
icon="visibility"
iconBg="#8E8E93"
label={t("calendarSet.showOtherWeek")}
showArrow={false}
right={
<Switch
value={showOtherWeekCourses}
onValueChange={setShowOtherWeekCourses}
/>
}
/>
</MenuGroup>

<MenuGroup title={t("calendarSet.syncGroup")}>
Expand Down
75 changes: 42 additions & 33 deletions app/(pages)/settings/course/add.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import Toast from "react-native-toast-message";

import { useColorScheme } from "@/hooks/use-color-scheme";
import { MAX_SECTION, MAX_WEEK, weeksToRanges } from "@/lib/course-weeks";
import { type TKey, useT } from "@/lib/i18n";
import { type Course, useCourseStore } from "@/store/course";

Expand All @@ -27,8 +28,6 @@ const DAY_KEYS: TKey[] = [
"schedule.weekday.sat",
"schedule.weekday.sun",
];
const MAX_WEEK = 20;
const MAX_SECTION = 16;

interface TimeSlot {
day: number;
Expand Down Expand Up @@ -70,25 +69,6 @@ function recordsToSlots(records: Course[]): TimeSlot[] {
return map.size > 0 ? [...map.values()] : [createEmptySlot()];
}

function weeksToRanges(weeks: Set<number>): [number, number][] {
const sorted = [...weeks].sort((a, b) => a - b);
if (sorted.length === 0) return [];
const ranges: [number, number][] = [];
let start = sorted[0];
let end = sorted[0];
for (let i = 1; i < sorted.length; i++) {
if (sorted[i] === end + 1) {
end = sorted[i];
} else {
ranges.push([start, end]);
start = sorted[i];
end = sorted[i];
}
}
ranges.push([start, end]);
return ranges;
}

function formatWeeks(
weeks: Set<number>,
notSelectedLabel: string,
Expand All @@ -105,7 +85,16 @@ function formatWeeks(
export default function AddEditCourseScreen() {
const t = useT();
const router = useRouter();
const { name: editName } = useLocalSearchParams<{ name?: string }>();
const params = useLocalSearchParams<{
name?: string;
prefillName?: string;
prefillRoom?: string;
prefillTeacher?: string;
prefillDay?: string;
prefillSectionStart?: string;
prefillSectionEnd?: string;
}>();
const editName = params.name;
const isEdit = !!editName;

const scheme = useColorScheme();
Expand All @@ -124,17 +113,36 @@ export default function AddEditCourseScreen() {
[editName, courses],
);

const [name, setName] = useState(() =>
isEdit && existingRecords.length > 0 ? existingRecords[0].name : "",
);
const [teacher, setTeacher] = useState(() =>
isEdit && existingRecords.length > 0 ? existingRecords[0].teacher : "",
);
const [slots, setSlots] = useState<TimeSlot[]>(() =>
isEdit && existingRecords.length > 0
? recordsToSlots(existingRecords)
: [createEmptySlot()],
);
const prefillSlot = useMemo<TimeSlot | null>(() => {
if (isEdit) return null;
const day = Number(params.prefillDay);
const ss = Number(params.prefillSectionStart);
const se = Number(params.prefillSectionEnd);
if (!day || !ss || !se) return null;
return {
day: Math.min(7, Math.max(1, day)),
sectionStart: ss,
sectionEnd: Math.max(ss, se),
room: params.prefillRoom ?? "",
weeks: new Set<number>(),
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isEdit]);

const [name, setName] = useState(() => {
if (isEdit && existingRecords.length > 0) return existingRecords[0].name;
return params.prefillName ?? "";
});
const [teacher, setTeacher] = useState(() => {
if (isEdit && existingRecords.length > 0) return existingRecords[0].teacher;
return params.prefillTeacher ?? "";
});
const [slots, setSlots] = useState<TimeSlot[]>(() => {
if (isEdit && existingRecords.length > 0)
return recordsToSlots(existingRecords);
if (prefillSlot) return [prefillSlot];
return [createEmptySlot()];
});
const [expandedIndex, setExpandedIndex] = useState<number | null>(() =>
isEdit && existingRecords.length > 0 ? null : 0,
);
Expand Down Expand Up @@ -252,6 +260,7 @@ export default function AddEditCourseScreen() {
<Stack.Screen
options={{
title: isEdit ? t("courseAdd.titleEdit") : t("courseAdd.titleAdd"),
fullScreenGestureEnabled: false,
}}
/>
<KeyboardAvoidingView
Expand Down
45 changes: 22 additions & 23 deletions app/(tabs)/course.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import Animated, {
} from "react-native-reanimated";
import { SafeAreaView } from "react-native-safe-area-context";

import { CourseDrawer } from "@/components/layout/course-drawer";
import { Schedule } from "@/components/layout/schedule";
import { BottomSheet } from "@/components/ui/bottom-sheet";
import { IconSymbol } from "@/components/ui/icon-symbol";
Expand All @@ -32,14 +33,14 @@ export default function CourseScreen() {
const t = useT();
const courses = useCourseStore((store) => store.courses);
const termStart = useCourseStore((store) => store.termStart);
const lastImportType = useCourseStore((s) => s.lastImportType);
const isBound = useUserBindStore((store) => store.isBound);
const backgroundImageUri = useScheduleStore((s) => s.backgroundImageUri);
const [week, setWeek] = useState<number>(() => getCurrentWeek(termStart));
const today = getCurrentDayOfWeek();
const haptic = useHaptics();
const [showWeekPicker, setShowWeekPicker] = useState(false);
const [showTypePicker, setShowTypePicker] = useState(false);
const [showDrawer, setShowDrawer] = useState(false);

const scheme = useColorScheme();
const isDark = scheme === "dark";
Expand Down Expand Up @@ -90,16 +91,7 @@ export default function CourseScreen() {
importerRef.current?.startImport(type);
};

const handleRefreshPress = () => {
haptic();
if (lastImportType) {
doImport(lastImportType);
} else {
setShowTypePicker(true);
}
};

const handleRefreshLongPress = () => {
const handleReimport = () => {
haptic();
setShowTypePicker(true);
};
Expand All @@ -120,19 +112,17 @@ export default function CourseScreen() {
contentFit="cover"
/>
)}
<SafeAreaView style={{ flex: 1 }}>
<SafeAreaView edges={["top"]} style={{ flex: 1 }}>
<View className="h-12 w-full flex-row items-center px-3">
{isBound && courses.some((c) => c.source === "imported") ? (
<Pressable
style={{ width: 48, alignItems: "center" }}
onPress={handleRefreshPress}
onLongPress={handleRefreshLongPress}
>
<Ionicons name="refresh" size={20} color={iconColor} />
</Pressable>
) : (
<View style={{ width: 48 }} />
)}
<Pressable
style={{ width: 48, alignItems: "center" }}
onPress={() => {
haptic();
setShowDrawer(true);
}}
>
<Ionicons name="menu-outline" size={24} color={iconColor} />
</Pressable>

<View className="flex-1 flex-row items-center justify-center">
<Pressable
Expand Down Expand Up @@ -400,6 +390,15 @@ export default function CourseScreen() {
</Text>
</Pressable>
</BottomSheet>

<CourseDrawer
visible={showDrawer}
onClose={() => setShowDrawer(false)}
isBound={isBound}
onManage={() => router.push("/(pages)/settings/course/manage")}
onReimport={handleReimport}
onOpenSettings={() => router.push("/(pages)/settings/calendar")}
/>
</View>
);
}
2 changes: 1 addition & 1 deletion app/(tabs)/function.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export default function FunctionScreen() {
const [uri, setUri] = useState("");

return (
<SafeAreaView style={{ flex: 1 }}>
<SafeAreaView edges={["top"]} style={{ flex: 1 }}>
<ScrollView
className="flex-1"
contentContainerStyle={{ paddingBottom: 32 }}
Expand Down
2 changes: 1 addition & 1 deletion app/(tabs)/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ export default function HomeScreen() {
];

return (
<SafeAreaView style={{ flex: 1 }}>
<SafeAreaView edges={["top"]} style={{ flex: 1 }}>
<ScrollView
className="flex-1"
contentContainerStyle={{ paddingBottom: 32, flexGrow: 1 }}
Expand Down
Loading
Loading