207 lines
11 KiB
Markdown
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` và `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. |