Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Compose migration #568

Draft
wants to merge 27 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1039f2b
Add M3 theme
Goooler Mar 25, 2024
b5ca9de
Add DemoScaffold
Goooler Mar 25, 2024
659f5e5
Move VM initialization into Composable
Goooler Mar 26, 2024
fef5663
Merge remote-tracking branch 'origin/trunk' into compose-migration
Goooler Mar 31, 2024
28e1805
Merge remote-tracking branch 'origin/trunk' into compose-migration
Goooler Apr 1, 2024
050fe24
Fix detekt
Goooler Apr 1, 2024
196cb36
Use modifier param
Goooler Apr 1, 2024
ab543b0
Add PaddingValues.copy
Goooler Apr 1, 2024
9facbb9
Migrate PullToRefresh to M3
Goooler Apr 1, 2024
9ff9ddb
Cleanup asStateFlow
Goooler Apr 1, 2024
e478df0
Merge remote-tracking branch 'origin/trunk' into compose-migration
Goooler Apr 1, 2024
2fcaafe
Merge branch 'refs/heads/trunk' into compose-migration
Goooler Apr 6, 2024
ca6d70c
Launcher DemoApp by default
Goooler Apr 6, 2024
b9c4622
Exported
Goooler Apr 6, 2024
c49d772
List and anim
Goooler Apr 6, 2024
992489f
Preview
Goooler Apr 6, 2024
8739913
Theme
Goooler Apr 6, 2024
5df5c37
Fix detekt
Goooler Apr 6, 2024
6374ea6
Adjust
Goooler Apr 6, 2024
944518d
Merge remote-tracking branch 'refs/remotes/origin/trunk' into compose…
Goooler Apr 10, 2024
8ab111c
Merge remote-tracking branch 'refs/remotes/origin/trunk' into compose…
Goooler Apr 11, 2024
e054f0e
Merge remote-tracking branch 'refs/remotes/origin/trunk' into compose…
Goooler Apr 24, 2024
6f9a8a0
Merge branch 'refs/heads/trunk' into compose-migration
Goooler May 1, 2024
c9da8ca
Merge remote-tracking branch 'refs/remotes/origin/trunk' into compose…
Goooler May 14, 2024
76502c1
Merge branch 'refs/heads/trunk' into compose-migration
Goooler May 17, 2024
8546123
Merge branch 'trunk' into compose-migration
Goooler Jun 28, 2024
8d10b1c
Merge branch 'refs/heads/trunk' into compose-migration
Goooler Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion biz/detail/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<activity android:name=".ui.RepoDetailActivity" />
<activity
android:name=".ui.RepoDetailActivity"
android:exported="true" />
</application>

</manifest>
10 changes: 10 additions & 0 deletions biz/detail/src/main/kotlin/io/goooler/demoapp/detail/ui/Color.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@file:Suppress("MagicNumber")

package io.goooler.demoapp.detail.ui

import androidx.compose.ui.graphics.Color

val Navy = Color(0xFF073042)
val Blue = Color(0xFF4285F4)
val LightBlue = Color(0xFFD7EFFE)
val Chartreuse = Color(0xFFEFF7CF)
131 changes: 0 additions & 131 deletions biz/detail/src/main/kotlin/io/goooler/demoapp/detail/ui/DetailPage.kt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package io.goooler.demoapp.detail.ui

import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Share
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import io.goooler.demoapp.common.util.getQuantityString
import io.goooler.demoapp.common.util.showToast
import io.goooler.demoapp.detail.R
import io.goooler.demoapp.detail.model.RepoDetailModel
import io.goooler.demoapp.detail.vm.DetailViewModel

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DetailScreenWithSwipeRefresh(
modifier: Modifier = Modifier,
vm: DetailViewModel = viewModel(),
) {
val model by vm.repoDetailModel.collectAsState()
val isRefreshing by vm.isRefreshing.collectAsState()
val refreshState = rememberPullToRefreshState()

if (refreshState.isRefreshing) {
LaunchedEffect(true) {
// fetch something
vm.refresh()
if (!isRefreshing) {
refreshState.endRefresh()
}
}
}

Surface(
color = MaterialTheme.colorScheme.surface,
modifier = modifier.padding(horizontal = 10.dp),
) {
Box(Modifier.nestedScroll(refreshState.nestedScrollConnection)) {
DetailList(model, vm::fork)

PullToRefreshContainer(
modifier = Modifier.align(Alignment.TopCenter),
state = refreshState,
)
}
}
}

@Composable
private fun DetailList(
model: RepoDetailModel,
onForkClick: () -> Unit = {},
) {
LazyColumn {
@Suppress("MagicNumber")
val models = List(10) { model }
items(models) { model ->
DetailCard(model = model, onForkClick = onForkClick)
}
}
}

@Composable
private fun DetailCard(
model: RepoDetailModel,
modifier: Modifier = Modifier,
onForkClick: () -> Unit = {},
) {
var isDescExpanded by rememberSaveable { mutableStateOf(false) }

Card(
modifier = modifier.padding(8.dp),
) {
Column(
modifier = Modifier
.padding(12.dp)
.animateContentSize(
animationSpec = spring(
dampingRatio = Spring.DampingRatioMediumBouncy,
stiffness = Spring.StiffnessLow,
),
),
) {
Text(
text = model.fullName,
style = MaterialTheme.typography.titleLarge.copy(
fontWeight = FontWeight.SemiBold,
),
maxLines = 1,
)
Spacer(modifier = Modifier.height(5.dp))
Text(
text = model.description,
style = MaterialTheme.typography.bodyLarge,
maxLines = if (isDescExpanded) Int.MAX_VALUE else 1,
modifier = Modifier.clickable {
isDescExpanded = !isDescExpanded
},
)
Spacer(modifier = Modifier.height(5.dp))
Row {
Button(
modifier = Modifier.weight(1f),
onClick = {
R.plurals.detail_star_count_tip.getQuantityString(model.starsCount)?.showToast()
},
) {
Icon(
Icons.Filled.Star,
contentDescription = "Star",
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(model.starsCount.toString())
}
Spacer(modifier = Modifier.width(20.dp))
Button(
modifier = Modifier.weight(1f),
onClick = onForkClick,
) {
Icon(
Icons.Filled.Share,
contentDescription = "Fork",
modifier = Modifier.size(ButtonDefaults.IconSize),
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(model.forksCount.toString())
}
}
Spacer(modifier = Modifier.height(5.dp))
}
}
}

@PreviewDemo
@Composable
private fun DetailListPreview() {
@Suppress("MagicNumber")
val model = RepoDetailModel(
"Compose/Demo",
"Jetpack Compose is Android’s modern toolkit for building native UI. " +
"It simplifies and accelerates UI development on Android. " +
"Quickly bring your app to life with less code, powerful tools, and intuitive Kotlin APIs.",
"Apache",
99,
1,
2,
)
DetailList(model)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package io.goooler.demoapp.detail.ui
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.Modifier
import io.goooler.demoapp.base.core.BaseActivity
import io.goooler.demoapp.detail.vm.DetailViewModel

Expand All @@ -15,15 +15,15 @@ class RepoDetailActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent.getStringExtra(FULL_NAME)?.let {
vm.fullName = it
vm.refresh()
}
vm.fullName = intent.getStringExtra(FULL_NAME) ?: "Goooler/DemoApp"
vm.refresh()

setContent {
val model by vm.repoDetailModel.collectAsState()
val isRefreshing by vm.isRefreshing.collectAsState()
DetailPageWithSwipeRefresh(isRefreshing, vm::refresh, model, onForkClick = vm::fork)
DemoScaffold { innerPadding ->
DetailScreenWithSwipeRefresh(
modifier = Modifier.padding(innerPadding),
)
}
}
}

Expand Down
Loading