Rebrand the entire application from "胡萝卜社区" (Carrot BBS) to "威友" (WithYou), including:
- Update app name, package name (skin.carrot.bbs → cn.qczlit.withyou), and bundle identifier - Update API endpoints (bbs.littlelan.cn → withyou.littlelan.cn) - Update URL scheme (carrotbbs:// → withyou://) - Rename database from carrot_bbs to with_you - Update CI/CD pipeline image names and artifact naming - Add Android signing configuration for release builds - Update all UI text and comments throughout the codebase - Refactor registerStore to use in-memory state instead of AsyncStorage persistence - Improve WebRTC track handling and call stream management - Add metro platform resolution for native platform support BREAKING app package, database, and URLs are no longer valid
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
/**
|
||||
* 注册流程状态管理
|
||||
* 使用 Zustand + AsyncStorage 实现步骤数据的持久化
|
||||
* 使用 Zustand 纯内存状态,不持久化到 AsyncStorage
|
||||
*/
|
||||
|
||||
import { create } from 'zustand';
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
|
||||
const STORAGE_KEY = 'register_form_data';
|
||||
|
||||
export type RegisterStep = 0 | 1 | 2;
|
||||
|
||||
@@ -42,9 +39,6 @@ interface RegisterState {
|
||||
resetRegisterData: () => void;
|
||||
goToNextStep: () => void;
|
||||
goToPrevStep: () => void;
|
||||
// 持久化
|
||||
hydrate: () => Promise<void>;
|
||||
persistData: () => Promise<void>;
|
||||
}
|
||||
|
||||
const initialFormData: RegisterFormData = {
|
||||
@@ -63,31 +57,18 @@ const initialCompletedSteps: Record<RegisterStep, boolean> = {
|
||||
2: false,
|
||||
};
|
||||
|
||||
export const useRegisterStore = create<RegisterState>((set, get) => ({
|
||||
export const useRegisterStore = create<RegisterState>((set) => ({
|
||||
currentStep: 0,
|
||||
formData: initialFormData,
|
||||
countdown: 0,
|
||||
completedSteps: initialCompletedSteps,
|
||||
|
||||
setCurrentStep: (step) => {
|
||||
set({ currentStep: step });
|
||||
get().persistData();
|
||||
},
|
||||
setCurrentStep: (step) => set({ currentStep: step }),
|
||||
|
||||
updateFormData: (data) =>
|
||||
set((state) => {
|
||||
const newFormData = { ...state.formData, ...data };
|
||||
// 异步保存到 AsyncStorage
|
||||
AsyncStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
currentStep: state.currentStep,
|
||||
formData: newFormData,
|
||||
completedSteps: state.completedSteps,
|
||||
})
|
||||
).catch(() => {});
|
||||
return { formData: newFormData };
|
||||
}),
|
||||
set((state) => ({
|
||||
formData: { ...state.formData, ...data },
|
||||
})),
|
||||
|
||||
setCountdown: (seconds) => set({ countdown: seconds }),
|
||||
|
||||
@@ -97,81 +78,33 @@ export const useRegisterStore = create<RegisterState>((set, get) => ({
|
||||
})),
|
||||
|
||||
markStepCompleted: (step) =>
|
||||
set((state) => {
|
||||
const newCompletedSteps = { ...state.completedSteps, [step]: true };
|
||||
// 异步保存到 AsyncStorage
|
||||
AsyncStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
currentStep: state.currentStep,
|
||||
formData: state.formData,
|
||||
completedSteps: newCompletedSteps,
|
||||
})
|
||||
).catch(() => {});
|
||||
return { completedSteps: newCompletedSteps };
|
||||
}),
|
||||
set((state) => ({
|
||||
completedSteps: { ...state.completedSteps, [step]: true },
|
||||
})),
|
||||
|
||||
resetRegisterData: () => {
|
||||
resetRegisterData: () =>
|
||||
set({
|
||||
currentStep: 0,
|
||||
formData: initialFormData,
|
||||
countdown: 0,
|
||||
completedSteps: initialCompletedSteps,
|
||||
});
|
||||
AsyncStorage.removeItem(STORAGE_KEY).catch(() => {});
|
||||
},
|
||||
}),
|
||||
|
||||
goToNextStep: () => {
|
||||
const { currentStep } = get();
|
||||
if (currentStep < 2) {
|
||||
const newStep = (currentStep + 1) as RegisterStep;
|
||||
set({ currentStep: newStep });
|
||||
get().persistData();
|
||||
}
|
||||
},
|
||||
|
||||
goToPrevStep: () => {
|
||||
const { currentStep } = get();
|
||||
if (currentStep > 0) {
|
||||
const newStep = (currentStep - 1) as RegisterStep;
|
||||
set({ currentStep: newStep });
|
||||
get().persistData();
|
||||
}
|
||||
},
|
||||
|
||||
// 从 AsyncStorage 恢复数据
|
||||
hydrate: async () => {
|
||||
try {
|
||||
const raw = await AsyncStorage.getItem(STORAGE_KEY);
|
||||
if (raw) {
|
||||
const data = JSON.parse(raw);
|
||||
set({
|
||||
currentStep: data.currentStep ?? 0,
|
||||
formData: { ...initialFormData, ...data.formData },
|
||||
completedSteps: { ...initialCompletedSteps, ...data.completedSteps },
|
||||
});
|
||||
goToNextStep: () =>
|
||||
set((state) => {
|
||||
if (state.currentStep < 2) {
|
||||
return { currentStep: (state.currentStep + 1) as RegisterStep };
|
||||
}
|
||||
} catch {
|
||||
// 忽略错误
|
||||
}
|
||||
},
|
||||
return state;
|
||||
}),
|
||||
|
||||
// 保存数据到 AsyncStorage
|
||||
persistData: async () => {
|
||||
const { currentStep, formData, completedSteps } = get();
|
||||
try {
|
||||
await AsyncStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
currentStep,
|
||||
formData,
|
||||
completedSteps,
|
||||
})
|
||||
);
|
||||
} catch {
|
||||
// 忽略错误
|
||||
}
|
||||
},
|
||||
goToPrevStep: () =>
|
||||
set((state) => {
|
||||
if (state.currentStep > 0) {
|
||||
return { currentStep: (state.currentStep - 1) as RegisterStep };
|
||||
}
|
||||
return state;
|
||||
}),
|
||||
}));
|
||||
|
||||
// 导出便捷 hooks
|
||||
|
||||
@@ -146,13 +146,20 @@ function setupWebRTCEvents(callId: string, myUserId: string): void {
|
||||
* Handle remote stream with video track detection
|
||||
*/
|
||||
function handleRemoteStream(stream: MediaStream): void {
|
||||
callStore.setState({ peerStream: stream });
|
||||
// Create a new MediaStream instance to force zustand subscribers to update
|
||||
// because react-native-webrtc may add tracks to the same stream object reference
|
||||
const newStream = new MediaStream();
|
||||
stream.getTracks().forEach((track) => {
|
||||
newStream.addTrack(track);
|
||||
});
|
||||
|
||||
callStore.setState({ peerStream: newStream });
|
||||
|
||||
// Detect video tracks in remote stream
|
||||
const videoTracks = stream.getVideoTracks();
|
||||
const videoTracks = newStream.getVideoTracks();
|
||||
const hasPeerVideo = videoTracks.length > 0 && videoTracks.some((t) => t.enabled);
|
||||
|
||||
console.log('[CallStore] Remote stream received, hasVideo:', hasPeerVideo, 'videoTracks:', videoTracks.length);
|
||||
console.log('[CallStore] Remote stream received, hasVideo:', hasPeerVideo, 'videoTracks:', videoTracks.length, 'audioTracks:', newStream.getAudioTracks().length);
|
||||
|
||||
callStore.setState((s) => ({
|
||||
currentCall: s.currentCall
|
||||
|
||||
Reference in New Issue
Block a user