icon picker
Phân tích chức năng

Last edited 251 days ago by Long Nguyễn
info

Cần confirm lại

Các behavor cần có từ màn 4 - 7
các màn nào cần có design thì confirm lại khách xem có chưa?

ok

Ghi chú

Tuần đầu có thể Long cover các task ưu tiên, nên trong tuần này Mạnh sẽ nghiên cứu 1 phần trước (màn 4 - 7)
chức năng Camera & video
3
Nhân sự
Màn hình
Tên chức năng
mô tả chức năng theo ý hiểu
tham khảo
Tính khả thi
Thời gian thực thi
1
Long
Màn hình 1
image.png
Bật đèn flash trong camera
Có 1 màn hình camera
thêm 1 button để bật - tắt flash
sử dụng function của thư viện để bật flash

yarn add react-native-vision-camera
Example:
import React, { useState } from 'react';
import { Camera } from 'react-native-vision-camera';

const FlashCamera = () => {
const [isFlashOn, setFlashOn] = useState(false);

const toggleFlash = () => {
setFlashOn(!isFlashOn);
};

return (
<Camera torch={isFlashOn} style={{ flex: 1 }}>
<button onPress={toggleFlash}>Toggle Flash</button>
</Camera>
);
};

export default FlashCamera;
✅ khả thi 100%
chỉ cần xử lý trên js
có thư viện support
khoảng 8h
2
Long
màn hình 2
image.png
Hẹn giờ bắt đầu quay video
như trong description UI thì chỉ có phần đếm ngược → không có phần đặt giới hạn quay (cần re-confirm)
sau khi đếm ngược X giây, camera sẽ tự động quay clip

Example:
import React, { useState, useEffect } from 'react';
import { Camera } from 'react-native-vision-camera';

const CountdownCamera = () => {
const [countdown, setCountdown] = useState(0);
const cameraRef = useRef(null);

useEffect(() => {
let interval = null;
if (countdown > 0) {
interval = setInterval(() => {
setCountdown(countdown - 1);
}, 1000);
} else if (countdown === 0) {
startRecording();
}
return () => clearInterval(interval);
}, [countdown]);

const startCountdown = () => {
setCountdown(3); // Start countdown from 3
};

const startRecording = async () => {
if (cameraRef.current) {
const data = await cameraRef.current.startRecording();
console.log(data);
}
};

return (
<Camera ref={cameraRef} style={{ flex: 1 }}>
<button onPress={startCountdown}>Start Countdown</button>
{countdown > 0 && <p>Recording in {countdown}</p>}
</Camera>
);
};

export default CountdownCamera;
✅ khả thi 100%
chỉ cần xử lý trên js
có thư viện support
khoảng 6h
3
LOng
Màn hình 3
image.png
thay đổi tốc độ quay video (timelapse, slowmotion, ...)
keyword: Trim control
có thể thay đổi tốc độ quay video theo các mức 0.3, 0.5, 1, 2, 3

Example:
import React, { useRef } from 'react';
import { Camera } from 'react-native-vision-camera';

const SlowMotionCamera = () => {
const cameraRef = useRef(null);

const startRecording = async () => {
if (cameraRef.current) {
const options = { frameRate: 120 }; // Set high frame rate for slow motion
const data = await cameraRef.current.startRecording(options);
console.log(data);
}
};

const stopRecording = () => {
if (cameraRef.current) {
cameraRef.current.stopRecording();
}
};

return (
<Camera ref={cameraRef} style={{ flex: 1 }}>
<button onPress={startRecording}>Start Recording</button>
<button onPress={stopRecording}>Stop Recording</button>
</Camera>
);
};

export default SlowMotionCamera;
❗️ khả thi 80%
chỉ cần xử lý trên js
có thư viện support
nhưng không biết code như này có chạy được thật không, nếu không chạy được như kỳ vọng thì phải build native module.
Example:
import AVFoundation

let captureSession = AVCaptureSession()
guard let camera = AVCaptureDevice.default(for: .video) else { return }

do {
let input = try AVCaptureDeviceInput(device: camera)
captureSession.addInput(input)
} catch {
print("Error creating input: \(error)")
return
}

if let format = camera.formats.filter({ CMTimeGetSeconds($0.videoMaxFrameDuration) >= 120 }).first {
do {
try camera.lockForConfiguration()
camera.activeFormat = format
camera.activeVideoMinFrameDuration = CMTime(value: 1, timescale: 120) // Set high frame rate for slow motion
camera.unlockForConfiguration()
} catch {
print("Error setting format: \(error)")
return
}
}

captureSession.startRunning()
Cần thời gian nghiên cứu: 4h Thời gian thực thi: 4h
4
Long + Mạnh
Màn hình 4
image.png
Phân chia video
xoá đi các đoạn được phân chia đó
phân chia video thì đầu tiên phải tách video thành các image frames.
→ có thể dùng thư viện để calculate the times at which to extract frames.
xoá đc các phân đoạn video đã chọn
→ cái này có thể nhờ backend xử bằng cách : gửi video lên server, gửi thêm startTime & endTime để cắt đi đc đoạn video mong muốn
Example:
import { ProcessingManager } from 'react-native-video-processing';

const extractFrames = async (videoPath) => {
const videoInfo = await ProcessingManager.getVideoInfo(videoPath);

const frameTimes = []; // Calculate frame times based on videoInfo.duration

const frames = await Promise.all(
frameTimes.map((time) =>
ProcessingManager.getPreviewForSecond(videoPath, time)
)
);

// frames now contains the image data for each frame
};

extractFrames('path/to/video.mp4');
hoặc có thể dùng cách này
đọc ra các frame images, ghi vào file
đọc từ file ra các images đó
import { FFmpegKit, FFmpegKitConfig, ReturnCode } from 'ffmpeg-kit-react-native';
import RNFS from 'react-native-fs';

const extractFrames = async (videoPath, outputPath, frameRate) => {
const command = `-i ${videoPath} -vf fps=${frameRate} ${outputPath}/frame%03d.jpg`;

const session = await FFmpegKit.execute(command);

if (ReturnCode.isSuccess(session.getReturnCode())) {
console.log('Frames extracted successfully');
} else {
console.log('Error extracting frames:', session.getFailStackTrace());
return [];
}

const files = await RNFS.readdir(outputPath);
return files.map(file => `${outputPath}/${file}`);
};

extractFrames('path/to/video.mp4', 'path/to/output', 1)
.then(frames => console.log(frames));
đây là UI để chọn các frame

Hoặc có thể mua SDK bên thứ 3:

❗️ khả thi 50%
chỉ cần xử lý trên js
có thư viện support
nhưng không biết code như này có chạy được thật không, nếu không chạy được như kỳ vọng thì phải build native module.
cần backend support build, render video (có thể cần 80%) → để client focus xử lý các vấn đề khác .
Cần confirm lại với khách xem màn hình này có những behavor gì?
pseudocode:
Load the video file.

video = load_video(video_path)
Define the sections of the video.

sections = [(start1, end1), (start2, end2), ..., (startN, endN)]
Split the video into sections.

clips = [video.subclip(start, end) for start, end in sections]
Define the indices of the sections to delete.

sections_to_delete = [index1, index2, ..., indexM]
Delete the specified sections.

clips = [clip for i, clip in enumerate(clips) if i not in sections_to_delete]
Concatenate the remaining sections to rebuild the video.

final_video = concatenate_clips(clips)
Save the final video to a file.

save_video(final_video, output_path)

Thời gian nghiên cứu demo: 8x3 = 24h
5
Long + Mạnh
Màn hình 5
image.png
chèn chữ vào video
có thể customize chữ , tuỳ chỉnh hiệu ứng theo form có sẵn
chèn chữ vào video, không biết có cần kéo thả chữ hay ko?
→ nếu cần kéo thả chữ , thì cần 1 backend service hỗ trợ, client sẽ truyền lên video và text đó + toạ độ (x,y) của text ở trên màn hình để backend chèn chữ vào đúng vị trí đó trong video.
Example :
đây là UI UX drag text to any where on screen
mport React from 'react';
import { View, StyleSheet } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { useAnimatedGestureHandler, useAnimatedStyle, withSpring } from 'react-native-reanimated';

const DragDropUI = () => {
const position = React.useRef(new Animated.ValueXY()).current;

const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.startX = position.value.x;
ctx.startY = position.value.y;
},
onActive: (event, ctx) => {
position.value.x = ctx.startX + event.translationX;
position.value.y = ctx.startY + event.translationY;
},
onEnd: () => {
position.value.x = withSpring(0);
position.value.y = withSpring(0);
},
});

const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{ translateX: position.value.x },
{ translateY: position.value.y },
],
};
});

return (
<View style={styles.container}>
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]} />
</PanGestureHandler>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 100,
height: 100,
backgroundColor: 'blue',
},
});

export default DragDropUI;

❗️ khả thi 60%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .

pseudocode
1. Load the video file.
- `video = load_video(video_path)`

2. Create a text clip with the desired text, font size, and color.
- `text_clip = create_text_clip(text, font_size, color)`

3. Set the position of the text clip.
- `text_clip = set_position(text_clip, x, y)`

4. Set the duration of the text clip to match the duration of the video.
- `text_clip = set_duration(text_clip, video_duration)`

5. Overlay the text clip on the video.
- `final_video = overlay_text_on_video(video, text_clip)`

6. Save the final video to a file.
- `save_video(final_video, output_path)`
Thời gian nghiên cứu demo: 8x2 = 16h
6
Long + Mạnh
màn hình 6:
image.png
Chèn âm thanh vào video
chèn âm thanh vào 1 phần của video
Cần backend render lại video, client truyền lên file audio, file video, time start , time end
reackeyword: waveform sound react native sound UI customize như trim video
❗️ khả thi 70%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .
pseudocode
1. Load the video file.
- `video = load_video(video_path)`

2. Load the audio file.
- `audio = load_audio(audio_path)`

3. Trim the audio to the desired start and end times.
- `audio = trim_audio(audio, start_time, end_time)`

4. Set the audio of the video to the trimmed audio.
- `video = set_audio(video, audio)`

5. Save the final video to a file.
- `save_video(video, output_path)`

Thời gian nghiên cứu demo: 8x2 = 16h
7
Long + Mạnh
màn hình 7
Chèn nhãn dán, biểu tượng cảm xúc vào video
giống chức năm 5, nhg thay text bằng nhãn dán, biểu tượng cảm xúc , hình ảnh
Làm đc chức năng 5 thì sẽ làm đc chức năng này
❗️ khả thi 60%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .
Thời gian nghiên cứu demo: 8x2 = 16h
There are no rows in this table
View of Đánh giá chức năng
3
Nhân sự
Màn hình
Tên chức năng
mô tả chức năng theo ý hiểu
tham khảo
Tính khả thi
Thời gian thực thi
1
Long
Màn hình 1
image.png
Bật đèn flash trong camera
Có 1 màn hình camera
thêm 1 button để bật - tắt flash
sử dụng function của thư viện để bật flash

yarn add react-native-vision-camera
Example:
import React, { useState } from 'react';
import { Camera } from 'react-native-vision-camera';

const FlashCamera = () => {
const [isFlashOn, setFlashOn] = useState(false);

const toggleFlash = () => {
setFlashOn(!isFlashOn);
};

return (
<Camera torch={isFlashOn} style={{ flex: 1 }}>
<button onPress={toggleFlash}>Toggle Flash</button>
</Camera>
);
};

export default FlashCamera;
✅ khả thi 100%
chỉ cần xử lý trên js
có thư viện support
khoảng 8h
2
Long
màn hình 2
image.png
Hẹn giờ bắt đầu quay video
như trong description UI thì chỉ có phần đếm ngược → không có phần đặt giới hạn quay (cần re-confirm)
sau khi đếm ngược X giây, camera sẽ tự động quay clip

Example:
import React, { useState, useEffect } from 'react';
import { Camera } from 'react-native-vision-camera';

const CountdownCamera = () => {
const [countdown, setCountdown] = useState(0);
const cameraRef = useRef(null);

useEffect(() => {
let interval = null;
if (countdown > 0) {
interval = setInterval(() => {
setCountdown(countdown - 1);
}, 1000);
} else if (countdown === 0) {
startRecording();
}
return () => clearInterval(interval);
}, [countdown]);

const startCountdown = () => {
setCountdown(3); // Start countdown from 3
};

const startRecording = async () => {
if (cameraRef.current) {
const data = await cameraRef.current.startRecording();
console.log(data);
}
};

return (
<Camera ref={cameraRef} style={{ flex: 1 }}>
<button onPress={startCountdown}>Start Countdown</button>
{countdown > 0 && <p>Recording in {countdown}</p>}
</Camera>
);
};

export default CountdownCamera;
✅ khả thi 100%
chỉ cần xử lý trên js
có thư viện support
khoảng 6h
3
LOng
Màn hình 3
image.png
thay đổi tốc độ quay video (timelapse, slowmotion, ...)
keyword: Trim control
có thể thay đổi tốc độ quay video theo các mức 0.3, 0.5, 1, 2, 3

Example:
import React, { useRef } from 'react';
import { Camera } from 'react-native-vision-camera';

const SlowMotionCamera = () => {
const cameraRef = useRef(null);

const startRecording = async () => {
if (cameraRef.current) {
const options = { frameRate: 120 }; // Set high frame rate for slow motion
const data = await cameraRef.current.startRecording(options);
console.log(data);
}
};

const stopRecording = () => {
if (cameraRef.current) {
cameraRef.current.stopRecording();
}
};

return (
<Camera ref={cameraRef} style={{ flex: 1 }}>
<button onPress={startRecording}>Start Recording</button>
<button onPress={stopRecording}>Stop Recording</button>
</Camera>
);
};

export default SlowMotionCamera;
❗️ khả thi 80%
chỉ cần xử lý trên js
có thư viện support
nhưng không biết code như này có chạy được thật không, nếu không chạy được như kỳ vọng thì phải build native module.
Example:
import AVFoundation

let captureSession = AVCaptureSession()
guard let camera = AVCaptureDevice.default(for: .video) else { return }

do {
let input = try AVCaptureDeviceInput(device: camera)
captureSession.addInput(input)
} catch {
print("Error creating input: \(error)")
return
}

if let format = camera.formats.filter({ CMTimeGetSeconds($0.videoMaxFrameDuration) >= 120 }).first {
do {
try camera.lockForConfiguration()
camera.activeFormat = format
camera.activeVideoMinFrameDuration = CMTime(value: 1, timescale: 120) // Set high frame rate for slow motion
camera.unlockForConfiguration()
} catch {
print("Error setting format: \(error)")
return
}
}

captureSession.startRunning()
Cần thời gian nghiên cứu: 4h Thời gian thực thi: 4h
4
Long + Mạnh
Màn hình 4
image.png
Phân chia video
xoá đi các đoạn được phân chia đó
phân chia video thì đầu tiên phải tách video thành các image frames.
→ có thể dùng thư viện để calculate the times at which to extract frames.
xoá đc các phân đoạn video đã chọn
→ cái này có thể nhờ backend xử bằng cách : gửi video lên server, gửi thêm startTime & endTime để cắt đi đc đoạn video mong muốn
Example:
import { ProcessingManager } from 'react-native-video-processing';

const extractFrames = async (videoPath) => {
const videoInfo = await ProcessingManager.getVideoInfo(videoPath);

const frameTimes = []; // Calculate frame times based on videoInfo.duration

const frames = await Promise.all(
frameTimes.map((time) =>
ProcessingManager.getPreviewForSecond(videoPath, time)
)
);

// frames now contains the image data for each frame
};

extractFrames('path/to/video.mp4');
hoặc có thể dùng cách này
đọc ra các frame images, ghi vào file
đọc từ file ra các images đó
import { FFmpegKit, FFmpegKitConfig, ReturnCode } from 'ffmpeg-kit-react-native';
import RNFS from 'react-native-fs';

const extractFrames = async (videoPath, outputPath, frameRate) => {
const command = `-i ${videoPath} -vf fps=${frameRate} ${outputPath}/frame%03d.jpg`;

const session = await FFmpegKit.execute(command);

if (ReturnCode.isSuccess(session.getReturnCode())) {
console.log('Frames extracted successfully');
} else {
console.log('Error extracting frames:', session.getFailStackTrace());
return [];
}

const files = await RNFS.readdir(outputPath);
return files.map(file => `${outputPath}/${file}`);
};

extractFrames('path/to/video.mp4', 'path/to/output', 1)
.then(frames => console.log(frames));
đây là UI để chọn các frame

Hoặc có thể mua SDK bên thứ 3:

❗️ khả thi 50%
chỉ cần xử lý trên js
có thư viện support
nhưng không biết code như này có chạy được thật không, nếu không chạy được như kỳ vọng thì phải build native module.
cần backend support build, render video (có thể cần 80%) → để client focus xử lý các vấn đề khác .
Cần confirm lại với khách xem màn hình này có những behavor gì?
pseudocode:
Load the video file.

video = load_video(video_path)
Define the sections of the video.

sections = [(start1, end1), (start2, end2), ..., (startN, endN)]
Split the video into sections.

clips = [video.subclip(start, end) for start, end in sections]
Define the indices of the sections to delete.

sections_to_delete = [index1, index2, ..., indexM]
Delete the specified sections.

clips = [clip for i, clip in enumerate(clips) if i not in sections_to_delete]
Concatenate the remaining sections to rebuild the video.

final_video = concatenate_clips(clips)
Save the final video to a file.

save_video(final_video, output_path)

Thời gian nghiên cứu demo: 8x3 = 24h
5
Long + Mạnh
Màn hình 5
image.png
chèn chữ vào video
có thể customize chữ , tuỳ chỉnh hiệu ứng theo form có sẵn
chèn chữ vào video, không biết có cần kéo thả chữ hay ko?
→ nếu cần kéo thả chữ , thì cần 1 backend service hỗ trợ, client sẽ truyền lên video và text đó + toạ độ (x,y) của text ở trên màn hình để backend chèn chữ vào đúng vị trí đó trong video.
Example :
đây là UI UX drag text to any where on screen
mport React from 'react';
import { View, StyleSheet } from 'react-native';
import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, { useAnimatedGestureHandler, useAnimatedStyle, withSpring } from 'react-native-reanimated';

const DragDropUI = () => {
const position = React.useRef(new Animated.ValueXY()).current;

const gestureHandler = useAnimatedGestureHandler({
onStart: (_, ctx) => {
ctx.startX = position.value.x;
ctx.startY = position.value.y;
},
onActive: (event, ctx) => {
position.value.x = ctx.startX + event.translationX;
position.value.y = ctx.startY + event.translationY;
},
onEnd: () => {
position.value.x = withSpring(0);
position.value.y = withSpring(0);
},
});

const animatedStyle = useAnimatedStyle(() => {
return {
transform: [
{ translateX: position.value.x },
{ translateY: position.value.y },
],
};
});

return (
<View style={styles.container}>
<PanGestureHandler onGestureEvent={gestureHandler}>
<Animated.View style={[styles.box, animatedStyle]} />
</PanGestureHandler>
</View>
);
};

const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
box: {
width: 100,
height: 100,
backgroundColor: 'blue',
},
});

export default DragDropUI;

❗️ khả thi 60%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .

pseudocode
1. Load the video file.
- `video = load_video(video_path)`

2. Create a text clip with the desired text, font size, and color.
- `text_clip = create_text_clip(text, font_size, color)`

3. Set the position of the text clip.
- `text_clip = set_position(text_clip, x, y)`

4. Set the duration of the text clip to match the duration of the video.
- `text_clip = set_duration(text_clip, video_duration)`

5. Overlay the text clip on the video.
- `final_video = overlay_text_on_video(video, text_clip)`

6. Save the final video to a file.
- `save_video(final_video, output_path)`
Thời gian nghiên cứu demo: 8x2 = 16h
6
Long + Mạnh
màn hình 6:
image.png
Chèn âm thanh vào video
chèn âm thanh vào 1 phần của video
Cần backend render lại video, client truyền lên file audio, file video, time start , time end
reackeyword: waveform sound react native sound UI customize như trim video
❗️ khả thi 70%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .
pseudocode
1. Load the video file.
- `video = load_video(video_path)`

2. Load the audio file.
- `audio = load_audio(audio_path)`

3. Trim the audio to the desired start and end times.
- `audio = trim_audio(audio, start_time, end_time)`

4. Set the audio of the video to the trimmed audio.
- `video = set_audio(video, audio)`

5. Save the final video to a file.
- `save_video(video, output_path)`

Thời gian nghiên cứu demo: 8x2 = 16h
7
Long + Mạnh
màn hình 7
Chèn nhãn dán, biểu tượng cảm xúc vào video
giống chức năm 5, nhg thay text bằng nhãn dán, biểu tượng cảm xúc , hình ảnh
Làm đc chức năng 5 thì sẽ làm đc chức năng này
❗️ khả thi 60%
chỉ cần xử lý trên js
có thư viện support
cần backend support build, render video (cần 100%) → để client focus xử lý các vấn đề khác .
Thời gian nghiên cứu demo: 8x2 = 16h
There are no rows in this table



Karaoke bottomtab
Màn hình
Tên chức năng
mô tả chức năng theo ý hiểu
tham khảo
Tính khả thi
1
Home,
Hiện bottom tab khi show màn hình karaoke , để người dùng có thể chuyển tab khi vẫn đang dùng karaoke.
IOS:
Cần code lại module call với karaoke SDK
cho height của màn karaoke ngắn lại để hiện ra bottom tab
add VTKaraDelegate shared thành sub view của root controller, sticky nó lên top của màn hình
ANDROID: Cần bên SDK return ra view
Tự đọc code rồi code lại
✅ khả thi 90%
chỉ cần xử lý trên js
có thư viện support
nhưng cần bên SDK code lại logic nut back, vì bây giờ ko còn dùng presentViewcontroller nữa
There are no rows in this table

Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.