Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
738ed357bf
|
|||
|
0876ab9b74
|
|||
|
7071399cd8
|
|||
|
af23df6e48
|
|||
|
e7e7cc424b
|
|||
|
56ad8f60ea
|
|||
|
026dd3eb01
|
|||
|
72baf0ca5c
|
|||
|
82cb8c7ff9
|
|||
|
a266177628
|
|||
|
2474c7f97c
|
|||
|
1716afd66c
|
|||
|
78a3cd6dd2
|
|||
|
d655840e85
|
@@ -143,6 +143,7 @@
|
|||||||
"connectionConnected": "Connected",
|
"connectionConnected": "Connected",
|
||||||
"connectionDisconnected": "Disconnected",
|
"connectionDisconnected": "Disconnected",
|
||||||
"connectionReconnecting": "Reconnecting",
|
"connectionReconnecting": "Reconnecting",
|
||||||
|
"connectionServerDown": "Unable to Connect",
|
||||||
"accountConnections": "Account Connections",
|
"accountConnections": "Account Connections",
|
||||||
"accountConnectionsDescription": "Manage your external account connections",
|
"accountConnectionsDescription": "Manage your external account connections",
|
||||||
"accountConnectionAdd": "Add Connection",
|
"accountConnectionAdd": "Add Connection",
|
||||||
@@ -1020,6 +1021,7 @@
|
|||||||
"noResultsFound": "No results found",
|
"noResultsFound": "No results found",
|
||||||
"toggleFilters": "Toggle filters",
|
"toggleFilters": "Toggle filters",
|
||||||
"notableDayNext": "{} is in",
|
"notableDayNext": "{} is in",
|
||||||
|
"notableDayToday": "{} is today!",
|
||||||
"expandPoll": "Expand Poll",
|
"expandPoll": "Expand Poll",
|
||||||
"collapsePoll": "Collapse Poll",
|
"collapsePoll": "Collapse Poll",
|
||||||
"embedView": "Embed View",
|
"embedView": "Embed View",
|
||||||
@@ -1537,5 +1539,8 @@
|
|||||||
"settingsGroupedChatList": "Grouped Chat List",
|
"settingsGroupedChatList": "Grouped Chat List",
|
||||||
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
"settingsNotifyWithHaptic": "Notification with Haptic Feedback",
|
||||||
"settingsDashSearchEngine": "Search Engine for web",
|
"settingsDashSearchEngine": "Search Engine for web",
|
||||||
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query."
|
"settingsDashSearchEngineHelper": "Use %s as the placeholder for the query.",
|
||||||
|
"settingsDefaultScreen": "Default Screen",
|
||||||
|
"notableDayChristmas": "Christmas",
|
||||||
|
"notableDayNewYear": "New Year"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -999,6 +999,7 @@
|
|||||||
"noResultsFound": "未找到结果",
|
"noResultsFound": "未找到结果",
|
||||||
"toggleFilters": "切换过滤器",
|
"toggleFilters": "切换过滤器",
|
||||||
"notableDayNext": "距离 {} 还有",
|
"notableDayNext": "距离 {} 还有",
|
||||||
|
"notableDayToday": "今天是 {}!",
|
||||||
"expandPoll": "展开投票",
|
"expandPoll": "展开投票",
|
||||||
"collapsePoll": "折叠投票",
|
"collapsePoll": "折叠投票",
|
||||||
"embedView": "嵌入视图",
|
"embedView": "嵌入视图",
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ sealed class SnNotableDay with _$SnNotableDay {
|
|||||||
required DateTime date,
|
required DateTime date,
|
||||||
required String localName,
|
required String localName,
|
||||||
required String globalName,
|
required String globalName,
|
||||||
required String countryCode,
|
required String? countryCode,
|
||||||
|
required String? localizableKey,
|
||||||
required List<int> holidays,
|
required List<int> holidays,
|
||||||
}) = _SnNotableDay;
|
}) = _SnNotableDay;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ T _$identity<T>(T value) => value;
|
|||||||
/// @nodoc
|
/// @nodoc
|
||||||
mixin _$SnNotableDay {
|
mixin _$SnNotableDay {
|
||||||
|
|
||||||
DateTime get date; String get localName; String get globalName; String get countryCode; List<int> get holidays;
|
DateTime get date; String get localName; String get globalName; String? get countryCode; String? get localizableKey; List<int> get holidays;
|
||||||
/// Create a copy of SnNotableDay
|
/// Create a copy of SnNotableDay
|
||||||
/// 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)
|
||||||
@@ -28,16 +28,16 @@ $SnNotableDayCopyWith<SnNotableDay> get copyWith => _$SnNotableDayCopyWithImpl<S
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other.holidays, holidays));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.localizableKey, localizableKey) || other.localizableKey == localizableKey)&&const DeepCollectionEquality().equals(other.holidays, holidays));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,const DeepCollectionEquality().hash(holidays));
|
int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,localizableKey,const DeepCollectionEquality().hash(holidays));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, holidays: $holidays)';
|
return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, localizableKey: $localizableKey, holidays: $holidays)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ abstract mixin class $SnNotableDayCopyWith<$Res> {
|
|||||||
factory $SnNotableDayCopyWith(SnNotableDay value, $Res Function(SnNotableDay) _then) = _$SnNotableDayCopyWithImpl;
|
factory $SnNotableDayCopyWith(SnNotableDay value, $Res Function(SnNotableDay) _then) = _$SnNotableDayCopyWithImpl;
|
||||||
@useResult
|
@useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime date, String localName, String globalName, String countryCode, List<int> holidays
|
DateTime date, String localName, String globalName, String? countryCode, String? localizableKey, List<int> holidays
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -65,13 +65,14 @@ class _$SnNotableDayCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnNotableDay
|
/// Create a copy of SnNotableDay
|
||||||
/// 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? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = null,Object? holidays = null,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = freezed,Object? localizableKey = freezed,Object? holidays = null,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable
|
as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable
|
||||||
as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable
|
as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable
|
||||||
as String,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
|
as String,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
|
||||||
as String,holidays: null == holidays ? _self.holidays : holidays // ignore: cast_nullable_to_non_nullable
|
as String?,localizableKey: freezed == localizableKey ? _self.localizableKey : localizableKey // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,holidays: null == holidays ? _self.holidays : holidays // ignore: cast_nullable_to_non_nullable
|
||||||
as List<int>,
|
as List<int>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -154,10 +155,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date, String localName, String globalName, String countryCode, List<int> holidays)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date, String localName, String globalName, String? countryCode, String? localizableKey, List<int> holidays)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnNotableDay() when $default != null:
|
case _SnNotableDay() when $default != null:
|
||||||
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);case _:
|
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.localizableKey,_that.holidays);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -175,10 +176,10 @@ return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_t
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date, String localName, String globalName, String countryCode, List<int> holidays) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date, String localName, String globalName, String? countryCode, String? localizableKey, List<int> holidays) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnNotableDay():
|
case _SnNotableDay():
|
||||||
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);}
|
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.localizableKey,_that.holidays);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -192,10 +193,10 @@ return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_t
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date, String localName, String globalName, String countryCode, List<int> holidays)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date, String localName, String globalName, String? countryCode, String? localizableKey, List<int> holidays)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _SnNotableDay() when $default != null:
|
case _SnNotableDay() when $default != null:
|
||||||
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.holidays);case _:
|
return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_that.localizableKey,_that.holidays);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -207,13 +208,14 @@ return $default(_that.date,_that.localName,_that.globalName,_that.countryCode,_t
|
|||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
|
|
||||||
class _SnNotableDay implements SnNotableDay {
|
class _SnNotableDay implements SnNotableDay {
|
||||||
const _SnNotableDay({required this.date, required this.localName, required this.globalName, required this.countryCode, required final List<int> holidays}): _holidays = holidays;
|
const _SnNotableDay({required this.date, required this.localName, required this.globalName, required this.countryCode, required this.localizableKey, required final List<int> holidays}): _holidays = holidays;
|
||||||
factory _SnNotableDay.fromJson(Map<String, dynamic> json) => _$SnNotableDayFromJson(json);
|
factory _SnNotableDay.fromJson(Map<String, dynamic> json) => _$SnNotableDayFromJson(json);
|
||||||
|
|
||||||
@override final DateTime date;
|
@override final DateTime date;
|
||||||
@override final String localName;
|
@override final String localName;
|
||||||
@override final String globalName;
|
@override final String globalName;
|
||||||
@override final String countryCode;
|
@override final String? countryCode;
|
||||||
|
@override final String? localizableKey;
|
||||||
final List<int> _holidays;
|
final List<int> _holidays;
|
||||||
@override List<int> get holidays {
|
@override List<int> get holidays {
|
||||||
if (_holidays is EqualUnmodifiableListView) return _holidays;
|
if (_holidays is EqualUnmodifiableListView) return _holidays;
|
||||||
@@ -235,16 +237,16 @@ Map<String, dynamic> toJson() {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&const DeepCollectionEquality().equals(other._holidays, _holidays));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnNotableDay&&(identical(other.date, date) || other.date == date)&&(identical(other.localName, localName) || other.localName == localName)&&(identical(other.globalName, globalName) || other.globalName == globalName)&&(identical(other.countryCode, countryCode) || other.countryCode == countryCode)&&(identical(other.localizableKey, localizableKey) || other.localizableKey == localizableKey)&&const DeepCollectionEquality().equals(other._holidays, _holidays));
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,const DeepCollectionEquality().hash(_holidays));
|
int get hashCode => Object.hash(runtimeType,date,localName,globalName,countryCode,localizableKey,const DeepCollectionEquality().hash(_holidays));
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, holidays: $holidays)';
|
return 'SnNotableDay(date: $date, localName: $localName, globalName: $globalName, countryCode: $countryCode, localizableKey: $localizableKey, holidays: $holidays)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -255,7 +257,7 @@ abstract mixin class _$SnNotableDayCopyWith<$Res> implements $SnNotableDayCopyWi
|
|||||||
factory _$SnNotableDayCopyWith(_SnNotableDay value, $Res Function(_SnNotableDay) _then) = __$SnNotableDayCopyWithImpl;
|
factory _$SnNotableDayCopyWith(_SnNotableDay value, $Res Function(_SnNotableDay) _then) = __$SnNotableDayCopyWithImpl;
|
||||||
@override @useResult
|
@override @useResult
|
||||||
$Res call({
|
$Res call({
|
||||||
DateTime date, String localName, String globalName, String countryCode, List<int> holidays
|
DateTime date, String localName, String globalName, String? countryCode, String? localizableKey, List<int> holidays
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -272,13 +274,14 @@ class __$SnNotableDayCopyWithImpl<$Res>
|
|||||||
|
|
||||||
/// Create a copy of SnNotableDay
|
/// Create a copy of SnNotableDay
|
||||||
/// 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? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = null,Object? holidays = null,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? date = null,Object? localName = null,Object? globalName = null,Object? countryCode = freezed,Object? localizableKey = freezed,Object? holidays = null,}) {
|
||||||
return _then(_SnNotableDay(
|
return _then(_SnNotableDay(
|
||||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
|
||||||
as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable
|
as DateTime,localName: null == localName ? _self.localName : localName // ignore: cast_nullable_to_non_nullable
|
||||||
as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable
|
as String,globalName: null == globalName ? _self.globalName : globalName // ignore: cast_nullable_to_non_nullable
|
||||||
as String,countryCode: null == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
|
as String,countryCode: freezed == countryCode ? _self.countryCode : countryCode // ignore: cast_nullable_to_non_nullable
|
||||||
as String,holidays: null == holidays ? _self._holidays : holidays // ignore: cast_nullable_to_non_nullable
|
as String?,localizableKey: freezed == localizableKey ? _self.localizableKey : localizableKey // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,holidays: null == holidays ? _self._holidays : holidays // ignore: cast_nullable_to_non_nullable
|
||||||
as List<int>,
|
as List<int>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ _SnNotableDay _$SnNotableDayFromJson(Map<String, dynamic> json) =>
|
|||||||
date: DateTime.parse(json['date'] as String),
|
date: DateTime.parse(json['date'] as String),
|
||||||
localName: json['local_name'] as String,
|
localName: json['local_name'] as String,
|
||||||
globalName: json['global_name'] as String,
|
globalName: json['global_name'] as String,
|
||||||
countryCode: json['country_code'] as String,
|
countryCode: json['country_code'] as String?,
|
||||||
|
localizableKey: json['localizable_key'] as String?,
|
||||||
holidays: (json['holidays'] as List<dynamic>)
|
holidays: (json['holidays'] as List<dynamic>)
|
||||||
.map((e) => (e as num).toInt())
|
.map((e) => (e as num).toInt())
|
||||||
.toList(),
|
.toList(),
|
||||||
@@ -23,6 +24,7 @@ Map<String, dynamic> _$SnNotableDayToJson(_SnNotableDay instance) =>
|
|||||||
'local_name': instance.localName,
|
'local_name': instance.localName,
|
||||||
'global_name': instance.globalName,
|
'global_name': instance.globalName,
|
||||||
'country_code': instance.countryCode,
|
'country_code': instance.countryCode,
|
||||||
|
'localizable_key': instance.localizableKey,
|
||||||
'holidays': instance.holidays,
|
'holidays': instance.holidays,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
16
lib/models/fortune.dart
Normal file
16
lib/models/fortune.dart
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'fortune.g.dart';
|
||||||
|
part 'fortune.freezed.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
sealed class SnFortuneSaying with _$SnFortuneSaying {
|
||||||
|
const factory SnFortuneSaying({
|
||||||
|
required String content,
|
||||||
|
required String source,
|
||||||
|
required String language,
|
||||||
|
}) = _SnFortuneSaying;
|
||||||
|
|
||||||
|
factory SnFortuneSaying.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$SnFortuneSayingFromJson(json);
|
||||||
|
}
|
||||||
277
lib/models/fortune.freezed.dart
Normal file
277
lib/models/fortune.freezed.dart
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'fortune.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$SnFortuneSaying {
|
||||||
|
|
||||||
|
String get content; String get source; String get language;
|
||||||
|
/// Create a copy of SnFortuneSaying
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SnFortuneSayingCopyWith<SnFortuneSaying> get copyWith => _$SnFortuneSayingCopyWithImpl<SnFortuneSaying>(this as SnFortuneSaying, _$identity);
|
||||||
|
|
||||||
|
/// Serializes this SnFortuneSaying to a JSON map.
|
||||||
|
Map<String, dynamic> toJson();
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is SnFortuneSaying&&(identical(other.content, content) || other.content == content)&&(identical(other.source, source) || other.source == source)&&(identical(other.language, language) || other.language == language));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,content,source,language);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFortuneSaying(content: $content, source: $source, language: $language)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SnFortuneSayingCopyWith<$Res> {
|
||||||
|
factory $SnFortuneSayingCopyWith(SnFortuneSaying value, $Res Function(SnFortuneSaying) _then) = _$SnFortuneSayingCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String content, String source, String language
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SnFortuneSayingCopyWithImpl<$Res>
|
||||||
|
implements $SnFortuneSayingCopyWith<$Res> {
|
||||||
|
_$SnFortuneSayingCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final SnFortuneSaying _self;
|
||||||
|
final $Res Function(SnFortuneSaying) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFortuneSaying
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? content = null,Object? source = null,Object? language = null,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
content: null == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,source: null == source ? _self.source : source // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [SnFortuneSaying].
|
||||||
|
extension SnFortuneSayingPatterns on SnFortuneSaying {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _SnFortuneSaying value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _SnFortuneSaying value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying():
|
||||||
|
return $default(_that);}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _SnFortuneSaying value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( String content, String source, String language)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying() when $default != null:
|
||||||
|
return $default(_that.content,_that.source,_that.language);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( String content, String source, String language) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying():
|
||||||
|
return $default(_that.content,_that.source,_that.language);}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( String content, String source, String language)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _SnFortuneSaying() when $default != null:
|
||||||
|
return $default(_that.content,_that.source,_that.language);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
|
||||||
|
class _SnFortuneSaying implements SnFortuneSaying {
|
||||||
|
const _SnFortuneSaying({required this.content, required this.source, required this.language});
|
||||||
|
factory _SnFortuneSaying.fromJson(Map<String, dynamic> json) => _$SnFortuneSayingFromJson(json);
|
||||||
|
|
||||||
|
@override final String content;
|
||||||
|
@override final String source;
|
||||||
|
@override final String language;
|
||||||
|
|
||||||
|
/// Create a copy of SnFortuneSaying
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SnFortuneSayingCopyWith<_SnFortuneSaying> get copyWith => __$SnFortuneSayingCopyWithImpl<_SnFortuneSaying>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$SnFortuneSayingToJson(this, );
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _SnFortuneSaying&&(identical(other.content, content) || other.content == content)&&(identical(other.source, source) || other.source == source)&&(identical(other.language, language) || other.language == language));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,content,source,language);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'SnFortuneSaying(content: $content, source: $source, language: $language)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SnFortuneSayingCopyWith<$Res> implements $SnFortuneSayingCopyWith<$Res> {
|
||||||
|
factory _$SnFortuneSayingCopyWith(_SnFortuneSaying value, $Res Function(_SnFortuneSaying) _then) = __$SnFortuneSayingCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
String content, String source, String language
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SnFortuneSayingCopyWithImpl<$Res>
|
||||||
|
implements _$SnFortuneSayingCopyWith<$Res> {
|
||||||
|
__$SnFortuneSayingCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _SnFortuneSaying _self;
|
||||||
|
final $Res Function(_SnFortuneSaying) _then;
|
||||||
|
|
||||||
|
/// Create a copy of SnFortuneSaying
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? content = null,Object? source = null,Object? language = null,}) {
|
||||||
|
return _then(_SnFortuneSaying(
|
||||||
|
content: null == content ? _self.content : content // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,source: null == source ? _self.source : source // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,language: null == language ? _self.language : language // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
21
lib/models/fortune.g.dart
Normal file
21
lib/models/fortune.g.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'fortune.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_SnFortuneSaying _$SnFortuneSayingFromJson(Map<String, dynamic> json) =>
|
||||||
|
_SnFortuneSaying(
|
||||||
|
content: json['content'] as String,
|
||||||
|
source: json['source'] as String,
|
||||||
|
language: json['language'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$SnFortuneSayingToJson(_SnFortuneSaying instance) =>
|
||||||
|
<String, dynamic>{
|
||||||
|
'content': instance.content,
|
||||||
|
'source': instance.source,
|
||||||
|
'language': instance.language,
|
||||||
|
};
|
||||||
@@ -32,7 +32,6 @@ const kAppEnterToSend = 'app_enter_to_send';
|
|||||||
const kAppDefaultPoolId = 'app_default_pool_id';
|
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 kAppDisableAnimation = 'app_disable_animation';
|
const kAppDisableAnimation = 'app_disable_animation';
|
||||||
const kAppFabPosition = 'app_fab_position';
|
const kAppFabPosition = 'app_fab_position';
|
||||||
const kAppGroupedChatList = 'app_grouped_chat_list';
|
const kAppGroupedChatList = 'app_grouped_chat_list';
|
||||||
@@ -41,26 +40,13 @@ const kFeaturedPostsCollapsedId =
|
|||||||
const kAppFirstLaunchAt = 'app_first_launch_at';
|
const kAppFirstLaunchAt = 'app_first_launch_at';
|
||||||
const kAppAskedReview = 'app_asked_review';
|
const kAppAskedReview = 'app_asked_review';
|
||||||
const kAppDashSearchEngine = 'app_dash_search_engine';
|
const kAppDashSearchEngine = 'app_dash_search_engine';
|
||||||
|
const kAppDefaultScreen = 'app_default_screen';
|
||||||
|
|
||||||
const Map<String, FilterQuality> kImageQualityLevel = {
|
// Will be overrided by the ProviderScope
|
||||||
'settingsImageQualityLowest': FilterQuality.none,
|
|
||||||
'settingsImageQualityLow': FilterQuality.low,
|
|
||||||
'settingsImageQualityMedium': FilterQuality.medium,
|
|
||||||
'settingsImageQualityHigh': FilterQuality.high,
|
|
||||||
};
|
|
||||||
|
|
||||||
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
final sharedPreferencesProvider = Provider<SharedPreferences>((ref) {
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
});
|
});
|
||||||
|
|
||||||
final imageQualityProvider = Provider<FilterQuality>((ref) {
|
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
|
||||||
return kImageQualityLevel.values.elementAtOrNull(
|
|
||||||
prefs.getInt('app_image_quality') ?? 3,
|
|
||||||
) ??
|
|
||||||
FilterQuality.high;
|
|
||||||
});
|
|
||||||
|
|
||||||
final serverUrlProvider = Provider<String>((ref) {
|
final serverUrlProvider = Provider<String>((ref) {
|
||||||
final prefs = ref.watch(sharedPreferencesProvider);
|
final prefs = ref.watch(sharedPreferencesProvider);
|
||||||
return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
return prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||||
@@ -100,13 +86,13 @@ sealed class AppSettings with _$AppSettings {
|
|||||||
required String? defaultPoolId,
|
required String? defaultPoolId,
|
||||||
required String messageDisplayStyle,
|
required String messageDisplayStyle,
|
||||||
required String? themeMode,
|
required String? themeMode,
|
||||||
required bool useMaterial3,
|
|
||||||
required bool disableAnimation,
|
required bool disableAnimation,
|
||||||
required String fabPosition,
|
required String fabPosition,
|
||||||
required bool groupedChatList,
|
required bool groupedChatList,
|
||||||
required String? firstLaunchAt,
|
required String? firstLaunchAt,
|
||||||
required bool askedReview,
|
required bool askedReview,
|
||||||
required String? dashSearchEngine,
|
required String? dashSearchEngine,
|
||||||
|
required String? defaultScreen,
|
||||||
}) = _AppSettings;
|
}) = _AppSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,13 +118,13 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
defaultPoolId: prefs.getString(kAppDefaultPoolId),
|
defaultPoolId: prefs.getString(kAppDefaultPoolId),
|
||||||
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,
|
|
||||||
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
disableAnimation: prefs.getBool(kAppDisableAnimation) ?? false,
|
||||||
fabPosition: prefs.getString(kAppFabPosition) ?? 'center',
|
fabPosition: prefs.getString(kAppFabPosition) ?? 'center',
|
||||||
groupedChatList: prefs.getBool(kAppGroupedChatList) ?? false,
|
groupedChatList: prefs.getBool(kAppGroupedChatList) ?? false,
|
||||||
askedReview: prefs.getBool(kAppAskedReview) ?? false,
|
askedReview: prefs.getBool(kAppAskedReview) ?? false,
|
||||||
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
|
firstLaunchAt: prefs.getString(kAppFirstLaunchAt),
|
||||||
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
|
dashSearchEngine: prefs.getString(kAppDashSearchEngine),
|
||||||
|
defaultScreen: prefs.getString(kAppDefaultScreen),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +215,12 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
state = state.copyWith(customFonts: value);
|
state = state.copyWith(customFonts: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setDefaultScreen(String? value) {
|
||||||
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
|
prefs.setString(kAppDefaultScreen, value ?? 'dashboard');
|
||||||
|
state = state.copyWith(defaultScreen: value);
|
||||||
|
}
|
||||||
|
|
||||||
void setAppColorScheme(int? value) {
|
void setAppColorScheme(int? value) {
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
prefs.setInt(kAppColorSchemeStoreKey, value ?? 0);
|
prefs.setInt(kAppColorSchemeStoreKey, value ?? 0);
|
||||||
@@ -274,12 +266,6 @@ class AppSettingsNotifier extends _$AppSettingsNotifier {
|
|||||||
state = state.copyWith(cardTransparency: value);
|
state = state.copyWith(cardTransparency: value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setUseMaterial3(bool value) {
|
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
|
||||||
prefs.setBool(kMaterialYouToggleStoreKey, value);
|
|
||||||
state = state.copyWith(useMaterial3: value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCustomColors(ThemeColors? value) {
|
void setCustomColors(ThemeColors? value) {
|
||||||
final prefs = ref.read(sharedPreferencesProvider);
|
final prefs = ref.read(sharedPreferencesProvider);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
|||||||
@@ -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; bool get disableAnimation; String get fabPosition; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine;
|
String? get defaultPoolId; String get messageDisplayStyle; String? get themeMode; bool get disableAnimation; String get fabPosition; bool get groupedChatList; String? get firstLaunchAt; bool get askedReview; String? get dashSearchEngine; String? get defaultScreen;
|
||||||
/// 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.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(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)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(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.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine]);
|
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine)';
|
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -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 dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine
|
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -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? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = 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,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,}) {
|
@pragma('vm:prefer-inline') @override $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = 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? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
||||||
return _then(_self.copyWith(
|
return _then(_self.copyWith(
|
||||||
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -356,13 +356,13 @@ as double,cardTransparency: null == cardTransparency ? _self.cardTransparency :
|
|||||||
as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
||||||
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?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
||||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@@ -457,10 +457,10 @@ return $default(_that);case _:
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine)? $default,{required TResult orElse(),}) {final _that = this;
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine);case _:
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
||||||
return orElse();
|
return orElse();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -478,10 +478,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine) $default,) {final _that = this;
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen) $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings():
|
case _AppSettings():
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine);}
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);}
|
||||||
}
|
}
|
||||||
/// A variant of `when` that fallback to returning `null`
|
/// A variant of `when` that fallback to returning `null`
|
||||||
///
|
///
|
||||||
@@ -495,10 +495,10 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine)? $default,) {final _that = this;
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen)? $default,) {final _that = this;
|
||||||
switch (_that) {
|
switch (_that) {
|
||||||
case _AppSettings() when $default != null:
|
case _AppSettings() when $default != null:
|
||||||
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.useMaterial3,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine);case _:
|
return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_that.enterToSend,_that.appBarTransparent,_that.showBackgroundImage,_that.notifyWithHaptic,_that.customFonts,_that.appColorScheme,_that.customColors,_that.windowSize,_that.windowOpacity,_that.cardTransparency,_that.defaultPoolId,_that.messageDisplayStyle,_that.themeMode,_that.disableAnimation,_that.fabPosition,_that.groupedChatList,_that.firstLaunchAt,_that.askedReview,_that.dashSearchEngine,_that.defaultScreen);case _:
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -510,7 +510,7 @@ return $default(_that.dataSavingMode,_that.soundEffects,_that.festivalFeatures,_
|
|||||||
|
|
||||||
|
|
||||||
class _AppSettings implements AppSettings {
|
class _AppSettings implements AppSettings {
|
||||||
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, 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, required this.fabPosition, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine});
|
const _AppSettings({required this.dataSavingMode, required this.soundEffects, required this.festivalFeatures, required this.enterToSend, required this.appBarTransparent, required this.showBackgroundImage, required this.notifyWithHaptic, 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.disableAnimation, required this.fabPosition, required this.groupedChatList, required this.firstLaunchAt, required this.askedReview, required this.dashSearchEngine, required this.defaultScreen});
|
||||||
|
|
||||||
|
|
||||||
@override final bool dataSavingMode;
|
@override final bool dataSavingMode;
|
||||||
@@ -533,13 +533,13 @@ class _AppSettings implements AppSettings {
|
|||||||
@override final String? defaultPoolId;
|
@override final String? defaultPoolId;
|
||||||
@override final String messageDisplayStyle;
|
@override final String messageDisplayStyle;
|
||||||
@override final String? themeMode;
|
@override final String? themeMode;
|
||||||
@override final bool useMaterial3;
|
|
||||||
@override final bool disableAnimation;
|
@override final bool disableAnimation;
|
||||||
@override final String fabPosition;
|
@override final String fabPosition;
|
||||||
@override final bool groupedChatList;
|
@override final bool groupedChatList;
|
||||||
@override final String? firstLaunchAt;
|
@override final String? firstLaunchAt;
|
||||||
@override final bool askedReview;
|
@override final bool askedReview;
|
||||||
@override final String? dashSearchEngine;
|
@override final String? dashSearchEngine;
|
||||||
|
@override final String? defaultScreen;
|
||||||
|
|
||||||
/// 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.
|
||||||
@@ -551,16 +551,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.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(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)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine));
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _AppSettings&&(identical(other.dataSavingMode, dataSavingMode) || other.dataSavingMode == dataSavingMode)&&(identical(other.soundEffects, soundEffects) || other.soundEffects == soundEffects)&&(identical(other.festivalFeatures, festivalFeatures) || other.festivalFeatures == festivalFeatures)&&(identical(other.enterToSend, enterToSend) || other.enterToSend == enterToSend)&&(identical(other.appBarTransparent, appBarTransparent) || other.appBarTransparent == appBarTransparent)&&(identical(other.showBackgroundImage, showBackgroundImage) || other.showBackgroundImage == showBackgroundImage)&&(identical(other.notifyWithHaptic, notifyWithHaptic) || other.notifyWithHaptic == notifyWithHaptic)&&(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.disableAnimation, disableAnimation) || other.disableAnimation == disableAnimation)&&(identical(other.fabPosition, fabPosition) || other.fabPosition == fabPosition)&&(identical(other.groupedChatList, groupedChatList) || other.groupedChatList == groupedChatList)&&(identical(other.firstLaunchAt, firstLaunchAt) || other.firstLaunchAt == firstLaunchAt)&&(identical(other.askedReview, askedReview) || other.askedReview == askedReview)&&(identical(other.dashSearchEngine, dashSearchEngine) || other.dashSearchEngine == dashSearchEngine)&&(identical(other.defaultScreen, defaultScreen) || other.defaultScreen == defaultScreen));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,useMaterial3,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine]);
|
int get hashCode => Object.hashAll([runtimeType,dataSavingMode,soundEffects,festivalFeatures,enterToSend,appBarTransparent,showBackgroundImage,notifyWithHaptic,customFonts,appColorScheme,customColors,windowSize,windowOpacity,cardTransparency,defaultPoolId,messageDisplayStyle,themeMode,disableAnimation,fabPosition,groupedChatList,firstLaunchAt,askedReview,dashSearchEngine,defaultScreen]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, useMaterial3: $useMaterial3, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine)';
|
return 'AppSettings(dataSavingMode: $dataSavingMode, soundEffects: $soundEffects, festivalFeatures: $festivalFeatures, enterToSend: $enterToSend, appBarTransparent: $appBarTransparent, showBackgroundImage: $showBackgroundImage, notifyWithHaptic: $notifyWithHaptic, customFonts: $customFonts, appColorScheme: $appColorScheme, customColors: $customColors, windowSize: $windowSize, windowOpacity: $windowOpacity, cardTransparency: $cardTransparency, defaultPoolId: $defaultPoolId, messageDisplayStyle: $messageDisplayStyle, themeMode: $themeMode, disableAnimation: $disableAnimation, fabPosition: $fabPosition, groupedChatList: $groupedChatList, firstLaunchAt: $firstLaunchAt, askedReview: $askedReview, dashSearchEngine: $dashSearchEngine, defaultScreen: $defaultScreen)';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -571,7 +571,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 dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool useMaterial3, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine
|
bool dataSavingMode, bool soundEffects, bool festivalFeatures, bool enterToSend, bool appBarTransparent, bool showBackgroundImage, bool notifyWithHaptic, String? customFonts, int? appColorScheme, ThemeColors? customColors, Size? windowSize, double windowOpacity, double cardTransparency, String? defaultPoolId, String messageDisplayStyle, String? themeMode, bool disableAnimation, String fabPosition, bool groupedChatList, String? firstLaunchAt, bool askedReview, String? dashSearchEngine, String? defaultScreen
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -588,7 +588,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? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = 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,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,}) {
|
@override @pragma('vm:prefer-inline') $Res call({Object? dataSavingMode = null,Object? soundEffects = null,Object? festivalFeatures = null,Object? enterToSend = null,Object? appBarTransparent = null,Object? showBackgroundImage = null,Object? notifyWithHaptic = 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? disableAnimation = null,Object? fabPosition = null,Object? groupedChatList = null,Object? firstLaunchAt = freezed,Object? askedReview = null,Object? dashSearchEngine = freezed,Object? defaultScreen = freezed,}) {
|
||||||
return _then(_AppSettings(
|
return _then(_AppSettings(
|
||||||
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
dataSavingMode: null == dataSavingMode ? _self.dataSavingMode : dataSavingMode // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
as bool,soundEffects: null == soundEffects ? _self.soundEffects : soundEffects // ignore: cast_nullable_to_non_nullable
|
||||||
@@ -606,13 +606,13 @@ as double,cardTransparency: null == cardTransparency ? _self.cardTransparency :
|
|||||||
as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
as double,defaultPoolId: freezed == defaultPoolId ? _self.defaultPoolId : defaultPoolId // ignore: cast_nullable_to_non_nullable
|
||||||
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?,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,disableAnimation: null == disableAnimation ? _self.disableAnimation : disableAnimation // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
as bool,fabPosition: null == fabPosition ? _self.fabPosition : fabPosition // ignore: cast_nullable_to_non_nullable
|
||||||
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
as String,groupedChatList: null == groupedChatList ? _self.groupedChatList : groupedChatList // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
as bool,firstLaunchAt: freezed == firstLaunchAt ? _self.firstLaunchAt : firstLaunchAt // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
as String?,askedReview: null == askedReview ? _self.askedReview : askedReview // ignore: cast_nullable_to_non_nullable
|
||||||
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
as bool,dashSearchEngine: freezed == dashSearchEngine ? _self.dashSearchEngine : dashSearchEngine // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,defaultScreen: freezed == defaultScreen ? _self.defaultScreen : defaultScreen // ignore: cast_nullable_to_non_nullable
|
||||||
as String?,
|
as String?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ final class AppSettingsNotifierProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _$appSettingsNotifierHash() =>
|
String _$appSettingsNotifierHash() =>
|
||||||
r'ee6b67190f3db5d8cb8a9e438a444e91685927d4';
|
r'ef10d95a9f22e891ad6f5e0225e31508b3eb038e';
|
||||||
|
|
||||||
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
abstract class _$AppSettingsNotifier extends $Notifier<AppSettings> {
|
||||||
AppSettings build();
|
AppSettings build();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'dart:io';
|
|||||||
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_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
@@ -16,6 +17,36 @@ import 'package:island/talker.dart';
|
|||||||
|
|
||||||
import 'config.dart';
|
import 'config.dart';
|
||||||
|
|
||||||
|
part 'network.g.dart';
|
||||||
|
|
||||||
|
// Network status enum to track different states
|
||||||
|
enum NetworkStatus { online, notReady, maintenance, offline }
|
||||||
|
|
||||||
|
// Provider for network status using Riverpod v3 annotation
|
||||||
|
@riverpod
|
||||||
|
class NetworkStatusNotifier extends _$NetworkStatusNotifier {
|
||||||
|
@override
|
||||||
|
NetworkStatus build() {
|
||||||
|
return NetworkStatus.online;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOnline() {
|
||||||
|
state = NetworkStatus.online;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMaintenance() {
|
||||||
|
state = NetworkStatus.maintenance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOffline() {
|
||||||
|
state = NetworkStatus.offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setNotReady() {
|
||||||
|
state = NetworkStatus.notReady;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final imagePickerProvider = Provider((ref) => ImagePicker());
|
final imagePickerProvider = Provider((ref) => ImagePicker());
|
||||||
|
|
||||||
final userAgentProvider = FutureProvider<String>((ref) async {
|
final userAgentProvider = FutureProvider<String>((ref) async {
|
||||||
@@ -80,24 +111,66 @@ final apiClientProvider = Provider<Dio>((ref) {
|
|||||||
|
|
||||||
dio.interceptors.addAll([
|
dio.interceptors.addAll([
|
||||||
InterceptorsWrapper(
|
InterceptorsWrapper(
|
||||||
onRequest: (
|
onRequest:
|
||||||
RequestOptions options,
|
(RequestOptions options, RequestInterceptorHandler handler) async {
|
||||||
RequestInterceptorHandler handler,
|
try {
|
||||||
) async {
|
final token = await getToken(ref.watch(tokenProvider));
|
||||||
try {
|
if (token != null) {
|
||||||
final token = await getToken(ref.watch(tokenProvider));
|
options.headers['Authorization'] = 'AtField $token';
|
||||||
if (token != null) {
|
}
|
||||||
options.headers['Authorization'] = 'AtField $token';
|
} catch (err) {
|
||||||
}
|
// ignore
|
||||||
} catch (err) {
|
}
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
final userAgent = ref.read(userAgentProvider);
|
final userAgent = ref.read(userAgentProvider);
|
||||||
if (userAgent.value != null) {
|
if (userAgent.value != null) {
|
||||||
options.headers['User-Agent'] = userAgent.value;
|
options.headers['User-Agent'] = userAgent.value;
|
||||||
|
}
|
||||||
|
return handler.next(options);
|
||||||
|
},
|
||||||
|
onResponse: (response, handler) {
|
||||||
|
// Check for 503 status code (Service Unavailable/Maintenance)
|
||||||
|
if (response.statusCode == 503) {
|
||||||
|
final networkStatusNotifier = ref.read(
|
||||||
|
networkStatusProvider.notifier,
|
||||||
|
);
|
||||||
|
if (response.headers.value('X-NotReady') != null) {
|
||||||
|
networkStatusNotifier.setNotReady();
|
||||||
|
} else {
|
||||||
|
networkStatusNotifier.setMaintenance();
|
||||||
|
}
|
||||||
|
} else if (response.statusCode != null &&
|
||||||
|
response.statusCode! >= 200 &&
|
||||||
|
response.statusCode! < 300) {
|
||||||
|
// Set online status for successful responses
|
||||||
|
final networkStatusNotifier = ref.read(
|
||||||
|
networkStatusProvider.notifier,
|
||||||
|
);
|
||||||
|
networkStatusNotifier.setOnline();
|
||||||
}
|
}
|
||||||
return handler.next(options);
|
return handler.next(response);
|
||||||
|
},
|
||||||
|
onError: (error, handler) {
|
||||||
|
// Handle network errors and set offline status
|
||||||
|
if (error.type == DioExceptionType.connectionTimeout ||
|
||||||
|
error.type == DioExceptionType.receiveTimeout ||
|
||||||
|
error.type == DioExceptionType.sendTimeout ||
|
||||||
|
error.type == DioExceptionType.connectionError) {
|
||||||
|
final networkStatusNotifier = ref.read(
|
||||||
|
networkStatusProvider.notifier,
|
||||||
|
);
|
||||||
|
networkStatusNotifier.setOffline();
|
||||||
|
} else if (error.response?.statusCode == 503) {
|
||||||
|
final networkStatusNotifier = ref.read(
|
||||||
|
networkStatusProvider.notifier,
|
||||||
|
);
|
||||||
|
if (error.response?.headers.value('X-NotReady') != null) {
|
||||||
|
networkStatusNotifier.setNotReady();
|
||||||
|
} else {
|
||||||
|
networkStatusNotifier.setMaintenance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return handler.next(error);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TalkerDioLogger(
|
TalkerDioLogger(
|
||||||
|
|||||||
64
lib/pods/network.g.dart
Normal file
64
lib/pods/network.g.dart
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'network.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// RiverpodGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint, type=warning
|
||||||
|
|
||||||
|
@ProviderFor(NetworkStatusNotifier)
|
||||||
|
const networkStatusProvider = NetworkStatusNotifierProvider._();
|
||||||
|
|
||||||
|
final class NetworkStatusNotifierProvider
|
||||||
|
extends $NotifierProvider<NetworkStatusNotifier, NetworkStatus> {
|
||||||
|
const NetworkStatusNotifierProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'networkStatusProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$networkStatusNotifierHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
NetworkStatusNotifier create() => NetworkStatusNotifier();
|
||||||
|
|
||||||
|
/// {@macro riverpod.override_with_value}
|
||||||
|
Override overrideWithValue(NetworkStatus value) {
|
||||||
|
return $ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
providerOverride: $SyncValueProvider<NetworkStatus>(value),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$networkStatusNotifierHash() =>
|
||||||
|
r'6f08e3067fa5265432f28f64e10775e3039506c3';
|
||||||
|
|
||||||
|
abstract class _$NetworkStatusNotifier extends $Notifier<NetworkStatus> {
|
||||||
|
NetworkStatus build();
|
||||||
|
@$mustCallSuper
|
||||||
|
@override
|
||||||
|
void runBuild() {
|
||||||
|
final created = build();
|
||||||
|
final ref = this.ref as $Ref<NetworkStatus, NetworkStatus>;
|
||||||
|
final element =
|
||||||
|
ref.element
|
||||||
|
as $ClassProviderElement<
|
||||||
|
AnyNotifier<NetworkStatus, NetworkStatus>,
|
||||||
|
NetworkStatus,
|
||||||
|
Object?,
|
||||||
|
Object?
|
||||||
|
>;
|
||||||
|
element.handleValue(ref, created);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,10 +25,9 @@ ThemeSet createAppThemeSet(AppSettings settings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ThemeData createAppTheme(Brightness brightness, AppSettings settings) {
|
ThemeData createAppTheme(Brightness brightness, AppSettings settings) {
|
||||||
final seedColor =
|
final seedColor = settings.appColorScheme != null
|
||||||
settings.appColorScheme != null
|
? Color(settings.appColorScheme!)
|
||||||
? Color(settings.appColorScheme!)
|
: Colors.indigo;
|
||||||
: Colors.indigo;
|
|
||||||
|
|
||||||
var colorScheme = ColorScheme.fromSeed(
|
var colorScheme = ColorScheme.fromSeed(
|
||||||
seedColor: seedColor,
|
seedColor: seedColor,
|
||||||
@@ -38,33 +37,33 @@ ThemeData createAppTheme(Brightness brightness, AppSettings settings) {
|
|||||||
final customColors = settings.customColors;
|
final customColors = settings.customColors;
|
||||||
if (customColors != null) {
|
if (customColors != null) {
|
||||||
colorScheme = colorScheme.copyWith(
|
colorScheme = colorScheme.copyWith(
|
||||||
primary:
|
primary: customColors.primary != null
|
||||||
customColors.primary != null ? Color(customColors.primary!) : null,
|
? Color(customColors.primary!)
|
||||||
secondary:
|
: null,
|
||||||
customColors.secondary != null
|
secondary: customColors.secondary != null
|
||||||
? Color(customColors.secondary!)
|
? Color(customColors.secondary!)
|
||||||
: null,
|
: null,
|
||||||
tertiary:
|
tertiary: customColors.tertiary != null
|
||||||
customColors.tertiary != null ? Color(customColors.tertiary!) : null,
|
? Color(customColors.tertiary!)
|
||||||
surface:
|
: null,
|
||||||
customColors.surface != null ? Color(customColors.surface!) : null,
|
surface: customColors.surface != null
|
||||||
background:
|
? Color(customColors.surface!)
|
||||||
customColors.background != null
|
: null,
|
||||||
? Color(customColors.background!)
|
background: customColors.background != null
|
||||||
: null,
|
? Color(customColors.background!)
|
||||||
|
: null,
|
||||||
error: customColors.error != null ? Color(customColors.error!) : null,
|
error: customColors.error != null ? Color(customColors.error!) : null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final hasAppBarTransparent = settings.appBarTransparent;
|
final hasAppBarTransparent = settings.appBarTransparent;
|
||||||
final useM3 = settings.useMaterial3;
|
|
||||||
|
|
||||||
final inUseFonts =
|
final inUseFonts =
|
||||||
settings.customFonts?.split(',').map((ele) => ele.trim()).toList() ??
|
settings.customFonts?.split(',').map((ele) => ele.trim()).toList() ??
|
||||||
['Nunito'];
|
['Nunito'];
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
useMaterial3: useM3,
|
useMaterial3: true,
|
||||||
colorScheme: colorScheme,
|
colorScheme: colorScheme,
|
||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
fontFamily: inUseFonts.firstOrNull,
|
fontFamily: inUseFonts.firstOrNull,
|
||||||
@@ -78,10 +77,12 @@ ThemeData createAppTheme(Brightness brightness, AppSettings settings) {
|
|||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
elevation: hasAppBarTransparent ? 0 : null,
|
elevation: hasAppBarTransparent ? 0 : null,
|
||||||
backgroundColor:
|
backgroundColor: hasAppBarTransparent
|
||||||
hasAppBarTransparent ? Colors.transparent : colorScheme.primary,
|
? Colors.transparent
|
||||||
foregroundColor:
|
: colorScheme.primary,
|
||||||
hasAppBarTransparent ? colorScheme.onSurface : colorScheme.onPrimary,
|
foregroundColor: hasAppBarTransparent
|
||||||
|
? colorScheme.onSurface
|
||||||
|
: colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
cardTheme: CardThemeData(
|
cardTheme: CardThemeData(
|
||||||
color: colorScheme.surfaceContainer.withOpacity(
|
color: colorScheme.surfaceContainer.withOpacity(
|
||||||
|
|||||||
@@ -36,71 +36,41 @@ class UserInfoNotifier extends AsyncNotifier<SnAccount?> {
|
|||||||
}
|
}
|
||||||
return user;
|
return user;
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
if (!kIsWeb) {
|
if (error is DioException) {
|
||||||
if (error is DioException) {
|
if (error.response?.statusCode == 503) return null;
|
||||||
showOverlayDialog<bool>(
|
showOverlayDialog<bool>(
|
||||||
builder:
|
builder: (context, close) => AlertDialog(
|
||||||
(context, close) => AlertDialog(
|
title: Text('failedToLoadUserInfo'.tr()),
|
||||||
title: Text('failedToLoadUserInfo'.tr()),
|
content: Text(
|
||||||
content: Text(
|
[
|
||||||
[
|
(error.response?.statusCode == 401
|
||||||
(error.response?.statusCode == 401
|
? 'failedToLoadUserInfoUnauthorized'
|
||||||
? 'failedToLoadUserInfoUnauthorized'
|
: 'failedToLoadUserInfoNetwork')
|
||||||
: 'failedToLoadUserInfoNetwork')
|
.tr()
|
||||||
.tr()
|
.trim(),
|
||||||
.trim(),
|
'',
|
||||||
'',
|
'${error.response?.statusCode ?? 'Network Error'}',
|
||||||
'${error.response?.statusCode ?? 'Network Error'}',
|
if (error.response?.headers != null) error.response?.headers,
|
||||||
if (error.response?.headers != null)
|
if (error.response?.data != null)
|
||||||
error.response?.headers,
|
jsonEncode(error.response?.data),
|
||||||
if (error.response?.data != null)
|
].join('\n'),
|
||||||
jsonEncode(error.response?.data),
|
),
|
||||||
].join('\n'),
|
actions: [
|
||||||
),
|
TextButton(
|
||||||
actions: [
|
onPressed: () => close(false),
|
||||||
TextButton(
|
child: Text('okay'.tr()),
|
||||||
onPressed: () => close(false),
|
),
|
||||||
child: Text('okay'.tr()),
|
TextButton(
|
||||||
),
|
onPressed: () => close(true),
|
||||||
TextButton(
|
child: Text('retry'.tr()),
|
||||||
onPressed: () => close(true),
|
),
|
||||||
child: Text('retry'.tr()),
|
],
|
||||||
),
|
),
|
||||||
],
|
).then((value) {
|
||||||
),
|
if (value == true) {
|
||||||
).then((value) {
|
ref.invalidateSelf();
|
||||||
if (value == true) {
|
}
|
||||||
ref.invalidateSelf();
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
showOverlayDialog<bool>(
|
|
||||||
builder:
|
|
||||||
(context, close) => AlertDialog(
|
|
||||||
title: Text('failedToLoadUserInfo'.tr()),
|
|
||||||
content: Text(
|
|
||||||
[
|
|
||||||
'failedToLoadUserInfoNetwork'.tr(),
|
|
||||||
error.toString(),
|
|
||||||
].join('\n\n').trim(),
|
|
||||||
),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => close(false),
|
|
||||||
child: Text('okay'.tr()),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => close(true),
|
|
||||||
child: Text('retry'.tr()),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
).then((value) {
|
|
||||||
if (value == true) {
|
|
||||||
ref.invalidateSelf();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
talker.error(
|
talker.error(
|
||||||
"[UserInfo] Failed to fetch user info...",
|
"[UserInfo] Failed to fetch user info...",
|
||||||
|
|||||||
@@ -52,6 +52,11 @@ class WebSocketService {
|
|||||||
DateTime? _heartbeatAt;
|
DateTime? _heartbeatAt;
|
||||||
Duration? heartbeatDelay;
|
Duration? heartbeatDelay;
|
||||||
|
|
||||||
|
// Reconnection tracking
|
||||||
|
int _reconnectCount = 0;
|
||||||
|
DateTime? _reconnectWindowStart;
|
||||||
|
static const int _maxReconnectsPerMinute = 5;
|
||||||
|
|
||||||
Stream<WebSocketPacket> get dataStream => _streamController.stream;
|
Stream<WebSocketPacket> get dataStream => _streamController.stream;
|
||||||
Stream<WebSocketState> get statusStream => _statusStreamController.stream;
|
Stream<WebSocketState> get statusStream => _statusStreamController.stream;
|
||||||
|
|
||||||
@@ -79,8 +84,9 @@ class WebSocketService {
|
|||||||
_scheduleHeartbeat();
|
_scheduleHeartbeat();
|
||||||
_channel!.stream.listen(
|
_channel!.stream.listen(
|
||||||
(data) {
|
(data) {
|
||||||
final dataStr =
|
final dataStr = data is Uint8List
|
||||||
data is Uint8List ? utf8.decode(data) : data.toString();
|
? utf8.decode(data)
|
||||||
|
: data.toString();
|
||||||
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
final packet = WebSocketPacket.fromJson(jsonDecode(dataStr));
|
||||||
if (packet.type == 'error.dupe') {
|
if (packet.type == 'error.dupe') {
|
||||||
_statusStreamController.sink.add(WebSocketState.duplicateDevice());
|
_statusStreamController.sink.add(WebSocketState.duplicateDevice());
|
||||||
@@ -123,6 +129,35 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _scheduleReconnect() {
|
void _scheduleReconnect() {
|
||||||
|
// Check if we've exceeded the reconnect limit
|
||||||
|
final now = DateTime.now();
|
||||||
|
if (_reconnectWindowStart == null ||
|
||||||
|
now.difference(_reconnectWindowStart!).inMinutes >= 1) {
|
||||||
|
// Reset window if it's been more than 1 minute since the window started
|
||||||
|
_reconnectWindowStart = now;
|
||||||
|
_reconnectCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reconnectCount++;
|
||||||
|
|
||||||
|
if (_reconnectCount > _maxReconnectsPerMinute) {
|
||||||
|
talker.error(
|
||||||
|
'[WebSocket] Reconnect limit exceeded: $_maxReconnectsPerMinute reconnections in the last minute. Stopping auto-reconnect.',
|
||||||
|
);
|
||||||
|
_statusStreamController.sink.add(WebSocketState.serverDown());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_reconnectTimer?.cancel();
|
||||||
|
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
||||||
|
_statusStreamController.sink.add(WebSocketState.connecting());
|
||||||
|
connect(_ref);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void manualReconnect() {
|
||||||
|
_statusStreamController.sink.add(WebSocketState.connecting());
|
||||||
|
talker.info('[WebSocket] Manual reconnect triggered by user');
|
||||||
_reconnectTimer?.cancel();
|
_reconnectTimer?.cancel();
|
||||||
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
_reconnectTimer = Timer(const Duration(milliseconds: 500), () {
|
||||||
_statusStreamController.sink.add(WebSocketState.connecting());
|
_statusStreamController.sink.add(WebSocketState.connecting());
|
||||||
@@ -204,4 +239,9 @@ class WebSocketStateNotifier extends Notifier<WebSocketState> {
|
|||||||
_reconnectTimer?.cancel();
|
_reconnectTimer?.cancel();
|
||||||
state = const WebSocketState.disconnected();
|
state = const WebSocketState.disconnected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void manualReconnect() {
|
||||||
|
final service = ref.read(websocketProvider);
|
||||||
|
service.manualReconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import 'package:island/screens/files/file_detail.dart';
|
|||||||
import 'package:island/screens/posts/post_categories_list.dart';
|
import 'package:island/screens/posts/post_categories_list.dart';
|
||||||
import 'package:island/screens/posts/post_category_detail.dart';
|
import 'package:island/screens/posts/post_category_detail.dart';
|
||||||
import 'package:island/screens/posts/post_search.dart';
|
import 'package:island/screens/posts/post_search.dart';
|
||||||
|
import 'package:island/widgets/app_scaffold.dart';
|
||||||
import 'package:island/widgets/app_wrapper.dart';
|
import 'package:island/widgets/app_wrapper.dart';
|
||||||
import 'package:island/screens/tabs.dart';
|
import 'package:island/screens/tabs.dart';
|
||||||
import 'package:island/screens/explore.dart';
|
import 'package:island/screens/explore.dart';
|
||||||
@@ -121,7 +122,12 @@ final routerProvider = Provider<GoRouter>((ref) {
|
|||||||
GoRoute(
|
GoRoute(
|
||||||
name: 'logs',
|
name: 'logs',
|
||||||
path: '/logs',
|
path: '/logs',
|
||||||
builder: (context, state) => TalkerScreen(talker: talker),
|
builder: (context, state) => TalkerScreen(
|
||||||
|
talker: talker,
|
||||||
|
appBarTitle: 'Debug Logs',
|
||||||
|
appBarLeading: const PageBackButton(),
|
||||||
|
theme: TalkerScreenTheme.fromTheme(Theme.of(context)),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Web articles
|
// Web articles
|
||||||
|
|||||||
@@ -368,20 +368,22 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
if (!isWideScreen(context))
|
||||||
'icon': Symbols.files,
|
{
|
||||||
'title': 'files',
|
'icon': Symbols.files,
|
||||||
'onTap': () {
|
'title': 'files',
|
||||||
context.goNamed('files');
|
'onTap': () {
|
||||||
|
context.goNamed('files');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
if (!isWideScreen(context))
|
||||||
{
|
{
|
||||||
'icon': Symbols.group,
|
'icon': Symbols.groups_3,
|
||||||
'title': 'realms',
|
'title': 'realms',
|
||||||
'onTap': () {
|
'onTap': () {
|
||||||
context.goNamed('realmList');
|
context.goNamed('realmList');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'icon': Symbols.wallet,
|
'icon': Symbols.wallet,
|
||||||
'title': 'wallet',
|
'title': 'wallet',
|
||||||
@@ -418,67 +420,47 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return GridView.builder(
|
return Column(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
children: menuItems.map((item) {
|
||||||
shrinkWrap: true,
|
|
||||||
physics: NeverScrollableScrollPhysics(),
|
|
||||||
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
|
|
||||||
maxCrossAxisExtent: 80,
|
|
||||||
crossAxisSpacing: 8,
|
|
||||||
mainAxisSpacing: 8,
|
|
||||||
),
|
|
||||||
itemCount: menuItems.length,
|
|
||||||
itemBuilder: (context, index) {
|
|
||||||
final item = menuItems[index];
|
|
||||||
final icon = item['icon'] as IconData;
|
final icon = item['icon'] as IconData;
|
||||||
final title = item['title'] as String;
|
final title = item['title'] as String;
|
||||||
final badgeCount = item['badgeCount'] as int?;
|
final badgeCount = item['badgeCount'] as int?;
|
||||||
final onTap = item['onTap'] as VoidCallback?;
|
final onTap = item['onTap'] as VoidCallback?;
|
||||||
return Card(
|
return ListTile(
|
||||||
margin: EdgeInsets.zero,
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
child: Tooltip(
|
horizontal: 24,
|
||||||
message: title.tr(),
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
onTap: onTap,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Badge(
|
|
||||||
isLabelVisible:
|
|
||||||
badgeCount != null && badgeCount > 0,
|
|
||||||
label: Text(badgeCount.toString()),
|
|
||||||
child: Icon(icon, size: 28),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
|
dense: true,
|
||||||
|
leading: Badge(
|
||||||
|
isLabelVisible: badgeCount != null && badgeCount > 0,
|
||||||
|
label: Text(badgeCount.toString()),
|
||||||
|
child: Icon(icon, size: 24),
|
||||||
|
),
|
||||||
|
title: Text(title).tr(),
|
||||||
|
onTap: onTap,
|
||||||
);
|
);
|
||||||
},
|
}).toList(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 1).padding(vertical: 8),
|
const Divider(height: 1).padding(vertical: 8),
|
||||||
ListTile(
|
ListTile(
|
||||||
minTileHeight: 48,
|
|
||||||
leading: const Icon(Symbols.info),
|
leading: const Icon(Symbols.info),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
|
dense: true,
|
||||||
title: Text('about').tr(),
|
title: Text('about').tr(),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.pushNamed('about');
|
context.pushNamed('about');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
minTileHeight: 48,
|
|
||||||
leading: const Icon(Symbols.bug_report),
|
leading: const Icon(Symbols.bug_report),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
title: Text('debugOptions').tr(),
|
title: Text('debugOptions').tr(),
|
||||||
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
@@ -489,11 +471,11 @@ class AccountScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
minTileHeight: 48,
|
|
||||||
leading: const Icon(Symbols.logout),
|
leading: const Icon(Symbols.logout),
|
||||||
trailing: const Icon(Symbols.chevron_right),
|
trailing: const Icon(Symbols.chevron_right),
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
contentPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||||
title: Text('logout').tr(),
|
title: Text('logout').tr(),
|
||||||
|
dense: true,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final ws = ref.watch(websocketStateProvider.notifier);
|
final ws = ref.watch(websocketStateProvider.notifier);
|
||||||
final apiClient = ref.watch(apiClientProvider);
|
final apiClient = ref.watch(apiClientProvider);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import 'package:island/widgets/app_scaffold.dart';
|
|||||||
import 'package:island/widgets/notification_tile.dart';
|
import 'package:island/widgets/notification_tile.dart';
|
||||||
import 'package:island/widgets/post/post_featured.dart';
|
import 'package:island/widgets/post/post_featured.dart';
|
||||||
import 'package:island/widgets/check_in.dart';
|
import 'package:island/widgets/check_in.dart';
|
||||||
|
import 'package:island/models/activity.dart';
|
||||||
import 'package:island/screens/notification.dart';
|
import 'package:island/screens/notification.dart';
|
||||||
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
import 'package:material_symbols_icons/material_symbols_icons.dart';
|
||||||
import 'package:slide_countdown/slide_countdown.dart';
|
import 'package:slide_countdown/slide_countdown.dart';
|
||||||
@@ -229,7 +230,7 @@ class ClockCard extends HookConsumerWidget {
|
|||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final time = useState(DateTime.now());
|
final time = useState(DateTime.now());
|
||||||
final timer = useRef<Timer?>(null);
|
final timer = useRef<Timer?>(null);
|
||||||
final nextNotableDay = ref.watch(nextNotableDayProvider);
|
final notableDay = ref.watch(recentNotableDayProvider);
|
||||||
|
|
||||||
// Determine icon based on time of day
|
// Determine icon based on time of day
|
||||||
final int hour = time.value.hour;
|
final int hour = time.value.hour;
|
||||||
@@ -301,23 +302,13 @@ class ClockCard extends HookConsumerWidget {
|
|||||||
Row(
|
Row(
|
||||||
spacing: 5,
|
spacing: 5,
|
||||||
children: [
|
children: [
|
||||||
Text('notableDayNext')
|
notableDay.when(
|
||||||
.tr(
|
data: (day) => _buildNotableDayText(context, day!),
|
||||||
args: [
|
error: (err, _) =>
|
||||||
nextNotableDay.value?.localName ?? 'idk',
|
Text(err.toString()).fontSize(12),
|
||||||
],
|
loading: () =>
|
||||||
)
|
const Text('loading').tr().fontSize(12),
|
||||||
.fontSize(12),
|
),
|
||||||
if (nextNotableDay.value != null)
|
|
||||||
SlideCountdown(
|
|
||||||
decoration: const BoxDecoration(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
separatorStyle: const TextStyle(fontSize: 12),
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
duration: nextNotableDay.value?.date.difference(
|
|
||||||
DateTime.now(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -330,6 +321,42 @@ class ClockCard extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildNotableDayText(BuildContext context, SnNotableDay notableDay) {
|
||||||
|
final today = DateTime.now();
|
||||||
|
final isToday =
|
||||||
|
notableDay.date.year == today.year &&
|
||||||
|
notableDay.date.month == today.month &&
|
||||||
|
notableDay.date.day == today.day;
|
||||||
|
|
||||||
|
if (isToday) {
|
||||||
|
return Row(
|
||||||
|
spacing: 5,
|
||||||
|
children: [
|
||||||
|
Text('notableDayToday').tr(args: [notableDay.localName]).fontSize(12),
|
||||||
|
Icon(
|
||||||
|
Symbols.celebration_rounded,
|
||||||
|
size: 16,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Row(
|
||||||
|
spacing: 5,
|
||||||
|
children: [
|
||||||
|
Text('notableDayNext').tr(args: [notableDay.localName]).fontSize(12),
|
||||||
|
SlideCountdown(
|
||||||
|
decoration: const BoxDecoration(),
|
||||||
|
style: const TextStyle(fontSize: 12),
|
||||||
|
separatorStyle: const TextStyle(fontSize: 12),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
duration: notableDay.date.difference(DateTime.now()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotificationsCard extends HookConsumerWidget {
|
class NotificationsCard extends HookConsumerWidget {
|
||||||
@@ -493,65 +520,38 @@ class ChatListCard extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FortuneCard extends HookWidget {
|
class FortuneCard extends HookConsumerWidget {
|
||||||
const FortuneCard({super.key});
|
const FortuneCard({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final fortune = useMemoized(() {
|
final fortuneAsync = ref.watch(randomFortuneSayingProvider);
|
||||||
const fortunes = [
|
|
||||||
{'text': '有的人活着,但他已经死了。', 'author': '—— 鲁迅'},
|
|
||||||
{'text': '天行健,君子以自强不息。', 'author': '—— 《周易》'},
|
|
||||||
{'text': '路漫漫其修远兮,吾将上下而求索。', 'author': '—— 屈原'},
|
|
||||||
{'text': '学海无涯苦作舟。', 'author': '—— 韩愈'},
|
|
||||||
{'text': '天道酬勤。', 'author': '—— 古语'},
|
|
||||||
{'text': '书山有路勤为径,学海无涯苦作舟。', 'author': '—— 韩愈'},
|
|
||||||
{'text': '莫等闲,白了少年头,空悲切。', 'author': '—— 岳飞'},
|
|
||||||
{
|
|
||||||
'text': 'The best way to predict the future is to create it.',
|
|
||||||
'author': '— Peter Drucker',
|
|
||||||
},
|
|
||||||
{'text': 'Fortune favors the bold.', 'author': '— Virgil'},
|
|
||||||
{
|
|
||||||
'text': 'A journey of a thousand miles begins with a single step.',
|
|
||||||
'author': '— Lao Tzu',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text': 'The only way to do great work is to love what you do.',
|
|
||||||
'author': '— Steve Jobs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text': 'Believe you can and you\'re halfway there.',
|
|
||||||
'author': '— Theodore Roosevelt',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'text':
|
|
||||||
'The future belongs to those who believe in the beauty of their dreams.',
|
|
||||||
'author': '— Eleanor Roosevelt',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
return fortunes[math.Random().nextInt(fortunes.length)];
|
|
||||||
});
|
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: fortuneAsync.when(
|
||||||
spacing: 8,
|
loading: () => const Center(child: CircularProgressIndicator()),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
error: (error, stack) => Center(child: Text('Error: $error')),
|
||||||
children: [
|
data: (fortune) {
|
||||||
Expanded(
|
return Row(
|
||||||
child: Text(
|
spacing: 8,
|
||||||
fortune['text']!,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
maxLines: 2,
|
children: [
|
||||||
overflow: TextOverflow.fade,
|
Expanded(
|
||||||
),
|
child: Text(
|
||||||
),
|
fortune.content,
|
||||||
Text(fortune['author']!).bold(),
|
maxLines: 2,
|
||||||
],
|
overflow: TextOverflow.fade,
|
||||||
).padding(horizontal: 16),
|
),
|
||||||
|
),
|
||||||
|
Text('—— ${fortune.source}').bold(),
|
||||||
|
],
|
||||||
|
).padding(horizontal: 16);
|
||||||
|
},
|
||||||
|
),
|
||||||
).height(48);
|
).height(48);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -834,6 +834,50 @@ class SettingsScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Default screen settings
|
||||||
|
ListTile(
|
||||||
|
minLeadingWidth: 48,
|
||||||
|
title: Text('settingsDefaultScreen').tr(),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
|
leading: const Icon(Symbols.home),
|
||||||
|
trailing: DropdownButtonHideUnderline(
|
||||||
|
child: DropdownButton2<String>(
|
||||||
|
isExpanded: true,
|
||||||
|
items: [
|
||||||
|
DropdownMenuItem<String>(
|
||||||
|
value: 'dashboard',
|
||||||
|
child: Text('dashboard').tr().fontSize(14),
|
||||||
|
),
|
||||||
|
DropdownMenuItem<String>(
|
||||||
|
value: 'explore',
|
||||||
|
child: Text('explore').tr().fontSize(14),
|
||||||
|
),
|
||||||
|
DropdownMenuItem<String>(
|
||||||
|
value: 'chat',
|
||||||
|
child: Text('chat').tr().fontSize(14),
|
||||||
|
),
|
||||||
|
DropdownMenuItem<String>(
|
||||||
|
value: 'account',
|
||||||
|
child: Text('account').tr().fontSize(14),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
value: settings.defaultScreen ?? 'dashboard',
|
||||||
|
onChanged: (String? value) {
|
||||||
|
if (value != null) {
|
||||||
|
ref.read(appSettingsProvider.notifier).setDefaultScreen(value);
|
||||||
|
showSnackBar('settingsApplied'.tr());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
buttonStyleData: const ButtonStyleData(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 5),
|
||||||
|
height: 40,
|
||||||
|
width: 140,
|
||||||
|
),
|
||||||
|
menuItemStyleData: const MenuItemStyleData(height: 40),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// Dash search engine settings
|
// Dash search engine settings
|
||||||
ListTile(
|
ListTile(
|
||||||
isThreeLine: true,
|
isThreeLine: true,
|
||||||
|
|||||||
@@ -523,52 +523,113 @@ class _WebSocketIndicator extends HookConsumerWidget {
|
|||||||
final isDesktop =
|
final isDesktop =
|
||||||
!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux);
|
!kIsWeb && (Platform.isMacOS || Platform.isWindows || Platform.isLinux);
|
||||||
|
|
||||||
|
final devicePadding = MediaQuery.of(context).padding;
|
||||||
|
|
||||||
final user = ref.watch(userInfoProvider);
|
final user = ref.watch(userInfoProvider);
|
||||||
final websocketState = ref.watch(websocketStateProvider);
|
final websocketState = ref.watch(websocketStateProvider);
|
||||||
final indicatorHeight =
|
|
||||||
MediaQuery.of(context).padding.top + (isDesktop ? 27.5 : 25);
|
|
||||||
|
|
||||||
Color indicatorColor;
|
Color indicatorColor;
|
||||||
String indicatorText;
|
String indicatorText;
|
||||||
|
Widget indicatorIcon;
|
||||||
|
bool isInteractive = true;
|
||||||
|
double opacity = 0.0;
|
||||||
|
|
||||||
if (websocketState == WebSocketState.connected()) {
|
if (websocketState == WebSocketState.connected()) {
|
||||||
indicatorColor = Colors.green;
|
indicatorColor = Colors.green;
|
||||||
indicatorText = 'connectionConnected';
|
indicatorText = 'connectionConnected';
|
||||||
|
indicatorIcon = Icon(
|
||||||
|
key: ValueKey('ws_connected'),
|
||||||
|
Symbols.power,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
opacity = 0.0;
|
||||||
|
isInteractive = false;
|
||||||
} else if (websocketState == WebSocketState.connecting()) {
|
} else if (websocketState == WebSocketState.connecting()) {
|
||||||
indicatorColor = Colors.teal;
|
indicatorColor = Colors.teal;
|
||||||
indicatorText = 'connectionReconnecting';
|
indicatorText = 'connectionReconnecting';
|
||||||
|
indicatorIcon = SizedBox(
|
||||||
|
key: ValueKey('ws_connecting'),
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
|
||||||
|
strokeWidth: 2,
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
opacity = 1.0;
|
||||||
|
isInteractive = false;
|
||||||
|
} else if (websocketState == WebSocketState.serverDown()) {
|
||||||
|
indicatorColor = Colors.red;
|
||||||
|
indicatorText = 'connectionServerDown';
|
||||||
|
isInteractive = true;
|
||||||
|
indicatorIcon = Icon(
|
||||||
|
key: ValueKey('ws_server_down'),
|
||||||
|
Symbols.power_off,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
opacity = 1.0;
|
||||||
} else {
|
} else {
|
||||||
indicatorColor = Colors.red;
|
indicatorColor = Colors.red;
|
||||||
indicatorText = 'connectionDisconnected';
|
indicatorText = 'connectionDisconnected';
|
||||||
|
indicatorIcon = Icon(
|
||||||
|
key: ValueKey('ws_disconnected'),
|
||||||
|
Symbols.power_off,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16,
|
||||||
|
);
|
||||||
|
opacity = 1.0;
|
||||||
|
isInteractive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return AnimatedPositioned(
|
return Positioned(
|
||||||
duration: Duration(milliseconds: 1850),
|
top: devicePadding.top + (isDesktop ? 27.5 : 25),
|
||||||
top:
|
|
||||||
user.value == null ||
|
|
||||||
user.value == null ||
|
|
||||||
websocketState == WebSocketState.connected()
|
|
||||||
? -indicatorHeight
|
|
||||||
: 0,
|
|
||||||
curve: Curves.fastLinearToSlowEaseIn,
|
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: indicatorHeight,
|
|
||||||
child: IgnorePointer(
|
child: IgnorePointer(
|
||||||
child: Material(
|
ignoring: !isInteractive,
|
||||||
elevation:
|
child: Align(
|
||||||
user.value == null || websocketState == WebSocketState.connected()
|
alignment: Alignment.topCenter,
|
||||||
? 0
|
child: AnimatedOpacity(
|
||||||
: 4,
|
|
||||||
child: AnimatedContainer(
|
|
||||||
duration: Duration(milliseconds: 300),
|
duration: Duration(milliseconds: 300),
|
||||||
color: indicatorColor,
|
opacity: opacity,
|
||||||
child: Center(
|
child: Material(
|
||||||
child: Text(
|
elevation:
|
||||||
indicatorText,
|
user.value == null ||
|
||||||
style: TextStyle(color: Colors.white, fontSize: 16),
|
websocketState == WebSocketState.connected()
|
||||||
).tr(),
|
? 0
|
||||||
).padding(top: MediaQuery.of(context).padding.top),
|
: 4,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
ref.read(websocketStateProvider.notifier).manualReconnect();
|
||||||
|
},
|
||||||
|
child: Container(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: indicatorColor,
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: Duration(milliseconds: 300),
|
||||||
|
child: indicatorIcon,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
indicatorText,
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 13),
|
||||||
|
).tr(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,25 +33,43 @@ class AppWrapper extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final networkStateShowing = useState(false);
|
final networkStateShowing = useState(false);
|
||||||
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
|
||||||
final websocketState = ref.watch(websocketStateProvider);
|
final websocketState = ref.watch(websocketStateProvider);
|
||||||
|
final apiState = ref.watch(networkStatusProvider);
|
||||||
final isShowSnow = useState(false);
|
final isShowSnow = useState(false);
|
||||||
final isSnowGone = useState(false);
|
final isSnowGone = useState(false);
|
||||||
|
|
||||||
// Handle network status modal
|
// Handle network status modal
|
||||||
if (websocketState == WebSocketState.duplicateDevice() &&
|
useEffect(() {
|
||||||
!networkStateShowing.value) {
|
bool triedOpen = false;
|
||||||
networkStateShowing.value = true;
|
if (websocketState == WebSocketState.duplicateDevice() &&
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
!networkStateShowing.value &&
|
||||||
showModalBottomSheet(
|
!triedOpen) {
|
||||||
context: context,
|
networkStateShowing.value = true;
|
||||||
isScrollControlled: true,
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
isDismissible: false,
|
showModalBottomSheet(
|
||||||
builder: (context) =>
|
context: context,
|
||||||
NetworkStatusSheet(onReconnect: () => wsNotifier.connect()),
|
isScrollControlled: true,
|
||||||
).then((_) => networkStateShowing.value = false);
|
builder: (context) => NetworkStatusSheet(autoClose: true),
|
||||||
});
|
).then((_) => networkStateShowing.value = false);
|
||||||
}
|
});
|
||||||
|
triedOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (apiState != NetworkStatus.online &&
|
||||||
|
!networkStateShowing.value &&
|
||||||
|
!triedOpen) {
|
||||||
|
networkStateShowing.value = true;
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
builder: (context) => const NetworkStatusSheet(),
|
||||||
|
).then((_) => networkStateShowing.value = false);
|
||||||
|
});
|
||||||
|
triedOpen = true;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, [websocketState, apiState]);
|
||||||
|
|
||||||
// Initialize services and listeners
|
// Initialize services and listeners
|
||||||
useEffect(() {
|
useEffect(() {
|
||||||
@@ -127,6 +145,16 @@ class AppWrapper extends HookConsumerWidget {
|
|||||||
final settings = ref.watch(appSettingsProvider);
|
final settings = ref.watch(appSettingsProvider);
|
||||||
final settingsNotifier = ref.watch(appSettingsProvider.notifier);
|
final settingsNotifier = ref.watch(appSettingsProvider.notifier);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
if (settings.defaultScreen != null &&
|
||||||
|
settings.defaultScreen != 'dashboard') {
|
||||||
|
Future(() {
|
||||||
|
ref.read(routerProvider).goNamed(settings.defaultScreen!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}, []);
|
||||||
|
|
||||||
final now = DateTime.now();
|
final now = DateTime.now();
|
||||||
final doesShowSnow =
|
final doesShowSnow =
|
||||||
settings.festivalFeatures &&
|
settings.festivalFeatures &&
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:flutter_hooks/flutter_hooks.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';
|
||||||
|
import 'package:island/models/fortune.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/userinfo.dart';
|
import 'package:island/pods/userinfo.dart';
|
||||||
import 'package:island/screens/auth/captcha.dart';
|
import 'package:island/screens/auth/captcha.dart';
|
||||||
@@ -42,12 +43,50 @@ Future<SnNotableDay?> nextNotableDay(Ref ref) async {
|
|||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
try {
|
try {
|
||||||
final resp = await client.get('/pass/notable/me/next');
|
final resp = await client.get('/pass/notable/me/next');
|
||||||
return SnNotableDay.fromJson(resp.data);
|
final day = SnNotableDay.fromJson(resp.data);
|
||||||
|
if (day.localizableKey != null) {
|
||||||
|
final key = 'notableDay${day.localizableKey}';
|
||||||
|
if (key.trExists()) {
|
||||||
|
return day.copyWith(
|
||||||
|
localName: key.tr(),
|
||||||
|
date: day.date.toLocal().copyWith(hour: 0, second: 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return day.copyWith(date: day.date.toLocal().copyWith(hour: 0, second: 0));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<SnNotableDay?> recentNotableDay(Ref ref) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
try {
|
||||||
|
final resp = await client.get('/pass/notable/me/recent');
|
||||||
|
final day = SnNotableDay.fromJson(resp.data[0]);
|
||||||
|
if (day.localizableKey != null) {
|
||||||
|
final key = 'notableDay${day.localizableKey}';
|
||||||
|
if (key.trExists()) {
|
||||||
|
return day.copyWith(
|
||||||
|
localName: key.tr(),
|
||||||
|
date: day.date.toLocal().copyWith(hour: 0, second: 0),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return day.copyWith(date: day.date.toLocal().copyWith(hour: 0, second: 0));
|
||||||
|
} catch (err) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@riverpod
|
||||||
|
Future<SnFortuneSaying> randomFortuneSaying(Ref ref) async {
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/pass/fortune/random');
|
||||||
|
return SnFortuneSaying.fromJson(resp.data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
class CheckInWidget extends HookConsumerWidget {
|
class CheckInWidget extends HookConsumerWidget {
|
||||||
final EdgeInsets? margin;
|
final EdgeInsets? margin;
|
||||||
final VoidCallback? onChecked;
|
final VoidCallback? onChecked;
|
||||||
|
|||||||
@@ -86,4 +86,83 @@ final class NextNotableDayProvider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$nextNotableDayHash() => r'c8404308f6b0f581cc7df251bce8f3c5ac130245';
|
String _$nextNotableDayHash() => r'60d0546a086bdcb89c433c38133eb4197e4fb0a6';
|
||||||
|
|
||||||
|
@ProviderFor(recentNotableDay)
|
||||||
|
const recentNotableDayProvider = RecentNotableDayProvider._();
|
||||||
|
|
||||||
|
final class RecentNotableDayProvider
|
||||||
|
extends
|
||||||
|
$FunctionalProvider<
|
||||||
|
AsyncValue<SnNotableDay?>,
|
||||||
|
SnNotableDay?,
|
||||||
|
FutureOr<SnNotableDay?>
|
||||||
|
>
|
||||||
|
with $FutureModifier<SnNotableDay?>, $FutureProvider<SnNotableDay?> {
|
||||||
|
const RecentNotableDayProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'recentNotableDayProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$recentNotableDayHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$FutureProviderElement<SnNotableDay?> $createElement(
|
||||||
|
$ProviderPointer pointer,
|
||||||
|
) => $FutureProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<SnNotableDay?> create(Ref ref) {
|
||||||
|
return recentNotableDay(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$recentNotableDayHash() => r'780d0f0747d753c5d535d9c2413f8e68d457d974';
|
||||||
|
|
||||||
|
@ProviderFor(randomFortuneSaying)
|
||||||
|
const randomFortuneSayingProvider = RandomFortuneSayingProvider._();
|
||||||
|
|
||||||
|
final class RandomFortuneSayingProvider
|
||||||
|
extends
|
||||||
|
$FunctionalProvider<
|
||||||
|
AsyncValue<SnFortuneSaying>,
|
||||||
|
SnFortuneSaying,
|
||||||
|
FutureOr<SnFortuneSaying>
|
||||||
|
>
|
||||||
|
with $FutureModifier<SnFortuneSaying>, $FutureProvider<SnFortuneSaying> {
|
||||||
|
const RandomFortuneSayingProvider._()
|
||||||
|
: super(
|
||||||
|
from: null,
|
||||||
|
argument: null,
|
||||||
|
retry: null,
|
||||||
|
name: r'randomFortuneSayingProvider',
|
||||||
|
isAutoDispose: true,
|
||||||
|
dependencies: null,
|
||||||
|
$allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String debugGetCreateSourceHash() => _$randomFortuneSayingHash();
|
||||||
|
|
||||||
|
@$internal
|
||||||
|
@override
|
||||||
|
$FutureProviderElement<SnFortuneSaying> $createElement(
|
||||||
|
$ProviderPointer pointer,
|
||||||
|
) => $FutureProviderElement(pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<SnFortuneSaying> create(Ref ref) {
|
||||||
|
return randomFortuneSaying(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _$randomFortuneSayingHash() =>
|
||||||
|
r'861378dba8021e8555b568fb8e0390b2b24056f6';
|
||||||
|
|||||||
@@ -1,78 +1,227 @@
|
|||||||
|
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:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:island/pods/config.dart';
|
||||||
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
import 'package:island/pods/websocket.dart';
|
||||||
import 'package:material_symbols_icons/symbols.dart';
|
import 'package:material_symbols_icons/symbols.dart';
|
||||||
import 'package:island/widgets/content/sheet.dart';
|
import 'package:island/widgets/content/sheet.dart';
|
||||||
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class NetworkStatusSheet extends HookConsumerWidget {
|
class NetworkStatusSheet extends HookConsumerWidget {
|
||||||
final VoidCallback onReconnect;
|
final bool autoClose;
|
||||||
|
const NetworkStatusSheet({super.key, this.autoClose = false});
|
||||||
const NetworkStatusSheet({super.key, required this.onReconnect});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final ws = ref.watch(websocketProvider);
|
final ws = ref.watch(websocketProvider);
|
||||||
final wsState = ref.watch(websocketStateProvider);
|
final wsState = ref.watch(websocketStateProvider);
|
||||||
|
final apiState = ref.watch(networkStatusProvider);
|
||||||
|
final serverUrl = ref.watch(serverUrlProvider);
|
||||||
|
|
||||||
|
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
||||||
|
|
||||||
|
final checks = [
|
||||||
|
wsState == WebSocketState.connected(),
|
||||||
|
apiState == NetworkStatus.online,
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
if (!autoClose) return;
|
||||||
|
|
||||||
|
final checks = [
|
||||||
|
wsState == WebSocketState.connected(),
|
||||||
|
apiState == NetworkStatus.online,
|
||||||
|
];
|
||||||
|
if (!checks.any((e) => !e)) {
|
||||||
|
Future.delayed(Duration(seconds: 3), () {
|
||||||
|
if (context.mounted) Navigator.of(context).pop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [wsState, apiState]);
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
heightFactor: 0.4,
|
heightFactor: 0.6,
|
||||||
titleText:
|
titleText: !checks.any((e) => !e)
|
||||||
wsState == WebSocketState.connected()
|
? 'Connection Status'
|
||||||
? 'Connection Status'
|
: 'Connection Issues',
|
||||||
: 'Connection Issue',
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
spacing: 4,
|
||||||
children: [
|
children: [
|
||||||
wsState.when(
|
Container(
|
||||||
connected:
|
decoration: BoxDecoration(
|
||||||
() => Text(
|
borderRadius: BorderRadius.circular(12),
|
||||||
'Connected to server',
|
color: !checks.any((e) => !e)
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
? Colors.green.withOpacity(0.1)
|
||||||
),
|
: Colors.red.withOpacity(0.1),
|
||||||
connecting:
|
),
|
||||||
() => Text(
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
'Connecting to server...',
|
margin: const EdgeInsets.only(bottom: 8),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
child: Column(
|
||||||
),
|
mainAxisSize: MainAxisSize.min,
|
||||||
disconnected:
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
() => Text(
|
children: [
|
||||||
'Disconnected from server',
|
Text('overview').tr().bold(),
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
Column(
|
||||||
),
|
spacing: 8,
|
||||||
serverDown:
|
mainAxisSize: MainAxisSize.min,
|
||||||
() => Text(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
'The server is not available right now... Please try again later...',
|
children: [
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
if (!checks.any((e) => !e))
|
||||||
),
|
Text('Everything is operational.'),
|
||||||
duplicateDevice:
|
if (!checks[0])
|
||||||
() => Text(
|
Text(
|
||||||
'Another device has connected with the same account.',
|
'WebSocket is disconnected. Realtime updates are not available. You can try tap the reconnect button below to try connect again.',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
),
|
||||||
),
|
if (!checks[1])
|
||||||
error:
|
...([
|
||||||
(message) => Text(
|
Text(
|
||||||
'Connection error: $message',
|
'API is unreachable, you can try again later. If the issue persists, please contact support. Or you can check the service status.',
|
||||||
style: Theme.of(context).textTheme.bodyLarge,
|
),
|
||||||
|
InkWell(
|
||||||
|
onTap: () {
|
||||||
|
launchUrlString("https://status.solsynth.dev");
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
'Check Service Status',
|
||||||
|
).textColor(Colors.blueAccent).bold(),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
Row(
|
||||||
if (ws.heartbeatDelay != null)
|
spacing: 8,
|
||||||
Text(
|
children: [
|
||||||
'Last heartbeat: ${ws.heartbeatDelay!.inMilliseconds}ms',
|
Text('WebSocket').bold(),
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
wsState.when(
|
||||||
),
|
connected: () => Text('connectionConnected').tr(),
|
||||||
const SizedBox(height: 24),
|
connecting: () => Text('connectionReconnecting').tr(),
|
||||||
Center(
|
disconnected: () => Text('connectionDisconnected').tr(),
|
||||||
child: FilledButton.icon(
|
serverDown: () => Text('connectionServerDown').tr(),
|
||||||
icon: const Icon(Symbols.wifi),
|
duplicateDevice: () => Text(
|
||||||
label: const Text('Reconnect'),
|
'Another device has connected with the same account.',
|
||||||
onPressed: () {
|
),
|
||||||
onReconnect();
|
error: (message) => Text('Connection error: $message'),
|
||||||
Navigator.pop(context);
|
),
|
||||||
},
|
if (ws.heartbeatDelay != null)
|
||||||
),
|
Text('${ws.heartbeatDelay!.inMilliseconds}ms'),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: wsState.when(
|
||||||
|
connected: () => Icon(
|
||||||
|
Symbols.check_circle,
|
||||||
|
key: ValueKey(WebSocketState.connected),
|
||||||
|
color: Colors.green,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
connecting: () => Icon(
|
||||||
|
Symbols.sync,
|
||||||
|
key: ValueKey(WebSocketState.connecting),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
disconnected: () => Icon(
|
||||||
|
Symbols.wifi_off,
|
||||||
|
key: ValueKey(WebSocketState.disconnected),
|
||||||
|
color: Colors.grey,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
serverDown: () => Icon(
|
||||||
|
Symbols.cloud_off,
|
||||||
|
key: ValueKey(WebSocketState.serverDown),
|
||||||
|
color: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
duplicateDevice: () => Icon(
|
||||||
|
Symbols.devices,
|
||||||
|
key: ValueKey(WebSocketState.duplicateDevice),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
error: (message) => Icon(
|
||||||
|
Symbols.error,
|
||||||
|
key: ValueKey(WebSocketState.error),
|
||||||
|
color: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Text('API').bold(),
|
||||||
|
Text(
|
||||||
|
apiState == NetworkStatus.online
|
||||||
|
? 'Online'
|
||||||
|
: apiState == NetworkStatus.notReady
|
||||||
|
? 'Not Ready'
|
||||||
|
: apiState == NetworkStatus.maintenance
|
||||||
|
? 'Under Maintenance'
|
||||||
|
: 'Offline',
|
||||||
|
),
|
||||||
|
AnimatedSwitcher(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: apiState == NetworkStatus.online
|
||||||
|
? Icon(
|
||||||
|
Symbols.check_circle,
|
||||||
|
key: ValueKey(NetworkStatus.online),
|
||||||
|
color: Colors.green,
|
||||||
|
size: 16,
|
||||||
|
)
|
||||||
|
: apiState == NetworkStatus.notReady
|
||||||
|
? Icon(
|
||||||
|
Symbols.warning,
|
||||||
|
key: ValueKey(NetworkStatus.notReady),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
)
|
||||||
|
: apiState == NetworkStatus.maintenance
|
||||||
|
? Icon(
|
||||||
|
Symbols.construction,
|
||||||
|
key: ValueKey(NetworkStatus.maintenance),
|
||||||
|
color: Colors.orange,
|
||||||
|
size: 16,
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
Symbols.cloud_off,
|
||||||
|
key: ValueKey(NetworkStatus.offline),
|
||||||
|
color: Colors.red,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Text('API Server').bold(),
|
||||||
|
Expanded(child: Text(serverUrl)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
FilledButton.icon(
|
||||||
|
icon: const Icon(Symbols.wifi),
|
||||||
|
label: const Text('Reconnect'),
|
||||||
|
onPressed: () {
|
||||||
|
wsNotifier.manualReconnect();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import 'package:gap/gap.dart';
|
|||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:island/pods/message.dart';
|
import 'package:island/pods/message.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
import 'package:island/pods/websocket.dart';
|
|
||||||
import 'package:island/services/update_service.dart';
|
import 'package:island/services/update_service.dart';
|
||||||
import 'package:island/widgets/alert.dart';
|
import 'package:island/widgets/alert.dart';
|
||||||
import 'package:island/widgets/content/network_status_sheet.dart';
|
import 'package:island/widgets/content/network_status_sheet.dart';
|
||||||
@@ -67,8 +66,6 @@ class DebugSheet extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final wsNotifier = ref.watch(websocketStateProvider.notifier);
|
|
||||||
|
|
||||||
return SheetScaffold(
|
return SheetScaffold(
|
||||||
titleText: 'Debug',
|
titleText: 'Debug',
|
||||||
heightFactor: 0.6,
|
heightFactor: 0.6,
|
||||||
@@ -111,10 +108,7 @@ class DebugSheet extends HookConsumerWidget {
|
|||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
builder:
|
builder: (context) => NetworkStatusSheet(),
|
||||||
(context) => NetworkStatusSheet(
|
|
||||||
onReconnect: () => wsNotifier.connect(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -78,28 +78,24 @@ class FileItem extends HookConsumerWidget {
|
|||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
await Navigator.of(context).push(
|
await Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder:
|
builder: (context) => Scaffold(
|
||||||
(context) => Scaffold(
|
appBar: AppBar(
|
||||||
appBar: AppBar(
|
title: Text(file.relativePath),
|
||||||
title: Text(file.relativePath),
|
backgroundColor: Colors.transparent,
|
||||||
backgroundColor: Colors.transparent,
|
elevation: 0,
|
||||||
elevation: 0,
|
),
|
||||||
),
|
extendBodyBehindAppBar: true,
|
||||||
extendBodyBehindAppBar: true,
|
backgroundColor: Colors.black,
|
||||||
backgroundColor: Colors.black,
|
body: PhotoView(
|
||||||
body: PhotoView(
|
imageProvider: CachedNetworkImageProvider(
|
||||||
imageProvider: CachedNetworkImageProvider(
|
imageUrl,
|
||||||
imageUrl,
|
headers: token != null
|
||||||
headers:
|
? {'Authorization': 'AtField $token'}
|
||||||
token != null
|
: null,
|
||||||
? {'Authorization': 'AtField $token'}
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
heroAttributes: PhotoViewHeroAttributes(
|
|
||||||
tag: file.relativePath,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
heroAttributes: PhotoViewHeroAttributes(tag: file.relativePath),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -107,7 +103,16 @@ class FileItem extends HookConsumerWidget {
|
|||||||
|
|
||||||
Future<void> _openFile(BuildContext context, WidgetRef ref) async {
|
Future<void> _openFile(BuildContext context, WidgetRef ref) async {
|
||||||
final ext = file.relativePath.split('.').last.toLowerCase();
|
final ext = file.relativePath.split('.').last.toLowerCase();
|
||||||
final isImage = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'].contains(ext);
|
final isImage = [
|
||||||
|
'jpg',
|
||||||
|
'jpeg',
|
||||||
|
'png',
|
||||||
|
'gif',
|
||||||
|
'webp',
|
||||||
|
'bmp',
|
||||||
|
'ico',
|
||||||
|
'svg',
|
||||||
|
].contains(ext);
|
||||||
|
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
await _showImageViewer(context, ref);
|
await _showImageViewer(context, ref);
|
||||||
@@ -182,41 +187,40 @@ class FileItem extends HookConsumerWidget {
|
|||||||
: '${(file.size / 1024).toStringAsFixed(1)} KB',
|
: '${(file.size / 1024).toStringAsFixed(1)} KB',
|
||||||
),
|
),
|
||||||
trailing: PopupMenuButton<String>(
|
trailing: PopupMenuButton<String>(
|
||||||
itemBuilder:
|
itemBuilder: (context) => [
|
||||||
(context) => [
|
PopupMenuItem(
|
||||||
PopupMenuItem(
|
value: 'download',
|
||||||
value: 'download',
|
child: Row(
|
||||||
child: Row(
|
children: [
|
||||||
children: [
|
const Icon(Symbols.download),
|
||||||
const Icon(Symbols.download),
|
const Gap(16),
|
||||||
const Gap(16),
|
Text('Download'),
|
||||||
Text('Download'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (!file.isDirectory) ...[
|
|
||||||
PopupMenuItem(
|
|
||||||
value: 'edit',
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Icon(Symbols.edit),
|
|
||||||
const Gap(16),
|
|
||||||
Text('Open'),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
PopupMenuItem(
|
),
|
||||||
value: 'delete',
|
),
|
||||||
child: Row(
|
if (!file.isDirectory) ...[
|
||||||
children: [
|
PopupMenuItem(
|
||||||
const Icon(Symbols.delete, color: Colors.red),
|
value: 'edit',
|
||||||
const Gap(16),
|
child: Row(
|
||||||
Text('Delete').textColor(Colors.red),
|
children: [
|
||||||
],
|
const Icon(Symbols.edit),
|
||||||
),
|
const Gap(16),
|
||||||
|
Text('Open'),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
|
],
|
||||||
|
PopupMenuItem(
|
||||||
|
value: 'delete',
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Symbols.delete, color: Colors.red),
|
||||||
|
const Gap(16),
|
||||||
|
Text('Delete').textColor(Colors.red),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
onSelected: (value) async {
|
onSelected: (value) async {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case 'download':
|
case 'download':
|
||||||
@@ -228,23 +232,22 @@ class FileItem extends HookConsumerWidget {
|
|||||||
case 'delete':
|
case 'delete':
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder:
|
builder: (context) => AlertDialog(
|
||||||
(context) => AlertDialog(
|
title: const Text('Delete File'),
|
||||||
title: const Text('Delete File'),
|
content: Text(
|
||||||
content: Text(
|
'Are you sure you want to delete "${file.relativePath}"?',
|
||||||
'Are you sure you want to delete "${file.relativePath}"?',
|
),
|
||||||
),
|
actions: [
|
||||||
actions: [
|
TextButton(
|
||||||
TextButton(
|
onPressed: () => Navigator.of(context).pop(false),
|
||||||
onPressed: () => Navigator.of(context).pop(false),
|
child: const Text('Cancel'),
|
||||||
child: const Text('Cancel'),
|
|
||||||
),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Navigator.of(context).pop(true),
|
|
||||||
child: const Text('Delete'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
|
child: const Text('Delete'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (confirmed == true) {
|
if (confirmed == true) {
|
||||||
|
|||||||
@@ -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.5.0+155
|
version: 3.5.0+156
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.8.0
|
sdk: ^3.8.0
|
||||||
|
|||||||
Reference in New Issue
Block a user