♻️ Android use background info too

This commit is contained in:
LittleSheep 2024-12-21 13:03:07 +08:00
parent 73468c5c6d
commit 435b730f3b
8 changed files with 95 additions and 96 deletions

View File

@ -27,6 +27,11 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Widgets Indents -->
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
<!-- Sharing Intents --> <!-- Sharing Intents -->
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -100,15 +105,15 @@
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/check_in_widget" /> android:resource="@xml/check_in_widget" />
</receiver> </receiver>
<receiver android:name=".widgets.FeaturedPostWidgetReceiver" <receiver android:name=".widgets.RandomPostWidgetReceiver"
android:label="Featured Post" android:label="Random Post"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data <meta-data
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/featured_post_widget" /> android:resource="@xml/random_post_widget" />
</receiver> </receiver>
</application> </application>

View File

@ -1,10 +1,12 @@
import android.content.Context import android.content.Context
import android.net.Uri
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.glance.GlanceId import androidx.glance.GlanceId
import androidx.glance.GlanceModifier import androidx.glance.GlanceModifier
import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.provideContent import androidx.glance.appwidget.provideContent
import androidx.glance.background import androidx.glance.background
@ -26,11 +28,11 @@ import com.google.gson.GsonBuilder
import dev.solsynth.solian.data.InstantAdapter import dev.solsynth.solian.data.InstantAdapter
import dev.solsynth.solian.data.SolarCheckInRecord import dev.solsynth.solian.data.SolarCheckInRecord
import java.time.Instant import java.time.Instant
import java.time.LocalDate
import java.time.OffsetDateTime import java.time.OffsetDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
class CheckInWidget : GlanceAppWidget() { class CheckInWidget : GlanceAppWidget() {
override val stateDefinition: GlanceStateDefinition<*>? override val stateDefinition: GlanceStateDefinition<*>?
get() = HomeWidgetGlanceStateDefinition() get() = HomeWidgetGlanceStateDefinition()
@ -51,7 +53,7 @@ class CheckInWidget : GlanceAppWidget() {
val resultTierSymbols = listOf("大凶", "", "中平", "", "大吉") val resultTierSymbols = listOf("大凶", "", "中平", "", "大吉")
val prefs = currentState.preferences val prefs = currentState.preferences
val checkInRaw = prefs.getString("today_check_in", null) val checkInRaw = prefs.getString("pas_check_in_record", null)
Column( Column(
modifier = GlanceModifier modifier = GlanceModifier
@ -61,33 +63,43 @@ class CheckInWidget : GlanceAppWidget() {
.padding(16.dp) .padding(16.dp)
) { ) {
if (checkInRaw != null) { if (checkInRaw != null) {
val checkIn = gson.fromJson(checkInRaw, SolarCheckInRecord::class.java) val checkIn: SolarCheckInRecord =
gson.fromJson(checkInRaw, SolarCheckInRecord::class.java)
val dateFormatter = DateTimeFormatter.ofPattern("EEE, MM/dd") val dateFormatter = DateTimeFormatter.ofPattern("EEE, MM/dd")
Column { val checkDate = checkIn.createdAt.atZone(ZoneId.of("UTC")).toLocalDate()
Text( val currentDate = LocalDate.now()
text = resultTierSymbols[checkIn.resultTier], if (checkDate.isEqual(currentDate)) {
style = TextStyle(fontSize = 25.sp, fontFamily = FontFamily.Serif) Column {
) Text(
Text( text = resultTierSymbols[checkIn.resultTier],
text = "+${checkIn.resultExperience} EXP", style = TextStyle(fontSize = 25.sp, fontFamily = FontFamily.Serif)
style = TextStyle(fontSize = 15.sp, fontFamily = FontFamily.Monospace) )
) Text(
text = "+${checkIn.resultExperience} EXP",
style = TextStyle(fontSize = 15.sp, fontFamily = FontFamily.Monospace)
)
}
Spacer(modifier = GlanceModifier.height(8.dp))
Row(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = OffsetDateTime.ofInstant(
checkIn.createdAt,
ZoneId.systemDefault()
)
.format(dateFormatter),
style = TextStyle(fontSize = 13.sp)
)
}
return@Column;
} }
Spacer(modifier = GlanceModifier.height(8.dp))
Row(horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = OffsetDateTime.ofInstant(checkIn.createdAt, ZoneId.systemDefault())
.format(dateFormatter),
style = TextStyle(fontSize = 13.sp)
)
}
} else {
Text(
text = "You haven't checked in today",
style = TextStyle(fontSize = 15.sp)
)
} }
} }
Text(
text = "You haven't checked in today",
style = TextStyle(fontSize = 15.sp)
)
} }
} }

View File

@ -1,8 +0,0 @@
package dev.solsynth.solian.widgets
import FeaturedPostWidget
import HomeWidgetGlanceWidgetReceiver
class FeaturedPostWidgetReceiver : HomeWidgetGlanceWidgetReceiver<FeaturedPostWidget>() {
override val glanceAppWidget = FeaturedPostWidget()
}

View File

@ -1,6 +1,7 @@
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.net.Uri
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -10,10 +11,12 @@ import androidx.glance.GlanceModifier
import androidx.glance.GlanceTheme import androidx.glance.GlanceTheme
import androidx.glance.Image import androidx.glance.Image
import androidx.glance.ImageProvider import androidx.glance.ImageProvider
import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.cornerRadius import androidx.glance.appwidget.cornerRadius
import androidx.glance.appwidget.provideContent import androidx.glance.appwidget.provideContent
import androidx.glance.background import androidx.glance.background
import androidx.glance.currentState
import androidx.glance.layout.Alignment import androidx.glance.layout.Alignment
import androidx.glance.layout.Column import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale import androidx.glance.layout.ContentScale
@ -30,23 +33,12 @@ import androidx.glance.text.FontFamily
import androidx.glance.text.FontWeight import androidx.glance.text.FontWeight
import androidx.glance.text.Text import androidx.glance.text.Text
import androidx.glance.text.TextStyle import androidx.glance.text.TextStyle
import coil3.Image
import coil3.compose.AsyncImagePainter
import coil3.compose.rememberAsyncImagePainter
import coil3.imageLoader
import coil3.request.ErrorResult
import coil3.request.ImageRequest
import coil3.request.SuccessResult
import coil3.request.crossfade
import coil3.toBitmap
import com.google.gson.FieldNamingPolicy import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken import dev.solsynth.solian.MainActivity
import dev.solsynth.solian.data.InstantAdapter import dev.solsynth.solian.data.InstantAdapter
import dev.solsynth.solian.data.SolarPagination
import dev.solsynth.solian.data.SolarPost import dev.solsynth.solian.data.SolarPost
import kotlinx.coroutines.Dispatchers import es.antonborri.home_widget.actionStartActivity
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -56,31 +48,16 @@ import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
import java.time.format.DateTimeFormatter import java.time.format.DateTimeFormatter
class FeaturedPostWidget : GlanceAppWidget() { class RandomPostWidget : GlanceAppWidget() {
override val stateDefinition: GlanceStateDefinition<*>? override val stateDefinition: GlanceStateDefinition<*>?
get() = HomeWidgetGlanceStateDefinition() get() = HomeWidgetGlanceStateDefinition()
private val defaultUrl = "https://api.sn.solsynth.dev" private val defaultUrl = "https://api.sn.solsynth.dev"
override suspend fun provideGlance(context: Context, id: GlanceId) { override suspend fun provideGlance(context: Context, id: GlanceId) {
// TODO: Fix this
// val state = currentState<HomeWidgetGlanceState>()
// val prefs = state.preferences
// var baseUrl = prefs.getString("nex_server_url", null) ?: defaultUrl
// if (baseUrl.startsWith("\"") && baseUrl.endsWith("\"")) {
// baseUrl = baseUrl.substring(1, baseUrl.length - 1)
// }
val postData = withContext(Dispatchers.IO) { fetchPostRandomly(defaultUrl) }
val avatarImage = withContext(Dispatchers.IO) {
postData?.publisher?.avatar?.let {
loadImageFromUrl(it)
}
}
provideContent { provideContent {
GlanceTheme { GlanceTheme {
GlanceContent(context, postData, avatarImage) GlanceContent(context, currentState(), null)
} }
} }
} }
@ -109,40 +86,37 @@ class FeaturedPostWidget : GlanceAppWidget() {
} }
} }
private fun fetchPostRandomly(baseUrl: String): SolarPost? { @Composable
private fun GlanceContent(
context: Context,
currentState: HomeWidgetGlanceState,
avatar: Bitmap?
) {
val prefs = currentState.preferences
val postRaw = prefs.getString("int_random_post", null)
val gson = val gson =
GsonBuilder() GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
.registerTypeAdapter(Instant::class.java, InstantAdapter()) .registerTypeAdapter(Instant::class.java, InstantAdapter())
.create() .create()
val type = object : TypeToken<SolarPagination<SolarPost>>() {}.type
val request = Request.Builder() val data: SolarPost? = postRaw?.let { postRaw ->
.url("$baseUrl/cgi/co/recommendations/shuffle?take=1") gson.fromJson(postRaw, SolarPost::class.java)
.build() } ?: null;
return try {
val response: Response = client.newCall(request).execute()
if (response.isSuccessful) {
val body = response.body?.string()
val resp = gson.fromJson<SolarPagination<SolarPost>>(body, type)
resp.data.firstOrNull()
} else {
null
}
} catch (e: IOException) {
null
}
}
@Composable
private fun GlanceContent(context: Context, data: SolarPost?, avatar: Bitmap?) {
Column( Column(
modifier = GlanceModifier modifier = GlanceModifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxHeight() .fillMaxHeight()
.background(Color.White) .background(Color.White)
.padding(16.dp) .padding(16.dp)
.clickable(
onClick = actionStartActivity<MainActivity>(
context,
Uri.parse("https://sn.solsynth.dev/posts/${data!!.id}")
)
)
) { ) {
if (data != null) { if (data != null) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
@ -154,10 +128,9 @@ class FeaturedPostWidget : GlanceAppWidget() {
.cornerRadius(18.dp), .cornerRadius(18.dp),
contentScale = ContentScale.Crop contentScale = ContentScale.Crop
) )
Spacer(modifier = GlanceModifier.width(8.dp))
} }
Spacer(modifier = GlanceModifier.width(8.dp))
Text( Text(
text = data.publisher.nick, text = data.publisher.nick,
style = TextStyle(fontSize = 15.sp) style = TextStyle(fontSize = 15.sp)
@ -174,13 +147,13 @@ class FeaturedPostWidget : GlanceAppWidget() {
if (data.body.title != null) { if (data.body.title != null) {
Text( Text(
text = data.body.title, text = data.body.title,
style = TextStyle(fontSize = 25.sp, fontFamily = FontFamily.Serif) style = TextStyle(fontSize = 25.sp)
) )
} }
if (data.body.description != null) { if (data.body.description != null) {
Text( Text(
text = data.body.description, text = data.body.description,
style = TextStyle(fontSize = 19.sp, fontFamily = FontFamily.Serif) style = TextStyle(fontSize = 19.sp)
) )
} }
@ -203,7 +176,7 @@ class FeaturedPostWidget : GlanceAppWidget() {
) )
Text( Text(
"Solar Network Featured Post", "#${data.id}",
style = TextStyle(fontSize = 11.sp, fontWeight = FontWeight.Bold), style = TextStyle(fontSize = 11.sp, fontWeight = FontWeight.Bold),
) )

View File

@ -0,0 +1,8 @@
package dev.solsynth.solian.widgets
import RandomPostWidget
import HomeWidgetGlanceWidgetReceiver
class RandomPostWidgetReceiver : HomeWidgetGlanceWidgetReceiver<RandomPostWidget>() {
override val glanceAppWidget = RandomPostWidget()
}

View File

@ -1,6 +1,6 @@
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/glance_default_loading_layout" android:initialLayout="@layout/glance_default_loading_layout"
android:minWidth="280dp" android:minWidth="240dp"
android:minHeight="40dp" android:minHeight="40dp"
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="10000"> android:updatePeriodMillis="10000">

View File

@ -3,6 +3,15 @@ allprojects {
google() google()
mavenCentral() mavenCentral()
} }
configurations.all {
resolutionStrategy {
eachDependency {
if ((requested.group == "androidx.work") && (requested.name.startsWith("work-runtime"))) {
useVersion("2.9.1")
}
}
}
}
} }
rootProject.buildDir = "../build" rootProject.buildDir = "../build"

View File

@ -34,7 +34,7 @@ class HomeWidgetProvider {
); );
} }
} else if (Platform.isAndroid) { } else if (Platform.isAndroid) {
const widgets = ["FeaturedPostWidget", "CheckInWidget"]; const widgets = ["RandomPostWidget", "CheckInWidget"];
for (final widget in widgets) { for (final widget in widgets) {
await HomeWidget.updateWidget( await HomeWidget.updateWidget(
androidName: "${widget}Receiver", androidName: "${widget}Receiver",
@ -53,7 +53,7 @@ Future<void> widgetUpdateRandomPost() async {
await HomeWidget.updateWidget( await HomeWidget.updateWidget(
name: "SolarRandomPostWidget", name: "SolarRandomPostWidget",
iOSName: "SolarRandomPostWidget", iOSName: "SolarRandomPostWidget",
androidName: "FeaturedPostWidgetReceiver", androidName: "RandomPostWidgetReceiver",
qualifiedAndroidName: "dev.solsynth.solian.widgets.FeaturedPostWidgetReceiver", qualifiedAndroidName: "dev.solsynth.solian.widgets.RandomPostWidgetReceiver",
); );
} }