Initial commit: Set up retro photobooth monorepo structure, core configurations, and premium sample assets

This commit is contained in:
2026-07-05 11:47:59 +07:00
commit a3b9c24936
17 changed files with 1603 additions and 0 deletions
+33
View File
@@ -0,0 +1,33 @@
# --- OS Files ---
.DS_Store
Thumbs.db
*.swp
# --- Android Studio / Gradle ---
.gradle/
build/
captures/
.externalNativeBuild/
.cxx/
local.properties
*.apk
*.aar
*.bms
.idea/workspace.xml
.idea/libraries/
.idea/caches/
# --- Xcode / iOS ---
build/
DerivedData/
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
*.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
.strongspace/
project.xcworkspace/
xcuserdata/
*.moved-aside
*.xccheckout
*.xcscmblueprint
+28
View File
@@ -0,0 +1,28 @@
# Kế hoạch Phát triển Dự án Mobile Photobooth (Vintage Style)
Tài liệu này ghi nhận kế hoạch phát triển qua các giai đoạn (sprint) cho ứng dụng Mobile Photobooth.
## 📅 Giai Đoạn 1 (Sprint 1 - Tuần 1-2)
* **Thiết lập cấu trúc monorepo & quyền:** Hoàn thành việc tạo thư mục và các cấu hình quyền Android/iOS.
* **Chuẩn bị dữ liệu mẫu:** Tải các font chữ vintage, khung hình Instax mini và stickers.
* **Màn hình Preview Camera (Android):** Code màn hình Preview Camera cơ bản sử dụng Jetpack Compose và CameraX.
* **Tích hợp KVM trên emulator:** Cấu hình chạy thử nghiệm.
## 📅 Giai Đoạn 2 (Sprint 2 - Tuần 3-4)
* **Bộ lọc Vintage (Filters):** Phát triển bộ lọc màu vintage (sepia, monochrome, warm tones).
* **Trang trí (Sticker & Frame):** Cho phép người dùng kéo thả sticker và chọn khung ảnh Instax/Photobooth 4-strip.
* **Lưu và chia sẻ:** Xuất ảnh chất lượng cao và lưu vào thư viện thiết bị.
## 💡 Cấu trúc dữ liệu vị trí Sticker (Đề xuất)
Để đồng bộ tọa độ sticker giữa iOS và Android, sử dụng phần trăm vị trí thay vì pixel:
```json
{
"sticker_id": "sunglasses",
"x_percent": 0.25,
"y_percent": 0.40,
"scale": 1.2,
"rotation_degree": 45
}
```
+198
View File
@@ -0,0 +1,198 @@
# 📋 KẾ HOẠCH PHÁT TRIỂN DỰ ÁN: MOBILE PHOTOBOOTH (VINTAGE STYLE)
Dự án ứng dụng Photobooth di động đa nền tảng (Native iOS/Android), lưu trữ mã nguồn tập trung trên Debian Linux, ưu tiên phát triển, build và kiểm thử trên Android trước.
---
## 📁 1. Cấu Trúc Thư Mục Dự Án (Monorepo Structure)
Tạo cấu trúc thư mục này tại thư mục gốc trên Debian Server để quản lý chung toàn bộ tài nguyên và mã nguồn của cả hai nền tảng.
```text
photobooth-project/
├── .gitignore
├── README.md
├── PLAN.md
├── assets/ # Tài nguyên dùng chung cho cả iOS và Android
│ ├── fonts/ # Font chữ vintage, viết tay (.ttf, .otf)
│ │ ├── CourierPrime-Regular.ttf
│ │ └── HomemadeApple-Regular.ttf
│ ├── frames/ # Khung ảnh định dạng PNG-24 trong suốt
│ │ ├── instax_mini_single.png
│ │ └── photobooth_4strip.png
│ └── stickers/ # Icon phụ kiện, smileys dạng vector/PNG cao cấp
│ ├── sunglasses.png
│ └── vintage_heart.svg
├── android-project/ # Dự án Android Native (Mở bằng Android Studio)
│ ├── build.gradle.kts
│ ├── settings.gradle.kts
│ └── app/
│ ├── build.gradle.kts
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ └── java/com/photobooth/app/ # Mã nguồn Kotlin
└── ios-project/ # Dự án iOS Native (Mở bằng Xcode trên Mac)
├── PhotoboothApp.xcodeproj
└── PhotoboothApp/
├── Info.plist
└── Assets.xcassets # Nơi chứa LaunchScreen, AppIcon của iOS
```
---
## 🛠️ 2. Chuẩn Bị Các Tập Tin Cấu Hình Cốt Lõi
### 🔹 File `2.1. .gitignore` (Đặt tại thư mục gốc)
Tập tin này giúp bỏ qua các file rác của hệ thống Linux, Android Studio và Xcode khi push code lên Debian Git Server.
```ini
# --- OS Files ---
.DS_Store
Thumbs.db
*.swp
# --- Android Studio / Gradle ---
.gradle/
build/
captures/
.externalNativeBuild/
.cxx/
local.properties
*.apk
*.aar
*.bms
.idea/workspace.xml
.idea/libraries/
.idea/caches/
# --- Xcode / iOS ---
build/
DerivedData/
*.xcodeproj/*
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
*.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
.strongspace/
project.xcworkspace/
xcuserdata/
*.moved-aside
*.xccheckout
*.xcscmblueprint
```
### 🔹 File `2.2. AndroidManifest.xml` (Cấu hình quyền Android)
Đặt tại `android-project/app/src/main/AndroidManifest.xml`. Cần khai báo sẵn các quyền về Camera, Lưu trữ và In ấn.
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.photobooth.app">
<!-- Quyền truy cập Camera -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<!-- Quyền lưu ảnh (Android 10 trở xuống cần WRITE, Android 11+ dùng Scoped Storage) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Quyền Internet để in ấn qua mạng Local -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Retro Photobooth"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
```
### 🔹 File `2.3. Info.plist` (Cấu hình quyền iOS)
Đặt sơ bộ tại `ios-project/PhotoboothApp/Info.plist` để khi chuyển sang Mac build không bị crash do thiếu giải trình quyền.
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.photobooth.app</string>
<key>CFBundleName</key>
<string>Retro Photobooth</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<!-- Giải trình quyền sử dụng Camera -->
<key>NSCameraUsageDescription</key>
<string>Ứng dụng cần sử dụng Camera để chụp ảnh Photobooth.</string>
<!-- Giải trình quyền lưu trữ ảnh vào Thư viện -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Ứng dụng cần quyền lưu ảnh đã chụp và trang trí vào thư viện của bạn.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Ứng dụng cần quyền thêm ảnh vào thư viện của bạn.</string>
</dict>
</plist>
```
---
## 🏃‍♂️ 3. Các Lệnh Triển Khai Nhanh Trên Debian Terminal
Để tạo nhanh bộ khung này trên Debian mà không cần tạo thủ công từng thư mục, bạn có thể chạy đoạn script ngắn này:
```bash
# 1. Tạo thư mục gốc dự án
mkdir -p photobooth-project && cd photobooth-project
# 2. Tạo cấu trúc thư mục tài nguyên và các project con
mkdir -p assets/fonts assets/frames assets/stickers
mkdir -p android-project/app/src/main/java/com/photobooth/app
mkdir -p ios-project/PhotoboothApp/Assets.xcassets
# 3. Khởi tạo Git repository nội bộ
git init
---
## 📅 4. Kế Hoạch Chạy Thử Nghiệm Giai Đoạn 1 (Sprint 1 - Tuần 1-2)
* [ ] **Chuẩn bị dữ liệu mẫu:** Copy ít nhất 2 font `.ttf`, 2 khung hình `.png` và 3 sticker vào các thư mục tương ứng trong `assets/`.
* [ ] **Mở Android Studio trên Debian:** Import thư mục `android-project`.
* [ ] **Cấu hình Gradle:** Tích hợp các dependency cho CameraX (`androidx.camera:camera-camera2`).
* [ ] **Code kiểm thử:** Tạo màn hình Preview Camera cơ bản trên Android Emulator (đã bật KVM) để đảm bảo luồng hình ảnh phần cứng hoạt động ổn định.
> 💡 **Mẹo nhỏ:** Khi viết code xử lý tọa độ kéo thả sticker trên Android sau này, hãy thiết kế một cấu trúc dữ liệu kiểu JSON đại diện cho "vị trí tương đối" (tính theo %) để sau này đưa sang iOS đọc hiểu y hệt:
> ```json
> { "sticker_id": "sunglasses", "x_percent": 0.25, "y_percent": 0.40, "scale": 1.2, "rotation_degree": 45 }
>
> ```
+25
View File
@@ -0,0 +1,25 @@
# Retro Photobooth (Vintage Style)
Dự án ứng dụng Photobooth di động đa nền tảng (Native iOS/Android) với phong cách vintage cổ điển. Dự án được cấu trúc theo dạng Monorepo để quản lý chung toàn bộ tài nguyên và mã nguồn của cả hai nền tảng.
## 📁 Cấu Trúc Thư Mục (Monorepo)
- `assets/`: Tài nguyên dùng chung (fonts, frames, stickers).
- `android-project/`: Mã nguồn dự án Native Android (sử dụng Kotlin, Jetpack Compose, CameraX).
- `ios-project/`: Mã nguồn dự án Native iOS (Swift, Xcode).
## 🚀 Hướng Dẫn Bắt Đầu Nhanh
### Môi trường Android
1. Mở Android Studio và chọn **Open An Existing Project**.
2. Tìm đến thư mục `android-project/` và import dự án.
3. Chờ Gradle sync hoàn tất.
4. Chạy ứng dụng trên Thiết bị mô phỏng (Emulator) hoặc Thiết bị thật hỗ trợ API 24 trở lên.
### Môi trường iOS
1. Mở Xcode trên macOS.
2. Mở file `ios-project/PhotoboothApp.xcodeproj` hoặc thư mục dự án tương ứng.
3. Đảm bảo đã khai báo các quyền truy cập camera và thư viện ảnh trong `Info.plist`.
## 📜 Giấy Phép & Tài Liệu Tham Khảo
Chi tiết kế hoạch triển khai và roadmap có thể xem tại tệp `PLAN.md`.
+77
View File
@@ -0,0 +1,77 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.photobooth.app"
compileSdk = 33
defaultConfig {
applicationId = "com.photobooth.app"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary = true
}
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
}
}
dependencies {
implementation("androidx.core:core-ktx:1.10.1")
implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
implementation("androidx.activity:activity-compose:1.7.2")
implementation(platform("androidx.compose:compose-bom:2023.06.01"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
// CameraX dependencies for Sprint 1 Camera preview
val cameraVersion = "1.3.0-rc01"
implementation("androidx.camera:camera-core:$cameraVersion")
implementation("androidx.camera:camera-camera2:$cameraVersion")
implementation("androidx.camera:camera-lifecycle:$cameraVersion")
implementation("androidx.camera:camera-view:$cameraVersion")
implementation("androidx.camera:camera-extensions:$cameraVersion")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation(platform("androidx.compose:compose-bom:2023.06.01"))
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest")
}
@@ -0,0 +1,33 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.photobooth.app">
<!-- Quyền truy cập Camera -->
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="true" />
<!-- Quyền lưu ảnh (Android 10 trở xuống cần WRITE, Android 11+ dùng Scoped Storage) -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<!-- Quyền Internet để in ấn qua mạng Local -->
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="Retro Photobooth"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
@@ -0,0 +1,44 @@
package com.photobooth.app
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState: Bundle?)
setContent {
MaterialTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Greeting("Retro Photobooth")
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Welcome to $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MaterialTheme {
Greeting("Retro Photobooth")
}
}
+5
View File
@@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.1.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.0" apply false
}
+17
View File
@@ -0,0 +1,17 @@
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Retro Photobooth"
include(":app")
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 598 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 699 KiB

+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>com.photobooth.app</string>
<key>CFBundleName</key>
<string>Retro Photobooth</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<!-- Giải trình quyền sử dụng Camera -->
<key>NSCameraUsageDescription</key>
<string>Ứng dụng cần sử dụng Camera để chụp ảnh Photobooth.</string>
<!-- Giải trình quyền lưu trữ ảnh vào Thư viện -->
<key>NSPhotoLibraryUsageDescription</key>
<string>Ứng dụng cần quyền lưu ảnh đã chụp và trang trí vào thư viện của bạn.</string>
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Ứng dụng cần quyền thêm ảnh vào thư viện của bạn.</string>
</dict>
</plist>