feat(CommentItem, PostDetailScreen, ReportDialog): integrate report functionality
- Added report button to CommentItem for reporting comments and replies. - Integrated ReportDialog into PostDetailScreen for handling report submissions. - Enhanced ReportDialog with detailed report reasons and improved UI interactions. - Updated styles across various components for a more modern look and feel. Made-with: Cursor
This commit is contained in:
@@ -215,6 +215,7 @@ const CommentItem: React.FC<CommentItemProps> = ({
|
||||
onDelete,
|
||||
onImagePress,
|
||||
currentUserId,
|
||||
onReport,
|
||||
}) => {
|
||||
const colors = useAppColors();
|
||||
const styles = useMemo(() => createCommentItemStyles(colors), [colors]);
|
||||
@@ -541,6 +542,18 @@ const CommentItem: React.FC<CommentItemProps> = ({
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
{/* 举报按钮 - 对非子评论作者显示 */}
|
||||
{!isSubReplyAuthor && onReport && (
|
||||
<TouchableOpacity
|
||||
style={styles.subActionButton}
|
||||
onPress={() => onReport(reply)}
|
||||
>
|
||||
<MaterialCommunityIcons name="flag-outline" size={12} color={colors.text.hint} />
|
||||
<Text variant="caption" color={colors.text.hint} style={styles.subActionText}>
|
||||
举报
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
@@ -635,6 +648,19 @@ const CommentItem: React.FC<CommentItemProps> = ({
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* 举报按钮 - 只对非评论作者显示 */}
|
||||
{!isCommentAuthor && onReport && (
|
||||
<TouchableOpacity
|
||||
style={styles.actionButton}
|
||||
onPress={() => onReport(comment)}
|
||||
>
|
||||
<MaterialCommunityIcons name="flag-outline" size={14} color={colors.text.hint} />
|
||||
<Text variant="caption" color={colors.text.hint} style={styles.actionText}>
|
||||
举报
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* 删除按钮 - 只对评论作者显示 */}
|
||||
{isCommentAuthor && (
|
||||
<TouchableOpacity
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
/**
|
||||
* 举报对话框组件
|
||||
* 支持举报帖子、评论、消息
|
||||
* 提供友好的用户界面和流畅的交互体验
|
||||
*/
|
||||
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState, useCallback, useMemo } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TextInput,
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Platform,
|
||||
KeyboardAvoidingView,
|
||||
} from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useAppColors } from '../../../theme';
|
||||
import { spacing, borderRadius, fontSizes } from '../../../theme';
|
||||
import { spacing, borderRadius, fontSizes, shadows } from '../../../theme';
|
||||
import reportService, { ReportReason, ReportTargetType, REPORT_REASONS } from '../../../services/reportService';
|
||||
import Text from '../../common/Text';
|
||||
|
||||
export interface ReportDialogProps {
|
||||
visible: boolean;
|
||||
@@ -28,14 +31,23 @@ export interface ReportDialogProps {
|
||||
onSuccess?: () => void;
|
||||
}
|
||||
|
||||
// 目标类型中文名称映射
|
||||
const TARGET_TYPE_LABELS: Record<ReportTargetType, string> = {
|
||||
post: '帖子',
|
||||
comment: '评论',
|
||||
message: '消息',
|
||||
// 目标类型配置
|
||||
const TARGET_CONFIG: Record<ReportTargetType, { label: string; icon: string; color: string }> = {
|
||||
post: { label: '帖子', icon: 'file-document-outline', color: '#FF6B35' },
|
||||
comment: { label: '评论', icon: 'comment-text-outline', color: '#4CAF50' },
|
||||
message: { label: '消息', icon: 'message-text-outline', color: '#2196F3' },
|
||||
};
|
||||
|
||||
export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
// 举报原因详细配置(带图标和说明)
|
||||
const REPORT_REASONS_DETAILED = [
|
||||
{ value: 'spam' as ReportReason, label: '垃圾广告', icon: 'email-newsletter', description: '包含广告、推广或重复内容' },
|
||||
{ value: 'inappropriate' as ReportReason, label: '违规内容', icon: 'alert-circle-outline', description: '包含违法、色情或暴力内容' },
|
||||
{ value: 'harassment' as ReportReason, label: '辱骂攻击', icon: 'account-off-outline', description: '包含人身攻击、骚扰或歧视' },
|
||||
{ value: 'misinformation' as ReportReason, label: '虚假信息', icon: 'alert-outline', description: '包含谣言、诈骗或误导信息' },
|
||||
{ value: 'other' as ReportReason, label: '其他原因', icon: 'dots-horizontal-circle-outline', description: '其他需要举报的情况' },
|
||||
];
|
||||
|
||||
const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
visible,
|
||||
targetType,
|
||||
targetId,
|
||||
@@ -48,10 +60,23 @@ export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
const [description, setDescription] = useState('');
|
||||
const [submitting, setSubmitting] = useState(false);
|
||||
|
||||
const targetConfig = TARGET_CONFIG[targetType];
|
||||
|
||||
// 判断补充说明是否必填(选择"其他原因"时必填)
|
||||
const isDescriptionRequired = selectedReason === 'other';
|
||||
const descriptionPlaceholder = isDescriptionRequired
|
||||
? '请详细描述您举报的原因(必填)...'
|
||||
: '请提供更多详细信息(选填)...';
|
||||
|
||||
// 提交举报
|
||||
const handleSubmit = useCallback(async () => {
|
||||
if (!selectedReason) {
|
||||
Alert.alert('提示', '请选择举报原因');
|
||||
Alert.alert('提示', '请选择举报原因', [{ text: '确定' }]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isDescriptionRequired && !description.trim()) {
|
||||
Alert.alert('提示', '请选择"其他原因"时,请详细描述举报原因', [{ text: '确定' }]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,11 +100,11 @@ export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
Alert.alert('举报失败', '请稍后重试');
|
||||
Alert.alert('举报失败', '请稍后重试', [{ text: '确定' }]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Submit report error:', error);
|
||||
Alert.alert('举报失败', '网络错误,请稍后重试');
|
||||
Alert.alert('举报失败', '网络错误,请稍后重试', [{ text: '确定' }]);
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
@@ -92,6 +117,11 @@ export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
|
||||
const selectedReasonData = useMemo(
|
||||
() => REPORT_REASONS_DETAILED.find(r => r.value === selectedReason),
|
||||
[selectedReason]
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
@@ -99,99 +129,153 @@ export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
animationType="fade"
|
||||
onRequestClose={handleClose}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.container}>
|
||||
{/* 头部 */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>
|
||||
举报{TARGET_TYPE_LABELS[targetType]}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.closeButton}
|
||||
onPress={handleClose}
|
||||
disabled={submitting}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name="close"
|
||||
size={24}
|
||||
color={colors.textSecondary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* 内容 */}
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* 举报原因选择 */}
|
||||
<Text style={styles.sectionTitle}>请选择举报原因</Text>
|
||||
<View style={styles.reasonList}>
|
||||
{REPORT_REASONS.map((item) => (
|
||||
<TouchableOpacity
|
||||
key={item.value}
|
||||
style={[
|
||||
styles.reasonItem,
|
||||
selectedReason === item.value && styles.reasonItemSelected,
|
||||
]}
|
||||
onPress={() => setSelectedReason(item.value)}
|
||||
disabled={submitting}
|
||||
>
|
||||
<View style={styles.radioContainer}>
|
||||
<View
|
||||
style={[
|
||||
styles.radio,
|
||||
selectedReason === item.value && styles.radioSelected,
|
||||
]}
|
||||
>
|
||||
{selectedReason === item.value && (
|
||||
<View style={styles.radioDot} />
|
||||
)}
|
||||
</View>
|
||||
<Text style={styles.reasonLabel}>{item.label}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
<KeyboardAvoidingView
|
||||
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
||||
style={styles.keyboardView}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={styles.container}>
|
||||
{/* 头部 */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerContent}>
|
||||
<View style={[styles.headerIcon, { backgroundColor: targetConfig.color + '15' }]}>
|
||||
<MaterialCommunityIcons
|
||||
name={targetConfig.icon as any}
|
||||
size={20}
|
||||
color={targetConfig.color}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.headerText}>
|
||||
<Text style={styles.title}>举报{targetConfig.label}</Text>
|
||||
<Text style={styles.subtitle}>请选择合适的举报原因</Text>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={styles.closeButton}
|
||||
onPress={handleClose}
|
||||
disabled={submitting}
|
||||
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name="close"
|
||||
size={24}
|
||||
color={colors.chat.textSecondary}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* 补充说明 */}
|
||||
<Text style={styles.sectionTitle}>补充说明(选填)</Text>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
placeholder="请提供更多详细信息..."
|
||||
placeholderTextColor={colors.textTertiary}
|
||||
multiline
|
||||
maxLength={500}
|
||||
value={description}
|
||||
onChangeText={setDescription}
|
||||
editable={!submitting}
|
||||
/>
|
||||
<Text style={styles.charCount}>{description.length}/500</Text>
|
||||
</ScrollView>
|
||||
{/* 内容 */}
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
{/* 举报原因选择 */}
|
||||
<View style={styles.section}>
|
||||
<Text style={styles.sectionTitle}>举报原因</Text>
|
||||
<View style={styles.reasonList}>
|
||||
{REPORT_REASONS_DETAILED.map((item) => (
|
||||
<TouchableOpacity
|
||||
key={item.value}
|
||||
style={[
|
||||
styles.reasonItem,
|
||||
selectedReason === item.value && [
|
||||
styles.reasonItemSelected,
|
||||
{ borderColor: colors.primary.main + '40' }
|
||||
],
|
||||
]}
|
||||
onPress={() => setSelectedReason(item.value)}
|
||||
disabled={submitting}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.reasonLeft}>
|
||||
<View
|
||||
style={[
|
||||
styles.reasonIcon,
|
||||
selectedReason === item.value && styles.reasonIconSelected,
|
||||
]}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name={item.icon as any}
|
||||
size={20}
|
||||
color={selectedReason === item.value ? colors.primary.main : colors.chat.textSecondary}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.reasonTextContainer}>
|
||||
<Text style={[
|
||||
styles.reasonLabel,
|
||||
...(selectedReason === item.value ? [styles.reasonLabelSelected] : []),
|
||||
]}>
|
||||
{item.label}
|
||||
</Text>
|
||||
<Text style={styles.reasonDescription}>{item.description}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View
|
||||
style={[
|
||||
styles.radio,
|
||||
selectedReason === item.value && styles.radioSelected,
|
||||
]}
|
||||
>
|
||||
{selectedReason === item.value && (
|
||||
<View style={styles.radioDot} />
|
||||
)}
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<View style={styles.footer}>
|
||||
<TouchableOpacity
|
||||
style={styles.cancelButton}
|
||||
onPress={handleClose}
|
||||
disabled={submitting}
|
||||
>
|
||||
<Text style={styles.cancelButtonText}>取消</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.submitButton,
|
||||
(!selectedReason || submitting) && styles.submitButtonDisabled,
|
||||
]}
|
||||
onPress={handleSubmit}
|
||||
disabled={!selectedReason || submitting}
|
||||
>
|
||||
{submitting ? (
|
||||
<ActivityIndicator size="small" color="#FFFFFF" />
|
||||
) : (
|
||||
<Text style={styles.submitButtonText}>提交举报</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
{/* 补充说明 */}
|
||||
<View style={styles.section}>
|
||||
<View style={styles.sectionHeader}>
|
||||
<Text style={styles.sectionTitle}>
|
||||
补充说明{isDescriptionRequired ? ' *' : ''}
|
||||
</Text>
|
||||
<Text style={styles.charCount}>{description.length}/500</Text>
|
||||
</View>
|
||||
<TextInput
|
||||
style={[
|
||||
styles.textInput,
|
||||
isDescriptionRequired && !description && styles.textInputError,
|
||||
]}
|
||||
placeholder={descriptionPlaceholder}
|
||||
placeholderTextColor={colors.chat.textPlaceholder}
|
||||
multiline
|
||||
maxLength={500}
|
||||
value={description}
|
||||
onChangeText={setDescription}
|
||||
editable={!submitting}
|
||||
textAlignVertical="top"
|
||||
/>
|
||||
</View>
|
||||
</ScrollView>
|
||||
|
||||
{/* 底部按钮 */}
|
||||
<View style={styles.footer}>
|
||||
<TouchableOpacity
|
||||
style={styles.cancelButton}
|
||||
onPress={handleClose}
|
||||
disabled={submitting}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.cancelButtonText}>取消</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.submitButton,
|
||||
(!selectedReason || submitting) && styles.submitButtonDisabled,
|
||||
]}
|
||||
onPress={handleSubmit}
|
||||
disabled={!selectedReason || submitting}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
{submitting ? (
|
||||
<ActivityIndicator size="small" color="#FFFFFF" />
|
||||
) : (
|
||||
<Text style={styles.submitButtonText}>提交举报</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</KeyboardAvoidingView>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -199,6 +283,9 @@ export const ReportDialog: React.FC<ReportDialogProps> = ({
|
||||
// 创建样式
|
||||
const useStyles = (colors: ReturnType<typeof useAppColors>) =>
|
||||
StyleSheet.create({
|
||||
keyboardView: {
|
||||
flex: 1,
|
||||
},
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
@@ -207,129 +294,193 @@ const useStyles = (colors: ReturnType<typeof useAppColors>) =>
|
||||
padding: spacing.lg,
|
||||
},
|
||||
container: {
|
||||
backgroundColor: colors.backgroundPrimary,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.chat.card,
|
||||
borderRadius: borderRadius.xl,
|
||||
width: '100%',
|
||||
maxWidth: 400,
|
||||
maxHeight: '80%',
|
||||
maxWidth: 420,
|
||||
maxHeight: '85%',
|
||||
...shadows.lg,
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: spacing.lg,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.borderLight,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
headerContent: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.md,
|
||||
},
|
||||
headerIcon: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: borderRadius.md,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerText: {
|
||||
flex: 1,
|
||||
},
|
||||
title: {
|
||||
fontSize: fontSizes.lg,
|
||||
fontSize: fontSizes.xl,
|
||||
fontWeight: '600',
|
||||
color: colors.textPrimary,
|
||||
color: colors.chat.textPrimary,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.chat.textSecondary,
|
||||
marginTop: 2,
|
||||
},
|
||||
closeButton: {
|
||||
padding: spacing.xs,
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
content: {
|
||||
padding: spacing.lg,
|
||||
paddingTop: 0,
|
||||
maxHeight: 400,
|
||||
},
|
||||
section: {
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '500',
|
||||
color: colors.textPrimary,
|
||||
marginBottom: spacing.sm,
|
||||
fontWeight: '600',
|
||||
color: colors.chat.textPrimary,
|
||||
},
|
||||
reasonList: {
|
||||
marginBottom: spacing.lg,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
reasonItem: {
|
||||
paddingVertical: spacing.sm,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.borderLight,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
borderWidth: 1,
|
||||
borderColor: 'transparent',
|
||||
backgroundColor: colors.chat.surfaceMuted,
|
||||
},
|
||||
reasonItemSelected: {
|
||||
backgroundColor: colors.backgroundSecondary,
|
||||
marginHorizontal: -spacing.sm,
|
||||
paddingHorizontal: spacing.sm,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.primary.main + '08',
|
||||
borderWidth: 1,
|
||||
},
|
||||
radioContainer: {
|
||||
reasonLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
gap: spacing.md,
|
||||
},
|
||||
radio: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.border,
|
||||
reasonIcon: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.chat.surfaceRaised,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
reasonIconSelected: {
|
||||
backgroundColor: colors.primary.main + '15',
|
||||
},
|
||||
reasonTextContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
reasonLabel: {
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '500',
|
||||
color: colors.chat.textPrimary,
|
||||
},
|
||||
reasonLabelSelected: {
|
||||
color: colors.primary.main,
|
||||
fontWeight: '600',
|
||||
},
|
||||
reasonDescription: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.chat.textSecondary,
|
||||
marginTop: 2,
|
||||
},
|
||||
radio: {
|
||||
width: 22,
|
||||
height: 22,
|
||||
borderRadius: 11,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.chat.border,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginLeft: spacing.sm,
|
||||
},
|
||||
radioSelected: {
|
||||
borderColor: colors.primary,
|
||||
borderColor: colors.primary.main,
|
||||
backgroundColor: colors.primary.main,
|
||||
},
|
||||
radioDot: {
|
||||
width: 10,
|
||||
height: 10,
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.primary,
|
||||
},
|
||||
reasonLabel: {
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.textPrimary,
|
||||
backgroundColor: '#FFFFFF',
|
||||
},
|
||||
textInput: {
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
borderColor: colors.chat.border,
|
||||
borderRadius: borderRadius.md,
|
||||
padding: spacing.sm,
|
||||
padding: spacing.md,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.textPrimary,
|
||||
color: colors.chat.textPrimary,
|
||||
minHeight: 100,
|
||||
textAlignVertical: 'top',
|
||||
backgroundColor: colors.chat.surfaceMuted,
|
||||
},
|
||||
textInputError: {
|
||||
borderColor: colors.error.main,
|
||||
backgroundColor: colors.error.main + '08',
|
||||
},
|
||||
charCount: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.textTertiary,
|
||||
textAlign: 'right',
|
||||
marginTop: spacing.xs,
|
||||
color: colors.chat.textSecondary,
|
||||
},
|
||||
footer: {
|
||||
flexDirection: 'row',
|
||||
padding: spacing.lg,
|
||||
gap: spacing.md,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.borderLight,
|
||||
gap: spacing.sm,
|
||||
borderTopColor: colors.chat.borderLight,
|
||||
},
|
||||
cancelButton: {
|
||||
flex: 1,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.border,
|
||||
borderColor: colors.chat.border,
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.chat.surfaceMuted,
|
||||
},
|
||||
cancelButtonText: {
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.textSecondary,
|
||||
fontWeight: '500',
|
||||
color: colors.chat.textSecondary,
|
||||
},
|
||||
submitButton: {
|
||||
flex: 1,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.primary,
|
||||
backgroundColor: colors.primary.main,
|
||||
alignItems: 'center',
|
||||
},
|
||||
submitButtonDisabled: {
|
||||
backgroundColor: colors.primary + '60',
|
||||
backgroundColor: colors.background.disabled,
|
||||
},
|
||||
submitButtonText: {
|
||||
fontSize: fontSizes.md,
|
||||
color: '#FFFFFF',
|
||||
fontWeight: '500',
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
|
||||
export default ReportDialog;
|
||||
export default ReportDialog;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
export { ReportDialog } from './ReportDialog';
|
||||
export { default } from './ReportDialog';
|
||||
export type { ReportDialogProps } from './ReportDialog';
|
||||
@@ -39,7 +39,7 @@ import { useCurrentUser } from '../../stores/authStore';
|
||||
import { postService, commentService, uploadService, authService, showPrompt, voteService } from '../../services';
|
||||
import { processPostUseCase } from '../../core/usecases/ProcessPostUseCase';
|
||||
import { useCursorPagination } from '../../hooks/useCursorPagination';
|
||||
import { CommentItem, VoteCard } from '../../components/business';
|
||||
import { CommentItem, VoteCard, ReportDialog } from '../../components/business';
|
||||
import { Avatar, Button, Loading, EmptyState, Text, ImageGallery, ImageGrid, ImageGridItem, AdaptiveLayout, AppBackButton } from '../../components/common';
|
||||
import { useResponsive, useResponsiveValue, useResponsiveSpacing } from '../../hooks/useResponsive';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
@@ -177,6 +177,10 @@ export const PostDetailScreen: React.FC = () => {
|
||||
const flatListRef = useRef<FlatList>(null);
|
||||
const hasRecordedView = useRef(false); // 是否已记录浏览量
|
||||
|
||||
// 举报相关状态
|
||||
const [reportDialogVisible, setReportDialogVisible] = useState(false);
|
||||
const [reportTarget, setReportTarget] = useState<{ type: 'post' | 'comment'; id: string } | null>(null);
|
||||
|
||||
// 投票相关状态
|
||||
const [voteResult, setVoteResult] = useState<VoteResultDTO | null>(null);
|
||||
const [isVoteLoading, setIsVoteLoading] = useState(false);
|
||||
@@ -1243,6 +1247,25 @@ export const PostDetailScreen: React.FC = () => {
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)}
|
||||
{/* 举报按钮 - 只对非帖子作者显示 */}
|
||||
{currentUser?.id !== post.author?.id && (
|
||||
<TouchableOpacity
|
||||
style={styles.reportButtonInline}
|
||||
onPress={() => {
|
||||
setReportTarget({ type: 'post', id: post.id });
|
||||
setReportDialogVisible(true);
|
||||
}}
|
||||
>
|
||||
<MaterialCommunityIcons
|
||||
name="flag-outline"
|
||||
size={14}
|
||||
color={colors.text.hint}
|
||||
/>
|
||||
<Text variant="caption" color={colors.text.hint} style={styles.reportButtonText}>
|
||||
举报
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 底部操作栏 - QQ频道风格 */}
|
||||
@@ -1347,6 +1370,12 @@ export const PostDetailScreen: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 处理举报评论
|
||||
const handleReportComment = useCallback((comment: Comment) => {
|
||||
setReportTarget({ type: 'comment', id: comment.id });
|
||||
setReportDialogVisible(true);
|
||||
}, []);
|
||||
|
||||
// 渲染评论 - 带楼层号
|
||||
const commentKeyExtractor = useCallback((item: Comment) => item.id, []);
|
||||
|
||||
@@ -1372,9 +1401,10 @@ export const PostDetailScreen: React.FC = () => {
|
||||
onDelete={handleDeleteComment}
|
||||
onImagePress={handleImagePress}
|
||||
currentUserId={currentUser?.id}
|
||||
onReport={handleReportComment}
|
||||
/>
|
||||
);
|
||||
}, [currentUser?.id, handleDeleteComment, handleImagePress, handleLikeComment, handleLoadMoreReplies, post?.user_id]);
|
||||
}, [currentUser?.id, handleDeleteComment, handleImagePress, handleLikeComment, handleLoadMoreReplies, post?.user_id, handleReportComment]);
|
||||
|
||||
// 渲染空评论 - 现代化设计
|
||||
const renderEmptyComments = useCallback(() => (
|
||||
@@ -1696,6 +1726,20 @@ export const PostDetailScreen: React.FC = () => {
|
||||
onClose={() => setShowImageModal(false)}
|
||||
enableSave
|
||||
/>
|
||||
|
||||
{/* 举报对话框 */}
|
||||
<ReportDialog
|
||||
visible={reportDialogVisible}
|
||||
targetType={reportTarget?.type || 'post'}
|
||||
targetId={reportTarget?.id || ''}
|
||||
onClose={() => {
|
||||
setReportDialogVisible(false);
|
||||
setReportTarget(null);
|
||||
}}
|
||||
onSuccess={() => {
|
||||
setReportTarget(null);
|
||||
}}
|
||||
/>
|
||||
</SafeAreaView>
|
||||
);
|
||||
};
|
||||
@@ -1858,7 +1902,13 @@ function createPostDetailStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
padding: spacing.xs,
|
||||
},
|
||||
editButtonText: {
|
||||
reportButtonInline: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginLeft: spacing.sm,
|
||||
padding: spacing.xs,
|
||||
},
|
||||
reportButtonText: {
|
||||
marginLeft: 2,
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
|
||||
@@ -322,10 +322,10 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xl,
|
||||
padding: spacing.md,
|
||||
paddingBottom: spacing.xl * 2,
|
||||
},
|
||||
// 头部区域样式
|
||||
// 头部区域样式 - 扁平化
|
||||
headerSection: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-start',
|
||||
@@ -341,12 +341,17 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 40,
|
||||
borderWidth: 3,
|
||||
borderColor: colors.primary.light + '40',
|
||||
},
|
||||
avatarPlaceholder: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: 40,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.divider,
|
||||
borderStyle: 'dashed',
|
||||
},
|
||||
avatarBadge: {
|
||||
position: 'absolute',
|
||||
@@ -358,7 +363,7 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
borderRadius: 14,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderWidth: 3,
|
||||
borderColor: colors.background.paper,
|
||||
},
|
||||
nameInputContainer: {
|
||||
@@ -367,7 +372,9 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
},
|
||||
inputLabel: {
|
||||
marginBottom: spacing.sm,
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.sm + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
nameInput: {
|
||||
backgroundColor: colors.background.paper,
|
||||
@@ -376,12 +383,15 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
paddingVertical: spacing.md,
|
||||
fontSize: fontSizes.lg,
|
||||
color: colors.text.primary,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
fontWeight: '600',
|
||||
},
|
||||
charCount: {
|
||||
textAlign: 'right',
|
||||
marginTop: spacing.xs,
|
||||
fontWeight: '500',
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
// 区域样式
|
||||
section: {
|
||||
@@ -391,18 +401,20 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.md + 1,
|
||||
marginBottom: spacing.sm,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
// 文本域样式
|
||||
// 文本域样式 - 更现代
|
||||
textAreaContainer: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
padding: spacing.md,
|
||||
},
|
||||
textArea: {
|
||||
@@ -414,6 +426,8 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
textAreaCharCount: {
|
||||
textAlign: 'right',
|
||||
marginTop: spacing.sm,
|
||||
fontWeight: '500',
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
// 已选成员样式
|
||||
selectedMembersList: {
|
||||
@@ -443,8 +457,10 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
marginTop: spacing.xs,
|
||||
textAlign: 'center',
|
||||
width: '100%',
|
||||
fontWeight: '600',
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
// 邀请按钮样式
|
||||
// 邀请按钮样式 - 扁平化
|
||||
inviteButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
@@ -452,13 +468,14 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
marginBottom: spacing.xl,
|
||||
...shadows.sm,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
inviteIconContainer: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.md,
|
||||
@@ -467,16 +484,18 @@ function createCreateGroupStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
},
|
||||
inviteTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md + 1,
|
||||
marginBottom: 2,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
// 底部按钮样式
|
||||
footer: {
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xl,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.divider,
|
||||
borderTopWidth: 0.5,
|
||||
borderTopColor: colors.divider + '60',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1091,13 +1091,15 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingVertical: spacing.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '60',
|
||||
},
|
||||
pageTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.xl,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
pageHeaderPlaceholder: {
|
||||
width: 40,
|
||||
@@ -1107,8 +1109,8 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xl,
|
||||
padding: spacing.md,
|
||||
paddingBottom: spacing.xl * 2,
|
||||
},
|
||||
errorContainer: {
|
||||
flex: 1,
|
||||
@@ -1116,13 +1118,14 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
},
|
||||
|
||||
// 头部卡片样式
|
||||
// 头部卡片样式 - 扁平化设计
|
||||
headerCard: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
marginBottom: spacing.lg,
|
||||
...shadows.sm,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
groupHeader: {
|
||||
flexDirection: 'row',
|
||||
@@ -1134,30 +1137,33 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
},
|
||||
groupName: {
|
||||
fontWeight: '700',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 2,
|
||||
marginBottom: spacing.xs,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
groupMeta: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
groupNoRow: {
|
||||
marginTop: spacing.xs,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
copyGroupNoBtn: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 4,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
},
|
||||
copyGroupNoBtnText: {
|
||||
marginLeft: 4,
|
||||
fontWeight: '500',
|
||||
},
|
||||
descriptionContainer: {
|
||||
flexDirection: 'row',
|
||||
@@ -1165,20 +1171,24 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '30',
|
||||
},
|
||||
groupDesc: {
|
||||
marginLeft: spacing.sm,
|
||||
flex: 1,
|
||||
lineHeight: 20,
|
||||
lineHeight: 22,
|
||||
fontWeight: '400',
|
||||
},
|
||||
|
||||
// 通用卡片样式
|
||||
// 通用卡片样式 - 扁平化
|
||||
card: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
marginBottom: spacing.lg,
|
||||
...shadows.sm,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
cardHeader: {
|
||||
flexDirection: 'row',
|
||||
@@ -1189,33 +1199,41 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.info.light + '20',
|
||||
backgroundColor: colors.info.light + '15',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
cardTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md + 1,
|
||||
flex: 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
|
||||
// 公告样式
|
||||
// 公告样式 - 更现代的卡片
|
||||
announcementContent: {
|
||||
backgroundColor: colors.background.default,
|
||||
backgroundColor: colors.warning.light + '08',
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: colors.warning.main,
|
||||
},
|
||||
announcementText: {
|
||||
lineHeight: 22,
|
||||
marginBottom: spacing.sm,
|
||||
fontWeight: '400',
|
||||
},
|
||||
announcementTime: {
|
||||
textAlign: 'right',
|
||||
fontWeight: '500',
|
||||
},
|
||||
|
||||
// 成员预览样式
|
||||
memberCount: {
|
||||
marginRight: spacing.xs,
|
||||
fontWeight: '600',
|
||||
color: colors.text.secondary,
|
||||
},
|
||||
memberPreview: {
|
||||
flexDirection: 'row',
|
||||
@@ -1226,7 +1244,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
},
|
||||
memberAvatar: {
|
||||
position: 'relative',
|
||||
marginLeft: -10,
|
||||
marginLeft: -8,
|
||||
},
|
||||
memberAvatarFirst: {
|
||||
marginLeft: 0,
|
||||
@@ -1239,12 +1257,12 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
borderRadius: borderRadius.sm,
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 1,
|
||||
borderWidth: 1.5,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.background.paper,
|
||||
},
|
||||
ownerBadgeText: {
|
||||
fontSize: 8,
|
||||
fontWeight: '700',
|
||||
fontWeight: '800',
|
||||
},
|
||||
moreMembers: {
|
||||
minWidth: 44,
|
||||
@@ -1254,49 +1272,55 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
marginLeft: -10,
|
||||
borderColor: colors.divider + '60',
|
||||
marginLeft: -8,
|
||||
paddingHorizontal: spacing.xs,
|
||||
},
|
||||
moreMembersText: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
includeFontPadding: false,
|
||||
fontSize: fontSizes.sm,
|
||||
},
|
||||
|
||||
// 邀请按钮样式
|
||||
// 邀请按钮样式 - 更加醒目
|
||||
inviteButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.light,
|
||||
backgroundColor: colors.primary.light + '10',
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.primary.light + '60',
|
||||
borderStyle: 'dashed',
|
||||
},
|
||||
inviteIconContainer: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
borderRadius: 16,
|
||||
backgroundColor: colors.background.paper,
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
inviteButtonText: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
marginRight: spacing.xs,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
|
||||
// 设置项样式
|
||||
// 设置项样式 - 更加扁平
|
||||
settingsList: {
|
||||
marginTop: spacing.sm,
|
||||
},
|
||||
settingItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.md,
|
||||
paddingHorizontal: spacing.sm,
|
||||
marginLeft: -spacing.sm,
|
||||
marginRight: -spacing.sm,
|
||||
},
|
||||
settingIconContainer: {
|
||||
width: 40,
|
||||
@@ -1308,24 +1332,29 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
settingIconDanger: {
|
||||
backgroundColor: colors.error.light + '20',
|
||||
backgroundColor: colors.error.light + '15',
|
||||
},
|
||||
settingContent: {
|
||||
flex: 1,
|
||||
},
|
||||
dangerText: {
|
||||
color: colors.error.main,
|
||||
fontWeight: '600',
|
||||
},
|
||||
settingDivider: {
|
||||
marginLeft: 56,
|
||||
width: 'auto',
|
||||
marginVertical: spacing.xs,
|
||||
opacity: 0.5,
|
||||
},
|
||||
|
||||
// 危险操作卡片
|
||||
// 危险操作卡片 - 更加醒目
|
||||
dangerCard: {
|
||||
padding: 0,
|
||||
overflow: 'hidden',
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.error.light + '30',
|
||||
marginTop: spacing.sm,
|
||||
},
|
||||
dangerButton: {
|
||||
flexDirection: 'row',
|
||||
@@ -1333,15 +1362,17 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.lg,
|
||||
gap: spacing.sm,
|
||||
backgroundColor: colors.error.light + '08',
|
||||
},
|
||||
dangerButtonText: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
|
||||
// 模态框样式
|
||||
// 模态框样式 - 更现代
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.45)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
modalContent: {
|
||||
@@ -1350,7 +1381,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
borderTopRightRadius: borderRadius['2xl'],
|
||||
height: '80%',
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingTop: spacing.lg,
|
||||
paddingTop: spacing.md,
|
||||
paddingBottom: spacing.xl,
|
||||
},
|
||||
modalHeader: {
|
||||
@@ -1358,24 +1389,29 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.lg,
|
||||
paddingBottom: spacing.md,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '60',
|
||||
},
|
||||
modalHeaderButton: {
|
||||
paddingVertical: spacing.sm,
|
||||
minWidth: 60,
|
||||
},
|
||||
modalTitle: {
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.xl,
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
saveButton: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
confirmButton: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
textAlign: 'right',
|
||||
},
|
||||
|
||||
// 编辑表单样式
|
||||
// 编辑表单样式 - 更现代
|
||||
editForm: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
@@ -1387,12 +1423,17 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
width: 90,
|
||||
height: 90,
|
||||
borderRadius: 45,
|
||||
borderWidth: 3,
|
||||
borderColor: colors.primary.light + '40',
|
||||
},
|
||||
editAvatarPlaceholder: {
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: 45,
|
||||
borderWidth: 2,
|
||||
borderColor: colors.divider,
|
||||
borderStyle: 'dashed',
|
||||
},
|
||||
editAvatarButton: {
|
||||
position: 'absolute',
|
||||
@@ -1413,7 +1454,9 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
},
|
||||
editLabel: {
|
||||
marginBottom: spacing.sm,
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.sm + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
editInput: {
|
||||
backgroundColor: colors.background.default,
|
||||
@@ -1422,8 +1465,9 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
paddingVertical: spacing.md,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
fontWeight: '400',
|
||||
},
|
||||
editTextArea: {
|
||||
minHeight: 100,
|
||||
@@ -1433,6 +1477,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
editCharCount: {
|
||||
textAlign: 'right',
|
||||
marginTop: spacing.xs,
|
||||
fontWeight: '500',
|
||||
},
|
||||
|
||||
// 公告表单样式
|
||||
@@ -1446,17 +1491,18 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
padding: spacing.md,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
lineHeight: 22,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
announcementCharCount: {
|
||||
textAlign: 'right',
|
||||
marginTop: spacing.sm,
|
||||
fontWeight: '500',
|
||||
},
|
||||
|
||||
// 加群方式样式
|
||||
// 加群方式样式 - 更现代的选中状态
|
||||
joinTypeList: {
|
||||
gap: spacing.md,
|
||||
},
|
||||
@@ -1465,36 +1511,39 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
padding: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
joinTypeItemSelected: {
|
||||
borderColor: colors.primary.main,
|
||||
backgroundColor: colors.primary.light + '10',
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
borderWidth: 2,
|
||||
},
|
||||
joinTypeIcon: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.background.default,
|
||||
backgroundColor: colors.background.paper,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.md,
|
||||
},
|
||||
joinTypeIconSelected: {
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
backgroundColor: colors.primary.light + '25',
|
||||
},
|
||||
joinTypeInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
joinTypeTextSelected: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
color: colors.primary.main,
|
||||
},
|
||||
|
||||
// 转让群主样式
|
||||
transferDesc: {
|
||||
marginBottom: spacing.md,
|
||||
fontWeight: '500',
|
||||
},
|
||||
transferList: {
|
||||
flex: 1,
|
||||
@@ -1504,11 +1553,15 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
marginBottom: spacing.xs,
|
||||
marginBottom: spacing.sm,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
transferItemSelected: {
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.primary.light + '60',
|
||||
},
|
||||
transferItemInfo: {
|
||||
flex: 1,
|
||||
@@ -1530,6 +1583,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
borderColor: colors.divider,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
transferRadioSelected: {
|
||||
backgroundColor: colors.primary.main,
|
||||
@@ -1546,6 +1600,8 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.xs,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider + '60',
|
||||
},
|
||||
tab: {
|
||||
flex: 1,
|
||||
@@ -1555,10 +1611,11 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
},
|
||||
tabActive: {
|
||||
backgroundColor: colors.background.paper,
|
||||
...shadows.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider + '60',
|
||||
},
|
||||
tabTextActive: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
},
|
||||
selectedBadge: {
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
@@ -1577,10 +1634,13 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.sm,
|
||||
borderRadius: borderRadius.lg,
|
||||
marginBottom: spacing.xs,
|
||||
marginBottom: spacing.sm,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
friendItemSelected: {
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.primary.light + '60',
|
||||
},
|
||||
friendInfo: {
|
||||
flex: 1,
|
||||
@@ -1588,7 +1648,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
nickname: {
|
||||
fontWeight: '500',
|
||||
fontWeight: '600',
|
||||
marginBottom: 2,
|
||||
},
|
||||
checkbox: {
|
||||
@@ -1599,6 +1659,7 @@ function createGroupInfoStyles(colors: AppColors) {
|
||||
borderColor: colors.divider,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
checkboxSelected: {
|
||||
backgroundColor: colors.primary.main,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { View, StyleSheet, ActivityIndicator, Alert, ScrollView, TouchableOpacit
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '../../theme';
|
||||
import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme';
|
||||
import { Avatar, Text } from '../../components/common';
|
||||
import { routePayloadCache } from '../../stores/routePayloadCache';
|
||||
import { groupService } from '../../services/groupService';
|
||||
@@ -196,14 +196,15 @@ function createGroupInviteDetailStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
},
|
||||
scrollContent: {
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xl,
|
||||
padding: spacing.md,
|
||||
paddingBottom: spacing.xl * 2,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
...shadows.sm,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
cardHeader: {
|
||||
flexDirection: 'row',
|
||||
@@ -211,20 +212,23 @@ function createGroupInviteDetailStyles(colors: AppColors) {
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
cardIconContainer: {
|
||||
width: 30,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
backgroundColor: colors.info.light + '30',
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.info.light + '15',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginRight: spacing.sm,
|
||||
},
|
||||
cardTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md + 1,
|
||||
flex: 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
memberCount: {
|
||||
marginRight: spacing.xs,
|
||||
fontWeight: '600',
|
||||
},
|
||||
loadingWrap: {
|
||||
paddingVertical: spacing.md,
|
||||
@@ -247,13 +251,15 @@ function createGroupInviteDetailStyles(colors: AppColors) {
|
||||
bottom: -2,
|
||||
right: -2,
|
||||
backgroundColor: colors.warning.main,
|
||||
borderRadius: 8,
|
||||
borderRadius: borderRadius.sm,
|
||||
paddingHorizontal: 4,
|
||||
paddingVertical: 1,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.background.paper,
|
||||
},
|
||||
ownerBadgeText: {
|
||||
fontSize: 10,
|
||||
fontWeight: '700',
|
||||
fontSize: 8,
|
||||
fontWeight: '800',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -664,19 +664,21 @@ function createGroupMembersStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
},
|
||||
// Header 样式
|
||||
// Header 样式 - 扁平化
|
||||
pageHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingVertical: spacing.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '60',
|
||||
},
|
||||
pageTitle: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
pageHeaderPlaceholder: {
|
||||
width: 40,
|
||||
@@ -688,18 +690,20 @@ function createGroupMembersStyles(colors: AppColors) {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingVertical: spacing.md,
|
||||
backgroundColor: colors.background.default,
|
||||
borderTopWidth: 0.5,
|
||||
borderTopColor: colors.divider + '40',
|
||||
},
|
||||
memberItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingVertical: spacing.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '40',
|
||||
},
|
||||
memberInfo: {
|
||||
flex: 1,
|
||||
@@ -711,63 +715,81 @@ function createGroupMembersStyles(colors: AppColors) {
|
||||
marginBottom: 2,
|
||||
},
|
||||
memberName: {
|
||||
fontWeight: '500',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
roleBadge: {
|
||||
paddingHorizontal: spacing.xs,
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 2,
|
||||
borderRadius: borderRadius.sm,
|
||||
marginLeft: spacing.sm,
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xs,
|
||||
color: colors.background.paper,
|
||||
},
|
||||
mutedBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginTop: 2,
|
||||
},
|
||||
// 模态框样式
|
||||
// 模态框样式 - 更现代
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.45)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderTopLeftRadius: borderRadius.lg,
|
||||
borderTopRightRadius: borderRadius.lg,
|
||||
borderTopLeftRadius: borderRadius['2xl'],
|
||||
borderTopRightRadius: borderRadius['2xl'],
|
||||
padding: spacing.lg,
|
||||
maxHeight: '80%',
|
||||
},
|
||||
modalHeader: {
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.md,
|
||||
marginBottom: spacing.lg,
|
||||
paddingBottom: spacing.md,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '60',
|
||||
},
|
||||
modalTitle: {
|
||||
fontWeight: '700',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
marginTop: spacing.sm,
|
||||
marginBottom: spacing.xs,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
actionItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
paddingHorizontal: spacing.sm,
|
||||
marginLeft: -spacing.sm,
|
||||
marginRight: -spacing.sm,
|
||||
borderRadius: borderRadius.md,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '40',
|
||||
},
|
||||
actionText: {
|
||||
marginLeft: spacing.md,
|
||||
fontWeight: '600',
|
||||
fontSize: fontSizes.md,
|
||||
},
|
||||
inputLabel: {
|
||||
marginBottom: spacing.xs,
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.sm + 1,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: colors.background.default,
|
||||
borderRadius: borderRadius.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.md,
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
modalButtons: {
|
||||
@@ -791,6 +813,8 @@ function createGroupMembersStyles(colors: AppColors) {
|
||||
noMoreText: {
|
||||
textAlign: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
fontWeight: '500',
|
||||
color: colors.text.hint,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
|
||||
import { spacing, borderRadius, useAppColors, type AppColors } from '../../theme';
|
||||
import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../theme';
|
||||
import Avatar from '../../components/common/Avatar';
|
||||
import Text from '../../components/common/Text';
|
||||
import { groupService } from '../../services/groupService';
|
||||
@@ -27,47 +27,58 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: colors.background.default,
|
||||
padding: spacing.lg,
|
||||
padding: spacing.md,
|
||||
},
|
||||
heroCard: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
marginBottom: spacing.lg,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
heroIconWrap: {
|
||||
width: 48,
|
||||
height: 48,
|
||||
borderRadius: 24,
|
||||
backgroundColor: colors.primary.light + '26',
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
heroTitle: {
|
||||
marginBottom: spacing.xs,
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
tip: {
|
||||
lineHeight: 20,
|
||||
lineHeight: 22,
|
||||
fontWeight: '400',
|
||||
},
|
||||
formCard: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
flex: 1,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
label: {
|
||||
marginBottom: spacing.xs,
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.sm + 1,
|
||||
},
|
||||
input: {
|
||||
flex: 1,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.background.paper,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.divider + '80',
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.background.default,
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingVertical: spacing.md,
|
||||
color: colors.text.primary,
|
||||
fontSize: fontSizes.md,
|
||||
},
|
||||
searchRow: {
|
||||
flexDirection: 'row',
|
||||
@@ -77,26 +88,28 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
searchBtn: {
|
||||
width: 46,
|
||||
height: 46,
|
||||
borderRadius: borderRadius.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.primary.main,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginLeft: spacing.sm,
|
||||
},
|
||||
searchResultSection: {
|
||||
marginBottom: spacing.lg,
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
sectionTitle: {
|
||||
marginBottom: spacing.sm,
|
||||
fontWeight: '600',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.md + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
listSection: {
|
||||
flex: 1,
|
||||
},
|
||||
groupCard: {
|
||||
borderWidth: 1,
|
||||
borderColor: colors.divider,
|
||||
borderRadius: borderRadius.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
backgroundColor: colors.background.default,
|
||||
marginBottom: spacing.md,
|
||||
@@ -111,11 +124,14 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
},
|
||||
groupName: {
|
||||
marginBottom: spacing.xs,
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
groupDesc: {
|
||||
marginTop: spacing.sm,
|
||||
lineHeight: 18,
|
||||
lineHeight: 20,
|
||||
fontWeight: '400',
|
||||
},
|
||||
groupInfoRow: {
|
||||
marginTop: spacing.sm,
|
||||
@@ -135,16 +151,17 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 4,
|
||||
borderRadius: borderRadius.sm,
|
||||
backgroundColor: colors.primary.light + '22',
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
},
|
||||
copyBtnText: {
|
||||
marginLeft: 4,
|
||||
fontWeight: '600',
|
||||
},
|
||||
submitBtn: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
borderRadius: borderRadius.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.primary.main,
|
||||
minHeight: 46,
|
||||
},
|
||||
@@ -153,10 +170,13 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
},
|
||||
submitText: {
|
||||
marginLeft: spacing.xs,
|
||||
fontWeight: '700',
|
||||
fontSize: fontSizes.md,
|
||||
},
|
||||
emptyText: {
|
||||
marginTop: spacing.sm,
|
||||
textAlign: 'center',
|
||||
fontWeight: '500',
|
||||
},
|
||||
loadingFooter: {
|
||||
paddingVertical: spacing.md,
|
||||
@@ -169,6 +189,8 @@ function createJoinGroupStyles(colors: AppColors) {
|
||||
noMoreText: {
|
||||
textAlign: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
fontWeight: '500',
|
||||
color: colors.text.hint,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -185,9 +185,11 @@ export const ChatInput: React.FC<ChatInputProps & {
|
||||
<TouchableOpacity
|
||||
style={styles.sendButtonActive}
|
||||
onPress={onSend}
|
||||
activeOpacity={0.8}
|
||||
activeOpacity={0.85}
|
||||
>
|
||||
<MaterialCommunityIcons name="send" size={20} color="#FFF" />
|
||||
{/* 光泽层 - 模拟渐变效果 */}
|
||||
<View style={styles.sendButtonShine} pointerEvents="none" />
|
||||
<MaterialCommunityIcons name="send" size={18} color="#FFF" />
|
||||
</TouchableOpacity>
|
||||
) : isComposerBusy && !isDisabled ? (
|
||||
<TouchableOpacity
|
||||
|
||||
@@ -374,7 +374,7 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
overlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.3)',
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.35)',
|
||||
zIndex: 100,
|
||||
},
|
||||
overlayTouchable: {
|
||||
@@ -388,24 +388,28 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
width: PANEL_WIDTH,
|
||||
backgroundColor: colors.background.paper,
|
||||
zIndex: 101,
|
||||
...shadows.lg,
|
||||
borderLeftWidth: 0.5,
|
||||
borderLeftColor: colors.divider + '60',
|
||||
},
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
paddingHorizontal: spacing.md,
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingVertical: spacing.md,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.divider,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '60',
|
||||
backgroundColor: colors.background.paper,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: fontSizes.xl,
|
||||
fontWeight: '600',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
fontWeight: '800',
|
||||
color: colors.text.primary,
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
closeButton: {
|
||||
padding: spacing.xs,
|
||||
borderRadius: borderRadius.md,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
@@ -413,22 +417,26 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
groupInfoSection: {
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.xl,
|
||||
paddingHorizontal: spacing.md,
|
||||
},
|
||||
groupName: {
|
||||
fontSize: fontSizes.xl,
|
||||
fontWeight: '600',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
fontWeight: '800',
|
||||
color: colors.text.primary,
|
||||
marginTop: spacing.md,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
memberCount: {
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.secondary,
|
||||
marginTop: spacing.xs,
|
||||
fontWeight: '500',
|
||||
},
|
||||
joinType: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.primary.main,
|
||||
marginTop: spacing.xs,
|
||||
fontWeight: '600',
|
||||
},
|
||||
inviteButton: {
|
||||
flexDirection: 'row',
|
||||
@@ -436,25 +444,27 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.md,
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
borderRadius: 20,
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
borderRadius: borderRadius.lg,
|
||||
marginTop: spacing.md,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.light,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.primary.light + '60',
|
||||
borderStyle: 'dashed',
|
||||
},
|
||||
inviteButtonText: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.primary.main,
|
||||
marginLeft: spacing.xs,
|
||||
fontWeight: '500',
|
||||
fontWeight: '700',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
divider: {
|
||||
height: 1,
|
||||
backgroundColor: colors.divider,
|
||||
marginHorizontal: spacing.md,
|
||||
height: 0.5,
|
||||
backgroundColor: colors.divider + '60',
|
||||
marginHorizontal: spacing.lg,
|
||||
},
|
||||
section: {
|
||||
padding: spacing.md,
|
||||
padding: spacing.lg,
|
||||
},
|
||||
sectionHeader: {
|
||||
flexDirection: 'row',
|
||||
@@ -462,38 +472,44 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '600',
|
||||
fontSize: fontSizes.md + 1,
|
||||
fontWeight: '700',
|
||||
color: colors.text.primary,
|
||||
marginLeft: spacing.xs,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
noticeBox: {
|
||||
backgroundColor: colors.chat.tipBg,
|
||||
backgroundColor: colors.warning.light + '08',
|
||||
padding: spacing.md,
|
||||
borderRadius: 8,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderLeftWidth: 3,
|
||||
borderLeftColor: colors.warning.main,
|
||||
},
|
||||
noticeText: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.text.secondary,
|
||||
lineHeight: 20,
|
||||
lineHeight: 22,
|
||||
fontWeight: '400',
|
||||
},
|
||||
noticeTime: {
|
||||
fontSize: fontSizes.xs,
|
||||
color: colors.text.hint,
|
||||
marginTop: spacing.xs,
|
||||
textAlign: 'right',
|
||||
fontWeight: '500',
|
||||
},
|
||||
descriptionBox: {
|
||||
backgroundColor: colors.chat.surfaceMuted,
|
||||
backgroundColor: colors.background.default,
|
||||
padding: spacing.md,
|
||||
borderRadius: 8,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '30',
|
||||
},
|
||||
description: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.text.secondary,
|
||||
lineHeight: 20,
|
||||
lineHeight: 22,
|
||||
fontWeight: '400',
|
||||
},
|
||||
memberList: {
|
||||
gap: spacing.sm,
|
||||
@@ -511,15 +527,20 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
viewAllText: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.primary.main,
|
||||
fontWeight: '600',
|
||||
},
|
||||
memberItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.xs,
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.sm,
|
||||
borderRadius: borderRadius.md,
|
||||
marginLeft: -spacing.sm,
|
||||
marginRight: -spacing.sm,
|
||||
},
|
||||
memberInfo: {
|
||||
flex: 1,
|
||||
marginLeft: spacing.sm,
|
||||
marginLeft: spacing.md,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
@@ -528,48 +549,55 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
fontSize: fontSizes.md,
|
||||
color: colors.text.primary,
|
||||
flex: 1,
|
||||
fontWeight: '600',
|
||||
},
|
||||
ownerBadge: {
|
||||
fontSize: fontSizes.xs,
|
||||
color: colors.warning.main,
|
||||
color: colors.background.paper,
|
||||
marginLeft: spacing.xs,
|
||||
backgroundColor: colors.warning.light + '30',
|
||||
backgroundColor: colors.warning.main,
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
borderRadius: borderRadius.sm,
|
||||
fontWeight: '800',
|
||||
},
|
||||
adminBadge: {
|
||||
fontSize: fontSizes.xs,
|
||||
color: colors.primary.main,
|
||||
marginLeft: spacing.xs,
|
||||
backgroundColor: colors.primary.light + '30',
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
borderRadius: 4,
|
||||
borderRadius: borderRadius.sm,
|
||||
fontWeight: '700',
|
||||
},
|
||||
moreMembers: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.text.secondary,
|
||||
textAlign: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
fontWeight: '500',
|
||||
},
|
||||
infoRow: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingVertical: spacing.sm,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.chat.borderHairline,
|
||||
paddingVertical: spacing.md,
|
||||
borderBottomWidth: 0.5,
|
||||
borderBottomColor: colors.divider + '40',
|
||||
},
|
||||
infoLabel: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.text.secondary,
|
||||
fontWeight: '500',
|
||||
},
|
||||
infoValue: {
|
||||
fontSize: fontSizes.sm,
|
||||
color: colors.text.primary,
|
||||
fontWeight: '600',
|
||||
textAlign: 'right',
|
||||
},
|
||||
actionSection: {
|
||||
padding: spacing.md,
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xl,
|
||||
},
|
||||
actionButton: {
|
||||
@@ -577,24 +605,27 @@ function createGroupInfoPanelStyles(colors: AppColors) {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
backgroundColor: colors.primary.light + '15',
|
||||
borderRadius: 12,
|
||||
backgroundColor: colors.primary.light + '10',
|
||||
borderRadius: borderRadius.lg,
|
||||
marginBottom: spacing.sm,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.primary.light,
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.primary.light + '50',
|
||||
},
|
||||
actionButtonText: {
|
||||
fontSize: fontSizes.md,
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
color: colors.primary.main,
|
||||
marginLeft: spacing.sm,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
leaveButton: {
|
||||
backgroundColor: colors.error.light + '15',
|
||||
borderColor: colors.error.light,
|
||||
backgroundColor: colors.error.light + '08',
|
||||
borderColor: colors.error.light + '50',
|
||||
borderWidth: 1.5,
|
||||
},
|
||||
leaveButtonText: {
|
||||
color: colors.error.main,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -432,18 +432,34 @@ export function createChatScreenStyles(colors: AppColors) {
|
||||
transform: [{ translateY: -1 }],
|
||||
},
|
||||
|
||||
// 发送按钮
|
||||
// 发送按钮 - QQ/微信风格
|
||||
sendButtonActive: {
|
||||
width: 38,
|
||||
height: 30,
|
||||
borderRadius: 15,
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 18, // 正圆形
|
||||
backgroundColor: colors.primary.main,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
...shadows.md,
|
||||
// 微信风格:轻微阴影,不夸张
|
||||
shadowColor: colors.primary.main,
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 3,
|
||||
elevation: 2,
|
||||
},
|
||||
sendButtonDisabled: {
|
||||
opacity: 0.6,
|
||||
opacity: 0.4,
|
||||
},
|
||||
// 发送按钮光泽层(叠加在按钮上模拟渐变)
|
||||
sendButtonShine: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: '50%',
|
||||
borderTopLeftRadius: 18,
|
||||
borderTopRightRadius: 18,
|
||||
backgroundColor: 'rgba(255, 255, 255, 0.08)',
|
||||
},
|
||||
|
||||
// 输入框
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import React, { memo, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Animated, StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { spacing, shadows, useAppColors, type AppColors } from '../../../theme';
|
||||
import { spacing, shadows, borderRadius, useAppColors, type AppColors } from '../../../theme';
|
||||
import {
|
||||
ConversationResponse,
|
||||
extractTextFromSegments,
|
||||
@@ -160,13 +160,14 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
backgroundColor: colors.background.paper,
|
||||
marginHorizontal: spacing.md,
|
||||
marginTop: spacing.sm,
|
||||
borderRadius: 12,
|
||||
...shadows.sm,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
conversationItemSelected: {
|
||||
backgroundColor: colors.primary.light + '20',
|
||||
borderColor: colors.primary.main,
|
||||
borderWidth: 1,
|
||||
backgroundColor: colors.primary.light + '12',
|
||||
borderColor: colors.primary.main + '60',
|
||||
borderWidth: 1.5,
|
||||
},
|
||||
avatarContainer: {
|
||||
position: 'relative',
|
||||
@@ -174,7 +175,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
systemAvatar: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 12,
|
||||
borderRadius: borderRadius.md,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: colors.primary.main,
|
||||
@@ -195,7 +196,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
},
|
||||
officialBadge: {
|
||||
backgroundColor: colors.primary.main,
|
||||
borderRadius: 4,
|
||||
borderRadius: borderRadius.sm,
|
||||
paddingHorizontal: 6,
|
||||
paddingVertical: 2,
|
||||
marginRight: spacing.xs,
|
||||
@@ -203,12 +204,13 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
officialBadgeText: {
|
||||
color: colors.primary.contrast,
|
||||
fontSize: 10,
|
||||
fontWeight: '600',
|
||||
fontWeight: '800',
|
||||
},
|
||||
userName: {
|
||||
fontWeight: '600',
|
||||
fontWeight: '700',
|
||||
color: colors.text.primary,
|
||||
fontSize: 16,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
groupIcon: {
|
||||
marginRight: 4,
|
||||
@@ -217,6 +219,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
fontSize: 12,
|
||||
color: colors.text.secondary,
|
||||
marginLeft: 2,
|
||||
fontWeight: '500',
|
||||
},
|
||||
pinnedIcon: {
|
||||
marginLeft: 6,
|
||||
@@ -228,7 +231,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
groupAvatarPlaceholder: {
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: 12,
|
||||
borderRadius: borderRadius.md,
|
||||
backgroundColor: colors.primary.main,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -236,6 +239,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
timeText: {
|
||||
color: colors.text.secondary,
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
},
|
||||
messageRow: {
|
||||
flexDirection: 'row',
|
||||
@@ -245,15 +249,16 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
flex: 1,
|
||||
color: colors.text.secondary,
|
||||
fontSize: 14,
|
||||
fontWeight: '400',
|
||||
},
|
||||
unreadMessageText: {
|
||||
color: colors.text.primary,
|
||||
fontWeight: '500',
|
||||
fontWeight: '600',
|
||||
},
|
||||
unreadBadge: {
|
||||
minWidth: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
minWidth: 22,
|
||||
height: 22,
|
||||
borderRadius: 11,
|
||||
backgroundColor: colors.primary.main,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
@@ -263,7 +268,7 @@ function createConversationRowStyles(colors: AppColors) {
|
||||
unreadBadgeText: {
|
||||
color: colors.primary.contrast,
|
||||
fontSize: 12,
|
||||
fontWeight: '600',
|
||||
fontWeight: '800',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
|
||||
import { Avatar, Text } from '../../../components/common';
|
||||
import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '../../../theme';
|
||||
import { spacing, borderRadius, fontSizes, useAppColors, type AppColors } from '../../../theme';
|
||||
|
||||
interface GroupInfoSummaryCardProps {
|
||||
groupName?: string;
|
||||
@@ -18,10 +18,11 @@ function createGroupRequestSharedStyles(colors: AppColors) {
|
||||
return StyleSheet.create({
|
||||
headerCard: {
|
||||
backgroundColor: colors.background.paper,
|
||||
borderRadius: borderRadius.lg,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.lg,
|
||||
marginBottom: spacing.md,
|
||||
...shadows.sm,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '40',
|
||||
},
|
||||
groupHeader: {
|
||||
flexDirection: 'row',
|
||||
@@ -33,7 +34,9 @@ function createGroupRequestSharedStyles(colors: AppColors) {
|
||||
},
|
||||
groupName: {
|
||||
marginBottom: spacing.xs,
|
||||
fontWeight: '700',
|
||||
fontWeight: '800',
|
||||
fontSize: fontSizes.xl + 1,
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
groupMeta: {
|
||||
flexDirection: 'row',
|
||||
@@ -42,6 +45,7 @@ function createGroupRequestSharedStyles(colors: AppColors) {
|
||||
},
|
||||
groupNoText: {
|
||||
marginTop: spacing.xs,
|
||||
fontWeight: '500',
|
||||
},
|
||||
descriptionContainer: {
|
||||
flexDirection: 'row',
|
||||
@@ -50,11 +54,14 @@ function createGroupRequestSharedStyles(colors: AppColors) {
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
marginTop: spacing.md,
|
||||
borderWidth: 0.5,
|
||||
borderColor: colors.divider + '30',
|
||||
},
|
||||
groupDesc: {
|
||||
marginLeft: spacing.sm,
|
||||
flex: 1,
|
||||
lineHeight: 20,
|
||||
lineHeight: 22,
|
||||
fontWeight: '400',
|
||||
},
|
||||
footer: {
|
||||
paddingHorizontal: spacing.lg,
|
||||
@@ -64,16 +71,16 @@ function createGroupRequestSharedStyles(colors: AppColors) {
|
||||
},
|
||||
btn: {
|
||||
flex: 1,
|
||||
height: 42,
|
||||
borderRadius: borderRadius.md,
|
||||
height: 46,
|
||||
borderRadius: borderRadius.lg,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
reject: {
|
||||
marginRight: spacing.sm,
|
||||
backgroundColor: colors.error.light + '25',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.error.light,
|
||||
backgroundColor: colors.error.light + '12',
|
||||
borderWidth: 1.5,
|
||||
borderColor: colors.error.light + '60',
|
||||
},
|
||||
approve: {
|
||||
marginLeft: spacing.sm,
|
||||
|
||||
Reference in New Issue
Block a user