feat: basic upcoming events list view
This commit is contained in:
parent
ea3a307f96
commit
2d665ab631
14 changed files with 155 additions and 10 deletions
|
@ -53,6 +53,7 @@ dependencies {
|
||||||
implementation(libs.androidx.material.icons.extended)
|
implementation(libs.androidx.material.icons.extended)
|
||||||
implementation(libs.androidx.material3)
|
implementation(libs.androidx.material3)
|
||||||
implementation(libs.androidx.ui.tooling.preview)
|
implementation(libs.androidx.ui.tooling.preview)
|
||||||
|
implementation(libs.protolite.well.known.types)
|
||||||
|
|
||||||
runtimeOnly(libs.androidx.ui.tooling)
|
runtimeOnly(libs.androidx.ui.tooling)
|
||||||
implementation(libs.org.eclipse.jgit)
|
implementation(libs.org.eclipse.jgit)
|
||||||
|
@ -64,5 +65,6 @@ dependencies {
|
||||||
debugImplementation("androidx.compose.ui:ui-tooling")
|
debugImplementation("androidx.compose.ui:ui-tooling")
|
||||||
implementation("androidx.compose.ui:ui-tooling-preview")
|
implementation("androidx.compose.ui:ui-tooling-preview")
|
||||||
implementation("androidx.annotation:annotation")
|
implementation("androidx.annotation:annotation")
|
||||||
|
implementation("com.google.code.gson:gson:2.10.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,5 +6,6 @@ class AppContext(
|
||||||
val androidContext: Context,
|
val androidContext: Context,
|
||||||
) {
|
) {
|
||||||
val gitActions = GitActions(androidContext)
|
val gitActions = GitActions(androidContext)
|
||||||
val popequer = PopequerAdapter(gitActions.cloneFolder.absolutePath)
|
val popequer = Popequer(PopequerAdapter(gitActions.cloneFolder.absolutePath))
|
||||||
|
val backgroundActions = BackgroundActions(this)
|
||||||
}
|
}
|
18
app/src/main/java/net/mbess/popequer/BackgroundActions.kt
Normal file
18
app/src/main/java/net/mbess/popequer/BackgroundActions.kt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package net.mbess.popequer
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class BackgroundActions(val context: AppContext) {
|
||||||
|
fun refresh() {
|
||||||
|
runCatching {
|
||||||
|
context.gitActions.sync()
|
||||||
|
context.popequer.index()
|
||||||
|
}.onFailure {
|
||||||
|
Log.e("BackgroundActions", "Failed to refresh the Notebook");
|
||||||
|
}.onSuccess {
|
||||||
|
Log.i("BackgroundActions", "Notebook refresh successfully");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
app/src/main/java/net/mbess/popequer/EventItem.kt
Normal file
11
app/src/main/java/net/mbess/popequer/EventItem.kt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package net.mbess.popequer
|
||||||
|
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class EventItem(
|
||||||
|
val name: String,
|
||||||
|
val startTime: Instant,
|
||||||
|
val endTime: Instant?
|
||||||
|
) {
|
||||||
|
|
||||||
|
}
|
|
@ -42,9 +42,13 @@ class GitActions(
|
||||||
|
|
||||||
fun sync() {
|
fun sync() {
|
||||||
git.fetch().setCredentialsProvider(credentials).call()
|
git.fetch().setCredentialsProvider(credentials).call()
|
||||||
git.rebase().setUpstream("origin/master").call().also { result ->
|
git.reset().setMode(ResetCommand.ResetType.HARD).setRef("origin/master").call().also {
|
||||||
Log.i("GitActions", "Rebase status: ${result.status} ${result.conflicts}")
|
result ->
|
||||||
|
Log.i("GitActions", "reset!");
|
||||||
}
|
}
|
||||||
|
//git.rebase().setUpstream("origin/master").call().also { result ->
|
||||||
|
// Log.i("GitActions", "Rebase status: ${result.status} ${result.conflicts}")
|
||||||
|
//}
|
||||||
Log.i("GitActions", "Successfully sync repo")
|
Log.i("GitActions", "Successfully sync repo")
|
||||||
}
|
}
|
||||||
fun trigger() {
|
fun trigger() {
|
||||||
|
|
18
app/src/main/java/net/mbess/popequer/Popequer.kt
Normal file
18
app/src/main/java/net/mbess/popequer/Popequer.kt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package net.mbess.popequer
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
|
||||||
|
class Popequer(
|
||||||
|
val adapter: PopequerAdapter
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun index(): String {
|
||||||
|
return adapter.index()
|
||||||
|
}
|
||||||
|
fun upcomingEvents(): List<EventItem> {
|
||||||
|
val events_str = adapter.upcomingEvents()
|
||||||
|
Log.d("Popequer", "From rust: $events_str")
|
||||||
|
val events = PopequerDeserializer().deserializeEvents(events_str)
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
22
app/src/main/java/net/mbess/popequer/PopequerDeserializer.kt
Normal file
22
app/src/main/java/net/mbess/popequer/PopequerDeserializer.kt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package net.mbess.popequer
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
|
||||||
|
class PopequerDeserializer() {
|
||||||
|
private var gsonInstance: Gson =
|
||||||
|
GsonBuilder().registerTypeAdapter(Instant::class.java, InstantDeserializer()).create()
|
||||||
|
|
||||||
|
fun deserializeEvents(inp: String): List<EventItem> {
|
||||||
|
val listType: Type = object : TypeToken<ArrayList<EventItem>?>() {}.type
|
||||||
|
return gsonInstance
|
||||||
|
.fromJson(inp, listType)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.*
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
@ -84,6 +85,13 @@ fun AppContainer(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
context.backgroundActions.refresh()
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Icon(Icons.Filled.Refresh, contentDescription = "Refresh icon")
|
||||||
|
}
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
// TODO: switch to settings view
|
// TODO: switch to settings view
|
||||||
}) {
|
}) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ fun AppNavGraph(
|
||||||
composable(
|
composable(
|
||||||
route = AppDestinations.UPCOMING_EVENTS
|
route = AppDestinations.UPCOMING_EVENTS
|
||||||
) {
|
) {
|
||||||
UpcomingEventsRoute()
|
UpcomingEventsRoute(appContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -40,10 +40,7 @@ class MainActivity : ComponentActivity() {
|
||||||
Toast.makeText(appContext.androidContext, "A repo was just cloned", Toast.LENGTH_LONG)
|
Toast.makeText(appContext.androidContext, "A repo was just cloned", Toast.LENGTH_LONG)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
appContext.gitActions.sync()
|
appContext.backgroundActions.refresh()
|
||||||
Log.d("Ppq", "${appContext.popequer}");
|
|
||||||
Log.d("Ppq", "Index: ${appContext.popequer.index()}");
|
|
||||||
Log.d("Ppq", "Upcoming: ${appContext.popequer.upcomingEvents()}");
|
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
Log.e("MainActivity", "Failed to prepare git repo", it)
|
Log.e("MainActivity", "Failed to prepare git repo", it)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,46 @@
|
||||||
package net.mbess.popequer.ui
|
package net.mbess.popequer.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import net.mbess.popequer.AppContext
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneOffset.UTC
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun UpcomingEventsRoute() {
|
fun UpcomingEventsRoute(
|
||||||
Text(text = "This is the upcoming events route")
|
appContext: AppContext
|
||||||
|
) {
|
||||||
|
Surface(modifier = Modifier.padding(10.dp)) {
|
||||||
|
val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
||||||
|
|
||||||
|
LazyColumn {
|
||||||
|
itemsIndexed(appContext.popequer.upcomingEvents()) { index, item ->
|
||||||
|
Card(
|
||||||
|
elevation = CardDefaults.cardElevation(
|
||||||
|
defaultElevation = 6.dp
|
||||||
|
),
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(bottom = 10.dp)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(15.dp)) {
|
||||||
|
Text(item.name, style = MaterialTheme.typography.headlineSmall)
|
||||||
|
Text("Start: ${LocalDateTime.ofInstant(item.startTime, UTC).format(formatter)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
24
app/src/main/java/net/mbess/popequer/utils.kt
Normal file
24
app/src/main/java/net/mbess/popequer/utils.kt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package net.mbess.popequer
|
||||||
|
|
||||||
|
import com.google.gson.JsonDeserializationContext
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
class InstantDeserializer : JsonDeserializer<Instant?> {
|
||||||
|
@Throws(JsonParseException::class)
|
||||||
|
override fun deserialize(
|
||||||
|
json: JsonElement,
|
||||||
|
typeOfT: Type?,
|
||||||
|
context: JsonDeserializationContext?
|
||||||
|
): Instant?
|
||||||
|
{
|
||||||
|
if (json.isJsonNull) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return Instant.parse(json.asString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ compose-bom = "2023.10.01"
|
||||||
material3 = "1.1.2"
|
material3 = "1.1.2"
|
||||||
org-eclipse-jgit = "6.8.0.202311291450-r"
|
org-eclipse-jgit = "6.8.0.202311291450-r"
|
||||||
twain = "0.2.2"
|
twain = "0.2.2"
|
||||||
|
protolite-well-known-types = "18.0.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
|
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
|
||||||
|
@ -27,6 +28,7 @@ compose-markdown = { module = "com.github.jeziellago:compose-markdown", version.
|
||||||
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines-android" }
|
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinx-coroutines-android" }
|
||||||
org-eclipse-jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version.ref = "org-eclipse-jgit" }
|
org-eclipse-jgit = { module = "org.eclipse.jgit:org.eclipse.jgit", version.ref = "org-eclipse-jgit" }
|
||||||
twain = { module = "com.meetup:twain", version.ref = "twain" }
|
twain = { module = "com.meetup:twain", version.ref = "twain" }
|
||||||
|
protolite-well-known-types = { group = "com.google.firebase", name = "protolite-well-known-types", version.ref = "protolite-well-known-types" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|
|
@ -20,6 +20,7 @@ enum PopequerAdapterErr {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
struct EventItem {
|
struct EventItem {
|
||||||
name: String,
|
name: String,
|
||||||
start_time: String,
|
start_time: String,
|
||||||
|
|
Loading…
Reference in a new issue