Skip to content

Commit

Permalink
Refactor pinned quick pairs widget (#117)
Browse files Browse the repository at this point in the history
* Handle display quick pairs in widget by group

* Update icon

* Refactor quick pairs widget

* Move findActivity to utils

* Refactor ActionCallback

* Handle new pair nav in MainScreen instead of QuickScreen

* Accept group in AddQuickScreen, pass group on new pair from widget

* Extract common login between NextPageAction and PreviousPageAction

---------

Co-authored-by: Hieu Vu <[email protected]>
  • Loading branch information
mdrlzy and hieuwu authored Oct 5, 2024
1 parent e12ebb0 commit 59c12e0
Show file tree
Hide file tree
Showing 16 changed files with 240 additions and 144 deletions.
3 changes: 3 additions & 0 deletions app/src/main/java/dev/arkbuilders/rate/di/AppComponent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import dev.arkbuilders.rate.domain.repo.NetworkStatus
import dev.arkbuilders.rate.domain.repo.Prefs
import dev.arkbuilders.rate.domain.usecase.CalcFrequentCurrUseCase
import dev.arkbuilders.rate.domain.usecase.ConvertWithRateUseCase
import dev.arkbuilders.rate.domain.usecase.GetSortedPinnedQuickPairsUseCase
import dev.arkbuilders.rate.presentation.pairalert.AddPairAlertViewModelFactory
import dev.arkbuilders.rate.presentation.pairalert.PairAlertViewModelFactory
import dev.arkbuilders.rate.presentation.portfolio.AddAssetViewModelFactory
Expand Down Expand Up @@ -72,6 +73,8 @@ interface AppComponent {

fun calcFrequentCurrUseCase(): CalcFrequentCurrUseCase

fun getSortedPinnedQuickPairsUseCase(): GetSortedPinnedQuickPairsUseCase

@Component.Factory
interface Factory {
fun create(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ interface QuickRepo {

suspend fun getAll(): List<QuickPair>

suspend fun getAllGroups(): List<String?> = getAll().groupBy { it.group }.map { it.key }

fun allFlow(): Flow<List<QuickPair>>

suspend fun delete(id: Long): Boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.arkbuilders.rate.domain.usecase

import dev.arkbuilders.rate.domain.model.PinnedQuickPair
import dev.arkbuilders.rate.domain.model.QuickPair
import dev.arkbuilders.rate.domain.repo.QuickRepo
import java.time.OffsetDateTime
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class GetSortedPinnedQuickPairsUseCase @Inject constructor(
private val quickRepo: QuickRepo,
private val convertUseCase: ConvertWithRateUseCase,
) {
suspend operator fun invoke() =
quickRepo.getAll()
.filter { it.isPinned() }
.map {
mapPairToPinned(it)
}
.sortedByDescending { it.pair.pinnedDate }

private suspend fun mapPairToPinned(pair: QuickPair): PinnedQuickPair {
val actualTo =
pair.to.map { to ->
val (amount, _) = convertUseCase.invoke(pair.from, pair.amount, to.code)
amount
}
return PinnedQuickPair(pair, actualTo, OffsetDateTime.now())
}
}
18 changes: 18 additions & 0 deletions app/src/main/java/dev/arkbuilders/rate/presentation/MainScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,29 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.currentBackStackEntryAsState
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
import com.ramcosta.composedestinations.animations.rememberAnimatedNavHostEngine
import com.ramcosta.composedestinations.navigation.navigate
import com.ramcosta.composedestinations.utils.startDestination
import dev.arkbuilders.rate.di.DIManager
import dev.arkbuilders.rate.presentation.destinations.AddQuickScreenDestination
import dev.arkbuilders.rate.presentation.destinations.PairAlertConditionScreenDestination
import dev.arkbuilders.rate.presentation.destinations.PortfolioScreenDestination
import dev.arkbuilders.rate.presentation.destinations.QuickScreenDestination
import dev.arkbuilders.rate.presentation.destinations.SettingsScreenDestination
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.AddNewPairAction.Companion.ADD_NEW_PAIR
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.AddNewPairAction.Companion.ADD_NEW_PAIR_GROUP_KEY
import dev.arkbuilders.rate.presentation.ui.AnimatedRateBottomNavigation
import dev.arkbuilders.rate.presentation.ui.ConnectivityOfflineSnackbar
import dev.arkbuilders.rate.presentation.ui.ConnectivityOfflineSnackbarVisuals
import dev.arkbuilders.rate.presentation.ui.ConnectivityOnlineSnackbar
import dev.arkbuilders.rate.presentation.ui.ConnectivityOnlineSnackbarVisuals
import dev.arkbuilders.rate.presentation.utils.findActivity
import dev.arkbuilders.rate.presentation.utils.keyboardAsState
import kotlinx.coroutines.flow.drop

Expand All @@ -47,7 +53,19 @@ fun MainScreen() {
)
val navController = engine.rememberNavController()
val snackState = remember { SnackbarHostState() }
val ctx = LocalContext.current

LaunchedEffect(key1 = Unit) {
val activity = ctx.findActivity()
val intent = activity?.intent
val createNewPair = intent?.getStringExtra(ADD_NEW_PAIR) ?: ""
if (createNewPair.isNotEmpty()) {
val group = intent?.getStringExtra(ADD_NEW_PAIR_GROUP_KEY)
navController.navigate(AddQuickScreenDestination(group = group))
intent?.removeExtra(ADD_NEW_PAIR_GROUP_KEY)
intent?.removeExtra(ADD_NEW_PAIR)
}
}
LaunchedEffect(key1 = Unit) {
DIManager.component.networkStatus().onlineStatus
.drop(1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,15 @@ fun AddQuickScreen(
quickPairId: Long? = null,
newCode: CurrencyCode? = null,
reuseNotEdit: Boolean = true,
group: String? = null,
navigator: DestinationsNavigator,
) {
val ctx = LocalContext.current
val viewModel: AddQuickViewModel =
viewModel(
factory =
DIManager.component.addQuickVMFactory()
.create(quickPairId, newCode, reuseNotEdit),
.create(quickPairId, newCode, reuseNotEdit, group),
)

val state by viewModel.collectAsState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class AddQuickViewModel(
private val quickPairId: Long?,
private val newCode: CurrencyCode?,
private val reuseNotEdit: Boolean,
private val group: String?,
private val quickRepo: QuickRepo,
private val convertUseCase: ConvertWithRateUseCase,
private val codeUseStatRepo: CodeUseStatRepo,
Expand Down Expand Up @@ -105,7 +106,7 @@ class AddQuickViewModel(
newCode?.let {
listOf(AmountStr(newCode, ""))
} ?: state.currencies
state.copy(currencies = currencies, availableGroups = groups)
state.copy(currencies = currencies, availableGroups = groups, group = group)
}
}
}
Expand Down Expand Up @@ -201,8 +202,9 @@ class AddQuickViewModel(

class AddQuickViewModelFactory @AssistedInject constructor(
@Assisted private val quickPairId: Long?,
@Assisted private val newCode: CurrencyCode?,
@Assisted("newCode") private val newCode: CurrencyCode?,
@Assisted private val reuseNotEdit: Boolean,
@Assisted("group") private val group: String?,
private val quickRepo: QuickRepo,
private val codeUseStatRepo: CodeUseStatRepo,
private val convertUseCase: ConvertWithRateUseCase,
Expand All @@ -213,6 +215,7 @@ class AddQuickViewModelFactory @AssistedInject constructor(
quickPairId,
newCode,
reuseNotEdit,
group,
quickRepo,
convertUseCase,
codeUseStatRepo,
Expand All @@ -224,8 +227,9 @@ class AddQuickViewModelFactory @AssistedInject constructor(
interface Factory {
fun create(
quickPairId: Long?,
newCode: CurrencyCode?,
@Assisted("newCode") newCode: CurrencyCode?,
reuseNotEdit: Boolean,
@Assisted("group") group: String?,
): AddQuickViewModelFactory
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package dev.arkbuilders.rate.presentation.quick

import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
Expand All @@ -26,7 +23,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand Down Expand Up @@ -58,7 +54,6 @@ import dev.arkbuilders.rate.domain.model.CurrencyName
import dev.arkbuilders.rate.domain.model.PinnedQuickPair
import dev.arkbuilders.rate.domain.model.QuickPair
import dev.arkbuilders.rate.presentation.destinations.AddQuickScreenDestination
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.AddNewPairAction.Companion.ADD_NEW_PAIR
import dev.arkbuilders.rate.presentation.theme.ArkColor
import dev.arkbuilders.rate.presentation.ui.AppButton
import dev.arkbuilders.rate.presentation.ui.AppHorDiv16
Expand Down Expand Up @@ -91,15 +86,6 @@ fun QuickScreen(navigator: DestinationsNavigator) {
val state by viewModel.collectAsState()
val snackState = remember { SnackbarHostState() }
val ctx = LocalContext.current
LaunchedEffect(key1 = Unit) {
val activity = ctx.findActivity()
val intent = activity?.intent
val createNewPair = intent?.getStringExtra(ADD_NEW_PAIR) ?: ""
if (createNewPair.isNotEmpty()) {
navigator.navigate(AddQuickScreenDestination())
intent?.removeExtra(ADD_NEW_PAIR)
}
}
viewModel.collectSideEffect { effect ->
when (effect) {
is QuickScreenEffect.ShowSnackbarAdded ->
Expand Down Expand Up @@ -591,10 +577,3 @@ private fun QuickEmpty(navigator: DestinationsNavigator) {
}
}
}

fun Context.findActivity(): Activity? =
when (this) {
is Activity -> this
is ContextWrapper -> baseContext.findActivity()
else -> null
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,27 @@ import androidx.glance.text.FontWeight
import androidx.glance.text.Text
import androidx.glance.text.TextStyle
import androidx.glance.unit.ColorProvider
import com.google.gson.GsonBuilder
import dev.arkbuilders.rate.R
import dev.arkbuilders.rate.domain.model.PinnedQuickPair
import dev.arkbuilders.rate.di.DIManager
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.AddNewPairAction
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.NextPageAction
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.OpenAppAction
import dev.arkbuilders.rate.presentation.quick.glancewidget.action.PreviousPageAction
import dev.arkbuilders.rate.presentation.theme.ArkColor

class QuickPairsWidget : GlanceAppWidget() {
private val getPinnedUseCase = DIManager.component.getSortedPinnedQuickPairsUseCase()

override suspend fun provideGlance(
context: Context,
id: GlanceId,
) {
val pinned = getPinnedUseCase.invoke()
provideContent {
val prefs = currentState<Preferences>()
val quickPairsString = prefs[QuickPairsWidgetReceiver.quickDisplayPairs]
val quickPairsList = quickPairsString?.let { parseQuickPairs(it) }
val group = prefs[QuickPairsWidgetReceiver.currentGroupKey]
val quickPairsList = pinned.filter { it.pair.group == group }
val displayGroup = group ?: context.getString(R.string.group_default_name)
Column(
modifier =
GlanceModifier.fillMaxSize().background(Color.White)
Expand All @@ -59,10 +64,7 @@ class QuickPairsWidget : GlanceAppWidget() {
modifier =
GlanceModifier.size(24.dp).padding(4.dp)
.clickable(actionRunCallback<AddNewPairAction>()),
provider =
ImageProvider(
R.drawable.ic_about_logo,
),
provider = ImageProvider(R.drawable.ic_about_logo),
contentDescription = null,
)
Text(
Expand All @@ -74,6 +76,30 @@ class QuickPairsWidget : GlanceAppWidget() {
fontWeight = FontWeight.Medium,
),
)
Text(
modifier = GlanceModifier.defaultWeight(),
text = displayGroup,
style =
TextStyle(
color = ColorProvider(ArkColor.TextTertiary),
fontWeight = FontWeight.Medium,
),
)
Image(
modifier =
GlanceModifier.size(24.dp).padding(4.dp)
.clickable(actionRunCallback<PreviousPageAction>()),
provider = ImageProvider(R.drawable.ic_chevron_left),
contentDescription = null,
)

Image(
modifier =
GlanceModifier.size(24.dp).padding(4.dp)
.clickable(actionRunCallback<NextPageAction>()),
provider = ImageProvider(R.drawable.ic_chevron_right),
contentDescription = null,
)
Image(
modifier =
GlanceModifier.size(24.dp).padding(4.dp)
Expand All @@ -97,29 +123,24 @@ class QuickPairsWidget : GlanceAppWidget() {
)
}
LazyColumn(modifier = GlanceModifier.fillMaxHeight()) {
quickPairsList?.let { pairs ->
items(pairs) { quick ->
Column {
QuickPairItem(
quick = quick,
context = context,
)
Spacer(
modifier =
GlanceModifier.fillMaxWidth().height(1.dp)
.background(Color.Gray.copy(alpha = 0.2f))
.padding(vertical = 2.dp),
)
}
items(quickPairsList) { quick ->
Column {
QuickPairItem(
quick = quick,
context = context,
)
Spacer(
modifier =
GlanceModifier
.fillMaxWidth()
.height(1.dp)
.background(Color.Gray.copy(alpha = 0.2f))
.padding(vertical = 2.dp),
)
}
}
}
}
}
}

private fun parseQuickPairs(quickPairsString: String): List<PinnedQuickPair> {
val gson = GsonBuilder().create()
return gson.fromJson(quickPairsString, Array<PinnedQuickPair>::class.java).toList()
}
}
Loading

0 comments on commit 59c12e0

Please sign in to comment.