From fb44396f4623d3c9ce5ce69c1f15ade64c207f0c Mon Sep 17 00:00:00 2001 From: Emma Vandewalle Date: Sun, 1 Sep 2024 11:17:44 +0000 Subject: [PATCH] feat: settings popup implemented --- .../settings/SetMaxSavedFilesUseCase.kt | 17 + .../settings/SetMaxSavedProjectsUseCase.kt | 18 + .../re/writand/screens/editor/EditorScreen.kt | 2 + .../editor/bottom/BottomEditorBarViewModel.kt | 1 - .../editor/top/TopEditorBarViewModel.kt | 1 - .../settings/EditorSettingsViewModel.kt | 171 +++++++++ .../writand/screens/settings/SettingsPopup.kt | 349 ++++++++++++++++++ .../screens/welcome/WelcomeStartScreen.kt | 2 +- .../screens/welcome/WelcomeTOSScreen.kt | 2 +- ...baseline_keyboard_double_arrow_left_24.xml | 7 + ...aseline_keyboard_double_arrow_right_24.xml | 7 + 11 files changed, 573 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/be/re/writand/domain/settings/SetMaxSavedFilesUseCase.kt create mode 100644 app/src/main/java/be/re/writand/domain/settings/SetMaxSavedProjectsUseCase.kt create mode 100644 app/src/main/java/be/re/writand/screens/settings/EditorSettingsViewModel.kt create mode 100644 app/src/main/java/be/re/writand/screens/settings/SettingsPopup.kt create mode 100644 app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml create mode 100644 app/src/main/res/drawable/baseline_keyboard_double_arrow_right_24.xml diff --git a/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedFilesUseCase.kt b/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedFilesUseCase.kt new file mode 100644 index 0000000..de7e1a8 --- /dev/null +++ b/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedFilesUseCase.kt @@ -0,0 +1,17 @@ +package be.re.writand.domain.settings +import be.re.writand.data.repos.settings.UserSettingsRepository +import javax.inject.Inject + +/** + * Use-case to change the amount of open/saved files to have in the app, this changes the settings. + * @param[userSettingsRepository] repository to change the UserSettings when valid input is given. + */ +class SetMaxSavedFilesUseCase @Inject constructor( + private val userSettingsRepository: UserSettingsRepository +) { + + suspend operator fun invoke(maxSavedFiles: Int) { + userSettingsRepository.setMaxSavedFiles(maxSavedFiles) + } + +} diff --git a/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedProjectsUseCase.kt b/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedProjectsUseCase.kt new file mode 100644 index 0000000..99bd895 --- /dev/null +++ b/app/src/main/java/be/re/writand/domain/settings/SetMaxSavedProjectsUseCase.kt @@ -0,0 +1,18 @@ +package be.re.writand.domain.settings + +import be.re.writand.data.repos.settings.UserSettingsRepository +import javax.inject.Inject + +/** + * Use-case to change the amount of saved projects to have in the app, this changes the settings. + * @param[userSettingsRepository] repository to change the UserSettings when valid input is given. + */ +class SetMaxSavedProjectsUseCase @Inject constructor( + private val userSettingsRepository: UserSettingsRepository +) { + + suspend operator fun invoke(maxSavedProjects: Int) { + userSettingsRepository.setMaxSavedProjects(maxSavedProjects) + } + +} diff --git a/app/src/main/java/be/re/writand/screens/editor/EditorScreen.kt b/app/src/main/java/be/re/writand/screens/editor/EditorScreen.kt index 6667b42..873c84a 100644 --- a/app/src/main/java/be/re/writand/screens/editor/EditorScreen.kt +++ b/app/src/main/java/be/re/writand/screens/editor/EditorScreen.kt @@ -9,6 +9,7 @@ import androidx.navigation.NavHostController import be.re.writand.screens.editor.bottom.BottomEditorBar import be.re.writand.screens.editor.editorspace.EditorSpace import be.re.writand.screens.editor.top.TopEditorBar +import be.re.writand.screens.settings.SettingsPopup /** * Composable presenting the full screen when IDE is open. This holds all the different composables @@ -30,6 +31,7 @@ fun EditorScreen( Row(modifier = Modifier.padding(it)) { // TODO: show filetree when open EditorSpace() + SettingsPopup() } } diff --git a/app/src/main/java/be/re/writand/screens/editor/bottom/BottomEditorBarViewModel.kt b/app/src/main/java/be/re/writand/screens/editor/bottom/BottomEditorBarViewModel.kt index de6c1e2..023fd7e 100644 --- a/app/src/main/java/be/re/writand/screens/editor/bottom/BottomEditorBarViewModel.kt +++ b/app/src/main/java/be/re/writand/screens/editor/bottom/BottomEditorBarViewModel.kt @@ -1,7 +1,6 @@ package be.re.writand.screens.editor.bottom import be.re.writand.screens.WViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/be/re/writand/screens/editor/top/TopEditorBarViewModel.kt b/app/src/main/java/be/re/writand/screens/editor/top/TopEditorBarViewModel.kt index 5b48e19..eb332c9 100644 --- a/app/src/main/java/be/re/writand/screens/editor/top/TopEditorBarViewModel.kt +++ b/app/src/main/java/be/re/writand/screens/editor/top/TopEditorBarViewModel.kt @@ -1,7 +1,6 @@ package be.re.writand.screens.editor.top import be.re.writand.screens.WViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow diff --git a/app/src/main/java/be/re/writand/screens/settings/EditorSettingsViewModel.kt b/app/src/main/java/be/re/writand/screens/settings/EditorSettingsViewModel.kt new file mode 100644 index 0000000..8405553 --- /dev/null +++ b/app/src/main/java/be/re/writand/screens/settings/EditorSettingsViewModel.kt @@ -0,0 +1,171 @@ +package be.re.writand.screens.settings + +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import be.re.writand.data.local.models.UserSettings +import be.re.writand.data.repos.settings.UserSettingsRepository +import be.re.writand.domain.settings.SetFontSizeSettingsUseCase +import be.re.writand.domain.settings.SetLanguageSettingsUseCase +import be.re.writand.domain.settings.SetMaxSavedFilesUseCase +import be.re.writand.domain.settings.SetMaxSavedProjectsUseCase +import be.re.writand.domain.settings.SetThemeSettingsUseCase +import be.re.writand.screens.WViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import javax.inject.Inject + +/** + * View model to be used by SettingsPopup handling all the different changes in the settings and ui. + * @param[userSettingsRepository] repository that holds the settings of the current user. + * @param[setLanguage] use case to change the language. + * @param[setTheme] use case to change the theme. + * @param[setFontSize] use case to change the font size used in the different text fields. + * @param[setMaxSavedProjects] use case to change the max amount of projects kept in memory. + * @param[setMaxSavedFiles] use case to change the max amount of open files in the editor. + */ +@HiltViewModel +class EditorSettingsViewModel @Inject constructor( + private val userSettingsRepository: UserSettingsRepository, + private val setLanguage: SetLanguageSettingsUseCase, + private val setTheme: SetThemeSettingsUseCase, + private val setFontSize: SetFontSizeSettingsUseCase, + private val setMaxSavedProjects: SetMaxSavedProjectsUseCase, + private val setMaxSavedFiles: SetMaxSavedFilesUseCase +) : WViewModel() { + + private val _settings = MutableStateFlow(null) + val settings: StateFlow = _settings + + val changedAppearance = mutableStateOf(false) + val changedAdvanced = mutableStateOf(false) + + val textFieldFontSize = mutableStateOf(_settings.value?.fontSize.toString()) + val language = mutableStateOf(_settings.value?.userLanguage.toString()) + val theme = mutableStateOf(_settings.value?.userTheme.toString()) + + val amountSavedProjects = mutableIntStateOf(_settings.value?.maxSavedProjects?: 1) + val amountSavedFiles = mutableIntStateOf(_settings.value?.maxSavedFiles?: 1) + + init { + launchCatching { + userSettingsRepository.userSettings.collect { settings -> + _settings.value = settings + textFieldFontSize.value = settings.fontSize.toString() + language.value = settings.userLanguage.toString() + theme.value = settings.userTheme.toString() + amountSavedProjects.intValue = settings.maxSavedProjects + amountSavedFiles.intValue = settings.maxSavedFiles + } + } + } + + fun onTextFieldFontSizeChange(newValue: String) { + textFieldFontSize.value = newValue + if (!changedAppearance.value && newValue != _settings.value?.fontSize.toString()) { + changedAppearance.value = true + } + } + + fun onLanguageSelect(newLanguage: String) { + language.value = newLanguage + if (!changedAppearance.value && newLanguage != _settings.value?.userLanguage.toString()) { + changedAppearance.value = true + } + } + + fun onThemeSelect(newTheme: String) { + theme.value = newTheme + if (!changedAppearance.value && newTheme != _settings.value?.userTheme.toString()) { + changedAppearance.value = true + } + } + + fun onApplyAppearance() { + launchCatching { + changedAppearance.value = false + + setLanguage(language.value) + setTheme(theme.value) + + val errorFontSize: NumberFormatException? = setFontSize(textFieldFontSize.value) + errorFontSize.let { + // reset the text field to its old value + textFieldFontSize.value = _settings.value?.fontSize.toString() + } + } + } + + fun onApplyAdvanced() { + launchCatching { + changedAdvanced.value = false + + setMaxSavedProjects(amountSavedProjects.intValue) + setMaxSavedFiles(amountSavedFiles.intValue) + } + } + + fun onCancelAppearance() { + changedAppearance.value = false + textFieldFontSize.value = _settings.value?.fontSize.toString() + language.value = _settings.value?.userLanguage.toString() + theme.value = _settings.value?.userTheme.toString() + } + + fun onCancelAdvanced() { + changedAdvanced.value = false + if (_settings.value != null) { + amountSavedProjects.intValue = _settings.value?.maxSavedProjects!! + amountSavedFiles.intValue = _settings.value?.maxSavedFiles!! + } + } + + fun onMinValueProjects() { + changedAdvanced.value = true + amountSavedProjects.intValue = 0 + } + + fun onDecrementProjects() { + if (amountSavedProjects.intValue > 1) { + changedAdvanced.value = true + amountSavedProjects.intValue = amountSavedProjects.intValue.dec() + } + } + + fun onIncrementProjects() { + if (amountSavedProjects.intValue < 100) { + changedAdvanced.value = true + amountSavedProjects.intValue = amountSavedProjects.intValue.inc() + } + } + + fun onMaxValueProjects() { + changedAdvanced.value = true + amountSavedProjects.intValue = 25 + } + + fun onMinValueFiles() { + changedAdvanced.value = true + amountSavedFiles.intValue = 1 + } + + fun onDecrementFiles() { + if (amountSavedFiles.intValue > 1) { + changedAdvanced.value = true + amountSavedFiles.intValue = amountSavedFiles.intValue.dec() + } + } + + fun onIncrementFiles() { + if (amountSavedFiles.intValue < 100) { + changedAdvanced.value = true + amountSavedFiles.intValue = amountSavedFiles.intValue.inc() + } + } + + fun onMaxValueFiles() { + changedAdvanced.value = true + amountSavedFiles.intValue = 50 + } + +} \ No newline at end of file diff --git a/app/src/main/java/be/re/writand/screens/settings/SettingsPopup.kt b/app/src/main/java/be/re/writand/screens/settings/SettingsPopup.kt new file mode 100644 index 0000000..e596a1c --- /dev/null +++ b/app/src/main/java/be/re/writand/screens/settings/SettingsPopup.kt @@ -0,0 +1,349 @@ +package be.re.writand.screens.settings + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft +import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Button +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationDrawerItem +import androidx.compose.material3.PermanentDrawerSheet +import androidx.compose.material3.PermanentNavigationDrawer +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import androidx.hilt.navigation.compose.hiltViewModel +import be.re.writand.R +import be.re.writand.data.local.models.UserLanguage +import be.re.writand.data.local.models.UserTheme +import be.re.writand.screens.components.WButton +import be.re.writand.screens.components.WLabelAndTextField +import be.re.writand.screens.components.WRadioButtonsSelectorRowWise +import be.re.writand.screens.components.WText + +/** + * Popup screen to handle let the user change the settings once the welcome part of the app has + * gone through. This should involve all the settings possible to be changed. + * @param[vM] view model corresponding to this screen. + */ +@Composable +fun SettingsPopup( + vM: EditorSettingsViewModel = hiltViewModel() +) { + val openDialog = remember { mutableStateOf(false) } + val buttonTitle = remember { + mutableStateOf("Show Pop Up") + } + + // keep these variables for settings at the top level, so it remembers the state even though + // settings were temporarily closed + val items = listOf("Appearance", "Advanced") + val selectedItem = remember { + mutableStateOf(items[0]) + } + + Button( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp), + onClick = { + openDialog.value = !openDialog.value + if (!openDialog.value) { + buttonTitle.value = "Show Pop Up" + } + } + ) { + Text(text = buttonTitle.value, modifier = Modifier.padding(3.dp)) + } + + if (openDialog.value) { + buttonTitle.value = "Hide Pop Up" + Dialog( + onDismissRequest = { openDialog.value = false }, + properties = DialogProperties(usePlatformDefaultWidth = false) + ) { + Box( + modifier = Modifier + .height(600.dp) + .width(800.dp), + contentAlignment = Alignment.Center + ) { + Scaffold( + modifier = Modifier + .fillMaxSize() + .clip(shape = RoundedCornerShape(10.dp)) + .border( + width = 1.dp, + color = MaterialTheme.colorScheme.tertiary, + shape = RoundedCornerShape(10.dp) + ), + topBar = { + Row( + modifier = Modifier + .fillMaxWidth() + .background(color = MaterialTheme.colorScheme.tertiary), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween + ) { + // spacer to divide the row in 3 parts and spread them over the width + Spacer(modifier = Modifier.size(0.dp)) + + WText(text = "Settings", fontSize = 25.sp) + + IconButton( + onClick = { openDialog.value = false }, + modifier = Modifier.padding(start = 10.dp), + ) { + Icon( + modifier = Modifier.size(35.dp), + imageVector = Icons.Default.Close, + contentDescription = "Close" + ) + } + } + } + ) { + PermanentNavigationDrawer( + modifier = Modifier + .padding(it) + .fillMaxSize(), + drawerContent = { + PermanentDrawerSheet( + modifier = Modifier + .padding(top = 10.dp) + .width(240.dp) + ) { + Column(modifier = Modifier.verticalScroll(rememberScrollState())) { + items.forEach { item -> + NavigationDrawerItem( + label = { Text(text = item) }, + selected = item == selectedItem.value, + onClick = { selectedItem.value = item }, + modifier = Modifier.padding(horizontal = 12.dp) + ) + } + } + } + }) { + // cancel the last changes to the other tab first to the ones not + // applied yet, otherwise it looks like there are applied + if (selectedItem.value == items[0]) { + if (vM.changedAdvanced.value) { + vM.onCancelAdvanced() + } + AppearanceSettings(editorSettingsVM = vM) + } else { + if (vM.changedAppearance.value) { + vM.onCancelAppearance() + } + AdvancedSettings(editorSettingsVM = vM) + } + } + } + } + } + } +} + +@Composable +fun AppearanceSettings( + editorSettingsVM: EditorSettingsViewModel +) { + val languageOptions = UserLanguage.entries.map { entry -> entry.toString() } + val themeOptions = UserTheme.entries.map { entry -> entry.toString() } + + Scaffold( + bottomBar = { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.End + ) { + WButton( + modifier = Modifier.padding(end = 10.dp), + text = "Cancel", + onClick = editorSettingsVM::onCancelAppearance, + enabled = editorSettingsVM.changedAppearance.value + ) + WButton( + text = "Apply", + onClick = editorSettingsVM::onApplyAppearance, + enabled = editorSettingsVM.changedAppearance.value + ) + } + } + ) { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = MaterialTheme.colorScheme.secondary) + .padding(it) + .padding(start = 16.dp) + ) { + + WText(modifier = Modifier.padding(top = 25.dp), text = "Language", fontSize = 25.sp) + WRadioButtonsSelectorRowWise( + enable = true, + textTitle = "", + options = languageOptions, + selectedOption = editorSettingsVM.language.value, + onOptionSelected = editorSettingsVM::onLanguageSelect, + labelSize = 0.dp + ) + + WText(modifier = Modifier.padding(top = 25.dp), text = "Theme", fontSize = 25.sp) + WRadioButtonsSelectorRowWise( + enable = true, + textTitle = "", + options = themeOptions, + selectedOption = editorSettingsVM.theme.value, + onOptionSelected = editorSettingsVM::onThemeSelect, + labelSize = 0.dp + ) + + WText(modifier = Modifier.padding(top = 25.dp), text = "Font", fontSize = 25.sp) + WLabelAndTextField( + title = "Fontsize", + value = editorSettingsVM.textFieldFontSize.value, + fullSize = 200.dp, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal), + onTextChange = editorSettingsVM::onTextFieldFontSizeChange + ) + } + } +} + +@Composable +fun AdvancedSettings( + editorSettingsVM: EditorSettingsViewModel +) { + Scaffold( + bottomBar = { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(10.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.End + ) { + WButton( + modifier = Modifier.padding(end = 10.dp), + text = "Cancel", + onClick = editorSettingsVM::onCancelAdvanced, + enabled = editorSettingsVM.changedAdvanced.value + ) + WButton( + text = "Apply", + onClick = editorSettingsVM::onApplyAdvanced, + enabled = editorSettingsVM.changedAdvanced.value + ) + } + } + ) { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = MaterialTheme.colorScheme.secondary) + .padding(it) + .padding(start = 16.dp) + ) { + WText(text = "History", modifier = Modifier.padding(top = 25.dp), fontSize = 25.sp) + ArrowAmountChooser( + text = "Max amount of recently opened projects:", + amountInt = editorSettingsVM.amountSavedProjects.intValue, + onMinValue = editorSettingsVM::onMinValueProjects, + onDecrementValue = editorSettingsVM::onDecrementProjects, + onIncrementValue = editorSettingsVM::onIncrementProjects, + onMaxValue = editorSettingsVM::onMaxValueProjects + ) + WText(text = "IDE tabs", modifier = Modifier.padding(top = 25.dp), fontSize = 25.sp) + ArrowAmountChooser( + text = "Max amount of opened files:", + amountInt = editorSettingsVM.amountSavedFiles.intValue, + onMinValue = editorSettingsVM::onMinValueFiles, + onDecrementValue = editorSettingsVM::onDecrementFiles, + onIncrementValue = editorSettingsVM::onIncrementFiles, + onMaxValue = editorSettingsVM::onMaxValueFiles + ) + // LATER ON: add a checkbox whether they want to automatically start the last project + // in history or always get the project picker when opening the app + } + } +} + +@Composable +fun ArrowAmountChooser( + text: String, + amountInt: Int, + onMinValue: () -> Unit, + onDecrementValue: () -> Unit, + onIncrementValue: () -> Unit, + onMaxValue: () -> Unit +) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + WText(text = text) + IconButton(onClick = onMinValue) { + Icon( + modifier = Modifier.size(25.dp), + painter = painterResource(R.drawable.baseline_keyboard_double_arrow_left_24), + contentDescription = "Min" + ) + } + IconButton(onClick = onDecrementValue) { + Icon( + modifier = Modifier.size(25.dp), + imageVector = Icons.AutoMirrored.Filled.KeyboardArrowLeft, + contentDescription = "Less" + ) + } + WText(text = amountInt.toString()) + IconButton(onClick = onIncrementValue) { + Icon( + modifier = Modifier.size(25.dp), + imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight, + contentDescription = "More" + ) + } + IconButton(onClick = onMaxValue) { + Icon( + modifier = Modifier.size(25.dp), + painter = painterResource(R.drawable.baseline_keyboard_double_arrow_right_24), + contentDescription = "Max" + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/be/re/writand/screens/welcome/WelcomeStartScreen.kt b/app/src/main/java/be/re/writand/screens/welcome/WelcomeStartScreen.kt index 99c72b1..48e0e97 100644 --- a/app/src/main/java/be/re/writand/screens/welcome/WelcomeStartScreen.kt +++ b/app/src/main/java/be/re/writand/screens/welcome/WelcomeStartScreen.kt @@ -69,7 +69,7 @@ fun WelcomeStartScreen( ) } } - ) { it -> + ) { Column( modifier = Modifier .padding(it) diff --git a/app/src/main/java/be/re/writand/screens/welcome/WelcomeTOSScreen.kt b/app/src/main/java/be/re/writand/screens/welcome/WelcomeTOSScreen.kt index 891d6ae..86fb5d9 100644 --- a/app/src/main/java/be/re/writand/screens/welcome/WelcomeTOSScreen.kt +++ b/app/src/main/java/be/re/writand/screens/welcome/WelcomeTOSScreen.kt @@ -85,7 +85,7 @@ fun WelcomeTOSScreen( ) } } - ) { it -> + ) { Column( modifier = Modifier .padding(it) diff --git a/app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml b/app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml new file mode 100644 index 0000000..bafd5a1 --- /dev/null +++ b/app/src/main/res/drawable/baseline_keyboard_double_arrow_left_24.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable/baseline_keyboard_double_arrow_right_24.xml b/app/src/main/res/drawable/baseline_keyboard_double_arrow_right_24.xml new file mode 100644 index 0000000..e11e1a3 --- /dev/null +++ b/app/src/main/res/drawable/baseline_keyboard_double_arrow_right_24.xml @@ -0,0 +1,7 @@ + + + + + + +