feat(Theme): enhance theming and UI consistency across components
- Updated app.json to set userInterfaceStyle to automatic for improved theme adaptability. - Refactored layout components to utilize useAppColors for dynamic theming, ensuring consistent color usage. - Introduced SystemChrome component to manage system UI background color based on theme. - Enhanced TabsLayout, ProfileStackLayout, and other components to leverage new theming structure. - Improved QRCodeScanner, SearchBar, and CommentItem styles to align with the updated theme system. - Consolidated styles in SystemMessageItem and TabBar for better maintainability and visual coherence.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
@@ -12,7 +12,7 @@ import { CameraView, useCameraPermissions } from 'expo-camera';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
||||
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
|
||||
|
||||
const { width, height } = Dimensions.get('window');
|
||||
|
||||
@@ -21,14 +21,130 @@ interface QRCodeScannerProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
function createQrScannerStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
camera: {
|
||||
flex: 1,
|
||||
},
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingTop: spacing.xl,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
closeButton: {
|
||||
padding: spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: fontSizes.lg,
|
||||
fontWeight: '600',
|
||||
color: '#fff',
|
||||
},
|
||||
placeholder: {
|
||||
width: 40,
|
||||
},
|
||||
scanArea: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scanFrame: {
|
||||
width: width * 0.7,
|
||||
height: width * 0.7,
|
||||
position: 'relative',
|
||||
},
|
||||
corner: {
|
||||
position: 'absolute',
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderColor: colors.primary.main,
|
||||
borderWidth: 3,
|
||||
},
|
||||
topLeft: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
borderRightWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
topRight: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
borderLeftWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
bottomLeft: {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
borderRightWidth: 0,
|
||||
borderTopWidth: 0,
|
||||
},
|
||||
bottomRight: {
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
borderLeftWidth: 0,
|
||||
borderTopWidth: 0,
|
||||
},
|
||||
scanText: {
|
||||
marginTop: spacing.lg,
|
||||
fontSize: fontSizes.md,
|
||||
color: '#fff',
|
||||
textAlign: 'center',
|
||||
},
|
||||
footer: {
|
||||
padding: spacing.xl,
|
||||
alignItems: 'center',
|
||||
},
|
||||
flashButton: {
|
||||
padding: spacing.md,
|
||||
backgroundColor: 'rgba(255,255,255,0.2)',
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
permissionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: spacing.xl,
|
||||
},
|
||||
permissionText: {
|
||||
marginTop: spacing.lg,
|
||||
fontSize: fontSizes.md,
|
||||
color: 'rgba(255,255,255,0.72)',
|
||||
textAlign: 'center',
|
||||
},
|
||||
permissionButton: {
|
||||
marginTop: spacing.xl,
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.xl,
|
||||
backgroundColor: colors.primary.main,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
permissionButtonText: {
|
||||
color: '#fff',
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export const QRCodeScanner: React.FC<QRCodeScannerProps> = ({ visible, onClose }) => {
|
||||
const router = useRouter();
|
||||
const themeColors = useAppColors();
|
||||
const styles = useMemo(() => createQrScannerStyles(themeColors), [themeColors]);
|
||||
const [permission, requestPermission] = useCameraPermissions();
|
||||
const [scanned, setScanned] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
// 重置扫描状态,确保每次打开都能重新扫描
|
||||
setScanned(false);
|
||||
if (!permission?.granted) {
|
||||
requestPermission();
|
||||
@@ -39,16 +155,11 @@ export const QRCodeScanner: React.FC<QRCodeScannerProps> = ({ visible, onClose }
|
||||
const handleBarCodeScanned = ({ type, data }: { type: string; data: string }) => {
|
||||
if (scanned) return;
|
||||
setScanned(true);
|
||||
|
||||
// 先关闭扫描界面,类似微信的做法
|
||||
onClose();
|
||||
|
||||
// 解析二维码内容
|
||||
// 格式: carrotbbs://qrcode/login?session_id=xxx
|
||||
if (data.startsWith('carrotbbs://qrcode/login')) {
|
||||
const sessionId = extractSessionId(data);
|
||||
if (sessionId) {
|
||||
// 跳转到确认页面
|
||||
router.push(hrefs.hrefQrLoginConfirm(sessionId));
|
||||
} else {
|
||||
Alert.alert('无效的二维码', '无法识别该二维码');
|
||||
@@ -79,7 +190,7 @@ export const QRCodeScanner: React.FC<QRCodeScannerProps> = ({ visible, onClose }
|
||||
<View style={styles.placeholder} />
|
||||
</View>
|
||||
<View style={styles.permissionContainer}>
|
||||
<MaterialCommunityIcons name="camera-off" size={64} color="#999" />
|
||||
<MaterialCommunityIcons name="camera-off" size={64} color="rgba(255,255,255,0.5)" />
|
||||
<Text style={styles.permissionText}>需要相机权限才能扫码</Text>
|
||||
<TouchableOpacity style={styles.permissionButton} onPress={requestPermission}>
|
||||
<Text style={styles.permissionButtonText}>授予权限</Text>
|
||||
@@ -132,117 +243,4 @@ export const QRCodeScanner: React.FC<QRCodeScannerProps> = ({ visible, onClose }
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#000',
|
||||
},
|
||||
camera: {
|
||||
flex: 1,
|
||||
},
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingTop: spacing.xl,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
closeButton: {
|
||||
padding: spacing.sm,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: fontSizes.lg,
|
||||
fontWeight: '600',
|
||||
color: '#fff',
|
||||
},
|
||||
placeholder: {
|
||||
width: 40,
|
||||
},
|
||||
scanArea: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scanFrame: {
|
||||
width: width * 0.7,
|
||||
height: width * 0.7,
|
||||
position: 'relative',
|
||||
},
|
||||
corner: {
|
||||
position: 'absolute',
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderColor: colors.primary.main,
|
||||
borderWidth: 3,
|
||||
},
|
||||
topLeft: {
|
||||
top: 0,
|
||||
left: 0,
|
||||
borderRightWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
topRight: {
|
||||
top: 0,
|
||||
right: 0,
|
||||
borderLeftWidth: 0,
|
||||
borderBottomWidth: 0,
|
||||
},
|
||||
bottomLeft: {
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
borderRightWidth: 0,
|
||||
borderTopWidth: 0,
|
||||
},
|
||||
bottomRight: {
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
borderLeftWidth: 0,
|
||||
borderTopWidth: 0,
|
||||
},
|
||||
scanText: {
|
||||
marginTop: spacing.lg,
|
||||
fontSize: fontSizes.md,
|
||||
color: '#fff',
|
||||
textAlign: 'center',
|
||||
},
|
||||
footer: {
|
||||
padding: spacing.xl,
|
||||
alignItems: 'center',
|
||||
},
|
||||
flashButton: {
|
||||
padding: spacing.md,
|
||||
backgroundColor: 'rgba(255,255,255,0.2)',
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
permissionContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: spacing.xl,
|
||||
},
|
||||
permissionText: {
|
||||
marginTop: spacing.lg,
|
||||
fontSize: fontSizes.md,
|
||||
color: '#666',
|
||||
textAlign: 'center',
|
||||
},
|
||||
permissionButton: {
|
||||
marginTop: spacing.xl,
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.xl,
|
||||
backgroundColor: colors.primary.main,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
permissionButtonText: {
|
||||
color: '#fff',
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
||||
export default QRCodeScanner;
|
||||
export default QRCodeScanner;
|
||||
|
||||
Reference in New Issue
Block a user