Skip to content

feat: shortcuts info panel #1392

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: feat/shortcuts-customization
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ buildscript {
// UI
materialVersion = "1.6.1"
browserVersion = "1.3.0"
constrainLayoutVersion = '2.1.4'
constrainLayoutVersion = '2.2.1'
recyclerViewVersion = "1.2.1"
glideVersion = '4.12.0'
zxingVersion = '3.3.3' // Don't update. 3.3.3 is the maximum to support Android 6.x
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.dash.wallet.common.services.ExchangeRatesProvider
import org.dash.wallet.common.util.Constants
import javax.inject.Inject
import javax.inject.Singleton
import androidx.core.content.edit

@Singleton
// Intended for the UI settings which affect what the user sees on the screen.
Expand Down Expand Up @@ -66,6 +67,7 @@ open class WalletUIConfig @Inject constructor(
val LAST_TOTAL_BALANCE = longPreferencesKey("last_total_balance")
val LAST_MIXED_BALANCE = longPreferencesKey("last_mixed_balance")
val CUSTOMIZED_SHORTCUTS = stringPreferencesKey("customized_shortcuts")
val IS_SHORTCUT_INFO_HIDDEN = booleanPreferencesKey("is_shortcut_info_hidden")
}

suspend fun getExchangeCurrencyCode(): String {
Expand Down Expand Up @@ -112,7 +114,7 @@ class ExchangeCurrencyMigration(
} else {
otherName
}
sharedPreferences.edit().putString(WalletUIConfig.SELECTED_CURRENCY.name, fixedValue).apply()
sharedPreferences.edit { putString(WalletUIConfig.SELECTED_CURRENCY.name, fixedValue) }
}
// The database might have obsolete currencies as well
exchangeRates.cleanupObsoleteCurrencies()
Expand Down
123 changes: 123 additions & 0 deletions common/src/main/java/org/dash/wallet/common/ui/components/InfoPanel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
* Copyright 2024 Dash Core Group.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package org.dash.wallet.common.ui.components

import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.dash.wallet.common.R

@Composable
fun InfoPanel(
title: String,
description: String,
modifier: Modifier = Modifier,
@DrawableRes leftIconRes: Int? = null,
@DrawableRes actionIconRes: Int? = null,
onAction: (() -> Unit)? = null
) {
Box(
modifier = modifier
.fillMaxWidth()
.background(MyTheme.Colors.backgroundSecondary, RoundedCornerShape(16.dp))
.shadow(elevation = 20.dp, spotColor = Color(0x1AB8C1CC), ambientColor = Color(0x1AB8C1CC)),
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(14.dp, 15.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
leftIconRes?.let {
Box(
modifier = Modifier
.size(34.dp),
contentAlignment = Alignment.Center
) {
Icon(
painter = painterResource(id = leftIconRes),
contentDescription = null,
tint = Color.Unspecified
)
}
}

Column(
modifier = Modifier.weight(1f),
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Text(
text = title,
style = MyTheme.CaptionMedium
)

Text(
text = description,
style = MyTheme.Caption,
color = MyTheme.Colors.textSecondary
)
}

if (actionIconRes != null && onAction != null) {
Box(
modifier = Modifier
.size(28.dp)
.clickable { onAction() },
contentAlignment = Alignment.Center
) {
Icon(
painter = painterResource(id = actionIconRes),
contentDescription = "Close",
tint = MyTheme.Colors.gray
)
}
}
}
}
}

@Preview
@Composable
fun InfoPanelPreview() {
InfoPanel(
title = "Customize shortcut bar",
description = "Hold any button above to replace it with the function you need",
leftIconRes = R.drawable.ic_dash_blue_filled,
actionIconRes = R.drawable.ic_popup_close,
onAction = {}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fun MenuItem(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp)
.background(Color.White, RoundedCornerShape(8.dp))
.background(MyTheme.Colors.backgroundSecondary, RoundedCornerShape(8.dp))
.clickable { action?.invoke() }
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,42 +28,59 @@ import org.dash.wallet.common.R

object MyTheme {
val ToastBackground = Color(0xff191c1f).copy(alpha = 0.9f)
val InterFont = FontFamily(Font(R.font.inter))
private val interRegular = FontFamily(Font(R.font.inter_regular))
private val interMedium = FontFamily(Font(R.font.inter_medium))
private val interSemibold = FontFamily(Font(R.font.inter_semibold))
private val interBold = FontFamily(Font(R.font.inter_bold))

val Body2Regular = TextStyle(
fontSize = 14.sp,
lineHeight = 20.sp,
fontFamily = InterFont,
fontFamily = interRegular,
fontWeight = FontWeight(400)
)

val Overline = TextStyle(
fontSize = 12.sp,
lineHeight = 16.sp,
fontFamily = InterFont,
fontFamily = interMedium,
fontWeight = FontWeight(500),
textAlign = TextAlign.Center
)

val OverlineSemibold = TextStyle(
fontSize = 12.sp,
lineHeight = 16.sp,
fontFamily = InterFont,
fontFamily = interSemibold,
fontWeight = FontWeight(600),
textAlign = TextAlign.Center
)

val Caption = TextStyle(
fontSize = 13.sp,
lineHeight = 18.sp,
fontFamily = interRegular,
fontWeight = FontWeight(400)
)

val CaptionMedium = TextStyle(
fontSize = 13.sp,
lineHeight = 18.sp,
fontFamily = interMedium,
fontWeight = FontWeight(500)
)

val SubtitleSemibold = TextStyle(
fontSize = 16.sp,
lineHeight = 22.sp,
fontFamily = InterFont,
fontFamily = interSemibold,
fontWeight = FontWeight(600)
)

val H6Bold = TextStyle(
fontSize = 20.sp,
lineHeight = 26.sp,
fontFamily = InterFont,
fontFamily = interBold,
fontWeight = FontWeight(700)
)

Expand All @@ -77,5 +94,6 @@ object MyTheme {
val primary40 = Color(0x66191C1F)
val dashBlue = Color(0xFF008DE4)
val dashBlue5 = Color(0x0D008DE4)
val gray = Color(0xFFB0B6BC)
}
}
1 change: 1 addition & 0 deletions wallet/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ dependencies {
implementation("androidx.compose.ui:ui-tooling")
implementation("androidx.compose.material3:material3")
implementation("androidx.activity:activity-compose:1.7.2")
implementation "androidx.lifecycle:lifecycle-runtime-compose:$lifecycleVersion"

// Navigation
implementation "androidx.navigation:navigation-fragment-ktx:$navigationVersion"
Expand Down
22 changes: 22 additions & 0 deletions wallet/res/drawable/ic_shortcuts.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M19,1.992H5C3.343,1.992 2,3.335 2,4.992V18.992C2,20.649 3.343,21.992 5,21.992H19C20.657,21.992 22,20.649 22,18.992V4.992C22,3.335 20.657,1.992 19,1.992ZM5,-0.008C2.239,-0.008 0,2.231 0,4.992V18.992C0,21.754 2.239,23.992 5,23.992H19C21.761,23.992 24,21.754 24,18.992V4.992C24,2.231 21.761,-0.008 19,-0.008H5Z"
android:fillColor="#008DE4"
android:fillType="evenOdd"/>
<path
android:pathData="M4,5.992C4,4.888 4.895,3.992 6,3.992H9C10.105,3.992 11,4.888 11,5.992V8.992C11,10.097 10.105,10.992 9,10.992H6C4.895,10.992 4,10.097 4,8.992V5.992Z"
android:fillColor="#008DE4"/>
<path
android:pathData="M4,14.992C4,13.888 4.895,12.992 6,12.992H9C10.105,12.992 11,13.888 11,14.992V17.992C11,19.097 10.105,19.992 9,19.992H6C4.895,19.992 4,19.097 4,17.992V14.992Z"
android:fillColor="#008DE4"/>
<path
android:pathData="M13,5.992C13,4.888 13.895,3.992 15,3.992H18C19.105,3.992 20,4.888 20,5.992V8.992C20,10.097 19.105,10.992 18,10.992H15C13.895,10.992 13,10.097 13,8.992V5.992Z"
android:fillColor="#008DE4"/>
<path
android:pathData="M13,14.992C13,13.888 13.895,12.992 15,12.992H18C19.105,12.992 20,13.888 20,14.992V17.992C20,19.097 19.105,19.992 18,19.992H15C13.895,19.992 13,19.097 13,17.992V14.992Z"
android:fillColor="#008DE4"/>
</vector>
7 changes: 6 additions & 1 deletion wallet/res/layout/home_content.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
android:background="@color/background_primary"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingTop="54dp"
android:paddingTop="40dp"
android:paddingEnd="16dp">

<include
Expand All @@ -75,6 +75,11 @@
tools:visibility="visible"
android:layout_marginBottom="14dp" />

<androidx.compose.ui.platform.ComposeView
android:id="@+id/info_panel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp" />
</LinearLayout>
</LinearLayout>

Expand Down
2 changes: 2 additions & 0 deletions wallet/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -423,4 +423,6 @@

<!-- Shortcuts -->
<string name="select_option">Select option</string>
<string name="customize_shortcuts">Customize shortcut bar</string>
<string name="customize_shortcuts_description">Hold any button above to replace it with the function you need</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import de.schildbach.wallet_test.databinding.HeaderBalanceFragmentBinding
import org.bitcoinj.core.Coin
import org.dash.wallet.common.ui.viewBinding
import org.dash.wallet.common.util.GenericUtils
import org.dash.wallet.common.util.observe

class HeaderBalanceFragment : Fragment(R.layout.header_balance_fragment) {
private val viewModel by activityViewModels<MainViewModel>()
Expand Down Expand Up @@ -66,7 +67,7 @@ class HeaderBalanceFragment : Fragment(R.layout.header_balance_fragment) {
}

viewModel.showTapToHideHint.observe(viewLifecycleOwner) { showHint ->
binding.hideBalanceHintText.isVisible = showHint ?: true
binding.hideBalanceHintText.isVisible = showHint != false
}
}

Expand Down
23 changes: 15 additions & 8 deletions wallet/src/de/schildbach/wallet/ui/main/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import org.bitcoinj.core.Coin
import org.bitcoinj.core.Context
Expand Down Expand Up @@ -220,9 +224,13 @@ class MainViewModel @Inject constructor(
.combine(_temporaryHideBalance) { autoHide, temporaryHide ->
temporaryHide ?: autoHide ?: false
}
.asLiveData()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = false
)

val showTapToHideHint = walletUIConfig.observe(WalletUIConfig.SHOW_TAP_TO_HIDE_HINT).asLiveData()
val showTapToHideHint = walletUIConfig.observe(WalletUIConfig.SHOW_TAP_TO_HIDE_HINT)

private val _isNetworkUnavailable = MutableLiveData<Boolean>()
val isNetworkUnavailable: LiveData<Boolean>
Expand Down Expand Up @@ -418,8 +426,7 @@ class MainViewModel @Inject constructor(
}

fun triggerHideBalance() {
val isHiding = hideBalance.value ?: false
_temporaryHideBalance.value = !isHiding
_temporaryHideBalance.value = !hideBalance.value

if (_temporaryHideBalance.value == true) {
logEvent(AnalyticsConstants.Home.HIDE_BALANCE)
Expand Down Expand Up @@ -468,7 +475,7 @@ class MainViewModel @Inject constructor(
coinJoinService.updateTimeSkew(timeSkew)
log.info("timeskew: {} ms", timeSkew)
return Pair(abs(timeSkew) > maxAllowedTimeSkew, timeSkew)
} catch (ex: Exception) {
} catch (_: Exception) {
// Ignore errors
Pair(false, 0)
}
Expand Down Expand Up @@ -580,15 +587,15 @@ class MainViewModel @Inject constructor(
}

if (included && wrapper != null) {
itemId = wrapper!!.id
itemId = wrapper.id
} else {
this.crowdNodeWrapperFactory.tryInclude(tx).also {
included = it.first
wrapper = it.second
}

if (included && wrapper != null) {
itemId = wrapper!!.id
itemId = wrapper.id
}
}
}
Expand All @@ -608,7 +615,7 @@ class MainViewModel @Inject constructor(
)
} else {
TransactionRowView.fromTransactionWrapper(
wrapper!!,
wrapper,
walletData.transactionBag,
Constants.CONTEXT,
null,
Expand Down
Loading