fade out enabled for set minutes and added volumen bar in ui
This commit is contained in:
@@ -7,7 +7,9 @@ import android.media.SoundPool
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
|
import android.widget.ProgressBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
class MainActivity : Activity() {
|
class MainActivity : Activity() {
|
||||||
|
|
||||||
@@ -18,6 +20,9 @@ class MainActivity : Activity() {
|
|||||||
private var isPlaying = false
|
private var isPlaying = false
|
||||||
private var remainingMinutes = 0
|
private var remainingMinutes = 0
|
||||||
private var countdownRunnable: Runnable? = null
|
private var countdownRunnable: Runnable? = null
|
||||||
|
private var fadeRunnable: Runnable? = null
|
||||||
|
private var totalMillis: Long = 0
|
||||||
|
private var startTime: Long = 0
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -25,6 +30,7 @@ class MainActivity : Activity() {
|
|||||||
|
|
||||||
val status = findViewById<TextView>(R.id.statusText)
|
val status = findViewById<TextView>(R.id.statusText)
|
||||||
val input = findViewById<EditText>(R.id.timerInput)
|
val input = findViewById<EditText>(R.id.timerInput)
|
||||||
|
val volumeBar = findViewById<ProgressBar>(R.id.volumeBar)
|
||||||
|
|
||||||
val attrs = AudioAttributes.Builder()
|
val attrs = AudioAttributes.Builder()
|
||||||
.setUsage(AudioAttributes.USAGE_MEDIA)
|
.setUsage(AudioAttributes.USAGE_MEDIA)
|
||||||
@@ -38,59 +44,92 @@ class MainActivity : Activity() {
|
|||||||
|
|
||||||
soundId = soundPool.load(this, R.raw.sound, 1)
|
soundId = soundPool.load(this, R.raw.sound, 1)
|
||||||
|
|
||||||
// Anfangszustand
|
updateUI(status, volumeBar, "Ready", Color.LTGRAY, 1f)
|
||||||
updateUI(status, "Ready", Color.LTGRAY)
|
|
||||||
|
|
||||||
// Das Statusfeld ist jetzt klickbar
|
|
||||||
status.setOnClickListener {
|
status.setOnClickListener {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
stopSound(status)
|
stopSound(status, volumeBar)
|
||||||
} else {
|
} else {
|
||||||
val min = input.text.toString().toIntOrNull() ?: 0
|
val min = input.text.toString().toIntOrNull() ?: 0
|
||||||
startSound(min, status)
|
startSound(min, status, volumeBar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startSound(minutes: Int, status: TextView) {
|
private fun startSound(minutes: Int, status: TextView, volumeBar: ProgressBar) {
|
||||||
stopSound(status)
|
stopSound(status, volumeBar)
|
||||||
streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f)
|
streamId = soundPool.play(soundId, 1f, 1f, 1, -1, 1f)
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
|
startTime = System.currentTimeMillis()
|
||||||
|
|
||||||
if (minutes > 0) {
|
if (minutes > 0) {
|
||||||
remainingMinutes = minutes
|
remainingMinutes = minutes
|
||||||
updateUI(status, "Runs for: $remainingMinutes min", Color.GREEN)
|
totalMillis = minutes * 60_000L
|
||||||
|
updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, 1f)
|
||||||
|
|
||||||
|
// Countdown jede Minute
|
||||||
countdownRunnable = object : Runnable {
|
countdownRunnable = object : Runnable {
|
||||||
override fun run() {
|
override fun run() {
|
||||||
remainingMinutes--
|
remainingMinutes--
|
||||||
if (remainingMinutes > 0) {
|
if (remainingMinutes > 0) {
|
||||||
updateUI(status, "Runs for: $remainingMinutes min", Color.GREEN)
|
updateUI(status, volumeBar, "Runs for: $remainingMinutes min", Color.GREEN, currentVolume())
|
||||||
handler.postDelayed(this, 60_000L)
|
handler.postDelayed(this, 60_000L)
|
||||||
} else {
|
} else {
|
||||||
stopSound(status)
|
stopSound(status, volumeBar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler.postDelayed(countdownRunnable!!, 60_000L)
|
handler.postDelayed(countdownRunnable!!, 60_000L)
|
||||||
|
|
||||||
|
// Exponentieller Fade-Out alle 200 ms
|
||||||
|
fadeRunnable = object : Runnable {
|
||||||
|
override fun run() {
|
||||||
|
if (!isPlaying) return
|
||||||
|
val elapsed = System.currentTimeMillis() - startTime
|
||||||
|
val progress = (elapsed.toFloat() / totalMillis).coerceIn(0f, 1f)
|
||||||
|
// exponentielles Absenken: volume = (1 - progress)^2
|
||||||
|
val volume = (1 - progress).pow(2)
|
||||||
|
soundPool.setVolume(streamId, volume, volume)
|
||||||
|
volumeBar.progress = (volume * 100).toInt()
|
||||||
|
if (progress < 1f) {
|
||||||
|
handler.postDelayed(this, 200L)
|
||||||
|
} else {
|
||||||
|
stopSound(status, volumeBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
handler.postDelayed(fadeRunnable!!, 200L)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
updateUI(status, "Runs: ∞", Color.GREEN)
|
// unendlich
|
||||||
|
updateUI(status, volumeBar, "Runs: ∞", Color.GREEN, 1f)
|
||||||
|
volumeBar.progress = 100
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun stopSound(status: TextView) {
|
private fun stopSound(status: TextView, volumeBar: ProgressBar) {
|
||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
soundPool.stop(streamId)
|
soundPool.stop(streamId)
|
||||||
isPlaying = false
|
isPlaying = false
|
||||||
}
|
}
|
||||||
remainingMinutes = 0
|
remainingMinutes = 0
|
||||||
handler.removeCallbacks(countdownRunnable ?: Runnable { })
|
handler.removeCallbacks(countdownRunnable ?: Runnable { })
|
||||||
updateUI(status, "Stopped", Color.RED)
|
handler.removeCallbacks(fadeRunnable ?: Runnable { })
|
||||||
|
updateUI(status, volumeBar, "Stopped", Color.RED, 0f)
|
||||||
|
volumeBar.progress = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateUI(view: TextView, text: String, color: Int) {
|
private fun updateUI(view: TextView, bar: ProgressBar, text: String, color: Int, volume: Float) {
|
||||||
view.text = text
|
view.text = text
|
||||||
view.setBackgroundColor(color)
|
view.setBackgroundColor(color)
|
||||||
view.setTextColor(Color.BLACK)
|
view.setTextColor(Color.BLACK)
|
||||||
|
bar.progress = (volume * 100).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun currentVolume(): Float {
|
||||||
|
val elapsed = System.currentTimeMillis() - startTime
|
||||||
|
val progress = (elapsed.toFloat() / totalMillis).coerceIn(0f, 1f)
|
||||||
|
return (1 - progress).pow(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
|||||||
@@ -37,4 +37,13 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"/>
|
android:layout_marginTop="20dp"/>
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/volumeBar"
|
||||||
|
style="@android:style/Widget.ProgressBar.Horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:max="100"
|
||||||
|
android:progress="100"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user