desktop: integrate with API

Signed-off-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
Harsh Shandilya 2021-03-14 19:57:10 +05:30
parent be6e0c9498
commit 704e59afdf
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
6 changed files with 142 additions and 22 deletions

View file

@ -68,6 +68,7 @@ object Dependencies {
const val accompanist = "dev.chrisbanes.accompanist:accompanist-coil:0.6.2"
const val composeFlowLayout = "com.star-zero:compose-flowlayout:0.0.1"
const val kamel = "com.alialbaali.kamel:kamel-image:0.2.0"
const val pullToRefresh = "com.puculek.pulltorefresh:pull-to-refresh-compose:1.0.0"
object Moshi {
@ -100,7 +101,6 @@ object Dependencies {
object AndroidX {
private const val version = "1.3.1-alpha02"
const val runner = "androidx.test:runner:$version"
object Compose {

View file

@ -17,6 +17,8 @@ dependencies {
implementation(compose.runtime)
implementation(compose.material)
implementation(Dependencies.Kotlin.Coroutines.jvmCore)
implementation(Dependencies.ThirdParty.kamel)
implementation(Dependencies.ThirdParty.Retrofit.moshi)
}
compose.desktop {

View file

@ -0,0 +1,20 @@
import com.squareup.moshi.Moshi
import dev.msfjarvis.lobsters.data.api.LobstersApi
import dev.msfjarvis.lobsters.model.LobstersPost
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.create
class ApiRepository {
private val moshi = Moshi.Builder()
.build()
private val retrofit = Retrofit.Builder()
.baseUrl(LobstersApi.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
private val api: LobstersApi = retrofit.create()
suspend fun loadPosts(pageNumber: Int): List<LobstersPost> {
return api.getHottestPosts(pageNumber)
}
}

View file

@ -1,13 +1,24 @@
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import dev.msfjarvis.lobsters.data.local.SavedPost
import java.awt.Desktop
import io.kamel.image.KamelImage
import io.kamel.image.lazyImageResource
import java.net.URI
@Composable
@ -17,15 +28,67 @@ fun LobstersItem(
Surface(
modifier = Modifier
.fillMaxWidth()
.requiredHeight(48.dp)
.clickable {
if (Desktop.isDesktopSupported() && Desktop.getDesktop()
.isSupported(Desktop.Action.BROWSE)
UrlLauncher.launch(post.url)
}
.wrapContentHeight(),
) {
Row(
modifier = Modifier
.padding(start = 12.dp, end = 24.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
) {
Desktop.getDesktop().browse(URI(post.url))
Column(
modifier = Modifier.fillMaxWidth(),
) {
Text(
text = post.title,
color = titleColor,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(top = 4.dp),
)
TagRow(
tags = post.tags,
modifier = Modifier
.padding(top = 8.dp, bottom = 8.dp, end = 16.dp),
)
Row {
KamelImage(
resource = lazyImageResource(data = URI(post.submitterAvatarUrl)),
contentDescription = "${post.submitterName}'s avatar",
modifier = Modifier
.requiredWidth(30.dp)
.padding(4.dp),
)
Text(
text = "Submitted by ${post.submitterName}",
modifier = Modifier
.padding(4.dp),
)
}
}
}
}
}
@Composable
fun TagRow(
tags: List<String>,
modifier: Modifier = Modifier,
) {
Row(
modifier = Modifier.then(modifier),
) {
Text(post.title)
tags.forEach { tag ->
Text(
text = tag,
modifier = Modifier
.background(Color(0xFFFFFCD7), RoundedCornerShape(8.dp))
.padding(horizontal = 8.dp),
color = Color.DarkGray,
)
}
}
}

View file

@ -7,23 +7,31 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.rememberScrollbarAdapter
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.Text
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import dev.msfjarvis.lobsters.data.local.SavedPost
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import dev.msfjarvis.lobsters.model.LobstersPost
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
val TEST_POST = SavedPost(
shortId = "zqyydb",
title = "k2k20 hackathon report: Bob Beck on LibreSSL progress",
url = "https://undeadly.org/cgi?action=article;sid=20200921105847",
createdAt = "2020-09-21T07:11:14.000-05:00",
commentsUrl = "https://lobste.rs/s/zqyydb/k2k20_hackathon_report_bob_beck_on",
submitterName = "Vigdis",
submitterAvatarUrl = "/avatars/Vigdis-100.png",
tags = listOf("openbsd", "linux", "containers", "hack the planet", "no thanks"),
)
val repository = ApiRepository()
@OptIn(ExperimentalStdlibApi::class)
fun main() = Window(title = "Claw for lobste.rs") {
val coroutineScope = rememberCoroutineScope()
var items by remember { mutableStateOf(emptyList<SavedPost>()) }
coroutineScope.launch {
withContext(Dispatchers.IO) {
items = repository.loadPosts(0).map(::toDbModel)
}
}
LobstersTheme {
Box(
modifier = Modifier.fillMaxSize(),
@ -34,9 +42,13 @@ fun main() = Window(title = "Claw for lobste.rs") {
.fillMaxSize()
.verticalScroll(stateVertical),
) {
if (items.isEmpty()) {
Text("Loading...")
} else {
Column {
repeat(50) {
LobstersItem(TEST_POST)
items.forEach {
LobstersItem(it)
}
}
}
}
@ -47,3 +59,16 @@ fun main() = Window(title = "Claw for lobste.rs") {
}
}
}
fun toDbModel(post: LobstersPost): SavedPost {
return SavedPost(
shortId = post.shortId,
title = post.title,
url = post.url,
createdAt = post.createdAt,
commentsUrl = post.commentsUrl,
submitterName = post.submitterUser.username,
submitterAvatarUrl = post.submitterUser.avatarUrl,
tags = post.tags,
)
}

View file

@ -0,0 +1,10 @@
import java.awt.Desktop
import java.net.URI
object UrlLauncher {
fun launch(url: String) {
if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(URI(url))
}
}
}