Files
photobooth-app/11_FIX_PRESET_APPLY.md
T

207 lines
11 KiB
Markdown

# 🛠️ KẾ HOẠCH FIX BUG: CHUẨN HÓA LOGIC SLIDERS & FIX LỖI TRÀN KHUNG HIỂN THỊ
Mục tiêu:
1. Khắc phục triệt để lỗi gán nhầm thông số xử lý ảnh (ví dụ: kéo Brightness lại đổi Temperature).
2. Chuyển đổi dải giá trị từ số thập phân nhỏ sang thang đo nguyên trực quan từ `-100` đến `+100` để người dùng thấy rõ sự thay đổi.
3. Cô lập nội dung cuộn bên trong phạm vi bo góc của `MaterialCardView` để không bị tràn đè lên khung viền của bảng.
---
## 📐 1. Khắc Phục Lỗi Giao Diện Tràn Khung Biển (`activity_main.xml`)
**Nguyên nhân lỗi:** Do tệp cấu hình cũ đặt thuộc tính `padding` trực tiếp lên thẻ cha hoặc thẻ `LinearLayout` bên trong mà không giới hạn vùng hiển thị đồ họa của thẻ cuộn `ScrollView`. Khi vuốt, các phần tử chữ và thanh kéo sẽ trượt đè qua các góc bo tròn của hộp Floating Card.
**Giải pháp:** Di chuyển toàn bộ cấu hình `padding` vào bên trong thẻ `ScrollView` và ép cấu trúc cắt vùng đồ họa thừa bằng thuộc tính `android:clipToPadding="true"`.
```xml
<!-- LỚP 3: BẢNG SLIDERS FLOATING (Nằm gọn bên trong ảnh cameraContainer) -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardAdvancedSliders"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="24dp"
app:cardCornerRadius="12dp"
app:cardElevation="8dp"
android:visibility="gone"
app:strokeWidth="0dp"
android:backgroundTint="#A6000000">
<!-- FIX LỖI ĐÈ KHUNG: Đưa padding và clipToPadding vào ScrollView -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="vertical"
android:padding="16dp"
android:clipToPadding="true"> <!-- Ép nội dung cuộn phải biến mất khi chạm tới viền bo góc -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Tiêu đề & Nút X (Đóng) -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp">
<TextView
android:id="@+id/tvEditPresetName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="15sp" />
<ImageButton
android:id="@+id/btnCancelEdit"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentEnd="true"
android:background="@null"
android:src="@drawable/ic_close_white" />
</RelativeLayout>
<!-- ================= CẬP NHẬT DẢI GIÁ TRỊ TOÀN BỘ SLIDERS (-100 đến 100) ================= -->
<!-- Brightness -->
<TextView android:id="@+id/tvLabelBrightness" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF" android:textSize="11sp"/>
<com.google.android.material.slider.Slider
android:id="@+id/sliderBrightness"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:valueFrom="-100.0"
android:valueTo="100.0"
android:value="0.0"
app:thumbColor="#FF9800"
app:trackColorActive="#FF9800"/>
<!-- Temperature -->
<TextView android:id="@+id/tvLabelTemperature" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#FFFFFF" android:textSize="11sp"/>
<com.google.android.material.slider.Slider
android:id="@+id/sliderTemperature"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:valueFrom="-100.0"
android:valueTo="100.0"
android:value="0.0"
app:thumbColor="#FF9800"
app:trackColorActive="#FF9800"/>
<!-- Áp dụng tương tự cho tất cả 12 thanh Sliders còn lại cấu hình valueFrom="-100.0" và valueTo="100.0" -->
<!-- Đối với các thuộc tính đi từ 0 (Vignette, Grain, Faded Black) thì cấu hình valueFrom="0.0" và valueTo="100.0" -->
<!-- NÚT LƯU THÀNH PRESET MỚI -->
<Button
android:id="@+id/btnSaveCustomPreset"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_marginTop="20dp"
android:text="LƯU THÀNH PRESET MỚI"
android:textColor="#FFFFFF"
android:backgroundTint="#FF9800"
android:textStyle="bold" />
</LinearLayout>
</ScrollView>
</com.google.android.material.card.MaterialCardView>
```
---
## 💻 2. Chuẩn Hóa Logic Gán Hàm Độc Lập & Quy Đổi Tỷ Lệ Giá Trị (Kotlin)
**Giải pháp sửa lỗi gán sai thông số:** Quy hoạch lại chính xác từng sự kiện lắng nghe để tránh việc copy-paste mã lệnh bị trùng lặp biến.
**Giải pháp dải giá trị lớn:** Người dùng nhìn thấy và kéo trượt trên thang đo nguyên trực quan từ `-100` đến `+100` (để thấy tác động lớn, rõ rệt trên UI). Tuy nhiên, trước khi gán dữ liệu vào hàm `applyLiveFilterToCamera` để GPU xử lý, ta phải **chia cho 100** để đưa về dải số thực chuẩn hóa (`-1.0` đến `1.0`) giúp lõi phần cứng đồ họa không bị lỗi tính toán (vì Shader/CoreImage nhận giá trị số thực từ `-1` đến `1`).
```kotlin
private fun setupSliderListeners() {
// FIX 1: Chuẩn hóa gán đúng hàm cho Brightness
binding.sliderBrightness.addOnChangeListener { _, value, _ ->
// Hiển thị số nguyên (-100 đến 100) lên nhãn văn bản cho người dùng thấy
binding.tvLabelBrightness.text = String.format("Brightness (Độ sáng): %.0f", value)
// Quy đổi tỉ lệ về dải số thực (-1.0 đến 1.0) để gán cho Object cấu hình
val normalizedValue = value / 100f
editingPreset?.basic?.brightness = normalizedValue
// Đẩy giá trị ĐÚNG của Brightness sang bộ lọc GPU
applyLiveFilterToCamera(editingPreset)
}
// FIX 2: Chuẩn hóa gán đúng hàm cho Temperature (Không bị nhầm với Brightness nữa)
binding.sliderTemperature.addOnChangeListener { _, value, _ ->
binding.tvLabelTemperature.text = String.format("Temperature (Nhiệt màu): %.0f", value)
val normalizedValue = value / 100f
editingPreset?.basic?.temperature = normalizedValue // Gán chuẩn xác cho biến temperature
applyLiveFilterToCamera(editingPreset)
}
// FIX 3: Chuẩn hóa gán đúng hàm cho Vibrance
binding.sliderVibrance.addOnChangeListener { _, value, _ ->
binding.tvLabelVibrance.text = String.format("Vibrance (Bão hòa thông minh): %.0f", value)
val normalizedValue = value / 100f
editingPreset?.basic?.vibrance = normalizedValue // Gán chuẩn xác cho biến vibrance
applyLiveFilterToCamera(editingPreset)
}
// FIX 4: Chuẩn hóa cho hiệu ứng nhiễu hạt Film Grain (Dải giá trị từ 0 đến 100)
binding.sliderGrainAmount.addOnChangeListener { _, value, _ ->
binding.tvLabelGrainAmount.text = String.format("Grain Amount (Mật độ hạt): %.0f%%", value)
val normalizedValue = value / 100f
editingPreset?.grain?.grainAmount = normalizedValue // Gán chuẩn xác cho biến grainAmount
applyLiveFilterToCamera(editingPreset)
}
// Tiến hành rà soát lại tất cả các khối listener còn lại đảm bảo đúng biến nào - hàm đó!
}
```
---
## 🔄 3. Cơ Chế Nạp Lại Giá Trị Gốc Lên Sliders (Quy Đổi Ngược Nhân 100)
Khi người dùng mở bảng chỉnh sửa, chúng ta phải làm một phép tính ngược lại: Lấy giá trị số thực từ tệp JSON, **nhân với 100** để hiển thị đúng vị trí con trỏ trên thanh kéo `-100 -> +100`.
```kotlin
fun openAdvancedSliders(selectedPreset: ColorPreset) {
editingPreset = selectedPreset.deepCopy()
binding.tvEditPresetName.text = "Chỉnh sửa: ${editingPreset!!.name}"
// Đọc giá trị số thực từ JSON, nhân 100 để hiển thị dải số nguyên rõ rệt trên thanh trượt
binding.sliderBrightness.value = editingPreset!!.basic.brightness * 100f
binding.sliderTemperature.value = editingPreset!!.basic.temperature * 100f
binding.sliderVibrance.value = editingPreset!!.basic.vibrance * 100f
binding.sliderClarity.value = editingPreset!!.advanced.clarity * 100f
binding.sliderDehaze.value = editingPreset!!.advanced.dehaze * 100f
binding.sliderGrainAmount.value = editingPreset!!.grain.grainAmount * 100f
binding.sliderGrainSize.value = editingPreset!!.grain.grainSize * 100f
// Cập nhật text nhãn ban đầu
binding.tvLabelBrightness.text = String.format("Brightness (Độ sáng): %.0f", binding.sliderBrightness.value)
binding.tvLabelTemperature.text = String.format("Temperature (Nhiệt màu): %.0f", binding.sliderTemperature.value)
setupSliderListeners()
binding.cardAdvancedSliders.visibility = View.VISIBLE
}
```
---
## 📅 4. Các Đầu Việc Cần Hoàn Thành (Checklist)
* [ ] Thực hiện thay đổi cấu trúc `ScrollView` trong tệp XML để cô lập hoàn toàn nội dung cuộn, giải quyết triệt để lỗi tràn khung hiển thị.
* [ ] Tiến hành cập nhật lại toàn bộ 14 hàm lắng nghe sự kiện `addOnChangeListener`, rà soát kỹ lưỡng từng dòng lệnh để đảm bảo tính độc lập tuyệt đối giữa các thông số.
* [ ] Chạy thử nghiệm kéo trượt mạnh về hai cực đầu mút (`-100``100`) trên thiết bị thật để kiểm tra độ trễ phản hồi hình ảnh và biên độ thay đổi của màu ảnh xem đã đủ rõ rệt chưa.