Compare commits
4 Commits
65a8f1e6c3
...
d6d60e60a9
Author | SHA1 | Date | |
---|---|---|---|
d6d60e60a9 | |||
435b730f3b | |||
73468c5c6d | |||
8db6513eef |
@ -14,6 +14,7 @@ dependencies {
|
|||||||
implementation "androidx.glance:glance-appwidget:1.1.1"
|
implementation "androidx.glance:glance-appwidget:1.1.1"
|
||||||
implementation 'androidx.compose.foundation:foundation-layout-android:1.7.6'
|
implementation 'androidx.compose.foundation:foundation-layout-android:1.7.6'
|
||||||
implementation 'com.google.code.gson:gson:2.10.1'
|
implementation 'com.google.code.gson:gson:2.10.1'
|
||||||
|
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
|
||||||
implementation 'io.coil-kt.coil3:coil-compose:3.0.4'
|
implementation 'io.coil-kt.coil3:coil-compose:3.0.4'
|
||||||
implementation 'io.coil-kt.coil3:coil-network-okhttp:3.0.4'
|
implementation 'io.coil-kt.coil3:coil-network-okhttp:3.0.4'
|
||||||
}
|
}
|
||||||
@ -50,8 +51,7 @@ android {
|
|||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
minifyEnabled true
|
debuggable true
|
||||||
shrinkResources true
|
|
||||||
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
package dev.solsynth.solian.data
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarPagination<T>(val count: Int, val data: List<T>)
|
@ -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)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,139 +0,0 @@
|
|||||||
import android.content.Context
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import androidx.glance.GlanceId
|
|
||||||
import androidx.glance.GlanceModifier
|
|
||||||
import androidx.glance.appwidget.GlanceAppWidget
|
|
||||||
import androidx.glance.appwidget.provideContent
|
|
||||||
import androidx.glance.background
|
|
||||||
import androidx.glance.currentState
|
|
||||||
import androidx.glance.layout.Alignment
|
|
||||||
import androidx.glance.layout.Column
|
|
||||||
import androidx.glance.layout.Row
|
|
||||||
import androidx.glance.layout.Spacer
|
|
||||||
import androidx.glance.layout.fillMaxHeight
|
|
||||||
import androidx.glance.layout.fillMaxSize
|
|
||||||
import androidx.glance.layout.fillMaxWidth
|
|
||||||
import androidx.glance.layout.height
|
|
||||||
import androidx.glance.layout.padding
|
|
||||||
import androidx.glance.layout.width
|
|
||||||
import androidx.glance.state.GlanceStateDefinition
|
|
||||||
import androidx.glance.text.FontFamily
|
|
||||||
import androidx.glance.text.FontWeight
|
|
||||||
import androidx.glance.text.Text
|
|
||||||
import androidx.glance.text.TextStyle
|
|
||||||
import com.google.gson.FieldNamingPolicy
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.TypeAdapterFactory
|
|
||||||
import dev.solsynth.solian.data.InstantAdapter
|
|
||||||
import dev.solsynth.solian.data.SolarPost
|
|
||||||
import java.time.Instant
|
|
||||||
import java.time.LocalDateTime
|
|
||||||
import java.time.ZoneId
|
|
||||||
import java.time.format.DateTimeFormatter
|
|
||||||
|
|
||||||
class FeaturedPostWidget : GlanceAppWidget() {
|
|
||||||
override val stateDefinition: GlanceStateDefinition<*>?
|
|
||||||
get() = HomeWidgetGlanceStateDefinition()
|
|
||||||
|
|
||||||
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
|
||||||
provideContent {
|
|
||||||
GlanceContent(context, currentState())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun GlanceContent(context: Context, currentState: HomeWidgetGlanceState) {
|
|
||||||
val gson =
|
|
||||||
GsonBuilder()
|
|
||||||
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
|
||||||
.registerTypeAdapter(Instant::class.java, InstantAdapter())
|
|
||||||
.create()
|
|
||||||
|
|
||||||
val prefs = currentState.preferences
|
|
||||||
val postFeaturedRaw = prefs.getString("post_featured", null)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = GlanceModifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.fillMaxHeight()
|
|
||||||
.background(Color.White)
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
if (postFeaturedRaw != null) {
|
|
||||||
val postFeatured = gson.fromJson(postFeaturedRaw, SolarPost::class.java)
|
|
||||||
|
|
||||||
Row {
|
|
||||||
Text(
|
|
||||||
text = postFeatured?.publisher?.nick ?: "Unknown",
|
|
||||||
style = TextStyle(fontSize = 15.sp)
|
|
||||||
)
|
|
||||||
Spacer(modifier = GlanceModifier.width(8.dp))
|
|
||||||
Text(
|
|
||||||
text = "@${postFeatured?.publisher?.name}",
|
|
||||||
style = TextStyle(fontSize = 13.sp, fontFamily = FontFamily.Monospace)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = GlanceModifier.height(8.dp))
|
|
||||||
|
|
||||||
if (postFeatured?.body?.title != null) {
|
|
||||||
Text(
|
|
||||||
text = postFeatured.body.title,
|
|
||||||
style = TextStyle(fontSize = 25.sp, fontFamily = FontFamily.Serif)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (postFeatured?.body?.description != null) {
|
|
||||||
Text(
|
|
||||||
text = postFeatured.body.description,
|
|
||||||
style = TextStyle(fontSize = 19.sp, fontFamily = FontFamily.Serif)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postFeatured?.body?.title != null || postFeatured?.body?.description != null) {
|
|
||||||
Spacer(modifier = GlanceModifier.height(8.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = postFeatured?.body?.content ?: "No content",
|
|
||||||
style = TextStyle(fontSize = 15.sp),
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = GlanceModifier.height(8.dp))
|
|
||||||
|
|
||||||
|
|
||||||
if (postFeatured?.createdAt != null) {
|
|
||||||
Text(
|
|
||||||
LocalDateTime.ofInstant(postFeatured.createdAt, ZoneId.systemDefault())
|
|
||||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
|
|
||||||
style = TextStyle(fontSize = 13.sp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
"Solar Network Featured Post",
|
|
||||||
style = TextStyle(fontSize = 11.sp, fontWeight = FontWeight.Bold),
|
|
||||||
)
|
|
||||||
|
|
||||||
return@Column;
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = GlanceModifier.fillMaxSize(),
|
|
||||||
verticalAlignment = Alignment.Vertical.CenterVertically,
|
|
||||||
horizontalAlignment = Alignment.Horizontal.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "No featured posts",
|
|
||||||
style = TextStyle(fontSize = 17.sp, fontWeight = FontWeight.Bold)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Open the app to load recommendations",
|
|
||||||
style = TextStyle(fontSize = 15.sp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package dev.solsynth.solian.widgets
|
|
||||||
|
|
||||||
import FeaturedPostWidget
|
|
||||||
import HomeWidgetGlanceWidgetReceiver
|
|
||||||
|
|
||||||
class FeaturedPostWidgetReceiver : HomeWidgetGlanceWidgetReceiver<FeaturedPostWidget>() {
|
|
||||||
override val glanceAppWidget = FeaturedPostWidget()
|
|
||||||
}
|
|
@ -0,0 +1,202 @@
|
|||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import androidx.glance.GlanceId
|
||||||
|
import androidx.glance.GlanceModifier
|
||||||
|
import androidx.glance.GlanceTheme
|
||||||
|
import androidx.glance.Image
|
||||||
|
import androidx.glance.ImageProvider
|
||||||
|
import androidx.glance.action.clickable
|
||||||
|
import androidx.glance.appwidget.GlanceAppWidget
|
||||||
|
import androidx.glance.appwidget.cornerRadius
|
||||||
|
import androidx.glance.appwidget.provideContent
|
||||||
|
import androidx.glance.background
|
||||||
|
import androidx.glance.currentState
|
||||||
|
import androidx.glance.layout.Alignment
|
||||||
|
import androidx.glance.layout.Column
|
||||||
|
import androidx.glance.layout.ContentScale
|
||||||
|
import androidx.glance.layout.Row
|
||||||
|
import androidx.glance.layout.Spacer
|
||||||
|
import androidx.glance.layout.fillMaxHeight
|
||||||
|
import androidx.glance.layout.fillMaxSize
|
||||||
|
import androidx.glance.layout.fillMaxWidth
|
||||||
|
import androidx.glance.layout.height
|
||||||
|
import androidx.glance.layout.padding
|
||||||
|
import androidx.glance.layout.width
|
||||||
|
import androidx.glance.state.GlanceStateDefinition
|
||||||
|
import androidx.glance.text.FontFamily
|
||||||
|
import androidx.glance.text.FontWeight
|
||||||
|
import androidx.glance.text.Text
|
||||||
|
import androidx.glance.text.TextStyle
|
||||||
|
import com.google.gson.FieldNamingPolicy
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import dev.solsynth.solian.MainActivity
|
||||||
|
import dev.solsynth.solian.data.InstantAdapter
|
||||||
|
import dev.solsynth.solian.data.SolarPost
|
||||||
|
import es.antonborri.home_widget.actionStartActivity
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import okio.IOException
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
class RandomPostWidget : GlanceAppWidget() {
|
||||||
|
override val stateDefinition: GlanceStateDefinition<*>?
|
||||||
|
get() = HomeWidgetGlanceStateDefinition()
|
||||||
|
|
||||||
|
private val defaultUrl = "https://api.sn.solsynth.dev"
|
||||||
|
|
||||||
|
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||||
|
provideContent {
|
||||||
|
GlanceTheme {
|
||||||
|
GlanceContent(context, currentState(), null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
|
private fun resizeBitmap(bitmap: Bitmap, maxWidth: Int, maxHeight: Int): Bitmap {
|
||||||
|
val aspectRatio = bitmap.width.toFloat() / bitmap.height.toFloat()
|
||||||
|
val newWidth = if (bitmap.width > maxWidth) maxWidth else bitmap.width
|
||||||
|
val newHeight = (newWidth / aspectRatio).toInt()
|
||||||
|
val resizedBitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true)
|
||||||
|
return resizedBitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadImageFromUrl(url: String): Bitmap? {
|
||||||
|
val request = Request.Builder().url(url).build()
|
||||||
|
|
||||||
|
return try {
|
||||||
|
val response: Response = client.newCall(request).execute()
|
||||||
|
val inputStream = response.body?.byteStream()
|
||||||
|
val bitmap = BitmapFactory.decodeStream(inputStream)
|
||||||
|
resizeBitmap(bitmap, 120, 120)
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun GlanceContent(
|
||||||
|
context: Context,
|
||||||
|
currentState: HomeWidgetGlanceState,
|
||||||
|
avatar: Bitmap?
|
||||||
|
) {
|
||||||
|
val prefs = currentState.preferences
|
||||||
|
val postRaw = prefs.getString("int_random_post", null)
|
||||||
|
|
||||||
|
val gson =
|
||||||
|
GsonBuilder()
|
||||||
|
.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
|
||||||
|
.registerTypeAdapter(Instant::class.java, InstantAdapter())
|
||||||
|
.create()
|
||||||
|
|
||||||
|
val data: SolarPost? = postRaw?.let { postRaw ->
|
||||||
|
gson.fromJson(postRaw, SolarPost::class.java)
|
||||||
|
} ?: null;
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = GlanceModifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(Color.White)
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable(
|
||||||
|
onClick = actionStartActivity<MainActivity>(
|
||||||
|
context,
|
||||||
|
Uri.parse("https://sn.solsynth.dev/posts/${data!!.id}")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (data != null) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
if (avatar != null) {
|
||||||
|
Image(
|
||||||
|
provider = ImageProvider(bitmap = avatar),
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = GlanceModifier.width(36.dp).height(36.dp)
|
||||||
|
.cornerRadius(18.dp),
|
||||||
|
contentScale = ContentScale.Crop
|
||||||
|
)
|
||||||
|
Spacer(modifier = GlanceModifier.width(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = data.publisher.nick,
|
||||||
|
style = TextStyle(fontSize = 15.sp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = GlanceModifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "@${data.publisher.name}",
|
||||||
|
style = TextStyle(fontSize = 13.sp, fontFamily = FontFamily.Monospace)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = GlanceModifier.height(8.dp))
|
||||||
|
|
||||||
|
if (data.body.title != null) {
|
||||||
|
Text(
|
||||||
|
text = data.body.title,
|
||||||
|
style = TextStyle(fontSize = 25.sp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (data.body.description != null) {
|
||||||
|
Text(
|
||||||
|
text = data.body.description,
|
||||||
|
style = TextStyle(fontSize = 19.sp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.body.title != null || data.body.description != null) {
|
||||||
|
Spacer(modifier = GlanceModifier.height(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = data.body.content ?: "No content",
|
||||||
|
style = TextStyle(fontSize = 15.sp),
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = GlanceModifier.height(8.dp))
|
||||||
|
|
||||||
|
|
||||||
|
Text(
|
||||||
|
LocalDateTime.ofInstant(data.createdAt, ZoneId.systemDefault())
|
||||||
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
|
||||||
|
style = TextStyle(fontSize = 13.sp),
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"#${data.id}",
|
||||||
|
style = TextStyle(fontSize = 11.sp, fontWeight = FontWeight.Bold),
|
||||||
|
)
|
||||||
|
|
||||||
|
return@Column;
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = GlanceModifier.fillMaxSize(),
|
||||||
|
verticalAlignment = Alignment.Vertical.CenterVertically,
|
||||||
|
horizontalAlignment = Alignment.Horizontal.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Unable to fetch post",
|
||||||
|
style = TextStyle(fontSize = 17.sp, fontWeight = FontWeight.Bold)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Check your internet connection",
|
||||||
|
style = TextStyle(fontSize = 15.sp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package dev.solsynth.solian.widgets
|
||||||
|
|
||||||
|
import RandomPostWidget
|
||||||
|
import HomeWidgetGlanceWidgetReceiver
|
||||||
|
|
||||||
|
class RandomPostWidgetReceiver : HomeWidgetGlanceWidgetReceiver<RandomPostWidget>() {
|
||||||
|
override val glanceAppWidget = RandomPostWidget()
|
||||||
|
}
|
@ -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="320dp"
|
android:minWidth="240dp"
|
||||||
android:minHeight="40dp"
|
android:minHeight="40dp"
|
||||||
android:resizeMode="horizontal|vertical"
|
android:resizeMode="horizontal|vertical"
|
||||||
android:updatePeriodMillis="10000">
|
android:updatePeriodMillis="10000">
|
@ -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"
|
||||||
|
@ -36,6 +36,11 @@ target 'Runner' do
|
|||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
end
|
end
|
||||||
|
|
||||||
|
target 'SolarWidgetExtension' do
|
||||||
|
inherit! :search_paths
|
||||||
|
pod 'Kingfisher', '~> 8.0'
|
||||||
|
end
|
||||||
|
|
||||||
target 'SolarShare' do
|
target 'SolarShare' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
end
|
end
|
||||||
|
@ -56,7 +56,7 @@ PODS:
|
|||||||
- Firebase/Analytics (= 11.4.0)
|
- Firebase/Analytics (= 11.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_core (3.8.1):
|
- firebase_core (3.9.0):
|
||||||
- Firebase/CoreOnly (= 11.4.0)
|
- Firebase/CoreOnly (= 11.4.0)
|
||||||
- Flutter
|
- Flutter
|
||||||
- firebase_messaging (15.1.6):
|
- firebase_messaging (15.1.6):
|
||||||
@ -167,6 +167,7 @@ PODS:
|
|||||||
- Flutter
|
- Flutter
|
||||||
- image_picker_ios (0.0.1):
|
- image_picker_ios (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
|
- Kingfisher (8.1.3)
|
||||||
- livekit_client (2.3.2):
|
- livekit_client (2.3.2):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_webrtc
|
- flutter_webrtc
|
||||||
@ -216,6 +217,8 @@ PODS:
|
|||||||
- wakelock_plus (0.0.1):
|
- wakelock_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- WebRTC-SDK (125.6422.06)
|
- WebRTC-SDK (125.6422.06)
|
||||||
|
- workmanager (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
DEPENDENCIES:
|
DEPENDENCIES:
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||||
@ -233,6 +236,7 @@ DEPENDENCIES:
|
|||||||
- gal (from `.symlinks/plugins/gal/darwin`)
|
- gal (from `.symlinks/plugins/gal/darwin`)
|
||||||
- home_widget (from `.symlinks/plugins/home_widget/ios`)
|
- home_widget (from `.symlinks/plugins/home_widget/ios`)
|
||||||
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
|
||||||
|
- Kingfisher (~> 8.0)
|
||||||
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
- livekit_client (from `.symlinks/plugins/livekit_client/ios`)
|
||||||
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
- media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`)
|
||||||
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
- media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`)
|
||||||
@ -249,6 +253,7 @@ DEPENDENCIES:
|
|||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
- volume_controller (from `.symlinks/plugins/volume_controller/ios`)
|
||||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||||
|
- workmanager (from `.symlinks/plugins/workmanager/ios`)
|
||||||
|
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
@ -263,6 +268,7 @@ SPEC REPOS:
|
|||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
|
- Kingfisher
|
||||||
- nanopb
|
- nanopb
|
||||||
- PromisesObjC
|
- PromisesObjC
|
||||||
- SAMKeychain
|
- SAMKeychain
|
||||||
@ -333,6 +339,8 @@ EXTERNAL SOURCES:
|
|||||||
:path: ".symlinks/plugins/volume_controller/ios"
|
:path: ".symlinks/plugins/volume_controller/ios"
|
||||||
wakelock_plus:
|
wakelock_plus:
|
||||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||||
|
workmanager:
|
||||||
|
:path: ".symlinks/plugins/workmanager/ios"
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
SPEC CHECKSUMS:
|
||||||
connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695
|
connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695
|
||||||
@ -344,7 +352,7 @@ SPEC CHECKSUMS:
|
|||||||
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808
|
||||||
Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99
|
Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99
|
||||||
firebase_analytics: 2815af29d49c1a994652abd37a5b001a88bc7b75
|
firebase_analytics: 2815af29d49c1a994652abd37a5b001a88bc7b75
|
||||||
firebase_core: 418aed674e9a0b8b6088aec16cde82a811f6261f
|
firebase_core: b62a5080210edad3f2934314a8b2c6f5124e8e10
|
||||||
firebase_messaging: 98619a0572d82cfb3668e78859ba9f1110e268c9
|
firebase_messaging: 98619a0572d82cfb3668e78859ba9f1110e268c9
|
||||||
FirebaseAnalytics: 3feef9ae8733c567866342a1000691baaa7cad49
|
FirebaseAnalytics: 3feef9ae8733c567866342a1000691baaa7cad49
|
||||||
FirebaseCore: e0510f1523bc0eb21653cac00792e1e2bd6f1771
|
FirebaseCore: e0510f1523bc0eb21653cac00792e1e2bd6f1771
|
||||||
@ -361,6 +369,7 @@ SPEC CHECKSUMS:
|
|||||||
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||||
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
|
Kingfisher: f2af9028b16baf9dc6c07c570072bc41cbf009ef
|
||||||
livekit_client: 6108dad8b77db3142bafd4c630f471d0a54335cd
|
livekit_client: 6108dad8b77db3142bafd4c630f471d0a54335cd
|
||||||
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1
|
||||||
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a
|
||||||
@ -381,9 +390,10 @@ SPEC CHECKSUMS:
|
|||||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||||
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
|
||||||
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9
|
||||||
wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1
|
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
|
||||||
WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db
|
WebRTC-SDK: 79942c006ea64f6fb48d7da8a4786dfc820bc1db
|
||||||
|
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||||
|
|
||||||
PODFILE CHECKSUM: 23d35ad686cacf9103d1e85035ee4f3e9750630d
|
PODFILE CHECKSUM: f36978bb00ec01cd27f69faaf9a821024de98fcc
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 77;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
0B21A2B78F1AE403D3BE143E /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26CC8DE2338798EAB472B62D /* Pods_RunnerTests.framework */; };
|
0B21A2B78F1AE403D3BE143E /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26CC8DE2338798EAB472B62D /* Pods_RunnerTests.framework */; };
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
2630F2992106E991467A6FC4 /* Pods_SolarWidgetExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */; };
|
||||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; };
|
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; };
|
||||||
@ -86,6 +87,7 @@
|
|||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarShare.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarShare.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
2134F3903A0E8EB8CC2670BE /* Pods-SolarWidgetExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarWidgetExtension.debug.xcconfig"; path = "Target Support Files/Pods-SolarWidgetExtension/Pods-SolarWidgetExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
26CC8DE2338798EAB472B62D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
26CC8DE2338798EAB472B62D /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
2DA1B873D39B9FD33298BBCE /* Pods-SolarShare.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.profile.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.profile.xcconfig"; sourceTree = "<group>"; };
|
2DA1B873D39B9FD33298BBCE /* Pods-SolarShare.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.profile.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
@ -96,6 +98,7 @@
|
|||||||
4A2F84B6033057E3BD2C7CB8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
4A2F84B6033057E3BD2C7CB8 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
5922A50B1231B06B92E31F20 /* Pods-SolarShare.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.debug.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.debug.xcconfig"; sourceTree = "<group>"; };
|
5922A50B1231B06B92E31F20 /* Pods-SolarShare.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.debug.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
64FBE78F9C282712818D6D95 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
64FBE78F9C282712818D6D95 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
6618E2E3015264643175B43D /* Pods-SolarWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarWidgetExtension.release.xcconfig"; path = "Target Support Files/Pods-SolarWidgetExtension/Pods-SolarWidgetExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
72E9279EFA6DAC00BBAC493C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
72E9279EFA6DAC00BBAC493C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
73111C212CEE3D5E004CF4B3 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
73111C212CEE3D5E004CF4B3 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||||
@ -117,7 +120,9 @@
|
|||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
A2C24C5238FAC44EA2CCF738 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
A2C24C5238FAC44EA2CCF738 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||||
B1763F1D7318A2745CA7EDFE /* Pods-SolarShare.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.release.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.release.xcconfig"; sourceTree = "<group>"; };
|
B1763F1D7318A2745CA7EDFE /* Pods-SolarShare.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarShare.release.xcconfig"; path = "Target Support Files/Pods-SolarShare/Pods-SolarShare.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
BCE0C4086B776A27B202B373 /* Pods-SolarWidgetExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarWidgetExtension.profile.xcconfig"; path = "Target Support Files/Pods-SolarWidgetExtension/Pods-SolarWidgetExtension.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarWidgetExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
@ -217,6 +222,7 @@
|
|||||||
files = (
|
files = (
|
||||||
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */,
|
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */,
|
||||||
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */,
|
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */,
|
||||||
|
2630F2992106E991467A6FC4 /* Pods_SolarWidgetExtension.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -262,6 +268,7 @@
|
|||||||
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */,
|
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */,
|
||||||
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */,
|
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */,
|
||||||
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */,
|
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */,
|
||||||
|
F357CFDA89A0D9E5692846D4 /* Pods_SolarWidgetExtension.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -344,6 +351,9 @@
|
|||||||
5922A50B1231B06B92E31F20 /* Pods-SolarShare.debug.xcconfig */,
|
5922A50B1231B06B92E31F20 /* Pods-SolarShare.debug.xcconfig */,
|
||||||
B1763F1D7318A2745CA7EDFE /* Pods-SolarShare.release.xcconfig */,
|
B1763F1D7318A2745CA7EDFE /* Pods-SolarShare.release.xcconfig */,
|
||||||
2DA1B873D39B9FD33298BBCE /* Pods-SolarShare.profile.xcconfig */,
|
2DA1B873D39B9FD33298BBCE /* Pods-SolarShare.profile.xcconfig */,
|
||||||
|
2134F3903A0E8EB8CC2670BE /* Pods-SolarWidgetExtension.debug.xcconfig */,
|
||||||
|
6618E2E3015264643175B43D /* Pods-SolarWidgetExtension.release.xcconfig */,
|
||||||
|
BCE0C4086B776A27B202B373 /* Pods-SolarWidgetExtension.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -374,6 +384,7 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 738C1EBA2D0D76A500A215F3 /* Build configuration list for PBXNativeTarget "SolarWidgetExtension" */;
|
buildConfigurationList = 738C1EBA2D0D76A500A215F3 /* Build configuration list for PBXNativeTarget "SolarWidgetExtension" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
F2FCDA0E1BD434BF4883AFFD /* [CP] Check Pods Manifest.lock */,
|
||||||
738C1EA72D0D76A400A215F3 /* Sources */,
|
738C1EA72D0D76A400A215F3 /* Sources */,
|
||||||
738C1EA82D0D76A400A215F3 /* Frameworks */,
|
738C1EA82D0D76A400A215F3 /* Frameworks */,
|
||||||
738C1EA92D0D76A400A215F3 /* Resources */,
|
738C1EA92D0D76A400A215F3 /* Resources */,
|
||||||
@ -710,6 +721,28 @@
|
|||||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
F2FCDA0E1BD434BF4883AFFD /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-SolarWidgetExtension-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
FC4815D44D909666EB1FA614 /* [CP] Embed Pods Frameworks */ = {
|
FC4815D44D909666EB1FA614 /* [CP] Embed Pods Frameworks */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -879,7 +912,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@ -947,6 +980,7 @@
|
|||||||
};
|
};
|
||||||
738C1EBB2D0D76A500A215F3 /* Debug */ = {
|
738C1EBB2D0D76A500A215F3 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 2134F3903A0E8EB8CC2670BE /* Pods-SolarWidgetExtension.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
@ -990,6 +1024,7 @@
|
|||||||
};
|
};
|
||||||
738C1EBC2D0D76A500A215F3 /* Release */ = {
|
738C1EBC2D0D76A500A215F3 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 6618E2E3015264643175B43D /* Pods-SolarWidgetExtension.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
@ -1030,6 +1065,7 @@
|
|||||||
};
|
};
|
||||||
738C1EBD2D0D76A500A215F3 /* Profile */ = {
|
738C1EBD2D0D76A500A215F3 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = BCE0C4086B776A27B202B373 /* Pods-SolarWidgetExtension.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
@ -1433,7 +1469,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@ -1461,7 +1497,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
import workmanager
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
@ -9,6 +11,12 @@ import UIKit
|
|||||||
) -> Bool {
|
) -> Bool {
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
|
||||||
|
WorkmanagerPlugin.setPluginRegistrantCallback { registry in
|
||||||
|
GeneratedPluginRegistrant.register(with: registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*5))
|
||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>AppGroupId</key>
|
||||||
|
<string>group.solsynth.solian</string>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
@ -27,6 +29,17 @@
|
|||||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
@ -66,8 +79,6 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>AppGroupId</key>
|
|
||||||
<string>group.solsynth.solian</string>
|
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
@ -75,16 +86,5 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleURLTypes</key>
|
|
||||||
<array>
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleTypeRole</key>
|
|
||||||
<string>Editor</string>
|
|
||||||
<key>CFBundleURLSchemes</key>
|
|
||||||
<array>
|
|
||||||
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
||||||
</array>
|
|
||||||
</dict>
|
|
||||||
</array>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
@ -29,10 +29,13 @@ struct CheckInProvider: TimelineProvider {
|
|||||||
user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!)
|
user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!)
|
||||||
}
|
}
|
||||||
|
|
||||||
let checkInRaw = prefs?.string(forKey: "today_check_in")
|
let checkInRaw = prefs?.string(forKey: "pas_check_in_record")
|
||||||
var checkIn: SolarCheckInRecord?
|
var checkIn: SolarCheckInRecord?
|
||||||
if let checkInRaw = checkInRaw {
|
if let checkInRaw = checkInRaw {
|
||||||
checkIn = try! jsonDecoder.decode(SolarCheckInRecord.self, from: checkInRaw.data(using: .utf8)!)
|
checkIn = try! jsonDecoder.decode(SolarCheckInRecord.self, from: checkInRaw.data(using: .utf8)!)
|
||||||
|
if checkIn != nil && Calendar.current.isDate(checkIn!.createdAt, inSameDayAs: Date()) {
|
||||||
|
checkIn = nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let entry = CheckInEntry(
|
let entry = CheckInEntry(
|
||||||
@ -105,7 +108,7 @@ struct CheckInWidgetEntryView : View {
|
|||||||
Button("Check In", systemImage: "checkmark", action: checkIn).labelStyle(.iconOnly).buttonBorderShape(.circle).frame(maxWidth: .infinity, alignment: .trailing)
|
Button("Check In", systemImage: "checkmark", action: checkIn).labelStyle(.iconOnly).buttonBorderShape(.circle).frame(maxWidth: .infinity, alignment: .trailing)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.padding(8)
|
}.padding(8).widgetURL(URL(string: "https://sn.solsynth.dev"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,241 +0,0 @@
|
|||||||
//
|
|
||||||
// FeaturedPostWidget.swift
|
|
||||||
// Runner
|
|
||||||
//
|
|
||||||
// Created by LittleSheep on 2024/12/14.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import WidgetKit
|
|
||||||
|
|
||||||
struct FeaturedPostProvider: TimelineProvider {
|
|
||||||
func placeholder(in context: Context) -> FeaturedPostEntry {
|
|
||||||
FeaturedPostEntry(date: Date(), user: nil, featuredPost: nil, family: .systemMedium)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSnapshot(in context: Context, completion: @escaping (FeaturedPostEntry) -> ()) {
|
|
||||||
let prefs = UserDefaults(suiteName: "group.solsynth.solian")
|
|
||||||
|
|
||||||
let dateFormatter = DateFormatter()
|
|
||||||
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
|
|
||||||
|
|
||||||
let jsonDecoder = JSONDecoder()
|
|
||||||
jsonDecoder.dateDecodingStrategy = .formatted(dateFormatter)
|
|
||||||
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
|
|
||||||
|
|
||||||
let userRaw = prefs?.string(forKey: "user")
|
|
||||||
var user: SolarUser?
|
|
||||||
if let userRaw = userRaw {
|
|
||||||
user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!)
|
|
||||||
}
|
|
||||||
|
|
||||||
let featuredPostRaw = prefs?.string(forKey: "post_featured")
|
|
||||||
var featuredPosts: [SolarPost]?
|
|
||||||
if let featuredPostRaw = featuredPostRaw {
|
|
||||||
featuredPosts = try! jsonDecoder.decode([SolarPost].self, from: featuredPostRaw.data(using: .utf8)!)
|
|
||||||
}
|
|
||||||
|
|
||||||
let entry = FeaturedPostEntry(
|
|
||||||
date: Date(),
|
|
||||||
user: user,
|
|
||||||
featuredPost: featuredPosts?.first,
|
|
||||||
family: context.family
|
|
||||||
)
|
|
||||||
completion(entry)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
|
||||||
getSnapshot(in: context) { (entry) in
|
|
||||||
let timeline = Timeline(entries: [entry], policy: .atEnd)
|
|
||||||
completion(timeline)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FeaturedPostEntry: TimelineEntry {
|
|
||||||
let date: Date
|
|
||||||
let user: SolarUser?
|
|
||||||
let featuredPost: SolarPost?
|
|
||||||
|
|
||||||
let family: WidgetFamily
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FeaturedPostWidgetEntryView : View {
|
|
||||||
var entry: FeaturedPostProvider.Entry
|
|
||||||
|
|
||||||
private let resultTierSymbols: [String] = ["大凶", "凶", "中平", "大吉", "吉"]
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
|
||||||
if let featuredPost = entry.featuredPost {
|
|
||||||
HStack(alignment: .center) {
|
|
||||||
if let avatar = featuredPost.publisher.avatar {
|
|
||||||
let avatarUrl = getAttachmentUrl(for: avatar)
|
|
||||||
let size: CGFloat = 24
|
|
||||||
|
|
||||||
AsyncImage(url: URL(string: avatarUrl)) { image in
|
|
||||||
image.resizable()
|
|
||||||
.aspectRatio(contentMode: .fit)
|
|
||||||
.frame(width: size, height: size)
|
|
||||||
.cornerRadius(size / 2)
|
|
||||||
.overlay(
|
|
||||||
Circle()
|
|
||||||
.stroke(Color.white, lineWidth: 4)
|
|
||||||
.frame(width: size, height: size)
|
|
||||||
)
|
|
||||||
.shadow(radius: 10)
|
|
||||||
.frame(width: 24, height: 24, alignment: .center)
|
|
||||||
} placeholder: {
|
|
||||||
ProgressView().frame(width: 24, height: 24, alignment: .center)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text("@\(featuredPost.publisher.name)")
|
|
||||||
.font(.system(size: 13, design: .monospaced))
|
|
||||||
.opacity(0.9)
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
}.frame(maxWidth: .infinity).padding(.bottom, 12)
|
|
||||||
|
|
||||||
if featuredPost.body.title != nil || featuredPost.body.description != nil {
|
|
||||||
VStack(alignment: .leading) {
|
|
||||||
if let title = featuredPost.body.title {
|
|
||||||
Text(title)
|
|
||||||
.font(.system(size: 17))
|
|
||||||
}
|
|
||||||
if let description = featuredPost.body.description {
|
|
||||||
Text(description)
|
|
||||||
.font(.system(size: 15))
|
|
||||||
}
|
|
||||||
}.padding(.bottom, 8)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let content = featuredPost.body.content {
|
|
||||||
if (featuredPost.body.title == nil && featuredPost.body.description == nil) || entry.family == .systemLarge || entry.family == .systemExtraLarge {
|
|
||||||
Text(
|
|
||||||
(entry.family == .systemLarge || entry.family == .systemExtraLarge) ? content : content.replacingOccurrences(of: "\n", with: " ")
|
|
||||||
)
|
|
||||||
.font(.system(size: 15))
|
|
||||||
} else {
|
|
||||||
Text("\(Image(systemName: "plus")) total \(content.count) characters")
|
|
||||||
.font(.system(size: 11, design: .monospaced))
|
|
||||||
.opacity(0.75)
|
|
||||||
.padding(.top, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let attachment = featuredPost.body.attachments {
|
|
||||||
if attachment.count == 1 {
|
|
||||||
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachment")
|
|
||||||
.font(.system(size: 11, design: .monospaced))
|
|
||||||
.opacity(0.75)
|
|
||||||
.padding(.top, 1)
|
|
||||||
} else if attachment.count > 1 {
|
|
||||||
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachments")
|
|
||||||
.font(.system(size: 11, design: .monospaced))
|
|
||||||
.opacity(0.75)
|
|
||||||
.padding(.top, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer()
|
|
||||||
|
|
||||||
Text(featuredPost.publishedAt!, format: .dateTime)
|
|
||||||
.font(.system(size: 11))
|
|
||||||
Text("Solar Network Featured Posts")
|
|
||||||
.font(.system(size: 9))
|
|
||||||
} else {
|
|
||||||
VStack(alignment: .center) {
|
|
||||||
Text("No Recommendations").font(.system(size: 19, weight: .bold))
|
|
||||||
Text("Click the widget to open the app to load featured posts")
|
|
||||||
.font(.system(size: 15))
|
|
||||||
.multilineTextAlignment(.center)
|
|
||||||
}.frame(alignment: .center)
|
|
||||||
}
|
|
||||||
}.padding(8).frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FeaturedPostWidget: Widget {
|
|
||||||
let kind: String = "SolarFeaturedPostWidget"
|
|
||||||
|
|
||||||
var body: some WidgetConfiguration {
|
|
||||||
StaticConfiguration(kind: kind, provider: FeaturedPostProvider()) { entry in
|
|
||||||
if #available(iOS 17.0, *) {
|
|
||||||
FeaturedPostWidgetEntryView(entry: entry)
|
|
||||||
.containerBackground(.fill.tertiary, for: .widget)
|
|
||||||
} else {
|
|
||||||
FeaturedPostWidgetEntryView(entry: entry)
|
|
||||||
.padding()
|
|
||||||
.background()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.configurationDisplayName("Featured Posts")
|
|
||||||
.description("View the featured posts on the Solar Network")
|
|
||||||
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview(as: .systemSmall) {
|
|
||||||
FeaturedPostWidget()
|
|
||||||
} timeline: {
|
|
||||||
FeaturedPostEntry(date: Date.now, user: nil, featuredPost: nil, family: .systemLarge)
|
|
||||||
FeaturedPostEntry(
|
|
||||||
date: .now,
|
|
||||||
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
|
||||||
featuredPost: SolarPost(
|
|
||||||
id: 1,
|
|
||||||
body: SolarPostBody(
|
|
||||||
content: "Hello, World",
|
|
||||||
title: nil,
|
|
||||||
description: nil,
|
|
||||||
attachments: ["zb2hiUEmYcnpHfVN"]
|
|
||||||
),
|
|
||||||
publisher: SolarPublisher(
|
|
||||||
id: 1,
|
|
||||||
name: "demo",
|
|
||||||
nick: "Deemo",
|
|
||||||
description: nil,
|
|
||||||
avatar: "IZxCFkJUPKRijFCx",
|
|
||||||
banner: nil,
|
|
||||||
createdAt: .now,
|
|
||||||
updatedAt: .now
|
|
||||||
),
|
|
||||||
publisherId: 1,
|
|
||||||
createdAt: .now,
|
|
||||||
updatedAt: .now,
|
|
||||||
editedAt: nil,
|
|
||||||
publishedAt: .now
|
|
||||||
),
|
|
||||||
family: .systemSmall
|
|
||||||
)
|
|
||||||
FeaturedPostEntry(
|
|
||||||
date: .now,
|
|
||||||
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
|
||||||
featuredPost: SolarPost(
|
|
||||||
id: 1,
|
|
||||||
body: SolarPostBody(
|
|
||||||
content: "Hello, World\nOh wow",
|
|
||||||
title: "Title",
|
|
||||||
description: "Description",
|
|
||||||
attachments: ["zb2hiUEmYcnpHfVN"]
|
|
||||||
),
|
|
||||||
publisher: SolarPublisher(
|
|
||||||
id: 1,
|
|
||||||
name: "demo",
|
|
||||||
nick: "Deemo",
|
|
||||||
description: nil,
|
|
||||||
avatar: "IZxCFkJUPKRijFCx",
|
|
||||||
banner: nil,
|
|
||||||
createdAt: .now,
|
|
||||||
updatedAt: .now
|
|
||||||
),
|
|
||||||
publisherId: 1,
|
|
||||||
createdAt: .now,
|
|
||||||
updatedAt: .now,
|
|
||||||
editedAt: nil,
|
|
||||||
publishedAt: .now
|
|
||||||
),
|
|
||||||
family: .systemLarge
|
|
||||||
)
|
|
||||||
}
|
|
235
ios/SolarWidget/RandomPostWidget.swift
Normal file
235
ios/SolarWidget/RandomPostWidget.swift
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
//
|
||||||
|
// RandomPostWidget.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2024/12/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import WidgetKit
|
||||||
|
import Kingfisher
|
||||||
|
|
||||||
|
struct RandomPostProvider: TimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> RandomPostEntry {
|
||||||
|
RandomPostEntry(date: Date(), user: nil, randomPost: nil, family: .systemMedium)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (RandomPostEntry) -> ()) {
|
||||||
|
let prefs = UserDefaults(suiteName: "group.solsynth.solian")
|
||||||
|
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
|
||||||
|
|
||||||
|
let jsonDecoder = JSONDecoder()
|
||||||
|
jsonDecoder.dateDecodingStrategy = .formatted(dateFormatter)
|
||||||
|
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
|
|
||||||
|
let userRaw = prefs?.string(forKey: "user")
|
||||||
|
var user: SolarUser?
|
||||||
|
if let userRaw = userRaw {
|
||||||
|
user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!)
|
||||||
|
}
|
||||||
|
|
||||||
|
let randomPostRaw = prefs?.string(forKey: "int_random_post")
|
||||||
|
var randomPost: SolarPost?
|
||||||
|
if let randomPostRaw = randomPostRaw {
|
||||||
|
randomPost = try! jsonDecoder.decode(SolarPost.self, from: randomPostRaw.data(using: .utf8)!)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let entry = RandomPostEntry(
|
||||||
|
date: Date(),
|
||||||
|
user: user,
|
||||||
|
randomPost: randomPost,
|
||||||
|
family: context.family
|
||||||
|
)
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
getSnapshot(in: context) { (entry) in
|
||||||
|
let timeline = Timeline(entries: [entry], policy: .atEnd)
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RandomPostEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let user: SolarUser?
|
||||||
|
let randomPost: SolarPost?
|
||||||
|
|
||||||
|
let family: WidgetFamily
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RandomPostWidgetEntryView : View {
|
||||||
|
var entry: RandomPostProvider.Entry
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
if let randomPost = entry.randomPost {
|
||||||
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
|
HStack(alignment: .center) {
|
||||||
|
if let avatar = randomPost.publisher.avatar {
|
||||||
|
let avatarUrl = getAttachmentUrl(for: avatar)
|
||||||
|
let size: CGFloat = 28
|
||||||
|
|
||||||
|
KFImage.url(URL(string: avatarUrl))
|
||||||
|
.resizable()
|
||||||
|
.setProcessor(ResizingImageProcessor(referenceSize: CGSize(width: size, height: size), mode: .aspectFit))
|
||||||
|
.aspectRatio(contentMode: .fit)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
.cornerRadius(size / 2)
|
||||||
|
.frame(width: size, height: size, alignment: .center)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("@\(randomPost.publisher.name)")
|
||||||
|
.font(.system(size: 13, design: .monospaced))
|
||||||
|
.opacity(0.9)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}.frame(maxWidth: .infinity).padding(.bottom, 12)
|
||||||
|
|
||||||
|
if randomPost.body.title != nil || randomPost.body.description != nil {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
if let title = randomPost.body.title {
|
||||||
|
Text(title)
|
||||||
|
.font(.system(size: 17))
|
||||||
|
}
|
||||||
|
if let description = randomPost.body.description {
|
||||||
|
Text(description)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
}
|
||||||
|
}.padding(.bottom, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let content = randomPost.body.content {
|
||||||
|
if (randomPost.body.title == nil && randomPost.body.description == nil) || entry.family == .systemLarge || entry.family == .systemExtraLarge {
|
||||||
|
Text(
|
||||||
|
(entry.family == .systemLarge || entry.family == .systemExtraLarge) ? content : content.replacingOccurrences(of: "\n", with: " ")
|
||||||
|
)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
} else {
|
||||||
|
Text("\(Image(systemName: "plus")) total \(content.count) characters")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let attachment = randomPost.body.attachments {
|
||||||
|
if attachment.count == 1 {
|
||||||
|
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachment")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 2)
|
||||||
|
} else if attachment.count > 1 {
|
||||||
|
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachments")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(randomPost.publishedAt!, format: .dateTime)
|
||||||
|
.font(.system(size: 11))
|
||||||
|
Text("#\(randomPost.id)")
|
||||||
|
.font(.system(size: 9))
|
||||||
|
}.widgetURL(URL(string: "https://sn.solsynth.dev/posts/\(randomPost.id)"))
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Text("No Recommendations").font(.system(size: 19, weight: .bold))
|
||||||
|
Text("Open the app to load some random post")
|
||||||
|
.font(.system(size: 15))
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}.frame(alignment: .center)
|
||||||
|
}
|
||||||
|
}.padding(8).frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RandomPostWidget: Widget {
|
||||||
|
let kind: String = "SolarRandomPostWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: RandomPostProvider()) { entry in
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
RandomPostWidgetEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
} else {
|
||||||
|
RandomPostWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Random Post")
|
||||||
|
.description("View the random post on the Solar Network")
|
||||||
|
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
RandomPostWidget()
|
||||||
|
} timeline: {
|
||||||
|
RandomPostEntry(date: Date.now, user: nil, randomPost: nil, family: .systemLarge)
|
||||||
|
RandomPostEntry(
|
||||||
|
date: .now,
|
||||||
|
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
||||||
|
randomPost: SolarPost(
|
||||||
|
id: 1,
|
||||||
|
body: SolarPostBody(
|
||||||
|
content: "Hello, World",
|
||||||
|
title: nil,
|
||||||
|
description: nil,
|
||||||
|
attachments: ["zb2hiUEmYcnpHfVN"]
|
||||||
|
),
|
||||||
|
publisher: SolarPublisher(
|
||||||
|
id: 1,
|
||||||
|
name: "demo",
|
||||||
|
nick: "Deemo",
|
||||||
|
description: nil,
|
||||||
|
avatar: "IZxCFkJUPKRijFCx",
|
||||||
|
banner: nil,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now
|
||||||
|
),
|
||||||
|
publisherId: 1,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now,
|
||||||
|
editedAt: nil,
|
||||||
|
publishedAt: .now
|
||||||
|
),
|
||||||
|
family: .systemSmall
|
||||||
|
)
|
||||||
|
RandomPostEntry(
|
||||||
|
date: .now,
|
||||||
|
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
||||||
|
randomPost: SolarPost(
|
||||||
|
id: 1,
|
||||||
|
body: SolarPostBody(
|
||||||
|
content: "Hello, World\nOh wow",
|
||||||
|
title: "Title",
|
||||||
|
description: "Description",
|
||||||
|
attachments: ["zb2hiUEmYcnpHfVN"]
|
||||||
|
),
|
||||||
|
publisher: SolarPublisher(
|
||||||
|
id: 1,
|
||||||
|
name: "demo",
|
||||||
|
nick: "Deemo",
|
||||||
|
description: nil,
|
||||||
|
avatar: "IZxCFkJUPKRijFCx",
|
||||||
|
banner: nil,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now
|
||||||
|
),
|
||||||
|
publisherId: 1,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now,
|
||||||
|
editedAt: nil,
|
||||||
|
publishedAt: .now
|
||||||
|
),
|
||||||
|
family: .systemLarge
|
||||||
|
)
|
||||||
|
}
|
@ -12,6 +12,6 @@ import SwiftUI
|
|||||||
struct SolarWidgetBundle: WidgetBundle {
|
struct SolarWidgetBundle: WidgetBundle {
|
||||||
var body: some Widget {
|
var body: some Widget {
|
||||||
CheckInWidget()
|
CheckInWidget()
|
||||||
FeaturedPostWidget()
|
RandomPostWidget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,24 @@ import 'package:surface/types/realm.dart';
|
|||||||
import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
|
import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
import 'package:surface/widgets/version_label.dart';
|
import 'package:surface/widgets/version_label.dart';
|
||||||
|
import 'package:workmanager/workmanager.dart';
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
void appBackgroundDispatcher() {
|
||||||
|
Workmanager().executeTask((task, inputData) async {
|
||||||
|
print("Native called background task: $task");
|
||||||
|
switch (task) {
|
||||||
|
case Workmanager.iOSBackgroundTask:
|
||||||
|
await Future.wait([widgetUpdateRandomPost()]);
|
||||||
|
return true;
|
||||||
|
case "WidgetUpdateRandomPost":
|
||||||
|
await widgetUpdateRandomPost();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -64,6 +82,20 @@ void main() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
|
Workmanager().initialize(
|
||||||
|
appBackgroundDispatcher,
|
||||||
|
isInDebugMode: kDebugMode,
|
||||||
|
);
|
||||||
|
Workmanager().registerPeriodicTask(
|
||||||
|
"widget-update-random-post",
|
||||||
|
"WidgetUpdateRandomPost",
|
||||||
|
frequency: Duration(minutes: 1),
|
||||||
|
constraints: Constraints(networkType: NetworkType.connected),
|
||||||
|
tag: "widget-update",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
runApp(const SolianApp());
|
runApp(const SolianApp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,10 +225,14 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _postInitialization() async {
|
||||||
|
await widgetUpdateRandomPost();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_initialize();
|
_initialize().then((_) => _postInitialization());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -71,7 +71,36 @@ class SnNetworkProvider {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initializeUserAgent() async {
|
static Future<Dio> createOffContextClient() async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final client = Dio();
|
||||||
|
client.interceptors.add(RetryInterceptor(
|
||||||
|
dio: client,
|
||||||
|
retries: 3,
|
||||||
|
retryDelays: const [
|
||||||
|
Duration(milliseconds: 300),
|
||||||
|
Duration(milliseconds: 1000),
|
||||||
|
Duration(milliseconds: 3000),
|
||||||
|
],
|
||||||
|
));
|
||||||
|
final ua = await _getUserAgent();
|
||||||
|
client.interceptors.add(
|
||||||
|
InterceptorsWrapper(
|
||||||
|
onRequest: (
|
||||||
|
RequestOptions options,
|
||||||
|
RequestInterceptorHandler handler,
|
||||||
|
) async {
|
||||||
|
options.headers['User-Agent'] = ua;
|
||||||
|
return handler.next(options);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
client.options.baseUrl = prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||||
|
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String> _getUserAgent() async {
|
||||||
final String platformInfo;
|
final String platformInfo;
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
final deviceInfo = await DeviceInfoPlugin().webBrowserInfo;
|
final deviceInfo = await DeviceInfoPlugin().webBrowserInfo;
|
||||||
@ -97,7 +126,11 @@ class SnNetworkProvider {
|
|||||||
|
|
||||||
final packageInfo = await PackageInfo.fromPlatform();
|
final packageInfo = await PackageInfo.fromPlatform();
|
||||||
|
|
||||||
_userAgent = 'Solian/${packageInfo.version}+${packageInfo.buildNumber} ($platformInfo)';
|
return 'Solian/${packageInfo.version}+${packageInfo.buildNumber} ($platformInfo)';
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initializeUserAgent() async {
|
||||||
|
_userAgent = await _getUserAgent();
|
||||||
}
|
}
|
||||||
|
|
||||||
final tkLock = Lock();
|
final tkLock = Lock();
|
||||||
|
@ -4,6 +4,8 @@ import 'dart:io';
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:home_widget/home_widget.dart';
|
import 'package:home_widget/home_widget.dart';
|
||||||
|
import 'package:surface/providers/sn_network.dart';
|
||||||
|
import 'package:surface/types/post.dart';
|
||||||
|
|
||||||
class HomeWidgetProvider {
|
class HomeWidgetProvider {
|
||||||
HomeWidgetProvider(BuildContext context);
|
HomeWidgetProvider(BuildContext context);
|
||||||
@ -15,8 +17,7 @@ class HomeWidgetProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveWidgetData(String id, dynamic data,
|
Future<void> saveWidgetData(String id, dynamic data, {bool update = true}) async {
|
||||||
{bool update = true}) async {
|
|
||||||
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return;
|
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return;
|
||||||
await HomeWidget.saveWidgetData(id, jsonEncode(data));
|
await HomeWidget.saveWidgetData(id, jsonEncode(data));
|
||||||
if (update) await updateWidget();
|
if (update) await updateWidget();
|
||||||
@ -25,7 +26,7 @@ class HomeWidgetProvider {
|
|||||||
Future<void> updateWidget() async {
|
Future<void> updateWidget() async {
|
||||||
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return;
|
if (kIsWeb || !(Platform.isAndroid || Platform.isIOS)) return;
|
||||||
if (Platform.isIOS) {
|
if (Platform.isIOS) {
|
||||||
const widgets = ["SolarFeaturedPostWidget", "SolarCheckInWidget"];
|
const widgets = ["SolarRandomPostWidget", "SolarCheckInWidget"];
|
||||||
for (final widget in widgets) {
|
for (final widget in widgets) {
|
||||||
await HomeWidget.updateWidget(
|
await HomeWidget.updateWidget(
|
||||||
name: widget,
|
name: widget,
|
||||||
@ -33,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",
|
||||||
@ -43,3 +44,16 @@ class HomeWidgetProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> widgetUpdateRandomPost() async {
|
||||||
|
final snc = await SnNetworkProvider.createOffContextClient();
|
||||||
|
final resp = await snc.get('/cgi/co/recommendations/shuffle?take=1');
|
||||||
|
final post = SnPost.fromJson(resp.data['data'][0]);
|
||||||
|
await HomeWidget.saveWidgetData("int_random_post", jsonEncode(post.toJson()));
|
||||||
|
await HomeWidget.updateWidget(
|
||||||
|
name: "SolarRandomPostWidget",
|
||||||
|
iOSName: "SolarRandomPostWidget",
|
||||||
|
androidName: "RandomPostWidgetReceiver",
|
||||||
|
qualifiedAndroidName: "dev.solsynth.solian.widgets.RandomPostWidgetReceiver",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -151,7 +151,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
final home = context.read<HomeWidgetProvider>();
|
final home = context.read<HomeWidgetProvider>();
|
||||||
final resp = await sn.client.get('/cgi/id/check-in/today');
|
final resp = await sn.client.get('/cgi/id/check-in/today');
|
||||||
_todayRecord = SnCheckInRecord.fromJson(resp.data);
|
_todayRecord = SnCheckInRecord.fromJson(resp.data);
|
||||||
home.saveWidgetData('today_check_in', _todayRecord!.toJson());
|
home.saveWidgetData('pas_check_in_record', _todayRecord!.toJson());
|
||||||
} finally {
|
} finally {
|
||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
|
|||||||
final home = context.read<HomeWidgetProvider>();
|
final home = context.read<HomeWidgetProvider>();
|
||||||
final resp = await sn.client.post('/cgi/id/check-in');
|
final resp = await sn.client.post('/cgi/id/check-in');
|
||||||
_todayRecord = SnCheckInRecord.fromJson(resp.data);
|
_todayRecord = SnCheckInRecord.fromJson(resp.data);
|
||||||
home.saveWidgetData('today_check_in', _todayRecord!.toJson());
|
home.saveWidgetData('pas_check_in_record', _todayRecord!.toJson());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
|
52
pubspec.lock
52
pubspec.lock
@ -13,10 +13,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: eae3133cbb06de9205899b822e3897fc6a8bc278ad4c944b4ce612689369694b
|
sha256: daa1d780fdecf8af925680c06c86563cdd445deea995d5c9176f1302a2b10bbe
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.47"
|
version: "1.3.48"
|
||||||
_macros:
|
_macros:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: dart
|
description: dart
|
||||||
@ -50,10 +50,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8"
|
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.2"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -562,26 +562,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: firebase_core
|
name: firebase_core
|
||||||
sha256: fef81a53ba1ca618def1f8bef4361df07968434e62cb204c1fb90bb880a03da2
|
sha256: "15d761b95dfa2906dfcc31b7fc6fe293188533d1a3ffe78389ba9e69bd7fdbde"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.8.1"
|
version: "3.9.0"
|
||||||
firebase_core_platform_interface:
|
firebase_core_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_platform_interface
|
name: firebase_core_platform_interface
|
||||||
sha256: b94b217e3ad745e784960603d33d99471621ecca151c99c670869b76e50ad2a6
|
sha256: d7253d255ff10f85cfd2adaba9ac17bae878fa3ba577462451163bd9f1d1f0bf
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.3.1"
|
version: "5.4.0"
|
||||||
firebase_core_web:
|
firebase_core_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: firebase_core_web
|
name: firebase_core_web
|
||||||
sha256: "9e69806bb3d905aeec3c1242e0e1475de6ea6d48f456af29d598fb229a2b4e5e"
|
sha256: fbc008cf390d909b823763064b63afefe9f02d8afdb13eb3f485b871afee956b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.18.2"
|
version: "2.19.0"
|
||||||
firebase_messaging:
|
firebase_messaging:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -894,10 +894,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: b50b415345578583de0f1cf4c7bd389f164de0b316d890c707b41133047dbc2a
|
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.5.1"
|
version: "4.5.2"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1038,10 +1038,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: lints
|
name: lints
|
||||||
sha256: "4a16b3f03741e1252fda5de3ce712666d010ba2122f8e912c94f9f7b90e1a4c3"
|
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.1.0"
|
version: "5.1.1"
|
||||||
livekit_client:
|
livekit_client:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1454,10 +1454,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: pubspec_parse
|
name: pubspec_parse
|
||||||
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
|
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.4.0"
|
||||||
qr:
|
qr:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2003,18 +2003,18 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus
|
name: wakelock_plus
|
||||||
sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484
|
sha256: "1aeab49f24aec1e5ab417d7cdfc47c7bbcb815353f1840667ffe68c89a0cd2e6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.8"
|
version: "1.2.9"
|
||||||
wakelock_plus_platform_interface:
|
wakelock_plus_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus_platform_interface
|
name: wakelock_plus_platform_interface
|
||||||
sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16"
|
sha256: "70e780bc99796e1db82fe764b1e7dcb89a86f1e5b3afb1db354de50f2e41eb7a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.2"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2071,6 +2071,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.5"
|
version: "1.1.5"
|
||||||
|
workmanager:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: workmanager
|
||||||
|
sha256: ed13530cccd28c5c9959ad42d657cd0666274ca74c56dea0ca183ddd527d3a00
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.5.2"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2091,10 +2099,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: yaml
|
name: yaml
|
||||||
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.6.0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.24.0"
|
flutter: ">=3.24.0"
|
||||||
|
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2.1.1+33
|
version: 2.1.1+34
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -107,6 +107,7 @@ dependencies:
|
|||||||
flutter_svg: ^2.0.16
|
flutter_svg: ^2.0.16
|
||||||
home_widget: ^0.7.0
|
home_widget: ^0.7.0
|
||||||
receive_sharing_intent: ^1.8.1
|
receive_sharing_intent: ^1.8.1
|
||||||
|
workmanager: ^0.5.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user