-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
568 additions
and
173 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,35 +1,36 @@ | ||
# IJH Android | ||
# IJH Android | ||
|
||
[![Android CI](https://github.com/I-Info/IJH-Android/actions/workflows/ci.yml/badge.svg)](https://github.com/I-Info/IJH-Android/actions/workflows/ci.yml) | ||
|
||
IJH app for Android, a **work in progress** currently. | ||
|
||
# Features | ||
## Features | ||
|
||
- [ ] All features supported by **WeJH**. | ||
- [ ] Notifications. | ||
- [ ] More... | ||
|
||
# Architecture | ||
## Architecture | ||
|
||
The app follows | ||
the [official architecture guidance](https://developer.android.com/topic/architecture). | ||
|
||
![module.png](https://s2.loli.net/2023/10/29/EUNtaGgBVqdfvJz.png) | ||
|
||
- data (repository -> data source) | ||
- network (Retrofit/OkHttp) | ||
- datastore (Protobuf) | ||
- database (Room) | ||
- network (Retrofit/OkHttp) | ||
- datastore (Protobuf) | ||
- database (Room) | ||
|
||
## UI | ||
|
||
UI is built with [Jetpack Compose](https://developer.android.com/jetpack/compose) and | ||
UI is built with [Jetpack Compose](https://developer.android.com/jetpack/compose) and follows | ||
[Material Design 3](https://m3.material.io). | ||
|
||
- Theme: IJH app uses the Dynamic color theme as possible, and provides a default theme for | ||
- Theme: IJH app uses the Dynamic color theme (Material You), and provides a default theme for | ||
fallbacks. | ||
|
||
## Dependency injection | ||
IJH app uses DI(Dependency injection) between layers and uses [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) | ||
to implement automatic DI. | ||
## Dependency injection (DI) | ||
|
||
IJH app uses [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) | ||
to implement automatic DI in modules and layers. |
105 changes: 105 additions & 0 deletions
105
app/src/main/kotlin/com/zjutjh/ijh/ui/component/CampusCardInfoCard.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package com.zjutjh.ijh.ui.component | ||
|
||
import android.content.Context | ||
import androidx.compose.animation.AnimatedContent | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.CreditCard | ||
import androidx.compose.material3.CircularProgressIndicator | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.platform.LocalContext | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.style.TextAlign | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.zjutjh.ijh.R | ||
import com.zjutjh.ijh.ui.theme.IJhTheme | ||
import com.zjutjh.ijh.util.toLocalizedString | ||
import java.time.Duration | ||
|
||
@Composable | ||
fun CampusCardInfoCard( | ||
modifier: Modifier = Modifier, | ||
balance: String?, | ||
lastSyncDuration: Duration? | ||
) { | ||
val context = LocalContext.current | ||
val subtitle = remember(lastSyncDuration) { | ||
prompt(context, lastSyncDuration) | ||
} | ||
|
||
GlanceCard( | ||
modifier = modifier, | ||
title = stringResource(id = R.string.campus_card), | ||
subtitle = subtitle, | ||
icon = Icons.Default.CreditCard | ||
) { | ||
AnimatedContent( | ||
modifier = Modifier | ||
.fillMaxWidth() | ||
.padding(16.dp), | ||
targetState = balance, | ||
contentAlignment = Alignment.Center, | ||
label = "Loading", | ||
) { | ||
when (it) { | ||
null -> Column( | ||
horizontalAlignment = Alignment.CenterHorizontally | ||
) { | ||
CircularProgressIndicator() | ||
Text( | ||
text = stringResource(id = R.string.loading), | ||
textAlign = TextAlign.Center | ||
) | ||
} | ||
|
||
else -> { | ||
Text( | ||
modifier = Modifier.padding(vertical = 8.dp), | ||
color = MaterialTheme.colorScheme.primary, | ||
text = "¥$it", | ||
style = MaterialTheme.typography.displaySmall, | ||
textAlign = TextAlign.Center, | ||
maxLines = 1, | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private fun prompt(context: Context, lastSyncDuration: Duration?) = | ||
buildString { | ||
val separator = " • " | ||
append(context.getString(R.string.balance)) | ||
append(separator) | ||
if (lastSyncDuration != null) { | ||
append(lastSyncDuration.toLocalizedString(context)) | ||
} else { | ||
append(context.getString(R.string.never)) | ||
} | ||
} | ||
|
||
|
||
@Preview | ||
@Composable | ||
private fun CampusCardInfoCardPreview() { | ||
IJhTheme { | ||
CampusCardInfoCard(balance = "123", lastSyncDuration = Duration.ofDays(1)) | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun CampusCardInfoCardPreviewEmpty() { | ||
IJhTheme { | ||
CampusCardInfoCard(balance = null, lastSyncDuration = null) | ||
} | ||
} |
101 changes: 101 additions & 0 deletions
101
app/src/main/kotlin/com/zjutjh/ijh/ui/component/GlanceCard.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package com.zjutjh.ijh.ui.component | ||
|
||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.ColumnScope | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.ChevronRight | ||
import androidx.compose.material.icons.filled.Image | ||
import androidx.compose.material3.Card | ||
import androidx.compose.material3.FilledTonalIconButton | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.vector.ImageVector | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.font.FontWeight | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.dp | ||
import com.zjutjh.ijh.R | ||
import com.zjutjh.ijh.ui.theme.IJhTheme | ||
import com.zjutjh.ijh.util.emptyFun | ||
|
||
@Composable | ||
internal fun GlanceCard( | ||
modifier: Modifier, | ||
title: String, | ||
subtitle: String, | ||
icon: ImageVector? = null, | ||
onButtonClick: (() -> Unit)? = null, | ||
content: @Composable (ColumnScope.() -> Unit), | ||
) { | ||
Card( | ||
modifier = modifier, | ||
) { | ||
Row( | ||
Modifier | ||
.padding(top = 12.dp, start = 16.dp, end = 16.dp) | ||
.fillMaxWidth(), | ||
horizontalArrangement = Arrangement.SpaceBetween, | ||
verticalAlignment = Alignment.CenterVertically, | ||
) { | ||
Column { | ||
// Title | ||
if (icon != null) | ||
IconText( | ||
icon = icon, | ||
text = " | $title", | ||
style = MaterialTheme.typography.headlineMedium, | ||
fontWeight = FontWeight.Bold, | ||
) | ||
else Text( | ||
text = title, | ||
style = MaterialTheme.typography.headlineMedium, | ||
fontWeight = FontWeight.Bold, | ||
maxLines = 1, | ||
) | ||
|
||
// Subtitle | ||
Text( | ||
text = subtitle, | ||
style = MaterialTheme.typography.titleSmall, | ||
color = MaterialTheme.colorScheme.outline, | ||
maxLines = 1, | ||
) | ||
} | ||
if (onButtonClick != null) | ||
FilledTonalIconButton( | ||
onClick = onButtonClick, | ||
) { | ||
Icon( | ||
imageVector = Icons.Default.ChevronRight, | ||
contentDescription = stringResource(id = R.string.more) | ||
) | ||
} | ||
} | ||
|
||
content() | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
private fun GlanceCardPreview() { | ||
IJhTheme { | ||
GlanceCard( | ||
modifier = Modifier, | ||
title = "Title", | ||
subtitle = "Subtitle", | ||
icon = Icons.Default.Image, | ||
onButtonClick = ::emptyFun, | ||
) { | ||
Text(modifier = Modifier.padding(24.dp), text = "Content") | ||
} | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
app/src/main/kotlin/com/zjutjh/ijh/ui/component/IconText.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package com.zjutjh.ijh.ui.component | ||
|
||
import androidx.compose.foundation.layout.fillMaxSize | ||
import androidx.compose.foundation.text.InlineTextContent | ||
import androidx.compose.foundation.text.appendInlineContent | ||
import androidx.compose.material.icons.Icons | ||
import androidx.compose.material.icons.filled.Image | ||
import androidx.compose.material3.Icon | ||
import androidx.compose.material3.MaterialTheme | ||
import androidx.compose.material3.Surface | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.graphics.vector.ImageVector | ||
import androidx.compose.ui.text.Placeholder | ||
import androidx.compose.ui.text.PlaceholderVerticalAlign | ||
import androidx.compose.ui.text.TextStyle | ||
import androidx.compose.ui.text.buildAnnotatedString | ||
import androidx.compose.ui.text.font.FontWeight | ||
import androidx.compose.ui.text.style.TextOverflow | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.sp | ||
|
||
@Composable | ||
fun IconText( | ||
icon: ImageVector, | ||
text: String, | ||
contentDescription: String? = null, | ||
fontWeight: FontWeight? = null, | ||
style: TextStyle = MaterialTheme.typography.bodyMedium, | ||
) { | ||
val id = "icon" | ||
val annotatedString = buildAnnotatedString { | ||
appendInlineContent(id, "[icon]") | ||
append(text) | ||
} | ||
val inlineContent = mapOf( | ||
id to InlineTextContent( | ||
Placeholder( | ||
width = style.fontSize, | ||
height = style.fontSize, | ||
placeholderVerticalAlign = PlaceholderVerticalAlign.TextCenter, | ||
) | ||
) { | ||
Icon( | ||
modifier = Modifier.fillMaxSize(), | ||
imageVector = icon, | ||
contentDescription = contentDescription, | ||
) | ||
} | ||
) | ||
|
||
Text( | ||
text = annotatedString, | ||
inlineContent = inlineContent, | ||
style = style, | ||
fontWeight = fontWeight, | ||
overflow = TextOverflow.Ellipsis, | ||
maxLines = 1 | ||
) | ||
} | ||
|
||
@Preview | ||
@Composable | ||
fun IconTextPreview() { | ||
Surface { | ||
IconText( | ||
icon = Icons.Default.Image, | ||
text = "Hello World", | ||
fontWeight = FontWeight.Bold, | ||
style = TextStyle(fontSize = 30.sp) | ||
) | ||
} | ||
} |
Oops, something went wrong.