diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4c2a923..795f887 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -30,7 +30,7 @@ android:parentActivityName="com.bartlomiejpluta.ttsserver.ui.main.MainActivity" /> diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt index ad100e6..b0cef44 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/sonos/worker/SonosWorker.kt @@ -7,7 +7,7 @@ import com.bartlomiejpluta.ttsserver.core.web.dto.SonosDTO import com.bartlomiejpluta.ttsserver.core.web.endpoint.Endpoint import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.service.state.ServiceState -import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey import com.vmichalak.sonoscontroller.Snapshot import com.vmichalak.sonoscontroller.SonosDevice import com.vmichalak.sonoscontroller.SonosDiscovery diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/tts/engine/TTSEngine.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/tts/engine/TTSEngine.kt index c59c1b9..4fb5d96 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/tts/engine/TTSEngine.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/tts/engine/TTSEngine.kt @@ -14,7 +14,7 @@ import com.bartlomiejpluta.ttsserver.core.tts.model.TTSStream import com.bartlomiejpluta.ttsserver.core.tts.status.TTSStatus import com.bartlomiejpluta.ttsserver.core.tts.status.TTSStatusHolder import com.bartlomiejpluta.ttsserver.core.util.AudioConverter -import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey import java.io.BufferedInputStream import java.io.File import java.io.FileInputStream diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/util/NetworkUtil.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/util/NetworkUtil.kt index 7f7b373..b089403 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/util/NetworkUtil.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/util/NetworkUtil.kt @@ -4,7 +4,7 @@ import android.content.Context import android.content.Context.WIFI_SERVICE import android.content.SharedPreferences import android.net.wifi.WifiManager -import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey import java.net.InetAddress diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt index 85e682f..56d1b02 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServer.kt @@ -18,13 +18,15 @@ import com.bartlomiejpluta.ttsserver.core.web.exception.WebException import com.bartlomiejpluta.ttsserver.core.web.mime.MimeType import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.service.state.ServiceState -import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.model.TimeRange import fi.iki.elonen.NanoHTTPD import fi.iki.elonen.NanoHTTPD.Response.Status.* import org.json.JSONObject import java.io.BufferedInputStream import java.io.File import java.io.FileInputStream +import java.util.* class WebServer( @@ -34,6 +36,20 @@ class WebServer( private val tts: TTSEngine, private val sonos: SonosQueue ) : NanoHTTPD(port) { + private val speakersSilenceSchedulerEnabled: Boolean + get() = preferences.getBoolean(PreferenceKey.ENABLE_SPEAKERS_SILENCE_SCHEDULER, false) + + private val sonosSilenceSchedulerEnabled: Boolean + get() = preferences.getBoolean(PreferenceKey.ENABLE_SONOS_SILENCE_SCHEDULER, false) + + private val speakersSilenceSchedule: TimeRange + get() = preferences.getString(PreferenceKey.SPEAKERS_SILENCE_SCHEDULE, "")!! + .let { TimeRange.parse(it) } + + private val sonosSilenceSchedule: TimeRange + get() = preferences.getString(PreferenceKey.SONOS_SILENCE_SCHEDULE, "")!! + .let { TimeRange.parse(it) } + override fun serve(session: IHTTPSession?): Response { try { assertThatTTSIsReady() @@ -97,6 +113,10 @@ class WebServer( throw WebException(BAD_REQUEST, "Only JSON data is accepted") } + if (speakersSilenceSchedulerEnabled && speakersSilenceSchedule.inRange(Calendar.getInstance())) { + return newFixedLengthResponse(NO_CONTENT, MIME_JSON, "") + } + val dto = extractBody(session) { BaseDTO(it) } tts.performTTS(dto.text, dto.language) @@ -142,6 +162,10 @@ class WebServer( throw WebException(BAD_REQUEST, "Only JSON data is accepted") } + if (sonosSilenceSchedulerEnabled && sonosSilenceSchedule.inRange(Calendar.getInstance())) { + return newFixedLengthResponse(NO_CONTENT, MIME_JSON, "") + } + val dto = extractBody(session) { SonosDTO(it) } sonos.push(dto) diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServerFactory.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServerFactory.kt index f7aaa51..055cb3b 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServerFactory.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/core/web/server/WebServerFactory.kt @@ -4,7 +4,7 @@ import android.content.Context import android.content.SharedPreferences import com.bartlomiejpluta.ttsserver.core.sonos.queue.SonosQueue import com.bartlomiejpluta.ttsserver.core.tts.engine.TTSEngine -import com.bartlomiejpluta.ttsserver.ui.preference.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey class WebServerFactory( private val preferences: SharedPreferences, diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/AndroidModule.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/AndroidModule.kt index ca06bf4..bb3748a 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/AndroidModule.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/di/module/AndroidModule.kt @@ -3,7 +3,7 @@ package com.bartlomiejpluta.ttsserver.di.module import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.ui.help.HelpActivity import com.bartlomiejpluta.ttsserver.ui.main.MainActivity -import com.bartlomiejpluta.ttsserver.ui.preference.PreferencesActivity +import com.bartlomiejpluta.ttsserver.ui.preference.component.PreferencesActivity import dagger.Module import dagger.android.ContributesAndroidInjector diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/main/MainActivity.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/main/MainActivity.kt index fbed55c..c16b797 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/main/MainActivity.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/main/MainActivity.kt @@ -14,7 +14,7 @@ import com.bartlomiejpluta.ttsserver.core.util.NetworkUtil import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.service.state.ServiceState import com.bartlomiejpluta.ttsserver.ui.help.HelpActivity -import com.bartlomiejpluta.ttsserver.ui.preference.PreferencesActivity +import com.bartlomiejpluta.ttsserver.ui.preference.component.PreferencesActivity import dagger.android.support.DaggerAppCompatActivity import javax.inject.Inject diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesActivity.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesActivity.kt similarity index 75% rename from app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesActivity.kt rename to app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesActivity.kt index 93f46c6..44128fd 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesActivity.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesActivity.kt @@ -1,4 +1,4 @@ -package com.bartlomiejpluta.ttsserver.ui.preference +package com.bartlomiejpluta.ttsserver.ui.preference.component import android.os.Bundle import androidx.appcompat.app.AppCompatActivity @@ -11,7 +11,9 @@ class PreferencesActivity : AppCompatActivity() { setContentView(R.layout.activity_preferences) supportFragmentManager .beginTransaction() - .replace(R.id.preferences, PreferencesFragment()) + .replace(R.id.preferences, + PreferencesFragment() + ) .commit() supportActionBar?.setDisplayHomeAsUpEnabled(true) } diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesFragment.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesFragment.kt similarity index 57% rename from app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesFragment.kt rename to app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesFragment.kt index 754e0cb..055423a 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/PreferencesFragment.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/component/PreferencesFragment.kt @@ -1,5 +1,6 @@ -package com.bartlomiejpluta.ttsserver.ui.preference +package com.bartlomiejpluta.ttsserver.ui.preference.component +import android.app.TimePickerDialog import android.content.BroadcastReceiver import android.content.Context import android.content.Intent @@ -15,6 +16,9 @@ import com.bartlomiejpluta.R import com.bartlomiejpluta.ttsserver.core.web.mime.MimeType import com.bartlomiejpluta.ttsserver.service.foreground.ForegroundService import com.bartlomiejpluta.ttsserver.service.state.ServiceState +import com.bartlomiejpluta.ttsserver.ui.preference.model.TimeRange +import com.bartlomiejpluta.ttsserver.ui.preference.key.PreferenceKey +import com.bartlomiejpluta.ttsserver.ui.preference.custom.IntEditTextPreference class PreferencesFragment : PreferenceFragmentCompat() { @@ -25,6 +29,8 @@ class PreferencesFragment : PreferenceFragmentCompat() { private lateinit var httpDebugPreference: SwitchPreference private lateinit var enableGongPreference: SwitchPreference private lateinit var ttsEnginePreference: Preference + private lateinit var enableSonosSilenceScheduler: SwitchPreference + private lateinit var enableSpeakersSilenceScheduler: SwitchPreference private lateinit var clearSonosCachePreference: Preference private val receiver = object : BroadcastReceiver() { @@ -75,6 +81,82 @@ class PreferencesFragment : PreferenceFragmentCompat() { startActivity(Intent(ANDROID_TTS_SETTINGS)) true } + enableSpeakersSilenceScheduler = findPreference(PreferenceKey.ENABLE_SPEAKERS_SILENCE_SCHEDULER)!! + enableSpeakersSilenceScheduler.setOnPreferenceClickListener { preference -> + if(!enableSpeakersSilenceScheduler.isChecked) { + return@setOnPreferenceClickListener true + } + enableSpeakersSilenceScheduler.isChecked = false + + val schedule = preference + .sharedPreferences + .getString( + PreferenceKey.SPEAKERS_SILENCE_SCHEDULE, + DEFAULT_SCHEDULE + )!! + .let { + TimeRange.parse( + it + ) + } + + TimePickerDialog(context, { _, newBeginHour, newBeginMinute -> + TimePickerDialog(context, { _, newEndHour, newEndMinute -> + preference.sharedPreferences.edit()?.let { editor -> + val newSchedule = + TimeRange( + newBeginHour, + newBeginMinute, + newEndHour, + newEndMinute + ) + editor.putString(PreferenceKey.SPEAKERS_SILENCE_SCHEDULE, newSchedule.toString()) + editor.apply() + enableSpeakersSilenceScheduler.isChecked = true + } + }, schedule.endHour, schedule.endMinute, true).show() + }, schedule.beginHour, schedule.beginMinute, true).show() + + true + } + enableSonosSilenceScheduler = findPreference(PreferenceKey.ENABLE_SONOS_SILENCE_SCHEDULER)!! + enableSonosSilenceScheduler.setOnPreferenceClickListener { preference -> + if(!enableSonosSilenceScheduler.isChecked) { + return@setOnPreferenceClickListener true + } + enableSonosSilenceScheduler.isChecked = false + + val schedule = preference + .sharedPreferences + .getString( + PreferenceKey.SONOS_SILENCE_SCHEDULE, + DEFAULT_SCHEDULE + )!! + .let { + TimeRange.parse( + it + ) + } + + TimePickerDialog(context, { _, newBeginHour, newBeginMinute -> + TimePickerDialog(context, { _, newEndHour, newEndMinute -> + preference.sharedPreferences.edit()?.let { editor -> + val newSchedule = + TimeRange( + newBeginHour, + newBeginMinute, + newEndHour, + newEndMinute + ) + editor.putString(PreferenceKey.SONOS_SILENCE_SCHEDULE, newSchedule.toString()) + editor.apply() + enableSonosSilenceScheduler.isChecked = true + } + }, schedule.endHour, schedule.endMinute, true).show() + }, schedule.beginHour, schedule.beginMinute, true).show() + + true + } clearSonosCachePreference = findPreference(PreferenceKey.INVALIDATE_SONOS_CACHE)!! clearSonosCachePreference.setOnPreferenceClickListener { context?.cacheDir?.listFiles()?.forEach { it.delete() } @@ -94,7 +176,9 @@ class PreferencesFragment : PreferenceFragmentCompat() { .apply { type = MimeType.WAV.mimeType } .let { Intent.createChooser(it, getString(R.string.preference_gong_picker_prompt)) } - startActivityForResult(intent, PICKFILE_RESULT_CODE) + startActivityForResult(intent, + PICKFILE_RESULT_CODE + ) } } @@ -118,5 +202,6 @@ class PreferencesFragment : PreferenceFragmentCompat() { companion object { private const val ANDROID_TTS_SETTINGS = "com.android.settings.TTS_SETTINGS" private const val PICKFILE_RESULT_CODE = 1 + private val DEFAULT_SCHEDULE = "22:00-07:00" } } \ No newline at end of file diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/IntEditTextPreference.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/custom/IntEditTextPreference.kt similarity index 93% rename from app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/IntEditTextPreference.kt rename to app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/custom/IntEditTextPreference.kt index 76d46bf..0af2594 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/IntEditTextPreference.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/custom/IntEditTextPreference.kt @@ -1,4 +1,4 @@ -package com.bartlomiejpluta.ttsserver.ui.preference +package com.bartlomiejpluta.ttsserver.ui.preference.custom import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/Preference.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/key/Preference.kt similarity index 57% rename from app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/Preference.kt rename to app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/key/Preference.kt index da588c9..d3c9b7e 100644 --- a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/Preference.kt +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/key/Preference.kt @@ -1,4 +1,4 @@ -package com.bartlomiejpluta.ttsserver.ui.preference +package com.bartlomiejpluta.ttsserver.ui.preference.key object PreferenceKey { @@ -10,5 +10,9 @@ object PreferenceKey { const val ENABLE_GONG = "preference_enable_gong" const val GONG = "preference_gong" const val TTS = "preference_tts" + const val ENABLE_SPEAKERS_SILENCE_SCHEDULER = "preference_enable_speakers_silence_scheduler" + const val SPEAKERS_SILENCE_SCHEDULE = "preference_speakers_silence_schedule" + const val ENABLE_SONOS_SILENCE_SCHEDULER = "preference_enable_sonos_silence_scheduler" + const val SONOS_SILENCE_SCHEDULE = "preference_sonos_silence_schedule" const val INVALIDATE_SONOS_CACHE = "preference_invalidate_sonos_cache" } \ No newline at end of file diff --git a/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/model/TimeRange.kt b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/model/TimeRange.kt new file mode 100644 index 0000000..855c6b4 --- /dev/null +++ b/app/src/main/java/com/bartlomiejpluta/ttsserver/ui/preference/model/TimeRange.kt @@ -0,0 +1,42 @@ +package com.bartlomiejpluta.ttsserver.ui.preference.model + +import java.util.* + +data class TimeRange(val beginHour: Int, val beginMinute: Int, val endHour: Int, val endMinute: Int) { + private val begin: Int + get() = beginHour * 60 + beginMinute + + private val end: Int + get() = endHour * 60 + endMinute + + fun inRange(calendar: Calendar): Boolean { + val current = calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE) + return when { + begin <= end -> current in begin..end + else -> !(current in end..begin) + } + } + + override fun toString() = "$beginHour:$beginMinute-$endHour:$endMinute" + + companion object { + fun parse(range: String): TimeRange { + val (beginTime, endTime) = range.splitAndMap("-") { it } + val (beginHour, beginMinute) = beginTime.splitAndMap(":") { it.toInt() } + val (endHour, endMinute) = endTime.splitAndMap(":") { it.toInt() } + return TimeRange( + beginHour, + beginMinute, + endHour, + endMinute + ) + } + + private fun String.splitAndMap(delimiter: String, mapper: (String) -> T): List { + return this.split(delimiter) + .map { mapper(it) } + .takeIf { it.size == 2 } + ?: throw IllegalArgumentException("Expected format: HH:mm-HH:mm") + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0964b6b..68d1fc5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -30,11 +30,16 @@ Enable gong Go to platform\'s TTS engine settings and adjust its parameters TTS engine settings + Determine a time range when /say endpoint should be disabled + Enable silence scheduler + Determine a time range when /sonos endpoint should be disabled + Enable silence scheduler Clear application cache directory from already generated Sonos TTS data for given sentences. You typically want to do it when you change the TTS engine\'s voice settings. Invalidate Sonos cache Server Features TTS engine + Speakers Sonos Sonos cache has been invalidated diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 0e05302..0fab131 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -2,7 +2,7 @@ - + + + + + +