Compare commits

...

7 Commits

Author SHA1 Message Date
6427ec1f82 🚀 Launch 2.1.1+36 2024-12-21 23:39:04 +08:00
35dc7f4392 💄 Optimize android widget color 2024-12-21 23:36:34 +08:00
b50191970e 🚀 Launch 2.1.1+35 2024-12-21 23:30:59 +08:00
1b69e6dd42 📝 Remove todo 2024-12-21 23:26:58 +08:00
39fb4d474f App updates & web deeplink 2024-12-21 23:26:42 +08:00
392aebcad7 🐛 Fix android widgets 2024-12-21 22:55:35 +08:00
e9e3a4c474 🐛 Bug fixes on iOS widget 2024-12-21 22:38:22 +08:00
17 changed files with 326 additions and 161 deletions

View File

@ -33,22 +33,6 @@
</intent-filter> </intent-filter>
<!-- Sharing Intents --> <!-- Sharing Intents -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="https"
android:host="sn.solsynth.dev"
android:pathPrefix="/invite"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data
android:mimeType="*/*"
android:scheme="content" />
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEND" /> <action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />

View File

@ -1,11 +1,11 @@
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
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.GlanceTheme
import androidx.glance.action.clickable 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
@ -25,8 +25,10 @@ import androidx.glance.text.Text
import androidx.glance.text.TextStyle import androidx.glance.text.TextStyle
import com.google.gson.FieldNamingPolicy import com.google.gson.FieldNamingPolicy
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import dev.solsynth.solian.MainActivity
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 es.antonborri.home_widget.actionStartActivity
import java.time.Instant import java.time.Instant
import java.time.LocalDate import java.time.LocalDate
import java.time.OffsetDateTime import java.time.OffsetDateTime
@ -39,7 +41,9 @@ class CheckInWidget : GlanceAppWidget() {
override suspend fun provideGlance(context: Context, id: GlanceId) { override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent { provideContent {
GlanceContent(context, currentState()) GlanceTheme {
GlanceContent(context, currentState())
}
} }
} }
@ -53,18 +57,27 @@ class CheckInWidget : GlanceAppWidget() {
val resultTierSymbols = listOf("大凶", "", "中平", "", "大吉") val resultTierSymbols = listOf("大凶", "", "中平", "", "大吉")
val prefs = currentState.preferences val prefs = currentState.preferences
val checkInRaw = prefs.getString("pas_check_in_record", null) val checkInRaw: String? = prefs.getString("pas_check_in_record", null)
val checkIn: SolarCheckInRecord? =
checkInRaw?.let { checkInRaw ->
gson.fromJson(checkInRaw, SolarCheckInRecord::class.java)
} ?: null;
Column( Column(
modifier = GlanceModifier modifier = GlanceModifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxHeight() .fillMaxHeight()
.background(Color.White) .background(GlanceTheme.colors.widgetBackground)
.padding(16.dp) .padding(16.dp)
.clickable(
onClick = actionStartActivity<MainActivity>(
context,
Uri.parse("https://sn.solsynth.dev")
)
)
) { ) {
if (checkInRaw != null) { if (checkIn != null) {
val checkIn: SolarCheckInRecord =
gson.fromJson(checkInRaw, SolarCheckInRecord::class.java)
val dateFormatter = DateTimeFormatter.ofPattern("EEE, MM/dd") val dateFormatter = DateTimeFormatter.ofPattern("EEE, MM/dd")
val checkDate = checkIn.createdAt.atZone(ZoneId.of("UTC")).toLocalDate() val checkDate = checkIn.createdAt.atZone(ZoneId.of("UTC")).toLocalDate()
@ -73,11 +86,18 @@ class CheckInWidget : GlanceAppWidget() {
Column { Column {
Text( Text(
text = resultTierSymbols[checkIn.resultTier], text = resultTierSymbols[checkIn.resultTier],
style = TextStyle(fontSize = 25.sp, fontFamily = FontFamily.Serif) style = TextStyle(
fontSize = 17.sp,
color = GlanceTheme.colors.onSurface
)
) )
Text( Text(
text = "+${checkIn.resultExperience} EXP", text = "+${checkIn.resultExperience} EXP",
style = TextStyle(fontSize = 15.sp, fontFamily = FontFamily.Monospace) style = TextStyle(
fontSize = 13.sp,
fontFamily = FontFamily.Monospace,
color = GlanceTheme.colors.onSurface
)
) )
} }
Spacer(modifier = GlanceModifier.height(8.dp)) Spacer(modifier = GlanceModifier.height(8.dp))
@ -88,18 +108,21 @@ class CheckInWidget : GlanceAppWidget() {
ZoneId.systemDefault() ZoneId.systemDefault()
) )
.format(dateFormatter), .format(dateFormatter),
style = TextStyle(fontSize = 13.sp) style = TextStyle(
fontSize = 11.sp,
color = GlanceTheme.colors.onSurface
)
) )
} }
return@Column; return@Column;
} }
} }
}
Text( Text(
text = "You haven't checked in today", text = "You haven't checked in today",
style = TextStyle(fontSize = 15.sp) style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
) )
}
} }
} }

View File

@ -1,6 +1,6 @@
import HomeWidgetGlanceState
import HomeWidgetGlanceStateDefinition
import android.content.Context import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri 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
@ -9,17 +9,13 @@ 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.GlanceTheme import androidx.glance.GlanceTheme
import androidx.glance.Image
import androidx.glance.ImageProvider
import androidx.glance.action.clickable import androidx.glance.action.clickable
import androidx.glance.appwidget.GlanceAppWidget import androidx.glance.appwidget.GlanceAppWidget
import androidx.glance.appwidget.cornerRadius
import androidx.glance.appwidget.provideContent import androidx.glance.appwidget.provideContent
import androidx.glance.background import androidx.glance.background
import androidx.glance.currentState import androidx.glance.currentState
import androidx.glance.layout.Alignment import androidx.glance.layout.Alignment
import androidx.glance.layout.Column import androidx.glance.layout.Column
import androidx.glance.layout.ContentScale
import androidx.glance.layout.Row import androidx.glance.layout.Row
import androidx.glance.layout.Spacer import androidx.glance.layout.Spacer
import androidx.glance.layout.fillMaxHeight import androidx.glance.layout.fillMaxHeight
@ -39,10 +35,6 @@ import dev.solsynth.solian.MainActivity
import dev.solsynth.solian.data.InstantAdapter import dev.solsynth.solian.data.InstantAdapter
import dev.solsynth.solian.data.SolarPost import dev.solsynth.solian.data.SolarPost
import es.antonborri.home_widget.actionStartActivity 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.Instant
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.ZoneId import java.time.ZoneId
@ -52,45 +44,18 @@ class RandomPostWidget : GlanceAppWidget() {
override val stateDefinition: GlanceStateDefinition<*>? override val stateDefinition: GlanceStateDefinition<*>?
get() = HomeWidgetGlanceStateDefinition() get() = HomeWidgetGlanceStateDefinition()
private val defaultUrl = "https://api.sn.solsynth.dev"
override suspend fun provideGlance(context: Context, id: GlanceId) { override suspend fun provideGlance(context: Context, id: GlanceId) {
provideContent { provideContent {
GlanceTheme { GlanceTheme {
GlanceContent(context, currentState(), null) GlanceContent(context, currentState())
} }
} }
} }
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 @Composable
private fun GlanceContent( private fun GlanceContent(
context: Context, context: Context,
currentState: HomeWidgetGlanceState, currentState: HomeWidgetGlanceState,
avatar: Bitmap?
) { ) {
val prefs = currentState.preferences val prefs = currentState.preferences
val postRaw = prefs.getString("int_random_post", null) val postRaw = prefs.getString("int_random_post", null)
@ -109,7 +74,7 @@ class RandomPostWidget : GlanceAppWidget() {
modifier = GlanceModifier modifier = GlanceModifier
.fillMaxWidth() .fillMaxWidth()
.fillMaxHeight() .fillMaxHeight()
.background(Color.White) .background(GlanceTheme.colors.widgetBackground)
.padding(16.dp) .padding(16.dp)
.clickable( .clickable(
onClick = actionStartActivity<MainActivity>( onClick = actionStartActivity<MainActivity>(
@ -120,25 +85,18 @@ class RandomPostWidget : GlanceAppWidget() {
) { ) {
if (data != null) { if (data != null) {
Row(verticalAlignment = Alignment.CenterVertically) { 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(
text = data.publisher.nick, text = data.publisher.nick,
style = TextStyle(fontSize = 15.sp) style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
) )
Spacer(modifier = GlanceModifier.width(8.dp)) Spacer(modifier = GlanceModifier.width(8.dp))
Text( Text(
text = "@${data.publisher.name}", text = "@${data.publisher.name}",
style = TextStyle(fontSize = 13.sp, fontFamily = FontFamily.Monospace) style = TextStyle(
fontSize = 13.sp,
fontFamily = FontFamily.Monospace,
color = GlanceTheme.colors.onSurface
)
) )
} }
@ -147,13 +105,13 @@ class RandomPostWidget : GlanceAppWidget() {
if (data.body.title != null) { if (data.body.title != null) {
Text( Text(
text = data.body.title, text = data.body.title,
style = TextStyle(fontSize = 25.sp) style = TextStyle(fontSize = 19.sp, color = GlanceTheme.colors.onSurface)
) )
} }
if (data.body.description != null) { if (data.body.description != null) {
Text( Text(
text = data.body.description, text = data.body.description,
style = TextStyle(fontSize = 19.sp) style = TextStyle(fontSize = 17.sp, color = GlanceTheme.colors.onSurface)
) )
} }
@ -163,7 +121,7 @@ class RandomPostWidget : GlanceAppWidget() {
Text( Text(
text = data.body.content ?: "No content", text = data.body.content ?: "No content",
style = TextStyle(fontSize = 15.sp), style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface),
) )
Spacer(modifier = GlanceModifier.height(8.dp)) Spacer(modifier = GlanceModifier.height(8.dp))
@ -172,12 +130,16 @@ class RandomPostWidget : GlanceAppWidget() {
Text( Text(
LocalDateTime.ofInstant(data.createdAt, ZoneId.systemDefault()) LocalDateTime.ofInstant(data.createdAt, ZoneId.systemDefault())
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")), .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")),
style = TextStyle(fontSize = 13.sp), style = TextStyle(fontSize = 13.sp, color = GlanceTheme.colors.onSurface),
) )
Text( Text(
"#${data.id}", "#${data.id}",
style = TextStyle(fontSize = 11.sp, fontWeight = FontWeight.Bold), style = TextStyle(
fontSize = 11.sp,
fontWeight = FontWeight.Bold,
color = GlanceTheme.colors.onSurface
),
) )
return@Column; return@Column;
@ -189,12 +151,16 @@ class RandomPostWidget : GlanceAppWidget() {
horizontalAlignment = Alignment.Horizontal.CenterHorizontally horizontalAlignment = Alignment.Horizontal.CenterHorizontally
) { ) {
Text( Text(
text = "Unable to fetch post", text = "No Recommendations",
style = TextStyle(fontSize = 17.sp, fontWeight = FontWeight.Bold) style = TextStyle(
fontSize = 17.sp,
fontWeight = FontWeight.Bold,
color = GlanceTheme.colors.onSurface
)
) )
Text( Text(
text = "Check your internet connection", text = "Open app to load some posts",
style = TextStyle(fontSize = 15.sp) style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
) )
} }
} }

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="120dp" android:minWidth="40dp"
android:minHeight="40dp" android:minHeight="40dp"
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="10000"> android:updatePeriodMillis="10000">

View File

@ -370,6 +370,8 @@
"dailyCheckNegativeHint6": "Going out", "dailyCheckNegativeHint6": "Going out",
"dailyCheckNegativeHint6Description": "Forgot your umbrella and got caught in the rain", "dailyCheckNegativeHint6Description": "Forgot your umbrella and got caught in the rain",
"happyBirthday": "Happy birthday, {}!", "happyBirthday": "Happy birthday, {}!",
"celebrateMerryXmas": "Merry christmas, {}",
"celebrateNewYear": "Happy new year, {}",
"friendNew": "Add Friend", "friendNew": "Add Friend",
"friendRequests": "Friend Requests", "friendRequests": "Friend Requests",
"friendRequestsDescription": { "friendRequestsDescription": {
@ -455,5 +457,7 @@
"poweredBy": "Powered by {}", "poweredBy": "Powered by {}",
"shareIntent": "Share", "shareIntent": "Share",
"shareIntentDescription": "What do you want to do with the content you are sharing?", "shareIntentDescription": "What do you want to do with the content you are sharing?",
"shareIntentPostStory": "Post a Story" "shareIntentPostStory": "Post a Story",
"updateAvailable": "Update Available",
"updateOngoing": "正在更新,请稍后..."
} }

View File

@ -368,6 +368,8 @@
"dailyCheckNegativeHint6": "出门", "dailyCheckNegativeHint6": "出门",
"dailyCheckNegativeHint6Description": "忘带伞遇上大雨", "dailyCheckNegativeHint6Description": "忘带伞遇上大雨",
"happyBirthday": "生日快乐,{}", "happyBirthday": "生日快乐,{}",
"celebrateMerryXmas": "圣诞快乐,{}",
"celebrateNewYear": "新年快乐,{}",
"friendNew": "添加好友", "friendNew": "添加好友",
"friendRequests": "好友请求", "friendRequests": "好友请求",
"friendRequestsDescription": { "friendRequestsDescription": {
@ -453,5 +455,7 @@
"poweredBy": "由 {} 提供支持", "poweredBy": "由 {} 提供支持",
"shareIntent": "分享", "shareIntent": "分享",
"shareIntentDescription": "您想对您分享的内容做些什么?", "shareIntentDescription": "您想对您分享的内容做些什么?",
"shareIntentPostStory": "发布动态" "shareIntentPostStory": "发布动态",
"updateAvailable": "检测到更新可用",
"updateOngoing": "正在更新,请稍后……"
} }

View File

@ -103,6 +103,8 @@ PODS:
- GoogleUtilities/UserDefaults (~> 8.0) - GoogleUtilities/UserDefaults (~> 8.0)
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- Flutter (1.0.0) - Flutter (1.0.0)
- flutter_app_update (0.0.1):
- Flutter
- flutter_native_splash (2.4.3): - flutter_native_splash (2.4.3):
- Flutter - Flutter
- flutter_udid (0.0.1): - flutter_udid (0.0.1):
@ -168,6 +170,8 @@ PODS:
- Flutter - Flutter
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
- Flutter - Flutter
- in_app_review (2.0.0):
- Flutter
- Kingfisher (8.1.3) - Kingfisher (8.1.3)
- livekit_client (2.3.2): - livekit_client (2.3.2):
- Flutter - Flutter
@ -232,12 +236,14 @@ DEPENDENCIES:
- firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_udid (from `.symlinks/plugins/flutter_udid/ios`) - flutter_udid (from `.symlinks/plugins/flutter_udid/ios`)
- flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`) - flutter_webrtc (from `.symlinks/plugins/flutter_webrtc/ios`)
- 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`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
- Kingfisher (~> 8.0) - 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`)
@ -298,6 +304,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_messaging/ios" :path: ".symlinks/plugins/firebase_messaging/ios"
Flutter: Flutter:
:path: Flutter :path: Flutter
flutter_app_update:
:path: ".symlinks/plugins/flutter_app_update/ios"
flutter_native_splash: flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios" :path: ".symlinks/plugins/flutter_native_splash/ios"
flutter_udid: flutter_udid:
@ -310,6 +318,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/home_widget/ios" :path: ".symlinks/plugins/home_widget/ios"
image_picker_ios: image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios" :path: ".symlinks/plugins/image_picker_ios/ios"
in_app_review:
:path: ".symlinks/plugins/in_app_review/ios"
livekit_client: livekit_client:
:path: ".symlinks/plugins/livekit_client/ios" :path: ".symlinks/plugins/livekit_client/ios"
media_kit_libs_ios_video: media_kit_libs_ios_video:
@ -364,8 +374,9 @@ SPEC CHECKSUMS:
FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414 FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414
FirebaseMessaging: f8a160d99c2c2e5babbbcc90c4a3e15db036aee2 FirebaseMessaging: f8a160d99c2c2e5babbbcc90c4a3e15db036aee2
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_app_update: 65f61da626cb111d1b24674abc4b01728d7723bc
flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a
flutter_udid: a2482c67a61b9c806ef59dd82ed8d007f1b7ac04 flutter_udid: b2417673f287ee62817a1de3d1643f47b9f508ab
flutter_webrtc: 1a53bd24f97bcfeff512f13699e721897f261563 flutter_webrtc: 1a53bd24f97bcfeff512f13699e721897f261563
gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5
GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e
@ -373,6 +384,7 @@ SPEC CHECKSUMS:
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57 home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
Kingfisher: f2af9028b16baf9dc6c07c570072bc41cbf009ef Kingfisher: f2af9028b16baf9dc6c07c570072bc41cbf009ef
livekit_client: 6108dad8b77db3142bafd4c630f471d0a54335cd livekit_client: 6108dad8b77db3142bafd4c630f471d0a54335cd
media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1

View File

@ -10,7 +10,7 @@ import SwiftUI
struct CheckInProvider: TimelineProvider { struct CheckInProvider: TimelineProvider {
func placeholder(in context: Context) -> CheckInEntry { func placeholder(in context: Context) -> CheckInEntry {
CheckInEntry(date: Date(), user: nil, checkIn: nil) CheckInEntry(date: Date(), checkIn: nil)
} }
func getSnapshot(in context: Context, completion: @escaping (CheckInEntry) -> ()) { func getSnapshot(in context: Context, completion: @escaping (CheckInEntry) -> ()) {
@ -23,24 +23,17 @@ struct CheckInProvider: TimelineProvider {
jsonDecoder.dateDecodingStrategy = .formatted(dateFormatter) jsonDecoder.dateDecodingStrategy = .formatted(dateFormatter)
jsonDecoder.keyDecodingStrategy = .convertFromSnakeCase 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 checkInRaw = prefs?.string(forKey: "pas_check_in_record") 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()) { if checkIn != nil && !Calendar.current.isDate(checkIn!.createdAt, inSameDayAs: Date()) {
checkIn = nil checkIn = nil
} }
} }
let entry = CheckInEntry( let entry = CheckInEntry(
date: Date(), date: Date(),
user: user,
checkIn: checkIn checkIn: checkIn
) )
completion(entry) completion(entry)
@ -56,7 +49,6 @@ struct CheckInProvider: TimelineProvider {
struct CheckInEntry: TimelineEntry { struct CheckInEntry: TimelineEntry {
let date: Date let date: Date
let user: SolarUser?
let checkIn: SolarCheckInRecord? let checkIn: SolarCheckInRecord?
} }
@ -135,10 +127,9 @@ struct CheckInWidget: Widget {
#Preview(as: .systemSmall) { #Preview(as: .systemSmall) {
CheckInWidget() CheckInWidget()
} timeline: { } timeline: {
CheckInEntry(date: .now, user: nil, checkIn: nil) CheckInEntry(date: .now, checkIn: nil)
CheckInEntry( CheckInEntry(
date: .now, date: .now,
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
checkIn: SolarCheckInRecord(id: 1, resultTier: 1, resultExperience: 100, createdAt: Date.now) checkIn: SolarCheckInRecord(id: 1, resultTier: 1, resultExperience: 100, createdAt: Date.now)
) )
} }

View File

@ -13,7 +13,7 @@ struct RandomPostProvider: TimelineProvider {
func placeholder(in context: Context) -> RandomPostEntry { func placeholder(in context: Context) -> RandomPostEntry {
RandomPostEntry(date: Date(), user: nil, randomPost: nil, family: .systemMedium) RandomPostEntry(date: Date(), user: nil, randomPost: nil, family: .systemMedium)
} }
func getSnapshot(in context: Context, completion: @escaping (RandomPostEntry) -> ()) { func getSnapshot(in context: Context, completion: @escaping (RandomPostEntry) -> ()) {
let prefs = UserDefaults(suiteName: "group.solsynth.solian") let prefs = UserDefaults(suiteName: "group.solsynth.solian")
@ -45,7 +45,7 @@ struct RandomPostProvider: TimelineProvider {
) )
completion(entry) completion(entry)
} }
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
getSnapshot(in: context) { (entry) in getSnapshot(in: context) { (entry) in
let timeline = Timeline(entries: [entry], policy: .atEnd) let timeline = Timeline(entries: [entry], policy: .atEnd)
@ -64,7 +64,7 @@ struct RandomPostEntry: TimelineEntry {
struct RandomPostWidgetEntryView : View { struct RandomPostWidgetEntryView : View {
var entry: RandomPostProvider.Entry var entry: RandomPostProvider.Entry
var body: some View { var body: some View {
VStack(alignment: .leading, spacing: 0) { VStack(alignment: .leading, spacing: 0) {
if let randomPost = entry.randomPost { if let randomPost = entry.randomPost {
@ -73,15 +73,20 @@ struct RandomPostWidgetEntryView : View {
if let avatar = randomPost.publisher.avatar { if let avatar = randomPost.publisher.avatar {
let avatarUrl = getAttachmentUrl(for: avatar) let avatarUrl = getAttachmentUrl(for: avatar)
let size: CGFloat = 28 let size: CGFloat = 28
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: size, height: size), mode: .aspectFit) let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: size, height: size), mode: .aspectFill)
KFImage.url(URL(string: avatarUrl)) KFImage.url(URL(string: avatarUrl))
.resizable() .resizable()
.setProcessor(scaleProcessor) .setProcessor(scaleProcessor)
.fade(duration: 0.25) .fade(duration: 0.25)
.aspectRatio(contentMode: .fit) .placeholder{
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
}
.aspectRatio(contentMode: .fill)
.frame(width: size, height: size) .frame(width: size, height: size)
.cornerRadius(size / 2) .cornerRadius(size / 2)
.frame(width: size, height: size, alignment: .center) .frame(width: size, height: size, alignment: .center)
} }
@ -158,7 +163,7 @@ struct RandomPostWidgetEntryView : View {
struct RandomPostWidget: Widget { struct RandomPostWidget: Widget {
let kind: String = "SolarRandomPostWidget" let kind: String = "SolarRandomPostWidget"
var body: some WidgetConfiguration { var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: RandomPostProvider()) { entry in StaticConfiguration(kind: kind, provider: RandomPostProvider()) { entry in
if #available(iOS 17.0, *) { if #available(iOS 17.0, *) {

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:bitsdojo_window/bitsdojo_window.dart'; import 'package:bitsdojo_window/bitsdojo_window.dart';
import 'package:croppy/croppy.dart'; import 'package:croppy/croppy.dart';
import 'package:dio/dio.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:easy_localization_loader/easy_localization_loader.dart'; import 'package:easy_localization_loader/easy_localization_loader.dart';
import 'package:firebase_core/firebase_core.dart'; import 'package:firebase_core/firebase_core.dart';
@ -12,9 +13,11 @@ import 'package:flutter/material.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:relative_time/relative_time.dart'; import 'package:relative_time/relative_time.dart';
import 'package:responsive_framework/responsive_framework.dart'; import 'package:responsive_framework/responsive_framework.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/firebase_options.dart'; import 'package:surface/firebase_options.dart';
import 'package:surface/providers/channel.dart'; import 'package:surface/providers/channel.dart';
@ -38,7 +41,9 @@ 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:version/version.dart';
import 'package:workmanager/workmanager.dart'; import 'package:workmanager/workmanager.dart';
import 'package:in_app_review/in_app_review.dart';
@pragma('vm:entry-point') @pragma('vm:entry-point')
void appBackgroundDispatcher() { void appBackgroundDispatcher() {
@ -125,7 +130,7 @@ class SolianApp extends StatelessWidget {
Provider(create: (ctx) => HomeWidgetProvider(ctx)), Provider(create: (ctx) => HomeWidgetProvider(ctx)),
// Preferences layer // Preferences layer
Provider(create: (ctx) => ConfigProvider(ctx)), ChangeNotifierProvider(create: (ctx) => ConfigProvider(ctx)),
// Display layer // Display layer
ChangeNotifierProvider(create: (_) => ThemeProvider()), ChangeNotifierProvider(create: (_) => ThemeProvider()),
@ -201,6 +206,55 @@ class _AppSplashScreen extends StatefulWidget {
class _AppSplashScreenState extends State<_AppSplashScreen> { class _AppSplashScreenState extends State<_AppSplashScreen> {
bool _isReady = false; bool _isReady = false;
void _tryRequestRating() async {
final prefs = await SharedPreferences.getInstance();
if (prefs.containsKey('first_boot_time')) {
final rawTime = prefs.getString('first_boot_time');
final time = DateTime.tryParse(rawTime ?? '');
if (time != null && time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
final inAppReview = InAppReview.instance;
if (prefs.getBool('rating_requested') == true) return;
if (await inAppReview.isAvailable()) {
await inAppReview.requestReview();
prefs.setBool('rating_requested', true);
} else {
log('Unable request app review, unavailable');
}
}
} else {
prefs.setString('first_boot_time', DateTime.now().toIso8601String());
}
}
Future<void> _checkForUpdate() async {
if (kIsWeb) return;
try {
final info = await PackageInfo.fromPlatform();
final localVersionString = '${info.version}+${info.buildNumber}';
final resp = await Dio(
BaseOptions(
sendTimeout: const Duration(seconds: 60),
receiveTimeout: const Duration(seconds: 60),
),
).get(
'https://git.solsynth.dev/api/v1/repos/HyperNet/Surface/tags?page=1&limit=1',
);
final remoteVersionString = (resp.data as List).firstOrNull?['name'] ?? '0.0.0+0';
final remoteVersion = Version.parse(remoteVersionString.split('+').first);
final localVersion = Version.parse(localVersionString.split('+').first);
final remoteBuildNumber = int.tryParse(remoteVersionString.split('+').last) ?? 0;
final localBuildNumber = int.tryParse(localVersionString.split('+').last) ?? 0;
log("[Update] Local: $localVersionString, Remote: $remoteVersionString");
if ((remoteVersion > localVersion || remoteBuildNumber > localBuildNumber) && mounted) {
final config = context.read<ConfigProvider>();
config.setUpdate(remoteVersionString);
log("[Update] Update available: $remoteVersionString");
}
} catch (e) {
if (mounted) context.showErrorDialog('Unable to check update: $e');
}
}
Future<void> _initialize() async { Future<void> _initialize() async {
try { try {
final home = context.read<HomeWidgetProvider>(); final home = context.read<HomeWidgetProvider>();
@ -235,7 +289,11 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initialize().then((_) => _postInitialization()); _initialize().then((_) {
_postInitialization();
_tryRequestRating();
_checkForUpdate();
});
} }
@override @override

View File

@ -16,7 +16,7 @@ const Map<String, FilterQuality> kImageQualityLevel = {
'settingsImageQualityHigh': FilterQuality.high, 'settingsImageQualityHigh': FilterQuality.high,
}; };
class ConfigProvider { class ConfigProvider extends ChangeNotifier {
late final SharedPreferences prefs; late final SharedPreferences prefs;
late final HomeWidgetProvider _home; late final HomeWidgetProvider _home;
@ -36,8 +36,16 @@ class ConfigProvider {
String get serverUrl { String get serverUrl {
return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault; return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
} }
set serverUrl(String url) { set serverUrl(String url) {
prefs.setString(kNetworkServerStoreKey, url); prefs.setString(kNetworkServerStoreKey, url);
_home.saveWidgetData("nex_server_url", url); _home.saveWidgetData("nex_server_url", url);
} }
String? updatableVersion;
void setUpdate(String newVersion) {
updatableVersion = newVersion;
notifyListeners();
}
} }

View File

@ -1,7 +1,10 @@
import 'dart:io';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:ui'; import 'dart:ui';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_app_update/flutter_app_update.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -10,6 +13,7 @@ import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:surface/providers/config.dart';
import 'package:surface/providers/post.dart'; import 'package:surface/providers/post.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart'; import 'package:surface/providers/userinfo.dart';
@ -69,18 +73,15 @@ class _HomeScreenState extends State<HomeScreen> {
body: LayoutBuilder( body: LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
return Align( return Align(
alignment: constraints.maxWidth > 640 alignment: constraints.maxWidth > 640 ? Alignment.center : Alignment.topCenter,
? Alignment.center
: Alignment.topCenter,
child: Container( child: Container(
constraints: const BoxConstraints(maxWidth: 640), constraints: const BoxConstraints(maxWidth: 640),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
mainAxisAlignment: constraints.maxWidth > 640 mainAxisAlignment: constraints.maxWidth > 640 ? MainAxisAlignment.center : MainAxisAlignment.start,
? MainAxisAlignment.center
: MainAxisAlignment.start,
children: [ children: [
_HomeDashSpecialDayWidget().padding(top: 8, horizontal: 8), _HomeDashSpecialDayWidget().padding(bottom: 8, horizontal: 8),
_HomeDashUpdateWidget(padding: const EdgeInsets.only(bottom: 8, left: 8, right: 8)),
StaggeredGrid.extent( StaggeredGrid.extent(
maxCrossAxisExtent: 280, maxCrossAxisExtent: 280,
mainAxisSpacing: 8, mainAxisSpacing: 8,
@ -104,6 +105,52 @@ class _HomeScreenState extends State<HomeScreen> {
} }
} }
class _HomeDashUpdateWidget extends StatelessWidget {
final EdgeInsets? padding;
const _HomeDashUpdateWidget({super.key, this.padding});
@override
Widget build(BuildContext context) {
final config = context.watch<ConfigProvider>();
return ListenableBuilder(
listenable: config,
builder: (context, _) {
if (config.updatableVersion != null) {
return Container(
padding: padding,
child: Card(
child: ListTile(
leading: Icon(Symbols.update),
title: Text('updateAvailable').tr(),
subtitle: Text(config.updatableVersion!),
trailing: (kIsWeb || Platform.isWindows || Platform.isLinux)
? null
: IconButton(
icon: const Icon(Symbols.arrow_right_alt),
onPressed: () {
final model = UpdateModel(
'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk',
'solian-app-release-${config.updatableVersion!}.apk',
'ic_notification',
'https://apps.apple.com/us/app/solian/id6499032345',
);
AzhonAppUpdate.update(model);
context.showSnackbar('updateOngoing'.tr());
},
),
),
),
);
}
return SizedBox.shrink();
},
);
}
}
class _HomeDashSpecialDayWidget extends StatelessWidget { class _HomeDashSpecialDayWidget extends StatelessWidget {
const _HomeDashSpecialDayWidget({super.key}); const _HomeDashSpecialDayWidget({super.key});
@ -112,10 +159,10 @@ class _HomeDashSpecialDayWidget extends StatelessWidget {
final ua = context.watch<UserProvider>(); final ua = context.watch<UserProvider>();
final today = DateTime.now(); final today = DateTime.now();
final birthday = ua.user?.profile?.birthday?.toLocal(); final birthday = ua.user?.profile?.birthday?.toLocal();
final isBirthday = birthday != null && final isBirthday = birthday != null && birthday.day == today.day && birthday.month == today.month;
birthday.day == today.day &&
birthday.month == today.month;
return Column( return Column(
spacing: 8,
children: [ children: [
if (isBirthday) if (isBirthday)
Card( Card(
@ -124,6 +171,20 @@ class _HomeDashSpecialDayWidget extends StatelessWidget {
title: Text('happyBirthday').tr(args: [ua.user?.nick ?? 'user']), title: Text('happyBirthday').tr(args: [ua.user?.nick ?? 'user']),
), ),
).padding(bottom: 8), ).padding(bottom: 8),
if (today.month == 12 && today.day == 25)
Card(
child: ListTile(
leading: Text('🎄').fontSize(24),
title: Text('celebrateMerryXmas').tr(args: [ua.user?.nick ?? 'user']),
),
),
if (today.month == 1 && today.day == 1)
Card(
child: ListTile(
leading: Text('🎉').fontSize(24),
title: Text('celebrateNewYear').tr(args: [ua.user?.nick ?? 'user']),
),
),
], ],
); );
} }
@ -174,20 +235,15 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
} }
Widget _buildDetailChunk(int index, bool positive) { Widget _buildDetailChunk(int index, bool positive) {
final prefix = final prefix = positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint';
positive ? 'dailyCheckPositiveHint' : 'dailyCheckNegativeHint'; final mod = positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount;
final mod =
positive ? kSuggestionPositiveHintCount : kSuggestionNegativeHintCount;
final pos = math.max(1, _todayRecord!.resultModifiers[index] % mod); final pos = math.max(1, _todayRecord!.resultModifiers[index] % mod);
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
prefix.tr(args: ['$prefix$pos'.tr()]), prefix.tr(args: ['$prefix$pos'.tr()]),
style: Theme.of(context) style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
.textTheme
.titleMedium!
.copyWith(fontWeight: FontWeight.bold),
), ),
Text( Text(
'$prefix${pos}Description', '$prefix${pos}Description',
@ -222,10 +278,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
else else
Text( Text(
'dailyCheckEverythingIsNegative', 'dailyCheckEverythingIsNegative',
style: Theme.of(context) style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
.textTheme
.titleMedium!
.copyWith(fontWeight: FontWeight.bold),
).tr(), ).tr(),
const Gap(8), const Gap(8),
if (_todayRecord?.resultTier != 4) if (_todayRecord?.resultTier != 4)
@ -241,10 +294,7 @@ class _HomeDashCheckInWidgetState extends State<_HomeDashCheckInWidget> {
else else
Text( Text(
'dailyCheckEverythingIsPositive', 'dailyCheckEverythingIsPositive',
style: Theme.of(context) style: Theme.of(context).textTheme.titleMedium!.copyWith(fontWeight: FontWeight.bold),
.textTheme
.titleMedium!
.copyWith(fontWeight: FontWeight.bold),
).tr(), ).tr(),
], ],
), ),
@ -362,12 +412,10 @@ class _HomeDashNotificationWidget extends StatefulWidget {
const _HomeDashNotificationWidget({super.key}); const _HomeDashNotificationWidget({super.key});
@override @override
State<_HomeDashNotificationWidget> createState() => State<_HomeDashNotificationWidget> createState() => _HomeDashNotificationWidgetState();
_HomeDashNotificationWidgetState();
} }
class _HomeDashNotificationWidgetState class _HomeDashNotificationWidgetState extends State<_HomeDashNotificationWidget> {
extends State<_HomeDashNotificationWidget> {
int? _count; int? _count;
Future<void> _fetchNotificationCount() async { Future<void> _fetchNotificationCount() async {
@ -404,9 +452,7 @@ class _HomeDashNotificationWidgetState
style: Theme.of(context).textTheme.titleLarge, style: Theme.of(context).textTheme.titleLarge,
).tr(), ).tr(),
Text( Text(
_count == null _count == null ? 'loading'.tr() : 'notificationUnreadCount'.plural(_count ?? 0),
? 'loading'.tr()
: 'notificationUnreadCount'.plural(_count ?? 0),
style: Theme.of(context).textTheme.bodyLarge, style: Theme.of(context).textTheme.bodyLarge,
), ),
], ],
@ -437,12 +483,10 @@ class _HomeDashRecommendationPostWidget extends StatefulWidget {
const _HomeDashRecommendationPostWidget({super.key}); const _HomeDashRecommendationPostWidget({super.key});
@override @override
State<_HomeDashRecommendationPostWidget> createState() => State<_HomeDashRecommendationPostWidget> createState() => _HomeDashRecommendationPostWidgetState();
_HomeDashRecommendationPostWidgetState();
} }
class _HomeDashRecommendationPostWidgetState class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendationPostWidget> {
extends State<_HomeDashRecommendationPostWidget> {
bool _isBusy = false; bool _isBusy = false;
List<SnPost>? _posts; List<SnPost>? _posts;
@ -491,8 +535,7 @@ class _HomeDashRecommendationPostWidgetState
).padding(horizontal: 18, top: 12, bottom: 8), ).padding(horizontal: 18, top: 12, bottom: 8),
Expanded( Expanded(
child: PageView.builder( child: PageView.builder(
scrollBehavior: scrollBehavior: ScrollConfiguration.of(context).copyWith(dragDevices: {
ScrollConfiguration.of(context).copyWith(dragDevices: {
PointerDeviceKind.mouse, PointerDeviceKind.mouse,
PointerDeviceKind.touch, PointerDeviceKind.touch,
}), }),
@ -505,8 +548,7 @@ class _HomeDashRecommendationPostWidgetState
showMenu: false, showMenu: false,
).padding(bottom: 8), ).padding(bottom: 8),
onTap: () { onTap: () {
GoRouter.of(context) GoRouter.of(context).pushNamed('postDetail', pathParameters: {
.pushNamed('postDetail', pathParameters: {
'slug': _posts![index].id.toString(), 'slug': _posts![index].id.toString(),
}); });
}, },

View File

@ -16,6 +16,7 @@ import firebase_messaging
import flutter_udid import flutter_udid
import flutter_webrtc import flutter_webrtc
import gal import gal
import in_app_review
import livekit_client import livekit_client
import media_kit_libs_macos_video import media_kit_libs_macos_video
import media_kit_video import media_kit_video
@ -41,6 +42,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin")) FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin"))
FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin")) FlutterWebRTCPlugin.register(with: registry.registrar(forPlugin: "FlutterWebRTCPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin")) GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
InAppReviewPlugin.register(with: registry.registrar(forPlugin: "InAppReviewPlugin"))
LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin")) LiveKitPlugin.register(with: registry.registrar(forPlugin: "LiveKitPlugin"))
MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin"))
MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin"))

View File

@ -132,6 +132,8 @@ PODS:
- GoogleUtilities/UserDefaults (8.0.2): - GoogleUtilities/UserDefaults (8.0.2):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- in_app_review (2.0.0):
- FlutterMacOS
- livekit_client (2.3.2): - livekit_client (2.3.2):
- flutter_webrtc - flutter_webrtc
- FlutterMacOS - FlutterMacOS
@ -186,6 +188,7 @@ DEPENDENCIES:
- flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`) - flutter_webrtc (from `Flutter/ephemeral/.symlinks/plugins/flutter_webrtc/macos`)
- FlutterMacOS (from `Flutter/ephemeral`) - FlutterMacOS (from `Flutter/ephemeral`)
- gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`) - gal (from `Flutter/ephemeral/.symlinks/plugins/gal/darwin`)
- in_app_review (from `Flutter/ephemeral/.symlinks/plugins/in_app_review/macos`)
- livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`) - livekit_client (from `Flutter/ephemeral/.symlinks/plugins/livekit_client/macos`)
- media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`) - media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`)
- media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`)
@ -243,6 +246,8 @@ EXTERNAL SOURCES:
:path: Flutter/ephemeral :path: Flutter/ephemeral
gal: gal:
:path: Flutter/ephemeral/.symlinks/plugins/gal/darwin :path: Flutter/ephemeral/.symlinks/plugins/gal/darwin
in_app_review:
:path: Flutter/ephemeral/.symlinks/plugins/in_app_review/macos
livekit_client: livekit_client:
:path: Flutter/ephemeral/.symlinks/plugins/livekit_client/macos :path: Flutter/ephemeral/.symlinks/plugins/livekit_client/macos
media_kit_libs_macos_video: media_kit_libs_macos_video:
@ -286,13 +291,14 @@ SPEC CHECKSUMS:
FirebaseCoreInternal: d98ab91e2d80a56d7b246856a8885443b302c0c2 FirebaseCoreInternal: d98ab91e2d80a56d7b246856a8885443b302c0c2
FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414 FirebaseInstallations: 6ef4a1c7eb2a61ee1f74727d7f6ce2e72acf1414
FirebaseMessaging: f8a160d99c2c2e5babbbcc90c4a3e15db036aee2 FirebaseMessaging: f8a160d99c2c2e5babbbcc90c4a3e15db036aee2
flutter_udid: 6b2b89780c3dfeecf0047bdf93f622d6416b1c07 flutter_udid: 2e7b3da4b5fdfba86a396b97898f5fe8f4ec1a52
flutter_webrtc: 53c9e1285ab32dfb58afb1e1471416a877e23d7a flutter_webrtc: 53c9e1285ab32dfb58afb1e1471416a877e23d7a
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5
GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
in_app_review: a6a031b9acd03c7d103e341aa334adf2c493fb93
livekit_client: 9fdcb22df3de55e6d4b24bdc3b5eb1c0269d774a livekit_client: 9fdcb22df3de55e6d4b24bdc3b5eb1c0269d774a
media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82 media_kit_libs_macos_video: b3e2bbec2eef97c285f2b1baa7963c67c753fb82
media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5 media_kit_native_event_loop: 81fd5b45192b72f8b5b69eaf5b540f45777eb8d5

View File

@ -627,6 +627,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.5.2" version: "4.5.2"
flutter_app_update:
dependency: "direct main"
description:
name: flutter_app_update
sha256: "09290240949c4651581cd6fc535e52d019e189e694d6019c56b5a56c2e69ba65"
url: "https://pub.dev"
source: hosted
version: "3.2.2"
flutter_cache_manager: flutter_cache_manager:
dependency: transitive dependency: transitive
description: description:
@ -729,10 +737,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_udid name: flutter_udid
sha256: "63384bd96203aaefccfd7137fab642edda18afede12b0e9e1a2c96fe2589fd07" sha256: be464dc5b1fb7ee894f6a32d65c086ca5e177fdcf9375ac08d77495b98150f84
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.1"
flutter_web_plugins: flutter_web_plugins:
dependency: "direct main" dependency: "direct main"
description: flutter description: flutter
@ -962,6 +970,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.1+1" version: "0.2.1+1"
in_app_review:
dependency: "direct main"
description:
name: in_app_review
sha256: "36a06771b88fb0e79985b15e7f2ac0f1142e903fe72517f3c055d78bc3bc1819"
url: "https://pub.dev"
source: hosted
version: "2.0.10"
in_app_review_platform_interface:
dependency: transitive
description:
name: in_app_review_platform_interface
sha256: fed2c755f2125caa9ae10495a3c163aa7fab5af3585a9c62ef4a6920c5b45f10
url: "https://pub.dev"
source: hosted
version: "2.0.5"
intl: intl:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1975,6 +1999,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
version:
dependency: "direct main"
description:
name: version
sha256: "3d4140128e6ea10d83da32fef2fa4003fccbf6852217bb854845802f04191f94"
url: "https://pub.dev"
source: hosted
version: "3.0.2"
very_good_infinite_list: very_good_infinite_list:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -108,6 +108,9 @@ dependencies:
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 workmanager: ^0.5.2
flutter_app_update: ^3.2.2
in_app_review: ^2.0.10
version: ^3.0.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -0,0 +1,25 @@
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": [
"W7HPZ53V6B.dev.solsynth.solian"
],
"paths": [
"*"
],
"components": [
{
"/": "/*"
}
]
}
]
},
"webcredentials": {
"apps": [
"W7HPZ53V6B.dev.solsynth.solian"
]
}
}