Compare commits

...

4 Commits

Author SHA1 Message Date
d6d60e60a9 🐛 Fix ios widget image 2024-12-21 13:21:44 +08:00
435b730f3b ♻️ Android use background info too 2024-12-21 13:03:07 +08:00
73468c5c6d iOS background widget fetching 2024-12-21 11:56:18 +08:00
8db6513eef Show random post instead of featured post 2024-12-21 04:12:52 +08:00
25 changed files with 718 additions and 475 deletions

View File

@ -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'
} }

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

@ -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>)

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,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)
)
}
}
}
}

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

@ -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)
)
}
}
}
}

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="320dp" 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

@ -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

View File

@ -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

View File

@ -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",

View File

@ -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)
} }
} }

View File

@ -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>

View File

@ -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"))
} }
} }

View File

@ -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
)
}

View 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
)
}

View File

@ -12,6 +12,6 @@ import SwiftUI
struct SolarWidgetBundle: WidgetBundle { struct SolarWidgetBundle: WidgetBundle {
var body: some Widget { var body: some Widget {
CheckInWidget() CheckInWidget()
FeaturedPostWidget() RandomPostWidget()
} }
} }

View File

@ -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

View File

@ -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();

View File

@ -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",
);
}

View File

@ -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);

View File

@ -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"

View File

@ -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: