diff --git a/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt b/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt
index b7661cd..ab2a7ee 100644
--- a/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt
+++ b/android-project/app/src/main/java/com/photobooth/app/MainActivity.kt
@@ -43,6 +43,7 @@ class MainActivity : AppCompatActivity() {
private var isPresetModeOpen = false
private var currentSelectedFramePath: String? = null
private var currentSelectedPreset: ColorPreset? = null
+ private var editingPreset: ColorPreset? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -136,13 +137,16 @@ class MainActivity : AppCompatActivity() {
val saturation = extractJsonDoubleField(content, "saturation").toFloat()
val vibrance = extractJsonDoubleField(content, "vibrance").toFloat()
+ val clarity = extractJsonDoubleField(content, "clarity").toFloat()
+ val dehaze = extractJsonDoubleField(content, "dehaze").toFloat()
+
val preset = ColorPreset(
id = id,
name = name,
themeCategory = category,
isEditable = true,
basic = BasicAdjustments(brightness, contrast, saturation, vibrance, 0f, 0f),
- advanced = AdvancedEffects(0f, 0f, 0f),
+ advanced = AdvancedEffects(clarity, dehaze, 0f),
toneCurve = ToneCurveEmulation(0f, 0f, 0f, 0f),
grain = FilmGrain(0f, 0f)
)
@@ -177,7 +181,7 @@ class MainActivity : AppCompatActivity() {
applyPresetFilter(preset)
updatePresetModeIcon(preset)
}, { preset ->
- showEditPresetDialog(preset)
+ openAdvancedSliders(preset)
})
}
@@ -209,11 +213,11 @@ class MainActivity : AppCompatActivity() {
"instax_bw_cool" -> android.graphics.Color.argb(80, 128, 128, 128)
"instax_cool_summer" -> android.graphics.Color.argb(45, 0, 188, 212)
else -> {
- // Map user configured RGB overlay
- val alpha = ((preset.basic.vibrance + 1.0f) * 40 + 20).toInt().coerceIn(10, 100)
- val r = ((preset.basic.brightness + 1.0f) * 127).toInt().coerceIn(0, 255)
+ // Map user configured RGB overlay incorporating Vibrance, Clarity, and Dehaze
+ val alpha = ((preset.basic.vibrance + 1.0f) * 45 + 15).toInt().coerceIn(10, 110)
+ val r = ((preset.advanced.clarity + 1.0f) * 115 + 20).toInt().coerceIn(0, 255)
val g = ((preset.basic.contrast + 1.0f) * 100 + 20).toInt().coerceIn(0, 255)
- val b = ((preset.basic.saturation + 1.0f) * 80 + 10).toInt().coerceIn(0, 255)
+ val b = ((preset.advanced.dehaze + 1.0f) * 95 + 15).toInt().coerceIn(0, 255)
android.graphics.Color.argb(alpha, r, g, b)
}
}
@@ -302,6 +306,39 @@ class MainActivity : AppCompatActivity() {
binding.btnShutterCapture.setOnClickListener {
onCaptureClick()
}
+
+ // Advanced Sliders listeners
+ binding.sliderVibrance.addOnChangeListener { _, value, _ ->
+ editingPreset?.let { preset ->
+ preset.basic.vibrance = value
+ binding.lblVibrance.text = "Vibrance (Bão hòa thông minh): ${String.format("%.2f", value)}"
+ applyPresetFilter(preset)
+ }
+ }
+ binding.sliderClarity.addOnChangeListener { _, value, _ ->
+ editingPreset?.let { preset ->
+ preset.advanced.clarity = value
+ binding.lblClarity.text = "Clarity (Độ rõ nét vùng trung tính): ${String.format("%.2f", value)}"
+ applyPresetFilter(preset)
+ }
+ }
+ binding.sliderDehaze.addOnChangeListener { _, value, _ ->
+ editingPreset?.let { preset ->
+ preset.advanced.dehaze = value
+ binding.lblDehaze.text = "Dehaze (Độ trong suốt / Sương mù): ${String.format("%.2f", value)}"
+ applyPresetFilter(preset)
+ }
+ }
+
+ binding.btnCancelEdit.setOnClickListener {
+ closeAdvancedSliders()
+ }
+
+ binding.btnSaveCustomPreset.setOnClickListener {
+ editingPreset?.let { preset ->
+ showSavePresetDialog(preset)
+ }
+ }
}
private fun toggleFrameMode() {
@@ -385,87 +422,49 @@ class MainActivity : AppCompatActivity() {
}
}
- private fun showEditPresetDialog(preset: ColorPreset) {
- val dialogView = layoutInflater.inflate(R.layout.dialog_edit_preset, null)
-
- val txtBrightness: android.widget.TextView = dialogView.findViewById(R.id.txtLabelBrightness)
- val seekBrightness: android.widget.SeekBar = dialogView.findViewById(R.id.seekBrightness)
-
- val txtContrast: android.widget.TextView = dialogView.findViewById(R.id.txtLabelContrast)
- val seekContrast: android.widget.SeekBar = dialogView.findViewById(R.id.seekContrast)
-
- val txtSaturation: android.widget.TextView = dialogView.findViewById(R.id.txtLabelSaturation)
- val seekSaturation: android.widget.SeekBar = dialogView.findViewById(R.id.seekSaturation)
-
- val txtVibrance: android.widget.TextView = dialogView.findViewById(R.id.txtLabelVibrance)
- val seekVibrance: android.widget.SeekBar = dialogView.findViewById(R.id.seekVibrance)
-
- // Set current values mapping (-1.0f..1.0f -> 0..200)
- seekBrightness.progress = ((preset.basic.brightness + 1.0f) * 100).toInt()
- seekContrast.progress = ((preset.basic.contrast + 1.0f) * 100).toInt()
- seekSaturation.progress = ((preset.basic.saturation + 1.0f) * 100).toInt()
- seekVibrance.progress = ((preset.basic.vibrance + 1.0f) * 100).toInt()
-
- txtBrightness.text = "Độ sáng (Brightness): ${String.format("%.2f", preset.basic.brightness)}"
- txtContrast.text = "Độ tương phản (Contrast): ${String.format("%.2f", preset.basic.contrast)}"
- txtSaturation.text = "Độ bão hòa (Saturation): ${String.format("%.2f", preset.basic.saturation)}"
- txtVibrance.text = "Độ sống động (Vibrance): ${String.format("%.2f", preset.basic.vibrance)}"
-
- // Clone current preset to modify values temporarily
- val tempPreset = ColorPreset(
- id = preset.id,
- name = preset.name,
- themeCategory = preset.themeCategory,
- isEditable = preset.isEditable,
- basic = BasicAdjustments(preset.basic.brightness, preset.basic.contrast, preset.basic.saturation, preset.basic.vibrance, preset.basic.temperature, preset.basic.tint),
- advanced = AdvancedEffects(preset.advanced.clarity, preset.advanced.dehaze, preset.advanced.vignetteAmount),
- toneCurve = ToneCurveEmulation(preset.toneCurve.fadedBlackLevel, preset.toneCurve.shadowsTintR, preset.toneCurve.shadowsTintG, preset.toneCurve.shadowsTintB),
- grain = FilmGrain(preset.grain.grainAmount, preset.grain.grainSize)
+ private fun openAdvancedSliders(selectedPreset: ColorPreset) {
+ editingPreset = selectedPreset.copy(
+ basic = selectedPreset.basic.copy(),
+ advanced = selectedPreset.advanced.copy(),
+ toneCurve = selectedPreset.toneCurve.copy(),
+ grain = selectedPreset.grain.copy()
)
- val seekBarListener = object : android.widget.SeekBar.OnSeekBarChangeListener {
- override fun onProgressChanged(seekBar: android.widget.SeekBar?, progress: Int, fromUser: Boolean) {
- val valFloat = (progress - 100) / 100f
- when (seekBar?.id) {
- R.id.seekBrightness -> {
- tempPreset.basic.brightness = valFloat
- txtBrightness.text = "Độ sáng (Brightness): ${String.format("%.2f", valFloat)}"
- }
- R.id.seekContrast -> {
- tempPreset.basic.contrast = valFloat
- txtContrast.text = "Độ tương phản (Contrast): ${String.format("%.2f", valFloat)}"
- }
- R.id.seekSaturation -> {
- tempPreset.basic.saturation = valFloat
- txtSaturation.text = "Độ bão hòa (Saturation): ${String.format("%.2f", valFloat)}"
- }
- R.id.seekVibrance -> {
- tempPreset.basic.vibrance = valFloat
- txtVibrance.text = "Độ sống động (Vibrance): ${String.format("%.2f", valFloat)}"
- }
- }
- // Live preview camera filter overlay while sliding seekbar!
- applyPresetFilter(tempPreset)
- }
- override fun onStartTrackingTouch(seekBar: android.widget.SeekBar?) {}
- override fun onStopTrackingTouch(seekBar: android.widget.SeekBar?) {}
+ binding.tvEditPresetName.text = "Chỉnh sửa: ${selectedPreset.name}"
+
+ // Update Sliders visual values
+ binding.sliderVibrance.value = editingPreset!!.basic.vibrance
+ binding.sliderClarity.value = editingPreset!!.advanced.clarity
+ binding.sliderDehaze.value = editingPreset!!.advanced.dehaze
+
+ // Update text labels
+ binding.lblVibrance.text = "Vibrance (Bão hòa thông minh): ${String.format("%.2f", editingPreset!!.basic.vibrance)}"
+ binding.lblClarity.text = "Clarity (Độ rõ nét vùng trung tính): ${String.format("%.2f", editingPreset!!.advanced.clarity)}"
+ binding.lblDehaze.text = "Dehaze (Độ trong suốt / Sương mù): ${String.format("%.2f", editingPreset!!.advanced.dehaze)}"
+
+ // Slide up overlay panel animation
+ binding.layoutAdvancedSliders.apply {
+ visibility = android.view.View.VISIBLE
+ alpha = 0f
+ translationY = 200f
+ animate()
+ .alpha(1f)
+ .translationY(0f)
+ .setDuration(300)
+ .start()
}
+ }
- seekBrightness.setOnSeekBarChangeListener(seekBarListener)
- seekContrast.setOnSeekBarChangeListener(seekBarListener)
- seekSaturation.setOnSeekBarChangeListener(seekBarListener)
- seekVibrance.setOnSeekBarChangeListener(seekBarListener)
-
- androidx.appcompat.app.AlertDialog.Builder(this)
- .setView(dialogView)
- .setPositiveButton("Lưu") { _, _ ->
- showSavePresetDialog(tempPreset)
+ private fun closeAdvancedSliders() {
+ binding.layoutAdvancedSliders.animate()
+ .alpha(0f)
+ .translationY(200f)
+ .setDuration(250)
+ .withEndAction {
+ binding.layoutAdvancedSliders.visibility = android.view.View.GONE
+ currentSelectedPreset?.let { applyPresetFilter(it) }
}
- .setNegativeButton("Hủy") { dialog, _ ->
- applyPresetFilter(preset) // Restore
- dialog.dismiss()
- }
- .show()
+ .start()
}
private fun showSavePresetDialog(tempPreset: ColorPreset) {
@@ -501,7 +500,7 @@ class MainActivity : AppCompatActivity() {
themeCategory = "Custom",
isEditable = true,
basic = BasicAdjustments(tempPreset.basic.brightness, tempPreset.basic.contrast, tempPreset.basic.saturation, tempPreset.basic.vibrance, 0f, 0f),
- advanced = AdvancedEffects(0f, 0f, 0f),
+ advanced = AdvancedEffects(tempPreset.advanced.clarity, tempPreset.advanced.dehaze, 0f),
toneCurve = ToneCurveEmulation(0f, 0f, 0f, 0f),
grain = FilmGrain(0f, 0f)
)
@@ -522,8 +521,8 @@ class MainActivity : AppCompatActivity() {
"tint": 0.0
},
"advanced_effects": {
- "clarity": 0.0,
- "dehaze": 0.0,
+ "clarity": ${customPreset.advanced.clarity},
+ "dehaze": ${customPreset.advanced.dehaze},
"vignette_amount": 0.0
},
"tone_curve_emulation": {
@@ -547,6 +546,7 @@ class MainActivity : AppCompatActivity() {
colorPresets = colorPresets + customPreset
presetAdapter.updatePresets(colorPresets)
Toast.makeText(this, "Đã lưu preset: $newName", Toast.LENGTH_SHORT).show()
+ closeAdvancedSliders()
} catch (e: Exception) {
Toast.makeText(this, "Không thể lưu Preset file", Toast.LENGTH_SHORT).show()
}
diff --git a/android-project/app/src/main/res/drawable/ic_close_white.xml b/android-project/app/src/main/res/drawable/ic_close_white.xml
new file mode 100644
index 0000000..6dd59cc
--- /dev/null
+++ b/android-project/app/src/main/res/drawable/ic_close_white.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/android-project/app/src/main/res/layout/activity_main.xml b/android-project/app/src/main/res/layout/activity_main.xml
index a9ec0f7..402eab8 100644
--- a/android-project/app/src/main/res/layout/activity_main.xml
+++ b/android-project/app/src/main/res/layout/activity_main.xml
@@ -103,6 +103,115 @@
android:text="3" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+