Compare commits

..

No commits in common. "master" and "v0.1.2" have entirely different histories.

7 changed files with 54 additions and 117 deletions

View file

@ -12,10 +12,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

View file

@ -11,10 +11,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@v2
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'

View file

@ -1,39 +1,14 @@
# Bob -- The Handy Feedback App
This is a Kotlin Multiplatform project targeting Android, iOS.
This project is a simple Kotlin Multiplatform Application that allows users to enter free-text and
submit the content to a server over HTTP. It also includes a form with sentiment selection and
displays a Snackbar whenever the submit button is pressed.
* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
It contains several subfolders:
- `commonMain` is for code thats common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
For example, if you want to use Apples CoreCrypto for the iOS part of your Kotlin app,
`iosMain` would be the right folder for such calls.
## Features
* `/iosApp` contains iOS applications. Even if youre sharing your UI with Compose Multiplatform,
you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
- Free-text input form
- Sentiment selection using FilterChips
- Submit content to a server using Retrofit
- Display Snackbar on form submission
## Technologies Used
- Kotlin
- Jetpack Compose
- Retrofit
- Gradle
## Getting Started
### Installation
1. Download the latest release from
the [releases page](https://git.brmartin.co.uk/bob/mobile-application/releases)
2. Install the application following the on-screen instructions.
### Usage
1. Run the application on an Android emulator or a physical device.
2. Select a sentiment using the FilterChips.
3. Enter your text in the provided text field.
4. Press the submit button to send the content to the server.
### Project Structure
- `composeApp/src/commonMain/kotlin/uk/sky/bob/application/App.kt`: Main Compose UI and form
submission logic.
Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html)…

View file

@ -1,38 +1,25 @@
package uk.sky.bob.application
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Button
import androidx.compose.material.ChipDefaults
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.FilterChip
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Send
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
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.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import org.jetbrains.compose.ui.tooling.preview.Preview
@OptIn(ExperimentalMaterialApi::class)
@ -40,60 +27,38 @@ import org.jetbrains.compose.ui.tooling.preview.Preview
@Preview
fun App() {
MaterialTheme {
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Row {
val state = remember { mutableStateOf(Sentiment.HAPPY) }
for (emotion in Sentiment.entries) {
FilterChip(
onClick = { state.value = emotion },
selected = state.value == emotion,
modifier = Modifier.padding(8.dp),
leadingIcon = { Text(emotion.leadingIcon) },
) {
Text(emotion.friendlyName)
}
}
}
Scaffold(scaffoldState = scaffoldState) {
Box(
modifier = Modifier.fillMaxHeight(),
contentAlignment = Alignment.Center,
) {
Column(
Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
) {
val sentiment = remember { mutableStateOf(Sentiment.HAPPY) }
var comment by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(
TextFieldValue("")
)
}
Row(modifier = Modifier.padding(8.dp)) {
for (emotion in Sentiment.entries) {
FilterChip(
onClick = { sentiment.value = emotion },
selected = sentiment.value == emotion,
modifier = Modifier.padding(8.dp),
leadingIcon = { Text(emotion.leadingIcon, fontSize = 20.sp) },
colors = ChipDefaults.outlinedFilterChipColors(),
border = ChipDefaults.outlinedBorder,
) {
Text(emotion.friendlyName, fontSize = 20.sp)
}
}
}
Row {
var text by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(
TextFieldValue("")
)
}
TextField(
value = text,
onValueChange = { text = it },
label = { Text("Your comment") },
maxLines = 3,
)
}
Row(modifier = Modifier.padding(8.dp)) {
TextField(
value = comment,
onValueChange = { comment = it },
label = { Text("Your comment") },
modifier = Modifier.height(100.dp).fillMaxWidth().padding(8.dp),
)
}
Row(modifier = Modifier.padding(8.dp)) {
Button(onClick = {
sentiment.value = Sentiment.HAPPY
comment = TextFieldValue("")
scope.launch {
delay(1000)
scaffoldState.snackbarHostState.showSnackbar("Feedback sent")
}
}, modifier = Modifier.padding(8.dp)) {
Icon(Icons.AutoMirrored.Filled.Send, contentDescription = "Send")
}
}
Row {
Button(onClick = { /* Handle submit */ }) {
Text("Submit")
}
}
}

View file

@ -1,19 +1,19 @@
[versions]
agp = "8.10.1"
android-compileSdk = "35"
agp = "8.5.2"
android-compileSdk = "34"
android-minSdk = "24"
android-targetSdk = "34"
androidx-activityCompose = "1.10.1"
androidx-appcompat = "1.7.1"
androidx-constraintlayout = "2.2.1"
androidx-core-ktx = "1.16.0"
androidx-activityCompose = "1.9.3"
androidx-appcompat = "1.7.0"
androidx-constraintlayout = "2.2.0"
androidx-core-ktx = "1.15.0"
androidx-espresso-core = "3.6.1"
androidx-lifecycle = "2.9.1"
androidx-lifecycle = "2.8.4"
androidx-material = "1.12.0"
androidx-test-junit = "1.2.1"
compose-multiplatform = "1.7.3"
compose-multiplatform = "1.7.0"
junit = "4.13.2"
kotlin = "2.1.21"
kotlin = "2.1.0"
[libraries]
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

View file

@ -1,3 +0,0 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}