Compare commits
10 Commits
8a2b321701
...
3.3.0+135
| Author | SHA1 | Date | |
|---|---|---|---|
|
5efa9b2ae8
|
|||
|
dd3e39e891
|
|||
|
b6896ded23
|
|||
|
f28a73ff9c
|
|||
|
a014b64235
|
|||
|
7e0e7c20d7
|
|||
|
389fa515ba
|
|||
|
681ead02eb
|
|||
|
8d1c145b0b
|
|||
|
51b4754182
|
@@ -25,13 +25,8 @@ android {
|
|||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
isCoreLibraryDesugaringEnabled = true
|
isCoreLibraryDesugaringEnabled = true
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions { jvmTarget = JavaVersion.VERSION_17.toString() }
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "dev.solsynth.solian"
|
applicationId = "dev.solsynth.solian"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
@@ -75,3 +70,17 @@ dependencies {
|
|||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_21)
|
||||||
|
}
|
||||||
|
jvmToolchain(21)
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -171,8 +171,8 @@
|
|||||||
"checkInResultLevel3": "Good Luck",
|
"checkInResultLevel3": "Good Luck",
|
||||||
"checkInResultLevel4": "Best Luck",
|
"checkInResultLevel4": "Best Luck",
|
||||||
"checkInActivityTitle": "{} checked in on {} and got a {}",
|
"checkInActivityTitle": "{} checked in on {} and got a {}",
|
||||||
"eventCalander": "Event Calander",
|
"eventCalendar": "Event Calendar",
|
||||||
"eventCalanderEmpty": "No events on that day.",
|
"eventCalendarEmpty": "No events on that day.",
|
||||||
"fortuneGraph": "Fortune Trend",
|
"fortuneGraph": "Fortune Trend",
|
||||||
"noFortuneData": "No fortune data available for this month.",
|
"noFortuneData": "No fortune data available for this month.",
|
||||||
"creatorHub": "Creator Hub",
|
"creatorHub": "Creator Hub",
|
||||||
@@ -639,6 +639,10 @@
|
|||||||
"chatNotJoined": "You have not joined this chat yet.",
|
"chatNotJoined": "You have not joined this chat yet.",
|
||||||
"chatUnableJoin": "You can't join this chat due to it's access control settings.",
|
"chatUnableJoin": "You can't join this chat due to it's access control settings.",
|
||||||
"chatJoin": "Join the Chat",
|
"chatJoin": "Join the Chat",
|
||||||
|
"chatReplyingTo": "Replying to {}",
|
||||||
|
"chatForwarding": "Forwarding message",
|
||||||
|
"chatEditing": "Editing message",
|
||||||
|
"chatNoContent": "No content",
|
||||||
"realmJoin": "Join the Realm",
|
"realmJoin": "Join the Realm",
|
||||||
"realmJoinSuccess": "Successfully joined the realm.",
|
"realmJoinSuccess": "Successfully joined the realm.",
|
||||||
"search": "Search",
|
"search": "Search",
|
||||||
@@ -1246,5 +1250,7 @@
|
|||||||
"addColor": "Add Color",
|
"addColor": "Add Color",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"availableWithYourPlan": "Available with your plan",
|
"availableWithYourPlan": "Available with your plan",
|
||||||
"upgradeRequired": "Upgrade required"
|
"upgradeRequired": "Upgrade required",
|
||||||
|
"settingsDisableAnimation": "Disable Animation",
|
||||||
|
"addTag": "Add Tag"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const kAppDefaultPoolId = 'app_default_pool_id';
|
|||||||
const kAppMessageDisplayStyle = 'app_message_display_style';
|
const kAppMessageDisplayStyle = 'app_message_display_style';
|
||||||
const kAppThemeMode = 'app_theme_mode';
|
const kAppThemeMode = 'app_theme_mode';
|
||||||
const kMaterialYouToggleStoreKey = 'app_theme_material_you';
|
const kMaterialYouToggleStoreKey = 'app_theme_material_you';
|
||||||
|
const kAppDisableAnimation = 'app_disable_animation';
|
||||||
const kFeaturedPostsCollapsedId =
|
const kFeaturedPostsCollapsedId =
|
||||||
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
'featured_posts_collapsed_id'; // Key for storing the ID of the collapsed featured post
|
||||||
|
|
||||||
@@ -96,6 +97,7 @@ sealed class AppSettings with _$AppSettings {
|
|||||||
required String messageDisplayStyle,
|
required String messageDisplayStyle,
|
||||||
required String? themeMode,
|
required String? themeMode,
|
||||||
required bool useMaterial3,
|
required bool useMaterial3,
|
||||||
|
required bool disableAnimation,
|
||||||
}) = _AppSettings;
|
}) = _AppSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,6 +124,7 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
messageDisplayStyle: prefs.getString(kAppMessageDisplayStyle) ?? 'bubble',
|
messageDisplayStyle: prefs.getString(kAppMessageDisplayStyle) ?? 'bubble',
|
||||||
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
|
themeMode: prefs.getString(kAppThemeMode) ?? 'system',
|
||||||
useMaterial3: prefs.getBool(kMaterialYouToggleStoreKey) ?? true,
|
useMaterial3: prefs.getBool(kMaterialYouToggleStoreKey) ?? true,
|
||||||
|
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,6 +276,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
}
|
}
|
||||||
state = state.copyWith(customColors: value);
|
state = state.copyWith(customColors: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDisableAnimation(bool value) {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
prefs.setBool(kAppDisableAnimation, value);
|
||||||
|
state = state.copyWith(disableAnimation: value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final updateInfoProvider =
|
final updateInfoProvider =
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ mixin _$AppSettings {
|
|||||||
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
|
ThemeColors? get customColors; Size? get windowSize;// The window size for desktop platforms
|
||||||
double get windowOpacity;// The window opacity for desktop platforms
|
double get windowOpacity;// The window opacity for desktop platforms
|
||||||
double get cardTransparency;// The card background opacity
|
double get cardTransparency;// The card background opacity
|
||||||
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get useMaterial3;
|
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get useMaterial3; bool get disableAnimation;
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@@ -301,16 +301,16 @@ $AppSettingsCopyWith<AppSettings> get copyWith => _$AppSettingsCopyWithImpl<AppS
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3);
|
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3)';
|
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -321,7 +321,7 @@ abstract mixin class $AppSettingsCopyWith<$Res> {
|
|||||||
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
factory $AppSettingsCopyWith(AppSettings value, $Res Function(AppSettings) _then) = _$AppSettingsCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3
|
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ class _$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -357,6 +357,7 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
|||||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
|
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -451,10 +452,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3);case _:
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -472,10 +473,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings():
|
case _AppSettings():
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3);}
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -489,10 +490,10 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3);case _:
|
return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_that.aprilFoolFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -504,7 +505,7 @@ return $default(_that.autoTranslate,_that.dataSavingMode,_that.soundEffects,_tha
|
|||||||
|
|
||||||
|
|
||||||
class _AppSettings implements AppSettings {
|
class _AppSettings implements AppSettings {
|
||||||
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.useMaterial3});
|
const _AppSettings({required this.autoTranslate, required this.dataSavingMode, required this.soundEffects, required this.aprilFoolFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.customFonts, required this.appColorScheme, required this.customColors, required this.windowSize, required this.windowOpacity, required this.cardTransparency, required this.defaultPoolId, required this.messageDisplayStyle, required this.themeMode, required this.useMaterial3, required this.disableAnimation});
|
||||||
|
|
||||||
|
|
||||||
@override final bool autoTranslate;
|
@override final bool autoTranslate;
|
||||||
@@ -528,6 +529,7 @@ class _AppSettings implements AppSettings {
|
|||||||
@override final String messageDisplayStyle;
|
@override final String messageDisplayStyle;
|
||||||
@override final String? themeMode;
|
@override final String? themeMode;
|
||||||
@override final bool useMaterial3;
|
@override final bool useMaterial3;
|
||||||
|
@override final bool disableAnimation;
|
||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@@ -539,16 +541,16 @@ _$AppSettingsCopyWith<_AppSettings> get copyWith => __$AppSettingsCopyWithImpl<_
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.autoTranslate, autoTranslate) || other.autoTranslate == autoTranslate)&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.aprilFoolFeatures, aprilFoolFeatures) || other.aprilFoolFeatures == aprilFoolFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.customFonts, customFonts) || other.customFonts == customFonts)&&(identical(other.appColorScheme, appColorScheme) || other.appColorScheme == appColorScheme)&&(identical(other.customColors, customColors) || other.customColors == customColors)&&(identical(other.windowSize, windowSize) || other.windowSize == windowSize)&&(identical(other.windowOpacity, windowOpacity) || other.windowOpacity == windowOpacity)&&(identical(other.cardTransparency, cardTransparency) || other.cardTransparency == cardTransparency)&&(identical(other.defaultPoolId, defaultPoolId) || other.defaultPoolId == defaultPoolId)&&(identical(other.messageDisplayStyle, messageDisplayStyle) || other.messageDisplayStyle == messageDisplayStyle)&&(identical(other.themeMode, themeMode) || other.themeMode == themeMode)&&(identical(other.useMaterial3, useMaterial3) || other.useMaterial3 == useMaterial3)&&(identical(other.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3);
|
int get hashCode => Object.hash(runtimeType,autoTranslate,dataSavingMode,soundEffects,aprilFoolFeatures,enterToSend,appBarTransparent,showBackgroundImage,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3)';
|
return 'AppSettings(autoTranslate: $autoTranslate, dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, aprilFoolFeatures: $aprilFoolFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -559,7 +561,7 @@ abstract mixin class _$AppSettingsCopyWith<$Res> implements $AppSettingsCopyWith
|
|||||||
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
factory _$AppSettingsCopyWith(_AppSettings value, $Res Function(_AppSettings) _then) = __$AppSettingsCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3
|
bool autoTranslate, bool dataSavingMode, bool soundEffects, bool aprilFoolFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -576,7 +578,7 @@ class __$AppSettingsCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of AppSettings
|
/// Create a copy of AppSettings
|
||||||
/// with the given fields replaced by the non-null parameter values.
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? autoTranslate = null,Object? dataSavingMode = null,Object? soundEffects = null,Object? aprilFoolFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? customFonts = freezed,Object? appColorScheme = freezed,Object? customColors = freezed,Object? windowSize = freezed,Object? windowOpacity = null,Object? cardTransparency = null,Object? defaultPoolId = freezed,Object? messageDisplayStyle = null,Object? themeMode = freezed,Object? useMaterial3 = null,Object? disableAnimation = null,}) {
|
||||||
return _then(_AppSettings(
|
return _then(_AppSettings(
|
||||||
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
autoTranslate: null == autoTranslate ? _self.autoTranslate : autoTranslate // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
as bool,dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -595,6 +597,7 @@ as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaul
|
|||||||
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
as String?,messageDisplayStyle: null == messageDisplayStyle ? _self.messageDisplayStyle : messageDisplayStyle // ignore: cast_nullable_to_non_nullable
|
||||||
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
as String,themeMode: freezed == themeMode ? _self.themeMode : themeMode // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
|
as String?,useMaterial3: null == useMaterial3 ? _self.useMaterial3 : useMaterial3 // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,
|
as bool,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Map<String, dynamic> _$ThemeColorsToJson(_ThemeColors instance) =>
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$appSettingsNotifierHash() =>
|
String _$appSettingsNotifierHash() =>
|
||||||
r'3ba2cdce76f3c4fed84f4108341c88a0a971bf3a';
|
r'10ebd893c39d24ae588a4c0bf4144ee4656465a4';
|
||||||
|
|
||||||
/// See also [AppSettingsNotifier].
|
/// See also [AppSettingsNotifier].
|
||||||
@ProviderFor(AppSettingsNotifier)
|
@ProviderFor(AppSettingsNotifier)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:async';
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dio_smart_retry/dio_smart_retry.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
@@ -109,6 +110,16 @@ final apiClientProvider = Provider<Dio>((ref) {
|
|||||||
printResponseData: false,
|
printResponseData: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
RetryInterceptor(
|
||||||
|
dio: dio,
|
||||||
|
retries: 3,
|
||||||
|
retryDelays: const [
|
||||||
|
Duration(seconds: 1),
|
||||||
|
Duration(seconds: 2),
|
||||||
|
Duration(seconds: 3),
|
||||||
|
],
|
||||||
|
retryEvaluator: (err, _) => err.requestOptions.method == 'GET',
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return dio;
|
return dio;
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ import 'package:island/screens/settings.dart';
|
|||||||
import 'package:island/screens/realm/realms.dart';
|
import 'package:island/screens/realm/realms.dart';
|
||||||
import 'package:island/screens/realm/realm_form.dart';
|
import 'package:island/screens/realm/realm_form.dart';
|
||||||
import 'package:island/screens/realm/realm_detail.dart';
|
import 'package:island/screens/realm/realm_detail.dart';
|
||||||
import 'package:island/screens/account/event_calendar.dart';
|
|
||||||
import 'package:island/screens/discovery/realms.dart';
|
import 'package:island/screens/discovery/realms.dart';
|
||||||
import 'package:island/screens/reports/report_detail.dart';
|
import 'package:island/screens/reports/report_detail.dart';
|
||||||
import 'package:island/screens/reports/report_list.dart';
|
import 'package:island/screens/reports/report_list.dart';
|
||||||
@@ -138,14 +137,6 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
path: '/logs',
|
path: '/logs',
|
||||||
builder: (context, state) => TalkerScreen(talker: talker),
|
builder: (context, state) => TalkerScreen(talker: talker),
|
||||||
),
|
),
|
||||||
GoRoute(
|
|
||||||
name: 'accountCalendar',
|
|
||||||
path: '/account/:name/calendar',
|
|
||||||
builder: (context, state) {
|
|
||||||
final name = state.pathParameters['name']!;
|
|
||||||
return EventCalanderScreen(name: name);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
|
|
||||||
// Web articles
|
// Web articles
|
||||||
GoRoute(
|
GoRoute(
|
||||||
|
|||||||
@@ -97,9 +97,7 @@ class _AccountBasicInfo extends StatelessWidget {
|
|||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
SharePlus.instance.share(
|
SharePlus.instance.share(
|
||||||
ShareParams(
|
ShareParams(uri: Uri.parse('https://solian.app/@${data.name}')),
|
||||||
uri: Uri.parse('https://solian.app/@${data.name}'),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
icon: const Icon(Symbols.share),
|
icon: const Icon(Symbols.share),
|
||||||
@@ -879,7 +877,7 @@ class AccountProfileScreen extends HookConsumerWidget {
|
|||||||
child: Card(
|
child: Card(
|
||||||
child: FortuneGraphWidget(
|
child: FortuneGraphWidget(
|
||||||
events: accountEvents,
|
events: accountEvents,
|
||||||
eventCalanderUser: data.name,
|
eventCalandarUser: data.name,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -1004,7 +1002,7 @@ class AccountProfileScreen extends HookConsumerWidget {
|
|||||||
child: Card(
|
child: Card(
|
||||||
child: FortuneGraphWidget(
|
child: FortuneGraphWidget(
|
||||||
events: accountEvents,
|
events: accountEvents,
|
||||||
eventCalanderUser: data.name,
|
eventCalandarUser: data.name,
|
||||||
),
|
),
|
||||||
).padding(horizontal: 4),
|
).padding(horizontal: 4),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import "package:island/pods/chat/chat_subscribe.dart";
|
|||||||
import "package:island/pods/chat/messages_notifier.dart";
|
import "package:island/pods/chat/messages_notifier.dart";
|
||||||
import "package:island/pods/network.dart";
|
import "package:island/pods/network.dart";
|
||||||
import "package:island/pods/chat/chat_online_count.dart";
|
import "package:island/pods/chat/chat_online_count.dart";
|
||||||
|
import "package:island/pods/config.dart";
|
||||||
import "package:island/screens/chat/search_messages.dart";
|
import "package:island/screens/chat/search_messages.dart";
|
||||||
import "package:island/services/file_uploader.dart";
|
import "package:island/services/file_uploader.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
import "package:island/screens/chat/chat.dart";
|
||||||
@@ -44,6 +45,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
||||||
final isSyncing = ref.watch(isSyncingProvider);
|
final isSyncing = ref.watch(isSyncingProvider);
|
||||||
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
||||||
|
final settings = ref.watch(appSettingsNotifierProvider);
|
||||||
|
|
||||||
final hasOnlineCount = onlineCount.hasValue;
|
final hasOnlineCount = onlineCount.hasValue;
|
||||||
|
|
||||||
@@ -535,7 +537,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
listController: listController,
|
listController: listController,
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
top: 16,
|
top: 16,
|
||||||
bottom: 80 + MediaQuery.of(context).padding.bottom,
|
bottom: MediaQuery.of(context).padding.bottom + 16,
|
||||||
),
|
),
|
||||||
controller: scrollController,
|
controller: scrollController,
|
||||||
reverse: true, // Show newest messages at the bottom
|
reverse: true, // Show newest messages at the bottom
|
||||||
@@ -543,7 +545,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
findChildIndexCallback: (key) {
|
findChildIndexCallback: (key) {
|
||||||
if (key is! ValueKey<String>) return null;
|
if (key is! ValueKey<String>) return null;
|
||||||
final messageId = key.value.substring(messageKeyPrefix.length);
|
final messageId = key.value.substring(messageKeyPrefix.length);
|
||||||
final index = messageList.indexWhere((m) => m.id == messageId);
|
final index = messageList.indexWhere(
|
||||||
|
(m) => (m.nonce ?? m.id) == messageId,
|
||||||
|
);
|
||||||
// Return null for invalid indices to let SuperListView handle it properly
|
// Return null for invalid indices to let SuperListView handle it properly
|
||||||
return index >= 0 ? index : null;
|
return index >= 0 ? index : null;
|
||||||
},
|
},
|
||||||
@@ -561,13 +565,14 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
.abs() >
|
.abs() >
|
||||||
3;
|
3;
|
||||||
|
|
||||||
final key = ValueKey('$messageKeyPrefix${message.id}');
|
// Use a stable animation key that doesn't change during message lifecycle
|
||||||
|
final key = Key('$messageKeyPrefix${message.nonce ?? message.id}');
|
||||||
|
|
||||||
return chatIdentity.when(
|
final messageWidget = chatIdentity.when(
|
||||||
skipError: true,
|
skipError: true,
|
||||||
data:
|
data:
|
||||||
(identity) => MessageItem(
|
(identity) => MessageItem(
|
||||||
key: key,
|
key: settings.disableAnimation ? key : null,
|
||||||
message: message,
|
message: message,
|
||||||
isCurrentUser: identity?.id == message.senderId,
|
isCurrentUser: identity?.id == message.senderId,
|
||||||
onAction: (action) {
|
onAction: (action) {
|
||||||
@@ -605,7 +610,6 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
loading:
|
loading:
|
||||||
() => MessageItem(
|
() => MessageItem(
|
||||||
key: key,
|
|
||||||
message: message,
|
message: message,
|
||||||
isCurrentUser: false,
|
isCurrentUser: false,
|
||||||
onAction: null,
|
onAction: null,
|
||||||
@@ -613,8 +617,29 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
showAvatar: false,
|
showAvatar: false,
|
||||||
onJump: (_) {},
|
onJump: (_) {},
|
||||||
),
|
),
|
||||||
error: (_, _) => SizedBox.shrink(key: key),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return settings.disableAnimation
|
||||||
|
? messageWidget
|
||||||
|
: TweenAnimationBuilder<double>(
|
||||||
|
key: key,
|
||||||
|
tween: Tween<double>(begin: 0.0, end: 1.0),
|
||||||
|
duration: Duration(
|
||||||
|
milliseconds: 400 + (index % 5) * 50,
|
||||||
|
), // Staggered delay
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
builder: (context, animationValue, child) {
|
||||||
|
return Transform.translate(
|
||||||
|
offset: Offset(
|
||||||
|
0,
|
||||||
|
20 * (1 - animationValue),
|
||||||
|
), // Slide up from bottom
|
||||||
|
child: Opacity(opacity: animationValue, child: child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: messageWidget,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -687,91 +712,116 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
// Messages
|
// Messages and Input in Column
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: messages.when(
|
child: Column(
|
||||||
data:
|
children: [
|
||||||
(messageList) =>
|
Expanded(
|
||||||
messageList.isEmpty
|
child: AnimatedSwitcher(
|
||||||
? Center(child: Text('No messages yet'.tr()))
|
duration: const Duration(milliseconds: 300),
|
||||||
: chatMessageListWidget(messageList),
|
switchInCurve: Curves.easeOutCubic,
|
||||||
loading: () => const Center(child: CircularProgressIndicator()),
|
switchOutCurve: Curves.easeInCubic,
|
||||||
error:
|
transitionBuilder: (
|
||||||
(error, _) => ResponseErrorWidget(
|
Widget child,
|
||||||
error: error,
|
Animation<double> animation,
|
||||||
onRetry: () => messagesNotifier.loadInitial(),
|
) {
|
||||||
|
return SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(0, 0.05),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(animation),
|
||||||
|
child: FadeTransition(opacity: animation, child: child),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: messages.when(
|
||||||
|
data:
|
||||||
|
(messageList) =>
|
||||||
|
messageList.isEmpty
|
||||||
|
? Center(
|
||||||
|
key: const ValueKey('empty-messages'),
|
||||||
|
child: Text('No messages yet'.tr()),
|
||||||
|
)
|
||||||
|
: chatMessageListWidget(messageList),
|
||||||
|
loading:
|
||||||
|
() => const Center(
|
||||||
|
key: ValueKey('loading-messages'),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
error:
|
||||||
|
(error, _) => ResponseErrorWidget(
|
||||||
|
key: const ValueKey('error-messages'),
|
||||||
|
error: error,
|
||||||
|
onRetry: () => messagesNotifier.loadInitial(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
chatRoom.when(
|
||||||
// Input
|
data:
|
||||||
Positioned(
|
(room) => Column(
|
||||||
bottom: 0,
|
mainAxisSize: MainAxisSize.min,
|
||||||
left: 0,
|
children: [
|
||||||
right: 0,
|
ChatInput(
|
||||||
child: chatRoom.when(
|
messageController: messageController,
|
||||||
data:
|
chatRoom: room!,
|
||||||
(room) => Column(
|
onSend: sendMessage,
|
||||||
mainAxisSize: MainAxisSize.min,
|
onClear: () {
|
||||||
children: [
|
if (messageEditingTo.value != null) {
|
||||||
ChatInput(
|
attachments.value.clear();
|
||||||
messageController: messageController,
|
messageController.clear();
|
||||||
chatRoom: room!,
|
}
|
||||||
onSend: sendMessage,
|
messageEditingTo.value = null;
|
||||||
onClear: () {
|
messageReplyingTo.value = null;
|
||||||
if (messageEditingTo.value != null) {
|
messageForwardingTo.value = null;
|
||||||
attachments.value.clear();
|
},
|
||||||
messageController.clear();
|
messageEditingTo: messageEditingTo.value,
|
||||||
}
|
messageReplyingTo: messageReplyingTo.value,
|
||||||
messageEditingTo.value = null;
|
messageForwardingTo: messageForwardingTo.value,
|
||||||
messageReplyingTo.value = null;
|
onPickFile: (bool isPhoto) {
|
||||||
messageForwardingTo.value = null;
|
if (isPhoto) {
|
||||||
},
|
pickPhotoMedia();
|
||||||
messageEditingTo: messageEditingTo.value,
|
} else {
|
||||||
messageReplyingTo: messageReplyingTo.value,
|
pickVideoMedia();
|
||||||
messageForwardingTo: messageForwardingTo.value,
|
}
|
||||||
onPickFile: (bool isPhoto) {
|
},
|
||||||
if (isPhoto) {
|
onPickAudio: pickAudioMedia,
|
||||||
pickPhotoMedia();
|
onPickGeneralFile: pickGeneralFile,
|
||||||
} else {
|
onLinkAttachment: linkAttachment,
|
||||||
pickVideoMedia();
|
attachments: attachments.value,
|
||||||
}
|
onUploadAttachment: uploadAttachment,
|
||||||
},
|
onDeleteAttachment: (index) async {
|
||||||
onPickAudio: pickAudioMedia,
|
final attachment = attachments.value[index];
|
||||||
onPickGeneralFile: pickGeneralFile,
|
if (attachment.isOnCloud && !attachment.isLink) {
|
||||||
onLinkAttachment: linkAttachment,
|
final client = ref.watch(apiClientProvider);
|
||||||
attachments: attachments.value,
|
await client.delete(
|
||||||
onUploadAttachment: uploadAttachment,
|
'/drive/files/${attachment.data.id}',
|
||||||
onDeleteAttachment: (index) async {
|
);
|
||||||
final attachment = attachments.value[index];
|
}
|
||||||
if (attachment.isOnCloud && !attachment.isLink) {
|
final clone = List.of(attachments.value);
|
||||||
final client = ref.watch(apiClientProvider);
|
clone.removeAt(index);
|
||||||
await client.delete(
|
attachments.value = clone;
|
||||||
'/drive/files/${attachment.data.id}',
|
},
|
||||||
);
|
onMoveAttachment: (idx, delta) {
|
||||||
}
|
if (idx + delta < 0 ||
|
||||||
final clone = List.of(attachments.value);
|
idx + delta >= attachments.value.length) {
|
||||||
clone.removeAt(index);
|
return;
|
||||||
attachments.value = clone;
|
}
|
||||||
},
|
final clone = List.of(attachments.value);
|
||||||
onMoveAttachment: (idx, delta) {
|
clone.insert(idx + delta, clone.removeAt(idx));
|
||||||
if (idx + delta < 0 ||
|
attachments.value = clone;
|
||||||
idx + delta >= attachments.value.length) {
|
},
|
||||||
return;
|
onAttachmentsChanged: (newAttachments) {
|
||||||
}
|
attachments.value = newAttachments;
|
||||||
final clone = List.of(attachments.value);
|
},
|
||||||
clone.insert(idx + delta, clone.removeAt(idx));
|
attachmentProgress: attachmentProgress.value,
|
||||||
attachments.value = clone;
|
),
|
||||||
},
|
Gap(MediaQuery.of(context).padding.bottom),
|
||||||
onAttachmentsChanged: (newAttachments) {
|
],
|
||||||
attachments.value = newAttachments;
|
|
||||||
},
|
|
||||||
attachmentProgress: attachmentProgress.value,
|
|
||||||
),
|
),
|
||||||
Gap(MediaQuery.of(context).padding.bottom),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
],
|
loading: () => const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
error: (_, _) => const SizedBox.shrink(),
|
],
|
||||||
loading: () => const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
|
|||||||
@@ -784,6 +784,22 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Disable animation settings
|
||||||
|
ListTile(
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
title: Text('settingsDisableAnimation').tr(),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
|
leading: const Icon(Symbols.animation),
|
||||||
|
trailing: Switch(
|
||||||
|
value: settings.disableAnimation,
|
||||||
|
onChanged: (value) {
|
||||||
|
ref
|
||||||
|
.read(appSettingsNotifierProvider.notifier)
|
||||||
|
.setDisableAnimation(value);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Desktop-specific settings
|
// Desktop-specific settings
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
@@ -6,14 +5,24 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:island/pods/event_calendar.dart';
|
import 'package:island/pods/event_calendar.dart';
|
||||||
import 'package:island/screens/account/profile.dart';
|
import 'package:island/screens/account/profile.dart';
|
||||||
import 'package:island/widgets/account/account_nameplate.dart';
|
import 'package:island/widgets/account/account_nameplate.dart';
|
||||||
import 'package:island/widgets/app_scaffold.dart';
|
|
||||||
import 'package:island/widgets/account/event_calendar.dart';
|
import 'package:island/widgets/account/event_calendar.dart';
|
||||||
import 'package:island/widgets/account/fortune_graph.dart';
|
import 'package:island/widgets/account/fortune_graph.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
class EventCalanderScreen extends HookConsumerWidget {
|
/// A reusable content widget for event calendar that can be used in screens or sheets
|
||||||
|
/// This widget manages the calendar state and displays the calendar and fortune graph
|
||||||
|
class EventCalendarContent extends HookConsumerWidget {
|
||||||
|
/// Username to fetch calendar for, null means current user ('me')
|
||||||
final String name;
|
final String name;
|
||||||
const EventCalanderScreen({super.key, required this.name});
|
|
||||||
|
/// Whether this is being displayed in a sheet (affects layout)
|
||||||
|
final bool isSheet;
|
||||||
|
|
||||||
|
const EventCalendarContent({
|
||||||
|
super.key,
|
||||||
|
required this.name,
|
||||||
|
this.isSheet = false,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
@@ -45,13 +54,37 @@ class EventCalanderScreen extends HookConsumerWidget {
|
|||||||
selectedDay.value = day;
|
selectedDay.value = day;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AppScaffold(
|
if (isSheet) {
|
||||||
isNoBackground: false,
|
// Sheet layout - simplified, no app bar, scrollable content
|
||||||
appBar: AppBar(
|
return SingleChildScrollView(
|
||||||
leading: const PageBackButton(),
|
child: Column(
|
||||||
title: Text('eventCalander').tr(),
|
children: [
|
||||||
),
|
// Use the reusable EventCalendarWidget
|
||||||
body: SingleChildScrollView(
|
EventCalendarWidget(
|
||||||
|
events: events,
|
||||||
|
initialDate: now,
|
||||||
|
showEventDetails: true,
|
||||||
|
onMonthChanged: onMonthChanged,
|
||||||
|
onDaySelected: onDaySelected,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Add the fortune graph widget
|
||||||
|
const Divider(height: 1),
|
||||||
|
FortuneGraphWidget(
|
||||||
|
events: events,
|
||||||
|
onPointSelected: onDaySelected,
|
||||||
|
).padding(horizontal: 8, vertical: 4),
|
||||||
|
|
||||||
|
// Show user profile if viewing someone else's calendar
|
||||||
|
if (name != 'me' && user.value != null)
|
||||||
|
AccountNameplate(name: name),
|
||||||
|
Gap(MediaQuery.of(context).padding.bottom + 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Screen layout - with responsive design
|
||||||
|
return SingleChildScrollView(
|
||||||
child:
|
child:
|
||||||
MediaQuery.of(context).size.width > 480
|
MediaQuery.of(context).size.width > 480
|
||||||
? ConstrainedBox(
|
? ConstrainedBox(
|
||||||
@@ -111,7 +144,7 @@ class EventCalanderScreen extends HookConsumerWidget {
|
|||||||
Gap(MediaQuery.of(context).padding.bottom + 16),
|
Gap(MediaQuery.of(context).padding.bottom + 16),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,10 +76,17 @@ class EventDetailsWidget extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if ((getActivityTitle(status.label, status.meta) ?? status.label).isNotEmpty)
|
if ((getActivityTitle(status.label, status.meta) ??
|
||||||
Text(getActivityTitle(status.label, status.meta) ?? status.label),
|
status.label)
|
||||||
|
.isNotEmpty)
|
||||||
|
Text(
|
||||||
|
getActivityTitle(status.label, status.meta) ??
|
||||||
|
status.label,
|
||||||
|
),
|
||||||
if (getActivitySubtitle(status.meta) != null)
|
if (getActivitySubtitle(status.meta) != null)
|
||||||
Text(getActivitySubtitle(status.meta)!).fontSize(11).opacity(0.8),
|
Text(
|
||||||
|
getActivitySubtitle(status.meta)!,
|
||||||
|
).fontSize(11).opacity(0.8),
|
||||||
Text(
|
Text(
|
||||||
'${status.createdAt.formatSystem()} - ${status.clearedAt?.formatSystem() ?? 'present'.tr()}',
|
'${status.createdAt.formatSystem()} - ${status.clearedAt?.formatSystem() ?? 'present'.tr()}',
|
||||||
).fontSize(11).opacity(0.8),
|
).fontSize(11).opacity(0.8),
|
||||||
@@ -92,7 +99,7 @@ class EventDetailsWidget extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true))
|
if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true))
|
||||||
Text('eventCalanderEmpty').tr(),
|
Text('eventCalandarEmpty').tr(),
|
||||||
],
|
],
|
||||||
).padding(vertical: 24, horizontal: 24);
|
).padding(vertical: 24, horizontal: 24);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:fl_chart/fl_chart.dart';
|
import 'package:fl_chart/fl_chart.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
|
import 'package:island/widgets/account/event_calendar_content.dart';
|
||||||
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
|
||||||
/// A widget that displays a graph of fortune levels over time
|
/// A widget that displays a graph of fortune levels over time
|
||||||
@@ -24,7 +25,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
/// Callback when a point is selected
|
/// Callback when a point is selected
|
||||||
final void Function(DateTime)? onPointSelected;
|
final void Function(DateTime)? onPointSelected;
|
||||||
|
|
||||||
final String? eventCalanderUser;
|
final String? eventCalandarUser;
|
||||||
|
|
||||||
final EdgeInsets? margin;
|
final EdgeInsets? margin;
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
this.maxWidth = double.infinity,
|
this.maxWidth = double.infinity,
|
||||||
this.height = 180,
|
this.height = 180,
|
||||||
this.onPointSelected,
|
this.onPointSelected,
|
||||||
this.eventCalanderUser,
|
this.eventCalandarUser,
|
||||||
this.margin,
|
this.margin,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('fortuneGraph').tr().fontSize(18).bold(),
|
Text('fortuneGraph').tr().fontSize(18).bold(),
|
||||||
if (eventCalanderUser != null)
|
if (eventCalandarUser != null)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.calendar_month, size: 20),
|
icon: const Icon(Icons.calendar_month, size: 20),
|
||||||
visualDensity: const VisualDensity(
|
visualDensity: const VisualDensity(
|
||||||
@@ -69,9 +70,17 @@ class FortuneGraphWidget extends HookConsumerWidget {
|
|||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
constraints: const BoxConstraints(),
|
constraints: const BoxConstraints(),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.pushNamed(
|
showModalBottomSheet(
|
||||||
'accountCalendar',
|
context: context,
|
||||||
pathParameters: {'name': eventCalanderUser!},
|
isScrollControlled: true,
|
||||||
|
builder:
|
||||||
|
(context) => SheetScaffold(
|
||||||
|
titleText: 'eventCalendar'.tr(),
|
||||||
|
child: EventCalendarContent(
|
||||||
|
name: eventCalandarUser!,
|
||||||
|
isSheet: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -225,86 +225,200 @@ class ChatInput extends HookConsumerWidget {
|
|||||||
key: ValueKey('typing-indicator-none'),
|
key: ValueKey('typing-indicator-none'),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (attachments.isNotEmpty)
|
AnimatedSwitcher(
|
||||||
SizedBox(
|
duration: const Duration(milliseconds: 250),
|
||||||
height: 180,
|
switchInCurve: Curves.easeOutCubic,
|
||||||
child: ListView.separated(
|
switchOutCurve: Curves.easeInCubic,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||||
scrollDirection: Axis.horizontal,
|
return SlideTransition(
|
||||||
itemCount: attachments.length,
|
position: Tween<Offset>(
|
||||||
itemBuilder: (context, idx) {
|
begin: const Offset(0, 0.1),
|
||||||
return SizedBox(
|
end: Offset.zero,
|
||||||
width: 180,
|
).animate(animation),
|
||||||
child: AttachmentPreview(
|
child: FadeTransition(
|
||||||
isCompact: true,
|
opacity: animation,
|
||||||
item: attachments[idx],
|
child: SizeTransition(
|
||||||
progress: attachmentProgress['chat-upload']?[idx],
|
sizeFactor: animation,
|
||||||
onRequestUpload: () => onUploadAttachment(idx),
|
axisAlignment: -1.0,
|
||||||
onDelete: () => onDeleteAttachment(idx),
|
child: child,
|
||||||
onUpdate: (value) {
|
|
||||||
attachments[idx] = value;
|
|
||||||
onAttachmentsChanged(attachments);
|
|
||||||
},
|
|
||||||
onMove: (delta) => onMoveAttachment(idx, delta),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder: (_, _) => const Gap(8),
|
|
||||||
),
|
|
||||||
).padding(vertical: 12),
|
|
||||||
if (messageReplyingTo != null ||
|
|
||||||
messageForwardingTo != null ||
|
|
||||||
messageEditingTo != null)
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 16,
|
|
||||||
vertical: 4,
|
|
||||||
),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context).colorScheme.surfaceContainerHigh,
|
|
||||||
borderRadius: BorderRadius.circular(32),
|
|
||||||
),
|
|
||||||
margin: const EdgeInsets.only(
|
|
||||||
left: 8,
|
|
||||||
right: 8,
|
|
||||||
top: 8,
|
|
||||||
bottom: 4,
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
messageReplyingTo != null
|
|
||||||
? Symbols.reply
|
|
||||||
: messageForwardingTo != null
|
|
||||||
? Symbols.forward
|
|
||||||
: Symbols.edit,
|
|
||||||
size: 20,
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
),
|
||||||
const Gap(8),
|
),
|
||||||
Expanded(
|
);
|
||||||
child: Text(
|
},
|
||||||
messageReplyingTo != null
|
child:
|
||||||
? 'Replying to ${messageReplyingTo?.sender.account.nick}'
|
attachments.isNotEmpty
|
||||||
: messageForwardingTo != null
|
? SizedBox(
|
||||||
? 'Forwarding message'
|
key: ValueKey('attachments-${attachments.length}'),
|
||||||
: 'Editing message',
|
height: 180,
|
||||||
style: Theme.of(context).textTheme.bodySmall,
|
child: ListView.separated(
|
||||||
maxLines: 1,
|
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||||
overflow: TextOverflow.ellipsis,
|
scrollDirection: Axis.horizontal,
|
||||||
|
itemCount: attachments.length,
|
||||||
|
itemBuilder: (context, idx) {
|
||||||
|
return SizedBox(
|
||||||
|
width: 180,
|
||||||
|
child: AttachmentPreview(
|
||||||
|
isCompact: true,
|
||||||
|
item: attachments[idx],
|
||||||
|
progress:
|
||||||
|
attachmentProgress['chat-upload']?[idx],
|
||||||
|
onRequestUpload:
|
||||||
|
() => onUploadAttachment(idx),
|
||||||
|
onDelete: () => onDeleteAttachment(idx),
|
||||||
|
onUpdate: (value) {
|
||||||
|
attachments[idx] = value;
|
||||||
|
onAttachmentsChanged(attachments);
|
||||||
|
},
|
||||||
|
onMove:
|
||||||
|
(delta) => onMoveAttachment(idx, delta),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder: (_, _) => const Gap(8),
|
||||||
|
),
|
||||||
|
).padding(vertical: 12)
|
||||||
|
: const SizedBox.shrink(
|
||||||
|
key: ValueKey('no-attachments'),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
switchInCurve: Curves.easeOutCubic,
|
||||||
|
switchOutCurve: Curves.easeInCubic,
|
||||||
|
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||||
|
return SlideTransition(
|
||||||
|
position: Tween<Offset>(
|
||||||
|
begin: const Offset(0, -0.2),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(animation),
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: animation,
|
||||||
|
child: SizeTransition(
|
||||||
|
sizeFactor: animation,
|
||||||
|
axisAlignment: -1.0,
|
||||||
|
child: child,
|
||||||
),
|
),
|
||||||
SizedBox(
|
),
|
||||||
width: 28,
|
);
|
||||||
height: 28,
|
},
|
||||||
child: InkWell(
|
child:
|
||||||
onTap: onClear,
|
(messageReplyingTo != null ||
|
||||||
child: const Icon(Icons.close, size: 20).center(),
|
messageForwardingTo != null ||
|
||||||
),
|
messageEditingTo != null)
|
||||||
),
|
? Container(
|
||||||
],
|
key: ValueKey(
|
||||||
),
|
messageReplyingTo?.id ??
|
||||||
),
|
messageForwardingTo?.id ??
|
||||||
|
messageEditingTo?.id ??
|
||||||
|
'action',
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.surfaceContainerHigh,
|
||||||
|
borderRadius: BorderRadius.circular(24),
|
||||||
|
border: Border.all(
|
||||||
|
color: Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.outline.withOpacity(0.2),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.only(
|
||||||
|
left: 8,
|
||||||
|
right: 8,
|
||||||
|
top: 8,
|
||||||
|
bottom: 8,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
messageReplyingTo != null
|
||||||
|
? Symbols.reply
|
||||||
|
: messageForwardingTo != null
|
||||||
|
? Symbols.forward
|
||||||
|
: Symbols.edit,
|
||||||
|
size: 18,
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
messageReplyingTo != null
|
||||||
|
? 'chatReplyingTo'.tr(
|
||||||
|
args: [
|
||||||
|
messageReplyingTo
|
||||||
|
?.sender
|
||||||
|
.account
|
||||||
|
.nick ??
|
||||||
|
'unknown'.tr(),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: messageForwardingTo != null
|
||||||
|
? 'chatForwarding'.tr()
|
||||||
|
: 'chatEditing'.tr(),
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.bodySmall!.copyWith(
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
child: IconButton(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
icon: const Icon(Icons.close, size: 18),
|
||||||
|
onPressed: onClear,
|
||||||
|
tooltip: 'clear'.tr(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (messageReplyingTo != null ||
|
||||||
|
messageForwardingTo != null ||
|
||||||
|
messageEditingTo != null)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 6,
|
||||||
|
left: 26,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
(messageReplyingTo ??
|
||||||
|
messageForwardingTo ??
|
||||||
|
messageEditingTo)
|
||||||
|
?.content ??
|
||||||
|
'chatNoContent'.tr(),
|
||||||
|
style: Theme.of(
|
||||||
|
context,
|
||||||
|
).textTheme.bodySmall!.copyWith(
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: const SizedBox.shrink(key: ValueKey('no-action')),
|
||||||
|
),
|
||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:dio/dio.dart';
|
|||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/activity.dart';
|
import 'package:island/models/activity.dart';
|
||||||
@@ -14,6 +13,8 @@ import 'package:island/pods/userinfo.dart';
|
|||||||
import 'package:island/screens/auth/captcha.dart';
|
import 'package:island/screens/auth/captcha.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/cloud_files.dart';
|
import 'package:island/widgets/content/cloud_files.dart';
|
||||||
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:island/widgets/account/event_calendar_content.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:slide_countdown/slide_countdown.dart';
|
import 'package:slide_countdown/slide_countdown.dart';
|
||||||
@@ -256,9 +257,17 @@ class CheckInWidget extends HookConsumerWidget {
|
|||||||
if (todayResult.valueOrNull == null) {
|
if (todayResult.valueOrNull == null) {
|
||||||
checkIn();
|
checkIn();
|
||||||
} else {
|
} else {
|
||||||
context.pushNamed(
|
showModalBottomSheet(
|
||||||
'accountCalendar',
|
context: context,
|
||||||
pathParameters: {'name': 'me'},
|
isScrollControlled: true,
|
||||||
|
builder:
|
||||||
|
(context) => SheetScaffold(
|
||||||
|
titleText: 'eventCalendar'.tr(),
|
||||||
|
child: EventCalendarContent(
|
||||||
|
name: 'me',
|
||||||
|
isSheet: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -530,7 +530,11 @@ class SpoilerSpanNode extends SpanNode {
|
|||||||
? Row(
|
? Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [Icon(Symbols.visibility, size: 18), Text(text)],
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Symbols.visibility, size: 18).padding(top: 1),
|
||||||
|
Flexible(child: Text(text)),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
: Row(
|
: Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
@@ -541,7 +545,13 @@ class SpoilerSpanNode extends SpanNode {
|
|||||||
color: foregroundColor,
|
color: foregroundColor,
|
||||||
size: 18,
|
size: 18,
|
||||||
),
|
),
|
||||||
Text(text, style: TextStyle(color: foregroundColor)),
|
Flexible(
|
||||||
|
child:
|
||||||
|
Text(
|
||||||
|
'spoiler',
|
||||||
|
style: TextStyle(color: foregroundColor),
|
||||||
|
).tr(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ import 'package:dropdown_button2/dropdown_button2.dart';
|
|||||||
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:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/models/post_category.dart';
|
import 'package:island/models/post_category.dart';
|
||||||
|
import 'package:island/models/post_tag.dart';
|
||||||
import 'package:island/models/realm.dart';
|
import 'package:island/models/realm.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/screens/realm/realms.dart';
|
import 'package:island/screens/realm/realms.dart';
|
||||||
@@ -132,6 +134,26 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
const ComposeSettingsSheet({super.key, required this.state});
|
const ComposeSettingsSheet({super.key, required this.state});
|
||||||
|
|
||||||
|
Future<List<SnPostTag>> _fetchTagSuggestions(
|
||||||
|
String query,
|
||||||
|
WidgetRef ref,
|
||||||
|
) async {
|
||||||
|
if (query.isEmpty) return [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final response = await client.get(
|
||||||
|
'/sphere/posts/tags',
|
||||||
|
queryParameters: {'query': query},
|
||||||
|
);
|
||||||
|
return response.data
|
||||||
|
.map<SnPostTag>((json) => SnPostTag.fromJson(json))
|
||||||
|
.toList();
|
||||||
|
} catch (e) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
@@ -140,6 +162,7 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
|||||||
// Listen to visibility changes to trigger rebuilds
|
// Listen to visibility changes to trigger rebuilds
|
||||||
final currentVisibility = useValueListenable(state.visibility);
|
final currentVisibility = useValueListenable(state.visibility);
|
||||||
final currentCategories = useValueListenable(state.categories);
|
final currentCategories = useValueListenable(state.categories);
|
||||||
|
final currentTags = useValueListenable(state.tags);
|
||||||
final currentRealm = useValueListenable(state.realm);
|
final currentRealm = useValueListenable(state.realm);
|
||||||
final postCategories = ref.watch(postCategoriesProvider);
|
final postCategories = ref.watch(postCategoriesProvider);
|
||||||
final userRealms = ref.watch(realmsJoinedProvider);
|
final userRealms = ref.watch(realmsJoinedProvider);
|
||||||
@@ -255,23 +278,118 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Tags field
|
// Tags field
|
||||||
TextFieldTags(
|
Container(
|
||||||
textfieldTagsController: state.tagsController,
|
decoration: BoxDecoration(
|
||||||
textSeparators: const [' ', ','],
|
border: Border.all(
|
||||||
letterCase: LetterCase.normal,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
validator: (String tag) {
|
width: 1,
|
||||||
if (tag.isEmpty) {
|
),
|
||||||
return 'No, cannot be empty';
|
borderRadius: BorderRadius.circular(12),
|
||||||
}
|
),
|
||||||
return null;
|
padding: const EdgeInsets.all(16),
|
||||||
},
|
child: Column(
|
||||||
inputFieldBuilder: (context, inputFieldValues) {
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
return ChipTagInputField(
|
spacing: 12,
|
||||||
inputFieldValues: inputFieldValues,
|
children: [
|
||||||
labelText: 'tags',
|
Text(
|
||||||
hintText: 'tagsHint',
|
'tags'.tr(),
|
||||||
);
|
style: Theme.of(context).textTheme.labelLarge,
|
||||||
},
|
),
|
||||||
|
// Existing tags display
|
||||||
|
if (currentTags.isNotEmpty)
|
||||||
|
Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children:
|
||||||
|
currentTags.map((tag) {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 12,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'#$tag',
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onPrimary,
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Gap(4),
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
final newTags = List<String>.from(
|
||||||
|
state.tags.value,
|
||||||
|
)..remove(tag);
|
||||||
|
state.tags.value = newTags;
|
||||||
|
},
|
||||||
|
child: Icon(
|
||||||
|
Icons.close,
|
||||||
|
size: 16,
|
||||||
|
color:
|
||||||
|
Theme.of(
|
||||||
|
context,
|
||||||
|
).colorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
// Tag input with autocomplete
|
||||||
|
TypeAheadField<SnPostTag>(
|
||||||
|
builder: (context, controller, focusNode) {
|
||||||
|
return TextField(
|
||||||
|
controller: controller,
|
||||||
|
focusNode: focusNode,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
hintText: 'addTag'.tr(),
|
||||||
|
border: InputBorder.none,
|
||||||
|
isCollapsed: true,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
onSubmitted: (value) {
|
||||||
|
state.tags.value = [...state.tags.value, value];
|
||||||
|
controller.clear();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
suggestionsCallback:
|
||||||
|
(pattern) => _fetchTagSuggestions(pattern, ref),
|
||||||
|
itemBuilder: (context, suggestion) {
|
||||||
|
return ListTile(
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(8)),
|
||||||
|
),
|
||||||
|
title: Text('#${suggestion.slug}'),
|
||||||
|
dense: true,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
onSelected: (suggestion) {
|
||||||
|
if (!state.tags.value.contains(suggestion.slug)) {
|
||||||
|
state.tags.value = [
|
||||||
|
...state.tags.value,
|
||||||
|
suggestion.slug,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
direction: VerticalDirection.down,
|
||||||
|
hideOnEmpty: true,
|
||||||
|
hideOnLoading: true,
|
||||||
|
debounceDuration: const Duration(milliseconds: 300),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Categories field
|
// Categories field
|
||||||
@@ -399,6 +517,25 @@ class ComposeSettingsSheet extends HookConsumerWidget {
|
|||||||
],
|
],
|
||||||
).padding(left: 16, right: 8),
|
).padding(left: 16, right: 8),
|
||||||
),
|
),
|
||||||
|
// Include current realm if it's not null and not in joined realms
|
||||||
|
if (currentRealm != null &&
|
||||||
|
!(userRealms.value ?? []).any(
|
||||||
|
(r) => r.id == currentRealm.id,
|
||||||
|
))
|
||||||
|
DropdownMenuItem<SnRealm?>(
|
||||||
|
value: currentRealm,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
ProfilePictureWidget(
|
||||||
|
fileId: currentRealm.picture?.id,
|
||||||
|
fallbackIcon: Symbols.workspaces,
|
||||||
|
radius: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(currentRealm.name),
|
||||||
|
],
|
||||||
|
).padding(left: 16, right: 8),
|
||||||
|
),
|
||||||
if (userRealms.hasValue)
|
if (userRealms.hasValue)
|
||||||
...(userRealms.value ?? []).map(
|
...(userRealms.value ?? []).map(
|
||||||
(realm) => DropdownMenuItem<SnRealm?>(
|
(realm) => DropdownMenuItem<SnRealm?>(
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import 'package:island/widgets/post/compose_poll.dart';
|
|||||||
import 'package:island/widgets/post/compose_recorder.dart';
|
import 'package:island/widgets/post/compose_recorder.dart';
|
||||||
import 'package:island/pods/file_pool.dart';
|
import 'package:island/pods/file_pool.dart';
|
||||||
import 'package:pasteboard/pasteboard.dart';
|
import 'package:pasteboard/pasteboard.dart';
|
||||||
import 'package:textfield_tags/textfield_tags.dart';
|
|
||||||
import 'package:island/talker.dart';
|
import 'package:island/talker.dart';
|
||||||
|
|
||||||
class ComposeState {
|
class ComposeState {
|
||||||
@@ -37,7 +36,7 @@ class ComposeState {
|
|||||||
final ValueNotifier<SnPublisher?> currentPublisher;
|
final ValueNotifier<SnPublisher?> currentPublisher;
|
||||||
final ValueNotifier<bool> submitting;
|
final ValueNotifier<bool> submitting;
|
||||||
final ValueNotifier<List<SnPostCategory>> categories;
|
final ValueNotifier<List<SnPostCategory>> categories;
|
||||||
StringTagController tagsController;
|
final ValueNotifier<List<String>> tags;
|
||||||
final ValueNotifier<SnRealm?> realm;
|
final ValueNotifier<SnRealm?> realm;
|
||||||
final ValueNotifier<SnPostEmbedView?> embedView;
|
final ValueNotifier<SnPostEmbedView?> embedView;
|
||||||
final String draftId;
|
final String draftId;
|
||||||
@@ -56,7 +55,7 @@ class ComposeState {
|
|||||||
required this.attachmentProgress,
|
required this.attachmentProgress,
|
||||||
required this.currentPublisher,
|
required this.currentPublisher,
|
||||||
required this.submitting,
|
required this.submitting,
|
||||||
required this.tagsController,
|
required this.tags,
|
||||||
required this.categories,
|
required this.categories,
|
||||||
required this.realm,
|
required this.realm,
|
||||||
required this.embedView,
|
required this.embedView,
|
||||||
@@ -90,14 +89,10 @@ class ComposeLogic {
|
|||||||
int postType = 0,
|
int postType = 0,
|
||||||
}) {
|
}) {
|
||||||
final id = draftId ?? DateTime.now().millisecondsSinceEpoch.toString();
|
final id = draftId ?? DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
final tagsController = StringTagController();
|
|
||||||
|
|
||||||
// Initialize tags from original post
|
// Initialize tags from original post
|
||||||
if (originalPost != null) {
|
final tags =
|
||||||
for (var tag in originalPost.tags) {
|
originalPost?.tags.map((tag) => tag.slug).toList() ?? <String>[];
|
||||||
tagsController.addTag(tag.slug);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize categories from original post
|
// Initialize categories from original post
|
||||||
final categories = originalPost?.categories ?? <SnPostCategory>[];
|
final categories = originalPost?.categories ?? <SnPostCategory>[];
|
||||||
@@ -129,7 +124,7 @@ class ComposeLogic {
|
|||||||
submitting: ValueNotifier<bool>(false),
|
submitting: ValueNotifier<bool>(false),
|
||||||
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
||||||
currentPublisher: ValueNotifier<SnPublisher?>(originalPost?.publisher),
|
currentPublisher: ValueNotifier<SnPublisher?>(originalPost?.publisher),
|
||||||
tagsController: tagsController,
|
tags: ValueNotifier<List<String>>(tags),
|
||||||
categories: ValueNotifier<List<SnPostCategory>>(categories),
|
categories: ValueNotifier<List<SnPostCategory>>(categories),
|
||||||
realm: ValueNotifier(originalPost?.realm),
|
realm: ValueNotifier(originalPost?.realm),
|
||||||
embedView: ValueNotifier<SnPostEmbedView?>(originalPost?.embedView),
|
embedView: ValueNotifier<SnPostEmbedView?>(originalPost?.embedView),
|
||||||
@@ -141,10 +136,7 @@ class ComposeLogic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static ComposeState createStateFromDraft(SnPost draft, {int postType = 0}) {
|
static ComposeState createStateFromDraft(SnPost draft, {int postType = 0}) {
|
||||||
final tagsController = StringTagController();
|
final tags = draft.tags.map((tag) => tag.slug).toList();
|
||||||
for (var x in draft.tags) {
|
|
||||||
tagsController.addTag(x.slug);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ComposeState(
|
return ComposeState(
|
||||||
attachments: ValueNotifier<List<UniversalFile>>(
|
attachments: ValueNotifier<List<UniversalFile>>(
|
||||||
@@ -158,7 +150,7 @@ class ComposeLogic {
|
|||||||
submitting: ValueNotifier<bool>(false),
|
submitting: ValueNotifier<bool>(false),
|
||||||
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
attachmentProgress: ValueNotifier<Map<int, double>>({}),
|
||||||
currentPublisher: ValueNotifier<SnPublisher?>(null),
|
currentPublisher: ValueNotifier<SnPublisher?>(null),
|
||||||
tagsController: tagsController,
|
tags: ValueNotifier<List<String>>(tags),
|
||||||
categories: ValueNotifier<List<SnPostCategory>>(draft.categories),
|
categories: ValueNotifier<List<SnPostCategory>>(draft.categories),
|
||||||
realm: ValueNotifier(draft.realm),
|
realm: ValueNotifier(draft.realm),
|
||||||
embedView: ValueNotifier<SnPostEmbedView?>(draft.embedView),
|
embedView: ValueNotifier<SnPostEmbedView?>(draft.embedView),
|
||||||
@@ -685,7 +677,7 @@ class ComposeLogic {
|
|||||||
'type': state.postType,
|
'type': state.postType,
|
||||||
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
||||||
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
||||||
'tags': state.tagsController.getTags,
|
'tags': state.tags.value,
|
||||||
'categories': state.categories.value.map((e) => e.slug).toList(),
|
'categories': state.categories.value.map((e) => e.slug).toList(),
|
||||||
if (state.realm.value != null) 'realm_id': state.realm.value?.id,
|
if (state.realm.value != null) 'realm_id': state.realm.value?.id,
|
||||||
if (state.pollId.value != null) 'poll_id': state.pollId.value,
|
if (state.pollId.value != null) 'poll_id': state.pollId.value,
|
||||||
@@ -781,7 +773,7 @@ class ComposeLogic {
|
|||||||
state.submitting.dispose();
|
state.submitting.dispose();
|
||||||
state.attachmentProgress.dispose();
|
state.attachmentProgress.dispose();
|
||||||
state.currentPublisher.dispose();
|
state.currentPublisher.dispose();
|
||||||
state.tagsController.dispose();
|
state.tags.dispose();
|
||||||
state.categories.dispose();
|
state.categories.dispose();
|
||||||
state.realm.dispose();
|
state.realm.dispose();
|
||||||
state.embedView.dispose();
|
state.embedView.dispose();
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ class ComposeStateUtils {
|
|||||||
state.attachmentProgress.value = {};
|
state.attachmentProgress.value = {};
|
||||||
|
|
||||||
// Clear tags
|
// Clear tags
|
||||||
state.tagsController.clearTags();
|
state.tags.value = [];
|
||||||
|
|
||||||
// Clear categories
|
// Clear categories
|
||||||
state.categories.value = [];
|
state.categories.value = [];
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class ComposeSubmitUtils {
|
|||||||
'type': state.postType,
|
'type': state.postType,
|
||||||
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
if (repliedPost != null) 'replied_post_id': repliedPost.id,
|
||||||
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
if (forwardedPost != null) 'forwarded_post_id': forwardedPost.id,
|
||||||
'tags': state.tagsController.getTags,
|
'tags': state.tags.value,
|
||||||
'categories': state.categories.value.map((e) => e.slug).toList(),
|
'categories': state.categories.value.map((e) => e.slug).toList(),
|
||||||
if (state.realm.value != null) 'realm_id': state.realm.value?.id,
|
if (state.realm.value != null) 'realm_id': state.realm.value?.id,
|
||||||
if (state.pollId.value != null) 'poll_id': state.pollId.value,
|
if (state.pollId.value != null) 'poll_id': state.pollId.value,
|
||||||
|
|||||||
@@ -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: 3.2.0+134
|
version: 3.3.0+135
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.7.2
|
sdk: ^3.7.2
|
||||||
|
|||||||
Reference in New Issue
Block a user