diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8ee462b..05c6410 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -4,15 +4,18 @@ + + + + + - - + - = ({ navigation, toggleSidebar, }: any) => { - const {registers, activeRegister, updatedAt} = useStore(); + const {registers, activeRegister, viewingRegisters, updatedAt} = useStore(); const [currentEvents, setCurrentEvents] = useState([]); const [upcomingEvents, setUpcomingEvents] = useState([]); @@ -63,60 +65,68 @@ const HomeScreen: React.FC = ({ return now.getHours() * 60 + now.getMinutes(); }; - // Process events from current register + // Process events from all viewing registers useEffect(() => { - if (!registers[activeRegister]?.cards) { - setCurrentEvents([]); - setUpcomingEvents([]); - return; - } + const processEvents = () => { + const currentDay = getCurrentDayKey(); + const currentTimeMinutes = getCurrentTimeInMinutes(); + const allEvents: EventInfo[] = []; - const currentDay = getCurrentDayKey(); - const currentTimeMinutes = getCurrentTimeInMinutes(); - const allEvents: EventInfo[] = []; + // Ensure viewingRegisters is an array before processing + if (!Array.isArray(viewingRegisters)) { + return; + } - // Extract all events for today from current register - registers[activeRegister].cards.forEach((card: CardInterface) => { - const todaySlots = card.days[currentDay] || []; + viewingRegisters.forEach(registerId => { + const register = registers[registerId]; + // Ensure the register and its cards exist and are in the correct format + if (register && Array.isArray(register.cards)) { + register.cards.forEach((card: CardInterface) => { + const todaySlots = card.days[currentDay] || []; - todaySlots.forEach((slot: Slots, index: number) => { - const startMinutes = timeToMinutes(slot.start); - const endMinutes = timeToMinutes(slot.end); + todaySlots.forEach((slot: Slots, index: number) => { + const startMinutes = timeToMinutes(slot.start); + const endMinutes = timeToMinutes(slot.end); - allEvents.push({ - id: `${card.id}-${currentDay}-${index}`, - title: card.title, - startTime: slot.start, - endTime: slot.end, - roomName: slot.roomName || undefined, - color: card.tagColor, - cardId: card.id, - registerId: activeRegister, - isRunning: - currentTimeMinutes >= startMinutes && - currentTimeMinutes <= endMinutes, - }); + allEvents.push({ + id: `${card.id}-${currentDay}-${index}-${registerId}`, + title: card.title, + startTime: slot.start, + endTime: slot.end, + roomName: slot.roomName || undefined, + color: card.tagColor, + cardId: card.id, + registerId: registerId, + isRunning: + currentTimeMinutes >= startMinutes && + currentTimeMinutes <= endMinutes, + }); + }); + }); + } }); - }); - // Sort events by start time - allEvents.sort( - (a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime), - ); + // Sort events by start time + allEvents.sort( + (a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime), + ); + + // Separate current and upcoming events + const running = allEvents.filter(event => event.isRunning); + const upcoming = allEvents + .filter( + event => + !event.isRunning && + timeToMinutes(event.startTime) > currentTimeMinutes, + ) + .slice(0, 2); // Next 2 upcoming events - // Separate current and upcoming events - const running = allEvents.filter(event => event.isRunning); - const upcoming = allEvents - .filter( - event => - !event.isRunning && - timeToMinutes(event.startTime) > currentTimeMinutes, - ) - .slice(0, 2); // Next 2 upcoming events + setCurrentEvents(running); + setUpcomingEvents(upcoming); + }; - setCurrentEvents(running); - setUpcomingEvents(upcoming); - }, [registers, activeRegister, updatedAt]); + processEvents(); + }, [registers, viewingRegisters, updatedAt]); // Navigate to card details const handleEventPress = (event: EventInfo) => { @@ -195,9 +205,8 @@ const HomeScreen: React.FC = ({ No events scheduled for today - Add subjects to{' '} - {registers[activeRegister]?.name || 'your register'} to see your - schedule + Please check that your selected registers have subjects scheduled + for today. )} @@ -324,4 +333,4 @@ const styles = StyleSheet.create({ }, }); -export default HomeScreen; +export default HomeScreen; \ No newline at end of file diff --git a/src/screens/time-table/TimeTableScreen.tsx b/src/screens/time-table/TimeTableScreen.tsx index 7f2a260..7d2a096 100644 --- a/src/screens/time-table/TimeTableScreen.tsx +++ b/src/screens/time-table/TimeTableScreen.tsx @@ -1,3 +1,5 @@ +// src/screens/time-table/TimeTableScreen.tsx + import React, {useState, useEffect} from 'react'; import { View, @@ -44,23 +46,15 @@ const TimeTableScreen: React.FC = ({ navigation, handleMenuOpen: _handleMenuOpen, }) => { - const {registers, activeRegister, markPresent, selectedRegisters, setSelectedRegisters} = useStore(); + const {registers, viewingRegisters, markPresent, setSelectedRegisters} = useStore(); const [subjects, setSubjects] = useState([]); - const [isDropdownOpen, setIsDropdownOpen] = useState(false); - - // Initialize selectedRegisters if empty (handles first app launch) - useEffect(() => { - if (Object.keys(registers).length > 0 && selectedRegisters.length === 0) { - setSelectedRegisters([activeRegister]); - } - }, [registers, activeRegister, selectedRegisters, setSelectedRegisters]); // Convert store data to TimeTable format useEffect(() => { const convertedSubjects: Subject[] = []; // Only process selected registers - selectedRegisters.forEach(registerIdx => { + viewingRegisters.forEach(registerIdx => { const register = registers[registerIdx]; if (register?.cards) { @@ -109,47 +103,7 @@ const TimeTableScreen: React.FC = ({ }); setSubjects(convertedSubjects); - }, [registers, selectedRegisters]); - - // Helper functions for register selection - const getAllRegisterIds = () => - Object.keys(registers).map(key => parseInt(key, 10)); - - const isAllSelected = () => { - const allIds = getAllRegisterIds(); - return ( - allIds.length > 0 && allIds.every(id => selectedRegisters.includes(id)) - ); - }; - - const toggleAllRegisters = () => { - if (isAllSelected()) { - setSelectedRegisters([]); - } else { - setSelectedRegisters(getAllRegisterIds()); - } - }; - - const toggleRegister = (registerId: number) => { - if (selectedRegisters.includes(registerId)) { - setSelectedRegisters(selectedRegisters.filter(id => id !== registerId)); - } else { - setSelectedRegisters([...selectedRegisters, registerId]); - } - }; - - const getDropdownDisplayText = () => { - if (selectedRegisters.length === 0) { - return 'No registers selected'; - } - if (isAllSelected()) { - return 'All Registers'; - } - if (selectedRegisters.length === 1) { - return registers[selectedRegisters[0]]?.name || 'Unknown Register'; - } - return `${selectedRegisters.length} registers selected`; - }; + }, [registers, viewingRegisters]); // Get current date for header display const getCurrentDate = () => { @@ -163,13 +117,6 @@ const TimeTableScreen: React.FC = ({ return ( - {isDropdownOpen && ( - setIsDropdownOpen(false)} - /> - )} @@ -189,82 +136,11 @@ const TimeTableScreen: React.FC = ({ style={styles.editIcon} /> - - setIsDropdownOpen(!isDropdownOpen)}> - - {getDropdownDisplayText()} - - - {isDropdownOpen ? '▲' : '▼'} - - - {isDropdownOpen && ( - - - - - All Registers - - - - {getAllRegisterIds().map(registerId => ( - toggleRegister(registerId)}> - - - - - {registers[registerId]?.name || 'Unknown Register'} - - - - - ))} - - )} - { acc[registerId] = registers[registerId]?.name || 'Unknown Register'; return acc; @@ -281,20 +157,9 @@ const styles = StyleSheet.create({ flex: 1, backgroundColor: '#18181B', }, - overlay: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - zIndex: 999, - }, headerContainer: { paddingHorizontal: 16, paddingVertical: 10, - // backgroundColor: '#1F1F23', - // borderBottomWidth: 1, - // borderBottomColor: '#2D2D2D', marginBottom: 12, flexDirection: 'row', alignItems: 'center', @@ -328,6 +193,7 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', alignSelf: 'center', + marginLeft: 'auto', marginRight: 16, }, editIcon: { @@ -341,88 +207,5 @@ const styles = StyleSheet.create({ fontWeight: '500', marginLeft: 36, // Align with Schedule text (icon width 28px + marginRight 8px) }, - dropdownContainer: { - position: 'relative', - zIndex: 1000, - minWidth: 150, - maxWidth: 200, - }, - dropdownButton: { - backgroundColor: '#2D2D2D', - borderRadius: 8, - paddingHorizontal: 12, - paddingVertical: 10, - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - borderWidth: 1, - borderColor: '#404040', - }, - dropdownButtonText: { - color: '#FFFFFF', - fontSize: 14, - fontWeight: '500', - flex: 1, - marginRight: 8, - }, - dropdownArrow: { - color: '#8B5CF6', - fontSize: 12, - fontWeight: 'bold', - }, - dropdownMenu: { - position: 'absolute', - top: '100%', - left: 0, - right: 0, - backgroundColor: '#2D2D2D', - borderRadius: 8, - borderWidth: 1, - borderColor: '#404040', - marginTop: 4, - maxHeight: 200, - zIndex: 1001, - overflow: 'hidden', - }, - dropdownItem: { - paddingHorizontal: 12, - paddingVertical: 12, - borderBottomWidth: 1, - borderBottomColor: '#404040', - }, - dropdownItemSelected: { - backgroundColor: '#8B5CF620', - }, - dropdownItemContent: { - flexDirection: 'row', - alignItems: 'center', - flex: 1, - overflow: 'hidden', - }, - registerItem: { - flexDirection: 'row', - alignItems: 'center', - flex: 1, - overflow: 'hidden', - }, - colorIndicator: { - width: 16, - height: 16, - borderRadius: 8, - marginRight: 10, - borderWidth: 1, - borderColor: '#3F3F46', - }, - dropdownItemText: { - color: '#FFFFFF', - fontSize: 14, - flex: 1, - }, - dropdownItemTextSelected: { - color: '#8B5CF6', - fontWeight: '600', - flex: 1, - }, }); - -export default TimeTableScreen; +export default TimeTableScreen; \ No newline at end of file diff --git a/src/screens/user-settings/SettingsScreen.tsx b/src/screens/user-settings/SettingsScreen.tsx index 28fec26..24e6c4a 100644 --- a/src/screens/user-settings/SettingsScreen.tsx +++ b/src/screens/user-settings/SettingsScreen.tsx @@ -1,3 +1,5 @@ +// src/screens/user-settings/SettingsScreen.tsx + import React, { useState, useEffect } from 'react'; import { View, @@ -37,6 +39,8 @@ const SettingsScreen: React.FC = () => { registers, activeRegister, selectedRegisters, + viewingRegisters, + setViewingRegisters, setDefaultTargetPercentage, updateAllRegistersTargetPercentage, selectedSchedules, @@ -55,6 +59,10 @@ const SettingsScreen: React.FC = () => { const [localLeadTime, setLocalLeadTime] = useState(notificationLeadTime); const [localSchedules, setLocalSchedules] = useState(selectedSchedules); + const registerOptions = Object.keys(registers).map(key => ({ + id: key, + name: registers[parseInt(key)].name, + })); // Effects useEffect(() => { setAppVersion(packageJson.version); @@ -108,22 +116,22 @@ const SettingsScreen: React.FC = () => { console.log('Starting save to device...'); console.log('Available registers:', Object.keys(registers)); console.log('Selected registers from store:', selectedRegisters); - + // Use all registers if no specific selection is available - const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0 - ? selectedRegisters + const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0 + ? selectedRegisters : Object.keys(registers).map(key => parseInt(key, 10)); - + console.log('Using registers for export:', currentSelectedRegisters); - + if (currentSelectedRegisters.length === 0) { Alert.alert('No Data', 'No registers found to export. Please create some schedules first.'); return; } - - await saveScheduleToDevice({ - selectedRegisters: currentSelectedRegisters, - registers + + await saveScheduleToDevice({ + selectedRegisters: currentSelectedRegisters, + registers }); } catch (error) { console.error('Save to device error:', error); @@ -137,22 +145,22 @@ const SettingsScreen: React.FC = () => { console.log('Starting share schedule...'); console.log('Available registers:', Object.keys(registers)); console.log('Selected registers from store:', selectedRegisters); - + // Use all registers if no specific selection is available - const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0 - ? selectedRegisters + const currentSelectedRegisters = selectedRegisters && selectedRegisters.length > 0 + ? selectedRegisters : Object.keys(registers).map(key => parseInt(key, 10)); - + console.log('Using registers for share:', currentSelectedRegisters); - + if (currentSelectedRegisters.length === 0) { Alert.alert('No Data', 'No registers found to share. Please create some schedules first.'); return; } - - await shareSchedule({ - selectedRegisters: currentSelectedRegisters, - registers + + await shareSchedule({ + selectedRegisters: currentSelectedRegisters, + registers }); } catch (error) { console.error('Share schedule error:', error); @@ -164,7 +172,7 @@ const SettingsScreen: React.FC = () => { const handleImportSchedule = async () => { try { console.log('Starting CSV import...'); - + if (!registers[activeRegister]) { Alert.alert('Error', 'No active register found. Please create a register first.'); return; @@ -173,7 +181,7 @@ const SettingsScreen: React.FC = () => { // Use raw CSV content instead of parsed data const csvContent = await pickCSVFileRaw(); console.log('Raw CSV Content received:', csvContent); - + if (!csvContent) { console.log('No CSV content received (user cancelled or error)'); return; @@ -238,7 +246,6 @@ const SettingsScreen: React.FC = () => { {registerInfo.name} {registerInfo.totalCards} subjects - {/* Preferences Section */} Preferences @@ -294,6 +301,30 @@ const SettingsScreen: React.FC = () => { + {/* Schedule View Section */} + + Schedule View + Select Registers to View + setViewingRegisters(items.map(Number))} + selectedItems={viewingRegisters.map(String)} + selectText="Pick Registers" + searchInputPlaceholderText="Search Registers..." + tagRemoveIconColor="#EF4444" + tagTextColor="#9a4848ff" + selectedItemTextColor="#4CAF50" + selectedItemIconColor="#4CAF50" + itemTextColor="#bb5656ff" + displayKey="name" + searchInputStyle={{ color: '#e23939ff' }} + submitButtonColor="#4CAF50" + submitButtonText="Apply" + styleMainWrapper={{ backgroundColor: '#27272A', borderRadius: 12, padding: 10 }} + /> + + {/* Notifications & Alerts Section */} Notifications & Alerts @@ -333,16 +364,15 @@ const SettingsScreen: React.FC = () => { />