Skip to content

Commit 45d3b85

Browse files
EmilJiangamjiao
andauthored
Pagination (#88)
* git issue fix * advanced fitler first iteration * center icon * google-services.json * fix scrollable * pagination * test * second test * pr comments * Spacing fix * Small UI fixes * Refactor advanced filters * fix/remove unused dependencies --------- Co-authored-by: amjiao <amyjiaowang@gmail.com> Co-authored-by: Amy Wang <74884877+amjiao@users.noreply.github.com>
1 parent 08c1378 commit 45d3b85

19 files changed

Lines changed: 650 additions & 38 deletions

.github/workflows/android-lint.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@ jobs:
1515

1616
steps:
1717
- uses: actions/checkout@v3
18+
1819
- name: set up JDK 17
1920
uses: actions/setup-java@v3
2021
with:
2122
java-version: '17'
2223
distribution: 'temurin'
2324
cache: gradle
25+
26+
- name: Create google-services.json
27+
run: |
28+
echo "${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}" | base64 --decode > app/google-services.json
2429
2530
- name: Run Lint
2631
run: ./gradlew lint
27-
continue-on-error: false
32+
continue-on-error: false
33+

app/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
/build
1+
/build
2+
app/google-services.json

app/build.gradle.kts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ plugins {
66
id("com.google.dagger.hilt.android")
77
id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" // this version matches your Kotlin version
88
id("org.jetbrains.kotlin.plugin.serialization")
9-
9+
id("com.google.gms.google-services")
1010
}
1111

1212

@@ -70,7 +70,7 @@ dependencies {
7070
implementation("androidx.navigation:navigation-compose:2.8.2")
7171
implementation(libs.material3)
7272
implementation("com.google.dagger:hilt-android:2.51.1")
73-
implementation(libs.androidx.foundation.layout)
73+
implementation(libs.androidx.foundation)
7474
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
7575
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
7676
implementation("com.google.accompanist:accompanist-pager:0.24.0-alpha")
@@ -91,6 +91,8 @@ dependencies {
9191
implementation("io.coil-kt.coil3:coil-compose:3.1.0")
9292
implementation("io.coil-kt.coil3:coil-network-okhttp:3.1.0")
9393
lintChecks(libs.compose.lint.checks)
94+
implementation(platform("com.google.firebase:firebase-bom:34.3.0"))
95+
implementation("com.google.firebase:firebase-analytics")
9496
}
9597

9698
apollo {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
query PagedGames($limit: Int!, $offset: Int!) {
2+
games(limit: $limit, offset: $offset) {
3+
id
4+
city
5+
date
6+
gender
7+
location
8+
opponentId
9+
result
10+
sport
11+
state
12+
time
13+
scoreBreakdown
14+
utcDate
15+
team {
16+
id
17+
color
18+
image
19+
name
20+
}
21+
boxScore {
22+
team
23+
period
24+
time
25+
description
26+
scorer
27+
assist
28+
scoreBy
29+
corScore
30+
oppScore
31+
}
32+
}
33+
}

app/src/main/graphql/schema.graphqls

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
type Query {
2+
articles(sportsType: String): [ArticleType]
3+
24
youtubeVideos: [YoutubeVideoType]
35

46
youtubeVideo(id: String!): YoutubeVideoType
57

6-
games: [GameType]
8+
games("Number of games to return" limit: Int = 100, "Number of games to skip" offset: Int = 0): [GameType]
79

810
game(id: String!): GameType
911

10-
gameByData(city: String!, date: String!, gender: String!, location: String, opponentId: String!, sport: String!, state: String!, time: String!): GameType
12+
gameByData(city: String!, date: String!, gender: String!, location: String, opponentId: String!, sport: String!, state: String!, time: String!, ticketLink: String): GameType
1113

1214
gamesBySport(sport: String!): [GameType]
1315

@@ -22,6 +24,30 @@ type Query {
2224
teamByName(name: String!): TeamType
2325
}
2426

27+
"""
28+
A GraphQL type representing a news article.
29+
30+
Attributes:
31+
- title: The title of the article
32+
- image: The filename of the article's main image
33+
- sports_type: The specific sport category
34+
- published_at: The publication date
35+
- url: The URL to the full article
36+
"""
37+
type ArticleType {
38+
id: String
39+
40+
title: String!
41+
42+
image: String
43+
44+
sportsType: String!
45+
46+
publishedAt: String!
47+
48+
url: String!
49+
}
50+
2551
"""
2652
A GraphQL type representing a YouTube video.
2753
@@ -42,6 +68,8 @@ type YoutubeVideoType {
4268

4369
thumbnail: String!
4470

71+
b64Thumbnail: String!
72+
4573
url: String!
4674

4775
publishedAt: String!
@@ -63,6 +91,7 @@ Attributes:
6391
- `time`: The time of the game. (optional)
6492
- `box_score`: The box score of the game.
6593
- `score_breakdown`: The score breakdown of the game.
94+
- `ticket_link`: The ticket link of the game. (optional)
6695
"""
6796
type GameType {
6897
id: String
@@ -90,6 +119,10 @@ type GameType {
90119
scoreBreakdown: [[String]]
91120

92121
team: TeamType
122+
123+
utcDate: String
124+
125+
ticketLink: String
93126
}
94127

95128
"""
@@ -133,6 +166,7 @@ Attributes:
133166
- `id`: The ID of the team (optional).
134167
- `color`: The color of the team.
135168
- `image`: The image of the team (optional).
169+
- `b64_image`: The base64 encoded image of the team (optional).
136170
- `name`: The name of the team.
137171
"""
138172
type TeamType {
@@ -142,24 +176,31 @@ type TeamType {
142176

143177
image: String
144178

179+
b64Image: String
180+
145181
name: String!
146182
}
147183

148184
type Mutation {
149185
"""
150186
Creates a new game.
151187
"""
152-
createGame(boxScore: String, city: String!, date: String!, gender: String!, location: String, opponentId: String!, result: String, scoreBreakdown: String, sport: String!, state: String!, time: String!): CreateGame
188+
createGame(boxScore: String, city: String!, date: String!, gender: String!, location: String, opponentId: String!, result: String, scoreBreakdown: String, sport: String!, state: String!, ticketLink: String, time: String!, utcDate: String): CreateGame
153189

154190
"""
155191
Creates a new team.
156192
"""
157-
createTeam(color: String!, image: String, name: String!): CreateTeam
193+
createTeam(b64Image: String, color: String!, image: String, name: String!): CreateTeam
158194

159195
"""
160196
Creates a new youtube video.
161197
"""
162-
createYoutubeVideo(description: String!, id: String!, publishedAt: String!, thumbnail: String!, title: String!, url: String!): CreateYoutubeVideo
198+
createYoutubeVideo(b64Thumbnail: String!, description: String!, id: String!, publishedAt: String!, thumbnail: String!, title: String!, url: String!): CreateYoutubeVideo
199+
200+
"""
201+
Creates a new article.
202+
"""
203+
createArticle(image: String, publishedAt: String!, slug: String!, sportsType: String!, title: String!, url: String!): CreateArticle
163204
}
164205

165206
type CreateGame {
@@ -174,6 +215,10 @@ type CreateYoutubeVideo {
174215
youtubeVideo: YoutubeVideoType
175216
}
176217

218+
type CreateArticle {
219+
article: ArticleType
220+
}
221+
177222
"""
178223
A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation and subscription operations.
179224
"""
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package com.cornellappdev.score.components
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.padding
8+
import androidx.compose.material3.ExperimentalMaterial3Api
9+
import androidx.compose.material3.ModalBottomSheet
10+
import androidx.compose.material3.SheetState
11+
import androidx.compose.material3.Text
12+
import androidx.compose.runtime.Composable
13+
import androidx.compose.runtime.getValue
14+
import androidx.compose.runtime.mutableStateOf
15+
import androidx.compose.runtime.remember
16+
import androidx.compose.runtime.setValue
17+
import androidx.compose.ui.Modifier
18+
import androidx.compose.ui.graphics.Color
19+
import androidx.compose.ui.text.style.TextAlign
20+
import androidx.compose.ui.unit.dp
21+
import androidx.compose.ui.unit.sp
22+
23+
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class)
24+
@Composable
25+
fun AdvancedFilterBottomSheet(
26+
sheetState: SheetState,
27+
onDismiss: () -> Unit,
28+
onApply: (
29+
price: PriceFilter?,
30+
location: LocationFilter?,
31+
date: DateFilter?
32+
) -> Unit,
33+
onReset: () -> Unit
34+
) {
35+
var selectedPrice by remember { mutableStateOf<PriceFilter?>(null) }
36+
var selectedLocation by remember { mutableStateOf<LocationFilter?>(null) }
37+
var selectedDate by remember { mutableStateOf<DateFilter?>(null) }
38+
39+
ModalBottomSheet(
40+
onDismissRequest = onDismiss,
41+
sheetState = sheetState,
42+
containerColor = Color.White
43+
) {
44+
Column(
45+
modifier = Modifier
46+
.fillMaxWidth()
47+
.padding(horizontal = 16.dp)
48+
.padding(top = 32.dp, bottom = 24.dp),
49+
verticalArrangement = Arrangement.spacedBy(32.dp)
50+
) {
51+
Column(
52+
verticalArrangement = Arrangement.spacedBy(20.dp),
53+
modifier = Modifier.padding(end = 12.dp)
54+
) {
55+
ExpandableSection(
56+
title = "Price",
57+
options = PriceFilter.entries,
58+
selectedOption = selectedPrice,
59+
onOptionSelected = { selectedPrice = it }
60+
)
61+
62+
ExpandableSection(
63+
title = "Location",
64+
options = LocationFilter.entries,
65+
selectedOption = selectedLocation,
66+
onOptionSelected = { selectedLocation = it }
67+
)
68+
69+
ExpandableSection(
70+
title = "Date of Game",
71+
options = DateFilter.entries,
72+
selectedOption = selectedDate,
73+
onOptionSelected = { selectedDate = it }
74+
)
75+
}
76+
77+
Column(verticalArrangement = Arrangement.spacedBy(16.dp)) {
78+
ButtonPrimary(
79+
text = "Apply",
80+
icon = null,
81+
modifier = Modifier.fillMaxWidth(),
82+
onClick = {
83+
onApply(
84+
selectedPrice,
85+
selectedLocation,
86+
selectedDate
87+
)
88+
onDismiss()
89+
}
90+
)
91+
92+
Text(
93+
text = "Reset",
94+
fontSize = 14.sp,
95+
modifier = Modifier
96+
.fillMaxWidth()
97+
.clickable {
98+
selectedPrice = null
99+
selectedLocation = null
100+
selectedDate = null
101+
onReset()
102+
onDismiss()
103+
},
104+
textAlign = TextAlign.Center
105+
)
106+
}
107+
}
108+
}
109+
}

app/src/main/java/com/cornellappdev/score/components/ButtonPrimary.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ import com.cornellappdev.score.theme.Style.bodyMedium
1818
import com.cornellappdev.score.theme.White
1919

2020
@Composable
21-
fun ButtonPrimary(text: String, icon: Painter?, onClick: () -> Unit = {}) {
22-
Button(onClick = onClick,
21+
fun ButtonPrimary(
22+
text: String,
23+
icon: Painter?,
24+
modifier: Modifier = Modifier,
25+
onClick: () -> Unit = {}
26+
) {
27+
Button(
28+
onClick = onClick,
2329
colors = ButtonDefaults.buttonColors(containerColor = CrimsonPrimary),
30+
modifier = modifier,
2431
contentPadding = PaddingValues(12.dp)
2532
) {
2633
if (icon != null) {
@@ -32,7 +39,9 @@ fun ButtonPrimary(text: String, icon: Painter?, onClick: () -> Unit = {}) {
3239
.height(24.dp),
3340
colorFilter = ColorFilter.tint(White)
3441
)
35-
Spacer(modifier = Modifier.width(8.dp))
42+
if (text.isNotEmpty()) {
43+
Spacer(modifier = Modifier.width(8.dp))
44+
}
3645
}
3746
Text(text = text, style = bodyMedium.copy(color = White))
3847
}

0 commit comments

Comments
 (0)