Skip to content

Commit

Permalink
Merge pull request #12 from Dev-Pasaka/dev
Browse files Browse the repository at this point in the history
Added transactions
  • Loading branch information
Dev-Pasaka authored Jan 2, 2025
2 parents 0695233 + b3cdda1 commit add6c45
Show file tree
Hide file tree
Showing 21 changed files with 550 additions and 34 deletions.
1 change: 1 addition & 0 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ kotlin {
implementation(libs.kotlinx.datetime)
api(libs.web.view)
implementation(libs.qr.kit)
implementation(libs.placeholder)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
Expand Down
23 changes: 23 additions & 0 deletions composeApp/src/commonMain/kotlin/org/example/common/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.benasher44.uuid.uuid4
import kotlinx.datetime.*
import java.text.DecimalFormat

data class MonthDay(val month: Int, val day: Int)

Expand Down Expand Up @@ -75,3 +76,25 @@ fun painterWithBackground(
}


fun String.convertToSignificantString(): String {
val number = this.toDouble()
val formatter = DecimalFormat("0.############") // Adjust pattern for desired precision
return formatter.format(number)
}


fun String.convertToLocalTime(): String {
// Parse the timestamp as an Instant
val instant = Instant.parse(this)
// Get the system's local time zone
val timeZone = TimeZone.currentSystemDefault()
// Convert to LocalDateTime in the system's time zone
val localDateTime = instant.toLocalDateTime(timeZone)

// Extract the components if needed
val hour = localDateTime.hour
val date = localDateTime.date

// Customize the return format
return "$date $hour:${localDateTime.minute}:${localDateTime.second}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package org.example.data.remote.dto.response.getTransactions

import kotlinx.serialization.Serializable
import org.example.domain.model.Transaction

@Serializable
data class Data(
val amount: String,
val blockchain: String,
val feeLevel: String,
val id: String,
val receiverAddress: String,
val senderAddress: String,
val status: String,
val timestamp: String
){
fun toTransaction(): Transaction {
return Transaction(
amount = amount,
blockchain = blockchain,
feeLevel = feeLevel,
id = id,
receiverAddress = receiverAddress,
senderAddress = senderAddress,
status = status,
timestamp = timestamp

)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.example.data.remote.dto.response.getTransactions

import kotlinx.serialization.Serializable

@Serializable
data class GetTransactionsRes(
val `data`: List<Data>,
val httpStatusCode: Int,
val message: String,
val status: Boolean
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import org.example.data.remote.dto.request.CreateWalletReq
import org.example.data.remote.dto.request.ImportWalletReq
import org.example.data.remote.dto.request.TransferCryptoReq
import org.example.data.remote.dto.response.createWallet.CreateWalletRes
import org.example.data.remote.dto.response.getTransactions.GetTransactionsRes
import org.example.data.remote.dto.response.getWallet.GetWalletRes
import org.example.data.remote.dto.response.getWalletBalance.GetWalletBalanceRes
import org.example.data.remote.dto.response.importWallet.ImportWalletRes
Expand Down Expand Up @@ -62,4 +63,12 @@ class WalletRepositoryImpl(
setBody(body)
}.body()
}

override suspend fun getTransactions(walletId: String): GetTransactionsRes = withContext(
Dispatchers.IO
) {
return@withContext api.client.get("${api.baseUrl}/transaction/history?walletId=$walletId")
.body()

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.example.domain.usecase.requestLink.CreateRequestLinkUseCase
import org.example.domain.usecase.requestLink.GetRequestLinkDataUseCase
import org.example.domain.usecase.user.GetSessionStatusUseCase
import org.example.domain.usecase.wallet.CreateWalletUseCase
import org.example.domain.usecase.wallet.GetTransactionUseCase
import org.example.domain.usecase.wallet.GetWalletUseCase
import org.example.domain.usecase.wallet.ImportWalletUseCase
import org.example.domain.usecase.wallet.TransferCryptoUseCase
Expand All @@ -17,4 +18,5 @@ val useCaseModule = module{
single{ CreateRequestLinkUseCase(get())}
single{ GetRequestLinkDataUseCase(get())}
single{ TransferCryptoUseCase(get(), get())}
single{ GetTransactionUseCase(get(), get())}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.example.domain.model

data class Transaction(
val amount: String,
val blockchain: String,
val feeLevel: String,
val id: String,
val receiverAddress: String,
val senderAddress: String,
val status: String,
val timestamp: String,
val transactionType: String = ""
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.example.data.remote.dto.request.TransferCryptoReq
import org.example.data.remote.dto.request.CreateWalletReq
import org.example.data.remote.dto.request.ImportWalletReq
import org.example.data.remote.dto.response.createWallet.CreateWalletRes
import org.example.data.remote.dto.response.getTransactions.GetTransactionsRes
import org.example.data.remote.dto.response.getWallet.GetWalletRes
import org.example.data.remote.dto.response.getWalletBalance.GetWalletBalanceRes
import org.example.data.remote.dto.response.importWallet.ImportWalletRes
Expand All @@ -15,6 +16,7 @@ interface WalletRepository {
suspend fun getWallet(id: String):GetWalletRes
suspend fun getWalletBalance(walletId: String): GetWalletBalanceRes
suspend fun transferCrypto(body: TransferCryptoReq): TransferCryptoRes
suspend fun getTransactions(walletId: String): GetTransactionsRes
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.example.domain.usecase.wallet

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import org.example.common.Constants
import org.example.common.Resource
import org.example.domain.model.Transaction
import org.example.domain.repository.KeyValueStorage
import org.example.domain.repository.WalletRepository

class GetTransactionUseCase(
private val repository: WalletRepository,
private val keyValueStorage: KeyValueStorage
) {
suspend operator fun invoke(): Flow<Resource<List<Transaction>>> = flow {
emit(Resource.Loading())
try {
val walletId = keyValueStorage.getString(Constants.WALLET_ID) ?: ""
val transactions = repository.getTransactions(walletId)
if (transactions.status) {
emit(
Resource.Success(
data = transactions.data.map { it.toTransaction() },
message = "Transactions retrieved successfully"
)
)
} else {
emit(Resource.Error(transactions.message))
}
} catch (e: Exception) {
e.printStackTrace()
emit(Resource.Error(e.message ?: "An error occurred"))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.example.domain.usecase.wallet

import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import org.example.common.Constants
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package org.example.presentation.screens.dashboardScreen

import DashboardScreenLowerSection
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material3.BottomSheetScaffold
Expand All @@ -14,14 +19,20 @@ import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState
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
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.eygraber.compose.placeholder.PlaceholderHighlight
import com.eygraber.compose.placeholder.fade
import com.eygraber.compose.placeholder.material.placeholder
import cryptowallet.composeapp.generated.resources.Res
import cryptowallet.composeapp.generated.resources.eth_icon
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -61,6 +72,9 @@ fun DashBoardScreen(
val scope = rememberCoroutineScope()
var selectedBottomSheetContent by mutableStateOf("")

val scrollState = rememberLazyListState()


BottomSheetScaffold(
sheetPeekHeight = 0.dp,
sheetSwipeEnabled = false,
Expand Down Expand Up @@ -110,14 +124,22 @@ fun DashBoardScreen(

) {
Surface(
modifier = Modifier.fillMaxSize(),
modifier = Modifier.fillMaxSize()
.navigationBarsPadding(),
color = MaterialTheme.colorScheme.background
) {
Column {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize(),
) {
DashboardScreenUpperSection(
onRefresh = {viewModel.getWallet()}
onRefresh = {
viewModel.refresh()
}
)

DashboardScreenMiddleSection(
isWalletLoading = viewModel.walletState.isLoading,
wallets = viewModel.walletState.wallets,
onNavigateToExplorer = onNavigateToExplorer,
onRequest = { content ->
Expand All @@ -137,6 +159,12 @@ fun DashBoardScreen(
}
}
)

DashboardScreenLowerSection(
isTransactionsLoading = viewModel.transactionsState.isLoading,
scrollState = scrollState,
transactions = viewModel.transactionsState.transactions,
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,32 @@ import org.example.data.remote.dto.request.CreateRequestLinkReq
import org.example.data.remote.dto.request.TransferCryptoReq
import org.example.domain.usecase.requestLink.CreateRequestLinkUseCase
import org.example.domain.usecase.requestLink.GetRequestLinkDataUseCase
import org.example.domain.usecase.wallet.GetTransactionUseCase
import org.example.presentation.screens.dashboardScreen.WalletState

class DashboardScreenViewModel(
private val getWalletUseCase: GetWalletUseCase,
private val createRequestLinkUseCase: CreateRequestLinkUseCase,
private val getRequestLinkDataUseCase: GetRequestLinkDataUseCase
private val getTransactionsUseCase: GetTransactionUseCase,
): ViewModel() {

var walletState by mutableStateOf(WalletState())
private set
var createRequestLinkState by mutableStateOf(CreateRequestLinkState())
private set
var getRequestLinkDataState by mutableStateOf(GetRequestLinkDataState())

var transactionsState by mutableStateOf(TransactionsState())
private set

var isRefreshing by mutableStateOf(false)
private set

fun refresh() {
isRefreshing = true
getWallet()
getTransactions()
isRefreshing = false
}

fun getWallet(){
viewModelScope.launch{
Expand Down Expand Up @@ -87,37 +98,62 @@ class DashboardScreenViewModel(
}
}
}
fun getRequestLinkData(){
val shortCode = createRequestLinkState.link.split("/").last()

fun getTransactions(){
viewModelScope.launch{
getRequestLinkDataUseCase.invoke(shortCode).collect{result ->
when(result) {
getTransactionsUseCase().collect { result ->
when (result) {
is Resource.Error -> {
getRequestLinkDataState = getRequestLinkDataState.copy(
transactionsState = transactionsState.copy(
isLoading = false,
error = result.message.toString()
error = result.message.toString(),
isSuccessful = false
)
println("Error: ${result.message}")
}

is Resource.Loading -> {
getRequestLinkDataState = getRequestLinkDataState.copy(
isLoading = true
transactionsState = transactionsState.copy(
isLoading = true,
isSuccessful = false
)
println("Loading")
}

is Resource.Success -> {
getRequestLinkDataState = getRequestLinkDataState.copy(
transactionsState = transactionsState.copy(
isLoading = false,
isSuccessful = true,
data = result.data
transactions = result.data?.map{transaction->
var transactionData = transaction
walletState.wallets.forEach{wallet->
transactionData = if (wallet.address == transaction.senderAddress){
transaction.copy(
transactionType = "OUT"
)
}
else if (wallet.address == transaction.receiverAddress){
transaction.copy(
transactionType = "IN"
)
}
else transaction
}
transactionData

} ?: emptyList()
)
println("Success: ${result.data}")
}
}
}
}
}



init {
getWallet()
getTransactions()
}
}
Loading

0 comments on commit add6c45

Please sign in to comment.