diff --git a/app/src/main/java/com/ivy/wallet/ui/IvyActivity.kt b/app/src/main/java/com/ivy/wallet/ui/IvyActivity.kt index a98e248e8c..0bdb51a899 100644 --- a/app/src/main/java/com/ivy/wallet/ui/IvyActivity.kt +++ b/app/src/main/java/com/ivy/wallet/ui/IvyActivity.kt @@ -56,6 +56,7 @@ import com.ivy.wallet.ui.paywall.PaywallScreen import com.ivy.wallet.ui.planned.edit.EditPlannedScreen import com.ivy.wallet.ui.planned.list.PlannedPaymentsScreen import com.ivy.wallet.ui.reports.ReportScreen +import com.ivy.wallet.ui.search.SearchScreen import com.ivy.wallet.ui.settings.SettingsScreen import com.ivy.wallet.ui.statistic.level1.PieChartStatisticScreen import com.ivy.wallet.ui.statistic.level2.ItemStatisticScreen @@ -172,6 +173,7 @@ class IvyActivity : AppCompatActivity() { is Screen.Budget -> BudgetScreen(screen = screen) is Screen.Loans -> LoansScreen(screen = screen) is Screen.LoanDetails -> LoanDetailsScreen(screen = screen) + is Screen.Search -> SearchScreen(screen = screen) is Screen.WebView -> WebViewScreen(screen = screen) null -> { } diff --git a/app/src/main/java/com/ivy/wallet/ui/Screens.kt b/app/src/main/java/com/ivy/wallet/ui/Screens.kt index 7b2f39ab33..f4a0ede074 100644 --- a/app/src/main/java/com/ivy/wallet/ui/Screens.kt +++ b/app/src/main/java/com/ivy/wallet/ui/Screens.kt @@ -70,6 +70,8 @@ sealed class Screen { object Loans : Screen() + object Search : Screen() + data class LoanDetails( val loanId: UUID ) : Screen() diff --git a/app/src/main/java/com/ivy/wallet/ui/home/HomeMoreMenu.kt b/app/src/main/java/com/ivy/wallet/ui/home/HomeMoreMenu.kt index 1c8d63c1d9..7a9b4020b1 100644 --- a/app/src/main/java/com/ivy/wallet/ui/home/HomeMoreMenu.kt +++ b/app/src/main/java/com/ivy/wallet/ui/home/HomeMoreMenu.kt @@ -35,7 +35,6 @@ import com.ivy.wallet.ui.Screen import com.ivy.wallet.ui.theme.* import com.ivy.wallet.ui.theme.components.BufferBattery import com.ivy.wallet.ui.theme.components.CircleButtonFilled -import com.ivy.wallet.ui.theme.components.IvyButton import com.ivy.wallet.ui.theme.components.IvyIcon import com.ivy.wallet.ui.theme.modal.AddModalBackHandling import com.ivy.wallet.ui.theme.wallet.AmountCurrencyB1 @@ -190,7 +189,16 @@ private fun ColumnScope.Content( onBufferClick: () -> Unit, onCurrencyClick: () -> Unit, ) { - Spacer(Modifier.height(32.dp)) + Spacer(Modifier.height(24.dp)) + + val ivyContext = LocalIvyContext.current + SearchButton { + ivyContext.navigateTo( + screen = Screen.Search + ) + } + + Spacer(Modifier.height(16.dp)) QuickAccess( theme = theme, @@ -211,16 +219,44 @@ private fun ColumnScope.Content( OpenSource() Spacer(Modifier.weight(1f)) +} - IvyButton( - modifier = Modifier.padding(start = 24.dp), - text = currency, - iconStart = R.drawable.ic_currency +@Composable +private fun SearchButton( + onClick: () -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .clip(Shapes.roundedFull) + .background(IvyTheme.colors.pure) + .border(1.dp, Gray, Shapes.roundedFull) + .clickable { + onClick() + }, + verticalAlignment = Alignment.CenterVertically ) { - onCurrencyClick() - } + Spacer(Modifier.width(12.dp)) - Spacer(Modifier.height(40.dp)) + IvyIcon(icon = R.drawable.ic_search) + + Spacer(Modifier.width(12.dp)) + + Text( + modifier = Modifier.padding( + top = 12.dp, + bottom = 14.dp + ), + text = "Search transactions", + style = Typo.body2.style( + fontWeight = FontWeight.SemiBold, + color = IvyTheme.colors.pureInverse + ) + ) + + Spacer(Modifier.width(16.dp)) + } } @Composable @@ -341,30 +377,30 @@ private fun QuickAccess( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.Top ) { - Spacer(Modifier.width(4.dp)) + Spacer(Modifier.weight(1f)) MoreMenuButton( - icon = R.drawable.ic_settings, + icon = R.drawable.home_more_menu_settings, label = "Settings" ) { ivyContext.navigateTo(Screen.Settings) } - Spacer(Modifier.width(0.dp)) + Spacer(Modifier.weight(1f)) MoreMenuButton( - icon = R.drawable.ic_categories, + icon = R.drawable.home_more_menu_categories, label = "Categories" ) { ivyContext.navigateTo(Screen.Categories) } - Spacer(Modifier.width(0.dp)) + Spacer(Modifier.weight(1f)) MoreMenuButton( icon = when (theme) { - Theme.LIGHT -> R.drawable.ic_lightmode - Theme.DARK -> R.drawable.ic_darkmode + Theme.LIGHT -> R.drawable.home_more_menu_light_mode + Theme.DARK -> R.drawable.home_more_menu_dark_mode }, label = when (theme) { Theme.LIGHT -> "Light mode" @@ -382,16 +418,16 @@ private fun QuickAccess( onSwitchTheme() } - Spacer(Modifier.width(0.dp)) + Spacer(Modifier.weight(1f)) MoreMenuButton( - icon = R.drawable.ic_planned_payments, + icon = R.drawable.home_more_menu_planned_payments, label = "Planned\nPayments" ) { ivyContext.navigateTo(Screen.PlannedPayments) } - Spacer(Modifier.width(12.dp)) + Spacer(Modifier.weight(1f)) } Spacer(Modifier.height(16.dp)) @@ -402,39 +438,44 @@ private fun QuickAccess( horizontalArrangement = Arrangement.Start, verticalAlignment = Alignment.Top ) { - Spacer(Modifier.width(4.dp)) + Spacer(Modifier.weight(1f)) val context = LocalContext.current MoreMenuButton( - icon = R.drawable.ic_share, - label = "Share\nIvy Wallet" + icon = R.drawable.home_more_menu_share, + label = "Share Ivy" ) { (context as IvyActivity).shareIvyWallet() } + Spacer(Modifier.weight(1f)) + MoreMenuButton( - icon = R.drawable.ic_statistics_s, + icon = R.drawable.home_more_menu_reports, label = "Reports", - expandPadding = 11.dp ) { ivyContext.navigateTo(Screen.Report) } + Spacer(Modifier.weight(1f)) + MoreMenuButton( - icon = R.drawable.ic_budget_s, + icon = R.drawable.home_more_menu_budgets, label = "Budgets", - expandPadding = 11.dp ) { ivyContext.navigateTo(Screen.Budget) } + Spacer(Modifier.weight(1f)) + MoreMenuButton( - icon = R.drawable.ic_custom_loan_s, + icon = R.drawable.home_more_menu_loans, label = "Loans", - expandPadding = 11.dp ) { ivyContext.navigateTo(Screen.Loans) } + + Spacer(Modifier.weight(1f)) } } @@ -445,7 +486,7 @@ private fun MoreMenuButton( backgroundColor: Color = IvyTheme.colors.pure, tint: Color = IvyTheme.colors.pureInverse, - expandPadding: Dp = 8.dp, + expandPadding: Dp = 14.dp, onClick: () -> Unit ) { diff --git a/app/src/main/java/com/ivy/wallet/ui/search/SearchScreen.kt b/app/src/main/java/com/ivy/wallet/ui/search/SearchScreen.kt new file mode 100644 index 0000000000..4e814ca2e5 --- /dev/null +++ b/app/src/main/java/com/ivy/wallet/ui/search/SearchScreen.kt @@ -0,0 +1,208 @@ +package com.ivy.wallet.ui.search + +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.tween +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.google.accompanist.insets.systemBarsPadding +import com.ivy.wallet.R +import com.ivy.wallet.base.* +import com.ivy.wallet.model.TransactionHistoryItem +import com.ivy.wallet.model.entity.Account +import com.ivy.wallet.model.entity.Category +import com.ivy.wallet.ui.IvyAppPreview +import com.ivy.wallet.ui.LocalIvyContext +import com.ivy.wallet.ui.Screen +import com.ivy.wallet.ui.theme.Gray +import com.ivy.wallet.ui.theme.IvyTheme +import com.ivy.wallet.ui.theme.Shapes +import com.ivy.wallet.ui.theme.components.IvyBasicTextField +import com.ivy.wallet.ui.theme.components.IvyIcon +import com.ivy.wallet.ui.theme.modal.DURATION_MODAL_KEYBOARD +import com.ivy.wallet.ui.theme.transaction.transactions + +@Composable +fun SearchScreen(screen: Screen.Search) { + val viewModel: SearchViewModel = viewModel() + + val transactions by viewModel.transactions.collectAsState() + val baseCurrency by viewModel.baseCurrencyCode.collectAsState() + val categories by viewModel.categories.collectAsState() + val accounts by viewModel.accounts.collectAsState() + + onScreenStart { + viewModel.search("") + } + + UI( + transactions = transactions, + baseCurrency = baseCurrency, + categories = categories, + accounts = accounts, + + onSearch = viewModel::search + ) +} + +@Composable +private fun UI( + transactions: List, + baseCurrency: String, + categories: List, + accounts: List, + + onSearch: (String) -> Unit = {} +) { + Column( + modifier = Modifier + .fillMaxSize() + .systemBarsPadding() + ) { + Spacer(Modifier.height(24.dp)) + + val listState = rememberLazyListState() + + var searchQueryTextFieldValue by remember { + mutableStateOf(selectEndTextFieldValue("")) + } + + SearchInput( + searchQueryTextFieldValue = searchQueryTextFieldValue, + onSetSearchQueryTextField = { + searchQueryTextFieldValue = it + onSearch(it.text) + } + ) + + LaunchedEffect(transactions) { + //scroll to top when transactions are changed + listState.animateScrollToItem(index = 0, scrollOffset = 0) + } + + Spacer(Modifier.height(16.dp)) + + val ivyContext = LocalIvyContext.current + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = listState + + ) { + transactions( + ivyContext = ivyContext, + upcoming = emptyList(), + upcomingExpanded = false, + setUpcomingExpanded = { }, + baseCurrency = baseCurrency, + upcomingIncome = 0.0, + upcomingExpenses = 0.0, + categories = categories, + accounts = accounts, + listState = listState, + overdue = emptyList(), + overdueExpanded = false, + setOverdueExpanded = { }, + overdueIncome = 0.0, + overdueExpenses = 0.0, + history = transactions, + onPayOrGet = { }, + dateDividerMarginTop = 16.dp, + emptyStateTitle = "No transactions", + emptyStateText = "You don't have any transactions for \"${searchQueryTextFieldValue.text}\" query." + ) + + item { + val keyboardVisible by keyboardVisibleState() + val keyboardShownInsetDp by animateDpAsState( + targetValue = densityScope { + if (keyboardVisible) keyboardOnlyWindowInsets().bottom.toDp() else 0.dp + }, + animationSpec = tween(DURATION_MODAL_KEYBOARD) + ) + + Spacer(Modifier.height(keyboardShownInsetDp)) + //add keyboard height margin at bototm so the list can scroll to bottom + } + } + } +} + +@Composable +private fun SearchInput( + searchQueryTextFieldValue: TextFieldValue, + onSetSearchQueryTextField: (TextFieldValue) -> Unit +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp) + .clip(Shapes.roundedFull) + .background(IvyTheme.colors.pure) + .border(1.dp, Gray, Shapes.roundedFull), + verticalAlignment = Alignment.CenterVertically + ) { + Spacer(Modifier.width(12.dp)) + + IvyIcon(icon = R.drawable.ic_search) + + Spacer(Modifier.width(12.dp)) + + val searchFocus = FocusRequester() + IvyBasicTextField( + modifier = Modifier + .padding( + top = 12.dp, + bottom = 14.dp + ) + .focusRequester(searchFocus), + value = searchQueryTextFieldValue, + hint = "Search transactions", + onValueChanged = { + onSetSearchQueryTextField(it) + } + ) + + onScreenStart { + searchFocus.requestFocus() + } + + Spacer(Modifier.weight(1f)) + + IvyIcon( + modifier = Modifier + .clickable { + onSetSearchQueryTextField(selectEndTextFieldValue("")) + } + .padding(all = 12.dp), //enlarge click area + icon = R.drawable.ic_outline_clear_24 + ) + + Spacer(Modifier.width(8.dp)) + } +} + +@Preview +@Composable +private fun Preview() { + IvyAppPreview { + UI( + transactions = emptyList(), + baseCurrency = "BGN", + categories = emptyList(), + accounts = emptyList() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ivy/wallet/ui/search/SearchViewModel.kt b/app/src/main/java/com/ivy/wallet/ui/search/SearchViewModel.kt new file mode 100644 index 0000000000..75f55568c6 --- /dev/null +++ b/app/src/main/java/com/ivy/wallet/ui/search/SearchViewModel.kt @@ -0,0 +1,82 @@ +package com.ivy.wallet.ui.search + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.ivy.wallet.base.TestIdlingResource +import com.ivy.wallet.base.getDefaultFIATCurrency +import com.ivy.wallet.base.ioThread +import com.ivy.wallet.logic.currency.ExchangeRatesLogic +import com.ivy.wallet.logic.withDateDividers +import com.ivy.wallet.model.TransactionHistoryItem +import com.ivy.wallet.model.entity.Account +import com.ivy.wallet.model.entity.Category +import com.ivy.wallet.model.entity.Transaction +import com.ivy.wallet.persistence.dao.AccountDao +import com.ivy.wallet.persistence.dao.CategoryDao +import com.ivy.wallet.persistence.dao.SettingsDao +import com.ivy.wallet.persistence.dao.TransactionDao +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class SearchViewModel @Inject constructor( + private val transactionDao: TransactionDao, + private val settingsDao: SettingsDao, + private val categoryDao: CategoryDao, + private val accountDao: AccountDao, + private val exchangeRatesLogic: ExchangeRatesLogic +) : ViewModel() { + + private val _baseCurrencyCode = MutableStateFlow(getDefaultFIATCurrency().currencyCode) + val baseCurrencyCode = _baseCurrencyCode.asStateFlow() + + private val _transactions = MutableStateFlow(emptyList()) + val transactions = _transactions.asStateFlow() + + private val _accounts = MutableStateFlow(emptyList()) + val accounts = _accounts.asStateFlow() + + private val _categories = MutableStateFlow(emptyList()) + val categories = _categories.asStateFlow() + + fun search(query: String) { + val normalizedQuery = query.lowercase().trim() + + viewModelScope.launch { + TestIdlingResource.increment() + + _baseCurrencyCode.value = ioThread { + settingsDao.findFirst().currency + } + + _categories.value = ioThread { + categoryDao.findAll() + } + + _accounts.value = ioThread { + accountDao.findAll() + } + + _transactions.value = ioThread { + transactionDao.findAll() + .filter { + it.title.matchesQuery(normalizedQuery) || + it.description.matchesQuery(normalizedQuery) + }.withDateDividers( + exchangeRatesLogic = exchangeRatesLogic, + accountDao = accountDao, + settingsDao = settingsDao + ) + } + + TestIdlingResource.decrement() + } + } + + private fun String?.matchesQuery(query: String): Boolean { + return this?.lowercase()?.trim()?.contains(query) == true + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ivy/wallet/ui/theme/components/IvyBasicTextField.kt b/app/src/main/java/com/ivy/wallet/ui/theme/components/IvyBasicTextField.kt new file mode 100644 index 0000000000..4d48c59cd3 --- /dev/null +++ b/app/src/main/java/com/ivy/wallet/ui/theme/components/IvyBasicTextField.kt @@ -0,0 +1,108 @@ +package com.ivy.wallet.ui.theme.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.platform.LocalView +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.input.* +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import com.ivy.wallet.base.hideKeyboard +import com.ivy.wallet.base.isNotNullOrBlank +import com.ivy.wallet.base.selectEndTextFieldValue +import com.ivy.wallet.ui.IvyAppPreview +import com.ivy.wallet.ui.theme.IvyComponentPreview +import com.ivy.wallet.ui.theme.IvyTheme +import com.ivy.wallet.ui.theme.Typo +import com.ivy.wallet.ui.theme.style + +@Composable +fun IvyBasicTextField( + modifier: Modifier = Modifier, + value: TextFieldValue, + textColor: Color = IvyTheme.colors.pureInverse, + hint: String?, + visualTransformation: VisualTransformation = VisualTransformation.None, + keyboardOptions: KeyboardOptions = KeyboardOptions( + autoCorrect = true, + keyboardType = KeyboardType.Text, + imeAction = ImeAction.Done, + capitalization = KeyboardCapitalization.Sentences + ), + keyboardActions: KeyboardActions? = null, + onValueChanged: (TextFieldValue) -> Unit +) { + val isEmpty = value.text.isBlank() + + Box( + modifier = modifier, + contentAlignment = Alignment.CenterStart + ) { + if (isEmpty && hint.isNotNullOrBlank()) { + Text( + modifier = Modifier, + text = hint!!, + style = Typo.body2.style( + color = IvyTheme.colors.gray, + fontWeight = FontWeight.SemiBold, + textAlign = TextAlign.Start + ), + ) + } + + val view = LocalView.current + BasicTextField( + modifier = Modifier + .testTag("base_input"), + value = value, + onValueChange = onValueChanged, + textStyle = Typo.body2.style( + fontWeight = FontWeight.SemiBold, + color = IvyTheme.colors.pureInverse, + textAlign = TextAlign.Start + ), + singleLine = false, + cursorBrush = SolidColor(IvyTheme.colors.pureInverse), + visualTransformation = visualTransformation, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions ?: KeyboardActions( + onDone = { + hideKeyboard(view) + } + ) + ) + } +} + +@Preview +@Composable +private fun Preview_Hint() { + IvyComponentPreview { + IvyBasicTextField( + value = selectEndTextFieldValue(""), + hint = "Search transactions", + onValueChanged = {} + ) + } +} + +@Preview +@Composable +private fun Preview_Filled() { + IvyComponentPreview { + IvyBasicTextField( + value = selectEndTextFieldValue("sfds"), + hint = "Okay", + onValueChanged = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ivy/wallet/ui/theme/transaction/Transactions.kt b/app/src/main/java/com/ivy/wallet/ui/theme/transaction/Transactions.kt index 87365be1f5..e4683abe0d 100644 --- a/app/src/main/java/com/ivy/wallet/ui/theme/transaction/Transactions.kt +++ b/app/src/main/java/com/ivy/wallet/ui/theme/transaction/Transactions.kt @@ -45,8 +45,8 @@ fun LazyListScope.transactions( lastItemSpacer: Dp? = null, onPayOrGet: (Transaction) -> Unit, emptyStateTitle: String = "No transactions", - - emptyStateText: String + emptyStateText: String, + dateDividerMarginTop: Dp? = null ) { if (upcoming.isNotEmpty()) { item { @@ -134,7 +134,8 @@ fun LazyListScope.transactions( is TransactionHistoryDateDivider -> { HistoryDateDivider( date = it.date, - spacerTop = if (it == history.firstOrNull()) 24.dp else 32.dp, + spacerTop = dateDividerMarginTop + ?: if (it == history.firstOrNull()) 24.dp else 32.dp, baseCurrency = baseCurrency, income = it.income, expenses = it.expenses diff --git a/app/src/main/res/drawable/home_more_menu_budgets.xml b/app/src/main/res/drawable/home_more_menu_budgets.xml new file mode 100644 index 0000000000..d2272ec248 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_budgets.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/app/src/main/res/drawable/home_more_menu_categories.xml b/app/src/main/res/drawable/home_more_menu_categories.xml new file mode 100644 index 0000000000..fad08f613e --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_categories.xml @@ -0,0 +1,27 @@ + + + + + diff --git a/app/src/main/res/drawable/home_more_menu_dark_mode.xml b/app/src/main/res/drawable/home_more_menu_dark_mode.xml new file mode 100644 index 0000000000..58cd3ab94a --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_dark_mode.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/home_more_menu_light_mode.xml b/app/src/main/res/drawable/home_more_menu_light_mode.xml new file mode 100644 index 0000000000..392fa4fab6 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_light_mode.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/home_more_menu_loans.xml b/app/src/main/res/drawable/home_more_menu_loans.xml new file mode 100644 index 0000000000..31ff84103e --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_loans.xml @@ -0,0 +1,34 @@ + + + + + + diff --git a/app/src/main/res/drawable/home_more_menu_planned_payments.xml b/app/src/main/res/drawable/home_more_menu_planned_payments.xml new file mode 100644 index 0000000000..6f85708f41 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_planned_payments.xml @@ -0,0 +1,13 @@ + + + diff --git a/app/src/main/res/drawable/home_more_menu_reports.xml b/app/src/main/res/drawable/home_more_menu_reports.xml new file mode 100644 index 0000000000..c5062eb779 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_reports.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/home_more_menu_settings.xml b/app/src/main/res/drawable/home_more_menu_settings.xml new file mode 100644 index 0000000000..4a20839040 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_settings.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/home_more_menu_share.xml b/app/src/main/res/drawable/home_more_menu_share.xml new file mode 100644 index 0000000000..d6ef47afc6 --- /dev/null +++ b/app/src/main/res/drawable/home_more_menu_share.xml @@ -0,0 +1,20 @@ + + + + diff --git a/app/src/main/res/drawable/ic_outline_clear_24.xml b/app/src/main/res/drawable/ic_outline_clear_24.xml new file mode 100644 index 0000000000..4ebf4a04e2 --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_clear_24.xml @@ -0,0 +1,10 @@ + + +