Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 7 additions & 1 deletion .github/workflows/android-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,19 @@ jobs:

steps:
- uses: actions/checkout@v3

- name: set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
cache: gradle

- name: Create google-services.json
run: |
echo "${{ secrets.GOOGLE_SERVICES_JSON_BASE64 }}" | base64 --decode > app/google-services.json

- name: Run Lint
run: ./gradlew lint
continue-on-error: false
continue-on-error: false

3 changes: 2 additions & 1 deletion app/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
/build
/build
app/google-services.json
7 changes: 5 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
id("com.google.dagger.hilt.android")
id("org.jetbrains.kotlin.plugin.compose") version "2.0.0" // this version matches your Kotlin version
id("org.jetbrains.kotlin.plugin.serialization")

id("com.google.gms.google-services")
}


Expand Down Expand Up @@ -72,6 +72,8 @@ dependencies {
implementation(libs.material3)
implementation("com.google.dagger:hilt-android:2.51.1")
implementation(libs.androidx.material3)
implementation(libs.androidx.foundation)
implementation(libs.androidx.compose.material3.material3)
kapt("com.google.dagger:hilt-android-compiler:2.51.1")
implementation("androidx.hilt:hilt-navigation-compose:1.0.0")
implementation("com.google.accompanist:accompanist-pager:0.24.0-alpha")
Expand All @@ -88,12 +90,13 @@ dependencies {
debugImplementation("androidx.compose.ui:ui-tooling")
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation(libs.apollo.runtime)
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1")
implementation(libs.apollo.runtime)
implementation("io.coil-kt.coil3:coil-compose:3.1.0")
implementation("io.coil-kt.coil3:coil-network-okhttp:3.1.0")
lintChecks(libs.compose.lint.checks)
implementation(platform("com.google.firebase:firebase-bom:34.3.0"))
implementation("com.google.firebase:firebase-analytics")
}

apollo {
Expand Down
33 changes: 33 additions & 0 deletions app/src/main/graphql/FragmentedGame.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
query PagedGames($limit: Int!, $offset: Int!) {
games(limit: $limit, offset: $offset) {
id
city
date
gender
location
opponentId
result
sport
state
time
scoreBreakdown
utcDate
team {
id
color
image
name
}
boxScore {
team
period
time
description
scorer
assist
scoreBy
corScore
oppScore
}
}
}
55 changes: 50 additions & 5 deletions app/src/main/graphql/schema.graphqls
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
type Query {
articles(sportsType: String): [ArticleType]

youtubeVideos: [YoutubeVideoType]

youtubeVideo(id: String!): YoutubeVideoType

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

game(id: String!): GameType

gameByData(city: String!, date: String!, gender: String!, location: String, opponentId: String!, sport: String!, state: String!, time: String!): GameType
gameByData(city: String!, date: String!, gender: String!, location: String, opponentId: String!, sport: String!, state: String!, time: String!, ticketLink: String): GameType

gamesBySport(sport: String!): [GameType]

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

"""
A GraphQL type representing a news article.

Attributes:
- title: The title of the article
- image: The filename of the article's main image
- sports_type: The specific sport category
- published_at: The publication date
- url: The URL to the full article
"""
type ArticleType {
id: String

title: String!

image: String

sportsType: String!

publishedAt: String!

url: String!
}

"""
A GraphQL type representing a YouTube video.

Expand All @@ -42,6 +68,8 @@ type YoutubeVideoType {

thumbnail: String!

b64Thumbnail: String!

url: String!

publishedAt: String!
Expand All @@ -63,6 +91,7 @@ Attributes:
- `time`: The time of the game. (optional)
- `box_score`: The box score of the game.
- `score_breakdown`: The score breakdown of the game.
- `ticket_link`: The ticket link of the game. (optional)
"""
type GameType {
id: String
Expand Down Expand Up @@ -90,6 +119,10 @@ type GameType {
scoreBreakdown: [[String]]

team: TeamType

utcDate: String

ticketLink: String
}

"""
Expand Down Expand Up @@ -133,6 +166,7 @@ Attributes:
- `id`: The ID of the team (optional).
- `color`: The color of the team.
- `image`: The image of the team (optional).
- `b64_image`: The base64 encoded image of the team (optional).
- `name`: The name of the team.
"""
type TeamType {
Expand All @@ -142,24 +176,31 @@ type TeamType {

image: String

b64Image: String

name: String!
}

type Mutation {
"""
Creates a new game.
"""
createGame(boxScore: String, city: String!, date: String!, gender: String!, location: String, opponentId: String!, result: String, scoreBreakdown: String, sport: String!, state: String!, time: String!): CreateGame
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

"""
Creates a new team.
"""
createTeam(color: String!, image: String, name: String!): CreateTeam
createTeam(b64Image: String, color: String!, image: String, name: String!): CreateTeam

"""
Creates a new youtube video.
"""
createYoutubeVideo(description: String!, id: String!, publishedAt: String!, thumbnail: String!, title: String!, url: String!): CreateYoutubeVideo
createYoutubeVideo(b64Thumbnail: String!, description: String!, id: String!, publishedAt: String!, thumbnail: String!, title: String!, url: String!): CreateYoutubeVideo

"""
Creates a new article.
"""
createArticle(image: String, publishedAt: String!, slug: String!, sportsType: String!, title: String!, url: String!): CreateArticle
}

type CreateGame {
Expand All @@ -174,6 +215,10 @@ type CreateYoutubeVideo {
youtubeVideo: YoutubeVideoType
}

type CreateArticle {
article: ArticleType
}

"""
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.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ import com.cornellappdev.score.theme.Style.bodyMedium
import com.cornellappdev.score.theme.White

@Composable
fun ButtonPrimary(text: String, icon: Painter?, onClick: () -> Unit = {}) {
Button(onClick = onClick,
fun ButtonPrimary(
text: String,
icon: Painter?,
modifier: Modifier = Modifier,
onClick: () -> Unit = {}
) {
Button(
onClick = onClick,
colors = ButtonDefaults.buttonColors(containerColor = CrimsonPrimary),
modifier = modifier,
contentPadding = PaddingValues(12.dp)
) {
if (icon != null) {
Expand All @@ -32,7 +39,9 @@ fun ButtonPrimary(text: String, icon: Painter?, onClick: () -> Unit = {}) {
.height(24.dp),
colorFilter = ColorFilter.tint(White)
)
Spacer(modifier = Modifier.width(8.dp))
if (text.isNotEmpty()) {
Spacer(modifier = Modifier.width(8.dp))
}
}
Text(text = text, style = bodyMedium.copy(color = White))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.cornellappdev.score.components

import androidx.compose.animation.animateContentSize
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.cornellappdev.score.R
import com.cornellappdev.score.theme.Style.bodyNormal
import com.cornellappdev.score.theme.Style.heading2

interface DisplayableFilter {
val displayName: String
}

enum class PriceFilter(override val displayName: String) : DisplayableFilter {
UNTICKETED("Unticketed"),
UNDER_20("Under $20"),
UNDER_50("Under $50"),
OVER_50("Over $50")
}

enum class LocationFilter(override val displayName: String) : DisplayableFilter {
ON_CAMPUS("On Campus"),
ONE_TO_TWO_HOURS("1-2 Hours"),
TWO_TO_FOUR_HOURS("2-4 Hours"),
OVER_FOUR_HOURS("Over 4 Hours")
}

enum class DateFilter(override val displayName: String) : DisplayableFilter {
TODAY("Today"),
WITHIN_7_DAYS("Within 7 Days"),
WITHIN_A_MONTH("Within a Month"),
OVER_A_MONTH("Over a Month")
}

@Composable
fun <T : DisplayableFilter> ExpandableSection(
title: String,
options: List<T>,
selectedOption: T?,
onOptionSelected: (T?) -> Unit
) {
var expanded by remember { mutableStateOf(false) }

Column {
Row(
modifier = Modifier
.fillMaxWidth()
.clickable { expanded = !expanded },
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(title, style = heading2)
Icon(
painter = painterResource(
id = if (expanded) R.drawable.ic_round_minus else R.drawable.ic_round_plus
),
contentDescription = if (expanded) "Collapse" else "Expand"
)
}

// Options
Column(
modifier = Modifier
.fillMaxWidth()
.animateContentSize()
) {
if (expanded) {
Column {
options.forEach { option ->
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.clickable { onOptionSelected(option) }
.padding(start = 16.dp, top = 4.dp, bottom = 4.dp)
) {
ScoreRadioButton(
selected = (selectedOption == option),
onClick = { onOptionSelected(option) },
modifier = Modifier
.size(20.dp)
.padding(end = 8.dp)
)
Text(option.displayName, style = bodyNormal)
}
}
}
}
}
}
}

@Preview(showBackground = true)
@Composable
private fun ExpandableSectionPreview() = ScorePreview {
var selected by remember { mutableStateOf<PriceFilter?>(null) }

Column(modifier = Modifier.padding(16.dp)) {
ExpandableSection(
title = "Price",
options = PriceFilter.entries,
selectedOption = selected,
onOptionSelected = { selected = it }
)
}
}
Loading
Loading