Updated on 2026-08-14

This commit is contained in:
Tangem 2025-12-09 17:38:17 +05:00
parent 2396225311
commit 23ddf1a665
34 changed files with 1301 additions and 226 deletions

View file

@ -59,6 +59,8 @@ dependencies {
/** Feature Apis */
implementation(projects.features.tester.api)
implementation(projects.features.pushNotifications.api)
implementation(projects.features.news.newsDetails.api)
implementation(projects.features.news.newsDetails.impl)
/* SDK */
implementation(tangemDeps.blockchain)

View file

@ -35,6 +35,11 @@ import com.tangem.feature.tester.presentation.providers.ui.BlockchainProvidersSc
import com.tangem.feature.tester.presentation.providers.viewmodel.BlockchainProvidersViewModel
import com.tangem.feature.tester.presentation.testpush.ui.TestPushScreen
import com.tangem.feature.tester.presentation.testpush.viewmodel.TestPushViewModel
import com.tangem.feature.tester.presentation.news.ui.NewsScreen
import com.tangem.feature.tester.presentation.news.viewmodel.NewsViewModel
import com.tangem.features.news.details.impl.MockArticlesFactory
import com.tangem.features.news.details.impl.ui.NewsDetailsContent
import com.tangem.features.news.details.impl.ui.NewsDetailsUM
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.collections.immutable.persistentSetOf
import javax.inject.Inject
@ -82,9 +87,10 @@ internal class TesterActivity : ComposeActivity() {
ButtonUM.TESTER_ACTIONS,
ButtonUM.TEST_PUSHES,
ButtonUM.ACCOUNTS,
ButtonUM.NEWS,
),
onButtonClick = {
val route = when (it) {
onButtonClick = { buttonUM ->
val route = when (buttonUM) {
ButtonUM.FEATURE_TOGGLES -> TesterScreen.FEATURE_TOGGLES
ButtonUM.EXCLUDED_BLOCKCHAINS -> TesterScreen.EXCLUDED_BLOCKCHAINS
ButtonUM.ENVIRONMENT_TOGGLES -> TesterScreen.ENVIRONMENTS_TOGGLES
@ -92,6 +98,7 @@ internal class TesterActivity : ComposeActivity() {
ButtonUM.TESTER_ACTIONS -> TesterScreen.TESTER_ACTIONS
ButtonUM.TEST_PUSHES -> TesterScreen.TEST_PUSHES
ButtonUM.ACCOUNTS -> TesterScreen.ACCOUNTS
ButtonUM.NEWS -> TesterScreen.NEWS
}
innerTesterRouter.open(route)
@ -162,6 +169,27 @@ internal class TesterActivity : ComposeActivity() {
AccountsScreen(state)
}
composable(route = TesterScreen.NEWS.name) {
val viewModel = hiltViewModel<NewsViewModel>().apply {
setupNavigation(innerTesterRouter)
}
val state by viewModel.uiState.collectAsStateWithLifecycle()
NewsScreen(state)
}
composable(route = TesterScreen.NEWS_DETAILS.name) {
NewsDetailsContent(
state = NewsDetailsUM(
articles = MockArticlesFactory.createMockArticles(),
selectedArticleIndex = 0,
onLikeClick = { },
onShareClick = { },
),
onBackClick = { innerTesterRouter.back() },
)
}
}
}
}

View file

@ -25,5 +25,6 @@ data class TesterMenuUM(
TESTER_ACTIONS(R.string.tester_actions),
TEST_PUSHES(R.string.test_push),
ACCOUNTS(R.string.accounts),
NEWS(R.string.news),
}
}

View file

@ -14,4 +14,6 @@ internal enum class TesterScreen {
BLOCKCHAIN_PROVIDERS,
TEST_PUSHES,
ACCOUNTS,
NEWS,
NEWS_DETAILS,
}

View file

@ -0,0 +1,16 @@
package com.tangem.feature.tester.presentation.news.state
import androidx.annotation.StringRes
import com.tangem.feature.tester.impl.R
import kotlinx.collections.immutable.ImmutableSet
data class NewsUM(
val onBackClick: () -> Unit,
val buttons: ImmutableSet<ButtonUM>,
val onButtonClick: (ButtonUM) -> Unit,
) {
enum class ButtonUM(@StringRes val textResId: Int) {
NEWS_DETAILS(R.string.news_details),
}
}

View file

@ -0,0 +1,62 @@
package com.tangem.feature.tester.presentation.news.ui
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.tangem.core.ui.components.PrimaryButton
import com.tangem.core.ui.components.appbar.AppBarWithBackButton
import com.tangem.core.ui.extensions.stringResourceSafe
import com.tangem.core.ui.res.TangemTheme
import com.tangem.feature.tester.impl.R
import com.tangem.feature.tester.presentation.news.state.NewsUM
import kotlinx.collections.immutable.ImmutableSet
@OptIn(ExperimentalFoundationApi::class)
@Composable
internal fun NewsScreen(state: NewsUM, modifier: Modifier = Modifier) {
BackHandler(onBack = state.onBackClick)
LazyColumn(
modifier = modifier
.fillMaxSize()
.background(TangemTheme.colors.background.primary),
) {
stickyHeader { AppBar(onBackClick = state.onBackClick) }
NewsButtons(buttons = state.buttons, onButtonClick = state.onButtonClick)
}
}
@Composable
private fun AppBar(onBackClick: () -> Unit) {
AppBarWithBackButton(
onBackClick = onBackClick,
text = stringResourceSafe(id = R.string.news),
containerColor = TangemTheme.colors.background.primary,
)
}
@Suppress("FunctionNaming")
private fun LazyListScope.NewsButtons(
buttons: ImmutableSet<NewsUM.ButtonUM>,
onButtonClick: (NewsUM.ButtonUM) -> Unit,
) {
items(buttons.toList()) { button ->
PrimaryButton(
text = stringResourceSafe(button.textResId),
onClick = { onButtonClick(button) },
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.fillMaxWidth(),
)
}
}

View file

@ -0,0 +1,44 @@
package com.tangem.feature.tester.presentation.news.viewmodel
import androidx.lifecycle.ViewModel
import com.tangem.feature.tester.presentation.navigation.InnerTesterRouter
import com.tangem.feature.tester.presentation.navigation.TesterScreen
import com.tangem.feature.tester.presentation.news.state.NewsUM
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject
@HiltViewModel
internal class NewsViewModel @Inject constructor() : ViewModel() {
private val _uiState = MutableStateFlow(createInitialState())
val uiState: StateFlow<NewsUM> = _uiState
private var router: InnerTesterRouter? = null
fun setupNavigation(router: InnerTesterRouter) {
this.router = router
}
private fun createInitialState(): NewsUM {
return NewsUM(
onBackClick = ::onBackClick,
buttons = persistentSetOf(
NewsUM.ButtonUM.NEWS_DETAILS,
),
onButtonClick = ::onButtonClick,
)
}
private fun onBackClick() {
router?.back()
}
private fun onButtonClick(button: NewsUM.ButtonUM) {
when (button) {
NewsUM.ButtonUM.NEWS_DETAILS -> router?.open(TesterScreen.NEWS_DETAILS)
}
}
}

View file

@ -18,4 +18,6 @@
<string name="share_logs" translatable="false">Share logs</string>
<string name="test_push" translatable="false">Test push</string>
<string name="accounts" translatable="false">Accounts</string>
<string name="news" translatable="false">News</string>
<string name="news_details" translatable="false">News details</string>
</resources>