v1.0.5 - 메모 아이콘 정리, 삼성 One UI 최신 알람 화면 개편, 달력 깜빡임 해소 및 카드 스택 전환 애니메이션 적용

This commit is contained in:
sanjeok77
2026-08-14 09:48:22 +09:00
parent d245aeb7d5
commit 696083060d
13 changed files with 395 additions and 195 deletions
@@ -185,50 +185,68 @@ class AlarmActivity : AppCompatActivity() {
}
private fun setupControls() {
val snoozeInterval = intent.getIntExtra("EXTRA_SNOOZE_INTERVAL", 5)
binding.tvSnoozeText.text = "다시 울림 (${snoozeInterval}분)"
binding.btnSnooze.setOnClickListener {
handleSnooze()
}
// Swipe-to-dismiss for Stop Button
// Omni-directional Swipe & Tap to Dismiss (Samsung One UI Clock Style)
var startX = 0f
var startY = 0f
var isMoved = false
val dismissBtn = binding.btnDismiss
val maxSwipe = dpToPx(100f).toFloat()
val maxSwipe = dpToPx(80f).toFloat()
dismissBtn.setOnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
startX = event.rawX
startY = event.rawY
isMoved = false
v.animate().cancel()
v.scaleX = 0.96f
v.scaleY = 0.96f
true
}
MotionEvent.ACTION_MOVE -> {
val dx = event.rawX - startX
val clampedDx = if (dx > 0) dx.coerceAtMost(maxSwipe) else dx.coerceAtLeast(-maxSwipe)
v.translationX = clampedDx
val dy = event.rawY - startY
val distance = Math.hypot(dx.toDouble(), dy.toDouble()).toFloat()
// Visual feedback: scale up when near trigger
val ratio = abs(clampedDx) / maxSwipe
v.scaleX = 1f + (ratio * 0.15f)
v.scaleY = 1f + (ratio * 0.15f)
v.alpha = 1f - (ratio * 0.3f)
if (distance > 10f) {
isMoved = true
}
val clampedDx = dx.coerceIn(-maxSwipe, maxSwipe)
val clampedDy = dy.coerceIn(-maxSwipe, maxSwipe)
v.translationX = clampedDx
v.translationY = clampedDy
val ratio = (distance / maxSwipe).coerceAtMost(1f)
v.scaleX = 0.96f + (ratio * 0.18f)
v.scaleY = 0.96f + (ratio * 0.18f)
binding.pulseCircle.alpha = 0.4f + (ratio * 0.6f)
true
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
val dx = event.rawX - startX
if (abs(dx) > maxSwipe * 0.8f) {
// Trigger Dismiss
@Suppress("DEPRECATION")
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(50)
Toast.makeText(this, "알람 해제 완료", Toast.LENGTH_SHORT).show()
stopAlarm(); finish()
val dy = event.rawY - startY
val distance = Math.hypot(dx.toDouble(), dy.toDouble()).toFloat()
// Trigger dismiss if swiped past threshold or tapped
if (!isMoved || distance > maxSwipe * 0.5f) {
triggerDismiss()
} else {
// Reset
// Spring back reset
v.animate()
.translationX(0f)
.translationY(0f)
.scaleX(1f)
.scaleY(1f)
.alpha(1f)
.setDuration(300)
.setDuration(250)
.setInterpolator(android.view.animation.OvershootInterpolator(1.5f))
.start()
}
true
@@ -237,17 +255,35 @@ class AlarmActivity : AppCompatActivity() {
}
}
// Pulse logic with enhanced glow
// Dual Wave Breathing Animation (Samsung Ambient Glow)
fun startPulse() {
binding.pulseCircle.scaleX = 0.85f; binding.pulseCircle.scaleY = 0.85f; binding.pulseCircle.alpha = 0.5f
binding.pulseCircle.scaleX = 0.8f
binding.pulseCircle.scaleY = 0.8f
binding.pulseCircle.alpha = 0.3f
binding.ambientRing.scaleX = 0.9f
binding.ambientRing.scaleY = 0.9f
binding.ambientRing.alpha = 0.5f
binding.pulseCircle.animate()
.scaleX(1.3f).scaleY(1.3f).alpha(1.0f)
.setDuration(1500)
.withEndAction {
.scaleX(1.35f).scaleY(1.35f).alpha(0.8f)
.setDuration(1600)
.withEndAction {
binding.pulseCircle.animate()
.scaleX(0.85f).scaleY(0.85f).alpha(0.5f)
.setDuration(1500)
.withEndAction { if(!isFinishing) startPulse() }
.scaleX(0.8f).scaleY(0.8f).alpha(0.3f)
.setDuration(1600)
.withEndAction { if (!isFinishing) startPulse() }
.start()
}
.start()
binding.ambientRing.animate()
.scaleX(1.15f).scaleY(1.15f).alpha(0.85f)
.setDuration(1600)
.withEndAction {
binding.ambientRing.animate()
.scaleX(0.9f).scaleY(0.9f).alpha(0.5f)
.setDuration(1600)
.start()
}
.start()
@@ -255,13 +291,35 @@ class AlarmActivity : AppCompatActivity() {
startPulse()
}
private fun triggerDismiss() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(
VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)
)
} else {
@Suppress("DEPRECATION")
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(50)
}
Toast.makeText(this, "알람이 해제되었습니다.", Toast.LENGTH_SHORT).show()
stopAlarm()
finish()
}
private fun handleSnooze() {
@Suppress("DEPRECATION")
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(50)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(
VibrationEffect.createOneShot(50, VibrationEffect.DEFAULT_AMPLITUDE)
)
} else {
@Suppress("DEPRECATION")
(getSystemService(Context.VIBRATOR_SERVICE) as? Vibrator)?.vibrate(50)
}
val snoozeRepeat = intent.getIntExtra("EXTRA_SNOOZE_REPEAT", 3)
val text = if (snoozeRepeat == 99) "다시 울림 설정됨" else "다시 울림 (${snoozeRepeat}회 남음)"
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
snoozeAlarm(); stopAlarm(); finish()
snoozeAlarm()
stopAlarm()
finish()
}
private fun dpToPx(dp: Float): Int {