Skip to content

Commit

Permalink
MBL-1472: Create PPO screen activity, ui, and viewmodel (#2056)
Browse files Browse the repository at this point in the history
* Create ppo screen scaffold, launch on menu item press

* linter

* remove unneeded file

* Address feedback

* linter

* Renaming

* cleanup

* fix test

---------

Co-authored-by: Leigh Douglas <[email protected]>
Co-authored-by: Yun Cheng <[email protected]>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent 6a4f779 commit 9cccf09
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,77 @@
package com.kickstarter.features.pledgedprojectsoverview.ui

import android.os.Build
import android.os.Bundle
import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.paging.compose.collectAsLazyPagingItems
import com.kickstarter.features.pledgedprojectsoverview.viewmodel.PledgedProjectsOverviewViewModel
import com.kickstarter.libs.utils.TransitionUtils
import com.kickstarter.libs.utils.extensions.getEnvironment
import com.kickstarter.libs.utils.extensions.isDarkModeEnabled
import com.kickstarter.ui.SharedPreferenceKey
import com.kickstarter.ui.activities.AppThemes
import com.kickstarter.ui.compose.designsystem.KickstarterApp
import com.kickstarter.ui.extensions.transition

class PledgedProjectsOverviewActivity : AppCompatActivity()
class PledgedProjectsOverviewActivity : AppCompatActivity() {

private lateinit var viewModelFactory: PledgedProjectsOverviewViewModel.Factory
private val viewModel: PledgedProjectsOverviewViewModel by viewModels { viewModelFactory }
private var theme = AppThemes.MATCH_SYSTEM.ordinal

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

this.getEnvironment()?.let { env ->
setContent {
viewModelFactory = PledgedProjectsOverviewViewModel.Factory(env)

theme = env.sharedPreferences()
?.getInt(SharedPreferenceKey.APP_THEME, AppThemes.MATCH_SYSTEM.ordinal)
?: AppThemes.MATCH_SYSTEM.ordinal

val darkModeEnabled = this.isDarkModeEnabled(env = env)
val lazyListState = rememberLazyListState()

val ppoCardPagingSource = viewModel.ppoCardsState.collectAsLazyPagingItems()
val totalAlerts = viewModel.totalAlertsState.collectAsStateWithLifecycle()

KickstarterApp(
useDarkTheme =
if (darkModeEnabled) {
when (theme) {
AppThemes.MATCH_SYSTEM.ordinal -> isSystemInDarkTheme()
AppThemes.DARK.ordinal -> true
AppThemes.LIGHT.ordinal -> false
else -> false
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
isSystemInDarkTheme()
} else false
) {
PledgedProjectsOverviewScreen(
modifier = Modifier,
onBackPressed = { onBackPressedDispatcher.onBackPressed() },
lazyColumnListState = lazyListState,
ppoCards = ppoCardPagingSource,
totalAlerts = totalAlerts.value
)
}

onBackPressedDispatcher.addCallback(object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
finish()
this@PledgedProjectsOverviewActivity.transition(TransitionUtils.slideInFromLeft())
}
})
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package com.kickstarter.features.pledgedprojectsoverview.ui

import android.content.res.Configuration
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.paging.PagingData
import androidx.paging.compose.LazyPagingItems
import androidx.paging.compose.collectAsLazyPagingItems
import com.kickstarter.R
import com.kickstarter.ui.compose.designsystem.KSTheme
import com.kickstarter.ui.compose.designsystem.KSTheme.colors
import com.kickstarter.ui.compose.designsystem.KSTheme.dimensions
import com.kickstarter.ui.compose.designsystem.KSTheme.typography
import com.kickstarter.ui.toolbars.compose.TopToolBar
import kotlinx.coroutines.flow.flowOf

@Composable
@Preview(name = "Light", uiMode = Configuration.UI_MODE_NIGHT_NO)
@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES)
private fun PledgedProjectsOverviewScreenPreview() {
KSTheme {
Scaffold(
backgroundColor = colors.backgroundSurfacePrimary
) { padding ->
val ppoCardList1 = (0..10).map {
PPOCardDataMock()
}
val ppoCardList = flowOf(PagingData.from(ppoCardList1)).collectAsLazyPagingItems()
PledgedProjectsOverviewScreen(
modifier = Modifier.padding(padding),
lazyColumnListState = rememberLazyListState(),
ppoCards = ppoCardList,
totalAlerts = 10,
onBackPressed = {}
)
}
}
}

@Composable
fun PledgedProjectsOverviewScreen(
modifier: Modifier,
onBackPressed: () -> Unit,
lazyColumnListState: LazyListState,
ppoCards: LazyPagingItems<PPOCardDataMock>,
totalAlerts: Int = 0
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Scaffold(
modifier = modifier,
topBar = {
TopToolBar(
title = stringResource(id = R.string.project_alerts_fpo),
titleColor = colors.textPrimary,
leftOnClickAction = onBackPressed,
leftIconColor = colors.icon,
leftIconModifier = Modifier.testTag(PledgedProjectsOverviewScreenTestTag.BACK_BUTTON.name),
backgroundColor = colors.backgroundSurfacePrimary,
)
},
backgroundColor = colors.backgroundSurfacePrimary
) { padding ->
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
.padding(
start = dimensions.paddingMedium,
end = dimensions.paddingMedium,
top = dimensions.paddingMedium
)
.padding(paddingValues = padding),
state = lazyColumnListState
) {
item {
Text(
text = stringResource(id = R.string.alerts_fpo, totalAlerts),
style = typography.title3Bold,
color = colors.textPrimary
)
}

items(
count = ppoCards.itemCount
) { index ->
Spacer(modifier = Modifier.height(dimensions.paddingMedium))

ppoCards[index]?.let {
PPOCardView(
viewType = it.viewType,
onCardClick = { },
projectName = it.projectName,
pledgeAmount = it.pledgeAmount,
imageUrl = it.imageUrl,
imageContentDescription = it.imageContentDescription,
creatorName = it.creatorName,
sendAMessageClickAction = { },
shippingAddress = it.shippingAddress,
showBadge = it.showBadge,
onActionButtonClicked = { },
onSecondaryActionButtonClicked = { },
timeNumberForAction = it.timeNumberForAction
)
}
}

item {
Spacer(modifier = Modifier.height(dimensions.paddingDoubleLarge))
}
}
}
}
}

enum class PledgedProjectsOverviewScreenTestTag {
BACK_BUTTON,
}

// For preview purposes only, will remove once we have the PPO Card payload model from graph
data class PPOCardDataMock(
val viewType: PPOCardViewType = PPOCardViewType.FIX_PAYMENT,
val onCardClick: () -> Unit = { },
val projectName: String = "This is a project name",
val pledgeAmount: String = "$14.00",
val imageUrl: String = "",
val imageContentDescription: String = "",
val creatorName: String = "Creator Name",
val sendAMessageClickAction: () -> Unit = { },
val shippingAddress: String = "",
val showBadge: Boolean = true,
val onActionButtonClicked: () -> Unit = {},
val onSecondaryActionButtonClicked: () -> Unit = {},
val timeNumberForAction: Int = 25
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.kickstarter.features.pledgedprojectsoverview.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.paging.PagingData
import com.kickstarter.features.pledgedprojectsoverview.ui.PPOCardDataMock
import com.kickstarter.libs.Environment
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow

class PledgedProjectsOverviewViewModel(environment: Environment) : ViewModel() {

private val ppoCards = MutableStateFlow<PagingData<PPOCardDataMock>>(PagingData.empty())
private val totalAlerts = MutableStateFlow<Int>(0)

val ppoCardsState: StateFlow<PagingData<PPOCardDataMock>> = ppoCards.asStateFlow()
val totalAlertsState: StateFlow<Int> = totalAlerts.asStateFlow()

class Factory(private val environment: Environment) :
ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return PledgedProjectsOverviewViewModel(environment) as T
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
style="@style/DrawerTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/profile_projects_backed_projects"
android:text="@string/project_alerts_fpo"
app:drawableStartCompat="@drawable/ic_notification_bell"
android:visibility="gone"/>

Expand Down
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,8 @@
<!-- TODO: Get translations for this and put it in i18n, then remove -->
<string name="project_status_project_was_successfully_funded_on_deadline_but_you_can_still_pledge_for_available_rewards" formatted="false">This project was successfully funded on %{deadline}, but you can still pledge for available rewards.</string>

<!-- PPO Mock Strings -->
<string name="project_alerts_fpo">Project Alerts</string>
<string name="alerts_fpo">Alerts (%1$s)</string>

</resources>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.kickstarter.features.pledgedprojectsoverview.ui

import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.ui.Modifier
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import androidx.paging.PagingData
import androidx.paging.compose.collectAsLazyPagingItems
import com.kickstarter.KSRobolectricTestCase
import com.kickstarter.ui.compose.designsystem.KSTheme
import kotlinx.coroutines.flow.flowOf
import org.junit.Test

class PledgedProjectsOverviewScreenTest : KSRobolectricTestCase() {

private val backButton =
composeTestRule.onNodeWithTag(PledgedProjectsOverviewScreenTestTag.BACK_BUTTON.name)
@Test
fun testBackButtonClick() {
var backClickedCount = 0
composeTestRule.setContent {
val ppoCardList1 = (0..10).map {
PPOCardDataMock()
}
val ppoCardList = flowOf(PagingData.from(ppoCardList1)).collectAsLazyPagingItems()

KSTheme {
PledgedProjectsOverviewScreen(
modifier = Modifier,
onBackPressed = { backClickedCount++ },
lazyColumnListState = rememberLazyListState(),
ppoCards = ppoCardList
)
}
}

backButton.performClick()
assertEquals(1, backClickedCount)
}
}

0 comments on commit 9cccf09

Please sign in to comment.