575 lines
27 KiB
Kotlin
575 lines
27 KiB
Kotlin
package com.example.shiftalarm
|
|
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.content.SharedPreferences
|
|
import android.graphics.Color
|
|
import android.os.Bundle
|
|
import android.util.Log
|
|
import android.view.LayoutInflater
|
|
import android.view.View
|
|
import android.view.ViewGroup
|
|
import android.widget.Button
|
|
import android.widget.LinearLayout
|
|
import android.widget.TextView
|
|
import android.widget.TimePicker
|
|
import android.widget.Toast
|
|
import androidx.appcompat.app.AlertDialog
|
|
import com.google.android.material.materialswitch.MaterialSwitch
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.fragment.app.Fragment
|
|
import androidx.lifecycle.lifecycleScope
|
|
import com.example.shiftalarm.databinding.FragmentSettingsAlarmBinding
|
|
import kotlinx.coroutines.launch
|
|
import org.json.JSONArray
|
|
import org.json.JSONObject
|
|
import java.time.LocalDate
|
|
|
|
class FragmentSettingsAlarm : Fragment(), SharedPreferences.OnSharedPreferenceChangeListener {
|
|
|
|
private var _binding: FragmentSettingsAlarmBinding? = null
|
|
private val binding get() = _binding!!
|
|
private val PREFS_NAME = "ShiftAlarmPrefs"
|
|
private lateinit var repository: ShiftRepository
|
|
private var customAlarms: MutableList<CustomAlarm> = mutableListOf()
|
|
|
|
override fun onCreateView(
|
|
inflater: LayoutInflater, container: ViewGroup?,
|
|
savedInstanceState: Bundle?
|
|
): View {
|
|
_binding = FragmentSettingsAlarmBinding.inflate(inflater, container, false)
|
|
repository = ShiftRepository(requireContext())
|
|
return binding.root
|
|
}
|
|
|
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
super.onViewCreated(view, savedInstanceState)
|
|
|
|
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
prefs.registerOnSharedPreferenceChangeListener(this)
|
|
|
|
setupListeners()
|
|
loadSettings()
|
|
}
|
|
|
|
override fun onResume() {
|
|
super.onResume()
|
|
refreshAlarmList()
|
|
}
|
|
|
|
override fun onDestroyView() {
|
|
super.onDestroyView()
|
|
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
prefs.unregisterOnSharedPreferenceChangeListener(this)
|
|
_binding = null
|
|
}
|
|
|
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
|
|
if (key == "master_alarm_enabled") {
|
|
sharedPreferences?.let {
|
|
updateMasterToggleUI(ShiftAlarmDefaults.isMasterAlarmEnabled(it))
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun loadSettings() {
|
|
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
|
|
// Master Toggle Button State
|
|
updateMasterToggleUI(ShiftAlarmDefaults.isMasterAlarmEnabled(prefs))
|
|
|
|
// Migrate and Refresh
|
|
lifecycleScope.launch {
|
|
migrateFromPrefsIfNecessary()
|
|
refreshAlarmList()
|
|
}
|
|
}
|
|
|
|
private suspend fun migrateFromPrefsIfNecessary() {
|
|
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
val legacyJson = prefs.getString("custom_alarms", null)
|
|
if (legacyJson != null) {
|
|
try {
|
|
val arr = JSONArray(legacyJson)
|
|
for (i in 0 until arr.length()) {
|
|
val obj = arr.getJSONObject(i)
|
|
val alarm = CustomAlarm(
|
|
time = obj.getString("time"),
|
|
shiftType = obj.getString("shiftType"),
|
|
isEnabled = obj.optBoolean("enabled", true),
|
|
soundUri = obj.optString("soundUri", null),
|
|
snoozeInterval = obj.optInt("snoozeInterval", 5),
|
|
snoozeRepeat = obj.optInt("snoozeRepeat", 3)
|
|
)
|
|
repository.addCustomAlarm(alarm)
|
|
}
|
|
// Clear legacy data
|
|
prefs.edit().remove("custom_alarms").apply()
|
|
} catch (e: Exception) {
|
|
e.printStackTrace()
|
|
}
|
|
}
|
|
}
|
|
|
|
private fun refreshAlarmList() {
|
|
lifecycleScope.launch {
|
|
customAlarms = repository.getAllCustomAlarms().toMutableList()
|
|
refreshUI()
|
|
}
|
|
}
|
|
|
|
private val soundTitleCache = mutableMapOf<String?, String>()
|
|
|
|
private fun updateMasterToggleUI(isEnabled: Boolean) {
|
|
if (isEnabled) {
|
|
binding.tvMasterStatus.text = "전체 알람 켜짐"
|
|
binding.tvMasterStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.primary))
|
|
binding.tvMasterStatus.backgroundTintList = android.content.res.ColorStateList.valueOf(Color.parseColor("#E3F2FD"))
|
|
} else {
|
|
binding.tvMasterStatus.text = "전체 알람 꺼짐"
|
|
binding.tvMasterStatus.setTextColor(ContextCompat.getColor(requireContext(), R.color.shift_red))
|
|
binding.tvMasterStatus.backgroundTintList = android.content.res.ColorStateList.valueOf(Color.parseColor("#FFEBEE"))
|
|
}
|
|
}
|
|
|
|
private fun setupListeners() {
|
|
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
|
|
binding.tvMasterStatus.setOnClickListener {
|
|
val isEnabled = !ShiftAlarmDefaults.isMasterAlarmEnabled(prefs)
|
|
prefs.edit().putBoolean("master_alarm_enabled", isEnabled).apply()
|
|
updateMasterToggleUI(isEnabled)
|
|
|
|
val message = if (isEnabled) "전체 알람이 켜졌습니다." else "전체 알람이 꺼졌습니다."
|
|
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
|
|
|
|
// Resync immediately
|
|
lifecycleScope.launch { syncAllAlarms(requireContext()) }
|
|
}
|
|
|
|
binding.btnAddCustomAlarm.setOnClickListener {
|
|
showEditDialog(
|
|
title = "새 알람 추가",
|
|
currentTime = "07:00",
|
|
shiftType = "주간",
|
|
existingAlarm = null,
|
|
isNew = true
|
|
)
|
|
}
|
|
|
|
binding.btnTestAlarm.setOnClickListener {
|
|
scheduleTestAlarm(requireContext())
|
|
}
|
|
}
|
|
|
|
private fun refreshUI() {
|
|
val container = binding.alarmListContainer
|
|
container.removeAllViews()
|
|
|
|
for (alarm in customAlarms) {
|
|
val item = createAlarmRow(alarm.shiftType, alarm.time, alarm.isEnabled, isCustom = true, snoozeMin = alarm.snoozeInterval, snoozeRepeat = alarm.snoozeRepeat, soundUri = alarm.soundUri) { isToggle, isLongOrShort ->
|
|
if (isToggle) {
|
|
// AlarmSyncManager를 사용하여 토글 동기화
|
|
lifecycleScope.launch {
|
|
val enable = !alarm.isEnabled
|
|
val result = AlarmSyncManager.toggleAlarm(requireContext(), alarm, enable)
|
|
if (result.isSuccess) {
|
|
Log.d("ShiftAlarm", "알람 토글 동기화 성공: ID=${alarm.id}, enabled=$enable")
|
|
} else {
|
|
Log.e("ShiftAlarm", "알람 토글 동기화 실패", result.exceptionOrNull())
|
|
Toast.makeText(requireContext(), "알람 상태 변경 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
|
|
}
|
|
refreshAlarmList()
|
|
}
|
|
} else {
|
|
showEditDialog("사용자 알람", alarm.time, alarm.shiftType, existingAlarm = alarm, isNew = false)
|
|
}
|
|
}
|
|
container.addView(item)
|
|
}
|
|
}
|
|
|
|
private fun createAlarmRow(
|
|
shiftName: String,
|
|
time: String,
|
|
isEnabled: Boolean,
|
|
isCustom: Boolean,
|
|
snoozeMin: Int,
|
|
snoozeRepeat: Int,
|
|
soundUri: String?,
|
|
onAction: (isToggle: Boolean, isLongClick: Boolean) -> Unit
|
|
): View {
|
|
val view = layoutInflater.inflate(R.layout.item_alarm_unified, binding.alarmListContainer, false)
|
|
view.isFocusable = true
|
|
|
|
val shiftIndicator = view.findViewById<TextView>(R.id.shiftIndicator)
|
|
val tvTime = view.findViewById<TextView>(R.id.tvTime)
|
|
val tvAmPm = view.findViewById<TextView>(R.id.tvAmPm)
|
|
val tvSummary = view.findViewById<TextView>(R.id.tvSummary)
|
|
val alarmSwitch = view.findViewById<MaterialSwitch>(R.id.alarmSwitch)
|
|
val layoutAlarmSwitch = view.findViewById<View>(R.id.layoutAlarmSwitch)
|
|
|
|
val shortName = when(shiftName) {
|
|
"주간" -> "주"
|
|
"석간" -> "석"
|
|
"야간" -> "야"
|
|
"주간 맞교대" -> "주맞"
|
|
"야간 맞교대" -> "야맞"
|
|
"기타" -> "기타"
|
|
else -> shiftName.take(1)
|
|
}
|
|
shiftIndicator.text = shortName
|
|
|
|
val colorRes = when(shiftName) {
|
|
"주간" -> R.color.shift_lemon
|
|
"석간" -> R.color.shift_seok
|
|
"야간" -> R.color.shift_ya
|
|
"주간 맞교대" -> R.color.shift_jumat
|
|
"야간 맞교대" -> R.color.shift_yamat
|
|
else -> R.color.shift_gray
|
|
}
|
|
|
|
val context = requireContext()
|
|
val color = ContextCompat.getColor(context, colorRes)
|
|
val drawable = ContextCompat.getDrawable(context, R.drawable.bg_shift_stroke_v4) as android.graphics.drawable.GradientDrawable
|
|
drawable.mutate()
|
|
drawable.setStroke(dpToPx(2.5f), color)
|
|
shiftIndicator.background = drawable
|
|
shiftIndicator.setTextColor(color)
|
|
|
|
try {
|
|
val parts = time.split(":")
|
|
val h24 = parts[0].toInt()
|
|
val m = parts[1].toInt()
|
|
val h12 = if (h24 % 12 == 0) 12 else h24 % 12
|
|
tvTime.text = String.format("%02d:%02d", h12, m)
|
|
tvAmPm.text = if (h24 < 12) "오전" else "오후"
|
|
|
|
if (!isEnabled) {
|
|
tvTime.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
|
tvAmPm.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
|
tvSummary.setTextColor(ContextCompat.getColor(context, R.color.text_tertiary))
|
|
shiftIndicator.alpha = 0.4f
|
|
} else {
|
|
tvTime.setTextColor(ContextCompat.getColor(context, R.color.text_primary))
|
|
tvAmPm.setTextColor(ContextCompat.getColor(context, R.color.text_secondary))
|
|
tvSummary.setTextColor(ContextCompat.getColor(context, R.color.primary))
|
|
shiftIndicator.alpha = 1.0f
|
|
}
|
|
} catch (e: Exception) { tvTime.text = time }
|
|
|
|
val tvSoundNameView = view.findViewById<TextView>(R.id.tvSoundName)
|
|
val soundName = getSoundTitle(context, soundUri)
|
|
tvSummary.text = "${snoozeMin}분 간격, ${if(snoozeRepeat == 99) "계속" else snoozeRepeat.toString() + "회"}"
|
|
tvSoundNameView.text = soundName
|
|
|
|
val rowContents = view.findViewById<View>(R.id.rowContents)
|
|
rowContents.setOnClickListener { onAction(false, false) }
|
|
rowContents.setOnLongClickListener { onAction(false, true); true }
|
|
|
|
alarmSwitch.isChecked = isEnabled
|
|
layoutAlarmSwitch.setOnClickListener {
|
|
// onAction will handle the data update and re-sync
|
|
onAction(true, false)
|
|
}
|
|
|
|
return view
|
|
}
|
|
|
|
private var currentDialogSoundUri: String? = null
|
|
private var tvSoundNameReference: android.widget.TextView? = null
|
|
|
|
/**
|
|
* 새 알람 추가 시 기본음으로 시스템 알람음 설정
|
|
* 무음 문제 해결을 위해 반드시 시스템 기본 알람음을 반환
|
|
*/
|
|
private fun getDefaultAlarmUri(context: Context): String {
|
|
// 1. 시스템 기본 알람음 (가장 우선)
|
|
val defaultUri = android.provider.Settings.System.DEFAULT_ALARM_ALERT_URI
|
|
if (defaultUri != null) {
|
|
Log.d("ShiftAlarm", "시스템 기본 알람음 URI: $defaultUri")
|
|
return defaultUri.toString()
|
|
}
|
|
|
|
// 2. RingtoneManager에서 알람 타입 기본값 가져오기
|
|
val fallbackUri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_ALARM)
|
|
if (fallbackUri != null) {
|
|
Log.d("ShiftAlarm", "Fallback 알람음 URI: $fallbackUri")
|
|
return fallbackUri.toString()
|
|
}
|
|
|
|
// 3. 마지막 fallback: 알림음이라도 사용
|
|
val notificationUri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_NOTIFICATION)
|
|
if (notificationUri != null) {
|
|
Log.w("ShiftAlarm", "알람음 없음, 알림음 사용: $notificationUri")
|
|
return notificationUri.toString()
|
|
}
|
|
|
|
// 4. 최후의 수단: 벨소리
|
|
val ringtoneUri = android.media.RingtoneManager.getDefaultUri(android.media.RingtoneManager.TYPE_RINGTONE)
|
|
if (ringtoneUri != null) {
|
|
Log.w("ShiftAlarm", "알림음 없음, 벨소리 사용: $ringtoneUri")
|
|
return ringtoneUri.toString()
|
|
}
|
|
|
|
// 이 경우는 거의 없지만, 안전장치
|
|
Log.e("ShiftAlarm", "어떤 기본 소리도 찾을 수 없음")
|
|
return ""
|
|
}
|
|
|
|
private fun showEditDialog(
|
|
title: String, currentTime: String, shiftType: String, existingAlarm: CustomAlarm?, isNew: Boolean
|
|
) {
|
|
val dialogView = layoutInflater.inflate(R.layout.dialog_alarm_edit_spinner, null)
|
|
val dialog = AlertDialog.Builder(requireContext(), android.R.style.Theme_DeviceDefault_Light_NoActionBar_Fullscreen).setView(dialogView).create()
|
|
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
|
|
dialog.window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
|
|
|
val tvTitle = dialogView.findViewById<TextView>(R.id.dialogTitle)
|
|
val timePicker = dialogView.findViewById<TimePicker>(R.id.timePicker)
|
|
val tvSoundName = dialogView.findViewById<TextView>(R.id.tvSoundName)
|
|
tvSoundNameReference = tvSoundName
|
|
|
|
val btnSelectSound = dialogView.findViewById<View>(R.id.btnSelectSound)
|
|
val btnDelete = dialogView.findViewById<Button>(R.id.btnDelete)
|
|
val btnCancel = dialogView.findViewById<View>(R.id.btnCancel)
|
|
val btnSave = dialogView.findViewById<View>(R.id.btnSave)
|
|
|
|
// Initialize Values
|
|
var selectedSnooze = existingAlarm?.snoozeInterval ?: 5
|
|
var selectedRepeat = existingAlarm?.snoozeRepeat ?: 3
|
|
|
|
// 새 알람 생성 시 기본적으로 시스템 알람음 설정 (무음 문제 해결)
|
|
// 기존 알람 수정 시에도 soundUri가 비어있거나 null이면 기본값으로 설정
|
|
val existingUri = existingAlarm?.soundUri
|
|
val isExistingUriEmpty = existingUri.isNullOrEmpty() || existingUri == "null"
|
|
|
|
currentDialogSoundUri = if (isNew || isExistingUriEmpty) {
|
|
// 새 알람 또는 기존 알람의 소리가 설정되지 않은 경우: 반드시 기본 알람음으로 설정
|
|
val defaultUri = getDefaultAlarmUri(requireContext())
|
|
Log.d("ShiftAlarm", "기본 알람음 설정: $defaultUri (isNew=$isNew, isExistingUriEmpty=$isExistingUriEmpty)")
|
|
defaultUri
|
|
} else {
|
|
// 기존 알람 수정: 기존 값 유지
|
|
existingUri
|
|
}
|
|
|
|
// soundUri가 비어있는 경우 최종 안전장치
|
|
if (currentDialogSoundUri.isNullOrEmpty()) {
|
|
currentDialogSoundUri = getDefaultAlarmUri(requireContext())
|
|
Log.w("ShiftAlarm", "soundUri가 비어있어 기본값으로 재설정: $currentDialogSoundUri")
|
|
}
|
|
|
|
Log.d("ShiftAlarm", "알람 ${if (isNew) "생성" else "수정"} - 최종 soundUri: $currentDialogSoundUri")
|
|
|
|
fun updateSoundName(uriStr: String?) {
|
|
if (uriStr.isNullOrEmpty() || uriStr == "null") {
|
|
tvSoundName.text = "기본 알람음"
|
|
} else {
|
|
try {
|
|
val uri = android.net.Uri.parse(uriStr)
|
|
val ringtone = android.media.RingtoneManager.getRingtone(requireContext(), uri)
|
|
val title = ringtone?.getTitle(requireContext()) ?: "알람음"
|
|
tvSoundName.text = title
|
|
} catch (e: Exception) {
|
|
tvSoundName.text = "알람음"
|
|
}
|
|
}
|
|
}
|
|
updateSoundName(currentDialogSoundUri)
|
|
|
|
// Snooze Interval Buttons
|
|
val snoozeButtons = listOf(
|
|
dialogView.findViewById<TextView>(R.id.snooze5),
|
|
dialogView.findViewById<TextView>(R.id.snooze10),
|
|
dialogView.findViewById<TextView>(R.id.snooze15),
|
|
dialogView.findViewById<TextView>(R.id.snooze30)
|
|
)
|
|
val snoozeValues = listOf(5, 10, 15, 30)
|
|
fun updateSnoozeUI() {
|
|
snoozeButtons.forEachIndexed { i, btn ->
|
|
val isSelected = snoozeValues[i] == selectedSnooze
|
|
btn.setBackgroundResource(if (isSelected) R.drawable.bg_pill_rect_selected else R.drawable.bg_pill_rect_unselected)
|
|
btn.setTextColor(if (isSelected) ContextCompat.getColor(requireContext(), R.color.white) else ContextCompat.getColor(requireContext(), R.color.text_secondary))
|
|
}
|
|
}
|
|
updateSnoozeUI()
|
|
snoozeButtons.forEachIndexed { i, btn -> btn.setOnClickListener { selectedSnooze = snoozeValues[i]; updateSnoozeUI() } }
|
|
|
|
// Repeat Count Buttons
|
|
val repeatButtons = listOf(
|
|
dialogView.findViewById<TextView>(R.id.repeat3),
|
|
dialogView.findViewById<TextView>(R.id.repeat5),
|
|
dialogView.findViewById<TextView>(R.id.repeatForever)
|
|
)
|
|
val repeatValues = listOf(3, 5, 99)
|
|
fun updateRepeatUI() {
|
|
repeatButtons.forEachIndexed { i, btn ->
|
|
val isSelected = repeatValues[i] == selectedRepeat
|
|
btn.setBackgroundResource(if (isSelected) R.drawable.bg_pill_rect_selected else R.drawable.bg_pill_rect_unselected)
|
|
btn.setTextColor(if (isSelected) ContextCompat.getColor(requireContext(), R.color.white) else ContextCompat.getColor(requireContext(), R.color.text_secondary))
|
|
}
|
|
}
|
|
updateRepeatUI()
|
|
repeatButtons.forEachIndexed { i, btn -> btn.setOnClickListener { selectedRepeat = repeatValues[i]; updateRepeatUI() } }
|
|
|
|
val cardShift = dialogView.findViewById<View>(R.id.cardShiftSelector)
|
|
var currentShift = shiftType
|
|
cardShift.visibility = View.VISIBLE
|
|
val shiftBtns = listOf(
|
|
dialogView.findViewById<TextView>(R.id.btnShiftJu),
|
|
dialogView.findViewById<TextView>(R.id.btnShiftSeok),
|
|
dialogView.findViewById<TextView>(R.id.btnShiftYa),
|
|
dialogView.findViewById<TextView>(R.id.btnShiftYaMat),
|
|
dialogView.findViewById<TextView>(R.id.btnShiftEtc)
|
|
)
|
|
val shiftTypes = listOf("주간", "석간", "야간", "야간 맞교대", "기타")
|
|
fun updateShiftUI() {
|
|
shiftBtns.forEachIndexed { i, btn ->
|
|
val isSelected = shiftTypes[i] == currentShift
|
|
val colorRes = when(shiftTypes[i]) {
|
|
"주간" -> R.color.shift_lemon; "석간" -> R.color.shift_seok; "야간" -> R.color.shift_ya
|
|
"야간 맞교대" -> R.color.shift_yamat; else -> R.color.shift_gray
|
|
}
|
|
val color = ContextCompat.getColor(requireContext(), colorRes)
|
|
if (isSelected) {
|
|
val d = ContextCompat.getDrawable(requireContext(), R.drawable.bg_shift_circle_v4) as android.graphics.drawable.GradientDrawable
|
|
d.mutate(); d.setColor(color); btn.background = d
|
|
btn.setTextColor(if (shiftTypes[i] == "야간") ContextCompat.getColor(requireContext(), R.color.white) else ContextCompat.getColor(requireContext(), R.color.black))
|
|
} else {
|
|
val d = ContextCompat.getDrawable(requireContext(), R.drawable.bg_shift_stroke_v4) as android.graphics.drawable.GradientDrawable
|
|
d.mutate(); d.setStroke(dpToPx(1.5f), color); btn.background = d; btn.setTextColor(color)
|
|
}
|
|
}
|
|
}
|
|
updateShiftUI()
|
|
shiftBtns.forEachIndexed { i, btn -> btn.setOnClickListener { currentShift = shiftTypes[i]; updateShiftUI() } }
|
|
|
|
tvTitle.text = if (isNew) "새 알람 추가" else "$shiftType 알람 수정"
|
|
timePicker.setIs24HourView(false)
|
|
val parts = currentTime.split(":")
|
|
if (android.os.Build.VERSION.SDK_INT >= 23) {
|
|
timePicker.hour = parts[0].toInt(); timePicker.minute = parts[1].toInt()
|
|
} else {
|
|
timePicker.currentHour = parts[0].toInt(); timePicker.currentMinute = parts[1].toInt()
|
|
}
|
|
|
|
btnSelectSound.setOnClickListener {
|
|
val intent = Intent(android.media.RingtoneManager.ACTION_RINGTONE_PICKER).apply {
|
|
putExtra(android.media.RingtoneManager.EXTRA_RINGTONE_TYPE, android.media.RingtoneManager.TYPE_ALARM)
|
|
putExtra(android.media.RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, if (currentDialogSoundUri != null) android.net.Uri.parse(currentDialogSoundUri) else null as android.net.Uri?)
|
|
}
|
|
startActivityForResult(intent, 100)
|
|
}
|
|
|
|
if (!isNew) {
|
|
btnDelete.visibility = View.VISIBLE
|
|
btnDelete.setOnClickListener {
|
|
lifecycleScope.launch {
|
|
existingAlarm?.let {
|
|
// AlarmSyncManager를 사용하여 동기화된 삭제 수행
|
|
// DB 삭제 전 AlarmManager 취소가 보장됨
|
|
val result = AlarmSyncManager.deleteAlarm(requireContext(), it)
|
|
if (result.isSuccess) {
|
|
Log.d("ShiftAlarm", "알람 삭제 동기화 성공: ID=${it.id}")
|
|
} else {
|
|
Log.e("ShiftAlarm", "알람 삭제 동기화 실패", result.exceptionOrNull())
|
|
Toast.makeText(requireContext(), "알람 삭제 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
refreshAlarmList()
|
|
dialog.dismiss()
|
|
}
|
|
}
|
|
}
|
|
|
|
btnCancel.setOnClickListener { dialog.dismiss() }
|
|
btnSave.setOnClickListener {
|
|
val h = if (android.os.Build.VERSION.SDK_INT >= 23) timePicker.hour else timePicker.currentHour
|
|
val m = if (android.os.Build.VERSION.SDK_INT >= 23) timePicker.minute else timePicker.currentMinute
|
|
val time = String.format("%02d:%02d", h, m)
|
|
|
|
lifecycleScope.launch {
|
|
if (isNew) {
|
|
val newAlarm = CustomAlarm(
|
|
time = time,
|
|
shiftType = currentShift,
|
|
isEnabled = true,
|
|
soundUri = currentDialogSoundUri,
|
|
snoozeInterval = selectedSnooze,
|
|
snoozeRepeat = selectedRepeat
|
|
)
|
|
// AlarmSyncManager를 사용하여 동기화된 추가 수행
|
|
val result = AlarmSyncManager.addAlarm(requireContext(), newAlarm)
|
|
if (result.isSuccess) {
|
|
Log.d("ShiftAlarm", "새 알람 추가 동기화 성공")
|
|
Toast.makeText(requireContext(), "알람이 추가되었습니다.", Toast.LENGTH_SHORT).show()
|
|
} else {
|
|
Log.e("ShiftAlarm", "새 알람 추가 동기화 실패", result.exceptionOrNull())
|
|
Toast.makeText(requireContext(), "알람 추가 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
|
|
}
|
|
} else {
|
|
val updated = existingAlarm!!.copy(
|
|
time = time,
|
|
shiftType = currentShift,
|
|
soundUri = currentDialogSoundUri,
|
|
snoozeInterval = selectedSnooze,
|
|
snoozeRepeat = selectedRepeat
|
|
)
|
|
// AlarmSyncManager를 사용하여 동기화된 수정 수행
|
|
val result = AlarmSyncManager.updateAlarm(requireContext(), updated)
|
|
if (result.isSuccess) {
|
|
Log.d("ShiftAlarm", "알람 수정 동기화 성공: ID=${updated.id}")
|
|
Toast.makeText(requireContext(), "알람이 수정되었습니다.", Toast.LENGTH_SHORT).show()
|
|
} else {
|
|
Log.e("ShiftAlarm", "알람 수정 동기화 실패", result.exceptionOrNull())
|
|
Toast.makeText(requireContext(), "알람 수정 중 오류가 발생했습니다.", Toast.LENGTH_SHORT).show()
|
|
}
|
|
}
|
|
refreshAlarmList()
|
|
dialog.dismiss()
|
|
}
|
|
}
|
|
dialog.setOnDismissListener { tvSoundNameReference = null }
|
|
dialog.show()
|
|
}
|
|
|
|
private fun dpToPx(dp: Float): Int {
|
|
return (dp * resources.displayMetrics.density).toInt()
|
|
}
|
|
|
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: android.content.Intent?) {
|
|
super.onActivityResult(requestCode, resultCode, data)
|
|
if (resultCode == androidx.appcompat.app.AppCompatActivity.RESULT_OK) {
|
|
val uri = data?.getParcelableExtra<android.net.Uri>(android.media.RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
|
|
if (uri != null) {
|
|
currentDialogSoundUri = uri.toString()
|
|
try {
|
|
val ringtone = android.media.RingtoneManager.getRingtone(requireContext(), uri)
|
|
tvSoundNameReference?.text = ringtone.getTitle(requireContext())
|
|
} catch(e: Exception) {
|
|
tvSoundNameReference?.text = "사용자 지정음"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
private fun getSoundTitle(context: Context, uriStr: String?): String {
|
|
if (soundTitleCache.containsKey(uriStr)) return soundTitleCache[uriStr]!!
|
|
|
|
// uriStr이 null이거나 비어있거나 "null" 문자열인 경우 기본음으로 처리
|
|
val title = if (uriStr.isNullOrEmpty() || uriStr == "null") {
|
|
"기본 알람음"
|
|
} else {
|
|
try {
|
|
val uri = android.net.Uri.parse(uriStr)
|
|
val ringtone = android.media.RingtoneManager.getRingtone(context, uri)
|
|
ringtone?.getTitle(context) ?: "알람음"
|
|
} catch (e: Exception) {
|
|
"알람음"
|
|
}
|
|
}
|
|
soundTitleCache[uriStr] = title
|
|
return title
|
|
}
|
|
}
|