From 4503281860948343674423f813b0fb9b033a61ad Mon Sep 17 00:00:00 2001 From: Naveen Date: Sun, 30 Apr 2023 14:40:05 +0530 Subject: [PATCH] Allow color customization of local events as well --- .../calendar/pro/activities/EventActivity.kt | 78 ++++-- .../calendar/pro/dialogs/ColorPickerDialog.kt | 247 ++++++++++++++++++ .../main/res/layout/dialog_color_picker.xml | 163 ++++++++++++ 3 files changed, 469 insertions(+), 19 deletions(-) create mode 100644 app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/ColorPickerDialog.kt create mode 100644 app/src/main/res/layout/dialog_color_picker.xml diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt index e067183de..a93f7babe 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt @@ -31,7 +31,6 @@ import com.simplemobiletools.calendar.pro.adapters.AutoCompleteTextViewAdapter import com.simplemobiletools.calendar.pro.dialogs.* import com.simplemobiletools.calendar.pro.extensions.* import com.simplemobiletools.calendar.pro.helpers.* -import com.simplemobiletools.calendar.pro.helpers.Formatter import com.simplemobiletools.calendar.pro.models.* import com.simplemobiletools.commons.dialogs.ConfirmationAdvancedDialog import com.simplemobiletools.commons.dialogs.RadioGroupDialog @@ -40,11 +39,13 @@ import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.RadioItem import com.simplemobiletools.commons.views.MyAutoCompleteTextView import kotlinx.android.synthetic.main.activity_event.* -import kotlinx.android.synthetic.main.activity_event.view.* +import kotlinx.android.synthetic.main.activity_event.view.event_reminder_2 +import kotlinx.android.synthetic.main.activity_event.view.event_reminder_3 import kotlinx.android.synthetic.main.item_attendee.view.* import org.joda.time.DateTime import org.joda.time.DateTimeZone -import java.util.* +import java.util.Calendar +import java.util.TimeZone import java.util.regex.Pattern class EventActivity : SimpleActivity() { @@ -834,25 +835,55 @@ class EventActivity : SimpleActivity() { private fun showEventColorDialog() { hideKeyboard() ensureBackgroundThread { - val eventType = eventsHelper.getEventTypeWithCalDAVCalendarId(calendarId = mEventCalendarId)!! - val eventColors = getEventColors(eventType) - runOnUiThread { - val currentColor = if (mEventColor == 0) { - eventType.color - } else { - mEventColor - } + val isLocalEvent = mEventCalendarId == STORED_LOCALLY_ONLY + if (isLocalEvent) { + showCustomEventColorDialog() + } else { + showCalDAVEventColorDialog() + } + } + } - SelectEventColorDialog(activity = this, colors = eventColors, currentColor = currentColor) { newColor -> - if (newColor != currentColor) { - mEventColor = newColor - updateEventColorInfo(defaultColor = eventType.color) - } + private fun showCustomEventColorDialog() { + val eventType = eventTypesDB.getEventTypeWithId(mEventTypeId)!! + val currentColor = if (mEventColor == 0) { + eventType.color + } else { + mEventColor + } + + runOnUiThread { + ColorPickerDialog(activity = this, color = currentColor) { wasPositivePressed, newColor -> + if (wasPositivePressed) { + gotNewEventColor(newColor, currentColor, eventType.color) } } } } + private fun showCalDAVEventColorDialog() { + val eventType = eventsHelper.getEventTypeWithCalDAVCalendarId(calendarId = mEventCalendarId)!! + val eventColors = getEventColors(eventType) + val currentColor = if (mEventColor == 0) { + eventType.color + } else { + mEventColor + } + + runOnUiThread { + SelectEventColorDialog(activity = this, colors = eventColors, currentColor = currentColor) { newColor -> + gotNewEventColor(newColor, currentColor, eventType.color) + } + } + } + + private fun gotNewEventColor(newColor: Int, currentColor: Int, defaultColor: Int) { + if (newColor != currentColor) { + mEventColor = newColor + updateEventColorInfo(defaultColor = defaultColor) + } + } + private fun checkReminderTexts() { updateReminder1Text() updateReminder2Text() @@ -1018,9 +1049,17 @@ class EventActivity : SimpleActivity() { setPadding(paddingLeft, mediumMargin, paddingRight, mediumMargin) } - event_caldav_color_image.beGone() - event_caldav_color_holder.beGone() - event_caldav_color_divider.beGone() + ensureBackgroundThread { + val eventType = eventTypesDB.getEventTypeWithId(mEventTypeId) + if (eventType != null) { + runOnUiThread { + event_caldav_color_image.beVisible() + event_caldav_color_holder.beVisible() + event_caldav_color_divider.beVisible() + updateEventColorInfo(eventType.color) + } + } + } } else { event_caldav_calendar_email.text = currentCalendar.accountName @@ -1326,6 +1365,7 @@ class EventActivity : SimpleActivity() { } } } + 1 -> { ensureBackgroundThread { eventsHelper.addEventRepeatLimit(mEvent.id!!, mEventOccurrenceTS) diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/ColorPickerDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/ColorPickerDialog.kt new file mode 100644 index 000000000..d39809364 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/ColorPickerDialog.kt @@ -0,0 +1,247 @@ +package com.simplemobiletools.calendar.pro.dialogs + +import android.app.Activity +import android.graphics.Color +import android.view.MotionEvent +import android.view.View +import android.view.View.OnTouchListener +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.EditText +import android.widget.ImageView +import androidx.appcompat.app.AlertDialog +import com.simplemobiletools.calendar.pro.R +import com.simplemobiletools.commons.extensions.* +import com.simplemobiletools.commons.helpers.isQPlus +import com.simplemobiletools.commons.views.ColorPickerSquare +import kotlinx.android.synthetic.main.dialog_color_picker.view.* +import java.util.LinkedList + +private const val RECENT_COLORS_NUMBER = 5 + +// forked from https://github.com/yukuku/ambilwarna +class ColorPickerDialog( + val activity: Activity, + color: Int, + val removeDimmedBackground: Boolean = false, + val currentColorCallback: ((color: Int) -> Unit)? = null, + val callback: (wasPositivePressed: Boolean, color: Int) -> Unit +) { + var viewHue: View + var viewSatVal: ColorPickerSquare + var viewCursor: ImageView + var viewNewColor: ImageView + var viewTarget: ImageView + var newHexField: EditText + var viewContainer: ViewGroup + private val baseConfig = activity.baseConfig + private val currentColorHsv = FloatArray(3) + private val backgroundColor = baseConfig.backgroundColor + private var isHueBeingDragged = false + private var wasDimmedBackgroundRemoved = false + private var dialog: AlertDialog? = null + + init { + Color.colorToHSV(color, currentColorHsv) + + val view = activity.layoutInflater.inflate(R.layout.dialog_color_picker, null).apply { + if (isQPlus()) { + isForceDarkAllowed = false + } + + viewHue = color_picker_hue + viewSatVal = color_picker_square + viewCursor = color_picker_hue_cursor + + viewNewColor = color_picker_new_color + viewTarget = color_picker_cursor + viewContainer = color_picker_holder + newHexField = color_picker_new_hex + + viewSatVal.setHue(getHue()) + + viewNewColor.setFillWithStroke(getColor(), backgroundColor) + color_picker_old_color.setFillWithStroke(color, backgroundColor) + + val hexCode = getHexCode(color) + color_picker_old_hex.text = "#$hexCode" + color_picker_old_hex.setOnLongClickListener { + activity.copyToClipboard(hexCode) + true + } + newHexField.setText(hexCode) + setupRecentColors() + } + + viewHue.setOnTouchListener(OnTouchListener { v, event -> + if (event.action == MotionEvent.ACTION_DOWN) { + isHueBeingDragged = true + } + + if (event.action == MotionEvent.ACTION_MOVE || event.action == MotionEvent.ACTION_DOWN || event.action == MotionEvent.ACTION_UP) { + var y = event.y + if (y < 0f) + y = 0f + + if (y > viewHue.measuredHeight) { + y = viewHue.measuredHeight - 0.001f // to avoid jumping the cursor from bottom to top. + } + var hue = 360f - 360f / viewHue.measuredHeight * y + if (hue == 360f) + hue = 0f + + currentColorHsv[0] = hue + updateHue() + newHexField.setText(getHexCode(getColor())) + + if (event.action == MotionEvent.ACTION_UP) { + isHueBeingDragged = false + } + return@OnTouchListener true + } + false + }) + + viewSatVal.setOnTouchListener(OnTouchListener { v, event -> + if (event.action == MotionEvent.ACTION_MOVE || event.action == MotionEvent.ACTION_DOWN || event.action == MotionEvent.ACTION_UP) { + var x = event.x + var y = event.y + + if (x < 0f) + x = 0f + if (x > viewSatVal.measuredWidth) + x = viewSatVal.measuredWidth.toFloat() + if (y < 0f) + y = 0f + if (y > viewSatVal.measuredHeight) + y = viewSatVal.measuredHeight.toFloat() + + currentColorHsv[1] = 1f / viewSatVal.measuredWidth * x + currentColorHsv[2] = 1f - 1f / viewSatVal.measuredHeight * y + + moveColorPicker() + viewNewColor.setFillWithStroke(getColor(), backgroundColor) + newHexField.setText(getHexCode(getColor())) + return@OnTouchListener true + } + false + }) + + newHexField.onTextChangeListener { + if (it.length == 6 && !isHueBeingDragged) { + try { + val newColor = Color.parseColor("#$it") + Color.colorToHSV(newColor, currentColorHsv) + updateHue() + moveColorPicker() + } catch (ignored: Exception) { + } + } + } + + val textColor = activity.getProperTextColor() + val builder = activity.getAlertDialogBuilder() + .setPositiveButton(R.string.ok) { _, _ -> confirmNewColor() } + .setNeutralButton(R.string.default_color) { _, _ -> confirmDefaultColor() } + .setOnCancelListener { dialogDismissed() } + + builder.apply { + activity.setupDialogStuff(view, this) { alertDialog -> + dialog = alertDialog + view.color_picker_arrow.applyColorFilter(textColor) + view.color_picker_hex_arrow.applyColorFilter(textColor) + viewCursor.applyColorFilter(textColor) + } + } + + view.onGlobalLayout { + moveHuePicker() + moveColorPicker() + } + } + + private fun View.setupRecentColors() { + val recentColors = baseConfig.colorPickerRecentColors + if (recentColors.isNotEmpty()) { + recent_colors.beVisible() + val squareSize = context.resources.getDimensionPixelSize(R.dimen.colorpicker_hue_width) + recentColors.take(RECENT_COLORS_NUMBER).forEach { recentColor -> + val recentColorView = ImageView(context) + recentColorView.id = View.generateViewId() + recentColorView.layoutParams = ViewGroup.LayoutParams(squareSize, squareSize) + recentColorView.setFillWithStroke(recentColor, backgroundColor) + recentColorView.setOnClickListener { newHexField.setText(getHexCode(recentColor)) } + recent_colors.addView(recentColorView) + recent_colors_flow.addView(recentColorView) + } + } + } + + private fun dialogDismissed() { + callback(false, 0) + } + + private fun confirmDefaultColor() { + callback(true, 0) + } + + private fun confirmNewColor() { + val hexValue = newHexField.value + val newColor = if (hexValue.length == 6) { + Color.parseColor("#$hexValue") + } else { + getColor() + } + + addRecentColor(newColor) + callback(true, newColor) + } + + private fun addRecentColor(color: Int) { + var recentColors = baseConfig.colorPickerRecentColors + + recentColors.remove(color) + if (recentColors.size >= RECENT_COLORS_NUMBER) { + val numberOfColorsToDrop = recentColors.size - RECENT_COLORS_NUMBER + 1 + recentColors = LinkedList(recentColors.dropLast(numberOfColorsToDrop)) + } + recentColors.addFirst(color) + + baseConfig.colorPickerRecentColors = recentColors + } + + private fun getHexCode(color: Int) = color.toHex().substring(1) + + private fun updateHue() { + viewSatVal.setHue(getHue()) + moveHuePicker() + viewNewColor.setFillWithStroke(getColor(), backgroundColor) + if (removeDimmedBackground && !wasDimmedBackgroundRemoved) { + dialog?.window?.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + wasDimmedBackgroundRemoved = true + } + + currentColorCallback?.invoke(getColor()) + } + + private fun moveHuePicker() { + var y = viewHue.measuredHeight - getHue() * viewHue.measuredHeight / 360f + if (y == viewHue.measuredHeight.toFloat()) + y = 0f + + viewCursor.x = (viewHue.left - viewCursor.width).toFloat() + viewCursor.y = viewHue.top + y - viewCursor.height / 2 + } + + private fun moveColorPicker() { + val x = getSat() * viewSatVal.measuredWidth + val y = (1f - getVal()) * viewSatVal.measuredHeight + viewTarget.x = viewSatVal.left + x - viewTarget.width / 2 + viewTarget.y = viewSatVal.top + y - viewTarget.height / 2 + } + + private fun getColor() = Color.HSVToColor(currentColorHsv) + private fun getHue() = currentColorHsv[0] + private fun getSat() = currentColorHsv[1] + private fun getVal() = currentColorHsv[2] +} diff --git a/app/src/main/res/layout/dialog_color_picker.xml b/app/src/main/res/layout/dialog_color_picker.xml new file mode 100644 index 000000000..1b5c7043e --- /dev/null +++ b/app/src/main/res/layout/dialog_color_picker.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +