2026-03-09 21:29:03 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* CreateGroupScreen 创建群聊界面
|
|
|
|
|
|
* 允许用户创建新的群聊,设置群名称、描述,并选择初始成员
|
|
|
|
|
|
* 支持响应式布局
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2026-03-25 05:16:54 +08:00
|
|
|
|
import React, { useState, useMemo } from 'react';
|
2026-03-09 21:29:03 +08:00
|
|
|
|
import {
|
|
|
|
|
|
View,
|
|
|
|
|
|
StyleSheet,
|
|
|
|
|
|
ScrollView,
|
|
|
|
|
|
TouchableOpacity,
|
|
|
|
|
|
Alert,
|
|
|
|
|
|
TextInput,
|
|
|
|
|
|
FlatList,
|
|
|
|
|
|
Image,
|
|
|
|
|
|
} from 'react-native';
|
|
|
|
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
2026-03-24 14:21:31 +08:00
|
|
|
|
import { useRouter } from 'expo-router';
|
2026-03-09 21:29:03 +08:00
|
|
|
|
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
|
|
|
|
|
import * as ImagePicker from 'expo-image-picker';
|
2026-03-25 05:16:54 +08:00
|
|
|
|
import { spacing, fontSizes, borderRadius, shadows, useAppColors, type AppColors } from '../../theme';
|
2026-03-09 21:29:03 +08:00
|
|
|
|
import { groupService } from '../../services/groupService';
|
|
|
|
|
|
import { uploadService } from '../../services/uploadService';
|
|
|
|
|
|
import { Avatar, Text, Button, Loading } from '../../components/common';
|
|
|
|
|
|
import { User } from '../../types';
|
|
|
|
|
|
import MutualFollowSelectorModal from './components/MutualFollowSelectorModal';
|
|
|
|
|
|
|
|
|
|
|
|
const CreateGroupScreen: React.FC = () => {
|
2026-03-25 05:16:54 +08:00
|
|
|
|
const colors = useAppColors();
|
|
|
|
|
|
const styles = useMemo(() => createCreateGroupStyles(colors), [colors]);
|
2026-03-24 14:21:31 +08:00
|
|
|
|
const router = useRouter();
|
2026-03-09 21:29:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 表单状态
|
|
|
|
|
|
const [groupName, setGroupName] = useState('');
|
|
|
|
|
|
const [groupDescription, setGroupDescription] = useState('');
|
|
|
|
|
|
const [groupAvatar, setGroupAvatar] = useState<string | null>(null);
|
|
|
|
|
|
const [selectedMembers, setSelectedMembers] = useState<User[]>([]);
|
|
|
|
|
|
const [selectedMemberIds, setSelectedMemberIds] = useState<Set<string>>(new Set());
|
|
|
|
|
|
|
|
|
|
|
|
// 提交状态
|
|
|
|
|
|
const [submitting, setSubmitting] = useState(false);
|
|
|
|
|
|
const [uploadingAvatar, setUploadingAvatar] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
// 邀请成员模态框状态
|
|
|
|
|
|
const [inviteModalVisible, setInviteModalVisible] = useState(false);
|
|
|
|
|
|
|
|
|
|
|
|
// 移除已选成员
|
|
|
|
|
|
const removeSelectedMember = (userId: string) => {
|
|
|
|
|
|
const newSelectedIds = new Set(selectedMemberIds);
|
|
|
|
|
|
newSelectedIds.delete(userId);
|
|
|
|
|
|
setSelectedMemberIds(newSelectedIds);
|
|
|
|
|
|
setSelectedMembers(prev => prev.filter(m => m.id !== userId));
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 选择群头像
|
|
|
|
|
|
const handleSelectAvatar = async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
|
|
|
|
|
if (status !== 'granted') {
|
|
|
|
|
|
Alert.alert('提示', '需要访问相册权限才能选择头像');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const result = await ImagePicker.launchImageLibraryAsync({
|
|
|
|
|
|
mediaTypes: 'images',
|
|
|
|
|
|
allowsEditing: true,
|
|
|
|
|
|
aspect: [1, 1],
|
|
|
|
|
|
quality: 0.8,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!result.canceled && result.assets && result.assets.length > 0) {
|
|
|
|
|
|
const selectedAsset = result.assets[0];
|
|
|
|
|
|
setUploadingAvatar(true);
|
|
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
const uploadResult = await uploadService.uploadGroupAvatar({
|
|
|
|
|
|
uri: selectedAsset.uri,
|
|
|
|
|
|
type: selectedAsset.mimeType || 'image/jpeg',
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (uploadResult && uploadResult.url) {
|
|
|
|
|
|
setGroupAvatar(uploadResult.url);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
Alert.alert('上传失败', '头像上传失败,请重试');
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('上传头像失败:', error);
|
|
|
|
|
|
Alert.alert('上传失败', '头像上传失败,请重试');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setUploadingAvatar(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('选择头像失败:', error);
|
|
|
|
|
|
Alert.alert('错误', '选择头像时发生错误');
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建群组
|
|
|
|
|
|
const handleCreateGroup = async () => {
|
|
|
|
|
|
// 验证群名称
|
|
|
|
|
|
if (!groupName.trim()) {
|
|
|
|
|
|
Alert.alert('提示', '请输入群名称');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (groupName.length > 50) {
|
|
|
|
|
|
Alert.alert('提示', '群名称最多50个字符');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (groupDescription.length > 500) {
|
|
|
|
|
|
Alert.alert('提示', '群描述最多500个字符');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setSubmitting(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const memberIds = selectedMembers.map(m => m.id);
|
|
|
|
|
|
const response = await groupService.createGroup({
|
|
|
|
|
|
name: groupName.trim(),
|
|
|
|
|
|
description: groupDescription.trim() || undefined,
|
|
|
|
|
|
member_ids: memberIds.length > 0 ? memberIds : undefined,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 如果设置了头像,更新群头像
|
|
|
|
|
|
if (groupAvatar && response.id) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
await groupService.setGroupAvatar(response.id, groupAvatar);
|
|
|
|
|
|
} catch (avatarError) {
|
|
|
|
|
|
console.error('设置群头像失败:', avatarError);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Alert.alert('成功', '群组创建成功', [
|
|
|
|
|
|
{
|
|
|
|
|
|
text: '确定',
|
2026-03-24 14:21:31 +08:00
|
|
|
|
onPress: () => router.back(),
|
2026-03-09 21:29:03 +08:00
|
|
|
|
},
|
|
|
|
|
|
]);
|
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
|
console.error('创建群组失败:', error);
|
|
|
|
|
|
Alert.alert('创建失败', error.message || '创建群组时发生错误,请重试');
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setSubmitting(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 渲染已选成员
|
|
|
|
|
|
const renderSelectedMember = ({ item }: { item: User }) => (
|
|
|
|
|
|
<View style={styles.selectedMemberItem}>
|
|
|
|
|
|
<Avatar source={item.avatar} size={48} name={item.nickname} />
|
|
|
|
|
|
<TouchableOpacity
|
|
|
|
|
|
style={styles.removeMemberButton}
|
|
|
|
|
|
onPress={() => removeSelectedMember(item.id)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<View style={styles.removeIconContainer}>
|
|
|
|
|
|
<MaterialCommunityIcons name="close" size={12} color={colors.background.paper} />
|
|
|
|
|
|
</View>
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
<Text variant="caption" numberOfLines={1} style={styles.selectedMemberName}>
|
|
|
|
|
|
{item.nickname}
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
const handleConfirmMembers = (users: User[]) => {
|
|
|
|
|
|
setSelectedMembers(users);
|
|
|
|
|
|
setSelectedMemberIds(new Set(users.map(user => user.id)));
|
|
|
|
|
|
setInviteModalVisible(false);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<SafeAreaView style={styles.container} edges={['bottom']}>
|
|
|
|
|
|
<ScrollView
|
|
|
|
|
|
style={styles.scrollView}
|
|
|
|
|
|
contentContainerStyle={styles.scrollContent}
|
|
|
|
|
|
keyboardShouldPersistTaps="handled"
|
|
|
|
|
|
showsVerticalScrollIndicator={false}
|
|
|
|
|
|
>
|
|
|
|
|
|
{/* 群头像和名称区域 */}
|
|
|
|
|
|
<View style={styles.headerSection}>
|
|
|
|
|
|
<View style={styles.avatarContainer}>
|
|
|
|
|
|
<TouchableOpacity style={styles.avatarWrapper} onPress={handleSelectAvatar} disabled={uploadingAvatar}>
|
|
|
|
|
|
{uploadingAvatar ? (
|
|
|
|
|
|
<View style={[styles.avatarPlaceholder, { width: 80, height: 80 }]}>
|
|
|
|
|
|
<Loading />
|
|
|
|
|
|
</View>
|
|
|
|
|
|
) : groupAvatar ? (
|
|
|
|
|
|
<Image source={{ uri: groupAvatar }} style={styles.avatarImage} />
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<Avatar
|
|
|
|
|
|
source={undefined}
|
|
|
|
|
|
size={80}
|
|
|
|
|
|
name={groupName || '群'}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
<View style={styles.avatarBadge}>
|
|
|
|
|
|
<MaterialCommunityIcons name="camera" size={14} color={colors.background.paper} />
|
|
|
|
|
|
</View>
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
|
|
|
|
<View style={styles.nameInputContainer}>
|
|
|
|
|
|
<Text variant="label" style={styles.inputLabel}>
|
|
|
|
|
|
群名称 <Text color={colors.error.main}>*</Text>
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
<TextInput
|
|
|
|
|
|
style={styles.nameInput}
|
|
|
|
|
|
value={groupName}
|
|
|
|
|
|
onChangeText={setGroupName}
|
|
|
|
|
|
placeholder="请输入群名称"
|
|
|
|
|
|
placeholderTextColor={colors.text.hint}
|
|
|
|
|
|
maxLength={50}
|
2026-03-16 17:47:10 +08:00
|
|
|
|
cursorColor={colors.primary.main}
|
|
|
|
|
|
selectionColor={`${colors.primary.main}40`}
|
2026-03-09 21:29:03 +08:00
|
|
|
|
/>
|
|
|
|
|
|
<Text variant="caption" color={colors.text.hint} style={styles.charCount}>
|
|
|
|
|
|
{groupName.length}/50
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 群描述输入 */}
|
|
|
|
|
|
<View style={styles.section}>
|
|
|
|
|
|
<Text variant="label" style={styles.sectionTitle}>
|
|
|
|
|
|
群描述
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
<View style={styles.textAreaContainer}>
|
|
|
|
|
|
<TextInput
|
|
|
|
|
|
style={styles.textArea}
|
|
|
|
|
|
value={groupDescription}
|
|
|
|
|
|
onChangeText={setGroupDescription}
|
|
|
|
|
|
placeholder="介绍一下这个群聊吧..."
|
|
|
|
|
|
placeholderTextColor={colors.text.hint}
|
|
|
|
|
|
maxLength={500}
|
|
|
|
|
|
multiline
|
|
|
|
|
|
numberOfLines={4}
|
|
|
|
|
|
textAlignVertical="top"
|
2026-03-16 17:47:10 +08:00
|
|
|
|
cursorColor={colors.primary.main}
|
|
|
|
|
|
selectionColor={`${colors.primary.main}40`}
|
2026-03-09 21:29:03 +08:00
|
|
|
|
/>
|
|
|
|
|
|
<Text variant="caption" color={colors.text.hint} style={styles.textAreaCharCount}>
|
|
|
|
|
|
{groupDescription.length}/500
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 已选成员 */}
|
|
|
|
|
|
{selectedMembers.length > 0 && (
|
|
|
|
|
|
<View style={styles.section}>
|
|
|
|
|
|
<View style={styles.sectionHeader}>
|
|
|
|
|
|
<Text variant="label" style={styles.sectionTitle}>
|
|
|
|
|
|
已选成员
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
<Text variant="caption" color={colors.primary.main}>
|
|
|
|
|
|
{selectedMembers.length}人
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
<FlatList
|
|
|
|
|
|
data={selectedMembers}
|
|
|
|
|
|
renderItem={renderSelectedMember}
|
|
|
|
|
|
keyExtractor={item => item.id}
|
|
|
|
|
|
horizontal
|
|
|
|
|
|
showsHorizontalScrollIndicator={false}
|
|
|
|
|
|
contentContainerStyle={styles.selectedMembersList}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{/* 邀请成员按钮 */}
|
|
|
|
|
|
<TouchableOpacity
|
|
|
|
|
|
style={styles.inviteButton}
|
|
|
|
|
|
onPress={() => setInviteModalVisible(true)}
|
|
|
|
|
|
activeOpacity={0.8}
|
|
|
|
|
|
>
|
|
|
|
|
|
<View style={styles.inviteIconContainer}>
|
|
|
|
|
|
<MaterialCommunityIcons name="account-plus" size={24} color={colors.primary.main} />
|
|
|
|
|
|
</View>
|
|
|
|
|
|
<View style={styles.inviteTextContainer}>
|
|
|
|
|
|
<Text variant="body" style={styles.inviteTitle}>邀请成员</Text>
|
|
|
|
|
|
<Text variant="caption" color={colors.text.secondary}>
|
|
|
|
|
|
仅可从互关好友中选择成员加入群聊
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
<MaterialCommunityIcons name="chevron-right" size={24} color={colors.text.hint} />
|
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
|
</ScrollView>
|
|
|
|
|
|
|
|
|
|
|
|
{/* 创建按钮 */}
|
|
|
|
|
|
<View style={styles.footer}>
|
|
|
|
|
|
<Button
|
|
|
|
|
|
title="创建群聊"
|
|
|
|
|
|
onPress={handleCreateGroup}
|
|
|
|
|
|
loading={submitting}
|
|
|
|
|
|
disabled={!groupName.trim() || submitting}
|
|
|
|
|
|
fullWidth
|
|
|
|
|
|
size="lg"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</View>
|
|
|
|
|
|
|
|
|
|
|
|
<MutualFollowSelectorModal
|
|
|
|
|
|
visible={inviteModalVisible}
|
|
|
|
|
|
title="邀请成员"
|
|
|
|
|
|
confirmText="完成"
|
|
|
|
|
|
initialSelectedIds={Array.from(selectedMemberIds)}
|
|
|
|
|
|
onClose={() => setInviteModalVisible(false)}
|
|
|
|
|
|
onConfirm={handleConfirmMembers}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</SafeAreaView>
|
|
|
|
|
|
);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-03-25 05:16:54 +08:00
|
|
|
|
function createCreateGroupStyles(colors: AppColors) {
|
|
|
|
|
|
return StyleSheet.create({
|
|
|
|
|
|
container: {
|
|
|
|
|
|
flex: 1,
|
|
|
|
|
|
backgroundColor: colors.background.default,
|
|
|
|
|
|
},
|
|
|
|
|
|
scrollView: {
|
|
|
|
|
|
flex: 1,
|
|
|
|
|
|
},
|
|
|
|
|
|
scrollContent: {
|
|
|
|
|
|
padding: spacing.lg,
|
|
|
|
|
|
paddingBottom: spacing.xl,
|
|
|
|
|
|
},
|
|
|
|
|
|
// 头部区域样式
|
|
|
|
|
|
headerSection: {
|
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
|
alignItems: 'flex-start',
|
|
|
|
|
|
marginBottom: spacing.xl,
|
|
|
|
|
|
},
|
|
|
|
|
|
avatarContainer: {
|
|
|
|
|
|
marginRight: spacing.lg,
|
|
|
|
|
|
},
|
|
|
|
|
|
avatarWrapper: {
|
|
|
|
|
|
position: 'relative',
|
|
|
|
|
|
},
|
|
|
|
|
|
avatarImage: {
|
|
|
|
|
|
width: 80,
|
|
|
|
|
|
height: 80,
|
|
|
|
|
|
borderRadius: 40,
|
|
|
|
|
|
},
|
|
|
|
|
|
avatarPlaceholder: {
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
backgroundColor: colors.background.default,
|
|
|
|
|
|
borderRadius: 40,
|
|
|
|
|
|
},
|
|
|
|
|
|
avatarBadge: {
|
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
|
bottom: 0,
|
|
|
|
|
|
right: 0,
|
|
|
|
|
|
backgroundColor: colors.primary.main,
|
|
|
|
|
|
width: 28,
|
|
|
|
|
|
height: 28,
|
|
|
|
|
|
borderRadius: 14,
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
borderWidth: 2,
|
|
|
|
|
|
borderColor: colors.background.paper,
|
|
|
|
|
|
},
|
|
|
|
|
|
nameInputContainer: {
|
|
|
|
|
|
flex: 1,
|
|
|
|
|
|
paddingTop: spacing.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
inputLabel: {
|
|
|
|
|
|
marginBottom: spacing.sm,
|
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
|
},
|
|
|
|
|
|
nameInput: {
|
|
|
|
|
|
backgroundColor: colors.background.paper,
|
|
|
|
|
|
borderRadius: borderRadius.lg,
|
|
|
|
|
|
paddingHorizontal: spacing.md,
|
|
|
|
|
|
paddingVertical: spacing.md,
|
|
|
|
|
|
fontSize: fontSizes.lg,
|
|
|
|
|
|
color: colors.text.primary,
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
borderColor: colors.divider,
|
|
|
|
|
|
},
|
|
|
|
|
|
charCount: {
|
|
|
|
|
|
textAlign: 'right',
|
|
|
|
|
|
marginTop: spacing.xs,
|
|
|
|
|
|
},
|
|
|
|
|
|
// 区域样式
|
|
|
|
|
|
section: {
|
|
|
|
|
|
marginBottom: spacing.xl,
|
|
|
|
|
|
},
|
|
|
|
|
|
sectionHeader: {
|
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
|
justifyContent: 'space-between',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
marginBottom: spacing.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
sectionTitle: {
|
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
|
marginBottom: spacing.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
// 文本域样式
|
|
|
|
|
|
textAreaContainer: {
|
|
|
|
|
|
backgroundColor: colors.background.paper,
|
|
|
|
|
|
borderRadius: borderRadius.lg,
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
borderColor: colors.divider,
|
|
|
|
|
|
padding: spacing.md,
|
|
|
|
|
|
},
|
|
|
|
|
|
textArea: {
|
|
|
|
|
|
minHeight: 100,
|
|
|
|
|
|
fontSize: fontSizes.md,
|
|
|
|
|
|
color: colors.text.primary,
|
|
|
|
|
|
lineHeight: 22,
|
|
|
|
|
|
},
|
|
|
|
|
|
textAreaCharCount: {
|
|
|
|
|
|
textAlign: 'right',
|
|
|
|
|
|
marginTop: spacing.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
// 已选成员样式
|
|
|
|
|
|
selectedMembersList: {
|
|
|
|
|
|
paddingVertical: spacing.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
selectedMemberItem: {
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
marginRight: spacing.lg,
|
|
|
|
|
|
width: 64,
|
|
|
|
|
|
},
|
|
|
|
|
|
removeMemberButton: {
|
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
|
top: -4,
|
|
|
|
|
|
right: 4,
|
|
|
|
|
|
},
|
|
|
|
|
|
removeIconContainer: {
|
|
|
|
|
|
backgroundColor: colors.text.secondary,
|
|
|
|
|
|
borderRadius: 10,
|
|
|
|
|
|
width: 20,
|
|
|
|
|
|
height: 20,
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
borderWidth: 2,
|
|
|
|
|
|
borderColor: colors.background.paper,
|
|
|
|
|
|
},
|
|
|
|
|
|
selectedMemberName: {
|
|
|
|
|
|
marginTop: spacing.xs,
|
|
|
|
|
|
textAlign: 'center',
|
|
|
|
|
|
width: '100%',
|
|
|
|
|
|
},
|
|
|
|
|
|
// 邀请按钮样式
|
|
|
|
|
|
inviteButton: {
|
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
backgroundColor: colors.background.paper,
|
|
|
|
|
|
borderRadius: borderRadius.lg,
|
|
|
|
|
|
padding: spacing.md,
|
|
|
|
|
|
marginBottom: spacing.xl,
|
|
|
|
|
|
...shadows.sm,
|
|
|
|
|
|
},
|
|
|
|
|
|
inviteIconContainer: {
|
|
|
|
|
|
width: 48,
|
|
|
|
|
|
height: 48,
|
|
|
|
|
|
borderRadius: borderRadius.lg,
|
|
|
|
|
|
backgroundColor: colors.primary.light + '20',
|
|
|
|
|
|
justifyContent: 'center',
|
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
|
marginRight: spacing.md,
|
|
|
|
|
|
},
|
|
|
|
|
|
inviteTextContainer: {
|
|
|
|
|
|
flex: 1,
|
|
|
|
|
|
},
|
|
|
|
|
|
inviteTitle: {
|
|
|
|
|
|
fontWeight: '600',
|
|
|
|
|
|
marginBottom: 2,
|
|
|
|
|
|
},
|
|
|
|
|
|
// 底部按钮样式
|
|
|
|
|
|
footer: {
|
|
|
|
|
|
padding: spacing.lg,
|
|
|
|
|
|
paddingBottom: spacing.xl,
|
|
|
|
|
|
backgroundColor: colors.background.paper,
|
|
|
|
|
|
borderTopWidth: 1,
|
|
|
|
|
|
borderTopColor: colors.divider,
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-03-09 21:29:03 +08:00
|
|
|
|
|
|
|
|
|
|
export default CreateGroupScreen;
|