Feat: Implement advanced sliders real-time color overlay panel (8_SLIDER_TABLE.md)
This commit is contained in:
@@ -43,6 +43,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
private var isPresetModeOpen = false
|
private var isPresetModeOpen = false
|
||||||
private var currentSelectedFramePath: String? = null
|
private var currentSelectedFramePath: String? = null
|
||||||
private var currentSelectedPreset: ColorPreset? = null
|
private var currentSelectedPreset: ColorPreset? = null
|
||||||
|
private var editingPreset: ColorPreset? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -136,13 +137,16 @@ class MainActivity : AppCompatActivity() {
|
|||||||
val saturation = extractJsonDoubleField(content, "saturation").toFloat()
|
val saturation = extractJsonDoubleField(content, "saturation").toFloat()
|
||||||
val vibrance = extractJsonDoubleField(content, "vibrance").toFloat()
|
val vibrance = extractJsonDoubleField(content, "vibrance").toFloat()
|
||||||
|
|
||||||
|
val clarity = extractJsonDoubleField(content, "clarity").toFloat()
|
||||||
|
val dehaze = extractJsonDoubleField(content, "dehaze").toFloat()
|
||||||
|
|
||||||
val preset = ColorPreset(
|
val preset = ColorPreset(
|
||||||
id = id,
|
id = id,
|
||||||
name = name,
|
name = name,
|
||||||
themeCategory = category,
|
themeCategory = category,
|
||||||
isEditable = true,
|
isEditable = true,
|
||||||
basic = BasicAdjustments(brightness, contrast, saturation, vibrance, 0f, 0f),
|
basic = BasicAdjustments(brightness, contrast, saturation, vibrance, 0f, 0f),
|
||||||
advanced = AdvancedEffects(0f, 0f, 0f),
|
advanced = AdvancedEffects(clarity, dehaze, 0f),
|
||||||
toneCurve = ToneCurveEmulation(0f, 0f, 0f, 0f),
|
toneCurve = ToneCurveEmulation(0f, 0f, 0f, 0f),
|
||||||
grain = FilmGrain(0f, 0f)
|
grain = FilmGrain(0f, 0f)
|
||||||
)
|
)
|
||||||
@@ -177,7 +181,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
applyPresetFilter(preset)
|
applyPresetFilter(preset)
|
||||||
updatePresetModeIcon(preset)
|
updatePresetModeIcon(preset)
|
||||||
}, { 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_bw_cool" -> android.graphics.Color.argb(80, 128, 128, 128)
|
||||||
"instax_cool_summer" -> android.graphics.Color.argb(45, 0, 188, 212)
|
"instax_cool_summer" -> android.graphics.Color.argb(45, 0, 188, 212)
|
||||||
else -> {
|
else -> {
|
||||||
// Map user configured RGB overlay
|
// Map user configured RGB overlay incorporating Vibrance, Clarity, and Dehaze
|
||||||
val alpha = ((preset.basic.vibrance + 1.0f) * 40 + 20).toInt().coerceIn(10, 100)
|
val alpha = ((preset.basic.vibrance + 1.0f) * 45 + 15).toInt().coerceIn(10, 110)
|
||||||
val r = ((preset.basic.brightness + 1.0f) * 127).toInt().coerceIn(0, 255)
|
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 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)
|
android.graphics.Color.argb(alpha, r, g, b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,6 +306,39 @@ class MainActivity : AppCompatActivity() {
|
|||||||
binding.btnShutterCapture.setOnClickListener {
|
binding.btnShutterCapture.setOnClickListener {
|
||||||
onCaptureClick()
|
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() {
|
private fun toggleFrameMode() {
|
||||||
@@ -385,87 +422,49 @@ class MainActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showEditPresetDialog(preset: ColorPreset) {
|
private fun openAdvancedSliders(selectedPreset: ColorPreset) {
|
||||||
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_preset, null)
|
editingPreset = selectedPreset.copy(
|
||||||
|
basic = selectedPreset.basic.copy(),
|
||||||
val txtBrightness: android.widget.TextView = dialogView.findViewById(R.id.txtLabelBrightness)
|
advanced = selectedPreset.advanced.copy(),
|
||||||
val seekBrightness: android.widget.SeekBar = dialogView.findViewById(R.id.seekBrightness)
|
toneCurve = selectedPreset.toneCurve.copy(),
|
||||||
|
grain = selectedPreset.grain.copy()
|
||||||
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)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val seekBarListener = object : android.widget.SeekBar.OnSeekBarChangeListener {
|
binding.tvEditPresetName.text = "Chỉnh sửa: ${selectedPreset.name}"
|
||||||
override fun onProgressChanged(seekBar: android.widget.SeekBar?, progress: Int, fromUser: Boolean) {
|
|
||||||
val valFloat = (progress - 100) / 100f
|
// Update Sliders visual values
|
||||||
when (seekBar?.id) {
|
binding.sliderVibrance.value = editingPreset!!.basic.vibrance
|
||||||
R.id.seekBrightness -> {
|
binding.sliderClarity.value = editingPreset!!.advanced.clarity
|
||||||
tempPreset.basic.brightness = valFloat
|
binding.sliderDehaze.value = editingPreset!!.advanced.dehaze
|
||||||
txtBrightness.text = "Độ sáng (Brightness): ${String.format("%.2f", valFloat)}"
|
|
||||||
}
|
// Update text labels
|
||||||
R.id.seekContrast -> {
|
binding.lblVibrance.text = "Vibrance (Bão hòa thông minh): ${String.format("%.2f", editingPreset!!.basic.vibrance)}"
|
||||||
tempPreset.basic.contrast = valFloat
|
binding.lblClarity.text = "Clarity (Độ rõ nét vùng trung tính): ${String.format("%.2f", editingPreset!!.advanced.clarity)}"
|
||||||
txtContrast.text = "Độ tương phản (Contrast): ${String.format("%.2f", valFloat)}"
|
binding.lblDehaze.text = "Dehaze (Độ trong suốt / Sương mù): ${String.format("%.2f", editingPreset!!.advanced.dehaze)}"
|
||||||
}
|
|
||||||
R.id.seekSaturation -> {
|
// Slide up overlay panel animation
|
||||||
tempPreset.basic.saturation = valFloat
|
binding.layoutAdvancedSliders.apply {
|
||||||
txtSaturation.text = "Độ bão hòa (Saturation): ${String.format("%.2f", valFloat)}"
|
visibility = android.view.View.VISIBLE
|
||||||
}
|
alpha = 0f
|
||||||
R.id.seekVibrance -> {
|
translationY = 200f
|
||||||
tempPreset.basic.vibrance = valFloat
|
animate()
|
||||||
txtVibrance.text = "Độ sống động (Vibrance): ${String.format("%.2f", valFloat)}"
|
.alpha(1f)
|
||||||
}
|
.translationY(0f)
|
||||||
}
|
.setDuration(300)
|
||||||
// Live preview camera filter overlay while sliding seekbar!
|
.start()
|
||||||
applyPresetFilter(tempPreset)
|
|
||||||
}
|
|
||||||
override fun onStartTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
|
||||||
override fun onStopTrackingTouch(seekBar: android.widget.SeekBar?) {}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
seekBrightness.setOnSeekBarChangeListener(seekBarListener)
|
private fun closeAdvancedSliders() {
|
||||||
seekContrast.setOnSeekBarChangeListener(seekBarListener)
|
binding.layoutAdvancedSliders.animate()
|
||||||
seekSaturation.setOnSeekBarChangeListener(seekBarListener)
|
.alpha(0f)
|
||||||
seekVibrance.setOnSeekBarChangeListener(seekBarListener)
|
.translationY(200f)
|
||||||
|
.setDuration(250)
|
||||||
androidx.appcompat.app.AlertDialog.Builder(this)
|
.withEndAction {
|
||||||
.setView(dialogView)
|
binding.layoutAdvancedSliders.visibility = android.view.View.GONE
|
||||||
.setPositiveButton("Lưu") { _, _ ->
|
currentSelectedPreset?.let { applyPresetFilter(it) }
|
||||||
showSavePresetDialog(tempPreset)
|
|
||||||
}
|
}
|
||||||
.setNegativeButton("Hủy") { dialog, _ ->
|
.start()
|
||||||
applyPresetFilter(preset) // Restore
|
|
||||||
dialog.dismiss()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSavePresetDialog(tempPreset: ColorPreset) {
|
private fun showSavePresetDialog(tempPreset: ColorPreset) {
|
||||||
@@ -501,7 +500,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
themeCategory = "Custom",
|
themeCategory = "Custom",
|
||||||
isEditable = true,
|
isEditable = true,
|
||||||
basic = BasicAdjustments(tempPreset.basic.brightness, tempPreset.basic.contrast, tempPreset.basic.saturation, tempPreset.basic.vibrance, 0f, 0f),
|
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),
|
toneCurve = ToneCurveEmulation(0f, 0f, 0f, 0f),
|
||||||
grain = FilmGrain(0f, 0f)
|
grain = FilmGrain(0f, 0f)
|
||||||
)
|
)
|
||||||
@@ -522,8 +521,8 @@ class MainActivity : AppCompatActivity() {
|
|||||||
"tint": 0.0
|
"tint": 0.0
|
||||||
},
|
},
|
||||||
"advanced_effects": {
|
"advanced_effects": {
|
||||||
"clarity": 0.0,
|
"clarity": ${customPreset.advanced.clarity},
|
||||||
"dehaze": 0.0,
|
"dehaze": ${customPreset.advanced.dehaze},
|
||||||
"vignette_amount": 0.0
|
"vignette_amount": 0.0
|
||||||
},
|
},
|
||||||
"tone_curve_emulation": {
|
"tone_curve_emulation": {
|
||||||
@@ -547,6 +546,7 @@ class MainActivity : AppCompatActivity() {
|
|||||||
colorPresets = colorPresets + customPreset
|
colorPresets = colorPresets + customPreset
|
||||||
presetAdapter.updatePresets(colorPresets)
|
presetAdapter.updatePresets(colorPresets)
|
||||||
Toast.makeText(this, "Đã lưu preset: $newName", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Đã lưu preset: $newName", Toast.LENGTH_SHORT).show()
|
||||||
|
closeAdvancedSliders()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Toast.makeText(this, "Không thể lưu Preset file", Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, "Không thể lưu Preset file", Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24.0"
|
||||||
|
android:viewportHeight="24.0">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/theme_white"
|
||||||
|
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
|
||||||
|
</vector>
|
||||||
@@ -103,6 +103,115 @@
|
|||||||
android:text="3" />
|
android:text="3" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
|
<!-- ================= BẢNG SLIDERS TÙY CHỈNH MÀU THỜI GIAN THỰC ================= -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/layoutAdvancedSliders"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="#D9000000"
|
||||||
|
android:padding="20dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/panelSelectionContainer">
|
||||||
|
|
||||||
|
<!-- Thanh tiêu đề & Nút thao tác nhanh -->
|
||||||
|
<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:text="Chỉnh sửa: Instax Warm"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/btnCancelEdit"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:background="@android:color/transparent"
|
||||||
|
android:src="@drawable/ic_close_white"
|
||||||
|
app:tint="@color/theme_white"
|
||||||
|
android:contentDescription="Cancel Edit" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<!-- KHU VỰC CÁC THANH KÉO (SLIDERS) -->
|
||||||
|
<!-- 1. Thanh chỉnh VIBRANCE -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lblVibrance"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Vibrance (Bão hòa thông minh): 0.0"
|
||||||
|
android:textColor="#CCCCCC"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/sliderVibrance"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:valueFrom="-1.0"
|
||||||
|
android:valueTo="1.0"
|
||||||
|
android:value="0.0"
|
||||||
|
app:thumbColor="#FF9800"
|
||||||
|
app:trackColorActive="#FF9800"
|
||||||
|
app:trackColorInactive="#333333" />
|
||||||
|
|
||||||
|
<!-- 2. Thanh chỉnh CLARITY -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lblClarity"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Clarity (Độ rõ nét vùng trung tính): 0.0"
|
||||||
|
android:textColor="#CCCCCC"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/sliderClarity"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:valueFrom="-1.0"
|
||||||
|
android:valueTo="1.0"
|
||||||
|
android:value="0.0"
|
||||||
|
app:thumbColor="#FF9800"
|
||||||
|
app:trackColorActive="#FF9800"
|
||||||
|
app:trackColorInactive="#333333" />
|
||||||
|
|
||||||
|
<!-- 3. Thanh chỉnh DEHAZE -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/lblDehaze"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Dehaze (Độ trong suốt / Sương mù): 0.0"
|
||||||
|
android:textColor="#CCCCCC"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginTop="8dp" />
|
||||||
|
<com.google.android.material.slider.Slider
|
||||||
|
android:id="@+id/sliderDehaze"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:valueFrom="-1.0"
|
||||||
|
android:valueTo="1.0"
|
||||||
|
android:value="0.0"
|
||||||
|
app:thumbColor="#FF9800"
|
||||||
|
app:trackColorActive="#FF9800"
|
||||||
|
app:trackColorInactive="#333333" />
|
||||||
|
|
||||||
|
<!-- NÚT LƯU THÀNH PRESET MỚI -->
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnSaveCustomPreset"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:text="LƯU THÀNH PRESET MỚI"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:backgroundTint="#FF9800"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<!-- ================= KHỐI 1: TIMELINE FRAMES & PRESETS ================= -->
|
<!-- ================= KHỐI 1: TIMELINE FRAMES & PRESETS ================= -->
|
||||||
<!-- Đặt ngay phía dưới Camera và không bị ai đè lên nữa -->
|
<!-- Đặt ngay phía dưới Camera và không bị ai đè lên nữa -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 411 KiB |
Reference in New Issue
Block a user