feat(service): add foreground service for background message sync
Implement Android foreground service to keep app alive in background for real-time message sync: - Add withForegroundService expo config plugin for notification channel setup - Add BackgroundSyncManager with REALTIME, BATTERY_SAVER, and DISABLED modes - Add ForegroundServiceModule for native Android foreground service binding - Refactor backgroundService to integrate foreground service and expo-background-task Also refactor auth and profile screens to use dynamic theme colors: - Replace hardcoded THEME_COLORS with colors.primary.main, colors.background.paper, etc. - Add useResolvedColorScheme for dynamic StatusBar styling - Update NotificationSettingsScreen with sync mode selection UI BREAKING CHANGE: Switched from expo-background-fetch to expo-background-task, minimum background sync interval changed from 900s to 15min in config
This commit is contained in:
@@ -26,12 +26,6 @@ import {
|
||||
import { showPrompt } from '../../services/promptService';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
|
||||
const THEME_COLORS = {
|
||||
primary: '#FF6B35',
|
||||
primaryLight: '#FF8C5A',
|
||||
primaryDark: '#E55A2B',
|
||||
};
|
||||
|
||||
const STATUS_CONFIG = {
|
||||
not_submitted: {
|
||||
title: '未认证',
|
||||
@@ -99,7 +93,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={THEME_COLORS.primary} />
|
||||
<ActivityIndicator size="large" color={colors.primary.main} />
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
);
|
||||
@@ -110,10 +104,11 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
const identityText = IDENTITY_TEXT[status?.identity || 'general'];
|
||||
|
||||
return (
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<SafeAreaView style={styles.container}>
|
||||
<ScrollView
|
||||
contentContainerStyle={styles.scrollContent}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
{/* 状态卡片 */}
|
||||
<View style={styles.statusCard}>
|
||||
<View style={[styles.statusIconContainer, { backgroundColor: statusConfig.color + '20' }]}>
|
||||
@@ -128,7 +123,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
|
||||
{status?.verification_status === 'approved' && (
|
||||
<View style={styles.identityBadge}>
|
||||
<MaterialCommunityIcons name="check-circle" size={16} color={THEME_COLORS.primary} />
|
||||
<MaterialCommunityIcons name="check-circle" size={16} color={colors.primary.main} />
|
||||
<Text style={styles.identityText}>{identityText}</Text>
|
||||
</View>
|
||||
)}
|
||||
@@ -153,7 +148,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
<MaterialCommunityIcons
|
||||
name="check-decagram"
|
||||
size={24}
|
||||
color={THEME_COLORS.primary}
|
||||
color={colors.primary.main}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.benefitContent}>
|
||||
@@ -169,7 +164,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
<MaterialCommunityIcons
|
||||
name="lock-open-outline"
|
||||
size={24}
|
||||
color={THEME_COLORS.primary}
|
||||
color={colors.primary.main}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.benefitContent}>
|
||||
@@ -185,7 +180,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
<MaterialCommunityIcons
|
||||
name="account-group-outline"
|
||||
size={24}
|
||||
color={THEME_COLORS.primary}
|
||||
color={colors.primary.main}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.benefitContent}>
|
||||
@@ -208,7 +203,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
onPress={handleStartVerification}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<MaterialCommunityIcons name="shield-check-outline" size={20} color="#FFF" />
|
||||
<MaterialCommunityIcons name="shield-check-outline" size={20} color={colors.primary.contrast} />
|
||||
<Text style={styles.primaryButtonText}>
|
||||
{status?.verification_status === 'rejected' ? '重新认证' : '开始认证'}
|
||||
</Text>
|
||||
@@ -221,7 +216,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
onPress={handleViewRecords}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<MaterialCommunityIcons name="file-document-outline" size={20} color={THEME_COLORS.primary} />
|
||||
<MaterialCommunityIcons name="file-document-outline" size={20} color={colors.primary.main} />
|
||||
<Text style={styles.secondaryButtonText}>查看认证记录</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
@@ -262,6 +257,7 @@ export const VerificationSettingsScreen: React.FC = () => {
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -269,7 +265,7 @@ function createStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#fff',
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
@@ -307,7 +303,7 @@ function createStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
paddingVertical: 32,
|
||||
paddingHorizontal: 24,
|
||||
backgroundColor: '#F9F9F9',
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: 16,
|
||||
marginBottom: 24,
|
||||
},
|
||||
@@ -334,7 +330,7 @@ function createStyles(colors: AppColors) {
|
||||
identityBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FFF5F0',
|
||||
backgroundColor: colors.primary.main + '15',
|
||||
borderRadius: 20,
|
||||
paddingVertical: 8,
|
||||
paddingHorizontal: 16,
|
||||
@@ -343,25 +339,25 @@ function createStyles(colors: AppColors) {
|
||||
identityText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: THEME_COLORS.primary,
|
||||
color: colors.primary.main,
|
||||
marginLeft: 6,
|
||||
},
|
||||
rejectReasonContainer: {
|
||||
marginTop: 16,
|
||||
padding: 12,
|
||||
backgroundColor: '#FFF3F3',
|
||||
backgroundColor: colors.error.light + '20',
|
||||
borderRadius: 8,
|
||||
width: '100%',
|
||||
},
|
||||
rejectReasonLabel: {
|
||||
fontSize: 13,
|
||||
fontWeight: '600',
|
||||
color: '#F44336',
|
||||
color: colors.error.main,
|
||||
marginBottom: 4,
|
||||
},
|
||||
rejectReasonText: {
|
||||
fontSize: 13,
|
||||
color: '#D32F2F',
|
||||
color: colors.error.dark,
|
||||
lineHeight: 18,
|
||||
},
|
||||
benefitsSection: {
|
||||
@@ -379,7 +375,7 @@ function createStyles(colors: AppColors) {
|
||||
benefitItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
backgroundColor: '#F9F9F9',
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
},
|
||||
@@ -387,7 +383,7 @@ function createStyles(colors: AppColors) {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '#FFF5F0',
|
||||
backgroundColor: colors.primary.main + '15',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: 12,
|
||||
@@ -415,12 +411,12 @@ function createStyles(colors: AppColors) {
|
||||
justifyContent: 'center',
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: THEME_COLORS.primary,
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
primaryButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: '#FFF',
|
||||
color: colors.text.inverse,
|
||||
marginLeft: 8,
|
||||
},
|
||||
secondaryButton: {
|
||||
@@ -429,18 +425,18 @@ function createStyles(colors: AppColors) {
|
||||
justifyContent: 'center',
|
||||
height: 56,
|
||||
borderRadius: 14,
|
||||
backgroundColor: '#FFF5F0',
|
||||
backgroundColor: colors.primary.main + '15',
|
||||
borderWidth: 1,
|
||||
borderColor: THEME_COLORS.primary,
|
||||
borderColor: colors.primary.main,
|
||||
},
|
||||
secondaryButtonText: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: THEME_COLORS.primary,
|
||||
color: colors.primary.main,
|
||||
marginLeft: 8,
|
||||
},
|
||||
verifiedInfo: {
|
||||
backgroundColor: '#F9F9F9',
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: 12,
|
||||
padding: 16,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user