Compare commits
No commits in common. "master" and "v0.1.1" have entirely different histories.
9 changed files with 51 additions and 142 deletions
4
.github/workflows/build.yaml
vendored
4
.github/workflows/build.yaml
vendored
|
@ -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'
|
||||
|
|
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
|
@ -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'
|
||||
|
|
45
README.md
45
README.md
|
@ -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 that’s 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 Apple’s 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 you’re 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)…
|
|
@ -1,102 +1,37 @@
|
|||
package uk.sky.bob.application
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
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.runtime.*
|
||||
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.resources.painterResource
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
import bob.composeapp.generated.resources.Res
|
||||
import bob.composeapp.generated.resources.compose_multiplatform
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
fun App() {
|
||||
MaterialTheme {
|
||||
val scaffoldState = rememberScaffoldState()
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
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(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")
|
||||
}
|
||||
}
|
||||
var showContent by remember { mutableStateOf(false) }
|
||||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Button(onClick = { showContent = !showContent }) {
|
||||
Text("Click me!")
|
||||
}
|
||||
AnimatedVisibility(showContent) {
|
||||
val greeting = remember { Greeting().greet() }
|
||||
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Image(painterResource(Res.drawable.compose_multiplatform), null)
|
||||
Text("Compose: $greeting")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package uk.sky.bob.application
|
||||
|
||||
class Greeting {
|
||||
private val platform = getPlatform()
|
||||
|
||||
fun greet(): String {
|
||||
return "Hello, ${platform.name}!"
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
package uk.sky.bob.application
|
||||
|
||||
enum class Sentiment(val friendlyName: String, val leadingIcon: String) {
|
||||
HAPPY("Happy", "\uD83D\uDE03"),
|
||||
NEUTRAL("Neutral", "\uD83D\uDE10"),
|
||||
SAD("Sad", "\uD83D\uDE1E");
|
||||
}
|
|
@ -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" }
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -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
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue