Initial commit - v1.1.9
This commit is contained in:
@@ -0,0 +1,268 @@
|
||||
package com.example.shiftalarm
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.example.shiftalarm.databinding.FragmentSettingsBasicBinding
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.HttpURLConnection
|
||||
import android.app.ProgressDialog
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.coroutines.launch
|
||||
import android.provider.Settings
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
class FragmentSettingsBasic : Fragment() {
|
||||
|
||||
private var _binding: FragmentSettingsBasicBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private val PREFS_NAME = "ShiftAlarmPrefs"
|
||||
private var isUserInteraction = false
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
_binding = FragmentSettingsBasicBinding.inflate(inflater, container, false)
|
||||
return binding.root
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
loadSettings()
|
||||
setupListeners()
|
||||
}
|
||||
|
||||
private fun loadSettings() {
|
||||
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
// Factory Spinner
|
||||
setupFactorySpinner(prefs)
|
||||
|
||||
// Team Spinner
|
||||
setupTeamSpinner(prefs)
|
||||
|
||||
// Version Info
|
||||
try {
|
||||
val pInfo = requireContext().packageManager.getPackageInfo(requireContext().packageName, 0)
|
||||
binding.versionInfo.text = "Ver. ${pInfo.versionName} | 제작자: 산적이얌"
|
||||
} catch (e: Exception) {
|
||||
binding.versionInfo.text = "Ver. Unknown | 제작자: 산적이얌"
|
||||
}
|
||||
|
||||
// Show/Hide Exact Alarm based on version
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
binding.btnExactAlarm.visibility = View.VISIBLE
|
||||
binding.dividerExact.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.btnExactAlarm.visibility = View.GONE
|
||||
binding.dividerExact.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupFactorySpinner(prefs: android.content.SharedPreferences) {
|
||||
val savedFactory = prefs.getString("selected_factory", "Jeonju")
|
||||
val factoryIndex = if (savedFactory == "Nonsan") 1 else 0
|
||||
binding.factorySpinner.setSelection(factoryIndex)
|
||||
|
||||
binding.factorySpinner.setOnTouchListener { _, _ ->
|
||||
isUserInteraction = true
|
||||
false
|
||||
}
|
||||
|
||||
binding.factorySpinner.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
if (!isUserInteraction) return
|
||||
|
||||
val isNonsan = position == 1
|
||||
val factory = if (isNonsan) "Nonsan" else "Jeonju"
|
||||
|
||||
val currentFactory = prefs.getString("selected_factory", "Jeonju")
|
||||
if (factory == currentFactory) {
|
||||
// Just update team spinner without resetting times if same factory
|
||||
updateTeamSpinner(isNonsan)
|
||||
return
|
||||
}
|
||||
|
||||
// Save immediately
|
||||
val editor = prefs.edit()
|
||||
editor.putString("selected_factory", factory)
|
||||
editor.apply()
|
||||
|
||||
// CRUCIAL: Re-sync all alarms for the new factory
|
||||
lifecycleScope.launch {
|
||||
syncAllAlarms(requireContext())
|
||||
Toast.makeText(requireContext(), "공장 설정이 변경되었습니다.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
// Update Team Spinner logic
|
||||
updateTeamSpinner(isNonsan)
|
||||
}
|
||||
override fun onNothingSelected(parent: android.widget.AdapterView<*>?) {}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTeamSpinner(isNonsan: Boolean) {
|
||||
val currentSelection = binding.teamSpinner.selectedItemPosition
|
||||
val teamOptions = if (isNonsan) {
|
||||
arrayOf("A반", "B반", "C반")
|
||||
} else {
|
||||
arrayOf("A반", "B반", "C반", "D반")
|
||||
}
|
||||
|
||||
val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, teamOptions)
|
||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
binding.teamSpinner.adapter = adapter
|
||||
|
||||
if (currentSelection < teamOptions.size) {
|
||||
binding.teamSpinner.setSelection(currentSelection)
|
||||
} else {
|
||||
binding.teamSpinner.setSelection(0)
|
||||
if (isUserInteraction) {
|
||||
Toast.makeText(requireContext(), "논산 회사는 D반이 없습니다. A반으로 설정됩니다.", Toast.LENGTH_SHORT).show()
|
||||
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
prefs.edit().putString("selected_team", "A").apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupTeamSpinner(prefs: android.content.SharedPreferences) {
|
||||
val savedFactory = prefs.getString("selected_factory", "Jeonju")
|
||||
val isNonsan = savedFactory == "Nonsan"
|
||||
updateTeamSpinner(isNonsan)
|
||||
|
||||
val savedTeam = prefs.getString("selected_team", "A")
|
||||
val teamIndex = when (savedTeam) {
|
||||
"A" -> 0
|
||||
"B" -> 1
|
||||
"C" -> 2
|
||||
"D" -> if (isNonsan) 0 else 3
|
||||
else -> 0
|
||||
}
|
||||
binding.teamSpinner.setSelection(teamIndex)
|
||||
|
||||
binding.teamSpinner.setOnTouchListener { _, _ ->
|
||||
isUserInteraction = true
|
||||
false
|
||||
}
|
||||
|
||||
binding.teamSpinner.onItemSelectedListener = object : android.widget.AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: android.widget.AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
if (!isUserInteraction) return
|
||||
|
||||
val selectedTeam = when(position) {
|
||||
0 -> "A"
|
||||
1 -> "B"
|
||||
2 -> "C"
|
||||
3 -> "D"
|
||||
else -> "A"
|
||||
}
|
||||
prefs.edit().putString("selected_team", selectedTeam).apply()
|
||||
|
||||
// CRUCIAL: Re-sync all alarms for the new team
|
||||
lifecycleScope.launch {
|
||||
syncAllAlarms(requireContext())
|
||||
Toast.makeText(requireContext(), "${selectedTeam}반으로 알람이 재설정되었습니다.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: android.widget.AdapterView<*>?) {}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
updatePermissionStatuses()
|
||||
}
|
||||
|
||||
private fun updatePermissionStatuses() {
|
||||
val context = requireContext()
|
||||
|
||||
// 1. 배터리 (Battery)
|
||||
val isBatteryIgnored = AlarmPermissionUtil.getBatteryOptimizationStatus(context)
|
||||
binding.tvBatteryStatus.text = if (isBatteryIgnored) "[설정 완료: 절전 예외]" else "클릭하여 '제한 없음'으로 설정하세요"
|
||||
binding.tvBatteryStatus.setTextColor(ContextCompat.getColor(context, if (isBatteryIgnored) R.color.primary else R.color.shift_red))
|
||||
|
||||
// 2. 정확한 알람 (Exact Alarm) - Android 12+
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val isExactGranted = AlarmPermissionUtil.getExactAlarmStatus(context)
|
||||
binding.tvExactStatus.text = if (isExactGranted) "[설정 완료: 정밀 알람]" else "필수: 클릭하여 권한을 허용하세요"
|
||||
binding.tvExactStatus.setTextColor(ContextCompat.getColor(context, if (isExactGranted) R.color.primary else R.color.shift_red))
|
||||
} else {
|
||||
binding.btnExactAlarm.visibility = View.GONE
|
||||
binding.dividerExact.visibility = View.GONE
|
||||
}
|
||||
|
||||
// 3. 다른 앱 위에 표시 (Overlay)
|
||||
val isOverlayGranted = AlarmPermissionUtil.getOverlayStatus(context)
|
||||
binding.tvOverlayStatus.text = if (isOverlayGranted) "[설정 완료: 화면 우위]" else "필수: 알람창 노출을 위해 허용하세요"
|
||||
binding.tvOverlayStatus.setTextColor(ContextCompat.getColor(context, if (isOverlayGranted) R.color.primary else R.color.shift_red))
|
||||
|
||||
// 4. 전체화면 알림 (Full Screen Intent) - Android 14+
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val isFullScreenGranted = AlarmPermissionUtil.getFullScreenIntentStatus(context)
|
||||
binding.tvFullScreenStatus.text = if (isFullScreenGranted) "[설정 완료: 전체화면]" else "필수: 안드로이드 14 이상 필수 설정"
|
||||
binding.tvFullScreenStatus.setTextColor(ContextCompat.getColor(context, if (isFullScreenGranted) R.color.primary else R.color.shift_red))
|
||||
binding.btnFullScreenIntent.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.btnFullScreenIntent.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupListeners() {
|
||||
val prefs = requireContext().getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
binding.btnBatteryOptimize.setOnClickListener {
|
||||
AlarmPermissionUtil.requestBatteryOptimization(requireContext())
|
||||
}
|
||||
|
||||
binding.btnExactAlarm.setOnClickListener {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).apply {
|
||||
data = Uri.parse("package:${requireContext().packageName}")
|
||||
}
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
binding.btnOverlayPermission.setOnClickListener {
|
||||
AlarmPermissionUtil.requestOverlayPermission(requireContext())
|
||||
}
|
||||
|
||||
binding.btnFullScreenIntent.setOnClickListener {
|
||||
AlarmPermissionUtil.requestFullScreenIntentPermission(requireContext())
|
||||
}
|
||||
|
||||
binding.btnPermissionSettings.setOnClickListener {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.parse("package:${requireContext().packageName}")
|
||||
}
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
binding.btnCheckUpdate.setOnClickListener {
|
||||
checkUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkUpdate() {
|
||||
AppUpdateManager.checkUpdate(requireActivity(), silent = false)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user