Compare commits
29 Commits
4daff41b3e
...
2.1.1+36
Author | SHA1 | Date | |
---|---|---|---|
6427ec1f82 | |||
35dc7f4392 | |||
b50191970e | |||
1b69e6dd42 | |||
39fb4d474f | |||
392aebcad7 | |||
e9e3a4c474 | |||
7182336a0d | |||
be98fe133d | |||
e458943f56 | |||
eb125fc436 | |||
dc78f39969 | |||
f5c06bc89c | |||
d6d60e60a9 | |||
435b730f3b | |||
73468c5c6d | |||
8db6513eef | |||
65a8f1e6c3 | |||
2671ffad4b | |||
8a628823e0 | |||
94d19a1524 | |||
d98f6c8d18 | |||
6d0f62016a | |||
7e0faba5db | |||
7508a54907 | |||
2eb1f4b52b | |||
00678c0ac8 | |||
abc21f858b | |||
d67e33a41d |
16
README.md
16
README.md
@ -1,16 +0,0 @@
|
|||||||
# surface
|
|
||||||
|
|
||||||
A new Flutter project.
|
|
||||||
|
|
||||||
## Getting Started
|
|
||||||
|
|
||||||
This project is a starting point for a Flutter application.
|
|
||||||
|
|
||||||
A few resources to get you started if this is your first Flutter project:
|
|
||||||
|
|
||||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
|
||||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
|
||||||
|
|
||||||
For help getting started with Flutter development, view the
|
|
||||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
|
||||||
samples, guidance on mobile development, and a full API reference.
|
|
@ -9,7 +9,21 @@ plugins {
|
|||||||
id "dev.flutter.flutter-gradle-plugin"
|
id "dev.flutter.flutter-gradle-plugin"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation "androidx.glance:glance:1.1.1"
|
||||||
|
implementation "androidx.glance:glance-appwidget:1.1.1"
|
||||||
|
implementation 'androidx.compose.foundation:foundation-layout-android:1.7.6'
|
||||||
|
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-network-okhttp:3.0.4'
|
||||||
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
|
buildFeatures {
|
||||||
|
compose true
|
||||||
|
}
|
||||||
|
|
||||||
namespace = "dev.solsynth.solian"
|
namespace = "dev.solsynth.solian"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = "27.0.12077973"
|
ndkVersion = "27.0.12077973"
|
||||||
@ -19,26 +33,34 @@ android {
|
|||||||
targetCompatibility JavaVersion.VERSION_17
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
|
composeOptions {
|
||||||
|
kotlinCompilerExtensionVersion = "1.4.8"
|
||||||
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_17
|
jvmTarget = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "dev.solsynth.solian"
|
applicationId = "dev.solsynth.solian"
|
||||||
// You can update the following values to match your application needs.
|
minSdk = 26
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
|
||||||
minSdk = flutter.minSdkVersion
|
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
|
debug {
|
||||||
|
debuggable true
|
||||||
|
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig = signingConfigs.debug
|
signingConfig = signingConfigs.debug
|
||||||
|
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,23 +27,12 @@
|
|||||||
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>
|
|
||||||
<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" />
|
||||||
@ -52,12 +41,22 @@
|
|||||||
<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" />
|
||||||
<data android:mimeType="*/*" />
|
<data android:mimeType="image/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<data android:mimeType="*/*" />
|
<data android:mimeType="image/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
@ -78,7 +77,30 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
|
||||||
|
<!-- Widgets -->
|
||||||
|
<receiver android:name=".widgets.CheckInWidgetReceiver"
|
||||||
|
android:label="Check In"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/check_in_widget" />
|
||||||
|
</receiver>
|
||||||
|
<receiver android:name=".widgets.RandomPostWidgetReceiver"
|
||||||
|
android:label="Random Post"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/random_post_widget" />
|
||||||
|
</receiver>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<!-- Required to query activities that can process text, see:
|
<!-- Required to query activities that can process text, see:
|
||||||
https://developer.android.com/training/package-visibility and
|
https://developer.android.com/training/package-visibility and
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
@ -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>)
|
@ -0,0 +1,35 @@
|
|||||||
|
package dev.solsynth.solian.data
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarPost(
|
||||||
|
val id: Int,
|
||||||
|
val body: SolarPostBody,
|
||||||
|
val publisher: SolarPublisher,
|
||||||
|
val publisherId: Int,
|
||||||
|
val createdAt: Instant,
|
||||||
|
val updatedAt: Instant,
|
||||||
|
val editedAt: Instant?,
|
||||||
|
val publishedAt: Instant?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarPostBody(
|
||||||
|
val content: String?,
|
||||||
|
val title: String?,
|
||||||
|
val description: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarPublisher(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val nick: String,
|
||||||
|
val description: String?,
|
||||||
|
val avatar: String?,
|
||||||
|
val banner: String?,
|
||||||
|
val createdAt: Instant,
|
||||||
|
val updatedAt: Instant
|
||||||
|
)
|
@ -0,0 +1,38 @@
|
|||||||
|
package dev.solsynth.solian.data
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import com.google.gson.JsonDeserializationContext
|
||||||
|
import com.google.gson.JsonDeserializer
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
import com.google.gson.JsonParseException
|
||||||
|
import com.google.gson.JsonPrimitive
|
||||||
|
import com.google.gson.JsonSerializationContext
|
||||||
|
import com.google.gson.JsonSerializer
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
class InstantAdapter : JsonSerializer<Instant?>,
|
||||||
|
JsonDeserializer<Instant?> {
|
||||||
|
override fun serialize(
|
||||||
|
src: Instant?,
|
||||||
|
typeOfSrc: Type?,
|
||||||
|
context: JsonSerializationContext?
|
||||||
|
): JsonElement {
|
||||||
|
return JsonPrimitive(formatter.format(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(JsonParseException::class)
|
||||||
|
override fun deserialize(
|
||||||
|
json: JsonElement,
|
||||||
|
typeOfT: Type?,
|
||||||
|
context: JsonDeserializationContext?
|
||||||
|
): Instant {
|
||||||
|
return Instant.parse(json.asString)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val formatter: DateTimeFormatter = DateTimeFormatter.ISO_INSTANT
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package dev.solsynth.solian.data
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import java.time.Instant
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarUser(
|
||||||
|
val id: Int,
|
||||||
|
val name: String,
|
||||||
|
val nick: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class SolarCheckInRecord(
|
||||||
|
val id: Int,
|
||||||
|
val resultTier: Int,
|
||||||
|
val resultExperience: Int,
|
||||||
|
val createdAt: Instant
|
||||||
|
)
|
@ -0,0 +1,128 @@
|
|||||||
|
import android.content.Context
|
||||||
|
import android.net.Uri
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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.action.clickable
|
||||||
|
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.fillMaxWidth
|
||||||
|
import androidx.glance.layout.height
|
||||||
|
import androidx.glance.layout.padding
|
||||||
|
import androidx.glance.state.GlanceStateDefinition
|
||||||
|
import androidx.glance.text.FontFamily
|
||||||
|
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.SolarCheckInRecord
|
||||||
|
import es.antonborri.home_widget.actionStartActivity
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.OffsetDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
class CheckInWidget : GlanceAppWidget() {
|
||||||
|
override val stateDefinition: GlanceStateDefinition<*>?
|
||||||
|
get() = HomeWidgetGlanceStateDefinition()
|
||||||
|
|
||||||
|
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||||
|
provideContent {
|
||||||
|
GlanceTheme {
|
||||||
|
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 resultTierSymbols = listOf("大凶", "凶", "中平", "吉", "大吉")
|
||||||
|
|
||||||
|
val prefs = currentState.preferences
|
||||||
|
val checkInRaw: String? = prefs.getString("pas_check_in_record", null)
|
||||||
|
|
||||||
|
val checkIn: SolarCheckInRecord? =
|
||||||
|
checkInRaw?.let { checkInRaw ->
|
||||||
|
gson.fromJson(checkInRaw, SolarCheckInRecord::class.java)
|
||||||
|
} ?: null;
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = GlanceModifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.fillMaxHeight()
|
||||||
|
.background(GlanceTheme.colors.widgetBackground)
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable(
|
||||||
|
onClick = actionStartActivity<MainActivity>(
|
||||||
|
context,
|
||||||
|
Uri.parse("https://sn.solsynth.dev")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (checkIn != null) {
|
||||||
|
val dateFormatter = DateTimeFormatter.ofPattern("EEE, MM/dd")
|
||||||
|
|
||||||
|
val checkDate = checkIn.createdAt.atZone(ZoneId.of("UTC")).toLocalDate()
|
||||||
|
val currentDate = LocalDate.now()
|
||||||
|
if (checkDate.isEqual(currentDate)) {
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = resultTierSymbols[checkIn.resultTier],
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 17.sp,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "+${checkIn.resultExperience} EXP",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 13.sp,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(modifier = GlanceModifier.height(8.dp))
|
||||||
|
Row(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||||
|
Text(
|
||||||
|
text = OffsetDateTime.ofInstant(
|
||||||
|
checkIn.createdAt,
|
||||||
|
ZoneId.systemDefault()
|
||||||
|
)
|
||||||
|
.format(dateFormatter),
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 11.sp,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return@Column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "You haven't checked in today",
|
||||||
|
style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package dev.solsynth.solian.widgets
|
||||||
|
|
||||||
|
import CheckInWidget
|
||||||
|
import HomeWidgetGlanceWidgetReceiver
|
||||||
|
|
||||||
|
class CheckInWidgetReceiver : HomeWidgetGlanceWidgetReceiver<CheckInWidget>() {
|
||||||
|
override val glanceAppWidget = CheckInWidget()
|
||||||
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
import HomeWidgetGlanceState
|
||||||
|
import HomeWidgetGlanceStateDefinition
|
||||||
|
import android.content.Context
|
||||||
|
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.action.clickable
|
||||||
|
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 dev.solsynth.solian.MainActivity
|
||||||
|
import dev.solsynth.solian.data.InstantAdapter
|
||||||
|
import dev.solsynth.solian.data.SolarPost
|
||||||
|
import es.antonborri.home_widget.actionStartActivity
|
||||||
|
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()
|
||||||
|
|
||||||
|
override suspend fun provideGlance(context: Context, id: GlanceId) {
|
||||||
|
provideContent {
|
||||||
|
GlanceTheme {
|
||||||
|
GlanceContent(context, currentState())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun GlanceContent(
|
||||||
|
context: Context,
|
||||||
|
currentState: HomeWidgetGlanceState,
|
||||||
|
) {
|
||||||
|
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(GlanceTheme.colors.widgetBackground)
|
||||||
|
.padding(16.dp)
|
||||||
|
.clickable(
|
||||||
|
onClick = actionStartActivity<MainActivity>(
|
||||||
|
context,
|
||||||
|
Uri.parse("https://sn.solsynth.dev/posts/${data!!.id}")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
if (data != null) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
Text(
|
||||||
|
text = data.publisher.nick,
|
||||||
|
style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
|
||||||
|
)
|
||||||
|
Spacer(modifier = GlanceModifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
text = "@${data.publisher.name}",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 13.sp,
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = GlanceModifier.height(8.dp))
|
||||||
|
|
||||||
|
if (data.body.title != null) {
|
||||||
|
Text(
|
||||||
|
text = data.body.title,
|
||||||
|
style = TextStyle(fontSize = 19.sp, color = GlanceTheme.colors.onSurface)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (data.body.description != null) {
|
||||||
|
Text(
|
||||||
|
text = data.body.description,
|
||||||
|
style = TextStyle(fontSize = 17.sp, color = GlanceTheme.colors.onSurface)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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, color = GlanceTheme.colors.onSurface),
|
||||||
|
)
|
||||||
|
|
||||||
|
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, color = GlanceTheme.colors.onSurface),
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
"#${data.id}",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return@Column;
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = GlanceModifier.fillMaxSize(),
|
||||||
|
verticalAlignment = Alignment.Vertical.CenterVertically,
|
||||||
|
horizontalAlignment = Alignment.Horizontal.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "No Recommendations",
|
||||||
|
style = TextStyle(
|
||||||
|
fontSize = 17.sp,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
color = GlanceTheme.colors.onSurface
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Open app to load some posts",
|
||||||
|
style = TextStyle(fontSize = 15.sp, color = GlanceTheme.colors.onSurface)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
package dev.solsynth.solian.widgets
|
||||||
|
|
||||||
|
import RandomPostWidget
|
||||||
|
import HomeWidgetGlanceWidgetReceiver
|
||||||
|
|
||||||
|
class RandomPostWidgetReceiver : HomeWidgetGlanceWidgetReceiver<RandomPostWidget>() {
|
||||||
|
override val glanceAppWidget = RandomPostWidget()
|
||||||
|
}
|
7
android/app/src/main/res/xml/check_in_widget.xml
Normal file
7
android/app/src/main/res/xml/check_in_widget.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:initialLayout="@layout/glance_default_loading_layout"
|
||||||
|
android:minWidth="40dp"
|
||||||
|
android:minHeight="40dp"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:updatePeriodMillis="10000">
|
||||||
|
</appwidget-provider>
|
7
android/app/src/main/res/xml/random_post_widget.xml
Normal file
7
android/app/src/main/res/xml/random_post_widget.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:initialLayout="@layout/glance_default_loading_layout"
|
||||||
|
android:minWidth="240dp"
|
||||||
|
android:minHeight="40dp"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:updatePeriodMillis="10000">
|
||||||
|
</appwidget-provider>
|
14
android/app/src/proguard-rules.pro
vendored
Normal file
14
android/app/src/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
-keepclassmembers class kotlin.Metadata { *; }
|
||||||
|
-keep class dev.solsynth.solian.** { *; }
|
||||||
|
-keep public class dev.solsynth.solian.data.** { public *; }
|
||||||
|
-keepclassmembers class dev.solsynth.solian.data.** { *; }
|
||||||
|
|
||||||
|
-keepattributes *Annotation*
|
||||||
|
-keepattributes Signature
|
||||||
|
-keepattributes EnclosingMethod
|
||||||
|
|
||||||
|
-keep class com.google.gson.** { *; }
|
||||||
|
|
||||||
|
-keepclassmembers class * {
|
||||||
|
@com.google.gson.annotations.SerializedName <fields>;
|
||||||
|
}
|
@ -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"
|
||||||
|
@ -18,7 +18,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version '8.7.2' apply false
|
id "com.android.application" version '8.7.3' apply false
|
||||||
// START: FlutterFire Configuration
|
// START: FlutterFire Configuration
|
||||||
id "com.google.gms.google-services" version "4.3.15" apply false
|
id "com.google.gms.google-services" version "4.3.15" apply false
|
||||||
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
id "com.google.firebase.crashlytics" version "2.8.1" apply false
|
||||||
|
@ -190,6 +190,13 @@
|
|||||||
"settingsNetworkServerPreset": "Present HyperNet Server",
|
"settingsNetworkServerPreset": "Present HyperNet Server",
|
||||||
"settingsNetworkServerPresetDescription": "You can choose one of our preset HyperNet server addresses from the list on the right.",
|
"settingsNetworkServerPresetDescription": "You can choose one of our preset HyperNet server addresses from the list on the right.",
|
||||||
"settingsNetworkServerSaved": "Server address saved.",
|
"settingsNetworkServerSaved": "Server address saved.",
|
||||||
|
"settingsPerformance": "Performance",
|
||||||
|
"settingsImageQuality": "Image Quality",
|
||||||
|
"settingsImageQualityDescription": "Set the image quality, it will affect the decoding speed of the image.",
|
||||||
|
"settingsImageQualityLowest": "Lowest",
|
||||||
|
"settingsImageQualityLow": "Low",
|
||||||
|
"settingsImageQualityMedium": "Medium",
|
||||||
|
"settingsImageQualityHigh": "High",
|
||||||
"settingsMisc": "Misc",
|
"settingsMisc": "Misc",
|
||||||
"settingsMiscAbout": "About",
|
"settingsMiscAbout": "About",
|
||||||
"settingsMiscAboutDescription": "View the version information of Solian.",
|
"settingsMiscAboutDescription": "View the version information of Solian.",
|
||||||
@ -363,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": {
|
||||||
@ -448,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": "正在更新,请稍后..."
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,13 @@
|
|||||||
"settingsNetworkServerPreset": "预设的 HyperNet 服务器",
|
"settingsNetworkServerPreset": "预设的 HyperNet 服务器",
|
||||||
"settingsNetworkServerPresetDescription": "你可以在旁边的列表中选择我们提供的预设 HyperNet 服务器地址。",
|
"settingsNetworkServerPresetDescription": "你可以在旁边的列表中选择我们提供的预设 HyperNet 服务器地址。",
|
||||||
"settingsNetworkServerSaved": "服务器地址已保存。",
|
"settingsNetworkServerSaved": "服务器地址已保存。",
|
||||||
|
"settingsPerformance": "性能",
|
||||||
|
"settingsImageQuality": "图片预览质量",
|
||||||
|
"settingsImageQualityDescription": "设置图片预览质量,会影响图片解码速度。",
|
||||||
|
"settingsImageQualityLowest": "极低",
|
||||||
|
"settingsImageQualityLow": "低",
|
||||||
|
"settingsImageQualityMedium": "中",
|
||||||
|
"settingsImageQualityHigh": "高",
|
||||||
"settingsMisc": "杂项",
|
"settingsMisc": "杂项",
|
||||||
"settingsMiscAbout": "关于",
|
"settingsMiscAbout": "关于",
|
||||||
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
||||||
@ -361,6 +368,8 @@
|
|||||||
"dailyCheckNegativeHint6": "出门",
|
"dailyCheckNegativeHint6": "出门",
|
||||||
"dailyCheckNegativeHint6Description": "忘带伞遇上大雨",
|
"dailyCheckNegativeHint6Description": "忘带伞遇上大雨",
|
||||||
"happyBirthday": "生日快乐,{}!",
|
"happyBirthday": "生日快乐,{}!",
|
||||||
|
"celebrateMerryXmas": "圣诞快乐,{}!",
|
||||||
|
"celebrateNewYear": "新年快乐,{}!",
|
||||||
"friendNew": "添加好友",
|
"friendNew": "添加好友",
|
||||||
"friendRequests": "好友请求",
|
"friendRequests": "好友请求",
|
||||||
"friendRequestsDescription": {
|
"friendRequestsDescription": {
|
||||||
@ -446,5 +455,7 @@
|
|||||||
"poweredBy": "由 {} 提供支持",
|
"poweredBy": "由 {} 提供支持",
|
||||||
"shareIntent": "分享",
|
"shareIntent": "分享",
|
||||||
"shareIntentDescription": "您想对您分享的内容做些什么?",
|
"shareIntentDescription": "您想对您分享的内容做些什么?",
|
||||||
"shareIntentPostStory": "发布动态"
|
"shareIntentPostStory": "发布动态",
|
||||||
|
"updateAvailable": "检测到更新可用",
|
||||||
|
"updateOngoing": "正在更新,请稍后……"
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,13 @@
|
|||||||
"settingsNetworkServerPreset": "預設的 HyperNet 服務器",
|
"settingsNetworkServerPreset": "預設的 HyperNet 服務器",
|
||||||
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 服務器地址。",
|
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 服務器地址。",
|
||||||
"settingsNetworkServerSaved": "服務器地址已保存。",
|
"settingsNetworkServerSaved": "服務器地址已保存。",
|
||||||
|
"settingsPerformance": "性能",
|
||||||
|
"settingsImageQuality": "圖片預覽質量",
|
||||||
|
"settingsImageQualityDescription": "設置圖片預覽質量,會影響圖片解碼速度。",
|
||||||
|
"settingsImageQualityLowest": "極低",
|
||||||
|
"settingsImageQualityLow": "低",
|
||||||
|
"settingsImageQualityMedium": "中",
|
||||||
|
"settingsImageQualityHigh": "高",
|
||||||
"settingsMisc": "雜項",
|
"settingsMisc": "雜項",
|
||||||
"settingsMiscAbout": "關於",
|
"settingsMiscAbout": "關於",
|
||||||
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
||||||
@ -441,5 +448,10 @@
|
|||||||
"postImageShareReadMore": "掃描右側 QRCode 查看全文",
|
"postImageShareReadMore": "掃描右側 QRCode 查看全文",
|
||||||
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
||||||
"postShare": "分享",
|
"postShare": "分享",
|
||||||
"postShareImage": "分享帖圖"
|
"postShareImage": "分享帖圖",
|
||||||
|
"appInitializing": "正在初始化",
|
||||||
|
"poweredBy": "由 {} 提供支持",
|
||||||
|
"shareIntent": "分享",
|
||||||
|
"shareIntentDescription": "您想對您分享的內容做些什麼?",
|
||||||
|
"shareIntentPostStory": "發佈動態"
|
||||||
}
|
}
|
||||||
|
@ -188,6 +188,13 @@
|
|||||||
"settingsNetworkServerPreset": "預設的 HyperNet 伺服器",
|
"settingsNetworkServerPreset": "預設的 HyperNet 伺服器",
|
||||||
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 伺服器地址。",
|
"settingsNetworkServerPresetDescription": "你可以在旁邊的列表中選擇我們提供的預設 HyperNet 伺服器地址。",
|
||||||
"settingsNetworkServerSaved": "伺服器地址已儲存。",
|
"settingsNetworkServerSaved": "伺服器地址已儲存。",
|
||||||
|
"settingsPerformance": "效能",
|
||||||
|
"settingsImageQuality": "圖片預覽質量",
|
||||||
|
"settingsImageQualityDescription": "設定圖片預覽質量,會影響圖片解碼速度。",
|
||||||
|
"settingsImageQualityLowest": "極低",
|
||||||
|
"settingsImageQualityLow": "低",
|
||||||
|
"settingsImageQualityMedium": "中",
|
||||||
|
"settingsImageQualityHigh": "高",
|
||||||
"settingsMisc": "雜項",
|
"settingsMisc": "雜項",
|
||||||
"settingsMiscAbout": "關於",
|
"settingsMiscAbout": "關於",
|
||||||
"settingsMiscAboutDescription": "檢視 Solian 的版本資訊。",
|
"settingsMiscAboutDescription": "檢視 Solian 的版本資訊。",
|
||||||
@ -441,5 +448,10 @@
|
|||||||
"postImageShareReadMore": "掃描右側 QRCode 檢視全文",
|
"postImageShareReadMore": "掃描右側 QRCode 檢視全文",
|
||||||
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
"postImageShareAds": "來 Solar Network 探索更多有趣帖子",
|
||||||
"postShare": "分享",
|
"postShare": "分享",
|
||||||
"postShareImage": "分享帖圖"
|
"postShareImage": "分享帖圖",
|
||||||
|
"appInitializing": "正在初始化",
|
||||||
|
"poweredBy": "由 {} 提供支援",
|
||||||
|
"shareIntent": "分享",
|
||||||
|
"shareIntentDescription": "您想對您分享的內容做些什麼?",
|
||||||
|
"shareIntentPostStory": "釋出動態"
|
||||||
}
|
}
|
||||||
|
18
ios/Podfile
18
ios/Podfile
@ -36,6 +36,24 @@ target 'Runner' do
|
|||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
end
|
end
|
||||||
|
|
||||||
|
target 'SolarNotifyService' do
|
||||||
|
inherit! :search_paths
|
||||||
|
pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios'
|
||||||
|
|
||||||
|
pod 'Kingfisher', '~> 8.0'
|
||||||
|
pod 'Alamofire'
|
||||||
|
end
|
||||||
|
|
||||||
|
target 'SolarWidgetExtension' do
|
||||||
|
inherit! :search_paths
|
||||||
|
use_frameworks!
|
||||||
|
use_modular_headers!
|
||||||
|
|
||||||
|
pod 'home_widget', :path => '.symlinks/plugins/home_widget/ios'
|
||||||
|
|
||||||
|
pod 'Kingfisher', '~> 8.0'
|
||||||
|
end
|
||||||
|
|
||||||
target 'SolarShare' do
|
target 'SolarShare' do
|
||||||
inherit! :search_paths
|
inherit! :search_paths
|
||||||
end
|
end
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
PODS:
|
PODS:
|
||||||
|
- Alamofire (5.10.2)
|
||||||
- connectivity_plus (0.0.1):
|
- connectivity_plus (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
@ -56,7 +57,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):
|
||||||
@ -102,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):
|
||||||
@ -167,6 +170,9 @@ 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)
|
||||||
- livekit_client (2.3.2):
|
- livekit_client (2.3.2):
|
||||||
- Flutter
|
- Flutter
|
||||||
- flutter_webrtc
|
- flutter_webrtc
|
||||||
@ -216,8 +222,11 @@ 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:
|
||||||
|
- Alamofire
|
||||||
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/darwin`)
|
||||||
- croppy (from `.symlinks/plugins/croppy/ios`)
|
- croppy (from `.symlinks/plugins/croppy/ios`)
|
||||||
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
|
||||||
@ -227,12 +236,15 @@ 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)
|
||||||
- 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,9 +261,11 @@ 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:
|
||||||
|
- Alamofire
|
||||||
- DKImagePickerController
|
- DKImagePickerController
|
||||||
- DKPhotoGallery
|
- DKPhotoGallery
|
||||||
- Firebase
|
- Firebase
|
||||||
@ -263,6 +277,7 @@ SPEC REPOS:
|
|||||||
- GoogleAppMeasurement
|
- GoogleAppMeasurement
|
||||||
- GoogleDataTransport
|
- GoogleDataTransport
|
||||||
- GoogleUtilities
|
- GoogleUtilities
|
||||||
|
- Kingfisher
|
||||||
- nanopb
|
- nanopb
|
||||||
- PromisesObjC
|
- PromisesObjC
|
||||||
- SAMKeychain
|
- SAMKeychain
|
||||||
@ -289,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:
|
||||||
@ -301,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:
|
||||||
@ -333,8 +352,11 @@ 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:
|
||||||
|
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||||
connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695
|
connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695
|
||||||
croppy: b6199bc8d56bd2e03cc11609d1c47ad9875c1321
|
croppy: b6199bc8d56bd2e03cc11609d1c47ad9875c1321
|
||||||
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
|
||||||
@ -344,7 +366,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
|
||||||
@ -352,15 +374,18 @@ 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: 61e868295d28fe67ffa297fae6dacebf56fd53e1
|
gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5
|
||||||
GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e
|
GoogleAppMeasurement: 987769c4ca6b968f2479fbcc9fe3ce34af454b8e
|
||||||
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
|
||||||
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
GoogleUtilities: 26a3abef001b6533cf678d3eb38fd3f614b7872d
|
||||||
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
home_widget: 0434835a4c9a75704264feff6be17ea40e0f0d57
|
||||||
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
|
||||||
|
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
|
||||||
|
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 +406,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: 9b244e02f87527430136c8d21cbdcf1cd586b6bc
|
||||||
|
|
||||||
COCOAPODS: 1.16.2
|
COCOAPODS: 1.16.2
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; };
|
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */; };
|
||||||
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */; };
|
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */; };
|
||||||
738C1EB82D0D76A500A215F3 /* SolarWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
738C1EB82D0D76A500A215F3 /* SolarWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
7396A3522D16BD890095F4A8 /* NotifyDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */; };
|
||||||
73B7746E2D0E869200A789CE /* SolarShare.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73B774642D0E869200A789CE /* SolarShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73B7746E2D0E869200A789CE /* SolarShare.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73B774642D0E869200A789CE /* SolarShare.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
73DA8A012D05C7620024A03E /* SolarNotifyService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
73DA8A012D05C7620024A03E /* SolarNotifyService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
@ -22,6 +23,8 @@
|
|||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
CED170BFB6A72CDDAC285637 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */; };
|
CED170BFB6A72CDDAC285637 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDF483E994343CDFBF9BA347 /* Pods_Runner.framework */; };
|
||||||
|
D5125CF12F159F0B8BC7641D /* Pods_SolarNotifyService.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */; };
|
||||||
|
D962B51F682FBDEC00AC7281 /* Pods_SolarWidgetExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */; };
|
||||||
F51C4E3C8FA95426C91FC0A4 /* Pods_SolarShare.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */; };
|
F51C4E3C8FA95426C91FC0A4 /* Pods_SolarShare.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -83,30 +86,40 @@
|
|||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarNotifyService.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
1077EFD9ACF793E9DA5D5B63 /* Pods-Runner-SolarNotifyService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.release.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
40B53769EB464E54DACA7CE4 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
40B53769EB464E54DACA7CE4 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
430F31F96B82659CBEAD4326 /* Pods-Runner-SolarWidgetExtension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.profile.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
48AE73F9950AF4FB02B5E9F4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
48AE73F9950AF4FB02B5E9F4 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.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>"; };
|
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>"; };
|
||||||
|
4CBF45ABD292EE527D0A4D1E /* Pods-SolarNotifyService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.profile.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.profile.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; };
|
||||||
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
738C1EAB2D0D76A400A215F3 /* SolarWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
738C1F132D0D7DDC00A215F3 /* SolarWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolarWidgetExtension.entitlements; sourceTree = "<group>"; };
|
738C1F132D0D7DDC00A215F3 /* SolarWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SolarWidgetExtension.entitlements; sourceTree = "<group>"; };
|
||||||
|
7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotifyDelegate.swift; sourceTree = "<group>"; };
|
||||||
73B774642D0E869200A789CE /* SolarShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarShare.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
73B774642D0E869200A789CE /* SolarShare.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarShare.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarNotifyService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
73DA89FA2D05C7620024A03E /* SolarNotifyService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SolarNotifyService.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SolarWidgetExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
8E44A071621D5CAF864FB2F1 /* Pods-Runner-SolarNotifyService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.debug.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
931FBE9EDB99B3AD8B1FFB00 /* Pods-Runner-SolarWidgetExtension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.release.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
96081771773FA019A97CCC3F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
96081771773FA019A97CCC3F /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
@ -117,6 +130,11 @@
|
|||||||
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>"; };
|
||||||
|
B4550C68292419CDC580808B /* Pods-Runner-SolarNotifyService.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarNotifyService.profile.xcconfig"; path = "Target Support Files/Pods-Runner-SolarNotifyService/Pods-Runner-SolarNotifyService.profile.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>"; };
|
||||||
|
BFF3B436D74FA8CBFFE34A27 /* Pods-Runner-SolarWidgetExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner-SolarWidgetExtension.debug.xcconfig"; path = "Target Support Files/Pods-Runner-SolarWidgetExtension/Pods-Runner-SolarWidgetExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
D7E1FA77FDA53439DB2C0E75 /* Pods-SolarNotifyService.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.release.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
D96D1DB4ED46A2640C1B9D34 /* Pods-SolarNotifyService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SolarNotifyService.debug.xcconfig"; path = "Target Support Files/Pods-SolarNotifyService/Pods-SolarNotifyService.debug.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; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -217,6 +235,7 @@
|
|||||||
files = (
|
files = (
|
||||||
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */,
|
738C1EAD2D0D76A400A215F3 /* SwiftUI.framework in Frameworks */,
|
||||||
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */,
|
738C1EAC2D0D76A400A215F3 /* WidgetKit.framework in Frameworks */,
|
||||||
|
D962B51F682FBDEC00AC7281 /* Pods_SolarWidgetExtension.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -232,6 +251,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
D5125CF12F159F0B8BC7641D /* Pods_SolarNotifyService.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -262,6 +282,8 @@
|
|||||||
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */,
|
731B7B6B2D0D6CE000CEB9B7 /* WidgetKit.framework */,
|
||||||
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */,
|
731B7B6D2D0D6CE000CEB9B7 /* SwiftUI.framework */,
|
||||||
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */,
|
16F41E029731EA30268EDE2A /* Pods_SolarShare.framework */,
|
||||||
|
02469D286F48D84300484B1E /* Pods_SolarNotifyService.framework */,
|
||||||
|
7B1A159F5551E280D0EFC129 /* Pods_SolarWidgetExtension.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -328,6 +350,7 @@
|
|||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
7396A3512D16BD890095F4A8 /* NotifyDelegate.swift */,
|
||||||
);
|
);
|
||||||
path = Runner;
|
path = Runner;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -344,6 +367,18 @@
|
|||||||
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 */,
|
||||||
|
D96D1DB4ED46A2640C1B9D34 /* Pods-SolarNotifyService.debug.xcconfig */,
|
||||||
|
D7E1FA77FDA53439DB2C0E75 /* Pods-SolarNotifyService.release.xcconfig */,
|
||||||
|
4CBF45ABD292EE527D0A4D1E /* Pods-SolarNotifyService.profile.xcconfig */,
|
||||||
|
8E44A071621D5CAF864FB2F1 /* Pods-Runner-SolarNotifyService.debug.xcconfig */,
|
||||||
|
1077EFD9ACF793E9DA5D5B63 /* Pods-Runner-SolarNotifyService.release.xcconfig */,
|
||||||
|
B4550C68292419CDC580808B /* Pods-Runner-SolarNotifyService.profile.xcconfig */,
|
||||||
|
BFF3B436D74FA8CBFFE34A27 /* Pods-Runner-SolarWidgetExtension.debug.xcconfig */,
|
||||||
|
931FBE9EDB99B3AD8B1FFB00 /* Pods-Runner-SolarWidgetExtension.release.xcconfig */,
|
||||||
|
430F31F96B82659CBEAD4326 /* Pods-Runner-SolarWidgetExtension.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -374,6 +409,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 */,
|
||||||
@ -416,6 +452,7 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 73DA8A072D05C7620024A03E /* Build configuration list for PBXNativeTarget "SolarNotifyService" */;
|
buildConfigurationList = 73DA8A072D05C7620024A03E /* Build configuration list for PBXNativeTarget "SolarNotifyService" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
50F5704AB2E7309C916CA2E7 /* [CP] Check Pods Manifest.lock */,
|
||||||
73DA89F62D05C7620024A03E /* Sources */,
|
73DA89F62D05C7620024A03E /* Sources */,
|
||||||
73DA89F72D05C7620024A03E /* Frameworks */,
|
73DA89F72D05C7620024A03E /* Frameworks */,
|
||||||
73DA89F82D05C7620024A03E /* Resources */,
|
73DA89F82D05C7620024A03E /* Resources */,
|
||||||
@ -611,6 +648,28 @@
|
|||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
50F5704AB2E7309C916CA2E7 /* [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-SolarNotifyService-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;
|
||||||
|
};
|
||||||
738C1EBE2D0D76C500A215F3 /* Copy Bundle Version */ = {
|
738C1EBE2D0D76C500A215F3 /* Copy Bundle Version */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@ -710,6 +769,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;
|
||||||
@ -765,6 +846,7 @@
|
|||||||
files = (
|
files = (
|
||||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
7396A3522D16BD890095F4A8 /* NotifyDelegate.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -879,7 +961,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 +1029,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 +1073,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 +1114,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;
|
||||||
@ -1193,6 +1278,7 @@
|
|||||||
};
|
};
|
||||||
73DA8A032D05C7620024A03E /* Debug */ = {
|
73DA8A032D05C7620024A03E /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = D96D1DB4ED46A2640C1B9D34 /* Pods-SolarNotifyService.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -1234,6 +1320,7 @@
|
|||||||
};
|
};
|
||||||
73DA8A042D05C7620024A03E /* Release */ = {
|
73DA8A042D05C7620024A03E /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = D7E1FA77FDA53439DB2C0E75 /* Pods-SolarNotifyService.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -1272,6 +1359,7 @@
|
|||||||
};
|
};
|
||||||
73DA8A052D05C7620024A03E /* Profile */ = {
|
73DA8A052D05C7620024A03E /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 4CBF45ABD292EE527D0A4D1E /* Pods-SolarNotifyService.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
@ -1433,7 +1521,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 +1549,7 @@
|
|||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
INFOPLIST_KEY_CFBundleDisplayName = Solian;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
@ -1,14 +1,26 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
import workmanager
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate {
|
@objc class AppDelegate: FlutterAppDelegate {
|
||||||
|
let notifyDelegate = NotifyDelegate()
|
||||||
|
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
GeneratedPluginRegistrant.register(with: self)
|
GeneratedPluginRegistrant.register(with: self)
|
||||||
|
WorkmanagerPlugin.setPluginRegistrantCallback { registry in
|
||||||
|
GeneratedPluginRegistrant.register(with: registry)
|
||||||
|
}
|
||||||
|
|
||||||
|
UIApplication.shared.setMinimumBackgroundFetchInterval(TimeInterval(60*5))
|
||||||
|
|
||||||
|
UNUserNotificationCenter.current().delegate = notifyDelegate
|
||||||
|
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
39
ios/Runner/AppIntent.swift
Normal file
39
ios/Runner/AppIntent.swift
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// AppIntent.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2024/12/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppIntents
|
||||||
|
import Flutter
|
||||||
|
import Foundation
|
||||||
|
import home_widget
|
||||||
|
|
||||||
|
@available(iOS 17, *)
|
||||||
|
public struct AppBackgroundIntent: AppIntent {
|
||||||
|
static public var title: LocalizedStringResource = "Solar Network Background Intent"
|
||||||
|
|
||||||
|
@Parameter(title: "Widget URI")
|
||||||
|
var url: URL?
|
||||||
|
|
||||||
|
@Parameter(title: "AppGroup")
|
||||||
|
var appGroup: String?
|
||||||
|
|
||||||
|
public init() {}
|
||||||
|
|
||||||
|
public init(url: URL?, appGroup: String?) {
|
||||||
|
self.url = url
|
||||||
|
self.appGroup = appGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
public func perform() async throws -> some IntentResult {
|
||||||
|
await HomeWidgetBackgroundWorker.run(url: url, appGroup: appGroup!)
|
||||||
|
|
||||||
|
return .result()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@available(iOS 17, *)
|
||||||
|
@available(iOSApplicationExtension, unavailable)
|
||||||
|
extension AppBackgroundIntent: ForegroundContinuableIntent {}
|
@ -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>
|
||||||
@ -34,9 +47,9 @@
|
|||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian take photo or video for your post.</string>
|
<string>Grant access to Camera will allow Solian take photo or video for your post.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian record audio for your post.</string>
|
<string>Grant access to Microphone will allow Solian record audio for your post.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</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>
|
||||||
|
55
ios/Runner/NotifyDelegate.swift
Normal file
55
ios/Runner/NotifyDelegate.swift
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// NotifyDelegate.swift
|
||||||
|
// Runner
|
||||||
|
//
|
||||||
|
// Created by LittleSheep on 2024/12/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import home_widget
|
||||||
|
import Alamofire
|
||||||
|
|
||||||
|
class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate {
|
||||||
|
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
|
||||||
|
if let textResponse = response as? UNTextInputNotificationResponse {
|
||||||
|
let content = response.notification.request.content
|
||||||
|
guard let metadata = content.userInfo["metadata"] as? [AnyHashable: Any] else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let channelId = metadata["channel_id"] as? Int
|
||||||
|
let eventId = metadata["event_id"] as? Int
|
||||||
|
|
||||||
|
let replyToken = metadata["reply_token"] as? String
|
||||||
|
|
||||||
|
if (channelId == nil || eventId == nil || replyToken == nil) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let serverUrl = "https://api.sn.solsynth.dev"
|
||||||
|
let url = "\(serverUrl)/cgi/im/quick/\(channelId!)/reply/\(eventId!)?replyToken=\(replyToken!)"
|
||||||
|
|
||||||
|
let parameters: [String: Any] = [
|
||||||
|
"type": "messages.new",
|
||||||
|
"body": [
|
||||||
|
"text": textResponse.userText,
|
||||||
|
"algorithm": "plain"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
AF.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
|
||||||
|
.validate()
|
||||||
|
.responseString { response in
|
||||||
|
switch response.result {
|
||||||
|
case .success(_):
|
||||||
|
break
|
||||||
|
case .failure(let error):
|
||||||
|
print("Failed to send chat reply message: \(error)")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completionHandler()
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
import UserNotifications
|
import UserNotifications
|
||||||
import Intents
|
import Intents
|
||||||
|
import Kingfisher
|
||||||
|
import UniformTypeIdentifiers
|
||||||
|
|
||||||
enum ParseNotificationPayloadError: Error {
|
enum ParseNotificationPayloadError: Error {
|
||||||
case missingMetadata(String)
|
case missingMetadata(String)
|
||||||
@ -18,58 +20,6 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
private var contentHandler: ((UNNotificationContent) -> Void)?
|
private var contentHandler: ((UNNotificationContent) -> Void)?
|
||||||
private var bestAttemptContent: UNMutableNotificationContent?
|
private var bestAttemptContent: UNMutableNotificationContent?
|
||||||
|
|
||||||
private func fetchAvatarImage(from url: String, completion: @escaping (INImage?) -> Void) {
|
|
||||||
guard let imageURL = URL(string: url) else {
|
|
||||||
completion(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define a cache location based on the URL hash
|
|
||||||
let cacheFileName = imageURL.lastPathComponent
|
|
||||||
let tempDirectory = FileManager.default.temporaryDirectory
|
|
||||||
let cachedFileUrl = tempDirectory.appendingPathComponent(cacheFileName)
|
|
||||||
|
|
||||||
// Check if the image is already cached
|
|
||||||
if FileManager.default.fileExists(atPath: cachedFileUrl.path) {
|
|
||||||
do {
|
|
||||||
let data = try Data(contentsOf: cachedFileUrl)
|
|
||||||
let cachedImage = INImage(imageData: data) // No optional binding here
|
|
||||||
completion(cachedImage)
|
|
||||||
return
|
|
||||||
} catch {
|
|
||||||
print("Failed to load cached avatar image: \(error.localizedDescription)")
|
|
||||||
try? FileManager.default.removeItem(at: cachedFileUrl) // Clear corrupted cache
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Download the image if not cached
|
|
||||||
let session = URLSession(configuration: .default)
|
|
||||||
session.downloadTask(with: imageURL) { localUrl, response, error in
|
|
||||||
if let error = error {
|
|
||||||
print("Failed to fetch avatar image: \(error.localizedDescription)")
|
|
||||||
completion(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let localUrl = localUrl, let data = try? Data(contentsOf: localUrl) else {
|
|
||||||
print("Failed to fetch data for avatar image.")
|
|
||||||
completion(nil)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
// Cache the downloaded file
|
|
||||||
try FileManager.default.moveItem(at: localUrl, to: cachedFileUrl)
|
|
||||||
} catch {
|
|
||||||
print("Failed to cache avatar image: \(error.localizedDescription)")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create INImage from the downloaded data
|
|
||||||
let inImage = INImage(imageData: data) // Create directly
|
|
||||||
completion(inImage)
|
|
||||||
}.resume()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didReceive(
|
override func didReceive(
|
||||||
_ request: UNNotificationRequest,
|
_ request: UNNotificationRequest,
|
||||||
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
|
||||||
@ -112,16 +62,39 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
throw ParseNotificationPayloadError.missingAvatarUrl("The notification has no avatar.")
|
throw ParseNotificationPayloadError.missingAvatarUrl("The notification has no avatar.")
|
||||||
}
|
}
|
||||||
|
|
||||||
let avatarUrl = getAttachmentUrl(for: avatarIdentifier)
|
let replyableMessageCategory = UNNotificationCategory(
|
||||||
fetchAvatarImage(from: avatarUrl) { [weak self] inImage in
|
identifier: content.categoryIdentifier,
|
||||||
guard let self = self else { return }
|
actions: [
|
||||||
|
UNTextInputNotificationAction(
|
||||||
|
identifier: "reply_action",
|
||||||
|
title: "Reply",
|
||||||
|
options: []
|
||||||
|
),
|
||||||
|
],
|
||||||
|
intentIdentifiers: [],
|
||||||
|
options: []
|
||||||
|
)
|
||||||
|
|
||||||
let handle = INPersonHandle(value: "\(metadata["user_id"] ?? "")", type: .unknown)
|
UNUserNotificationCenter.current().setNotificationCategories([replyableMessageCategory])
|
||||||
|
content.categoryIdentifier = replyableMessageCategory.identifier
|
||||||
|
|
||||||
|
let metadataCopy = metadata as? [String: String] ?? [:]
|
||||||
|
let avatarUrl = getAttachmentUrl(for: avatarIdentifier)
|
||||||
|
KingfisherManager.shared.retrieveImage(with: URL(string: avatarUrl)!, completionHandler: { result in
|
||||||
|
var image: Data?
|
||||||
|
switch result {
|
||||||
|
case .success(let value):
|
||||||
|
image = value.image.pngData()
|
||||||
|
case .failure(let error):
|
||||||
|
print("Unable to get avatar url: \(error)")
|
||||||
|
}
|
||||||
|
|
||||||
|
let handle = INPersonHandle(value: "\(metadataCopy["user_id"] ?? "")", type: .unknown)
|
||||||
let sender = INPerson(
|
let sender = INPerson(
|
||||||
personHandle: handle,
|
personHandle: handle,
|
||||||
nameComponents: nil,
|
nameComponents: nil,
|
||||||
displayName: content.title,
|
displayName: content.title,
|
||||||
image: inImage,
|
image: image == nil ? nil : INImage(imageData: image!),
|
||||||
contactIdentifier: nil,
|
contactIdentifier: nil,
|
||||||
customIdentifier: nil
|
customIdentifier: nil
|
||||||
)
|
)
|
||||||
@ -132,12 +105,12 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
let updatedContent = try? request.content.updating(from: intent)
|
let updatedContent = try? request.content.updating(from: intent)
|
||||||
self.contentHandler?(updatedContent ?? content)
|
self.contentHandler?(updatedContent ?? content)
|
||||||
} else {
|
} else {
|
||||||
let intent = self.createMessageIntent(with: sender, metadata: metadata, body: content.body)
|
let intent = self.createMessageIntent(with: sender, metadata: metadataCopy, body: content.body)
|
||||||
self.donateInteraction(for: intent)
|
self.donateInteraction(for: intent)
|
||||||
let updatedContent = try? request.content.updating(from: intent)
|
let updatedContent = try? request.content.updating(from: intent)
|
||||||
self.contentHandler?(updatedContent ?? content)
|
self.contentHandler?(updatedContent ?? content)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private func handleDefaultNotification(content: UNMutableNotificationContent) throws {
|
private func handleDefaultNotification(content: UNMutableNotificationContent) throws {
|
||||||
@ -146,15 +119,15 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let imageIdentifier = metadata["image"] as? String {
|
if let imageIdentifier = metadata["image"] as? String {
|
||||||
attachMedia(to: content, withIdentifier: imageIdentifier)
|
attachMedia(to: content, withIdentifier: imageIdentifier, fileType: UTType.jpeg, doScaleDown: true)
|
||||||
} else if let avatarIdentifier = metadata["avatar"] as? String {
|
} else if let avatarIdentifier = metadata["avatar"] as? String {
|
||||||
attachMedia(to: content, withIdentifier: avatarIdentifier)
|
attachMedia(to: content, withIdentifier: avatarIdentifier, fileType: UTType.jpeg, doScaleDown: true)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
contentHandler?(content)
|
contentHandler?(content)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func attachMedia(to content: UNMutableNotificationContent, withIdentifier identifier: String) {
|
private func attachMedia(to content: UNMutableNotificationContent, withIdentifier identifier: String, fileType type: UTType?, doScaleDown scaleDown: Bool = false) {
|
||||||
let attachmentUrl = getAttachmentUrl(for: identifier)
|
let attachmentUrl = getAttachmentUrl(for: identifier)
|
||||||
|
|
||||||
guard let remoteUrl = URL(string: attachmentUrl) else {
|
guard let remoteUrl = URL(string: attachmentUrl) else {
|
||||||
@ -162,49 +135,62 @@ class NotificationService: UNNotificationServiceExtension {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Define a cache location based on the identifier
|
let targetSize = 800
|
||||||
|
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: targetSize, height: targetSize), mode: .aspectFit)
|
||||||
|
|
||||||
|
KingfisherManager.shared.retrieveImage(with: remoteUrl, options: scaleDown ? [
|
||||||
|
.processor(scaleProcessor)
|
||||||
|
] : nil) { [weak self] result in
|
||||||
|
guard let self = self else { return }
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success(let retrievalResult):
|
||||||
|
// The image is either retrieved from cache or downloaded
|
||||||
let tempDirectory = FileManager.default.temporaryDirectory
|
let tempDirectory = FileManager.default.temporaryDirectory
|
||||||
let cachedFileUrl = tempDirectory.appendingPathComponent(identifier)
|
let cachedFileUrl = tempDirectory.appendingPathComponent(identifier)
|
||||||
|
|
||||||
if FileManager.default.fileExists(atPath: cachedFileUrl.path) {
|
|
||||||
// Use cached file
|
|
||||||
attachLocalMedia(to: content, from: cachedFileUrl, withIdentifier: identifier)
|
|
||||||
} else {
|
|
||||||
// Download and cache the file
|
|
||||||
let session = URLSession(configuration: .default)
|
|
||||||
session.downloadTask(with: remoteUrl) { [weak content] localUrl, response, error in
|
|
||||||
guard let content = content else { return }
|
|
||||||
|
|
||||||
if let error = error {
|
|
||||||
print("Failed to download media: \(error.localizedDescription)")
|
|
||||||
self.contentHandler?(content)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let localUrl = localUrl else {
|
|
||||||
print("No local file URL after download")
|
|
||||||
self.contentHandler?(content)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Move the downloaded file to the cache
|
// Write the image data to a temporary file for UNNotificationAttachment
|
||||||
try FileManager.default.moveItem(at: localUrl, to: cachedFileUrl)
|
try retrievalResult.image.pngData()?.write(to: cachedFileUrl)
|
||||||
self.attachLocalMedia(to: content, from: cachedFileUrl, withIdentifier: identifier)
|
self.attachLocalMedia(to: content, fileType: type?.identifier, from: cachedFileUrl, withIdentifier: identifier)
|
||||||
} catch {
|
} catch {
|
||||||
print("Failed to cache media file: \(error.localizedDescription)")
|
print("Failed to write media to temporary file: \(error.localizedDescription)")
|
||||||
|
self.contentHandler?(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
case .failure(let error):
|
||||||
|
print("Failed to retrieve image: \(error.localizedDescription)")
|
||||||
self.contentHandler?(content)
|
self.contentHandler?(content)
|
||||||
}
|
}
|
||||||
}.resume()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attachLocalMedia(to content: UNMutableNotificationContent, from localUrl: URL, withIdentifier identifier: String) {
|
private func attachLocalMedia(to content: UNMutableNotificationContent, fileType type: String?, from localUrl: URL, withIdentifier identifier: String) {
|
||||||
if let attachment = try? UNNotificationAttachment(identifier: identifier, url: localUrl) {
|
do {
|
||||||
|
let attachment = try UNNotificationAttachment(identifier: identifier, url: localUrl, options: [
|
||||||
|
UNNotificationAttachmentOptionsTypeHintKey: type as Any,
|
||||||
|
UNNotificationAttachmentOptionsThumbnailHiddenKey: 0,
|
||||||
|
])
|
||||||
content.attachments = [attachment]
|
content.attachments = [attachment]
|
||||||
} else {
|
} catch let error as NSError {
|
||||||
print("Failed to create attachment from cached file: \(localUrl.path)")
|
// Log detailed error information
|
||||||
|
print("Failed to create attachment from file at \(localUrl.path)")
|
||||||
|
print("Error: \(error.localizedDescription)")
|
||||||
|
|
||||||
|
// Check specific error codes if needed
|
||||||
|
if error.domain == NSCocoaErrorDomain {
|
||||||
|
switch error.code {
|
||||||
|
case NSFileReadNoSuchFileError:
|
||||||
|
print("File does not exist at \(localUrl.path)")
|
||||||
|
case NSFileReadNoPermissionError:
|
||||||
|
print("No permission to read file at \(localUrl.path)")
|
||||||
|
default:
|
||||||
|
print("Unhandled file error: \(error.code)")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call content handler regardless of success or failure
|
||||||
self.contentHandler?(content)
|
self.contentHandler?(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,21 +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")
|
let checkInRaw = prefs?.string(forKey: "pas_check_in_record")
|
||||||
var user: SolarUser?
|
|
||||||
if let userRaw = userRaw {
|
|
||||||
user = try! jsonDecoder.decode(SolarUser.self, from: userRaw.data(using: .utf8)!)
|
|
||||||
}
|
|
||||||
|
|
||||||
let checkInRaw = prefs?.string(forKey: "today_check_in")
|
|
||||||
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(
|
||||||
date: Date(),
|
date: Date(),
|
||||||
user: user,
|
|
||||||
checkIn: checkIn
|
checkIn: checkIn
|
||||||
)
|
)
|
||||||
completion(entry)
|
completion(entry)
|
||||||
@ -53,14 +49,13 @@ struct CheckInProvider: TimelineProvider {
|
|||||||
|
|
||||||
struct CheckInEntry: TimelineEntry {
|
struct CheckInEntry: TimelineEntry {
|
||||||
let date: Date
|
let date: Date
|
||||||
let user: SolarUser?
|
|
||||||
let checkIn: SolarCheckInRecord?
|
let checkIn: SolarCheckInRecord?
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckInWidgetEntryView : View {
|
struct CheckInWidgetEntryView : View {
|
||||||
var entry: CheckInProvider.Entry
|
var entry: CheckInProvider.Entry
|
||||||
|
|
||||||
private let resultTierSymbols: [String] = ["大凶", "凶", "中平", "大吉", "吉"]
|
private let resultTierSymbols: [String] = ["大凶", "凶", "中平", "吉", "大吉"]
|
||||||
|
|
||||||
func checkIn() -> Void {}
|
func checkIn() -> Void {}
|
||||||
|
|
||||||
@ -105,7 +100,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"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,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)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
246
ios/SolarWidget/RandomPostWidget.swift
Normal file
246
ios/SolarWidget/RandomPostWidget.swift
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
//
|
||||||
|
// 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
|
||||||
|
let scaleProcessor = ResizingImageProcessor(referenceSize: CGSize(width: size, height: size), mode: .aspectFill)
|
||||||
|
|
||||||
|
KFImage.url(URL(string: avatarUrl))
|
||||||
|
.resizable()
|
||||||
|
.setProcessor(scaleProcessor)
|
||||||
|
.fade(duration: 0.25)
|
||||||
|
.placeholder{
|
||||||
|
ProgressView()
|
||||||
|
.progressViewStyle(CircularProgressViewStyle())
|
||||||
|
}
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
.frame(width: size, height: size)
|
||||||
|
.cornerRadius(size / 2)
|
||||||
|
|
||||||
|
.frame(width: size, height: size, alignment: .center)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(randomPost.publisher.nick)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
.opacity(0.9)
|
||||||
|
|
||||||
|
Text("@\(randomPost.publisher.name)")
|
||||||
|
.font(.system(size: 13, design: .monospaced))
|
||||||
|
.opacity(0.9)
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
}.frame(maxWidth: .infinity).padding(.bottom, 12)
|
||||||
|
|
||||||
|
if randomPost.body.title != nil || randomPost.body.description != nil {
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
if let title = randomPost.body.title {
|
||||||
|
Text(title)
|
||||||
|
.font(.system(size: 17))
|
||||||
|
}
|
||||||
|
if let description = randomPost.body.description {
|
||||||
|
Text(description)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
}
|
||||||
|
}.padding(.bottom, 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let content = randomPost.body.content {
|
||||||
|
if (randomPost.body.title == nil && randomPost.body.description == nil) || entry.family == .systemLarge || entry.family == .systemExtraLarge {
|
||||||
|
Text(
|
||||||
|
(entry.family == .systemLarge || entry.family == .systemExtraLarge) ? content : content.replacingOccurrences(of: "\n", with: " ")
|
||||||
|
)
|
||||||
|
.font(.system(size: 15))
|
||||||
|
} else {
|
||||||
|
Text("\(Image(systemName: "plus")) total \(content.count) characters")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let attachment = randomPost.body.attachments {
|
||||||
|
if attachment.count == 1 {
|
||||||
|
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachment")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 2)
|
||||||
|
} else if attachment.count > 1 {
|
||||||
|
Text("\(Image(systemName: "document.fill")) \(attachment.count) attachments")
|
||||||
|
.font(.system(size: 11, design: .monospaced))
|
||||||
|
.opacity(0.75)
|
||||||
|
.padding(.top, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
Text(randomPost.publishedAt!, format: .dateTime)
|
||||||
|
.font(.system(size: 11))
|
||||||
|
Text("#\(randomPost.id)")
|
||||||
|
.font(.system(size: 9))
|
||||||
|
}.widgetURL(URL(string: "https://sn.solsynth.dev/posts/\(randomPost.id)"))
|
||||||
|
} else {
|
||||||
|
VStack(alignment: .center) {
|
||||||
|
Text("No Recommendations").font(.system(size: 19, weight: .bold))
|
||||||
|
Text("Open the app to load some random post")
|
||||||
|
.font(.system(size: 15))
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}.frame(alignment: .center)
|
||||||
|
}
|
||||||
|
}.padding(8).frame(maxWidth: .infinity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RandomPostWidget: Widget {
|
||||||
|
let kind: String = "SolarRandomPostWidget"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: RandomPostProvider()) { entry in
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
RandomPostWidgetEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
} else {
|
||||||
|
RandomPostWidgetEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configurationDisplayName("Random Post")
|
||||||
|
.description("View the random post on the Solar Network")
|
||||||
|
.supportedFamilies([.systemSmall, .systemMedium, .systemLarge, .systemExtraLarge])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
RandomPostWidget()
|
||||||
|
} timeline: {
|
||||||
|
RandomPostEntry(date: Date.now, user: nil, randomPost: nil, family: .systemLarge)
|
||||||
|
RandomPostEntry(
|
||||||
|
date: .now,
|
||||||
|
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
||||||
|
randomPost: SolarPost(
|
||||||
|
id: 1,
|
||||||
|
body: SolarPostBody(
|
||||||
|
content: "Hello, World",
|
||||||
|
title: nil,
|
||||||
|
description: nil,
|
||||||
|
attachments: ["zb2hiUEmYcnpHfVN"]
|
||||||
|
),
|
||||||
|
publisher: SolarPublisher(
|
||||||
|
id: 1,
|
||||||
|
name: "demo",
|
||||||
|
nick: "Deemo",
|
||||||
|
description: nil,
|
||||||
|
avatar: "IZxCFkJUPKRijFCx",
|
||||||
|
banner: nil,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now
|
||||||
|
),
|
||||||
|
publisherId: 1,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now,
|
||||||
|
editedAt: nil,
|
||||||
|
publishedAt: .now
|
||||||
|
),
|
||||||
|
family: .systemSmall
|
||||||
|
)
|
||||||
|
RandomPostEntry(
|
||||||
|
date: .now,
|
||||||
|
user: SolarUser(id: 1, name: "demo", nick: "Deemo"),
|
||||||
|
randomPost: SolarPost(
|
||||||
|
id: 1,
|
||||||
|
body: SolarPostBody(
|
||||||
|
content: "Hello, World\nOh wow",
|
||||||
|
title: "Title",
|
||||||
|
description: "Description",
|
||||||
|
attachments: ["zb2hiUEmYcnpHfVN"]
|
||||||
|
),
|
||||||
|
publisher: SolarPublisher(
|
||||||
|
id: 1,
|
||||||
|
name: "demo",
|
||||||
|
nick: "Deemo",
|
||||||
|
description: nil,
|
||||||
|
avatar: "IZxCFkJUPKRijFCx",
|
||||||
|
banner: nil,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now
|
||||||
|
),
|
||||||
|
publisherId: 1,
|
||||||
|
createdAt: .now,
|
||||||
|
updatedAt: .now,
|
||||||
|
editedAt: nil,
|
||||||
|
publishedAt: .now
|
||||||
|
),
|
||||||
|
family: .systemLarge
|
||||||
|
)
|
||||||
|
}
|
@ -12,6 +12,6 @@ import SwiftUI
|
|||||||
struct SolarWidgetBundle: WidgetBundle {
|
struct SolarWidgetBundle: WidgetBundle {
|
||||||
var body: some Widget {
|
var body: some Widget {
|
||||||
CheckInWidget()
|
CheckInWidget()
|
||||||
FeaturedPostWidget()
|
RandomPostWidget()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
116
lib/main.dart
116
lib/main.dart
@ -1,8 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'dart:developer';
|
||||||
import 'dart:io';
|
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';
|
||||||
@ -11,13 +13,16 @@ 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';
|
||||||
import 'package:surface/providers/chat_call.dart';
|
import 'package:surface/providers/chat_call.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/link_preview.dart';
|
import 'package:surface/providers/link_preview.dart';
|
||||||
import 'package:surface/providers/navigation.dart';
|
import 'package:surface/providers/navigation.dart';
|
||||||
import 'package:surface/providers/notification.dart';
|
import 'package:surface/providers/notification.dart';
|
||||||
@ -36,7 +41,26 @@ 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:in_app_review/in_app_review.dart';
|
||||||
|
|
||||||
|
@pragma('vm:entry-point')
|
||||||
|
void appBackgroundDispatcher() {
|
||||||
|
Workmanager().executeTask((task, inputData) async {
|
||||||
|
log("[WorkManager] 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 +88,22 @@ void main() async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
|
Workmanager().initialize(
|
||||||
|
appBackgroundDispatcher,
|
||||||
|
isInDebugMode: kDebugMode,
|
||||||
|
);
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,15 +126,18 @@ class SolianApp extends StatelessWidget {
|
|||||||
assetLoader: JsonAssetLoader(),
|
assetLoader: JsonAssetLoader(),
|
||||||
child: MultiProvider(
|
child: MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
// System extensions layer
|
||||||
|
Provider(create: (ctx) => HomeWidgetProvider(ctx)),
|
||||||
|
|
||||||
|
// Preferences layer
|
||||||
|
ChangeNotifierProvider(create: (ctx) => ConfigProvider(ctx)),
|
||||||
|
|
||||||
// Display layer
|
// Display layer
|
||||||
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
ChangeNotifierProvider(create: (_) => ThemeProvider()),
|
||||||
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
ChangeNotifierProvider(create: (ctx) => NavigationProvider()),
|
||||||
|
|
||||||
// System extensions layer
|
|
||||||
Provider(create: (ctx) => HomeWidgetProvider(ctx)),
|
|
||||||
|
|
||||||
// Data layer
|
// Data layer
|
||||||
Provider(create: (_) => SnNetworkProvider()),
|
Provider(create: (ctx) => SnNetworkProvider(ctx)),
|
||||||
Provider(create: (ctx) => UserDirectoryProvider(ctx)),
|
Provider(create: (ctx) => UserDirectoryProvider(ctx)),
|
||||||
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
Provider(create: (ctx) => SnAttachmentProvider(ctx)),
|
||||||
Provider(create: (ctx) => SnPostContentProvider(ctx)),
|
Provider(create: (ctx) => SnPostContentProvider(ctx)),
|
||||||
@ -163,13 +206,63 @@ class _AppSplashScreen extends StatefulWidget {
|
|||||||
class _AppSplashScreenState extends State<_AppSplashScreen> {
|
class _AppSplashScreenState extends State<_AppSplashScreen> {
|
||||||
bool _isReady = false;
|
bool _isReady = false;
|
||||||
|
|
||||||
late StreamSubscription _shareIntentSubscription;
|
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>();
|
||||||
await home.initialize();
|
await home.initialize();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
|
// The Network initialization must be done after the HomeWidget initialization
|
||||||
|
// The Network initialization will save the server url to the HomeWidget
|
||||||
|
// The Network initialization will also save initialize the Config, so it not need to be initialized again
|
||||||
final sn = context.read<SnNetworkProvider>();
|
final sn = context.read<SnNetworkProvider>();
|
||||||
await sn.initializeUserAgent();
|
await sn.initializeUserAgent();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@ -189,10 +282,18 @@ 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();
|
||||||
|
_tryRequestRating();
|
||||||
|
_checkForUpdate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -206,6 +307,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
|
|||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
if (MediaQuery.of(context).platformBrightness == Brightness.dark)
|
||||||
|
Image.asset("assets/icon/icon-dark.png", width: 64, height: 64)
|
||||||
|
else
|
||||||
Image.asset("assets/icon/icon.png", width: 64, height: 64),
|
Image.asset("assets/icon/icon.png", width: 64, height: 64),
|
||||||
const Gap(6),
|
const Gap(6),
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
|
@ -125,10 +125,8 @@ class ChatChannelProvider extends ChangeNotifier {
|
|||||||
final channelBox = await Hive.openBox<SnChatMessage>(
|
final channelBox = await Hive.openBox<SnChatMessage>(
|
||||||
'${ChatMessageController.kChatMessageBoxPrefix}${channel.id}',
|
'${ChatMessageController.kChatMessageBoxPrefix}${channel.id}',
|
||||||
);
|
);
|
||||||
final lastMessage = channelBox.isNotEmpty
|
final lastMessage =
|
||||||
? channelBox.values
|
channelBox.isNotEmpty ? channelBox.values.reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b) : null;
|
||||||
.reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b)
|
|
||||||
: null;
|
|
||||||
if (lastMessage != null) result.add(lastMessage);
|
if (lastMessage != null) result.add(lastMessage);
|
||||||
channelBox.close();
|
channelBox.close();
|
||||||
}
|
}
|
||||||
|
51
lib/providers/config.dart
Normal file
51
lib/providers/config.dart
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:surface/providers/widget.dart';
|
||||||
|
|
||||||
|
const kAtkStoreKey = 'nex_user_atk';
|
||||||
|
const kRtkStoreKey = 'nex_user_rtk';
|
||||||
|
|
||||||
|
const kNetworkServerDefault = 'https://api.sn.solsynth.dev';
|
||||||
|
const kNetworkServerStoreKey = 'app_server_url';
|
||||||
|
|
||||||
|
const Map<String, FilterQuality> kImageQualityLevel = {
|
||||||
|
'settingsImageQualityLowest': FilterQuality.none,
|
||||||
|
'settingsImageQualityLow': FilterQuality.low,
|
||||||
|
'settingsImageQualityMedium': FilterQuality.medium,
|
||||||
|
'settingsImageQualityHigh': FilterQuality.high,
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConfigProvider extends ChangeNotifier {
|
||||||
|
late final SharedPreferences prefs;
|
||||||
|
|
||||||
|
late final HomeWidgetProvider _home;
|
||||||
|
|
||||||
|
ConfigProvider(BuildContext context) {
|
||||||
|
_home = context.read<HomeWidgetProvider>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> initialize() async {
|
||||||
|
prefs = await SharedPreferences.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterQuality get imageQuality {
|
||||||
|
return kImageQualityLevel.values.elementAtOrNull(prefs.getInt('app_image_quality') ?? 3) ?? FilterQuality.high;
|
||||||
|
}
|
||||||
|
|
||||||
|
String get serverUrl {
|
||||||
|
return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
set serverUrl(String url) {
|
||||||
|
prefs.setString(kNetworkServerStoreKey, url);
|
||||||
|
_home.saveWidgetData("nex_server_url", url);
|
||||||
|
}
|
||||||
|
|
||||||
|
String? updatableVersion;
|
||||||
|
|
||||||
|
void setUpdate(String newVersion) {
|
||||||
|
updatableVersion = newVersion;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
@ -6,30 +6,34 @@ import 'dart:io';
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio_smart_retry/dio_smart_retry.dart';
|
import 'package:dio_smart_retry/dio_smart_retry.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
import 'package:device_info_plus/device_info_plus.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
|
import 'package:surface/providers/widget.dart';
|
||||||
import 'package:synchronized/synchronized.dart';
|
import 'package:synchronized/synchronized.dart';
|
||||||
|
|
||||||
const kAtkStoreKey = 'nex_user_atk';
|
|
||||||
const kRtkStoreKey = 'nex_user_rtk';
|
|
||||||
|
|
||||||
const kNetworkServerDefault = 'https://api.sn.solsynth.dev';
|
|
||||||
const kNetworkServerStoreKey = 'app_server_url';
|
|
||||||
|
|
||||||
const kNetworkServerDirectory = [
|
const kNetworkServerDirectory = [
|
||||||
('Solar Network', 'https://api.sn.solsynth.dev'),
|
('Solar Network', 'https://api.sn.solsynth.dev'),
|
||||||
('Local', 'http://localhost:8001'),
|
('Local', 'http://localhost:8001'),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
Completer<String?>? _refreshCompleter;
|
||||||
|
|
||||||
class SnNetworkProvider {
|
class SnNetworkProvider {
|
||||||
late final Dio client;
|
late final Dio client;
|
||||||
|
|
||||||
late final SharedPreferences _prefs;
|
late final SharedPreferences _prefs;
|
||||||
|
late final ConfigProvider _config;
|
||||||
|
late final HomeWidgetProvider _home;
|
||||||
|
|
||||||
String? _userAgent;
|
String? _userAgent;
|
||||||
|
|
||||||
SnNetworkProvider() {
|
SnNetworkProvider(BuildContext context) {
|
||||||
|
_home = context.read<HomeWidgetProvider>();
|
||||||
|
|
||||||
client = Dio();
|
client = Dio();
|
||||||
|
|
||||||
client.interceptors.add(RetryInterceptor(
|
client.interceptors.add(RetryInterceptor(
|
||||||
@ -60,13 +64,52 @@ class SnNetworkProvider {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
_config = context.read<ConfigProvider>();
|
||||||
_prefs = prefs;
|
_config.initialize().then((_) {
|
||||||
client.options.baseUrl = _prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
_prefs = _config.prefs;
|
||||||
|
client.options.baseUrl = _config.serverUrl;
|
||||||
|
if (!context.mounted) return;
|
||||||
|
_home.saveWidgetData("nex_server_url", client.options.baseUrl);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
|
final atk = await _getFreshAtk(client, prefs.getString(kAtkStoreKey), prefs.getString(kRtkStoreKey), (atk, rtk) {
|
||||||
|
prefs.setString(kAtkStoreKey, atk);
|
||||||
|
prefs.setString(kRtkStoreKey, rtk);
|
||||||
|
});
|
||||||
|
if (atk != null) {
|
||||||
|
options.headers['Authorization'] = 'Bearer $atk';
|
||||||
|
}
|
||||||
|
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;
|
||||||
@ -92,14 +135,22 @@ 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();
|
||||||
|
|
||||||
Completer<String?>? _refreshCompleter;
|
|
||||||
|
|
||||||
Future<String?> getFreshAtk() async {
|
Future<String?> getFreshAtk() async {
|
||||||
|
return await _getFreshAtk(client, _prefs.getString(kAtkStoreKey), _prefs.getString(kRtkStoreKey), (atk, rtk) {
|
||||||
|
setTokenPair(atk, rtk);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String?> _getFreshAtk(Dio client, String? atk, String? rtk, Function(String atk, String rtk)? onRefresh) async {
|
||||||
if (_refreshCompleter != null) {
|
if (_refreshCompleter != null) {
|
||||||
return await _refreshCompleter!.future;
|
return await _refreshCompleter!.future;
|
||||||
} else {
|
} else {
|
||||||
@ -107,7 +158,6 @@ class SnNetworkProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var atk = _prefs.getString(kAtkStoreKey);
|
|
||||||
if (atk != null) {
|
if (atk != null) {
|
||||||
final atkParts = atk.split('.');
|
final atkParts = atk.split('.');
|
||||||
if (atkParts.length != 3) {
|
if (atkParts.length != 3) {
|
||||||
@ -133,7 +183,13 @@ class SnNetworkProvider {
|
|||||||
final exp = jsonDecode(payload)['exp'];
|
final exp = jsonDecode(payload)['exp'];
|
||||||
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
if (exp <= DateTime.now().millisecondsSinceEpoch ~/ 1000) {
|
||||||
log('Access token need refresh, doing it at ${DateTime.now()}');
|
log('Access token need refresh, doing it at ${DateTime.now()}');
|
||||||
atk = await refreshToken();
|
final result = await _refreshToken(client.options.baseUrl, rtk);
|
||||||
|
if (result == null) {
|
||||||
|
atk = null;
|
||||||
|
} else {
|
||||||
|
atk = result.$1;
|
||||||
|
onRefresh?.call(atk, result.$2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (atk != null) {
|
if (atk != null) {
|
||||||
@ -171,24 +227,32 @@ class SnNetworkProvider {
|
|||||||
|
|
||||||
Future<String?> refreshToken() async {
|
Future<String?> refreshToken() async {
|
||||||
final rtk = _prefs.getString(kRtkStoreKey);
|
final rtk = _prefs.getString(kRtkStoreKey);
|
||||||
|
final result = await _refreshToken(client.options.baseUrl, rtk);
|
||||||
|
if (result == null) return null;
|
||||||
|
_prefs.setString(kAtkStoreKey, result.$1);
|
||||||
|
_prefs.setString(kRtkStoreKey, result.$2);
|
||||||
|
return result.$1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<(String, String)?> _refreshToken(String baseUrl, String? rtk) async {
|
||||||
if (rtk == null) return null;
|
if (rtk == null) return null;
|
||||||
|
|
||||||
final dio = Dio();
|
final dio = Dio();
|
||||||
dio.options.baseUrl = client.options.baseUrl;
|
dio.options.baseUrl = baseUrl;
|
||||||
|
|
||||||
final resp = await dio.post('/cgi/id/auth/token', data: {
|
final resp = await dio.post('/cgi/id/auth/token', data: {
|
||||||
'grant_type': 'refresh_token',
|
'grant_type': 'refresh_token',
|
||||||
'refresh_token': rtk,
|
'refresh_token': rtk,
|
||||||
});
|
});
|
||||||
|
|
||||||
final atk = resp.data['access_token'];
|
final String atk = resp.data['access_token'];
|
||||||
final nRtk = resp.data['refresh_token'];
|
final String nRtk = resp.data['refresh_token'];
|
||||||
setTokenPair(atk, nRtk);
|
|
||||||
|
|
||||||
return atk;
|
return (atk, nRtk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBaseUrl(String url) {
|
void setBaseUrl(String url) {
|
||||||
|
_config.serverUrl = url;
|
||||||
client.options.baseUrl = url;
|
client.options.baseUrl = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:home_widget/home_widget.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/widget.dart';
|
import 'package:surface/providers/widget.dart';
|
||||||
import 'package:surface/types/account.dart';
|
import 'package:surface/types/account.dart';
|
||||||
@ -14,10 +15,12 @@ class UserProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
late final SnNetworkProvider _sn;
|
late final SnNetworkProvider _sn;
|
||||||
late final HomeWidgetProvider _home;
|
late final HomeWidgetProvider _home;
|
||||||
|
late final ConfigProvider _config;
|
||||||
|
|
||||||
UserProvider(BuildContext context) {
|
UserProvider(BuildContext context) {
|
||||||
_sn = context.read<SnNetworkProvider>();
|
_sn = context.read<SnNetworkProvider>();
|
||||||
_home = context.read<HomeWidgetProvider>();
|
_home = context.read<HomeWidgetProvider>();
|
||||||
|
_config = context.read<ConfigProvider>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> get atk async {
|
Future<String?> get atk async {
|
||||||
@ -26,8 +29,7 @@ class UserProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initialize() async {
|
Future<void> initialize() async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final value = _config.prefs.getString(kAtkStoreKey);
|
||||||
final value = prefs.getString(kAtkStoreKey);
|
|
||||||
isAuthorized = value != null;
|
isAuthorized = value != null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
refreshUser().then((value) {
|
refreshUser().then((value) {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
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);
|
||||||
@ -24,15 +27,34 @@ 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,
|
||||||
iOSName: widget,
|
iOSName: widget,
|
||||||
androidName: "com.solsynth.solian.$widget",
|
);
|
||||||
qualifiedAndroidName: "group.solsynth.solian.$widget",
|
}
|
||||||
|
} else if (Platform.isAndroid) {
|
||||||
|
const widgets = ["RandomPostWidget", "CheckInWidget"];
|
||||||
|
for (final widget in widgets) {
|
||||||
|
await HomeWidget.updateWidget(
|
||||||
|
androidName: "${widget}Receiver",
|
||||||
|
qualifiedAndroidName: "dev.solsynth.solian.widgets.${widget}Receiver",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -158,7 +158,7 @@ class _ChatRoomScreenState extends State<ChatRoomScreen> {
|
|||||||
GoRouter.of(context).pushNamed(
|
GoRouter.of(context).pushNamed(
|
||||||
'chatCallRoom',
|
'chatCallRoom',
|
||||||
pathParameters: {
|
pathParameters: {
|
||||||
'scope': _channel!.realm!.alias,
|
'scope': _channel!.realm?.alias ?? 'global',
|
||||||
'alias': _channel!.alias,
|
'alias': _channel!.alias,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -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';
|
||||||
@ -76,7 +80,8 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: constraints.maxWidth > 640 ? MainAxisAlignment.center : MainAxisAlignment.start,
|
mainAxisAlignment: constraints.maxWidth > 640 ? 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,
|
||||||
@ -100,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});
|
||||||
|
|
||||||
@ -109,7 +160,9 @@ class _HomeDashSpecialDayWidget extends StatelessWidget {
|
|||||||
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 && birthday.day == today.day && birthday.month == today.month;
|
final isBirthday = birthday != null && birthday.day == today.day && birthday.month == today.month;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
if (isBirthday)
|
if (isBirthday)
|
||||||
Card(
|
Card(
|
||||||
@ -118,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']),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -145,7 +212,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);
|
||||||
}
|
}
|
||||||
@ -158,7 +225,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);
|
||||||
@ -429,7 +496,7 @@ class _HomeDashRecommendationPostWidgetState extends State<_HomeDashRecommendati
|
|||||||
final pt = context.read<SnPostContentProvider>();
|
final pt = context.read<SnPostContentProvider>();
|
||||||
final home = context.read<HomeWidgetProvider>();
|
final home = context.read<HomeWidgetProvider>();
|
||||||
_posts = await pt.listRecommendations();
|
_posts = await pt.listRecommendations();
|
||||||
home.saveWidgetData('post_featured', _posts!.map((e) => e.toJson()).toList());
|
home.saveWidgetData('post_featured', _posts!.first.toJson());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
context.showErrorDialog(err);
|
context.showErrorDialog(err);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
@ -12,6 +12,7 @@ import 'package:path_provider/path_provider.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.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/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/theme.dart';
|
import 'package:surface/providers/theme.dart';
|
||||||
import 'package:surface/theme.dart';
|
import 'package:surface/theme.dart';
|
||||||
@ -25,7 +26,7 @@ class SettingsScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _SettingsScreenState extends State<SettingsScreen> {
|
class _SettingsScreenState extends State<SettingsScreen> {
|
||||||
SharedPreferences? _prefs;
|
late final SharedPreferences _prefs;
|
||||||
String _docBasepath = '/';
|
String _docBasepath = '/';
|
||||||
|
|
||||||
final TextEditingController _serverUrlController = TextEditingController();
|
final TextEditingController _serverUrlController = TextEditingController();
|
||||||
@ -39,12 +40,9 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
SharedPreferences.getInstance().then((prefs) {
|
final config = context.read<ConfigProvider>();
|
||||||
setState(() {
|
_prefs = config.prefs;
|
||||||
_prefs = prefs;
|
_serverUrlController.text = config.serverUrl;
|
||||||
_serverUrlController.text = prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -60,6 +58,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
spacing: 16,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
@ -78,7 +77,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
if (image == null) return;
|
if (image == null) return;
|
||||||
|
|
||||||
await File(image.path).copy('$_docBasepath/app_background_image');
|
await File(image.path).copy('$_docBasepath/app_background_image');
|
||||||
_prefs?.setBool('has_background_image', true);
|
_prefs.setBool('has_background_image', true);
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
@ -99,21 +98,20 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
File('$_docBasepath/app_background_image').deleteSync();
|
File('$_docBasepath/app_background_image').deleteSync();
|
||||||
_prefs?.remove('has_background_image');
|
_prefs.remove('has_background_image');
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
if (_prefs != null)
|
|
||||||
CheckboxListTile(
|
CheckboxListTile(
|
||||||
title: Text('settingsThemeMaterial3').tr(),
|
title: Text('settingsThemeMaterial3').tr(),
|
||||||
subtitle: Text('settingsThemeMaterial3Description').tr(),
|
subtitle: Text('settingsThemeMaterial3Description').tr(),
|
||||||
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
secondary: const Icon(Symbols.new_releases),
|
secondary: const Icon(Symbols.new_releases),
|
||||||
value: _prefs!.getBool(kMaterialYouToggleStoreKey) ?? false,
|
value: _prefs.getBool(kMaterialYouToggleStoreKey) ?? false,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_prefs!.setBool(
|
_prefs.setBool(
|
||||||
kMaterialYouToggleStoreKey,
|
kMaterialYouToggleStoreKey,
|
||||||
value ?? false,
|
value ?? false,
|
||||||
);
|
);
|
||||||
@ -139,7 +137,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
icon: const Icon(Symbols.save),
|
icon: const Icon(Symbols.save),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
sn.setBaseUrl(_serverUrlController.text);
|
sn.setBaseUrl(_serverUrlController.text);
|
||||||
_prefs?.setString(
|
_prefs.setString(
|
||||||
kNetworkServerStoreKey,
|
kNetworkServerStoreKey,
|
||||||
_serverUrlController.text,
|
_serverUrlController.text,
|
||||||
);
|
);
|
||||||
@ -182,7 +180,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
onChanged: (String? value) {
|
onChanged: (String? value) {
|
||||||
if (value == null) return;
|
if (value == null) return;
|
||||||
_serverUrlController.text = value;
|
_serverUrlController.text = value;
|
||||||
_prefs?.setString(kNetworkServerStoreKey, value);
|
_prefs.setString(kNetworkServerStoreKey, value);
|
||||||
context.showSnackbar('settingsNetworkServerSaved'.tr());
|
context.showSnackbar('settingsNetworkServerSaved'.tr());
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
@ -208,13 +206,56 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_serverUrlController.text = kNetworkServerDefault;
|
_serverUrlController.text = kNetworkServerDefault;
|
||||||
_prefs?.remove(kNetworkServerStoreKey);
|
_prefs.remove(kNetworkServerStoreKey);
|
||||||
context.showSnackbar('settingsNetworkServerSaved'.tr());
|
context.showSnackbar('settingsNetworkServerSaved'.tr());
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text('settingsPerformance').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
||||||
|
ListTile(
|
||||||
|
title: Text('settingsImageQuality').tr(),
|
||||||
|
subtitle: Text('settingsImageQualityDescription').tr(),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
leading: const Icon(Symbols.image),
|
||||||
|
trailing: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<FilterQuality>(
|
||||||
|
value: kImageQualityLevel.values.elementAtOrNull(_prefs.getInt('app_image_quality') ?? 3) ??
|
||||||
|
FilterQuality.high,
|
||||||
|
isExpanded: true,
|
||||||
|
items: kImageQualityLevel.entries
|
||||||
|
.map(
|
||||||
|
(item) => DropdownMenuItem<FilterQuality>(
|
||||||
|
value: item.value,
|
||||||
|
child: Text(item.key).tr().fontSize(14),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
onChanged: (FilterQuality? value) {
|
||||||
|
if (value == null) return;
|
||||||
|
_prefs.setInt('app_image_quality', kImageQualityLevel.values.toList().indexOf(value));
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
buttonStyleData: const ButtonStyleData(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
|
height: 40,
|
||||||
|
width: 160,
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(
|
||||||
|
height: 60,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -231,7 +272,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
].expand((ele) => [ele, const Gap(16)]).toList(),
|
],
|
||||||
).padding(vertical: 20),
|
).padding(vertical: 20),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,16 +1,16 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:cross_file/cross_file.dart';
|
import 'package:cross_file/cross_file.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.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:receive_sharing_intent/receive_sharing_intent.dart';
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
import 'package:surface/controllers/post_write_controller.dart';
|
import 'package:surface/controllers/post_write_controller.dart';
|
||||||
import 'package:surface/screens/post/post_editor.dart';
|
import 'package:surface/screens/post/post_editor.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
|
||||||
|
|
||||||
class AppSharingListener extends StatefulWidget {
|
class AppSharingListener extends StatefulWidget {
|
||||||
final Widget child;
|
final Widget child;
|
||||||
@ -103,9 +103,11 @@ class _AppSharingListenerState extends State<AppSharingListener> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
if(!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
|
||||||
_initialize();
|
_initialize();
|
||||||
_initialHandle();
|
_initialHandle();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
@ -130,7 +130,7 @@ class _ChatCallPrejoinPopupState extends State<ChatCallPrejoinPopup> {
|
|||||||
Text('callCamera').tr(),
|
Text('callCamera').tr(),
|
||||||
Switch(
|
Switch(
|
||||||
value: call.enableVideo,
|
value: call.enableVideo,
|
||||||
onChanged: (value) => call.setEnableAudio(value),
|
onChanged: call.setEnableVideo,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
).padding(bottom: 5),
|
).padding(bottom: 5),
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
@ -458,6 +458,7 @@ class _PostBottomAction extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (showReactions || showComments)
|
if (showReactions || showComments)
|
||||||
Row(
|
Row(
|
||||||
|
spacing: 8,
|
||||||
children: [
|
children: [
|
||||||
if (showReactions)
|
if (showReactions)
|
||||||
InkWell(
|
InkWell(
|
||||||
@ -523,8 +524,7 @@ class _PostBottomAction extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
].expand((ele) => [ele, const Gap(8)]).toList()
|
],
|
||||||
..removeLast(),
|
|
||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: onShare,
|
onTap: onShare,
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
|
|
||||||
|
// Keep this import to make the web image render work
|
||||||
|
import 'package:cached_network_image_platform_interface/cached_network_image_platform_interface.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
|
|
||||||
class UniversalImage extends StatelessWidget {
|
class UniversalImage extends StatelessWidget {
|
||||||
final String url;
|
final String url;
|
||||||
final double? width, height;
|
final double? width, height;
|
||||||
@ -14,6 +17,7 @@ class UniversalImage extends StatelessWidget {
|
|||||||
final bool noProgressIndicator;
|
final bool noProgressIndicator;
|
||||||
final bool noErrorWidget;
|
final bool noErrorWidget;
|
||||||
final double? cacheWidth, cacheHeight;
|
final double? cacheWidth, cacheHeight;
|
||||||
|
final FilterQuality? filterQuality;
|
||||||
|
|
||||||
const UniversalImage(
|
const UniversalImage(
|
||||||
this.url, {
|
this.url, {
|
||||||
@ -25,18 +29,20 @@ class UniversalImage extends StatelessWidget {
|
|||||||
this.noErrorWidget = false,
|
this.noErrorWidget = false,
|
||||||
this.cacheWidth,
|
this.cacheWidth,
|
||||||
this.cacheHeight,
|
this.cacheHeight,
|
||||||
|
this.filterQuality,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
final double? resizeHeight =
|
final double? resizeHeight = cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
||||||
cacheHeight != null ? (cacheHeight! * devicePixelRatio) : null;
|
final double? resizeWidth = cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
||||||
final double? resizeWidth =
|
|
||||||
cacheWidth != null ? (cacheWidth! * devicePixelRatio) : null;
|
|
||||||
|
|
||||||
return Image(
|
return Image(
|
||||||
image: ResizeImage(
|
filterQuality: filterQuality ?? context.read<ConfigProvider>().imageQuality,
|
||||||
|
image: kIsWeb
|
||||||
|
? UniversalImage.provider(url)
|
||||||
|
: ResizeImage(
|
||||||
UniversalImage.provider(url),
|
UniversalImage.provider(url),
|
||||||
width: resizeWidth?.round(),
|
width: resizeWidth?.round(),
|
||||||
height: resizeHeight?.round(),
|
height: resizeHeight?.round(),
|
||||||
@ -47,23 +53,19 @@ class UniversalImage extends StatelessWidget {
|
|||||||
fit: fit,
|
fit: fit,
|
||||||
loadingBuilder: noProgressIndicator
|
loadingBuilder: noProgressIndicator
|
||||||
? null
|
? null
|
||||||
: (BuildContext context, Widget child,
|
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
||||||
ImageChunkEvent? loadingProgress) {
|
|
||||||
if (loadingProgress == null) return child;
|
if (loadingProgress == null) return child;
|
||||||
return Center(
|
return Center(
|
||||||
child: TweenAnimationBuilder(
|
child: TweenAnimationBuilder(
|
||||||
tween: Tween(
|
tween: Tween(
|
||||||
begin: 0,
|
begin: 0,
|
||||||
end: loadingProgress.expectedTotalBytes != null
|
end: loadingProgress.expectedTotalBytes != null
|
||||||
? loadingProgress.cumulativeBytesLoaded /
|
? loadingProgress.cumulativeBytesLoaded / loadingProgress.expectedTotalBytes!
|
||||||
loadingProgress.expectedTotalBytes!
|
|
||||||
: 0,
|
: 0,
|
||||||
),
|
),
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
builder: (context, value, _) => CircularProgressIndicator(
|
builder: (context, value, _) => CircularProgressIndicator(
|
||||||
value: loadingProgress.expectedTotalBytes != null
|
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
|
||||||
? value.toDouble()
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -94,10 +96,13 @@ class UniversalImage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ImageProvider provider(String url) {
|
static ImageProvider provider(String url) {
|
||||||
if (!kIsWeb && (Platform.isAndroid || Platform.isIOS || Platform.isMacOS)) {
|
// This place used to use network image or cached network image depending on the platform.
|
||||||
return CachedNetworkImageProvider(url);
|
// But now the cached network image is working on every platform.
|
||||||
}
|
// So we just use it now.
|
||||||
return NetworkImage(url);
|
return CachedNetworkImageProvider(
|
||||||
|
url,
|
||||||
|
imageRenderMethodForWeb: ImageRenderMethodForWeb.HttpGet,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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"))
|
||||||
|
@ -26,7 +26,7 @@ PODS:
|
|||||||
- Firebase/Analytics (= 11.4.0)
|
- Firebase/Analytics (= 11.4.0)
|
||||||
- firebase_core
|
- firebase_core
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- firebase_core (3.8.1):
|
- firebase_core (3.9.0):
|
||||||
- Firebase/CoreOnly (~> 11.4.0)
|
- Firebase/CoreOnly (~> 11.4.0)
|
||||||
- FlutterMacOS
|
- FlutterMacOS
|
||||||
- firebase_messaging (15.1.6):
|
- firebase_messaging (15.1.6):
|
||||||
@ -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:
|
||||||
@ -279,20 +284,21 @@ SPEC CHECKSUMS:
|
|||||||
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
|
file_selector_macos: cc3858c981fe6889f364731200d6232dac1d812d
|
||||||
Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99
|
Firebase: cf1b19f21410b029b6786a54e9764a0cacad3c99
|
||||||
firebase_analytics: a80b3d6645f2f12d626fde928b61dae12e5ea2ef
|
firebase_analytics: a80b3d6645f2f12d626fde928b61dae12e5ea2ef
|
||||||
firebase_core: e4a35c426636a2cce00a5163df7ba69bfd0cca57
|
firebase_core: 1dfe1f4d02ad78be0277e320aa3d8384cf46231f
|
||||||
firebase_messaging: 61f678060b69a7ae1013e3a939ec8e1c56ef6fcf
|
firebase_messaging: 61f678060b69a7ae1013e3a939ec8e1c56ef6fcf
|
||||||
FirebaseAnalytics: 3feef9ae8733c567866342a1000691baaa7cad49
|
FirebaseAnalytics: 3feef9ae8733c567866342a1000691baaa7cad49
|
||||||
FirebaseCore: e0510f1523bc0eb21653cac00792e1e2bd6f1771
|
FirebaseCore: e0510f1523bc0eb21653cac00792e1e2bd6f1771
|
||||||
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: 61e868295d28fe67ffa297fae6dacebf56fd53e1
|
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
|
||||||
|
@ -31,16 +31,18 @@
|
|||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
<string>NSApplication</string>
|
<string>NSApplication</string>
|
||||||
<key>NSCameraUsageDescription</key>
|
<key>NSCameraUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian take photo or video for your post.</string>
|
<string>Grant access to Camera will allow Solian use your camera during a call.</string>
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian record audio for your post.</string>
|
<string>Grant access to Microphone will allow Solian use your microphone during a call.</string>
|
||||||
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
|
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
<string>Grant access to Photo Library will allow Solian upload photo or video for your post.</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>$(PRODUCT_NAME)</string>
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>NSCameraUseContinuityCameraDeviceType</key>
|
||||||
|
<string></string>
|
||||||
<key>ITSAppUsesNonExemptEncryption</key>
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
|
||||||
<string>Grant access to Photo Library will allow Solian download photo to album for you.</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
160
pubspec.lock
160
pubspec.lock
@ -13,10 +13,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: _flutterfire_internals
|
name: _flutterfire_internals
|
||||||
sha256: eae3133cbb06de9205899b822e3897fc6a8bc278ad4c944b4ce612689369694b
|
sha256: daa1d780fdecf8af925680c06c86563cdd445deea995d5c9176f1302a2b10bbe
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.47"
|
version: "1.3.48"
|
||||||
_macros:
|
_macros:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description: dart
|
description: dart
|
||||||
@ -50,10 +50,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: archive
|
name: archive
|
||||||
sha256: "08064924cbf0ab88280a0c3f60db9dd24fec693927e725ecb176f16c629d1cb8"
|
sha256: "6199c74e3db4fbfbd04f66d739e72fe11c8a8957d5f219f1f4482dbde6420b5a"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.1"
|
version: "4.0.2"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -122,50 +122,50 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build
|
name: build
|
||||||
sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0"
|
sha256: cef23f1eda9b57566c81e2133d196f8e3df48f244b317368d65c5943d91148f0
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.1"
|
version: "2.4.2"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_config
|
name: build_config
|
||||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.2"
|
||||||
build_daemon:
|
build_daemon:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_daemon
|
name: build_daemon
|
||||||
sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9"
|
sha256: "294a2edaf4814a378725bfe6358210196f5ea37af89ecd81bfa32960113d4948"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.3"
|
||||||
build_resolvers:
|
build_resolvers:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_resolvers
|
name: build_resolvers
|
||||||
sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a"
|
sha256: "99d3980049739a985cf9b21f30881f46db3ebc62c5b8d5e60e27440876b1ba1e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.2"
|
version: "2.4.3"
|
||||||
build_runner:
|
build_runner:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
name: build_runner
|
name: build_runner
|
||||||
sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d"
|
sha256: "74691599a5bc750dc96a6b4bfd48f7d9d66453eab04c7f4063134800d6a5c573"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.13"
|
version: "2.4.14"
|
||||||
build_runner_core:
|
build_runner_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: build_runner_core
|
name: build_runner_core
|
||||||
sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0
|
sha256: "22e3aa1c80e0ada3722fe5b63fd43d9c8990759d0a2cf489c8c5d7b2bdebc021"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.3.2"
|
version: "8.0.0"
|
||||||
built_collection:
|
built_collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -178,10 +178,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
|
sha256: "28a712df2576b63c6c005c465989a348604960c0958d28be5303ba9baa841ac2"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.2"
|
version: "8.9.3"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -343,13 +343,13 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.7"
|
version: "2.3.7"
|
||||||
dart_webrtc:
|
dart_webrtc:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dart_webrtc
|
name: dart_webrtc
|
||||||
sha256: c664ad88d5646735753add421ee2118486c100febef5e92b7f59cdbabf6a51f6
|
sha256: e65506edb452148220efab53d8d2f8bb9d827bd8bcd53cf3a3e6df70b27f3d86
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.9"
|
version: "1.4.10"
|
||||||
dbus:
|
dbus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -490,10 +490,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: file_picker
|
name: file_picker
|
||||||
sha256: "16dc141db5a2ccc6520ebb6a2eb5945b1b09e95085c021d9f914f8ded7f1465c"
|
sha256: c2376a6aae82358a9f9ccdd7d1f4006d08faa39a2767cce01031d9f593a8bd3b
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.4"
|
version: "8.1.6"
|
||||||
file_saver:
|
file_saver:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
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:
|
||||||
@ -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:
|
||||||
@ -692,10 +700,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_plugin_android_lifecycle
|
name: flutter_plugin_android_lifecycle
|
||||||
sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398"
|
sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.23"
|
version: "2.0.24"
|
||||||
flutter_shaders:
|
flutter_shaders:
|
||||||
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
|
||||||
@ -742,10 +750,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: flutter_webrtc
|
name: flutter_webrtc
|
||||||
sha256: "4838217405c42cce422698eacc9c2e17089b9c05322be899c0a725107dcddbdc"
|
sha256: "430859fb5b763d7556d06ef287cfca582e17d9a2dc36da26017f25a5c0b2523e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.3"
|
version: "0.12.4"
|
||||||
freezed:
|
freezed:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -774,10 +782,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: gal
|
name: gal
|
||||||
sha256: "54c9b72528efce7c66234f3b6dd01cb0304fd8af8196de15571d7bdddb940977"
|
sha256: "2771519c8b29f784d5e27f4efc2667667eef51c6c47cccaa0435a8fe8aa208e4"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.1"
|
||||||
gap:
|
gap:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -870,10 +878,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http_multi_server
|
name: http_multi_server
|
||||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.2"
|
||||||
http_parser:
|
http_parser:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -894,10 +902,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image
|
name: image
|
||||||
sha256: "599d08e369969bdf83138f5b4e0a7e823d3f992f23b8a64dd626877c37013533"
|
sha256: "8346ad4b5173924b5ddddab782fc7d8a6300178c8b1dc427775405a01701c4a6"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.0"
|
version: "4.5.2"
|
||||||
image_picker:
|
image_picker:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -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:
|
||||||
@ -1038,10 +1062,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 +1478,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:
|
||||||
@ -1598,10 +1622,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: shared_preferences
|
name: shared_preferences
|
||||||
sha256: "95f9997ca1fb9799d494d0cb2a780fd7be075818d59f00c43832ed112b158a82"
|
sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.3"
|
version: "2.3.4"
|
||||||
shared_preferences_android:
|
shared_preferences_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1691,10 +1715,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: source_helper
|
name: source_helper
|
||||||
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
|
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.4"
|
version: "1.3.5"
|
||||||
source_span:
|
source_span:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -1771,10 +1795,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stream_transform
|
name: stream_transform
|
||||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.1"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
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:
|
||||||
@ -2003,26 +2035,26 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: wakelock_plus
|
name: wakelock_plus
|
||||||
sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484
|
sha256: "36c88af0b930121941345306d259ec4cc4ecca3b151c02e3a9e71aede83c615e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.8"
|
version: "1.2.10"
|
||||||
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:
|
||||||
name: watcher
|
name: watcher
|
||||||
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
web:
|
web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2071,6 +2103,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 +2131,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-0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.24.0"
|
flutter: ">=3.24.0"
|
||||||
|
12
pubspec.yaml
12
pubspec.yaml
@ -1,5 +1,5 @@
|
|||||||
name: surface
|
name: surface
|
||||||
description: "A new Flutter project."
|
description: "The application for Solar Network"
|
||||||
# The following line prevents the package from being accidentally published to
|
# The following line prevents the package from being accidentally published to
|
||||||
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
||||||
@ -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.0.1+29
|
version: 2.1.1+36
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -61,7 +61,7 @@ dependencies:
|
|||||||
relative_time: ^5.0.0
|
relative_time: ^5.0.0
|
||||||
image_picker: ^1.1.2
|
image_picker: ^1.1.2
|
||||||
cross_file: ^0.3.4+2
|
cross_file: ^0.3.4+2
|
||||||
file_picker: 8.1.4 # pinned due to compile failed on android, https://github.com/miguelpruivo/flutter_file_picker/issues/1643
|
file_picker: ^8.1.6 # pinned due to compile failed on android, https://github.com/miguelpruivo/flutter_file_picker/issues/1643
|
||||||
croppy: ^1.3.1
|
croppy: ^1.3.1
|
||||||
flutter_expandable_fab: ^2.3.0
|
flutter_expandable_fab: ^2.3.0
|
||||||
dropdown_button2: ^2.3.9
|
dropdown_button2: ^2.3.9
|
||||||
@ -86,6 +86,7 @@ dependencies:
|
|||||||
media_kit_libs_video: ^1.0.5
|
media_kit_libs_video: ^1.0.5
|
||||||
pasteboard: ^0.3.0
|
pasteboard: ^0.3.0
|
||||||
synchronized: ^3.3.0+3
|
synchronized: ^3.3.0+3
|
||||||
|
dart_webrtc: ^1.4.10
|
||||||
livekit_client: ^2.3.1+hotfix.1
|
livekit_client: ^2.3.1+hotfix.1
|
||||||
wakelock_plus: ^1.2.8
|
wakelock_plus: ^1.2.8
|
||||||
permission_handler: ^11.3.1
|
permission_handler: ^11.3.1
|
||||||
@ -106,6 +107,10 @@ 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
|
||||||
|
flutter_app_update: ^3.2.2
|
||||||
|
in_app_review: ^2.0.10
|
||||||
|
version: ^3.0.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@ -138,6 +143,7 @@ flutter:
|
|||||||
# To add assets to your application, add an assets section, like this:
|
# To add assets to your application, add an assets section, like this:
|
||||||
assets:
|
assets:
|
||||||
- assets/icon/icon.png
|
- assets/icon/icon.png
|
||||||
|
- assets/icon/icon-dark.png
|
||||||
- assets/icon/icon-light-radius.png
|
- assets/icon/icon-light-radius.png
|
||||||
- assets/translations/
|
- assets/translations/
|
||||||
|
|
||||||
|
25
web/.well-known/apple-app-site-association
Normal file
25
web/.well-known/apple-app-site-association
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"applinks": {
|
||||||
|
"apps": [],
|
||||||
|
"details": [
|
||||||
|
{
|
||||||
|
"appIDs": [
|
||||||
|
"W7HPZ53V6B.dev.solsynth.solian"
|
||||||
|
],
|
||||||
|
"paths": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"/": "/*"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"webcredentials": {
|
||||||
|
"apps": [
|
||||||
|
"W7HPZ53V6B.dev.solsynth.solian"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user