Skip to content

Commit e747613

Browse files
authored
feat(app-bar): adds top appbar (#2)
1 parent 5625869 commit e747613

File tree

14 files changed

+442
-100
lines changed

14 files changed

+442
-100
lines changed

.github/workflows/ci.yaml

+14
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,17 @@ jobs:
2121
uses: gradle/actions/setup-gradle@v4
2222
- name: Build
2323
run: ./gradlew app:assembleDebug
24+
lint:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- name: Checkout code
28+
uses: actions/checkout@v4
29+
- name: Setup Java
30+
uses: actions/setup-java@v4
31+
with:
32+
distribution: 'zulu'
33+
java-version: 17
34+
- name: Setup gradle
35+
uses: gradle/actions/setup-gradle@v4
36+
- name: Build
37+
run: ./gradlew app:spotlessCheck app:lintDebug

app/build.gradle.kts

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,10 @@ dependencies {
5252
implementation(platform(libs.androidx.compose.bom))
5353
implementation(libs.androidx.activity)
5454
implementation(libs.androidx.activity.compose)
55+
implementation(libs.androidx.compose.google.fonts)
5556
implementation(libs.androidx.compose.navigation)
5657
implementation(libs.androidx.core.ktx)
5758
implementation(libs.androidx.material3)
58-
implementation(libs.paging)
59-
implementation(libs.paging.compose)
6059
implementation(libs.androidx.ui)
6160
implementation(libs.androidx.ui.graphics)
6261
implementation(libs.androidx.ui.tooling.preview)
@@ -69,6 +68,8 @@ dependencies {
6968
implementation(libs.kotlinx.collections.immutable)
7069
implementation(libs.lifecycle.viewmodel)
7170
implementation(libs.lifecycle.viewmodel.compose)
71+
implementation(libs.paging)
72+
implementation(libs.paging.compose)
7273
implementation(libs.serialization.json)
7374
implementation(libs.timber)
7475

app/src/main/AndroidManifest.xml

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
<uses-permission android:name="android.permission.INTERNET" />
66

77
<application
8+
android:name=".PTPApplication"
89
android:allowBackup="true"
910
android:dataExtractionRules="@xml/data_extraction_rules"
1011
android:fullBackupContent="@xml/backup_rules"
1112
android:icon="@mipmap/ic_launcher"
1213
android:label="@string/app_name"
13-
android:name=".PTPApplication"
1414
android:roundIcon="@mipmap/ic_launcher_round"
1515
android:supportsRtl="true"
1616
android:theme="@style/Theme.Ptp"
17+
android:windowSoftInputMode="adjustResize"
1718
tools:targetApi="31">
1819
<activity
1920
android:name=".MainActivity"
@@ -27,4 +28,4 @@
2728
</activity>
2829
</application>
2930

30-
</manifest>
31+
</manifest>

app/src/main/java/us/kikin/android/ptp/MainActivity.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ import androidx.activity.compose.setContent
2222
import androidx.activity.enableEdgeToEdge
2323
import dagger.hilt.android.AndroidEntryPoint
2424
import us.kikin.android.ptp.navigation.SafePtpNavGraph
25-
import us.kikin.android.ptp.ui.theme.PtpTheme
25+
import us.kikin.android.ptp.ui.theme.AppTheme
2626

2727
@AndroidEntryPoint
2828
class MainActivity : ComponentActivity() {
2929
override fun onCreate(savedInstanceState: Bundle?) {
30-
super.onCreate(savedInstanceState)
3130
enableEdgeToEdge()
31+
super.onCreate(savedInstanceState)
3232
setContent {
33-
PtpTheme {
33+
AppTheme {
3434
SafePtpNavGraph()
3535
}
3636
}

app/src/main/java/us/kikin/android/ptp/carddetail/CardDetailScreen.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
4343
import coil3.compose.AsyncImage
4444
import us.kikin.android.ptp.components.Stepper
4545
import us.kikin.android.ptp.data.Card
46-
import us.kikin.android.ptp.ui.theme.PtpTheme
46+
import us.kikin.android.ptp.ui.theme.AppTheme
4747

4848
@Composable
4949
fun CardDetailScreen(
@@ -52,7 +52,7 @@ fun CardDetailScreen(
5252
viewModel: CardDetailViewModel = hiltViewModel(),
5353
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
5454
) {
55-
PtpTheme {
55+
AppTheme {
5656
Scaffold(
5757
modifier = modifier.fillMaxSize(),
5858
snackbarHost = { SnackbarHost(snackbarHostState) },

app/src/main/java/us/kikin/android/ptp/cards/CardsScreen.kt

+56-18
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,28 @@ import androidx.compose.foundation.lazy.grid.GridCells
2828
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
2929
import androidx.compose.foundation.lazy.grid.items
3030
import androidx.compose.material3.Card as MaterialCard
31+
import androidx.compose.material3.CenterAlignedTopAppBar
3132
import androidx.compose.material3.CircularProgressIndicator
33+
import androidx.compose.material3.ExperimentalMaterial3Api
34+
import androidx.compose.material3.Icon
35+
import androidx.compose.material3.IconButton
3236
import androidx.compose.material3.MaterialTheme
3337
import androidx.compose.material3.Scaffold
3438
import androidx.compose.material3.SnackbarHost
3539
import androidx.compose.material3.SnackbarHostState
3640
import androidx.compose.material3.Text
41+
import androidx.compose.material3.TopAppBarDefaults
42+
import androidx.compose.material3.rememberTopAppBarState
3743
import androidx.compose.runtime.Composable
3844
import androidx.compose.runtime.CompositionLocalProvider
3945
import androidx.compose.runtime.LaunchedEffect
4046
import androidx.compose.runtime.getValue
4147
import androidx.compose.runtime.remember
4248
import androidx.compose.ui.Modifier
4349
import androidx.compose.ui.graphics.Color
50+
import androidx.compose.ui.input.nestedscroll.nestedScroll
4451
import androidx.compose.ui.res.stringResource
52+
import androidx.compose.ui.text.style.TextOverflow
4553
import androidx.compose.ui.tooling.preview.Preview
4654
import androidx.compose.ui.unit.dp
4755
import androidx.hilt.navigation.compose.hiltViewModel
@@ -54,8 +62,13 @@ import coil3.test.FakeImage
5462
import kotlinx.collections.immutable.ImmutableList
5563
import kotlinx.collections.immutable.persistentListOf
5664
import kotlinx.collections.immutable.toPersistentList
65+
import us.kikin.android.ptp.R
5766
import us.kikin.android.ptp.data.Card
67+
import us.kikin.android.ptp.icons.PtpIcons
68+
import us.kikin.android.ptp.icons.rounded.FilterList
69+
import us.kikin.android.ptp.ui.theme.AppTheme
5870

71+
@OptIn(ExperimentalMaterial3Api::class)
5972
@Composable
6073
fun CardsScreen(
6174
onCardClick: (Card) -> Unit,
@@ -64,26 +77,51 @@ fun CardsScreen(
6477
viewModel: CardsViewModel = hiltViewModel(),
6578
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() },
6679
) {
67-
Scaffold(
68-
modifier = modifier.fillMaxSize(),
69-
snackbarHost = { SnackbarHost(snackbarHostState) },
70-
) { paddingValues ->
71-
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
80+
val scaffoldBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
81+
AppTheme {
82+
Scaffold(
83+
modifier = modifier
84+
.fillMaxSize()
85+
.nestedScroll(scaffoldBehavior.nestedScrollConnection),
86+
topBar = {
87+
CenterAlignedTopAppBar(
88+
title = {
89+
Text(
90+
text = stringResource(id = R.string.app_name),
91+
style = MaterialTheme.typography.titleLarge,
92+
maxLines = 1,
93+
overflow = TextOverflow.Ellipsis,
94+
)
95+
},
96+
actions = {
97+
IconButton(onClick = { /*TODO*/ }) {
98+
Icon(
99+
imageVector = PtpIcons.Rounded.FilterList,
100+
contentDescription = stringResource(R.string.card_list_filters),
101+
)
102+
}
103+
},
104+
)
105+
},
106+
snackbarHost = { SnackbarHost(snackbarHostState) },
107+
) { paddingValues ->
108+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
72109

73-
CardsContent(
74-
cards = uiState.cards.toPersistentList(),
75-
onCardClick = onCardClick,
76-
isLoading = uiState.isLoading,
77-
userMessage = userMessage,
78-
modifier = Modifier.padding(paddingValues),
79-
)
110+
CardsContent(
111+
cards = uiState.cards.toPersistentList(),
112+
onCardClick = onCardClick,
113+
isLoading = uiState.isLoading,
114+
userMessage = userMessage,
115+
modifier = Modifier.padding(paddingValues),
116+
)
80117

81-
// Check for user messages to display on the screen
82-
uiState.userMessage?.let { message ->
83-
val snackbarText = stringResource(message)
84-
LaunchedEffect(snackbarHostState, viewModel, message, snackbarText) {
85-
snackbarHostState.showSnackbar(snackbarText)
86-
viewModel.snackbarMessageShown()
118+
// Check for user messages to display on the screen
119+
uiState.userMessage?.let { message ->
120+
val snackbarText = stringResource(message)
121+
LaunchedEffect(snackbarHostState, viewModel, message, snackbarText) {
122+
snackbarHostState.showSnackbar(snackbarText)
123+
viewModel.snackbarMessageShown()
124+
}
87125
}
88126
}
89127
}

app/src/main/java/us/kikin/android/ptp/components/Stepper.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import androidx.compose.ui.tooling.preview.Preview
3737
import androidx.compose.ui.unit.dp
3838
import us.kikin.android.ptp.icons.PtpIcons
3939
import us.kikin.android.ptp.icons.rounded.Remove
40-
import us.kikin.android.ptp.ui.theme.PtpTheme
40+
import us.kikin.android.ptp.ui.theme.AppTheme
4141

4242
@Composable
4343
fun Stepper(
@@ -89,7 +89,7 @@ fun Stepper(
8989
@Composable
9090
@Preview
9191
internal fun StepperPreview() {
92-
PtpTheme {
92+
AppTheme {
9393
var value by remember { mutableIntStateOf(0) }
9494
Stepper(
9595
value = value,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright 2024
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package us.kikin.android.ptp.icons.rounded
18+
19+
import androidx.compose.ui.graphics.Color
20+
import androidx.compose.ui.graphics.PathFillType
21+
import androidx.compose.ui.graphics.SolidColor
22+
import androidx.compose.ui.graphics.StrokeCap
23+
import androidx.compose.ui.graphics.StrokeJoin
24+
import androidx.compose.ui.graphics.vector.ImageVector
25+
import androidx.compose.ui.graphics.vector.path
26+
import androidx.compose.ui.unit.dp
27+
import us.kikin.android.ptp.icons.PtpIcons.Rounded
28+
29+
public val Rounded.FilterList: ImageVector
30+
get() {
31+
if (_Filter_list != null) {
32+
return _Filter_list!!
33+
}
34+
_Filter_list = ImageVector.Builder(
35+
name = "Filter_list",
36+
defaultWidth = 24.dp,
37+
defaultHeight = 24.dp,
38+
viewportWidth = 960f,
39+
viewportHeight = 960f,
40+
).apply {
41+
path(
42+
fill = SolidColor(Color.Black),
43+
fillAlpha = 1.0f,
44+
stroke = null,
45+
strokeAlpha = 1.0f,
46+
strokeLineWidth = 1.0f,
47+
strokeLineCap = StrokeCap.Butt,
48+
strokeLineJoin = StrokeJoin.Miter,
49+
strokeLineMiter = 1.0f,
50+
pathFillType = PathFillType.NonZero,
51+
) {
52+
moveTo(440f, 720f)
53+
quadToRelative(-17f, 0f, -28.5f, -11.5f)
54+
reflectiveQuadTo(400f, 680f)
55+
reflectiveQuadToRelative(11.5f, -28.5f)
56+
reflectiveQuadTo(440f, 640f)
57+
horizontalLineToRelative(80f)
58+
quadToRelative(17f, 0f, 28.5f, 11.5f)
59+
reflectiveQuadTo(560f, 680f)
60+
reflectiveQuadToRelative(-11.5f, 28.5f)
61+
reflectiveQuadTo(520f, 720f)
62+
close()
63+
moveTo(280f, 520f)
64+
quadToRelative(-17f, 0f, -28.5f, -11.5f)
65+
reflectiveQuadTo(240f, 480f)
66+
reflectiveQuadToRelative(11.5f, -28.5f)
67+
reflectiveQuadTo(280f, 440f)
68+
horizontalLineToRelative(400f)
69+
quadToRelative(17f, 0f, 28.5f, 11.5f)
70+
reflectiveQuadTo(720f, 480f)
71+
reflectiveQuadToRelative(-11.5f, 28.5f)
72+
reflectiveQuadTo(680f, 520f)
73+
close()
74+
moveTo(160f, 320f)
75+
quadToRelative(-17f, 0f, -28.5f, -11.5f)
76+
reflectiveQuadTo(120f, 280f)
77+
reflectiveQuadToRelative(11.5f, -28.5f)
78+
reflectiveQuadTo(160f, 240f)
79+
horizontalLineToRelative(640f)
80+
quadToRelative(17f, 0f, 28.5f, 11.5f)
81+
reflectiveQuadTo(840f, 280f)
82+
reflectiveQuadToRelative(-11.5f, 28.5f)
83+
reflectiveQuadTo(800f, 320f)
84+
close()
85+
}
86+
}.build()
87+
return _Filter_list!!
88+
}
89+
90+
private var _Filter_list: ImageVector? = null

0 commit comments

Comments
 (0)