diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt index ea7434a1f5..b8cd9919de 100644 --- a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewActivity.kt @@ -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()) + } + }) + } + } + } +} diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt new file mode 100644 index 0000000000..7f957032a0 --- /dev/null +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreen.kt @@ -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, + 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 +) diff --git a/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt new file mode 100644 index 0000000000..3c493457ed --- /dev/null +++ b/app/src/main/java/com/kickstarter/features/pledgedprojectsoverview/viewmodel/PledgedProjectsOverviewViewModel.kt @@ -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.empty()) + private val totalAlerts = MutableStateFlow(0) + + val ppoCardsState: StateFlow> = ppoCards.asStateFlow() + val totalAlertsState: StateFlow = totalAlerts.asStateFlow() + + class Factory(private val environment: Environment) : + ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + return PledgedProjectsOverviewViewModel(environment) as T + } + } +} diff --git a/app/src/main/res/layout/discovery_drawer_logged_in_view.xml b/app/src/main/res/layout/discovery_drawer_logged_in_view.xml index 9288d5127a..4eb32338e9 100644 --- a/app/src/main/res/layout/discovery_drawer_logged_in_view.xml +++ b/app/src/main/res/layout/discovery_drawer_logged_in_view.xml @@ -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"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 769fd58aeb..d62390b71e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,4 +88,8 @@ This project was successfully funded on %{deadline}, but you can still pledge for available rewards. + + Project Alerts + Alerts (%1$s) + diff --git a/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt new file mode 100644 index 0000000000..acb7f6725c --- /dev/null +++ b/app/src/test/java/com/kickstarter/features/pledgedprojectsoverview/ui/PledgedProjectsOverviewScreenTest.kt @@ -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) + } +}