Skip to content

Commit

Permalink
Merge pull request #10 from yschimke/wear_markdown
Browse files Browse the repository at this point in the history
Use markdown in Wear app
  • Loading branch information
joreilly authored Jan 20, 2024
2 parents 69e8748 + d85adad commit 702a799
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 9 deletions.
8 changes: 7 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ compose = "1.5.4"
compose-compiler = "1.5.7"
compose-plugin = "1.6.0-alpha01"
composeWindowSize = "0.5.0-alpha03"
horologist = "0.5.19"
imageLoader = "1.7.1"
junit = "4.13.2"
koalaplot = "0.5.1"
Expand Down Expand Up @@ -46,7 +47,12 @@ compose-material = { module = "androidx.compose.material:material", version.ref
compose-window-size = { module = "dev.chrisbanes.material3:material3-window-size-class-multiplatform", version.ref = "composeWindowSize" }
mpfilepicker = { module = "com.darkrockstudios:mpfilepicker", version.ref = "mpFilePicker" }
markdown-renderer = { module = "com.mikepenz:multiplatform-markdown-renderer-m3", version.ref = "markdownRenderer" }
markdown-renderer-core = { module = "com.mikepenz:multiplatform-markdown-renderer", version.ref = "markdownRenderer" }

horologist-composables = { module = "com.google.android.horologist:horologist-composables", version.ref = "horologist" }
horologist-compose-layout = { module = "com.google.android.horologist:horologist-compose-layout", version.ref = "horologist" }
horologist-ai-ui = { module = "com.google.android.horologist:horologist-ai-ui", version.ref = "horologist" }
compose-material-iconsext = "androidx.compose.material:material-icons-extended:1.5.4"

kotlinx-coroutines = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }

Expand All @@ -65,7 +71,7 @@ ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.r
voyager = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
imageLoader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "imageLoader" }
koalaplot = { module = "io.github.koalaplot:koalaplot-core", version.ref = "koalaplot" }

desugar = "com.android.tools:desugar_jdk_libs:2.0.4"

[bundles]
ktor-common = ["ktor-client-core", "ktor-client-json", "ktor-client-logging", "ktor-client-serialization", "ktor-client-content-negotiation", "ktor-serialization-kotlinx-json"]
Expand Down
14 changes: 9 additions & 5 deletions wearApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import java.io.FileInputStream
@file:Suppress("UnstableApiUsage")

import java.util.Properties

val localProperties = Properties().apply {
Expand Down Expand Up @@ -30,6 +31,7 @@ android {
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
isCoreLibraryDesugaringEnabled = true
}

buildFeatures {
Expand Down Expand Up @@ -76,11 +78,13 @@ kotlin {

dependencies {
implementation(libs.compose.foundation)
implementation("com.google.android.horologist:horologist-composables:0.5.18")
implementation("com.google.android.horologist:horologist-compose-layout:0.5.18")
implementation("com.google.android.horologist:horologist-ai-ui:0.5.18")
implementation("androidx.compose.material:material-icons-extended:1.5.4")
implementation(libs.horologist.composables)
implementation(libs.horologist.compose.layout)
implementation(libs.horologist.ai.ui)
implementation(libs.markdown.renderer.core)
implementation(libs.compose.material.iconsext)
implementation(libs.kotlinx.coroutines)
implementation(libs.bundles.ktor.common)
implementation(libs.ktor.client.okhttp)
coreLibraryDesugaring(libs.desugar)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package dev.johnoreilly.gemini.wear.markdown

import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.wear.compose.material.LocalContentColor
import androidx.wear.compose.material.MaterialTheme
import com.mikepenz.markdown.model.DefaultMarkdownColors
import com.mikepenz.markdown.model.DefaultMarkdownTypography

@Composable
fun wearMaterialTypography() = DefaultMarkdownTypography(
h1 = MaterialTheme.typography.title1,
h2 = MaterialTheme.typography.title2,
h3 = MaterialTheme.typography.title3,
h4 = MaterialTheme.typography.caption1,
h5 = MaterialTheme.typography.caption2,
h6 = MaterialTheme.typography.caption3,
text = MaterialTheme.typography.body1,
code = MaterialTheme.typography.body2.copy(fontFamily = FontFamily.Monospace),
quote = MaterialTheme.typography.body2.plus(SpanStyle(fontStyle = FontStyle.Italic)),
paragraph = MaterialTheme.typography.body1,
ordered = MaterialTheme.typography.body1,
bullet = MaterialTheme.typography.body1,
list = MaterialTheme.typography.body1,
)

@Composable
fun wearMaterialColors() = DefaultMarkdownColors(
text = Color.White,
codeText = LocalContentColor.current,
linkText = Color.Blue,
codeBackground = MaterialTheme.colors.background,
inlineCodeBackground = MaterialTheme.colors.background,
dividerColor = MaterialTheme.colors.secondaryVariant
)
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.wear.compose.material.Card
import androidx.wear.compose.material.CardDefaults
import androidx.wear.compose.material.MaterialTheme
import com.google.android.horologist.ai.ui.components.PromptOrResponseDisplay
import com.google.android.horologist.ai.ui.model.PromptOrResponseUiModel
import com.google.android.horologist.ai.ui.model.TextResponseUiModel
import com.google.android.horologist.ai.ui.screens.PromptScreen
import com.google.android.horologist.ai.ui.screens.PromptUiState
import com.google.android.horologist.compose.layout.ScalingLazyColumnState
import com.google.android.horologist.compose.layout.ScreenScaffold
import com.google.android.horologist.compose.layout.rememberColumnState
import com.google.android.horologist.compose.material.Button
import com.mikepenz.markdown.compose.Markdown
import dev.johnoreilly.gemini.R
import dev.johnoreilly.gemini.wear.markdown.wearMaterialColors
import dev.johnoreilly.gemini.wear.markdown.wearMaterialTypography

@Composable
fun GeminiPromptScreen(
Expand Down Expand Up @@ -86,6 +95,41 @@ private fun GeminiPromptScreen(
columnState = columnState,
modifier = modifier,
promptEntry = promptEntry,
promptDisplay = { GeminiPromptDisplay(it) }
)
}
}

@Composable
private fun GeminiPromptDisplay(it: PromptOrResponseUiModel) {
if (it is TextResponseUiModel) {
GeminiTextResponseCard(it)
} else {
PromptOrResponseDisplay(
promptResponse = it,
onClick = {},
)
}
}

@Composable
fun GeminiTextResponseCard(
textResponseUiModel: TextResponseUiModel,
modifier: Modifier = Modifier,
onClick: () -> Unit = {},
) {
Card(
modifier = modifier.fillMaxWidth(),
onClick = onClick,
backgroundPainter = CardDefaults.cardBackgroundPainter(
MaterialTheme.colors.surface,
MaterialTheme.colors.surface,
),
) {
Markdown(
textResponseUiModel.text,
colors = wearMaterialColors(),
typography = wearMaterialTypography(),
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.horologist.ai.ui.model.FailedResponseUiModel
import com.google.android.horologist.ai.ui.model.ModelInstanceUiModel
import com.google.android.horologist.ai.ui.model.PromptResponseUiModel
import com.google.android.horologist.ai.ui.model.PromptOrResponseUiModel
import com.google.android.horologist.ai.ui.model.TextPromptUiModel
import com.google.android.horologist.ai.ui.model.TextResponseUiModel
import com.google.android.horologist.ai.ui.screens.PromptUiState
Expand All @@ -20,7 +20,7 @@ import kotlinx.coroutines.launch
class GeminiPromptViewModel : ViewModel() {
val api = GeminiApi()

val previousQuestions: MutableStateFlow<List<PromptResponseUiModel>> =
val previousQuestions: MutableStateFlow<List<PromptOrResponseUiModel>> =
MutableStateFlow(listOf())
val pendingQuestion: MutableStateFlow<TextPromptUiModel?> =
MutableStateFlow(null)
Expand All @@ -42,7 +42,7 @@ class GeminiPromptViewModel : ViewModel() {

private suspend fun queryForPrompt(
enteredPrompt: String,
): PromptResponseUiModel {
): PromptOrResponseUiModel {
return try {
val result = api.generateContent(enteredPrompt)
return if (result.candidates != null) {
Expand Down

0 comments on commit 702a799

Please sign in to comment.