From 46b421acf25363af34a16afd23958592854813d2 Mon Sep 17 00:00:00 2001 From: Rakshit Kumar Singh Date: Tue, 21 Apr 2026 03:43:46 +0530 Subject: [PATCH] light dark and font size and stripping (#7) * light dark and font size * striping * remove delete and rename buttons from main screen * add proguard rule --- android/app/build.gradle | 3 +- android/app/proguard-rules.pro | 3 + src/components/DocumentCard.tsx | 86 +++++--------------- src/components/FilterPicker.tsx | 38 ++++----- src/screens/HomeScreen.tsx | 60 +++++++------- src/screens/ReviewScreen.tsx | 86 ++++++-------------- src/screens/ScanScreen.tsx | 35 ++++---- src/screens/ViewerScreen.tsx | 140 ++++++++++++++------------------ src/theme.ts | 30 +++++++ 9 files changed, 204 insertions(+), 277 deletions(-) create mode 100644 src/theme.ts diff --git a/android/app/build.gradle b/android/app/build.gradle index f71f284..1ffeba7 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -48,7 +48,7 @@ react { /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ -def enableProguardInReleaseBuilds = false +def enableProguardInReleaseBuilds = true /** * The preferred build flavor of JavaScriptCore (JSC) @@ -94,6 +94,7 @@ android { // see https://reactnative.dev/docs/signed-apk-android. signingConfig signingConfigs.debug minifyEnabled enableProguardInReleaseBuilds + shrinkResources enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro index 11b0257..529e311 100644 --- a/android/app/proguard-rules.pro +++ b/android/app/proguard-rules.pro @@ -8,3 +8,6 @@ # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: + +# pdfbox optionally references this JP2 decoder which is not in our deps +-dontwarn com.gemalto.jp2.** diff --git a/src/components/DocumentCard.tsx b/src/components/DocumentCard.tsx index e9e2932..5218a03 100644 --- a/src/components/DocumentCard.tsx +++ b/src/components/DocumentCard.tsx @@ -2,23 +2,27 @@ import React from 'react'; import {View, Text, Image, TouchableOpacity, StyleSheet} from 'react-native'; import {ScannedDocument} from '../types'; import {formatDate} from '../utils/imageProcessing'; +import {useTheme} from '../theme'; interface Props { document: ScannedDocument; onPress: () => void; - onDelete: () => void; - onRename: () => void; } -export default function DocumentCard({document, onPress, onDelete, onRename}: Props) { +export default function DocumentCard({document, onPress}: Props) { + const t = useTheme(); const thumb = document.pages[0]?.uri; return ( - + {thumb ? ( ) : ( - + )} {document.pages.length > 1 && ( @@ -27,20 +31,12 @@ export default function DocumentCard({document, onPress, onDelete, onRename}: Pr )} - {document.name} - {formatDate(document.createdAt)} - + {document.name} + {formatDate(document.createdAt)} + {document.pages.length} {document.pages.length === 1 ? 'page' : 'pages'} - - - ✎ - - - βœ• - - ); } @@ -48,24 +44,15 @@ export default function DocumentCard({document, onPress, onDelete, onRename}: Pr const styles = StyleSheet.create({ card: { flexDirection: 'row', - backgroundColor: '#1c1c1e', borderRadius: 12, + borderWidth: StyleSheet.hairlineWidth, marginHorizontal: 16, marginVertical: 6, overflow: 'hidden', elevation: 2, }, - thumbContainer: { - width: 80, - height: 100, - }, - thumb: { - width: 80, - height: 100, - }, - placeholder: { - backgroundColor: '#333', - }, + thumbContainer: {width: 80, height: 100}, + thumb: {width: 80, height: 100}, badge: { position: 'absolute', bottom: 4, @@ -78,43 +65,8 @@ const styles = StyleSheet.create({ justifyContent: 'center', paddingHorizontal: 4, }, - badgeText: { - color: '#fff', - fontSize: 11, - fontWeight: '700', - }, - info: { - flex: 1, - padding: 12, - justifyContent: 'center', - }, - name: { - color: '#fff', - fontSize: 15, - fontWeight: '600', - marginBottom: 4, - }, - date: { - color: '#888', - fontSize: 12, - marginBottom: 2, - }, - pages: { - color: '#666', - fontSize: 12, - }, - actions: { - padding: 12, - justifyContent: 'center', - gap: 16, - }, - renameText: { - color: '#007AFF', - fontSize: 18, - }, - deleteText: { - color: '#ff453a', - fontSize: 16, - fontWeight: '600', - }, + badgeText: {color: '#fff', fontSize: 11, fontWeight: '700'}, + info: {flex: 1, padding: 12, justifyContent: 'center', gap: 3}, + name: {fontSize: 15, fontWeight: '600'}, + meta: {fontSize: 13}, }); diff --git a/src/components/FilterPicker.tsx b/src/components/FilterPicker.tsx index 1db336a..b4d97cd 100644 --- a/src/components/FilterPicker.tsx +++ b/src/components/FilterPicker.tsx @@ -1,6 +1,7 @@ import React from 'react'; import {View, Text, TouchableOpacity, StyleSheet} from 'react-native'; import {FilterMode} from '../types'; +import {useTheme} from '../theme'; const FILTERS: {label: string; value: FilterMode}[] = [ {label: 'Original', value: 'original'}, @@ -15,14 +16,23 @@ interface Props { } export default function FilterPicker({selected, onChange}: Props) { + const t = useTheme(); return ( - + {FILTERS.map(f => ( onChange(f.value)}> - + {f.label} @@ -36,26 +46,14 @@ const styles = StyleSheet.create({ flexDirection: 'row', justifyContent: 'center', gap: 8, - paddingVertical: 10, - backgroundColor: '#1c1c1e', + paddingVertical: 12, + borderTopWidth: StyleSheet.hairlineWidth, }, chip: { - paddingHorizontal: 14, - paddingVertical: 6, + paddingHorizontal: 16, + paddingVertical: 7, borderRadius: 20, borderWidth: 1, - borderColor: '#444', - }, - chipActive: { - backgroundColor: '#007AFF', - borderColor: '#007AFF', - }, - label: { - color: '#aaa', - fontSize: 13, - fontWeight: '500', - }, - labelActive: { - color: '#fff', }, + label: {fontSize: 14, fontWeight: '500'}, }); diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 6a9a01a..fd5ffbc 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -12,6 +12,7 @@ import { } from 'react-native'; import {ScannedDocument} from '../types'; import DocumentCard from '../components/DocumentCard'; +import {useTheme} from '../theme'; interface Props { documents: ScannedDocument[]; @@ -22,6 +23,7 @@ interface Props { } export default function HomeScreen({documents, onScan, onView, onDelete, onRename}: Props) { + const t = useTheme(); const [renameTarget, setRenameTarget] = useState(null); const [renameText, setRenameText] = useState(''); @@ -45,18 +47,22 @@ export default function HomeScreen({documents, onScan, onView, onDelete, onRenam }; return ( - - - - Lens - {documents.length} document{documents.length !== 1 ? 's' : ''} + + + + Lens + + {documents.length} document{documents.length !== 1 ? 's' : ''} + {documents.length === 0 ? ( πŸ“„ - No scans yet - Tap the button below to scan a document + No scans yet + + Tap the button below to scan a document + ) : ( onView(item)} - onDelete={() => confirmDelete(item)} - onRename={() => startRename(item)} /> )} contentContainerStyle={styles.list} @@ -82,23 +86,23 @@ export default function HomeScreen({documents, onScan, onView, onDelete, onRenam - - Rename Document + + Rename Document setRenameTarget(null)} style={styles.modalBtn}> - Cancel + Cancel - Rename + Rename @@ -109,21 +113,20 @@ export default function HomeScreen({documents, onScan, onView, onDelete, onRenam } const styles = StyleSheet.create({ - container: {flex: 1, backgroundColor: '#000'}, + container: {flex: 1}, header: { paddingTop: 56, paddingHorizontal: 20, paddingBottom: 16, - borderBottomWidth: 1, - borderBottomColor: '#222', + borderBottomWidth: StyleSheet.hairlineWidth, }, - title: {color: '#fff', fontSize: 32, fontWeight: '700'}, - subtitle: {color: '#666', fontSize: 14, marginTop: 2}, + title: {fontSize: 32, fontWeight: '700'}, + subtitle: {fontSize: 15, marginTop: 2}, list: {paddingTop: 8, paddingBottom: 100}, empty: {flex: 1, alignItems: 'center', justifyContent: 'center', gap: 8}, emptyIcon: {fontSize: 64}, - emptyTitle: {color: '#fff', fontSize: 20, fontWeight: '600'}, - emptyHint: {color: '#666', fontSize: 14}, + emptyTitle: {fontSize: 20, fontWeight: '600'}, + emptyHint: {fontSize: 15}, fab: { position: 'absolute', bottom: 32, @@ -142,18 +145,17 @@ const styles = StyleSheet.create({ }, fabIcon: {color: '#fff', fontSize: 22}, fabLabel: {color: '#fff', fontSize: 17, fontWeight: '600'}, - modalBg: {flex: 1, backgroundColor: 'rgba(0,0,0,0.7)', justifyContent: 'center', padding: 24}, - modalBox: {backgroundColor: '#1c1c1e', borderRadius: 16, padding: 20, gap: 16}, - modalTitle: {color: '#fff', fontSize: 17, fontWeight: '600'}, + modalBg: {flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', padding: 24}, + modalBox: {borderRadius: 16, padding: 20, gap: 16}, + modalTitle: {fontSize: 17, fontWeight: '600'}, modalInput: { - backgroundColor: '#2c2c2e', + borderWidth: StyleSheet.hairlineWidth, borderRadius: 10, padding: 12, - color: '#fff', fontSize: 15, }, modalActions: {flexDirection: 'row', justifyContent: 'flex-end', gap: 16}, modalBtn: {padding: 4}, - modalCancel: {color: '#888', fontSize: 15}, - modalConfirm: {color: '#007AFF', fontSize: 15, fontWeight: '600'}, + modalCancel: {fontSize: 15}, + modalConfirm: {fontSize: 15, fontWeight: '600'}, }); diff --git a/src/screens/ReviewScreen.tsx b/src/screens/ReviewScreen.tsx index 8f63007..15e33c4 100644 --- a/src/screens/ReviewScreen.tsx +++ b/src/screens/ReviewScreen.tsx @@ -7,11 +7,11 @@ import { TouchableOpacity, StyleSheet, Dimensions, - Alert, StatusBar, } from 'react-native'; import {ScannedPage, FilterMode} from '../types'; import FilterPicker from '../components/FilterPicker'; +import {useTheme} from '../theme'; const {width: SW} = Dimensions.get('window'); @@ -23,17 +23,10 @@ interface Props { } export default function ReviewScreen({pages, onSave, onAddMore, onCancel}: Props) { + const t = useTheme(); const [filter, setFilter] = useState('original'); const [currentIndex, setCurrentIndex] = useState(0); - const filterStyle = () => { - switch (filter) { - case 'grayscale': return {opacity: 0.85, tintColor: undefined}; - case 'blackwhite': return {opacity: 1}; - default: return {}; - } - }; - const imageContainerStyle = () => { switch (filter) { case 'grayscale': return styles.filterGrayscale; @@ -44,25 +37,21 @@ export default function ReviewScreen({pages, onSave, onAddMore, onCancel}: Props }; return ( - - + + - {/* Header */} - + - Cancel + Cancel - + {currentIndex + 1} / {pages.length} - onSave(pages, filter)} - style={styles.saveBtn}> + onSave(pages, filter)} style={styles.saveBtn}> Save - {/* Page viewer */} ( - + ))} - {/* Dot indicators */} {pages.length > 1 && ( {pages.map((_, i) => ( ))} )} - {/* Filter picker */} - {/* Bottom actions */} - - - + - Add Page + + + + + Add Page onSave(pages, filter)}> - - Save Document - + Save Document @@ -118,7 +98,7 @@ export default function ReviewScreen({pages, onSave, onAddMore, onCancel}: Props } const styles = StyleSheet.create({ - container: {flex: 1, backgroundColor: '#000'}, + container: {flex: 1}, header: { flexDirection: 'row', alignItems: 'center', @@ -126,12 +106,11 @@ const styles = StyleSheet.create({ paddingTop: 52, paddingHorizontal: 16, paddingBottom: 12, - borderBottomWidth: 1, - borderBottomColor: '#222', + borderBottomWidth: StyleSheet.hairlineWidth, }, headerBtn: {padding: 4}, - headerBtnText: {color: '#007AFF', fontSize: 16}, - headerTitle: {color: '#fff', fontSize: 16, fontWeight: '600'}, + headerBtnText: {fontSize: 16}, + headerTitle: {fontSize: 16, fontWeight: '600'}, saveBtn: { backgroundColor: '#007AFF', paddingHorizontal: 16, @@ -146,34 +125,20 @@ const styles = StyleSheet.create({ justifyContent: 'center', padding: 16, }, - imageWrapper: { - flex: 1, - width: '100%', - borderRadius: 8, - overflow: 'hidden', - }, + imageWrapper: {flex: 1, width: '100%', borderRadius: 8, overflow: 'hidden'}, pageImage: {flex: 1, width: '100%'}, filterGrayscale: {opacity: 0.9}, filterBW: {opacity: 1}, filterEnhanced: {opacity: 1}, - dots: { - flexDirection: 'row', - justifyContent: 'center', - gap: 6, - paddingVertical: 8, - }, - dot: { - width: 6, - height: 6, - borderRadius: 3, - backgroundColor: '#444', - }, + dots: {flexDirection: 'row', justifyContent: 'center', gap: 6, paddingVertical: 8}, + dot: {width: 6, height: 6, borderRadius: 3}, dotActive: {backgroundColor: '#007AFF', width: 18}, bottomActions: { flexDirection: 'row', gap: 12, padding: 16, paddingBottom: 32, + borderTopWidth: StyleSheet.hairlineWidth, }, actionBtn: { flex: 1, @@ -184,14 +149,13 @@ const styles = StyleSheet.create({ paddingVertical: 14, borderRadius: 14, borderWidth: 1, - borderColor: '#333', }, actionBtnPrimary: { backgroundColor: '#007AFF', borderColor: '#007AFF', flex: 2, }, - actionIcon: {color: '#007AFF', fontSize: 20, fontWeight: '600'}, - actionLabel: {color: '#007AFF', fontSize: 15, fontWeight: '500'}, + actionIcon: {fontSize: 20, fontWeight: '600'}, + actionLabel: {fontSize: 15, fontWeight: '500'}, actionLabelPrimary: {color: '#fff', fontWeight: '600'}, }); diff --git a/src/screens/ScanScreen.tsx b/src/screens/ScanScreen.tsx index 428492f..131471f 100644 --- a/src/screens/ScanScreen.tsx +++ b/src/screens/ScanScreen.tsx @@ -11,6 +11,7 @@ import { import DocumentScanner, {ResponseType} from 'react-native-document-scanner-plugin'; import RNFS from 'react-native-fs'; import {ScannedPage} from '../types'; +import {useTheme} from '../theme'; interface Props { onComplete: (pages: ScannedPage[]) => void; @@ -31,9 +32,9 @@ async function copyToPermanent(tempUri: string): Promise { } export default function ScanScreen({onComplete, onCancel}: Props) { + const t = useTheme(); const [scanning, setScanning] = useState(false); const [pageCount, setPageCount] = useState(0); - // Use a ref so the Alert closure always reads the latest pages without stale capture const pagesRef = useRef([]); const scan = useCallback(async () => { @@ -58,7 +59,6 @@ export default function ScanScreen({onComplete, onCancel}: Props) { return; } - // Copy temp files to permanent storage before the OS clears them const permanentUris = await Promise.all(scannedImages.map(copyToPermanent)); const newPages: ScannedPage[] = permanentUris.map(uri => ({ @@ -92,25 +92,23 @@ export default function ScanScreen({onComplete, onCancel}: Props) { }, []); return ( - - + + {scanning && ( - - Opening camera… + + Opening camera… )} {!scanning && pageCount > 0 && ( - {pageCount} - pages ready + {pageCount} + pages ready - - Add More + + Add More - onComplete(pagesRef.current)}> + onComplete(pagesRef.current)}> Finish @@ -121,11 +119,11 @@ export default function ScanScreen({onComplete, onCancel}: Props) { } const styles = StyleSheet.create({ - container: {flex: 1, backgroundColor: '#000'}, + container: {flex: 1}, center: {flex: 1, alignItems: 'center', justifyContent: 'center', gap: 12}, - hint: {color: '#888', fontSize: 15, marginTop: 12}, - count: {color: '#fff', fontSize: 72, fontWeight: '700'}, - pagesLabel: {color: '#888', fontSize: 18}, + hint: {fontSize: 15, marginTop: 12}, + count: {fontSize: 72, fontWeight: '700'}, + pagesLabel: {fontSize: 18}, actions: {flexDirection: 'row', gap: 16, marginTop: 24}, btnPrimary: { backgroundColor: '#007AFF', @@ -136,10 +134,9 @@ const styles = StyleSheet.create({ btnPrimaryText: {color: '#fff', fontSize: 16, fontWeight: '600'}, btnSecondary: { borderWidth: 1, - borderColor: '#007AFF', paddingHorizontal: 32, paddingVertical: 14, borderRadius: 28, }, - btnSecondaryText: {color: '#007AFF', fontSize: 16, fontWeight: '600'}, + btnSecondaryText: {fontSize: 16, fontWeight: '600'}, }); diff --git a/src/screens/ViewerScreen.tsx b/src/screens/ViewerScreen.tsx index 8536910..fccd840 100644 --- a/src/screens/ViewerScreen.tsx +++ b/src/screens/ViewerScreen.tsx @@ -16,6 +16,7 @@ import { import Share from 'react-native-share'; import {ScannedDocument} from '../types'; import {generatePdf} from '../utils/generatePdf'; +import {useTheme} from '../theme'; const {width: SW} = Dimensions.get('window'); @@ -27,6 +28,7 @@ interface Props { } export default function ViewerScreen({document, onBack, onDelete, onRename}: Props) { + const t = useTheme(); const [currentIndex, setCurrentIndex] = useState(0); const [generating, setGenerating] = useState(false); const [renaming, setRenaming] = useState(false); @@ -35,22 +37,17 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro const sharePdf = async (pageIndices?: number[]) => { setGenerating(true); try { - const pages = - pageIndices - ? pageIndices.map(i => document.pages[i]).filter(Boolean) - : document.pages; - - const label = - pageIndices?.length === 1 - ? `${document.name} β€” page ${pageIndices[0] + 1}` - : document.name; - + const pages = pageIndices + ? pageIndices.map(i => document.pages[i]).filter(Boolean) + : document.pages; + const label = pageIndices?.length === 1 + ? `${document.name} β€” page ${pageIndices[0] + 1}` + : document.name; const pdfPath = await generatePdf(pages, label); - await Share.open({ title: label, type: 'application/pdf', - url: pdfPath, // already normalised to file:// by generatePdf + url: pdfPath, failOnCancel: false, }); } catch (err: any) { @@ -68,16 +65,16 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro }; return ( - - + + - + - β€Ή Back + β€Ή Back - {document.name} - + {document.name} + {currentIndex + 1} / {document.pages.length} @@ -86,7 +83,7 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro onPress={() => sharePdf()} style={styles.headerBtn} disabled={generating}> - Share PDF + Share PDF @@ -105,7 +102,7 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro style={styles.pageImage} resizeMode="contain" /> - Page {i + 1} + Page {i + 1} ))} @@ -113,33 +110,32 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro {document.pages.length > 1 && ( {document.pages.map((_, i) => ( - + ))} )} - - sharePdf([currentIndex])} - disabled={generating}> - ⬆ - Share Page + + sharePdf([currentIndex])} disabled={generating}> + ⬆ + Share Page + + sharePdf()} disabled={generating}> + πŸ“„ + Share All sharePdf()} - disabled={generating}> - πŸ“„ - Share All + onPress={() => {setRenameText(document.name); setRenaming(true);}}> + ✎ + Rename - { setRenameText(document.name); setRenaming(true); }}> - ✎ - Rename - - - πŸ—‘ - Delete + + πŸ—‘ + Delete @@ -152,19 +148,19 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro - - Rename Document + + Rename Document setRenaming(false)} style={styles.modalBtn}> - Cancel + Cancel { @@ -172,7 +168,7 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro setRenaming(false); }} style={styles.modalBtn}> - Rename + Rename @@ -183,22 +179,21 @@ export default function ViewerScreen({document, onBack, onDelete, onRename}: Pro } const styles = StyleSheet.create({ - container: {flex: 1, backgroundColor: '#000'}, + container: {flex: 1}, header: { flexDirection: 'row', alignItems: 'center', paddingTop: 52, paddingHorizontal: 16, paddingBottom: 12, - borderBottomWidth: 1, - borderBottomColor: '#222', + borderBottomWidth: StyleSheet.hairlineWidth, }, headerBtn: {minWidth: 60}, headerCenter: {flex: 1, alignItems: 'center'}, - back: {color: '#007AFF', fontSize: 17}, - title: {color: '#fff', fontSize: 15, fontWeight: '600'}, - subtitle: {color: '#666', fontSize: 12, marginTop: 2}, - shareText: {color: '#007AFF', fontSize: 15, textAlign: 'right'}, + back: {fontSize: 17}, + title: {fontSize: 15, fontWeight: '600'}, + subtitle: {fontSize: 13, marginTop: 2}, + shareText: {fontSize: 15, textAlign: 'right'}, pageContainer: { width: SW, flex: 1, @@ -207,32 +202,18 @@ const styles = StyleSheet.create({ padding: 16, }, pageImage: {flex: 1, width: '100%', borderRadius: 4}, - pageNum: {color: '#444', fontSize: 12, marginTop: 8}, - dots: { - flexDirection: 'row', - justifyContent: 'center', - gap: 6, - paddingVertical: 8, - }, - dot: {width: 6, height: 6, borderRadius: 3, backgroundColor: '#333'}, + pageNum: {fontSize: 13, marginTop: 8}, + dots: {flexDirection: 'row', justifyContent: 'center', gap: 6, paddingVertical: 8}, + dot: {width: 6, height: 6, borderRadius: 3}, dotActive: {backgroundColor: '#007AFF', width: 18}, toolbar: { flexDirection: 'row', - borderTopWidth: 1, - borderTopColor: '#222', + borderTopWidth: StyleSheet.hairlineWidth, paddingBottom: 32, }, - toolBtn: { - flex: 1, - alignItems: 'center', - paddingVertical: 14, - gap: 4, - }, - toolBtnDanger: {}, - toolIcon: {fontSize: 20, color: '#007AFF'}, - toolIconDanger: {color: '#ff453a'}, - toolLabel: {fontSize: 11, color: '#007AFF'}, - toolLabelDanger: {color: '#ff453a'}, + toolBtn: {flex: 1, alignItems: 'center', paddingVertical: 14, gap: 4}, + toolIcon: {fontSize: 20}, + toolLabel: {fontSize: 13}, loadingOverlay: { ...StyleSheet.absoluteFillObject, backgroundColor: 'rgba(0,0,0,0.65)', @@ -241,18 +222,17 @@ const styles = StyleSheet.create({ gap: 12, }, loadingText: {color: '#fff', fontSize: 15}, - modalBg: {flex: 1, backgroundColor: 'rgba(0,0,0,0.7)', justifyContent: 'center', padding: 24}, - modalBox: {backgroundColor: '#1c1c1e', borderRadius: 16, padding: 20, gap: 16}, - modalTitle: {color: '#fff', fontSize: 17, fontWeight: '600'}, + modalBg: {flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', padding: 24}, + modalBox: {borderRadius: 16, padding: 20, gap: 16}, + modalTitle: {fontSize: 17, fontWeight: '600'}, modalInput: { - backgroundColor: '#2c2c2e', + borderWidth: StyleSheet.hairlineWidth, borderRadius: 10, padding: 12, - color: '#fff', fontSize: 15, }, modalActions: {flexDirection: 'row', justifyContent: 'flex-end', gap: 16}, modalBtn: {padding: 4}, - modalCancel: {color: '#888', fontSize: 15}, - modalConfirm: {color: '#007AFF', fontSize: 15, fontWeight: '600'}, + modalCancel: {fontSize: 15}, + modalConfirm: {fontSize: 15, fontWeight: '600'}, }); diff --git a/src/theme.ts b/src/theme.ts new file mode 100644 index 0000000..5e079b4 --- /dev/null +++ b/src/theme.ts @@ -0,0 +1,30 @@ +import {useColorScheme} from 'react-native'; + +const dark = { + bg: '#000000', + surface: '#1c1c1e', + text: '#ffffff', + textSecondary: '#8e8e93', + border: '#2c2c2e', + accent: '#007AFF', + danger: '#ff453a', + statusBar: 'light-content' as const, +}; + +const light = { + bg: '#f2f2f7', + surface: '#ffffff', + text: '#000000', + textSecondary: '#636366', + border: '#d1d1d6', + accent: '#007AFF', + danger: '#ff3b30', + statusBar: 'dark-content' as const, +}; + +export type Theme = typeof dark; + +export function useTheme(): Theme { + const scheme = useColorScheme(); + return scheme === 'dark' ? dark : light; +}