diff --git a/README.md b/README.md index 2aa7939..14ac33e 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ CheckMe/ │ │ │ └── raspi/ │ ├── AUTOSTART_CONVERTION.md # Run CheckMe on boot (systemd) -│ ├── L3210_INITIAL_SETUP.md # Epson L3210 scanner setup +│ ├── L3210_INITIAL_SETUP.md # Canon PIXMA MG2570S Scanner setup │ ├── RASPI_SYSTEM_FLOW.md # Full system flowchart │ ├── SCAN_ANSWER_KEY_FLOW.md # Answer key scanning flowchart │ ├── SCAN_ANSWER_SHEET_FLOW.md # Answer sheet checking flowchart @@ -114,7 +114,7 @@ CheckMe/ ## Components ### Raspberry Pi Device -The physical grading machine. Runs Python on a Raspberry Pi 4B with an I2C LCD display, a 4x3 matrix keypad, and an Epson L3210 flatbed scanner. +The physical grading machine. Runs Python on a Raspberry Pi 4B with an I2C LCD display, a 4x3 matrix keypad, and an Canon PIXMA MG2570S scanner. See [`raspi_code/`](./raspi_code/) and [`docs/raspi/`](./docs/raspi/) for setup and documentation. @@ -129,7 +129,7 @@ See [`app/CheckMe/`](./app/CheckMe/) and [`app/README.md`](./app/README.md) for | Layer | Technology | |---|---| -| Hardware | Raspberry Pi 4B, Epson L3210, I2C LCD, 4x3 Keypad | +| Hardware | Raspberry Pi 4B, Canon PIXMA MG2570S, I2C LCD, 4x3 Keypad | | Raspi Software | Python 3.12, Firebase Admin SDK, Gemini API, Cloudinary | | Mobile App | React Native (cross-platform) | | OCR | Google Gemini | diff --git a/app/CheckMe/assets/checkme-logo.png b/app/CheckMe/assets/checkme-logo.png index d6271a6..836dc13 100644 Binary files a/app/CheckMe/assets/checkme-logo.png and b/app/CheckMe/assets/checkme-logo.png differ diff --git a/app/CheckMe/src/screens/student/DashboardScreen.tsx b/app/CheckMe/src/screens/student/DashboardScreen.tsx index 9eaddb3..e23e1e6 100644 --- a/app/CheckMe/src/screens/student/DashboardScreen.tsx +++ b/app/CheckMe/src/screens/student/DashboardScreen.tsx @@ -361,7 +361,7 @@ const StudentDashboardScreen: React.FC = () => { start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.gradientButton} > - 📚 Join Subject + Join Subject diff --git a/app/CheckMe/src/screens/teacher/AnswerKeysScreen.tsx b/app/CheckMe/src/screens/teacher/AnswerKeysScreen.tsx index 905e406..af2fa4b 100644 --- a/app/CheckMe/src/screens/teacher/AnswerKeysScreen.tsx +++ b/app/CheckMe/src/screens/teacher/AnswerKeysScreen.tsx @@ -242,7 +242,7 @@ const AnswerKeysScreen: React.FC = ({ route }) => { {item.assessmentUid} - ❌ Not Scanned + Not Scanned @@ -273,7 +273,7 @@ const AnswerKeysScreen: React.FC = ({ route }) => { - ✅ Scanned + Scanned {hasImages && ( @@ -290,7 +290,7 @@ const AnswerKeysScreen: React.FC = ({ route }) => { {/* Scanned Images */} {hasImages && ( - 📄 Scanned Answer Key Images + Scanned Answer Key Images = ({ route }) => { /> Page {index + 1} - 🔍 + ))} diff --git a/app/CheckMe/src/screens/teacher/AssessmentScoreTableScreen.tsx b/app/CheckMe/src/screens/teacher/AssessmentScoreTableScreen.tsx index dbcde5a..9e65cc7 100644 --- a/app/CheckMe/src/screens/teacher/AssessmentScoreTableScreen.tsx +++ b/app/CheckMe/src/screens/teacher/AssessmentScoreTableScreen.tsx @@ -145,7 +145,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { msg += `${dirtyRows.length} answer${dirtyRows.length > 1 ? 's' : ''} edited.\n`; } msg += `New score: ${liveScore} / ${liveTotal} (${livePct}%)\n`; - msg += `Status: ${isFinal ? '✅ Final' : '⏳ Pending'}`; + msg += `Status: ${isFinal ? ' Final' : ' Pending'}`; if (isFinal && hasPendingRow) { msg += `\n\n⚠️ Some questions are still pending (essay). Marking as Final anyway — you can change this later.`; @@ -180,7 +180,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { Alert.alert( 'Saved', `Score: ${liveScore} / ${liveTotal} (${livePct}%)\n` + - `Status: ${isFinal ? 'Final ✅' : 'Pending ⏳'}` + `Status: ${isFinal ? 'Final ' : 'Pending '}` ); } catch (error: any) { Alert.alert('Error', error.message || 'Failed to save changes'); @@ -257,7 +257,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { - {isFinal ? '✅ Final Score' : '⏳ Pending'} + {isFinal ? ' Final Score' : ' Pending'} {isFinal @@ -314,7 +314,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { {/* ── Breakdown table ──────────────────── */} - 📝 Question Breakdown + Question Breakdown Q @@ -391,7 +391,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { style={[styles.essayBtn, row.editedResult === 'pending' && styles.essayBtnActivePending]} onPress={() => updateRow(index, 'editedResult', 'pending')} > - + ) : ( @@ -443,7 +443,7 @@ const AssessmentScoreTableScreen: React.FC = ({ route, navigation }) => { {liveScore} / {liveTotal} {rows.filter(r => r.isDirty).length} change{rows.filter(r => r.isDirty).length !== 1 ? 's' : ''} - {' '}· {isFinal ? '✅ Final' : '⏳ Pending'} + {' '}· {isFinal ? ' Final' : ' Pending'} = ({ navigation }) => { style={styles.generateCodeButton} onPress={handleOpenCodeModal} > - 🔑 Raspi Login + Raspi Login @@ -429,7 +429,7 @@ const DashboardScreen: React.FC = ({ navigation }) => { }} disabled={actionLoading} > - ℹ️ + 🛈 @@ -440,7 +440,7 @@ const DashboardScreen: React.FC = ({ navigation }) => { onPress={() => handleEditSection(section)} disabled={actionLoading} > - ✏️ + 🖊 = ({ navigation }) => { onPress={handleCopyCode} disabled={codeSecondsLeft === 0} > - 📋 Copy Code + Copy Code = ({ navigation }) => { {codeGenerating ? ( ) : ( - 🔑 Generate Code + Generate Code )} @@ -581,7 +581,7 @@ const DashboardScreen: React.FC = ({ navigation }) => { {actionLoading ? - : ✓ Save + : Save } setIsEditing(false)} disabled={actionLoading}> @@ -772,7 +772,7 @@ const DashboardScreen: React.FC = ({ navigation }) => { style={styles.copyButton} onPress={() => handleCopyToClipboard(selectedSectionForDetails?.id || '', 'Section ID')} > - 📋 Copy + Copy @@ -786,7 +786,7 @@ const DashboardScreen: React.FC = ({ navigation }) => { style={styles.copyButton} onPress={() => handleCopyToClipboard(selectedSectionForDetails?.teacherId || '', 'Teacher ID')} > - 📋 Copy + Copy diff --git a/app/CheckMe/src/screens/teacher/SectionDashboardScreen.tsx b/app/CheckMe/src/screens/teacher/SectionDashboardScreen.tsx index e85d1f7..c5fce79 100644 --- a/app/CheckMe/src/screens/teacher/SectionDashboardScreen.tsx +++ b/app/CheckMe/src/screens/teacher/SectionDashboardScreen.tsx @@ -262,7 +262,7 @@ const SectionDashboardScreen: React.FC = ({ route, navigation }) => { }} disabled={actionLoading} > - ℹ️ + 🛈 @@ -406,7 +406,7 @@ const SectionDashboardScreen: React.FC = ({ route, navigation }) => { {row.val} handleCopyToClipboard(row.val || '', row.label)}> - 📋 Copy + Copy diff --git a/app/CheckMe/src/screens/teacher/SubjectDashboardScreen.tsx b/app/CheckMe/src/screens/teacher/SubjectDashboardScreen.tsx index def1ffa..3f8f723 100644 --- a/app/CheckMe/src/screens/teacher/SubjectDashboardScreen.tsx +++ b/app/CheckMe/src/screens/teacher/SubjectDashboardScreen.tsx @@ -78,7 +78,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { const sorted = result.sort((a, b) => b.createdAt - a.createdAt); setAssessments(sorted); } catch (error: any) { - console.error('❌ [SubjectDashboard] Error loading assessments:', error); + console.error(' [SubjectDashboard] Error loading assessments:', error); setAssessments([]); } }; @@ -102,7 +102,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { const code = await getSubjectInviteCode(user.uid, subject.id); setInviteCode(code); } catch (error: any) { - console.error('❌ Error loading invite code:', error); + console.error(' Error loading invite code:', error); } }; @@ -329,7 +329,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { Invite Code: {inviteCode} - 📋 + )} @@ -347,7 +347,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { end={{ x: 1, y: 0 }} style={styles.gradientButton} > - 📝 Create Assessment + Create Assessment @@ -358,18 +358,18 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { Assessments - 🗝️ Answer Keys + Answer Keys {pendingEnrollments.length > 0 && ( - Pending ({pendingEnrollments.length}) 🔔 + Pending ({pendingEnrollments.length}) )} - Enrolled ({approvedEnrollments.length}) 👁️ + Enrolled ({approvedEnrollments.length}) @@ -554,7 +554,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { onPress={() => setIsEditingEnrollments(!isEditingEnrollments)} > - {isEditingEnrollments ? '✓ Done' : '✏️ Edit'} + {isEditingEnrollments ? ' Done' : ' Edit'} )} @@ -590,7 +590,7 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { {pendingEnrollments.length === 0 ? ( - + No pending requests ) : ( @@ -609,14 +609,14 @@ const SubjectDashboardScreen: React.FC = ({ route, navigation }) => { onPress={() => handleApproveEnrollment(enrollment)} disabled={actionLoading} > - ✓ Approve + Approve handleRejectEnrollment(enrollment)} disabled={actionLoading} > - ✕ Reject + Reject diff --git a/app/CheckMe/src/screens/teacher/ViewScoresScreen.tsx b/app/CheckMe/src/screens/teacher/ViewScoresScreen.tsx index 0ec4e3b..690e90a 100644 --- a/app/CheckMe/src/screens/teacher/ViewScoresScreen.tsx +++ b/app/CheckMe/src/screens/teacher/ViewScoresScreen.tsx @@ -347,7 +347,7 @@ const ViewScoresScreen: React.FC = ({ route, navigation }) => { ) : ( - ⏳ Pending + Pending )} @@ -396,7 +396,7 @@ const ViewScoresScreen: React.FC = ({ route, navigation }) => { {notScanned.length > 0 && ( - ⏳ Not Yet Scanned + Not Yet Scanned {notScanned.length} diff --git a/raspi_code/README.md b/raspi_code/README.md index 4a07b32..1daf9bc 100644 --- a/raspi_code/README.md +++ b/raspi_code/README.md @@ -43,7 +43,7 @@ CheckMe is an automated grading system that runs on a Raspberry Pi. It uses a fl | Raspberry Pi | Raspberry Pi 4B | | LCD Display | I2C LCD — 16x2 or 20x4 | | Keypad | 4x3 Matrix Keypad | -| Scanner | Epson L3210 | +| Scanner | Canon PIXMA MG2570S Scanner | --- @@ -100,7 +100,7 @@ raspi_code/ │ ├── auth.py # Teacher authentication │ ├── lcd_hardware.py # LCD I2C driver │ ├── keypad_hardware.py # 4x3 Keypad driver -│ ├── l3210_scanner_hardware.py # Epson L3210 scanner interface +│ ├── l3210_scanner_hardware.py # Canon PIXMA MG2570S Scanner interface │ ├── firebase_rtdb_client.py # Firebase RTDB (Admin SDK) │ ├── cloudinary_client.py # Cloudinary image uploader │ ├── gemini_client.py # Gemini OCR client @@ -117,7 +117,7 @@ raspi_code/ │ └── answer_sheets/ # Scanned student sheet images └── docs/ └── raspi/ - └── RASPI_L3210_SETUP.md # Scanner setup guide + └── RASPI_MG2570S_SETUP.md # Scanner setup guide ``` --- @@ -126,7 +126,7 @@ raspi_code/ - **Python:** 3.12 or above - **OS:** Raspberry Pi OS Desktop (Bookworm recommended) -- **System packages:** See `requirements.txt` and `docs/raspi/RASPI_L3210_SETUP.md` +- **System packages:** See `requirements.txt` and `docs/raspi/RASPI_MG2570S_SETUP.md` Enable I2C on your Raspberry Pi: ```bash @@ -159,7 +159,7 @@ pip install -r requirements.txt Follow the full scanner setup guide: ``` -docs/raspi/RASPI_L3210_SETUP.md +docs/raspi/RASPI_MG2570S__SETUP.md ``` **5. Set up Firebase credentials** @@ -289,7 +289,7 @@ Scoring features: | `auth.py` | Manages `cred.txt` session, validates 8-digit temp codes via Firebase | | `lcd_hardware.py` | I2C LCD driver with scrollable menus, multi-line display | | `keypad_hardware.py` | 4x3 matrix keypad GPIO driver with debounce | -| `l3210_scanner_hardware.py` | Epson L3210 scanner interface via SANE | +| `l3210_scanner_hardware.py` | Canon PIXMA MG2570S Scanner interface via SANE | | `firebase_rtdb_client.py` | Firebase Admin SDK RTDB client (answer keys, student results, temp codes) | | `cloudinary_client.py` | Single and batch image upload, delete | | `gemini_client.py` | Gemini OCR with retry logic | @@ -304,10 +304,10 @@ Scoring features: ## Scanner Setup -Full Epson L3210 setup instructions (SANE driver, permissions, testing): +Full Canon PIXMA MG2570S Scanner setup instructions (SANE driver, permissions, testing): ``` -docs/raspi/RASPI_L3210_SETUP.md +docs/raspi/RASPI_MG2570S_SETUP.md ``` ---