fretfret

learn the notes on a guitar from the comfort of your android phone
Log | Files | Refs | README | LICENSE

commit ac43dfd5c6141f9870ced8b8ecd64a1e2441309e
parent 5cd87823c76c28ceb052820079b78413a8f05412
Author: massi <mdsiboldi@gmail.com>
Date:   Thu, 11 Jul 2024 18:24:25 -0700

move stuff

Diffstat:
Mapp/src/main/java/com/example/fretboardtrainer/MainActivity.kt | 134+++++++++++++++++++++++++++++++++++++++++++------------------------------------
1 file changed, 73 insertions(+), 61 deletions(-)

diff --git a/app/src/main/java/com/example/fretboardtrainer/MainActivity.kt b/app/src/main/java/com/example/fretboardtrainer/MainActivity.kt @@ -60,58 +60,25 @@ import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch data object Constants { - val STRINGS = listOf("E", "B", "G", "D", "A", "E"); + val STRINGS = listOf("E", "B", "G", "D", "A", "E") val FRETS = listOf( "open", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12" - ); + ) val NOTES = listOf( "A", "A♯/B♭", "B", "C", "C♯/D♭", "D", "D♯/E♭", "E", "F", "F♯/G♭", "G", "G♯/A♭" ) const val FRETBOARD_HEIGHT = 200 -} - -val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings") - -fun encodeBoolList(l: List<Boolean>): ByteArray { - return ByteArray(l.size) { - when (l[it]) { - true -> 1.toByte() - else -> 0.toByte() - } - } -} - -fun decodeBoolList(arr: ByteArray): List<Boolean> { - return arr.toList().map { n -> - when (n) { - 1.toByte() -> true - else -> false - } - } -} - -fun weightForFret(fretIdx: Int): Float { - var weight = 24 - fretIdx * 1.0f - if (fretIdx == 0) { - weight /= 2 - } - return weight; -} - - -fun noteName(note: Note): String { - val startIdx = Constants.NOTES.indexOf(Constants.STRINGS[note.string]) - return Constants.NOTES[(startIdx + note.fret) % Constants.NOTES.size] + val STRING_KEY = byteArrayPreferencesKey("string_key") + val FRET_KEY = byteArrayPreferencesKey("fret_key") } data class Note( val string: Int, - val fret: Int + val fret: Int, ) -// TODO: persist string and fret settings across app launches. data class FretfretState( val showSettings: Boolean = false, val stringSettings: List<Boolean> = List(Constants.STRINGS.size) { true }, @@ -120,27 +87,54 @@ data class FretfretState( val lastNote: Note? = null, ) -val STRING_KEY = byteArrayPreferencesKey("string_key") -val FRET_KEY = byteArrayPreferencesKey("fret_key") +val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings") + + +fun weightForFret(fretIdx: Int): Float { + var weight = 24 - fretIdx * 1.0f + if (fretIdx == 0) { + weight /= 2 + } + return weight +} + class MainViewModel(application: Application) : AndroidViewModel(application) { private val _uiState = MutableStateFlow(FretfretState()) val uiState = _uiState.asStateFlow() + private fun encodeBoolList(l: List<Boolean>): ByteArray { + return ByteArray(l.size) { + when (l[it]) { + true -> 1.toByte() + else -> 0.toByte() + } + } + } + + private fun decodeBoolList(arr: ByteArray): List<Boolean> { + return arr.toList().map { n -> + when (n) { + 1.toByte() -> true + else -> false + } + } + } + init { viewModelScope.launch { try { _uiState.update { currentState -> currentState.copy( stringSettings = application.dataStore.data.map { prefs -> - when (prefs[STRING_KEY]) { - is ByteArray -> decodeBoolList(prefs[STRING_KEY]!!) + when (prefs[Constants.STRING_KEY]) { + is ByteArray -> decodeBoolList(prefs[Constants.STRING_KEY]!!) else -> List(Constants.STRINGS.size) { true } } }.first(), fretSettings = application.dataStore.data.map { prefs -> - when (prefs[FRET_KEY]) { - is ByteArray -> decodeBoolList(prefs[FRET_KEY]!!) + when (prefs[Constants.FRET_KEY]) { + is ByteArray -> decodeBoolList(prefs[Constants.FRET_KEY]!!) else -> List(Constants.FRETS.size) { true } } }.first(), @@ -190,19 +184,19 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { private fun pickNote(): Note { // find all true values in settings // randomly pick one of those - val notes = mutableSetOf<Note>(); + val notes = mutableSetOf<Note>() for (stringIdx in uiState.value.stringSettings.indices) { if (uiState.value.stringSettings[stringIdx]) { for (fretIdx in uiState.value.fretSettings.indices) { if (uiState.value.fretSettings[fretIdx]) { - notes.add(Note(fret = fretIdx, string = stringIdx)); + notes.add(Note(fret = fretIdx, string = stringIdx)) } } } } - var newNote = notes.random(); + var newNote = notes.random() while (newNote == uiState.value.note) { - newNote = notes.random(); + newNote = notes.random() } return newNote } @@ -218,8 +212,8 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { private suspend fun updateSettings() { getApplication<Application>().dataStore.edit { settings -> - settings[STRING_KEY] = encodeBoolList(uiState.value.stringSettings); - settings[FRET_KEY] = encodeBoolList(uiState.value.fretSettings); + settings[Constants.STRING_KEY] = encodeBoolList(uiState.value.stringSettings) + settings[Constants.FRET_KEY] = encodeBoolList(uiState.value.fretSettings) } } @@ -261,13 +255,23 @@ class MainActivity : ComponentActivity() { @Composable fun Fretfret(viewModel: MainViewModel = viewModel()) { val uiState by viewModel.uiState.collectAsState() + fun noteName(note: Note): String { + val startIdx = Constants.NOTES.indexOf(Constants.STRINGS[note.string]) + return Constants.NOTES[(startIdx + note.fret) % Constants.NOTES.size] + } FretboardTrainerTheme { Scaffold( modifier = Modifier.fillMaxSize(), topBar = { TopAppBar( modifier = Modifier.displayCutoutPadding(), - title = { Text("Fretfret") }, + title = { + if (uiState.showSettings) { + Text("Fretfret - Settings") + } else { + Text("Fretfret") + } + }, actions = { IconButton(onClick = { viewModel.toggleSettings() }) { Icon( @@ -290,7 +294,7 @@ fun Fretfret(viewModel: MainViewModel = viewModel()) { if (uiState.showSettings) { StringSettings( settings = uiState.stringSettings, - toggle = { n -> viewModel.toggleString(n) }); + toggle = { n -> viewModel.toggleString(n) }) } Column { Fretboard( @@ -316,12 +320,12 @@ fun Fretfret(viewModel: MainViewModel = viewModel()) { } } } - if (!uiState.showSettings) { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + if (!uiState.showSettings) { Row { if (uiState.lastNote != null) { Text("last answer: ") @@ -334,6 +338,14 @@ fun Fretfret(viewModel: MainViewModel = viewModel()) { ) { Text("next") } + } else { + Row {} + Button( + onClick = { viewModel.toggleSettings() }, + shape = RoundedCornerShape(5.dp) + ) { + Text("done") + } } } } @@ -365,8 +377,8 @@ fun Fretboard(modifier: Modifier = Modifier, note: Note?) { shadowElevation = 1.dp, shape = RoundedCornerShape(5.dp) ) { - val lineColor = MaterialTheme.colorScheme.onSurfaceVariant; - val dotColor = MaterialTheme.colorScheme.outline; + val lineColor = MaterialTheme.colorScheme.onSurfaceVariant + val dotColor = MaterialTheme.colorScheme.outline val openStringColor = dotColor Row( modifier = modifier @@ -374,7 +386,7 @@ fun Fretboard(modifier: Modifier = Modifier, note: Note?) { .height(Constants.FRETBOARD_HEIGHT.dp) ) { repeat(Constants.FRETS.size) { n: Int -> - val weight = weightForFret(n); + val weight = weightForFret(n) val nutWidth = 12.dp val fretWidth = if (n == 0) nutWidth else 6.dp Box(