Skip to content

Commit

Permalink
feat: Home Screen with jetpack compose
Browse files Browse the repository at this point in the history
  • Loading branch information
therajanmaurya committed Oct 31, 2023
1 parent 7c0e18d commit 603919e
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 191 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ ext {
buildToolsVersion = '30.0.3'
kotlinVersion = "1.9.10" // 1.9.10
compose_version = '1.5.4'
lifecycle_version = '2.6.2'
lifecycleExtensionsVersion = '2.2.0'
activity_version = '1.5.0'
fragment_version = '1.5.0'

// App dependencies
supportLibraryVersion = '28.0.0'
Expand Down
9 changes: 9 additions & 0 deletions mifospay/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ dependencies {

implementation 'androidx.appcompat:appcompat:1.6.1'
implementation "androidx.core:core-ktx:1.12.0"
implementation "androidx.activity:activity-ktx:$activity_version"
implementation "androidx.fragment:fragment-ktx:$fragment_version"
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
implementation 'androidx.media:media:1.6.0'
Expand All @@ -67,6 +69,13 @@ dependencies {
implementation "androidx.compose.ui:ui:$compose_version"
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version")

// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-extensions:$rootProject.lifecycleExtensionsVersion"

implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package org.mifos.mobilewallet.mifospay.home.presenter

import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import org.mifos.mobilewallet.core.base.TaskLooper
import org.mifos.mobilewallet.core.base.UseCase.UseCaseCallback
import org.mifos.mobilewallet.core.base.UseCaseFactory
import org.mifos.mobilewallet.core.base.UseCaseHandler
import org.mifos.mobilewallet.core.domain.model.Account
import org.mifos.mobilewallet.core.domain.model.Transaction
import org.mifos.mobilewallet.core.domain.usecase.account.FetchAccount
import org.mifos.mobilewallet.core.domain.usecase.account.FetchAccountTransactions
Expand All @@ -21,10 +27,11 @@ import javax.inject.Inject
/**
* Created by naman on 17/8/17.
*/
class HomePresenter @Inject constructor(
@HiltViewModel
class HomeViewModel @Inject constructor(
private val mUsecaseHandler: UseCaseHandler, private val localRepository: LocalRepository,
private val preferencesHelper: PreferencesHelper
) : BaseHomeContract.HomePresenter, TransactionsHistoryAsync {
) : ViewModel(), BaseHomeContract.HomePresenter, TransactionsHistoryAsync {

@JvmField
@Inject
Expand All @@ -48,6 +55,10 @@ class HomePresenter @Inject constructor(
private var mHomeView: HomeView? = null
private var transactionList: List<Transaction>? = null

// Expose screen UI state
private val _homeUIState = MutableStateFlow(HomeUiState())
val homeUIState: StateFlow<HomeUiState> = _homeUIState.asStateFlow()

override fun attachView(baseView: BaseView<*>?) {
mHomeView = baseView as HomeView?
mHomeView?.setPresenter(this)
Expand All @@ -60,6 +71,11 @@ class HomePresenter @Inject constructor(
object : UseCaseCallback<FetchAccount.ResponseValue?> {
override fun onSuccess(response: FetchAccount.ResponseValue?) {
preferencesHelper.accountId = response?.account?.id

_homeUIState.update { currentState ->
currentState.copy(account = response?.account)
}

mHomeView?.setAccountBalance(response?.account)
response?.account?.id?.let { transactionsHistory?.fetchTransactionsHistory(it) }
mHomeView?.hideSwipeProgress()
Expand Down Expand Up @@ -93,12 +109,18 @@ class HomePresenter @Inject constructor(
0,
Constants.HOME_HISTORY_TRANSACTIONS_LIMIT + existingItemCount
)
_homeUIState.update { currentState ->
currentState.copy(transactions = showList ?: emptyList())
}
mHomeView?.showTransactionsHistory(showList)
mHomeView?.showBottomSheetActionButton()
} else {
if (transactionsAmount <= Constants.HOME_HISTORY_TRANSACTIONS_LIMIT
&& transactionsAmount > 0
) {
_homeUIState.update { currentState ->
currentState.copy(transactions = transactionList ?: emptyList())
}
mHomeView?.showTransactionsHistory(transactionList)
mHomeView?.hideBottomSheetActionButton()
} else {
Expand All @@ -115,4 +137,9 @@ class HomePresenter @Inject constructor(
handleTransactionsHistory(existingItemCount)
}
}
}
}

data class HomeUiState(
val account: Account? = null,
val transactions: List<Transaction> = emptyList(),
)
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
package org.mifos.mobilewallet.mifospay.home.ui

import android.os.Bundle
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import androidx.transition.TransitionManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.fragment.app.viewModels
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import butterknife.BindView
import butterknife.ButterKnife
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import dagger.hilt.android.AndroidEntryPoint
import org.mifos.mobilewallet.core.domain.model.Account
import org.mifos.mobilewallet.core.domain.model.Transaction
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.base.BaseFragment
import org.mifos.mobilewallet.mifospay.databinding.FragmentHomeBinding
import org.mifos.mobilewallet.mifospay.history.ui.adapter.HistoryAdapter
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract
import org.mifos.mobilewallet.mifospay.home.BaseHomeContract.HomeView
import org.mifos.mobilewallet.mifospay.home.presenter.HomePresenter
import org.mifos.mobilewallet.mifospay.home.presenter.HomeViewModel
import org.mifos.mobilewallet.mifospay.utils.Constants
import org.mifos.mobilewallet.mifospay.utils.Toaster
import org.mifos.mobilewallet.mifospay.utils.Utils.getFormattedAccountBalance
Expand All @@ -35,9 +38,7 @@ import javax.inject.Inject
@AndroidEntryPoint
class HomeFragment : BaseFragment(), HomeView {

@JvmField
@Inject
var mPresenter: HomePresenter? = null
private val homeViewModel: HomeViewModel by viewModels()

private var mHomePresenter: BaseHomeContract.HomePresenter? = null

Expand Down Expand Up @@ -96,14 +97,31 @@ class HomeFragment : BaseFragment(), HomeView {
private var account: Account? = null
private var accountBalance: String? = null

private lateinit var binding: FragmentHomeBinding

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val rootView = inflater.inflate(R.layout.fragment_home, container, false)
): View {
binding = FragmentHomeBinding.inflate(inflater, container, false)
setToolbarTitle(Constants.HOME)
ButterKnife.bind(this, rootView)
mPresenter?.attachView(this)
ButterKnife.bind(this, binding.root)
homeViewModel.attachView(this)

binding.homeCompose.apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnLifecycleDestroyed(viewLifecycleOwner))
setContent {
HomeScreenDashboard(
homeViewModel,
onRequest = {

},
onPay = {

})
}
}

setUpSwipeRefresh()
setupUi()
showSwipeProgress()
Expand All @@ -128,7 +146,7 @@ class HomeFragment : BaseFragment(), HomeView {
homeScreenContainer?.let { it1 -> TransitionManager.beginDelayedTransition(it1) }
mHistoryAdapter?.let { it1 -> mHomePresenter?.showMoreHistory(it1.itemCount) }
}
return rootView
return binding.root
}

private fun setUpSwipeRefresh() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,44 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.getValue
import androidx.compose.ui.text.style.TextAlign
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.mifos.mobilewallet.core.domain.model.Account
import org.mifos.mobilewallet.core.domain.model.Transaction
import org.mifos.mobilewallet.core.domain.model.TransactionType
import org.mifos.mobilewallet.mifospay.R
import org.mifos.mobilewallet.mifospay.home.presenter.HomeUiState
import org.mifos.mobilewallet.mifospay.home.presenter.HomeViewModel
import org.mifos.mobilewallet.mifospay.theme.MifosTheme
import org.mifos.mobilewallet.mifospay.theme.border
import org.mifos.mobilewallet.mifospay.theme.lightGrey
import org.mifos.mobilewallet.mifospay.theme.styleMedium16sp
import org.mifos.mobilewallet.mifospay.utils.Utils

@Composable
fun HomeScreenDashboard(
homeViewModel: HomeViewModel = hiltViewModel(),
onRequest: () -> Unit,
onPay: () -> Unit
) {
val homeUIState by homeViewModel
.homeUIState
.collectAsStateWithLifecycle()

HomeScreen(
homeUIState.account,
homeUIState.transactions,
onRequest = onRequest,
onPay = onPay
)
}

@Composable
fun HomeScreen(
account: Account?,
transactions: List<Transaction>,
onRequest: () -> Unit,
onPay: () -> Unit
) {
Expand All @@ -54,7 +81,7 @@ fun HomeScreen(
Card(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
.height(225.dp)
.padding(top = 20.dp, bottom = 32.dp),
colors = CardDefaults.cardColors(containerColor = Color.Black)
) {
Expand All @@ -64,24 +91,34 @@ fun HomeScreen(
.padding(start = 36.dp),
verticalArrangement = Arrangement.Center
) {
val walletBalanceLabel =
if (account != null) "(${account.currency?.displayLabel})" else ""
Text(
text = "Wallet Balance (NGN)",
text = "Wallet Balance $walletBalanceLabel",
style = TextStyle(
fontSize = 12.sp,
fontWeight = FontWeight.W400,
color = lightGrey
)
)
Spacer(modifier = Modifier.height(10.dp))
val accountBalance = if (account != null) Utils.getFormattedAccountBalance(
account.balance, account.currency?.code
) else "0"
Text(
text = "₦ 3000",
text = accountBalance,
style = TextStyle(
fontSize = 42.sp,
fontWeight = FontWeight(600),
color = Color.White
)
)
Spacer(modifier = Modifier.height(10.dp))
val currencyEqual = if (account != null) {
"${account.currency.code}1 ${account.currency?.displayLabel}"
} else ""
Text(
text = "=$3.90 (USD)",
text = currencyEqual,
style = TextStyle(
fontSize = 12.sp,
fontWeight = FontWeight(500),
Expand Down Expand Up @@ -110,21 +147,18 @@ fun HomeScreen(
onPay.invoke()
}
}
Text(
modifier = Modifier.padding(top = 32.dp),
text = "Recent Transactions",
style = styleMedium16sp
)
Spacer(modifier = Modifier.height(16.dp))
LazyColumn {
val transactions = arrayListOf<Transaction>().apply {
add(Transaction())
add(Transaction())
add(Transaction())
add(Transaction())
}
items(transactions) { transaction ->
ItemTransaction(transaction = transaction)

if (transactions.isNotEmpty()) {
Text(
modifier = Modifier.padding(top = 32.dp),
text = "Recent Transactions",
style = styleMedium16sp
)
Spacer(modifier = Modifier.height(16.dp))
LazyColumn {
items(transactions) { transaction ->
ItemTransaction(transaction = transaction)
}
}
}
}
Expand Down Expand Up @@ -172,17 +206,23 @@ fun ItemTransaction(transaction: Transaction) {
horizontalArrangement = Arrangement.Absolute.SpaceBetween
) {
Image(
modifier = Modifier.size(20.dp).padding(top = 2.dp),
painter = painterResource(id = when(transaction.transactionType) {
TransactionType.DEBIT -> R.drawable.money_out
TransactionType.CREDIT -> R.drawable.money_in
else -> R.drawable.money_in
}),
modifier = Modifier
.size(20.dp)
.padding(top = 2.dp),
painter = painterResource(
id = when (transaction.transactionType) {
TransactionType.DEBIT -> R.drawable.money_out
TransactionType.CREDIT -> R.drawable.money_in
else -> R.drawable.money_in
}
),
contentDescription = null,
colorFilter = ColorFilter.tint(Color.Black)
)
Column(
modifier = Modifier.padding(start = 32.dp).weight(.3f)
modifier = Modifier
.padding(start = 32.dp)
.weight(.3f)
) {
Text(
text = "Payment Title",
Expand All @@ -198,7 +238,8 @@ fun ItemTransaction(transaction: Transaction) {
style = TextStyle(
fontSize = 10.sp,
fontWeight = FontWeight(400),
color = Color(0x66000000))
color = Color(0x66000000)
)
)
}
Text(
Expand All @@ -223,7 +264,7 @@ fun ItemTransactionPreview() {
@Preview(showSystemUi = true, device = "id:pixel_5")
@Composable
fun HomeScreenPreview() {
HomeScreen({}, {})
HomeScreen(null, listOf(), {}, {})
}

@Preview
Expand Down
Loading

0 comments on commit 603919e

Please sign in to comment.