AddClockViewModel

36 阅读2分钟
package com.alibaba.genie.panel.alarm.viewmodel

import android.app.Activity
import android.app.Application
import android.text.TextUtils
import cn.hutool.core.date.DateTime
import cn.hutool.core.date.DateUtil
import com.alibaba.fastjson.JSON
import com.alibaba.genie.panel.alarm.R
import com.alibaba.genie.panel.alarm.SettingRepository
import com.alibaba.genie.panel.alarm.repository.bean.AlarmBean
import com.alibaba.genie.panel.alarm.ui.utils.AlarmClockUtil
import com.alibaba.genie.panel.alarm.utils.CommonUtil
import com.alibaba.genie.panel.basic.base.SingleLiveData
import com.alibaba.genie.panel.basic.component.event.AlarmClockEvent
import com.alibaba.genie.panel.basic.constant.KeyConstant
import com.alibaba.genie.panel.basic.utils.SettingLog
import com.aliyun.aligeniessp_1_0.models.CreateAlarmRequest
import com.aliyun.aligeniessp_1_0.models.CreateAlarmRequest.CreateAlarmRequestPayloadScheduleInfoOnce
import com.aliyun.aligeniessp_1_0.models.CreateAlarmRequest.CreateAlarmRequestPayloadScheduleInfoStatutoryWorkingDay
import com.aliyun.aligeniessp_1_0.models.CreateAlarmResponse
import com.aliyun.aligeniessp_1_0.models.DeleteAlarmsResponse
import com.aliyun.aligeniessp_1_0.models.ListAlarmsResponseBody
import com.aliyun.aligeniessp_1_0.models.ListMusicResponse
import com.aliyun.aligeniessp_1_0.models.ListMusicResponseBody
import com.aliyun.aligeniessp_1_0.models.UpdateAlarmRequest
import com.aliyun.aligeniessp_1_0.models.UpdateAlarmResponse
import java.util.Date

open class AddClockViewModel(application: Application) : BaseAlarmViewModel(application) {
    val deleteLiveData = SingleLiveData<Boolean>()
    val pageTitleLiveData = SingleLiveData<String>()
    val nivIconLiveData = SingleLiveData<Int>()
    val nivRingtoneLiveData = SingleLiveData<String>()
    val nivRemarkLiveData = SingleLiveData<String>()
    val nivRepeatLiveData = SingleLiveData<Pair<Int, String>>()

    var dayOfWeek: IntArray? = null

    private val defaultRemarkName: String =
        application.getString(R.string.setting_alarm_clock_default_remark)
    var iconType: Int = AlarmClockUtil.AlarmIconType.ALARM_ICON_BELL
        set(value) {
            field = value
            nivIconLiveData.value = AlarmClockUtil.getSmallIcon(value)
        }

    /**
     * 闹钟信息(更新、编辑态)
     */
    var alarm: AlarmBean? = null
        set(value) {
            field = value
            deleteLiveData.value = (value != null && value.alarmId != 0L)
            pageTitleLiveData.value = if (value == null) "添加闹钟" else "编辑闹钟"

            val remark: String
            val iconType: Int
            if (value == null || value.alarmDBInfo == null) {
                remark = defaultRemarkName
                iconType = AlarmClockUtil.AlarmIconType.ALARM_ICON_BELL
            } else {
                remark = value.alarmDBInfo.remark
                iconType = value.alarmDBInfo.icon
            }

            val ringtone: String?
            if (value == null || value.alarmInfo == null) {
                ringtone = "鼓声"
                dealRepeat(0, null)
            } else {
                ringtone = value.alarmInfo.musicInfo?.musicName
                processRepeatInfo(value.alarmInfo.scheduleInfo)
            }
            nivRemarkLiveData.value = remark
            this@AddClockViewModel.iconType = iconType
            nivRingtoneLiveData.value = ringtone
        }

    private fun processRepeatInfo(scheduleInfo: ListAlarmsResponseBody.ListAlarmsResponseBodyResultModelScheduleInfo): Unit {
        when (scheduleInfo.type) {
            KeyConstant.ALARM_SCHEDULE_ONCE -> {
                dealRepeat(0, null)
            }

            KeyConstant.ALARM_SCHEDULE_STATUTORY_WORKING_DAY -> {
                dealRepeat(3, null)
            }

            KeyConstant.ALARM_SCHEDULE_WEEKLY -> {
                val weekly = scheduleInfo.weekly
                val daysOfWeek = weekly.daysOfWeek
                daysOfWeek?.let { week ->
                    val size = week.size
                    if (size == 7) {
                        dealRepeat(1, daysOfWeek.toIntArray())
                    } else if (size == 5 && week.sum() == 15) {
                        dealRepeat(2, daysOfWeek.toIntArray())
                    } else {
                        dealRepeat(4, daysOfWeek.toIntArray())
                    }
                }
            }

        }
    }

    var musicList: List<ListMusicResponseBody.ListMusicResponseBodyResultModel>? = null
        get() {
            if (field.isNullOrEmpty()) {
                field = pref.musicList
            }
            return field
        }

    var musicNameList: List<String>? = null
        get() {
            if (field == null) {
                field = musicList?.map { it.musicName }
            }
            return field
        }

    var remark: String? = null
        set(value) {
            field = if (value.isNullOrEmpty()) {
                defaultRemarkName
            } else {
                value
            }
            nivRemarkLiveData.value = field
        }
        get() = nivRemarkLiveData.value

    var scheduleType: String = KeyConstant.ALARM_SCHEDULE_ONCE
    var selectMusicId: Long = 1L

    fun dealRepeat(index: Int, dayOfWeek: IntArray?) {
        val info = when (index) {
            0 -> "单次"
            1 -> "每天"
            2 -> "工作日"
            3 -> "法定工作日"
            4 -> parseDayOdWeekToShortStr(dayOfWeek)
            else -> ""
        }
        scheduleType = when (index) {
            0 -> KeyConstant.ALARM_SCHEDULE_ONCE
            1, 2, 4 -> KeyConstant.ALARM_SCHEDULE_WEEKLY
            3 -> KeyConstant.ALARM_SCHEDULE_STATUTORY_WORKING_DAY
            else -> KeyConstant.ALARM_SCHEDULE_ONCE
        }
        this.dayOfWeek = when (index) {
            0 -> null
            1 -> intArrayOf(1, 2, 3, 4, 5, 6, 7)
            2 -> intArrayOf(1, 2, 3, 4, 5)
            3 -> null
            4 -> dayOfWeek
            else -> null
        }
        nivRepeatLiveData.value = Pair(index, info)
    }

    fun dealRingtone(index: Int) {
        musicList?.get(index)?.let {
            selectMusicId = it.musicId
            nivRingtoneLiveData.value = it.musicName
        }
    }

    private fun parseDayOdWeekToShortStr(dayOfWeek: IntArray?) = dayOfWeek?.map {
        when (it) {
            1 -> "一"
            2 -> "二"
            3 -> "三"
            4 -> "四"
            5 -> "五"
            6 -> "六"
            7 -> "日"
            else -> {}
        }
    }?.joinToString("/", prefix = "周") ?: ""


    fun performAddClock(
        hour: Int,
        minute: Int,
    ) {
        if (!checkNetWork()) return

        if (alarm == null || alarm!!.alarmId == 0L) {
            performAddClock(
                scheduleType,
                dayOfWeek,
                hour,
                minute,
                selectMusicId,
                remark ?: defaultRemarkName,
                iconType,
                false
            )
        } else {
            performDelAndAddClock {
                performAddClock(
                    scheduleType,
                    dayOfWeek,
                    hour,
                    minute,
                    selectMusicId,
                    remark ?: defaultRemarkName,
                    iconType,
                    true
                )
            }
//            performUpdateClock(
//                scheduleType,
//                dayOfWeek,
//                hour,
//                minute,
//                selectMusicId,
//                remark ?: defaultRemarkName,
//                nivIconLiveData.value ?: R.drawable.ic_alarm_clock_bell
//            )
        }

    }

    private fun checkNetWork(): Boolean {
        val app = this.getApplication<Application>()
        return if (app != null && !CommonUtil.isNetWorkAvailable(app)) {
            showToast(app.getString(R.string.setting_alarm_clock_no_network))
            false
        } else
            true
    }

    /**
     * 添加闹钟
     *
     * @param scheduleType
     * @param daysOfWeek
     * @param hour
     * @param minute
     * @param musicId
     * @param remark
     * @param iconType
     */
    private fun performAddClock(
        scheduleType: String,
        daysOfWeek: IntArray?,
        hour: Int,
        minute: Int,
        musicId: Long,
        remark: String,
        iconType: Int,
        delThenAdd: Boolean
    ) {

        // 调度信息
        val scheduleInfo =
            CreateAlarmRequest.CreateAlarmRequestPayloadScheduleInfo().setType(scheduleType)
        when (scheduleType) {
            KeyConstant.ALARM_SCHEDULE_ONCE -> scheduleInfo.setOnce(buildOnce(hour, minute))

            KeyConstant.ALARM_SCHEDULE_STATUTORY_WORKING_DAY -> scheduleInfo.setStatutoryWorkingDay(
                buildWorkingDay(hour, minute)
            )

            KeyConstant.ALARM_SCHEDULE_WEEKLY -> daysOfWeek?.let {
                scheduleInfo.setWeekly(buildWeekly(hour, minute, daysOfWeek))
            }
        }

        val music = getMusicInfoById(musicId)
        // 铃声信息
        val musicInfo = CreateAlarmRequest.CreateAlarmRequestPayloadMusicInfo().apply {
            setMusicId(music.musicId)
            setMusicType(music.musicType)
            setMusicName(music.musicName)
            setMusicTypeName(music.musicTypeName)
            setMusicUrl(music.musicUrl)
        }
        // 铃声音量
        val volume = 100
        SettingLog.w(
            TAG,
            "createAlarm, scheduleInfo: ${JSON.toJSONString(scheduleInfo)}, musicInfo: ${
                JSON.toJSONString(musicInfo)
            }, volume: $volume"
        )
        openApi.createAlarm(
            scheduleInfo,
            musicInfo,
            volume,
            object : SettingRepository.OnResponseListener<CreateAlarmResponse> {
                override fun onSuccess(response: CreateAlarmResponse) {

                    // 账号信息错误导致创建失败
                    if (null == response || null == response.body) {
                        showToast(if (delThenAdd) "更新失败" else "创建失败")
                        return
                    }
                    if (null == response.body.result) {
                        showToast(if (TextUtils.isEmpty(response.body.message)) "创建失败" else response.body.message)
                        return
                    }
                    val alarmId = response.body.result
                    alarmIconRemarkDatabaseHelper.insert(alarmId, remark, iconType)
                    // 创建成功
//                    liveBus.post(AlarmClockEvent.EVENT_REQUEST)
                    showToast(if (delThenAdd) "更新成功" else "创建成功")
                    SettingLog.i(TAG, "createAlarm, result: ${JSON.toJSONString(response)}")
                    addAlarmClockSuccess()
                }

                override fun onError(code: String, message: String) {
                    SettingLog.e(TAG, "createAlarm, error code: ${code}\tmessage: $message")
                    showToast(if (delThenAdd) "更新失败" else "创建失败")
                }
            })
    }

    protected open fun addAlarmClockSuccess() {
        finish(Activity.RESULT_OK, null)
    }

    private fun performDelAndAddClock(runnable: Runnable) {
        performDeleteAlarm(
            false,
            object : SettingRepository.OnResponseListener<DeleteAlarmsResponse?> {
                override fun onSuccess(response: DeleteAlarmsResponse?) {
                    runnable.run()
                }

                override fun onError(code: String?, message: String?) {

                }
            })
    }

    /**
     * 更新闹钟
     *
     * @param scheduleType
     * @param daysOfWeek
     * @param hour
     * @param minute
     * @param musicId
     * @param remark
     * @param iconType
     */
    private fun performUpdateClock(
        scheduleType: String,
        daysOfWeek: IntArray?,
        hour: Int,
        minute: Int,
        musicId: Long,
        remark: String,
        iconType: Int,
    ) {
        if (alarm == null || alarm!!.alarmId == 0L) {
            return
        }

        // 调度信息
        val scheduleInfo =
            UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfo().setType(scheduleType)
        when (scheduleType) {
            KeyConstant.ALARM_SCHEDULE_ONCE -> scheduleInfo.setOnce(buildUpdateOnce(hour, minute))

            KeyConstant.ALARM_SCHEDULE_STATUTORY_WORKING_DAY -> scheduleInfo.setStatutoryWorkingDay(
                buildUpdateWorkingDay(hour, minute)
            )

            KeyConstant.ALARM_SCHEDULE_WEEKLY -> daysOfWeek?.let {
                scheduleInfo.setWeekly(buildUpdateWeekly(hour, minute, daysOfWeek))
            }
        }

        val music = getMusicInfoById(musicId)
        // 铃声信息
        val musicInfo = UpdateAlarmRequest.UpdateAlarmRequestPayloadMusicInfo().apply {
            setMusicId(music.musicId)
            setMusicType(music.musicType)
            setMusicName(music.musicName)
            setMusicTypeName(music.musicTypeName)
            setMusicUrl(music.musicUrl)
        }
        // 铃声音量
        val volume = 100
        SettingLog.w(
            TAG,
            "updateAlarm, alarmId: ${alarm?.alarmId}, " +
                    "scheduleInfo: ${JSON.toJSONString(scheduleInfo)}," +
                    " musicInfo: ${
                        JSON.toJSONString(musicInfo)
                    }, volume: $volume"
        )
        openApi.updateAlarm(
            alarm!!.alarmId,
            scheduleInfo,
            musicInfo,
            volume,
            object : SettingRepository.OnResponseListener<UpdateAlarmResponse> {
                override fun onSuccess(response: UpdateAlarmResponse) {

                    // 账号信息错误导致创建失败
                    if (null == response || null == response.body) {
                        showToast("更新成功")
                        return
                    }
                    if (200 != response.body.code) {
                        showToast(if (TextUtils.isEmpty(response.body.message)) "更新失败" else response.body.message)
                        return
                    }
                    if (alarm?.alarmDBInfo != null) {
                        alarmIconRemarkDatabaseHelper.update(alarm!!.alarmId, remark, iconType)
                    } else {
                        alarmIconRemarkDatabaseHelper.insert(alarm!!.alarmId, remark, iconType)
                    }
                    // 创建成功
//                    liveBus.post(AlarmClockEvent.EVENT_REQUEST)
                    showToast("更新成功")
                    SettingLog.i(TAG, "updateAlarm, result: ${JSON.toJSONString(response)}")
                    finish()
                }

                override fun onError(code: String, message: String) {
                    SettingLog.e(TAG, "createAlarm, error code: ${code}\tmessage: $message")
                }
            })
    }

    private fun getMusicInfoById(musicId: Long): ListMusicResponseBody.ListMusicResponseBodyResultModel {
        musicList?.find { it.musicId == musicId }?.let {
            return it
        }
        return ListMusicResponseBody.ListMusicResponseBodyResultModel().apply {
            setMusicId(1L)
            setMusicName("鼓声")
            setMusicType(15)
            setMusicTypeName("经典铃声")
            setMusicUrl("http://ailabsaicloudservice.alicdn.com/alarm_music/classics/drum0.mp3")
        }
    }

    private fun buildOnce(hour: Int, minute: Int): CreateAlarmRequestPayloadScheduleInfoOnce? {
        val today = getDate(hour, minute)
        return CreateAlarmRequestPayloadScheduleInfoOnce().setYear(today.year())
            .setMonth(today.monthBaseOne()).setDay(today.dayOfMonth()).setHour(hour)
            .setMinute(minute)
    }

    private fun buildWorkingDay(
        hour: Int, minute: Int
    ): CreateAlarmRequestPayloadScheduleInfoStatutoryWorkingDay? {
        return CreateAlarmRequestPayloadScheduleInfoStatutoryWorkingDay().setHour(hour)
            .setMinute(minute)
    }

    private fun buildWeekly(
        hour: Int, minute: Int, daysOfWeek: IntArray
    ): CreateAlarmRequest.CreateAlarmRequestPayloadScheduleInfoWeekly? {
        return CreateAlarmRequest.CreateAlarmRequestPayloadScheduleInfoWeekly()
            .setDaysOfWeek(daysOfWeek.toList())
            .setHour(hour).setMinute(minute)
    }

    private fun buildUpdateOnce(
        hour: Int,
        minute: Int
    ): UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoOnce? {
        val today = getDate(hour, minute)
        return UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoOnce().setYear(today.year())
            .setMonth(today.monthBaseOne()).setDay(today.dayOfMonth()).setHour(hour)
            .setMinute(minute)
    }

    private fun buildUpdateWorkingDay(
        hour: Int, minute: Int
    ): UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoStatutoryWorkingDay? {
        return UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoStatutoryWorkingDay()
            .setHour(hour)
            .setMinute(minute)
    }

    private fun buildUpdateWeekly(
        hour: Int, minute: Int, daysOfWeek: IntArray
    ): UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoWeekly? {
        return UpdateAlarmRequest.UpdateAlarmRequestPayloadScheduleInfoWeekly()
            .setDaysOfWeek(daysOfWeek.toList())
            .setHour(hour).setMinute(minute)
    }


    /**
     * 如果设置的时间小于当前,则设置为明天
     */
    private fun getDate(hour: Int, minute: Int): DateTime {
        val dateNow = Date()
        val nowHour: Int = DateUtil.hour(dateNow, true)
        val nowMinute: Int = DateUtil.minute(dateNow)
        if (nowHour > hour) {
            return DateUtil.tomorrow()
        }
        return if (nowHour == hour && nowMinute > minute) {
            DateUtil.tomorrow()
        } else DateUtil.date()
    }

    override fun onCreate() {
        super.onCreate()
        checkAndRefreshMusicList()
    }

    private fun checkAndRefreshMusicList() {
        val musicList = this.musicList
        if (musicList.isNullOrEmpty()) {
            openApi.getMusicList(
                15,
                "经典铃声",
                0,
                10,
                object : SettingRepository.OnResponseListener<ListMusicResponse> {
                    override fun onSuccess(response: ListMusicResponse) {
                        val result = response.body.getResult().model
                        result?.toMutableList()?.let { musicList ->
                            musicList.sortBy { it.musicId }
                            this@AddClockViewModel.musicList = musicList
                            pref.putMusicList(musicList)
                        }
                    }

                    override fun onError(code: String, message: String) {
                        SettingLog.e(
                            TAG, "getMusicList, error code: ${code}\tmessage: $message"
                        )
                    }
                })
        }
    }

    fun performDeleteAlarm() {
        performDeleteAlarm(true, null)
    }

    private fun performDeleteAlarm(
        notify: Boolean,
        callback: SettingRepository.OnResponseListener<DeleteAlarmsResponse?>?
    ) {
        if (alarm == null) {
            return
        }

        if (!checkNetWork()) return

        openApi.deleteAlarms(
            listOf(alarm!!.alarmId),
            object : SettingRepository.OnResponseListener<DeleteAlarmsResponse?> {
                override fun onSuccess(response: DeleteAlarmsResponse?) {
                    alarmIconRemarkDatabaseHelper.delete(alarm!!.alarmId)

                    if (notify) {
                        showToast("删除成功")
                        // 更新闹钟列表
                        liveBus.post(AlarmClockEvent.EVENT_REQUEST)
                        finish()
                    }

                    callback?.onSuccess(response)
                }

                override fun onError(code: String?, message: String?) {
                    SettingLog.e(TAG, "deleteAlarms, error code: ${code}\tmessage: $message")

                    if (notify) {
                        showToast("删除失败");
                    }
                    callback?.onError(code, message)
                }
            })
    }

    companion object {
        private const val TAG = KeyConstant.TAG_PREFIX + "AddClockViewModel"
    }


}