feat: citizen news support

This commit is contained in:
xkeyC 2025-10-26 17:44:55 +08:00
parent 8d635827c4
commit c2a512699c
18 changed files with 1747 additions and 696 deletions

23
lib/api/news_api.dart Normal file
View File

@ -0,0 +1,23 @@
import 'dart:convert';
import '../common/conf/url_conf.dart';
import '../common/io/rs_http.dart';
import '../common/utils/log.dart';
import '../data/citizen_news_data.dart';
import 'api.dart';
class NewsApi {
static Future<CitizenNewsData?> getLatest() async {
try {
final data = await RSHttp.getText(
"${URLConf.newsApiHome}/api/latest",
withCustomDns: await Api.isUseInternalDNS(),
);
final map = json.decode(data);
return CitizenNewsData.fromJson(map);
} catch (e) {
dPrint("getLatestNews error: $e");
}
return null;
}
}

View File

@ -1,25 +0,0 @@
import 'dart:io';
import 'package:dart_rss/dart_rss.dart';
import 'package:starcitizen_doctor/common/io/rs_http.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart';
class RSSApi {
static Future<List<RssItem>> getRssVideo() async {
final r = await RSHttp.getText(URLConf.rssVideoUrl);
final f = RssFeed.parse(r);
return f.items.sublist(0, 8);
}
static Future<List<RssItem>> getRssText() async {
final r2 = await RSHttp.getText(URLConf.rssTextUrl2);
final r2f = RssFeed.parse(r2);
final items = r2f.items;
items.sort((a, b) {
final aDate = HttpDate.parse(a.pubDate ?? "").millisecondsSinceEpoch;
final bDate = HttpDate.parse(b.pubDate ?? "").millisecondsSinceEpoch;
return bDate - aDate;
});
return items;
}
}

View File

@ -7,7 +7,7 @@ import 'package:starcitizen_doctor/common/utils/log.dart';
class URLConf { class URLConf {
/// HOME API /// HOME API
static String gitApiHome = "https://git.scbox.xkeyc.cn"; static String gitApiHome = "https://git.scbox.xkeyc.cn";
static String rssApiHome = "https://rss.scbox.xkeyc.cn"; static String newsApiHome = "https://scbox.citizenwiki.cn";
static const String analyticsApiHome = "https://scbox.org"; static const String analyticsApiHome = "https://scbox.org";
static bool isUrlCheckPass = false; static bool isUrlCheckPass = false;
@ -15,31 +15,22 @@ class URLConf {
/// URLS /// URLS
static String get giteaAttachmentsUrl => "$gitApiHome/SCToolBox/Release"; static String get giteaAttachmentsUrl => "$gitApiHome/SCToolBox/Release";
static String get gitlabLocalizationUrl => static String get gitlabLocalizationUrl => "$gitApiHome/SCToolBox/LocalizationData";
"$gitApiHome/SCToolBox/LocalizationData";
static String get gitApiRSILauncherEnhanceUrl => static String get gitApiRSILauncherEnhanceUrl => "$gitApiHome/SCToolBox/RSILauncherEnhance";
"$gitApiHome/SCToolBox/RSILauncherEnhance";
static String get apiRepoPath => "$gitApiHome/SCToolBox/api/raw/branch/main"; static String get apiRepoPath => "$gitApiHome/SCToolBox/api/raw/branch/main";
static String get gitlabApiPath => "$gitApiHome/api/v1/"; static String get gitlabApiPath => "$gitApiHome/api/v1/";
static String get webTranslateHomeUrl => static String get webTranslateHomeUrl => "$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
"$gitApiHome/SCToolBox/ScWeb_Chinese_Translate/raw/branch/main/json/locales";
static String get rssVideoUrl => static const String googleTranslateApiUrl = "https://translate-g-proxy.xkeyc.com";
"$rssApiHome/bilibili/user/channel/27976358/290653";
static String get rssTextUrl2 =>
"$rssApiHome/baidu/tieba/user/%E7%81%AC%E7%81%ACG%E7%81%AC%E7%81%AC&";
static const String googleTranslateApiUrl =
"https://translate-g-proxy.xkeyc.com";
static const feedbackUrl = "https://support.citizenwiki.cn/all"; static const feedbackUrl = "https://support.citizenwiki.cn/all";
static const feedbackFAQUrl = "https://support.citizenwiki.cn/t/sc-toolbox"; static const feedbackFAQUrl = "https://support.citizenwiki.cn/t/sc-toolbox";
static String nav42KitUrl = "https://payload.citizenwiki.cn/api/community-navs?sort=is_sponsored&depth=2&page=1&limit=1000"; static String nav42KitUrl =
"https://payload.citizenwiki.cn/api/community-navs?sort=is_sponsored&depth=2&page=1&limit=1000";
static String get devReleaseUrl => "$gitApiHome/SCToolBox/Release/releases"; static String get devReleaseUrl => "$gitApiHome/SCToolBox/Release/releases";
@ -47,19 +38,19 @@ class URLConf {
// 使 DNS // 使 DNS
final gitApiList = _genFinalList(await dnsLookupTxt("git.dns.scbox.org")); final gitApiList = _genFinalList(await dnsLookupTxt("git.dns.scbox.org"));
dPrint("DNS gitApiList ==== $gitApiList"); dPrint("DNS gitApiList ==== $gitApiList");
final fasterGit = await getFasterUrl(gitApiList); final fasterGit = await getFasterUrl(gitApiList, "git");
dPrint("gitApiList.Faster ==== $fasterGit"); dPrint("gitApiList.Faster ==== $fasterGit");
if (fasterGit != null) { if (fasterGit != null) {
gitApiHome = fasterGit; gitApiHome = fasterGit;
} }
final rssApiList = _genFinalList(await dnsLookupTxt("rss.dns.scbox.org")); final newsApiList = _genFinalList(await dnsLookupTxt("news.dns.scbox.org"));
final fasterRss = await getFasterUrl(rssApiList); final fasterNews = await getFasterUrl(newsApiList, "news");
dPrint("DNS rssApiList ==== $rssApiList"); dPrint("DNS newsApiList ==== $newsApiList");
dPrint("rssApiList.Faster ==== $fasterRss"); dPrint("newsApiList.Faster ==== $fasterNews");
if (fasterRss != null) { if (fasterNews != null) {
rssApiHome = fasterRss; newsApiHome = fasterNews;
} }
isUrlCheckPass = fasterGit != null && fasterRss != null; isUrlCheckPass = fasterGit != null && fasterNews != null;
return isUrlCheckPass; return isUrlCheckPass;
} }
@ -72,7 +63,7 @@ class URLConf {
return (await DohClient.resolveTXT(host)) ?? []; return (await DohClient.resolveTXT(host)) ?? [];
} }
static Future<String?> getFasterUrl(List<String> urls) async { static Future<String?> getFasterUrl(List<String> urls, String mode) async {
String firstUrl = ""; String firstUrl = "";
int callLen = 0; int callLen = 0;
@ -83,11 +74,23 @@ class URLConf {
} }
} }
for (var value in urls) { for (var url in urls) {
RSHttp.head(value).then((resp) => onCall(resp, value), onError: (err) { var reqUrl = url;
callLen++; switch (mode) {
dPrint("RSHttp.head error $err"); case "git":
}); reqUrl = "$url/SCToolBox/Api/raw/branch/main/sc_doctor/version.json";
break;
case "news":
reqUrl = "$url/api/latest";
break;
}
RSHttp.head(reqUrl).then(
(resp) => onCall(resp, url),
onError: (err) {
callLen++;
dPrint("RSHttp.head error $err");
},
);
} }
while (true) { while (true) {

View File

@ -0,0 +1,54 @@
import 'package:freezed_annotation/freezed_annotation.dart';
part 'citizen_news_data.freezed.dart';
part 'citizen_news_data.g.dart';
@freezed
sealed class CitizenNewsData with _$CitizenNewsData {
const factory CitizenNewsData({
@Default(<CitizenNewsVideosItemData>[]) @JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,
@Default(<CitizenNewsArticlesItemData>[]) @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles,
}) = _CitizenNewsData;
const CitizenNewsData._();
factory CitizenNewsData.fromJson(Map<String, Object?> json) => _$CitizenNewsDataFromJson(json);
}
@freezed
sealed class CitizenNewsVideosItemData with _$CitizenNewsVideosItemData {
const factory CitizenNewsVideosItemData({
@Default('') @JsonKey(name: 'title') String title,
@Default('') @JsonKey(name: 'author') String author,
@Default('') @JsonKey(name: 'description') String description,
@Default('') @JsonKey(name: 'link') String link,
@Default('') @JsonKey(name: 'pubDate') String pubDate,
@Default('') @JsonKey(name: 'postId') String postId,
@Default(<String>[]) @JsonKey(name: 'detailedDescription') List<String> detailedDescription,
@Default('') @JsonKey(name: 'tag') String tag,
}) = _CitizenNewsVideosItemData;
const CitizenNewsVideosItemData._();
factory CitizenNewsVideosItemData.fromJson(Map<String, Object?> json) => _$CitizenNewsVideosItemDataFromJson(json);
}
@freezed
sealed class CitizenNewsArticlesItemData with _$CitizenNewsArticlesItemData {
const factory CitizenNewsArticlesItemData({
@Default('') @JsonKey(name: 'title') String title,
@Default('') @JsonKey(name: 'author') String author,
@Default('') @JsonKey(name: 'description') String description,
@Default('') @JsonKey(name: 'link') String link,
@Default('') @JsonKey(name: 'pubDate') String pubDate,
@Default('') @JsonKey(name: 'postId') String postId,
@Default(<String>[]) @JsonKey(name: 'detailedDescription') List<String> detailedDescription,
@Default('') @JsonKey(name: 'tag') String tag,
}) = _CitizenNewsArticlesItemData;
const CitizenNewsArticlesItemData._();
factory CitizenNewsArticlesItemData.fromJson(Map<String, Object?> json) =>
_$CitizenNewsArticlesItemDataFromJson(json);
}

View File

@ -0,0 +1,854 @@
// 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 'citizen_news_data.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$CitizenNewsData {
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> get videos;@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> get articles;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsDataCopyWith<CitizenNewsData> get copyWith => _$CitizenNewsDataCopyWithImpl<CitizenNewsData>(this as CitizenNewsData, _$identity);
/// Serializes this CitizenNewsData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsData&&const DeepCollectionEquality().equals(other.videos, videos)&&const DeepCollectionEquality().equals(other.articles, articles));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(videos),const DeepCollectionEquality().hash(articles));
@override
String toString() {
return 'CitizenNewsData(videos: $videos, articles: $articles)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsDataCopyWith<$Res> {
factory $CitizenNewsDataCopyWith(CitizenNewsData value, $Res Function(CitizenNewsData) _then) = _$CitizenNewsDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles
});
}
/// @nodoc
class _$CitizenNewsDataCopyWithImpl<$Res>
implements $CitizenNewsDataCopyWith<$Res> {
_$CitizenNewsDataCopyWithImpl(this._self, this._then);
final CitizenNewsData _self;
final $Res Function(CitizenNewsData) _then;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? videos = null,Object? articles = null,}) {
return _then(_self.copyWith(
videos: null == videos ? _self.videos : videos // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsVideosItemData>,articles: null == articles ? _self.articles : articles // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsArticlesItemData>,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsData].
extension CitizenNewsDataPatterns on CitizenNewsData {
/// 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( _CitizenNewsData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsData() 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( _CitizenNewsData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsData():
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( _CitizenNewsData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsData() 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(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that.videos,_that.articles);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(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsData():
return $default(_that.videos,_that.articles);}
}
/// 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(@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos, @JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsData() when $default != null:
return $default(_that.videos,_that.articles);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsData extends CitizenNewsData {
const _CitizenNewsData({@JsonKey(name: 'videos') final List<CitizenNewsVideosItemData> videos = const <CitizenNewsVideosItemData>[], @JsonKey(name: 'articles') final List<CitizenNewsArticlesItemData> articles = const <CitizenNewsArticlesItemData>[]}): _videos = videos,_articles = articles,super._();
factory _CitizenNewsData.fromJson(Map<String, dynamic> json) => _$CitizenNewsDataFromJson(json);
final List<CitizenNewsVideosItemData> _videos;
@override@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> get videos {
if (_videos is EqualUnmodifiableListView) return _videos;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_videos);
}
final List<CitizenNewsArticlesItemData> _articles;
@override@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> get articles {
if (_articles is EqualUnmodifiableListView) return _articles;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_articles);
}
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsDataCopyWith<_CitizenNewsData> get copyWith => __$CitizenNewsDataCopyWithImpl<_CitizenNewsData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsData&&const DeepCollectionEquality().equals(other._videos, _videos)&&const DeepCollectionEquality().equals(other._articles, _articles));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,const DeepCollectionEquality().hash(_videos),const DeepCollectionEquality().hash(_articles));
@override
String toString() {
return 'CitizenNewsData(videos: $videos, articles: $articles)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsDataCopyWith<$Res> implements $CitizenNewsDataCopyWith<$Res> {
factory _$CitizenNewsDataCopyWith(_CitizenNewsData value, $Res Function(_CitizenNewsData) _then) = __$CitizenNewsDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'videos') List<CitizenNewsVideosItemData> videos,@JsonKey(name: 'articles') List<CitizenNewsArticlesItemData> articles
});
}
/// @nodoc
class __$CitizenNewsDataCopyWithImpl<$Res>
implements _$CitizenNewsDataCopyWith<$Res> {
__$CitizenNewsDataCopyWithImpl(this._self, this._then);
final _CitizenNewsData _self;
final $Res Function(_CitizenNewsData) _then;
/// Create a copy of CitizenNewsData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? videos = null,Object? articles = null,}) {
return _then(_CitizenNewsData(
videos: null == videos ? _self._videos : videos // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsVideosItemData>,articles: null == articles ? _self._articles : articles // ignore: cast_nullable_to_non_nullable
as List<CitizenNewsArticlesItemData>,
));
}
}
/// @nodoc
mixin _$CitizenNewsVideosItemData {
@JsonKey(name: 'title') String get title;@JsonKey(name: 'author') String get author;@JsonKey(name: 'description') String get description;@JsonKey(name: 'link') String get link;@JsonKey(name: 'pubDate') String get pubDate;@JsonKey(name: 'postId') String get postId;@JsonKey(name: 'detailedDescription') List<String> get detailedDescription;@JsonKey(name: 'tag') String get tag;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsVideosItemDataCopyWith<CitizenNewsVideosItemData> get copyWith => _$CitizenNewsVideosItemDataCopyWithImpl<CitizenNewsVideosItemData>(this as CitizenNewsVideosItemData, _$identity);
/// Serializes this CitizenNewsVideosItemData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsVideosItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other.detailedDescription, detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsVideosItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsVideosItemDataCopyWith<$Res> {
factory $CitizenNewsVideosItemDataCopyWith(CitizenNewsVideosItemData value, $Res Function(CitizenNewsVideosItemData) _then) = _$CitizenNewsVideosItemDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class _$CitizenNewsVideosItemDataCopyWithImpl<$Res>
implements $CitizenNewsVideosItemDataCopyWith<$Res> {
_$CitizenNewsVideosItemDataCopyWithImpl(this._self, this._then);
final CitizenNewsVideosItemData _self;
final $Res Function(CitizenNewsVideosItemData) _then;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_self.copyWith(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self.detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsVideosItemData].
extension CitizenNewsVideosItemDataPatterns on CitizenNewsVideosItemData {
/// 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( _CitizenNewsVideosItemData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() 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( _CitizenNewsVideosItemData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData():
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( _CitizenNewsVideosItemData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() 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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData():
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);}
}
/// 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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsVideosItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsVideosItemData extends CitizenNewsVideosItemData {
const _CitizenNewsVideosItemData({@JsonKey(name: 'title') this.title = '', @JsonKey(name: 'author') this.author = '', @JsonKey(name: 'description') this.description = '', @JsonKey(name: 'link') this.link = '', @JsonKey(name: 'pubDate') this.pubDate = '', @JsonKey(name: 'postId') this.postId = '', @JsonKey(name: 'detailedDescription') final List<String> detailedDescription = const <String>[], @JsonKey(name: 'tag') this.tag = ''}): _detailedDescription = detailedDescription,super._();
factory _CitizenNewsVideosItemData.fromJson(Map<String, dynamic> json) => _$CitizenNewsVideosItemDataFromJson(json);
@override@JsonKey(name: 'title') final String title;
@override@JsonKey(name: 'author') final String author;
@override@JsonKey(name: 'description') final String description;
@override@JsonKey(name: 'link') final String link;
@override@JsonKey(name: 'pubDate') final String pubDate;
@override@JsonKey(name: 'postId') final String postId;
final List<String> _detailedDescription;
@override@JsonKey(name: 'detailedDescription') List<String> get detailedDescription {
if (_detailedDescription is EqualUnmodifiableListView) return _detailedDescription;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_detailedDescription);
}
@override@JsonKey(name: 'tag') final String tag;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsVideosItemDataCopyWith<_CitizenNewsVideosItemData> get copyWith => __$CitizenNewsVideosItemDataCopyWithImpl<_CitizenNewsVideosItemData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsVideosItemDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsVideosItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other._detailedDescription, _detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(_detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsVideosItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsVideosItemDataCopyWith<$Res> implements $CitizenNewsVideosItemDataCopyWith<$Res> {
factory _$CitizenNewsVideosItemDataCopyWith(_CitizenNewsVideosItemData value, $Res Function(_CitizenNewsVideosItemData) _then) = __$CitizenNewsVideosItemDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class __$CitizenNewsVideosItemDataCopyWithImpl<$Res>
implements _$CitizenNewsVideosItemDataCopyWith<$Res> {
__$CitizenNewsVideosItemDataCopyWithImpl(this._self, this._then);
final _CitizenNewsVideosItemData _self;
final $Res Function(_CitizenNewsVideosItemData) _then;
/// Create a copy of CitizenNewsVideosItemData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_CitizenNewsVideosItemData(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self._detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
mixin _$CitizenNewsArticlesItemData {
@JsonKey(name: 'title') String get title;@JsonKey(name: 'author') String get author;@JsonKey(name: 'description') String get description;@JsonKey(name: 'link') String get link;@JsonKey(name: 'pubDate') String get pubDate;@JsonKey(name: 'postId') String get postId;@JsonKey(name: 'detailedDescription') List<String> get detailedDescription;@JsonKey(name: 'tag') String get tag;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$CitizenNewsArticlesItemDataCopyWith<CitizenNewsArticlesItemData> get copyWith => _$CitizenNewsArticlesItemDataCopyWithImpl<CitizenNewsArticlesItemData>(this as CitizenNewsArticlesItemData, _$identity);
/// Serializes this CitizenNewsArticlesItemData to a JSON map.
Map<String, dynamic> toJson();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is CitizenNewsArticlesItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other.detailedDescription, detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsArticlesItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class $CitizenNewsArticlesItemDataCopyWith<$Res> {
factory $CitizenNewsArticlesItemDataCopyWith(CitizenNewsArticlesItemData value, $Res Function(CitizenNewsArticlesItemData) _then) = _$CitizenNewsArticlesItemDataCopyWithImpl;
@useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class _$CitizenNewsArticlesItemDataCopyWithImpl<$Res>
implements $CitizenNewsArticlesItemDataCopyWith<$Res> {
_$CitizenNewsArticlesItemDataCopyWithImpl(this._self, this._then);
final CitizenNewsArticlesItemData _self;
final $Res Function(CitizenNewsArticlesItemData) _then;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_self.copyWith(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self.detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [CitizenNewsArticlesItemData].
extension CitizenNewsArticlesItemDataPatterns on CitizenNewsArticlesItemData {
/// 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( _CitizenNewsArticlesItemData value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() 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( _CitizenNewsArticlesItemData value) $default,){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData():
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( _CitizenNewsArticlesItemData value)? $default,){
final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() 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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag) $default,) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData():
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);}
}
/// 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(@JsonKey(name: 'title') String title, @JsonKey(name: 'author') String author, @JsonKey(name: 'description') String description, @JsonKey(name: 'link') String link, @JsonKey(name: 'pubDate') String pubDate, @JsonKey(name: 'postId') String postId, @JsonKey(name: 'detailedDescription') List<String> detailedDescription, @JsonKey(name: 'tag') String tag)? $default,) {final _that = this;
switch (_that) {
case _CitizenNewsArticlesItemData() when $default != null:
return $default(_that.title,_that.author,_that.description,_that.link,_that.pubDate,_that.postId,_that.detailedDescription,_that.tag);case _:
return null;
}
}
}
/// @nodoc
@JsonSerializable()
class _CitizenNewsArticlesItemData extends CitizenNewsArticlesItemData {
const _CitizenNewsArticlesItemData({@JsonKey(name: 'title') this.title = '', @JsonKey(name: 'author') this.author = '', @JsonKey(name: 'description') this.description = '', @JsonKey(name: 'link') this.link = '', @JsonKey(name: 'pubDate') this.pubDate = '', @JsonKey(name: 'postId') this.postId = '', @JsonKey(name: 'detailedDescription') final List<String> detailedDescription = const <String>[], @JsonKey(name: 'tag') this.tag = ''}): _detailedDescription = detailedDescription,super._();
factory _CitizenNewsArticlesItemData.fromJson(Map<String, dynamic> json) => _$CitizenNewsArticlesItemDataFromJson(json);
@override@JsonKey(name: 'title') final String title;
@override@JsonKey(name: 'author') final String author;
@override@JsonKey(name: 'description') final String description;
@override@JsonKey(name: 'link') final String link;
@override@JsonKey(name: 'pubDate') final String pubDate;
@override@JsonKey(name: 'postId') final String postId;
final List<String> _detailedDescription;
@override@JsonKey(name: 'detailedDescription') List<String> get detailedDescription {
if (_detailedDescription is EqualUnmodifiableListView) return _detailedDescription;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_detailedDescription);
}
@override@JsonKey(name: 'tag') final String tag;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$CitizenNewsArticlesItemDataCopyWith<_CitizenNewsArticlesItemData> get copyWith => __$CitizenNewsArticlesItemDataCopyWithImpl<_CitizenNewsArticlesItemData>(this, _$identity);
@override
Map<String, dynamic> toJson() {
return _$CitizenNewsArticlesItemDataToJson(this, );
}
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _CitizenNewsArticlesItemData&&(identical(other.title, title) || other.title == title)&&(identical(other.author, author) || other.author == author)&&(identical(other.description, description) || other.description == description)&&(identical(other.link, link) || other.link == link)&&(identical(other.pubDate, pubDate) || other.pubDate == pubDate)&&(identical(other.postId, postId) || other.postId == postId)&&const DeepCollectionEquality().equals(other._detailedDescription, _detailedDescription)&&(identical(other.tag, tag) || other.tag == tag));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,title,author,description,link,pubDate,postId,const DeepCollectionEquality().hash(_detailedDescription),tag);
@override
String toString() {
return 'CitizenNewsArticlesItemData(title: $title, author: $author, description: $description, link: $link, pubDate: $pubDate, postId: $postId, detailedDescription: $detailedDescription, tag: $tag)';
}
}
/// @nodoc
abstract mixin class _$CitizenNewsArticlesItemDataCopyWith<$Res> implements $CitizenNewsArticlesItemDataCopyWith<$Res> {
factory _$CitizenNewsArticlesItemDataCopyWith(_CitizenNewsArticlesItemData value, $Res Function(_CitizenNewsArticlesItemData) _then) = __$CitizenNewsArticlesItemDataCopyWithImpl;
@override @useResult
$Res call({
@JsonKey(name: 'title') String title,@JsonKey(name: 'author') String author,@JsonKey(name: 'description') String description,@JsonKey(name: 'link') String link,@JsonKey(name: 'pubDate') String pubDate,@JsonKey(name: 'postId') String postId,@JsonKey(name: 'detailedDescription') List<String> detailedDescription,@JsonKey(name: 'tag') String tag
});
}
/// @nodoc
class __$CitizenNewsArticlesItemDataCopyWithImpl<$Res>
implements _$CitizenNewsArticlesItemDataCopyWith<$Res> {
__$CitizenNewsArticlesItemDataCopyWithImpl(this._self, this._then);
final _CitizenNewsArticlesItemData _self;
final $Res Function(_CitizenNewsArticlesItemData) _then;
/// Create a copy of CitizenNewsArticlesItemData
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? title = null,Object? author = null,Object? description = null,Object? link = null,Object? pubDate = null,Object? postId = null,Object? detailedDescription = null,Object? tag = null,}) {
return _then(_CitizenNewsArticlesItemData(
title: null == title ? _self.title : title // ignore: cast_nullable_to_non_nullable
as String,author: null == author ? _self.author : author // ignore: cast_nullable_to_non_nullable
as String,description: null == description ? _self.description : description // ignore: cast_nullable_to_non_nullable
as String,link: null == link ? _self.link : link // ignore: cast_nullable_to_non_nullable
as String,pubDate: null == pubDate ? _self.pubDate : pubDate // ignore: cast_nullable_to_non_nullable
as String,postId: null == postId ? _self.postId : postId // ignore: cast_nullable_to_non_nullable
as String,detailedDescription: null == detailedDescription ? _self._detailedDescription : detailedDescription // ignore: cast_nullable_to_non_nullable
as List<String>,tag: null == tag ? _self.tag : tag // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
// dart format on

View File

@ -0,0 +1,91 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'citizen_news_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
_CitizenNewsData _$CitizenNewsDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsData(
videos:
(json['videos'] as List<dynamic>?)
?.map(
(e) =>
CitizenNewsVideosItemData.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const <CitizenNewsVideosItemData>[],
articles:
(json['articles'] as List<dynamic>?)
?.map(
(e) =>
CitizenNewsArticlesItemData.fromJson(e as Map<String, dynamic>),
)
.toList() ??
const <CitizenNewsArticlesItemData>[],
);
Map<String, dynamic> _$CitizenNewsDataToJson(_CitizenNewsData instance) =>
<String, dynamic>{'videos': instance.videos, 'articles': instance.articles};
_CitizenNewsVideosItemData _$CitizenNewsVideosItemDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsVideosItemData(
title: json['title'] as String? ?? '',
author: json['author'] as String? ?? '',
description: json['description'] as String? ?? '',
link: json['link'] as String? ?? '',
pubDate: json['pubDate'] as String? ?? '',
postId: json['postId'] as String? ?? '',
detailedDescription:
(json['detailedDescription'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const <String>[],
tag: json['tag'] as String? ?? '',
);
Map<String, dynamic> _$CitizenNewsVideosItemDataToJson(
_CitizenNewsVideosItemData instance,
) => <String, dynamic>{
'title': instance.title,
'author': instance.author,
'description': instance.description,
'link': instance.link,
'pubDate': instance.pubDate,
'postId': instance.postId,
'detailedDescription': instance.detailedDescription,
'tag': instance.tag,
};
_CitizenNewsArticlesItemData _$CitizenNewsArticlesItemDataFromJson(
Map<String, dynamic> json,
) => _CitizenNewsArticlesItemData(
title: json['title'] as String? ?? '',
author: json['author'] as String? ?? '',
description: json['description'] as String? ?? '',
link: json['link'] as String? ?? '',
pubDate: json['pubDate'] as String? ?? '',
postId: json['postId'] as String? ?? '',
detailedDescription:
(json['detailedDescription'] as List<dynamic>?)
?.map((e) => e as String)
.toList() ??
const <String>[],
tag: json['tag'] as String? ?? '',
);
Map<String, dynamic> _$CitizenNewsArticlesItemDataToJson(
_CitizenNewsArticlesItemData instance,
) => <String, dynamic>{
'title': instance.title,
'author': instance.author,
'description': instance.description,
'link': instance.link,
'pubDate': instance.pubDate,
'postId': instance.postId,
'detailedDescription': instance.detailedDescription,
'tag': instance.tag,
};

View File

@ -6,18 +6,17 @@ import 'package:starcitizen_doctor/widgets/widgets.dart';
class HomeMdContentDialogUI extends HookConsumerWidget { class HomeMdContentDialogUI extends HookConsumerWidget {
final String title; final String title;
final String url; final String? url;
final String? mdContent;
const HomeMdContentDialogUI( const HomeMdContentDialogUI({super.key, required this.title, this.url, this.mdContent})
{super.key, required this.title, required this.url}); : assert(url != null || mdContent != null, "Either url or htmlContent must be provided");
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
return Material( return Material(
child: ContentDialog( child: ContentDialog(
constraints: BoxConstraints( constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .6),
maxWidth: MediaQuery.of(context).size.width * .6,
),
title: Text(title), title: Text(title),
content: LoadingWidget( content: LoadingWidget(
onLoadData: _getContent, onLoadData: _getContent,
@ -36,21 +35,24 @@ class HomeMdContentDialogUI extends HookConsumerWidget {
), ),
actions: [ actions: [
FilledButton( FilledButton(
child: Padding( child: Padding(
padding: padding: const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2),
const EdgeInsets.only(left: 8, right: 8, top: 2, bottom: 2), child: Text(S.current.action_close),
child: Text(S.current.action_close), ),
), onPressed: () {
onPressed: () { Navigator.pop(context);
Navigator.pop(context); },
}) ),
], ],
), ),
); );
} }
Future<String> _getContent() async { Future<String> _getContent() async {
final r = await RSHttp.getText(url); if (mdContent != null) {
return mdContent!;
}
final r = await RSHttp.getText(url!);
return r; return r;
} }
} }

View File

@ -59,29 +59,27 @@ class HomeUI extends HookConsumerWidget {
), ),
const SizedBox(height: 6), const SizedBox(height: 6),
], ],
...makeIndex(context, model, homeState, ref) ...makeIndex(context, model, homeState, ref),
], ],
), ),
), ),
), ),
if (homeState.isFixing) if (homeState.isFixing)
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.black.withAlpha(150)),
color: Colors.black.withAlpha(150),
),
child: Center( child: Center(
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const ProgressRing(), const ProgressRing(),
const SizedBox(height: 12), const SizedBox(height: 12),
Text(homeState.isFixingString.isNotEmpty Text(
? homeState.isFixingString homeState.isFixingString.isNotEmpty ? homeState.isFixingString : S.current.doctor_info_processing,
: S.current.doctor_info_processing), ),
], ],
), ),
), ),
) ),
], ],
); );
} }
@ -100,28 +98,16 @@ class HomeUI extends HookConsumerWidget {
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(bottom: 30), padding: const EdgeInsets.only(bottom: 30),
child: Image.asset( child: Image.asset("assets/sc_logo.png", fit: BoxFit.fitHeight, height: 260),
"assets/sc_logo.png",
fit: BoxFit.fitHeight,
height: 260,
),
), ),
makeGameStatusCard(context, model, 340, homeState) makeGameStatusCard(context, model, 340, homeState),
], ],
), ),
), ),
), ),
), ),
Positioned( Positioned(top: 0, left: 24, child: makeLeftColumn(context, model, width, homeState)),
top: 0, Positioned(right: 24, top: 0, child: makeNewsCard(context, model, homeState)),
left: 24,
child: makeLeftColumn(context, model, width, homeState),
),
Positioned(
right: 24,
top: 0,
child: makeNewsCard(context, model, homeState),
),
], ],
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
@ -137,10 +123,7 @@ class HomeUI extends HookConsumerWidget {
await context.push("/guide"); await context.push("/guide");
await model.reScanPath(); await model.reScanPath();
}, },
child: const Padding( child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.settings)),
padding: EdgeInsets.all(6),
child: Icon(FluentIcons.settings),
),
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Expanded( Expanded(
@ -148,17 +131,12 @@ class HomeUI extends HookConsumerWidget {
value: homeState.scInstalledPath, value: homeState.scInstalledPath,
isExpanded: true, isExpanded: true,
items: [ items: [
ComboBoxItem( ComboBoxItem(value: "not_install", child: Text(S.current.home_not_installed_or_failed)),
value: "not_install",
child: Text(S.current.home_not_installed_or_failed),
),
for (final path in homeState.scInstallPaths) for (final path in homeState.scInstallPaths)
ComboBoxItem( ComboBoxItem(
value: path, value: path,
child: Row( child: Row(children: [Text(path)]),
children: [Text(path)], ),
),
)
], ],
onChanged: model.onChangeInstallPath, onChanged: model.onChangeInstallPath,
), ),
@ -166,38 +144,29 @@ class HomeUI extends HookConsumerWidget {
if (S.current.app_language_code == NoL10n.langCodeZhCn) ...[ if (S.current.app_language_code == NoL10n.langCodeZhCn) ...[
const SizedBox(width: 12), const SizedBox(width: 12),
Button( Button(
onPressed: homeState.webLocalizationVersionsData == null ? null : () => model.launchRSI(context), onPressed: homeState.webLocalizationVersionsData == null ? null : () => model.launchRSI(context),
style: homeState.isCurGameRunning style: homeState.isCurGameRunning
? null ? null
: ButtonStyle( : ButtonStyle(backgroundColor: WidgetStateProperty.resolveWith(_getRunButtonColor)),
backgroundColor: WidgetStateProperty.resolveWith(_getRunButtonColor), child: Padding(
), padding: const EdgeInsets.all(6),
child: Padding( child: Icon(
padding: const EdgeInsets.all(6), homeState.isCurGameRunning ? FluentIcons.stop_solid : FluentIcons.play_solid,
child: Icon( color: homeState.isCurGameRunning ? Colors.red.withValues(alpha: .8) : Colors.white,
homeState.isCurGameRunning ? FluentIcons.stop_solid : FluentIcons.play_solid, ),
color: homeState.isCurGameRunning ? Colors.red.withValues(alpha: .8) : Colors.white, ),
), ),
)),
], ],
const SizedBox(width: 12), const SizedBox(width: 12),
Button( Button(
onPressed: () => _checkAndGoInputMethod(context, homeState, model, ref), onPressed: () => _checkAndGoInputMethod(context, homeState, model, ref),
style: ButtonStyle( style: ButtonStyle(backgroundColor: WidgetStateProperty.resolveWith((_) => Colors.blue)),
backgroundColor: WidgetStateProperty.resolveWith((_) => Colors.blue), child: Padding(padding: const EdgeInsets.all(6), child: Icon(FluentIcons.keyboard_classic)),
),
child: Padding(
padding: const EdgeInsets.all(6),
child: Icon(FluentIcons.keyboard_classic),
),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Button( Button(
onPressed: model.reScanPath, onPressed: model.reScanPath,
child: const Padding( child: const Padding(padding: EdgeInsets.all(6), child: Icon(FluentIcons.refresh)),
padding: EdgeInsets.all(6),
child: Icon(FluentIcons.refresh),
),
), ),
], ],
), ),
@ -223,55 +192,44 @@ class HomeUI extends HookConsumerWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
makeWebViewButton(context, model, makeWebViewButton(
icon: SvgPicture.asset( context,
"assets/rsi.svg", model,
colorFilter: makeSvgColor(Colors.white), icon: SvgPicture.asset("assets/rsi.svg", colorFilter: makeSvgColor(Colors.white), height: 18),
height: 18, name: S.current.home_action_star_citizen_website_localization,
), webTitle: S.current.home_action_star_citizen_website_localization,
name: S.current.home_action_star_citizen_website_localization, webURL: "https://robertsspaceindustries.com",
webTitle: S.current.home_action_star_citizen_website_localization, info: S.current.home_action_info_roberts_space_industries_origin,
webURL: "https://robertsspaceindustries.com", useLocalization: true,
info: S.current.home_action_info_roberts_space_industries_origin, width: width,
useLocalization: true, touchKey: "webLocalization_rsi",
width: width, ),
touchKey: "webLocalization_rsi"),
const SizedBox(height: 12), const SizedBox(height: 12),
makeWebViewButton(context, model, makeWebViewButton(
icon: Row( context,
children: [ model,
SvgPicture.asset( icon: Row(children: [SvgPicture.asset("assets/uex.svg", height: 18), const SizedBox(width: 12)]),
"assets/uex.svg", name: S.current.home_action_uex_localization,
height: 18, webTitle: S.current.home_action_uex_localization,
), webURL: "https://uexcorp.space/",
const SizedBox(width: 12), info: S.current.home_action_info_mining_refining_trade_calculator,
], useLocalization: true,
), width: width,
name: S.current.home_action_uex_localization, touchKey: "webLocalization_uex",
webTitle: S.current.home_action_uex_localization, ),
webURL: "https://uexcorp.space/",
info: S.current.home_action_info_mining_refining_trade_calculator,
useLocalization: true,
width: width,
touchKey: "webLocalization_uex"),
const SizedBox(height: 12), const SizedBox(height: 12),
makeWebViewButton(context, model, makeWebViewButton(
icon: Row( context,
children: [ model,
Image.asset( icon: Row(children: [Image.asset("assets/dps.png", height: 20), const SizedBox(width: 12)]),
"assets/dps.png", name: S.current.home_action_dps_calculator_localization,
height: 20, webTitle: S.current.home_action_dps_calculator_localization,
), webURL: "https://www.erkul.games/live/calculator",
const SizedBox(width: 12), info: S.current.home_action_info_ship_upgrade_damage_value_query,
], useLocalization: true,
), width: width,
name: S.current.home_action_dps_calculator_localization, touchKey: "webLocalization_dps",
webTitle: S.current.home_action_dps_calculator_localization, ),
webURL: "https://www.erkul.games/live/calculator",
info: S.current.home_action_info_ship_upgrade_damage_value_query,
useLocalization: true,
width: width,
touchKey: "webLocalization_dps"),
const SizedBox(height: 12), const SizedBox(height: 12),
Text(S.current.home_action_external_browser_extension), Text(S.current.home_action_external_browser_extension),
const SizedBox(height: 12), const SizedBox(height: 12),
@ -281,7 +239,8 @@ class HomeUI extends HookConsumerWidget {
child: const FaIcon(FontAwesomeIcons.chrome, size: 18), child: const FaIcon(FontAwesomeIcons.chrome, size: 18),
onPressed: () { onPressed: () {
launchUrlString( launchUrlString(
"https://chrome.google.com/webstore/detail/gocnjckojmledijgmadmacoikibcggja?authuser=0&hl=zh-CN"); "https://chrome.google.com/webstore/detail/gocnjckojmledijgmadmacoikibcggja?authuser=0&hl=zh-CN",
);
}, },
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
@ -289,15 +248,18 @@ class HomeUI extends HookConsumerWidget {
child: const FaIcon(FontAwesomeIcons.edge, size: 18), child: const FaIcon(FontAwesomeIcons.edge, size: 18),
onPressed: () { onPressed: () {
launchUrlString( launchUrlString(
"https://microsoftedge.microsoft.com/addons/detail/lipbbcckldklpdcpfagicipecaacikgi"); "https://microsoftedge.microsoft.com/addons/detail/lipbbcckldklpdcpfagicipecaacikgi",
);
}, },
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Button( Button(
child: const FaIcon(FontAwesomeIcons.firefoxBrowser, size: 18), child: const FaIcon(FontAwesomeIcons.firefoxBrowser, size: 18),
onPressed: () { onPressed: () {
launchUrlString("https://addons.mozilla.org/zh-CN/firefox/" launchUrlString(
"addon/%E6%98%9F%E9%99%85%E5%85%AC%E6%B0%91%E7%9B%92%E5%AD%90%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8B%93%E5%B1%95/"); "https://addons.mozilla.org/zh-CN/firefox/"
"addon/%E6%98%9F%E9%99%85%E5%85%AC%E6%B0%91%E7%9B%92%E5%AD%90%E6%B5%8F%E8%A7%88%E5%99%A8%E6%8B%93%E5%B1%95/",
);
}, },
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
@ -308,7 +270,7 @@ class HomeUI extends HookConsumerWidget {
}, },
), ),
], ],
) ),
], ],
), ),
), ),
@ -319,13 +281,14 @@ class HomeUI extends HookConsumerWidget {
), ),
if (homeState.webLocalizationVersionsData == null) if (homeState.webLocalizationVersionsData == null)
Positioned.fill( Positioned.fill(
child: Container( child: Container(
decoration: decoration: BoxDecoration(
BoxDecoration(color: Colors.black.withValues(alpha: .3), borderRadius: BorderRadius.circular(12)), color: Colors.black.withValues(alpha: .3),
child: const Center( borderRadius: BorderRadius.circular(12),
child: ProgressRing(), ),
child: const Center(child: ProgressRing()),
), ),
)) ),
], ],
); );
} }
@ -334,95 +297,113 @@ class HomeUI extends HookConsumerWidget {
return ScrollConfiguration( return ScrollConfiguration(
behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
child: Container( child: Container(
width: 316, width: 316,
height: 386, height: 386,
decoration: BoxDecoration(color: Colors.white.withValues(alpha: .1), borderRadius: BorderRadius.circular(12)), decoration: BoxDecoration(color: Colors.white.withValues(alpha: .1), borderRadius: BorderRadius.circular(12)),
child: SingleChildScrollView( child: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [
SizedBox( SizedBox(
height: 190, height: 210,
width: 316, width: 316,
child: Tilt( child: homeState.citizenNewsData == null
shadowConfig: const ShadowConfig(maxIntensity: .3), ? Container(
borderRadius: const BorderRadius.only( decoration: BoxDecoration(color: Colors.white.withValues(alpha: .1)),
topLeft: Radius.circular(12), child: makeLoading(context),
topRight: Radius.circular(12), )
), : HoverSwiper(
child: homeState.rssVideoItems == null itemCount: getMinNumber([homeState.citizenNewsData?.videos.length ?? 0, 6]),
? Container( itemBuilder: (context, index) {
decoration: BoxDecoration(color: Colors.white.withValues(alpha: .1)), final item = homeState.citizenNewsData?.videos[index];
child: makeLoading(context), return GestureDetector(
)
: Swiper(
itemCount: getMinNumber([homeState.rssVideoItems?.length ?? 0, 6]),
itemBuilder: (context, index) {
final item = homeState.rssVideoItems![index];
return GestureDetector(
onTap: () {
if (item.link != null) {
launchUrlString(item.link!);
}
},
child: CacheNetImage(
url: model.getRssImage(item),
fit: BoxFit.cover,
),
);
},
autoplay: true,
),
)),
const SizedBox(height: 1),
if (homeState.rssTextItems == null)
makeLoading(context)
else
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
final item = homeState.rssTextItems![index];
return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () { onTap: () {
if (item.link != null) { launchUrlString(item?.link ?? "");
launchUrlString(item.link!);
}
}, },
child: Padding( child: Column(
padding: const EdgeInsets.only(left: 12, right: 12, top: 4, bottom: 4), children: [
child: Row( CacheNetImage(
children: [ url: model.getRssImage(item?.description),
getRssIcon(item.link ?? ""), fit: BoxFit.cover,
const SizedBox(width: 6), height: 180,
Expanded( ),
child: Text( SizedBox(
model.handleTitle(item.title), height: 30,
textAlign: TextAlign.start, child: Container(
maxLines: 1, width: double.infinity,
overflow: TextOverflow.ellipsis, decoration: BoxDecoration(color: Colors.black),
style: const TextStyle(fontSize: 12.2), padding: EdgeInsets.symmetric(horizontal: 6),
child: Center(
child: Row(
children: [
Expanded(
child: Text(
"${index + 1}. ${(item?.title ?? "").replaceAll("【寰宇周刊】", "")}",
style: TextStyle(fontSize: 12),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
), ),
), ),
const SizedBox(width: 12), ),
Icon( ],
FluentIcons.chevron_right,
size: 12,
color: Colors.white.withValues(alpha: .4),
)
],
),
), ),
)); );
}, },
itemCount: homeState.rssTextItems?.length, paginationActiveSize: 8.0,
), controlSize: 24,
const SizedBox(height: 12), controlPadding: const EdgeInsets.symmetric(horizontal: 8, vertical: 0),
], autoplayDelay: 5000,
), ),
)), ),
const SizedBox(height: 1),
if (homeState.citizenNewsData?.articles == null)
makeLoading(context)
else
ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
final item = homeState.citizenNewsData!.articles[index];
return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12),
child: GestureDetector(
onTap: () {
launchUrlString(item.link);
},
child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12, top: 4, bottom: 4),
child: Row(
children: [
getRssIcon(item.link),
const SizedBox(width: 6),
Expanded(
child: Text(
model.handleTitle(item.title),
textAlign: TextAlign.start,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 12.2),
),
),
const SizedBox(width: 12),
Icon(FluentIcons.chevron_right, size: 12, color: Colors.white.withValues(alpha: .4)),
],
),
),
),
);
},
itemCount: homeState.citizenNewsData?.articles.length ?? 0,
),
const SizedBox(height: 12),
],
),
),
),
); );
} }
@ -432,11 +413,7 @@ class HomeUI extends HookConsumerWidget {
} }
if (url.startsWith("https://www.bilibili.com")) { if (url.startsWith("https://www.bilibili.com")) {
return const FaIcon( return const FaIcon(FontAwesomeIcons.bilibili, size: 14, color: Color.fromRGBO(0, 161, 214, 1));
FontAwesomeIcons.bilibili,
size: 14,
color: Color.fromRGBO(0, 161, 214, 1),
);
} }
return const FaIcon(FontAwesomeIcons.rss, size: 14); return const FaIcon(FontAwesomeIcons.rss, size: 14);
@ -444,97 +421,104 @@ class HomeUI extends HookConsumerWidget {
Widget makeIndexActionLists(BuildContext context, HomeUIModel model, HomeUIModelState homeState, WidgetRef ref) { Widget makeIndexActionLists(BuildContext context, HomeUIModel model, HomeUIModelState homeState, WidgetRef ref) {
final items = [ final items = [
_HomeItemData("game_doctor", S.current.home_action_one_click_diagnosis, _HomeItemData(
S.current.home_action_info_one_click_diagnosis_star_citizen, FluentIcons.auto_deploy_settings), "game_doctor",
_HomeItemData("localization", S.current.home_action_localization_management, S.current.home_action_one_click_diagnosis,
S.current.home_action_info_quick_install_localization_resources, FluentIcons.locale_language), S.current.home_action_info_one_click_diagnosis_star_citizen,
_HomeItemData("performance", S.current.home_action_performance_optimization, FluentIcons.auto_deploy_settings,
S.current.home_action_info_engine_config_optimization, FluentIcons.process_meta_task), ),
_HomeItemData(
"localization",
S.current.home_action_localization_management,
S.current.home_action_info_quick_install_localization_resources,
FluentIcons.locale_language,
),
_HomeItemData(
"performance",
S.current.home_action_performance_optimization,
S.current.home_action_info_engine_config_optimization,
FluentIcons.process_meta_task,
),
]; ];
return Padding( return Padding(
padding: const EdgeInsets.all(24), padding: const EdgeInsets.all(24),
child: AlignedGridView.count( child: AlignedGridView.count(
crossAxisCount: 3, crossAxisCount: 3,
mainAxisSpacing: 12, mainAxisSpacing: 12,
crossAxisSpacing: 12, crossAxisSpacing: 12,
itemCount: items.length, itemCount: items.length,
shrinkWrap: true, shrinkWrap: true,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = items.elementAt(index); final item = items.elementAt(index);
return HoverButton( return HoverButton(
onPressed: () => _onMenuTap(context, item.key, homeState, ref), onPressed: () => _onMenuTap(context, item.key, homeState, ref),
builder: (BuildContext context, Set<WidgetState> states) { builder: (BuildContext context, Set<WidgetState> states) {
return Container( return Container(
width: 300, width: 300,
height: 120, height: 120,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
color: states.isHovered color: states.isHovered
? FluentTheme.of(context).cardColor.withValues(alpha: .1) ? FluentTheme.of(context).cardColor.withValues(alpha: .1)
: FluentTheme.of(context).cardColor, : FluentTheme.of(context).cardColor,
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Row( child: Row(
children: [ children: [
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withValues(alpha: .2), borderRadius: BorderRadius.circular(1000)), color: Colors.white.withValues(alpha: .2),
child: Padding( borderRadius: BorderRadius.circular(1000),
padding: const EdgeInsets.all(12),
child: Icon(
item.icon,
size: 24,
),
),
), ),
const SizedBox(width: 24), child: Padding(padding: const EdgeInsets.all(12), child: Icon(item.icon, size: 24)),
Expanded( ),
child: Column( const SizedBox(width: 24),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(item.name, style: const TextStyle(fontSize: 18)),
item.name,
style: const TextStyle(fontSize: 18),
),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
item.infoString, item.infoString,
style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: .6)), style: TextStyle(fontSize: 14, color: Colors.white.withValues(alpha: .6)),
), ),
], ],
)), ),
if (item.key == "localization" && homeState.localizationUpdateInfo != null) ),
Container( if (item.key == "localization" && homeState.localizationUpdateInfo != null)
padding: const EdgeInsets.only(top: 3, bottom: 3, left: 8, right: 8), Container(
decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.only(top: 3, bottom: 3, left: 8, right: 8),
child: Text(homeState.localizationUpdateInfo?.key ?? " "), decoration: BoxDecoration(color: Colors.red, borderRadius: BorderRadius.circular(12)),
), child: Text(homeState.localizationUpdateInfo?.key ?? " "),
const SizedBox(width: 12), ),
const Icon( const SizedBox(width: 12),
FluentIcons.chevron_right, const Icon(FluentIcons.chevron_right, size: 16),
size: 16, ],
)
],
),
), ),
); ),
}, );
); },
}), );
},
),
); );
} }
Widget makeWebViewButton(BuildContext context, HomeUIModel model, Widget makeWebViewButton(
{required Widget icon, BuildContext context,
required String name, HomeUIModel model, {
required String webTitle, required Widget icon,
required String webURL, required String name,
required bool useLocalization, required String webTitle,
required double width, required String webURL,
String? info, required bool useLocalization,
String? touchKey}) { required double width,
String? info,
String? touchKey,
}) {
return Tilt( return Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3), shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
@ -547,9 +531,7 @@ class HomeUI extends HookConsumerWidget {
}, },
child: Container( child: Container(
width: width, width: width,
decoration: BoxDecoration( decoration: BoxDecoration(color: FluentTheme.of(context).cardColor),
color: FluentTheme.of(context).cardColor,
),
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: Row( child: Row(
@ -561,10 +543,7 @@ class HomeUI extends HookConsumerWidget {
Row( Row(
children: [ children: [
icon, icon,
Text( Text(name, style: const TextStyle(fontSize: 14)),
name,
style: const TextStyle(fontSize: 14),
),
], ],
), ),
if (info != null) if (info != null)
@ -575,16 +554,12 @@ class HomeUI extends HookConsumerWidget {
maxLines: 1, maxLines: 1,
style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)), style: TextStyle(fontSize: 12, color: Colors.white.withValues(alpha: .6)),
), ),
) ),
], ],
), ),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
Icon( Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)),
FluentIcons.chevron_right,
size: 14,
color: Colors.white.withValues(alpha: .6),
)
], ],
), ),
), ),
@ -598,7 +573,7 @@ class HomeUI extends HookConsumerWidget {
"Platform": S.current.home_action_rsi_status_platform, "Platform": S.current.home_action_rsi_status_platform,
"Persistent Universe": S.current.home_action_rsi_status_persistent_universe, "Persistent Universe": S.current.home_action_rsi_status_persistent_universe,
"Electronic Access": S.current.home_action_rsi_status_electronic_access, "Electronic Access": S.current.home_action_rsi_status_electronic_access,
"Arena Commander": S.current.home_action_rsi_status_arena_commander "Arena Commander": S.current.home_action_rsi_status_arena_commander,
}; };
return Tilt( return Tilt(
@ -607,52 +582,48 @@ class HomeUI extends HookConsumerWidget {
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
model.goWebView( model.goWebView(
context, S.current.home_action_rsi_status_rsi_server_status, "https://status.robertsspaceindustries.com/", context,
useLocalization: true); S.current.home_action_rsi_status_rsi_server_status,
"https://status.robertsspaceindustries.com/",
useLocalization: true,
);
}, },
child: Container( child: Container(
width: width, width: width,
decoration: BoxDecoration( decoration: BoxDecoration(color: FluentTheme.of(context).cardColor),
color: FluentTheme.of(context).cardColor,
),
child: Padding( child: Padding(
padding: const EdgeInsets.all(12), padding: const EdgeInsets.all(12),
child: Column(children: [ child: Column(
if (homeState.scServerStatus == null) children: [
makeLoading(context, width: 20) if (homeState.scServerStatus == null)
else makeLoading(context, width: 20)
Row( else
mainAxisAlignment: MainAxisAlignment.spaceBetween, Row(
children: [ mainAxisAlignment: MainAxisAlignment.spaceBetween,
Text(S.current.home_action_rsi_status_status), children: [
for (final item in homeState.scServerStatus ?? []) Text(S.current.home_action_rsi_status_status),
Row( for (final item in homeState.scServerStatus ?? [])
children: [ Row(
SizedBox( children: [
height: 14, SizedBox(
child: Center( height: 14,
child: Icon( child: Center(
FontAwesomeIcons.solidCircle, child: Icon(
color: model.isRSIServerStatusOK(item) ? Colors.green : Colors.red, FontAwesomeIcons.solidCircle,
size: 12, color: model.isRSIServerStatusOK(item) ? Colors.green : Colors.red,
size: 12,
),
), ),
), ),
), const SizedBox(width: 5),
const SizedBox(width: 5), Text("${statusCnName[item["name"]] ?? item["name"]}", style: const TextStyle(fontSize: 13)),
Text( ],
"${statusCnName[item["name"]] ?? item["name"]}", ),
style: const TextStyle(fontSize: 13), Icon(FluentIcons.chevron_right, size: 12, color: Colors.white.withValues(alpha: .4)),
), ],
], ),
), ],
Icon( ),
FluentIcons.chevron_right,
size: 12,
color: Colors.white.withValues(alpha: .4),
)
],
)
]),
), ),
), ),
), ),
@ -666,65 +637,55 @@ class HomeUI extends HookConsumerWidget {
child: GestureDetector( child: GestureDetector(
onTap: () => _onTapFestival(context), onTap: () => _onTapFestival(context),
child: Container( child: Container(
width: width + 24, width: width + 24,
decoration: BoxDecoration(color: FluentTheme.of(context).cardColor), decoration: BoxDecoration(color: FluentTheme.of(context).cardColor),
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 8), padding: const EdgeInsets.only(left: 12, right: 12, top: 8, bottom: 8),
child: (homeState.countdownFestivalListData == null) child: (homeState.countdownFestivalListData == null)
? SizedBox( ? SizedBox(
width: width, width: width,
height: 62, height: 62,
child: const Center( child: const Center(child: ProgressRing()),
child: ProgressRing(), )
), : SizedBox(
) width: width,
: SizedBox( height: 62,
width: width, child: Swiper(
height: 62, itemCount: getMinNumber([homeState.countdownFestivalListData!.length, 6]),
child: Swiper( autoplay: true,
itemCount: getMinNumber([homeState.countdownFestivalListData!.length, 6]), autoplayDelay: 5000,
autoplay: true, itemBuilder: (context, index) {
autoplayDelay: 5000, final item = homeState.countdownFestivalListData![index];
itemBuilder: (context, index) { return Row(
final item = homeState.countdownFestivalListData![index]; mainAxisAlignment: MainAxisAlignment.spaceEvenly,
return Row( children: [
mainAxisAlignment: MainAxisAlignment.spaceEvenly, if (item.icon != null && item.icon != "") ...[
children: [ ClipRRect(
if (item.icon != null && item.icon != "") ...[ borderRadius: BorderRadius.circular(1000),
ClipRRect( child: Image.asset(
borderRadius: BorderRadius.circular(1000), "assets/countdown/${item.icon}",
child: Image.asset( width: 48,
"assets/countdown/${item.icon}", height: 48,
width: 48, fit: BoxFit.cover,
height: 48,
fit: BoxFit.cover,
),
), ),
],
Column(
children: [
Text(
item.name ?? "",
style: const TextStyle(fontSize: 15),
),
const SizedBox(height: 3),
CountdownTimeText(
targetTime: DateTime.fromMillisecondsSinceEpoch(item.time ?? 0),
),
],
), ),
const SizedBox(width: 12),
Icon(
FluentIcons.chevron_right,
size: 14,
color: Colors.white.withValues(alpha: .6),
)
], ],
); Column(
}, children: [
), Text(item.name ?? "", style: const TextStyle(fontSize: 15)),
const SizedBox(height: 3),
CountdownTimeText(targetTime: DateTime.fromMillisecondsSinceEpoch(item.time ?? 0)),
],
),
const SizedBox(width: 12),
Icon(FluentIcons.chevron_right, size: 14, color: Colors.white.withValues(alpha: .6)),
],
);
},
), ),
)), ),
),
),
), ),
); );
} }
@ -736,13 +697,14 @@ class HomeUI extends HookConsumerWidget {
return; return;
case "doc": case "doc":
showDialog( showDialog(
context: context, context: context,
builder: (context) { builder: (context) {
return HomeMdContentDialogUI( return HomeMdContentDialogUI(
title: homeState.appPlacardData?.title ?? S.current.home_announcement_details, title: homeState.appPlacardData?.title ?? S.current.home_announcement_details,
url: homeState.appPlacardData?.link, url: homeState.appPlacardData?.link,
); );
}); },
);
return; return;
} }
} }
@ -804,15 +766,22 @@ class HomeUI extends HookConsumerWidget {
} }
void _checkAndGoInputMethod( void _checkAndGoInputMethod(
BuildContext context, HomeUIModelState homeState, HomeUIModel model, WidgetRef ref) async { BuildContext context,
HomeUIModelState homeState,
HomeUIModel model,
WidgetRef ref,
) async {
final localizationState = ref.read(localizationUIModelProvider); final localizationState = ref.read(localizationUIModelProvider);
if (localizationState.communityInputMethodLanguageData == null) { if (localizationState.communityInputMethodLanguageData == null) {
showToast(context, S.current.input_method_feature_maintenance); showToast(context, S.current.input_method_feature_maintenance);
return; return;
} }
if (localizationState.installedCommunityInputMethodSupportVersion == null) { if (localizationState.installedCommunityInputMethodSupportVersion == null) {
final userOK = await showConfirmDialogs(context, S.current.input_method_community_input_method_not_installed, final userOK = await showConfirmDialogs(
Text(S.current.input_method_install_community_input_method_prompt)); context,
S.current.input_method_community_input_method_not_installed,
Text(S.current.input_method_install_community_input_method_prompt),
);
if (userOK) { if (userOK) {
if (!context.mounted) return; if (!context.mounted) return;
() async { () async {
@ -837,10 +806,7 @@ class HomeUI extends HookConsumerWidget {
} }
Future<void> _goInputMethod(BuildContext context, HomeUIModel model) async { Future<void> _goInputMethod(BuildContext context, HomeUIModel model) async {
await showDialog( await showDialog(context: context, builder: (context) => const InputMethodDialogUI());
context: context,
builder: (context) => const InputMethodDialogUI(),
);
} }
} }

View File

@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:dart_rss/domain/rss_item.dart';
import 'package:desktop_webview_window/desktop_webview_window.dart'; import 'package:desktop_webview_window/desktop_webview_window.dart';
import 'package:fluent_ui/fluent_ui.dart'; import 'package:fluent_ui/fluent_ui.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@ -10,7 +9,7 @@ import 'package:hive_ce/hive.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:starcitizen_doctor/api/analytics.dart'; import 'package:starcitizen_doctor/api/analytics.dart';
import 'package:starcitizen_doctor/api/api.dart'; import 'package:starcitizen_doctor/api/api.dart';
import 'package:starcitizen_doctor/api/rss.dart'; import 'package:starcitizen_doctor/api/news_api.dart';
import 'package:starcitizen_doctor/common/conf/conf.dart'; import 'package:starcitizen_doctor/common/conf/conf.dart';
import 'package:starcitizen_doctor/common/conf/url_conf.dart'; import 'package:starcitizen_doctor/common/conf/url_conf.dart';
import 'package:starcitizen_doctor/common/helper/log_helper.dart'; import 'package:starcitizen_doctor/common/helper/log_helper.dart';
@ -23,12 +22,12 @@ import 'package:starcitizen_doctor/common/utils/log.dart';
import 'package:starcitizen_doctor/common/utils/provider.dart'; import 'package:starcitizen_doctor/common/utils/provider.dart';
import 'package:starcitizen_doctor/data/app_placard_data.dart'; import 'package:starcitizen_doctor/data/app_placard_data.dart';
import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart'; import 'package:starcitizen_doctor/data/app_web_localization_versions_data.dart';
import 'package:starcitizen_doctor/data/citizen_news_data.dart';
import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart'; import 'package:starcitizen_doctor/data/countdown_festival_item_data.dart';
import 'package:starcitizen_doctor/ui/home/dialogs/home_game_login_dialog_ui.dart'; import 'package:starcitizen_doctor/ui/home/dialogs/home_game_login_dialog_ui.dart';
import 'package:url_launcher/url_launcher_string.dart'; import 'package:url_launcher/url_launcher_string.dart';
import 'package:html/parser.dart' as html; import 'package:html/parser.dart' as html;
import 'package:html/dom.dart' as html_dom; import 'package:html/dom.dart' as html_dom;
import '../webview/webview.dart'; import '../webview/webview.dart';
import 'localization/localization_ui_model.dart'; import 'localization/localization_ui_model.dart';
@ -46,8 +45,7 @@ abstract class HomeUIModelState with _$HomeUIModelState {
@Default([]) List<String> scInstallPaths, @Default([]) List<String> scInstallPaths,
AppWebLocalizationVersionsData? webLocalizationVersionsData, AppWebLocalizationVersionsData? webLocalizationVersionsData,
@Default("") String lastScreenInfo, @Default("") String lastScreenInfo,
List<RssItem>? rssVideoItems, CitizenNewsData? citizenNewsData,
List<RssItem>? rssTextItems,
MapEntry<String, bool>? localizationUpdateInfo, MapEntry<String, bool>? localizationUpdateInfo,
List? scServerStatus, List? scServerStatus,
List<CountdownFestivalItemData>? countdownFestivalListData, List<CountdownFestivalItemData>? countdownFestivalListData,
@ -115,8 +113,9 @@ class HomeUIModel extends _$HomeUIModel {
} }
} }
String getRssImage(RssItem item) { String getRssImage(String? htmlString) {
final h = html.parse(item.description ?? ""); if (htmlString == null) return "";
final h = html.parse(htmlString);
if (h.body == null) return ""; if (h.body == null) return "";
for (var node in h.body!.nodes) { for (var node in h.body!.nodes) {
if (node is html_dom.Element) { if (node is html_dom.Element) {
@ -135,14 +134,15 @@ class HomeUIModel extends _$HomeUIModel {
return title; return title;
} }
// ignore: avoid_build_context_in_providers Future<void> goWebView(
Future<void> goWebView(BuildContext context, // ignore: avoid_build_context_in_providers
String title, BuildContext context,
String url, { String title,
bool useLocalization = false, String url, {
bool loginMode = false, bool useLocalization = false,
RsiLoginCallback? rsiLoginCallback, bool loginMode = false,
}) async { RsiLoginCallback? rsiLoginCallback,
}) async {
if (useLocalization) { if (useLocalization) {
const tipVersion = 2; const tipVersion = 2;
final box = await Hive.openBox("app_conf"); final box = await Hive.openBox("app_conf");
@ -153,10 +153,7 @@ class HomeUIModel extends _$HomeUIModel {
context, context,
S.current.home_action_title_star_citizen_website_localization, S.current.home_action_title_star_citizen_website_localization,
Text(S.current.home_action_info_web_localization_plugin_disclaimer, style: const TextStyle(fontSize: 16)), Text(S.current.home_action_info_web_localization_plugin_disclaimer, style: const TextStyle(fontSize: 16)),
constraints: BoxConstraints(maxWidth: MediaQuery constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * .6),
.of(context)
.size
.width * .6),
); );
if (!ok) { if (!ok) {
if (loginMode) { if (loginMode) {
@ -227,7 +224,8 @@ class HomeUIModel extends _$HomeUIModel {
final box = await Hive.openBox("app_conf"); final box = await Hive.openBox("app_conf");
final version = box.get("close_placard", defaultValue: ""); final version = box.get("close_placard", defaultValue: "");
if (r.enable == true) { if (r.enable == true) {
if (r.alwaysShow != true && version == r.version) {} else { if (r.alwaysShow != true && version == r.version) {
} else {
state = state.copyWith(appPlacardData: r); state = state.copyWith(appPlacardData: r);
} }
} }
@ -241,7 +239,7 @@ class HomeUIModel extends _$HomeUIModel {
countdownFestivalListData: _fixFestivalCountdownListDateTime(countdownFestivalListData), countdownFestivalListData: _fixFestivalCountdownListDateTime(countdownFestivalListData),
); );
_updateSCServerStatus(); _updateSCServerStatus();
_loadRRS(); _loadNews();
} catch (e) { } catch (e) {
dPrint(e); dPrint(e);
} }
@ -255,10 +253,10 @@ class HomeUIModel extends _$HomeUIModel {
return list.map((item) { return list.map((item) {
if (item.time == null) return item; if (item.time == null) return item;
final itemDateTime = DateTime.fromMillisecondsSinceEpoch(item.time! * 1000); final itemDateTime = DateTime.fromMillisecondsSinceEpoch(item.time!);
final itemDatePlusSeven = itemDateTime.add(const Duration(days: 7)); final itemDatePlusSeven = itemDateTime.add(const Duration(days: 7));
if (itemDatePlusSeven.isBefore(now)) { if (itemDatePlusSeven.isBefore(now)) {
final nextYearDate = DateTime( final nextDate = DateTime(
now.year + 1, now.year + 1,
itemDateTime.month, itemDateTime.month,
itemDateTime.day, itemDateTime.day,
@ -266,7 +264,7 @@ class HomeUIModel extends _$HomeUIModel {
itemDateTime.minute, itemDateTime.minute,
itemDateTime.second, itemDateTime.second,
); );
final newTimestamp = (nextYearDate.millisecondsSinceEpoch / 1000).round(); final newTimestamp = (nextDate.millisecondsSinceEpoch).round();
return CountdownFestivalItemData(name: item.name, time: newTimestamp, icon: item.icon); return CountdownFestivalItemData(name: item.name, time: newTimestamp, icon: item.icon);
} }
@ -284,23 +282,9 @@ class HomeUIModel extends _$HomeUIModel {
} }
} }
Future _loadRRS() async { Future _loadNews() async {
try { final news = await NewsApi.getLatest();
final rssVideoItems = await RSSApi.getRssVideo(); state = state.copyWith(citizenNewsData: news ?? CitizenNewsData());
state = state.copyWith(rssVideoItems: rssVideoItems);
final rssTextItems = await RSSApi.getRssText();
state = state.copyWith(rssTextItems: rssTextItems);
dPrint("RSS update Success !");
} catch (e) {
dPrint("_loadRRS Error:$e");
// loading
if (state.rssTextItems == null) {
state = state.copyWith(rssTextItems: []);
}
if (state.rssVideoItems == null) {
state = state.copyWith(rssVideoItems: []);
}
}
} }
Future<void> checkLocalizationUpdate({bool skipReload = false}) async { Future<void> checkLocalizationUpdate({bool skipReload = false}) async {
@ -362,12 +346,14 @@ class HomeUIModel extends _$HomeUIModel {
ref.read(localizationUIModelProvider.notifier).onChangeGameInstallPath(value); ref.read(localizationUIModelProvider.notifier).onChangeGameInstallPath(value);
} }
Future<void> doLaunchGame(// ignore: avoid_build_context_in_providers Future<void> doLaunchGame(
BuildContext context, // ignore: avoid_build_context_in_providers
String launchExe, BuildContext context,
List<String> args, String launchExe,
String installPath, List<String> args,
String? processorAffinity,) async { String installPath,
String? processorAffinity,
) async {
var runningMap = Map<String, bool>.from(state.isGameRunning); var runningMap = Map<String, bool>.from(state.isGameRunning);
runningMap[installPath] = true; runningMap[installPath] = true;
state = state.copyWith(isGameRunning: runningMap); state = state.copyWith(isGameRunning: runningMap);

View File

@ -14,7 +14,7 @@ T _$identity<T>(T value) => value;
/// @nodoc /// @nodoc
mixin _$HomeUIModelState { mixin _$HomeUIModelState {
AppPlacardData? get appPlacardData; bool get isFixing; String get isFixingString; String? get scInstalledPath; List<String> get scInstallPaths; AppWebLocalizationVersionsData? get webLocalizationVersionsData; String get lastScreenInfo; List<RssItem>? get rssVideoItems; List<RssItem>? get rssTextItems; MapEntry<String, bool>? get localizationUpdateInfo; List? get scServerStatus; List<CountdownFestivalItemData>? get countdownFestivalListData; Map<String, bool> get isGameRunning; AppPlacardData? get appPlacardData; bool get isFixing; String get isFixingString; String? get scInstalledPath; List<String> get scInstallPaths; AppWebLocalizationVersionsData? get webLocalizationVersionsData; String get lastScreenInfo; CitizenNewsData? get citizenNewsData; MapEntry<String, bool>? get localizationUpdateInfo; List? get scServerStatus; List<CountdownFestivalItemData>? get countdownFestivalListData; Map<String, bool> get isGameRunning;
/// Create a copy of HomeUIModelState /// Create a copy of HomeUIModelState
/// 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)
@ -25,16 +25,16 @@ $HomeUIModelStateCopyWith<HomeUIModelState> get copyWith => _$HomeUIModelStateCo
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeUIModelState&&(identical(other.appPlacardData, appPlacardData) || other.appPlacardData == appPlacardData)&&(identical(other.isFixing, isFixing) || other.isFixing == isFixing)&&(identical(other.isFixingString, isFixingString) || other.isFixingString == isFixingString)&&(identical(other.scInstalledPath, scInstalledPath) || other.scInstalledPath == scInstalledPath)&&const DeepCollectionEquality().equals(other.scInstallPaths, scInstallPaths)&&(identical(other.webLocalizationVersionsData, webLocalizationVersionsData) || other.webLocalizationVersionsData == webLocalizationVersionsData)&&(identical(other.lastScreenInfo, lastScreenInfo) || other.lastScreenInfo == lastScreenInfo)&&const DeepCollectionEquality().equals(other.rssVideoItems, rssVideoItems)&&const DeepCollectionEquality().equals(other.rssTextItems, rssTextItems)&&(identical(other.localizationUpdateInfo, localizationUpdateInfo) || other.localizationUpdateInfo == localizationUpdateInfo)&&const DeepCollectionEquality().equals(other.scServerStatus, scServerStatus)&&const DeepCollectionEquality().equals(other.countdownFestivalListData, countdownFestivalListData)&&const DeepCollectionEquality().equals(other.isGameRunning, isGameRunning)); return identical(this, other) || (other.runtimeType == runtimeType&&other is HomeUIModelState&&(identical(other.appPlacardData, appPlacardData) || other.appPlacardData == appPlacardData)&&(identical(other.isFixing, isFixing) || other.isFixing == isFixing)&&(identical(other.isFixingString, isFixingString) || other.isFixingString == isFixingString)&&(identical(other.scInstalledPath, scInstalledPath) || other.scInstalledPath == scInstalledPath)&&const DeepCollectionEquality().equals(other.scInstallPaths, scInstallPaths)&&(identical(other.webLocalizationVersionsData, webLocalizationVersionsData) || other.webLocalizationVersionsData == webLocalizationVersionsData)&&(identical(other.lastScreenInfo, lastScreenInfo) || other.lastScreenInfo == lastScreenInfo)&&(identical(other.citizenNewsData, citizenNewsData) || other.citizenNewsData == citizenNewsData)&&(identical(other.localizationUpdateInfo, localizationUpdateInfo) || other.localizationUpdateInfo == localizationUpdateInfo)&&const DeepCollectionEquality().equals(other.scServerStatus, scServerStatus)&&const DeepCollectionEquality().equals(other.countdownFestivalListData, countdownFestivalListData)&&const DeepCollectionEquality().equals(other.isGameRunning, isGameRunning));
} }
@override @override
int get hashCode => Object.hash(runtimeType,appPlacardData,isFixing,isFixingString,scInstalledPath,const DeepCollectionEquality().hash(scInstallPaths),webLocalizationVersionsData,lastScreenInfo,const DeepCollectionEquality().hash(rssVideoItems),const DeepCollectionEquality().hash(rssTextItems),localizationUpdateInfo,const DeepCollectionEquality().hash(scServerStatus),const DeepCollectionEquality().hash(countdownFestivalListData),const DeepCollectionEquality().hash(isGameRunning)); int get hashCode => Object.hash(runtimeType,appPlacardData,isFixing,isFixingString,scInstalledPath,const DeepCollectionEquality().hash(scInstallPaths),webLocalizationVersionsData,lastScreenInfo,citizenNewsData,localizationUpdateInfo,const DeepCollectionEquality().hash(scServerStatus),const DeepCollectionEquality().hash(countdownFestivalListData),const DeepCollectionEquality().hash(isGameRunning));
@override @override
String toString() { String toString() {
return 'HomeUIModelState(appPlacardData: $appPlacardData, isFixing: $isFixing, isFixingString: $isFixingString, scInstalledPath: $scInstalledPath, scInstallPaths: $scInstallPaths, webLocalizationVersionsData: $webLocalizationVersionsData, lastScreenInfo: $lastScreenInfo, rssVideoItems: $rssVideoItems, rssTextItems: $rssTextItems, localizationUpdateInfo: $localizationUpdateInfo, scServerStatus: $scServerStatus, countdownFestivalListData: $countdownFestivalListData, isGameRunning: $isGameRunning)'; return 'HomeUIModelState(appPlacardData: $appPlacardData, isFixing: $isFixing, isFixingString: $isFixingString, scInstalledPath: $scInstalledPath, scInstallPaths: $scInstallPaths, webLocalizationVersionsData: $webLocalizationVersionsData, lastScreenInfo: $lastScreenInfo, citizenNewsData: $citizenNewsData, localizationUpdateInfo: $localizationUpdateInfo, scServerStatus: $scServerStatus, countdownFestivalListData: $countdownFestivalListData, isGameRunning: $isGameRunning)';
} }
@ -45,11 +45,11 @@ abstract mixin class $HomeUIModelStateCopyWith<$Res> {
factory $HomeUIModelStateCopyWith(HomeUIModelState value, $Res Function(HomeUIModelState) _then) = _$HomeUIModelStateCopyWithImpl; factory $HomeUIModelStateCopyWith(HomeUIModelState value, $Res Function(HomeUIModelState) _then) = _$HomeUIModelStateCopyWithImpl;
@useResult @useResult
$Res call({ $Res call({
AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, List<RssItem>? rssVideoItems, List<RssItem>? rssTextItems, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, CitizenNewsData? citizenNewsData, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning
}); });
$CitizenNewsDataCopyWith<$Res>? get citizenNewsData;
} }
/// @nodoc /// @nodoc
@ -62,7 +62,7 @@ class _$HomeUIModelStateCopyWithImpl<$Res>
/// Create a copy of HomeUIModelState /// Create a copy of HomeUIModelState
/// 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? appPlacardData = freezed,Object? isFixing = null,Object? isFixingString = null,Object? scInstalledPath = freezed,Object? scInstallPaths = null,Object? webLocalizationVersionsData = freezed,Object? lastScreenInfo = null,Object? rssVideoItems = freezed,Object? rssTextItems = freezed,Object? localizationUpdateInfo = freezed,Object? scServerStatus = freezed,Object? countdownFestivalListData = freezed,Object? isGameRunning = null,}) { @pragma('vm:prefer-inline') @override $Res call({Object? appPlacardData = freezed,Object? isFixing = null,Object? isFixingString = null,Object? scInstalledPath = freezed,Object? scInstallPaths = null,Object? webLocalizationVersionsData = freezed,Object? lastScreenInfo = null,Object? citizenNewsData = freezed,Object? localizationUpdateInfo = freezed,Object? scServerStatus = freezed,Object? countdownFestivalListData = freezed,Object? isGameRunning = null,}) {
return _then(_self.copyWith( return _then(_self.copyWith(
appPlacardData: freezed == appPlacardData ? _self.appPlacardData : appPlacardData // ignore: cast_nullable_to_non_nullable appPlacardData: freezed == appPlacardData ? _self.appPlacardData : appPlacardData // ignore: cast_nullable_to_non_nullable
as AppPlacardData?,isFixing: null == isFixing ? _self.isFixing : isFixing // ignore: cast_nullable_to_non_nullable as AppPlacardData?,isFixing: null == isFixing ? _self.isFixing : isFixing // ignore: cast_nullable_to_non_nullable
@ -71,16 +71,27 @@ as String,scInstalledPath: freezed == scInstalledPath ? _self.scInstalledPath :
as String?,scInstallPaths: null == scInstallPaths ? _self.scInstallPaths : scInstallPaths // ignore: cast_nullable_to_non_nullable as String?,scInstallPaths: null == scInstallPaths ? _self.scInstallPaths : scInstallPaths // ignore: cast_nullable_to_non_nullable
as List<String>,webLocalizationVersionsData: freezed == webLocalizationVersionsData ? _self.webLocalizationVersionsData : webLocalizationVersionsData // ignore: cast_nullable_to_non_nullable as List<String>,webLocalizationVersionsData: freezed == webLocalizationVersionsData ? _self.webLocalizationVersionsData : webLocalizationVersionsData // ignore: cast_nullable_to_non_nullable
as AppWebLocalizationVersionsData?,lastScreenInfo: null == lastScreenInfo ? _self.lastScreenInfo : lastScreenInfo // ignore: cast_nullable_to_non_nullable as AppWebLocalizationVersionsData?,lastScreenInfo: null == lastScreenInfo ? _self.lastScreenInfo : lastScreenInfo // ignore: cast_nullable_to_non_nullable
as String,rssVideoItems: freezed == rssVideoItems ? _self.rssVideoItems : rssVideoItems // ignore: cast_nullable_to_non_nullable as String,citizenNewsData: freezed == citizenNewsData ? _self.citizenNewsData : citizenNewsData // ignore: cast_nullable_to_non_nullable
as List<RssItem>?,rssTextItems: freezed == rssTextItems ? _self.rssTextItems : rssTextItems // ignore: cast_nullable_to_non_nullable as CitizenNewsData?,localizationUpdateInfo: freezed == localizationUpdateInfo ? _self.localizationUpdateInfo : localizationUpdateInfo // ignore: cast_nullable_to_non_nullable
as List<RssItem>?,localizationUpdateInfo: freezed == localizationUpdateInfo ? _self.localizationUpdateInfo : localizationUpdateInfo // ignore: cast_nullable_to_non_nullable
as MapEntry<String, bool>?,scServerStatus: freezed == scServerStatus ? _self.scServerStatus : scServerStatus // ignore: cast_nullable_to_non_nullable as MapEntry<String, bool>?,scServerStatus: freezed == scServerStatus ? _self.scServerStatus : scServerStatus // ignore: cast_nullable_to_non_nullable
as List?,countdownFestivalListData: freezed == countdownFestivalListData ? _self.countdownFestivalListData : countdownFestivalListData // ignore: cast_nullable_to_non_nullable as List?,countdownFestivalListData: freezed == countdownFestivalListData ? _self.countdownFestivalListData : countdownFestivalListData // ignore: cast_nullable_to_non_nullable
as List<CountdownFestivalItemData>?,isGameRunning: null == isGameRunning ? _self.isGameRunning : isGameRunning // ignore: cast_nullable_to_non_nullable as List<CountdownFestivalItemData>?,isGameRunning: null == isGameRunning ? _self.isGameRunning : isGameRunning // ignore: cast_nullable_to_non_nullable
as Map<String, bool>, as Map<String, bool>,
)); ));
} }
/// Create a copy of HomeUIModelState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CitizenNewsDataCopyWith<$Res>? get citizenNewsData {
if (_self.citizenNewsData == null) {
return null;
}
return $CitizenNewsDataCopyWith<$Res>(_self.citizenNewsData!, (value) {
return _then(_self.copyWith(citizenNewsData: value));
});
}
} }
@ -162,10 +173,10 @@ return $default(_that);case _:
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, List<RssItem>? rssVideoItems, List<RssItem>? rssTextItems, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning)? $default,{required TResult orElse(),}) {final _that = this; @optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, CitizenNewsData? citizenNewsData, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) { switch (_that) {
case _HomeUIModelState() when $default != null: case _HomeUIModelState() when $default != null:
return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.rssVideoItems,_that.rssTextItems,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _: return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.citizenNewsData,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _:
return orElse(); return orElse();
} }
@ -183,10 +194,10 @@ return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.s
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, List<RssItem>? rssVideoItems, List<RssItem>? rssTextItems, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning) $default,) {final _that = this; @optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, CitizenNewsData? citizenNewsData, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning) $default,) {final _that = this;
switch (_that) { switch (_that) {
case _HomeUIModelState(): case _HomeUIModelState():
return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.rssVideoItems,_that.rssTextItems,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _: return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.citizenNewsData,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _:
throw StateError('Unexpected subclass'); throw StateError('Unexpected subclass');
} }
@ -203,10 +214,10 @@ return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.s
/// } /// }
/// ``` /// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, List<RssItem>? rssVideoItems, List<RssItem>? rssTextItems, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning)? $default,) {final _that = this; @optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, CitizenNewsData? citizenNewsData, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning)? $default,) {final _that = this;
switch (_that) { switch (_that) {
case _HomeUIModelState() when $default != null: case _HomeUIModelState() when $default != null:
return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.rssVideoItems,_that.rssTextItems,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _: return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.scInstalledPath,_that.scInstallPaths,_that.webLocalizationVersionsData,_that.lastScreenInfo,_that.citizenNewsData,_that.localizationUpdateInfo,_that.scServerStatus,_that.countdownFestivalListData,_that.isGameRunning);case _:
return null; return null;
} }
@ -218,7 +229,7 @@ return $default(_that.appPlacardData,_that.isFixing,_that.isFixingString,_that.s
class _HomeUIModelState implements HomeUIModelState { class _HomeUIModelState implements HomeUIModelState {
_HomeUIModelState({this.appPlacardData, this.isFixing = false, this.isFixingString = "", this.scInstalledPath, final List<String> scInstallPaths = const [], this.webLocalizationVersionsData, this.lastScreenInfo = "", final List<RssItem>? rssVideoItems, final List<RssItem>? rssTextItems, this.localizationUpdateInfo, final List? scServerStatus, final List<CountdownFestivalItemData>? countdownFestivalListData, final Map<String, bool> isGameRunning = const {}}): _scInstallPaths = scInstallPaths,_rssVideoItems = rssVideoItems,_rssTextItems = rssTextItems,_scServerStatus = scServerStatus,_countdownFestivalListData = countdownFestivalListData,_isGameRunning = isGameRunning; _HomeUIModelState({this.appPlacardData, this.isFixing = false, this.isFixingString = "", this.scInstalledPath, final List<String> scInstallPaths = const [], this.webLocalizationVersionsData, this.lastScreenInfo = "", this.citizenNewsData, this.localizationUpdateInfo, final List? scServerStatus, final List<CountdownFestivalItemData>? countdownFestivalListData, final Map<String, bool> isGameRunning = const {}}): _scInstallPaths = scInstallPaths,_scServerStatus = scServerStatus,_countdownFestivalListData = countdownFestivalListData,_isGameRunning = isGameRunning;
@override final AppPlacardData? appPlacardData; @override final AppPlacardData? appPlacardData;
@ -234,24 +245,7 @@ class _HomeUIModelState implements HomeUIModelState {
@override final AppWebLocalizationVersionsData? webLocalizationVersionsData; @override final AppWebLocalizationVersionsData? webLocalizationVersionsData;
@override@JsonKey() final String lastScreenInfo; @override@JsonKey() final String lastScreenInfo;
final List<RssItem>? _rssVideoItems; @override final CitizenNewsData? citizenNewsData;
@override List<RssItem>? get rssVideoItems {
final value = _rssVideoItems;
if (value == null) return null;
if (_rssVideoItems is EqualUnmodifiableListView) return _rssVideoItems;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
final List<RssItem>? _rssTextItems;
@override List<RssItem>? get rssTextItems {
final value = _rssTextItems;
if (value == null) return null;
if (_rssTextItems is EqualUnmodifiableListView) return _rssTextItems;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(value);
}
@override final MapEntry<String, bool>? localizationUpdateInfo; @override final MapEntry<String, bool>? localizationUpdateInfo;
final List? _scServerStatus; final List? _scServerStatus;
@override List? get scServerStatus { @override List? get scServerStatus {
@ -289,16 +283,16 @@ _$HomeUIModelStateCopyWith<_HomeUIModelState> get copyWith => __$HomeUIModelStat
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeUIModelState&&(identical(other.appPlacardData, appPlacardData) || other.appPlacardData == appPlacardData)&&(identical(other.isFixing, isFixing) || other.isFixing == isFixing)&&(identical(other.isFixingString, isFixingString) || other.isFixingString == isFixingString)&&(identical(other.scInstalledPath, scInstalledPath) || other.scInstalledPath == scInstalledPath)&&const DeepCollectionEquality().equals(other._scInstallPaths, _scInstallPaths)&&(identical(other.webLocalizationVersionsData, webLocalizationVersionsData) || other.webLocalizationVersionsData == webLocalizationVersionsData)&&(identical(other.lastScreenInfo, lastScreenInfo) || other.lastScreenInfo == lastScreenInfo)&&const DeepCollectionEquality().equals(other._rssVideoItems, _rssVideoItems)&&const DeepCollectionEquality().equals(other._rssTextItems, _rssTextItems)&&(identical(other.localizationUpdateInfo, localizationUpdateInfo) || other.localizationUpdateInfo == localizationUpdateInfo)&&const DeepCollectionEquality().equals(other._scServerStatus, _scServerStatus)&&const DeepCollectionEquality().equals(other._countdownFestivalListData, _countdownFestivalListData)&&const DeepCollectionEquality().equals(other._isGameRunning, _isGameRunning)); return identical(this, other) || (other.runtimeType == runtimeType&&other is _HomeUIModelState&&(identical(other.appPlacardData, appPlacardData) || other.appPlacardData == appPlacardData)&&(identical(other.isFixing, isFixing) || other.isFixing == isFixing)&&(identical(other.isFixingString, isFixingString) || other.isFixingString == isFixingString)&&(identical(other.scInstalledPath, scInstalledPath) || other.scInstalledPath == scInstalledPath)&&const DeepCollectionEquality().equals(other._scInstallPaths, _scInstallPaths)&&(identical(other.webLocalizationVersionsData, webLocalizationVersionsData) || other.webLocalizationVersionsData == webLocalizationVersionsData)&&(identical(other.lastScreenInfo, lastScreenInfo) || other.lastScreenInfo == lastScreenInfo)&&(identical(other.citizenNewsData, citizenNewsData) || other.citizenNewsData == citizenNewsData)&&(identical(other.localizationUpdateInfo, localizationUpdateInfo) || other.localizationUpdateInfo == localizationUpdateInfo)&&const DeepCollectionEquality().equals(other._scServerStatus, _scServerStatus)&&const DeepCollectionEquality().equals(other._countdownFestivalListData, _countdownFestivalListData)&&const DeepCollectionEquality().equals(other._isGameRunning, _isGameRunning));
} }
@override @override
int get hashCode => Object.hash(runtimeType,appPlacardData,isFixing,isFixingString,scInstalledPath,const DeepCollectionEquality().hash(_scInstallPaths),webLocalizationVersionsData,lastScreenInfo,const DeepCollectionEquality().hash(_rssVideoItems),const DeepCollectionEquality().hash(_rssTextItems),localizationUpdateInfo,const DeepCollectionEquality().hash(_scServerStatus),const DeepCollectionEquality().hash(_countdownFestivalListData),const DeepCollectionEquality().hash(_isGameRunning)); int get hashCode => Object.hash(runtimeType,appPlacardData,isFixing,isFixingString,scInstalledPath,const DeepCollectionEquality().hash(_scInstallPaths),webLocalizationVersionsData,lastScreenInfo,citizenNewsData,localizationUpdateInfo,const DeepCollectionEquality().hash(_scServerStatus),const DeepCollectionEquality().hash(_countdownFestivalListData),const DeepCollectionEquality().hash(_isGameRunning));
@override @override
String toString() { String toString() {
return 'HomeUIModelState(appPlacardData: $appPlacardData, isFixing: $isFixing, isFixingString: $isFixingString, scInstalledPath: $scInstalledPath, scInstallPaths: $scInstallPaths, webLocalizationVersionsData: $webLocalizationVersionsData, lastScreenInfo: $lastScreenInfo, rssVideoItems: $rssVideoItems, rssTextItems: $rssTextItems, localizationUpdateInfo: $localizationUpdateInfo, scServerStatus: $scServerStatus, countdownFestivalListData: $countdownFestivalListData, isGameRunning: $isGameRunning)'; return 'HomeUIModelState(appPlacardData: $appPlacardData, isFixing: $isFixing, isFixingString: $isFixingString, scInstalledPath: $scInstalledPath, scInstallPaths: $scInstallPaths, webLocalizationVersionsData: $webLocalizationVersionsData, lastScreenInfo: $lastScreenInfo, citizenNewsData: $citizenNewsData, localizationUpdateInfo: $localizationUpdateInfo, scServerStatus: $scServerStatus, countdownFestivalListData: $countdownFestivalListData, isGameRunning: $isGameRunning)';
} }
@ -309,11 +303,11 @@ abstract mixin class _$HomeUIModelStateCopyWith<$Res> implements $HomeUIModelSta
factory _$HomeUIModelStateCopyWith(_HomeUIModelState value, $Res Function(_HomeUIModelState) _then) = __$HomeUIModelStateCopyWithImpl; factory _$HomeUIModelStateCopyWith(_HomeUIModelState value, $Res Function(_HomeUIModelState) _then) = __$HomeUIModelStateCopyWithImpl;
@override @useResult @override @useResult
$Res call({ $Res call({
AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, List<RssItem>? rssVideoItems, List<RssItem>? rssTextItems, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning AppPlacardData? appPlacardData, bool isFixing, String isFixingString, String? scInstalledPath, List<String> scInstallPaths, AppWebLocalizationVersionsData? webLocalizationVersionsData, String lastScreenInfo, CitizenNewsData? citizenNewsData, MapEntry<String, bool>? localizationUpdateInfo, List? scServerStatus, List<CountdownFestivalItemData>? countdownFestivalListData, Map<String, bool> isGameRunning
}); });
@override $CitizenNewsDataCopyWith<$Res>? get citizenNewsData;
} }
/// @nodoc /// @nodoc
@ -326,7 +320,7 @@ class __$HomeUIModelStateCopyWithImpl<$Res>
/// Create a copy of HomeUIModelState /// Create a copy of HomeUIModelState
/// 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? appPlacardData = freezed,Object? isFixing = null,Object? isFixingString = null,Object? scInstalledPath = freezed,Object? scInstallPaths = null,Object? webLocalizationVersionsData = freezed,Object? lastScreenInfo = null,Object? rssVideoItems = freezed,Object? rssTextItems = freezed,Object? localizationUpdateInfo = freezed,Object? scServerStatus = freezed,Object? countdownFestivalListData = freezed,Object? isGameRunning = null,}) { @override @pragma('vm:prefer-inline') $Res call({Object? appPlacardData = freezed,Object? isFixing = null,Object? isFixingString = null,Object? scInstalledPath = freezed,Object? scInstallPaths = null,Object? webLocalizationVersionsData = freezed,Object? lastScreenInfo = null,Object? citizenNewsData = freezed,Object? localizationUpdateInfo = freezed,Object? scServerStatus = freezed,Object? countdownFestivalListData = freezed,Object? isGameRunning = null,}) {
return _then(_HomeUIModelState( return _then(_HomeUIModelState(
appPlacardData: freezed == appPlacardData ? _self.appPlacardData : appPlacardData // ignore: cast_nullable_to_non_nullable appPlacardData: freezed == appPlacardData ? _self.appPlacardData : appPlacardData // ignore: cast_nullable_to_non_nullable
as AppPlacardData?,isFixing: null == isFixing ? _self.isFixing : isFixing // ignore: cast_nullable_to_non_nullable as AppPlacardData?,isFixing: null == isFixing ? _self.isFixing : isFixing // ignore: cast_nullable_to_non_nullable
@ -335,9 +329,8 @@ as String,scInstalledPath: freezed == scInstalledPath ? _self.scInstalledPath :
as String?,scInstallPaths: null == scInstallPaths ? _self._scInstallPaths : scInstallPaths // ignore: cast_nullable_to_non_nullable as String?,scInstallPaths: null == scInstallPaths ? _self._scInstallPaths : scInstallPaths // ignore: cast_nullable_to_non_nullable
as List<String>,webLocalizationVersionsData: freezed == webLocalizationVersionsData ? _self.webLocalizationVersionsData : webLocalizationVersionsData // ignore: cast_nullable_to_non_nullable as List<String>,webLocalizationVersionsData: freezed == webLocalizationVersionsData ? _self.webLocalizationVersionsData : webLocalizationVersionsData // ignore: cast_nullable_to_non_nullable
as AppWebLocalizationVersionsData?,lastScreenInfo: null == lastScreenInfo ? _self.lastScreenInfo : lastScreenInfo // ignore: cast_nullable_to_non_nullable as AppWebLocalizationVersionsData?,lastScreenInfo: null == lastScreenInfo ? _self.lastScreenInfo : lastScreenInfo // ignore: cast_nullable_to_non_nullable
as String,rssVideoItems: freezed == rssVideoItems ? _self._rssVideoItems : rssVideoItems // ignore: cast_nullable_to_non_nullable as String,citizenNewsData: freezed == citizenNewsData ? _self.citizenNewsData : citizenNewsData // ignore: cast_nullable_to_non_nullable
as List<RssItem>?,rssTextItems: freezed == rssTextItems ? _self._rssTextItems : rssTextItems // ignore: cast_nullable_to_non_nullable as CitizenNewsData?,localizationUpdateInfo: freezed == localizationUpdateInfo ? _self.localizationUpdateInfo : localizationUpdateInfo // ignore: cast_nullable_to_non_nullable
as List<RssItem>?,localizationUpdateInfo: freezed == localizationUpdateInfo ? _self.localizationUpdateInfo : localizationUpdateInfo // ignore: cast_nullable_to_non_nullable
as MapEntry<String, bool>?,scServerStatus: freezed == scServerStatus ? _self._scServerStatus : scServerStatus // ignore: cast_nullable_to_non_nullable as MapEntry<String, bool>?,scServerStatus: freezed == scServerStatus ? _self._scServerStatus : scServerStatus // ignore: cast_nullable_to_non_nullable
as List?,countdownFestivalListData: freezed == countdownFestivalListData ? _self._countdownFestivalListData : countdownFestivalListData // ignore: cast_nullable_to_non_nullable as List?,countdownFestivalListData: freezed == countdownFestivalListData ? _self._countdownFestivalListData : countdownFestivalListData // ignore: cast_nullable_to_non_nullable
as List<CountdownFestivalItemData>?,isGameRunning: null == isGameRunning ? _self._isGameRunning : isGameRunning // ignore: cast_nullable_to_non_nullable as List<CountdownFestivalItemData>?,isGameRunning: null == isGameRunning ? _self._isGameRunning : isGameRunning // ignore: cast_nullable_to_non_nullable
@ -345,7 +338,19 @@ as Map<String, bool>,
)); ));
} }
/// Create a copy of HomeUIModelState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$CitizenNewsDataCopyWith<$Res>? get citizenNewsData {
if (_self.citizenNewsData == null) {
return null;
}
return $CitizenNewsDataCopyWith<$Res>(_self.citizenNewsData!, (value) {
return _then(_self.copyWith(citizenNewsData: value));
});
}
} }
// dart format on // dart format on

View File

@ -41,7 +41,7 @@ final class HomeUIModelProvider
} }
} }
String _$homeUIModelHash() => r'84eb149f999237410a7e0a95b74bd5729c2726d4'; String _$homeUIModelHash() => r'9dc8191f358c2d8e21ed931b3755e08ce394558e';
abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> { abstract class _$HomeUIModel extends $Notifier<HomeUIModelState> {
HomeUIModelState build(); HomeUIModelState build();

View File

@ -41,7 +41,7 @@ final class SettingsUIModelProvider
} }
} }
String _$settingsUIModelHash() => r'd19104d924f018a9230548d0372692fc344adacd'; String _$settingsUIModelHash() => r'5c08c56bf5464ef44bee8edb8c18c08d4217f135';
abstract class _$SettingsUIModel extends $Notifier<SettingsUIState> { abstract class _$SettingsUIModel extends $Notifier<SettingsUIState> {
SettingsUIState build(); SettingsUIState build();

View File

@ -10,12 +10,13 @@ class FlowNumberText extends HookConsumerWidget {
final TextStyle? style; final TextStyle? style;
final Curve curve; final Curve curve;
FlowNumberText( FlowNumberText({
{super.key, super.key,
required this.targetValue, required this.targetValue,
this.duration = const Duration(seconds: 1), this.duration = const Duration(seconds: 1),
this.style, this.style,
this.curve = Curves.bounceOut}); this.curve = Curves.bounceOut,
});
final _formatter = NumberFormat.decimalPattern(); final _formatter = NumberFormat.decimalPattern();
@ -46,9 +47,6 @@ class FlowNumberText extends HookConsumerWidget {
return timer.value?.cancel; return timer.value?.cancel;
}, [targetValue]); }, [targetValue]);
return Text( return Text(_formatter.format(value.value.toInt()), style: style);
_formatter.format(value.value.toInt()),
style: style,
);
} }
} }

View File

@ -20,19 +20,14 @@ class GridItemAnimator extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// //
final animationController = useAnimationController( final animationController = useAnimationController(duration: duration);
duration: duration,
);
// //
final opacityAnimation = useAnimation( final opacityAnimation = useAnimation(
Tween<double>( Tween<double>(
begin: 0.0, // begin: 0.0, //
end: 1.0, // end: 1.0, //
).animate(CurvedAnimation( ).animate(CurvedAnimation(parent: animationController, curve: Curves.easeOut)),
parent: animationController,
curve: Curves.easeOut,
)),
); );
// //
@ -40,23 +35,24 @@ class GridItemAnimator extends HookWidget {
Tween<double>( Tween<double>(
begin: 1.0, // begin: 1.0, //
end: 0.0, // end: 0.0, //
).animate(CurvedAnimation( ).animate(CurvedAnimation(parent: animationController, curve: Curves.easeOutCubic)),
parent: animationController,
curve: Curves.easeOutCubic,
)),
); );
// //
useEffect(() { useEffect(() {
// //
final delay = delayPerItem * index; final delay = delayPerItem * index;
bool cancelled = false;
Future.delayed(delay, () { Future.delayed(delay, () {
if (animationController.status != AnimationStatus.completed) { if (!cancelled && animationController.status != AnimationStatus.completed) {
animationController.forward(); animationController.forward();
} }
}); });
return null;
return () {
cancelled = true;
};
}, const []); }, const []);
// //

115
lib/widgets/src/swiper.dart Normal file
View File

@ -0,0 +1,115 @@
import 'package:card_swiper/card_swiper.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:flutter_tilt/flutter_tilt.dart';
class HoverSwiper extends HookWidget {
const HoverSwiper({
super.key,
required this.itemCount,
required this.itemBuilder,
this.autoplayDelay = 3000,
this.paginationActiveSize = 8.0,
this.controlSize = 24,
this.controlPadding = const EdgeInsets.symmetric(horizontal: 8, vertical: 0),
});
final int itemCount;
final IndexedWidgetBuilder itemBuilder;
final double paginationActiveSize;
final double controlSize;
final EdgeInsets controlPadding;
final int autoplayDelay;
@override
Widget build(BuildContext context) {
final isHovered = useState(false);
final controller = useMemoized(() => SwiperController());
useEffect(() {
return controller.dispose;
}, [controller]);
return MouseRegion(
onEnter: (_) {
isHovered.value = true;
controller.stopAutoplay();
},
onExit: (_) {
isHovered.value = false;
controller.startAutoplay();
},
child: Stack(
children: [
Tilt(
shadowConfig: const ShadowConfig(maxIntensity: .3),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(12), topRight: Radius.circular(12)),
child: Swiper(
controller: controller,
itemCount: itemCount,
itemBuilder: itemBuilder,
autoplay: true,
autoplayDelay: autoplayDelay,
),
),
// Left control button
_buildControlButton(
isHovered: isHovered.value,
position: 'left',
onTap: () => controller.previous(),
icon: FluentIcons.chevron_left,
),
// Right control button
_buildControlButton(
isHovered: isHovered.value,
position: 'right',
onTap: () => controller.next(),
icon: FluentIcons.chevron_right,
),
],
),
);
}
/// /
Widget _buildControlButton({
required bool isHovered,
required String position,
required VoidCallback onTap,
required IconData icon,
}) {
final isLeft = position == 'left';
return Positioned(
left: isLeft ? 0 : null,
right: isLeft ? null : 0,
top: 0,
bottom: 0,
child: AnimatedOpacity(
opacity: isHovered ? 1.0 : 0.0,
duration: const Duration(milliseconds: 200),
child: IgnorePointer(
ignoring: !isHovered,
child: Center(
child: Padding(
padding: controlPadding,
child: MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
onTap: onTap,
child: Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: .3),
borderRadius: BorderRadius.circular(4),
),
child: Icon(icon, size: controlSize, color: Colors.white.withValues(alpha: .8)),
),
),
),
),
),
),
),
);
}
}

View File

@ -17,53 +17,42 @@ export 'src/cache_image.dart';
export 'src/countdown_time_text.dart'; export 'src/countdown_time_text.dart';
export 'src/cache_svg_image.dart'; export 'src/cache_svg_image.dart';
export 'src/grid_item_animator.dart'; export 'src/grid_item_animator.dart';
export 'src/swiper.dart';
export '../common/utils/async.dart'; export '../common/utils/async.dart';
export '../common/utils/base_utils.dart'; export '../common/utils/base_utils.dart';
export 'package:starcitizen_doctor/generated/l10n.dart'; export 'package:starcitizen_doctor/generated/l10n.dart';
Widget makeLoading( Widget makeLoading(BuildContext context, {double? width}) {
BuildContext context, {
double? width,
}) {
width ??= 30; width ??= 30;
return Center( return Center(
child: SizedBox( child: SizedBox(width: width, height: width, child: const ProgressRing()),
width: width,
height: width,
child: const ProgressRing(),
),
); );
} }
Widget makeDefaultPage(BuildContext context, Widget makeDefaultPage(
{Widget? titleRow, BuildContext context, {
List<Widget>? actions, Widget? titleRow,
Widget? content, List<Widget>? actions,
bool automaticallyImplyLeading = true, Widget? content,
String title = "", bool automaticallyImplyLeading = true,
bool useBodyContainer = false}) { String title = "",
bool useBodyContainer = false,
}) {
return NavigationView( return NavigationView(
appBar: NavigationAppBar( appBar: NavigationAppBar(
automaticallyImplyLeading: automaticallyImplyLeading, automaticallyImplyLeading: automaticallyImplyLeading,
title: DragToMoveArea( title: DragToMoveArea(
child: titleRow ?? child:
Column( titleRow ??
children: [ Column(
Expanded( children: [
child: Row( Expanded(child: Row(children: [Text(title)])),
children: [ ],
Text(title), ),
], ),
), actions: Row(mainAxisAlignment: MainAxisAlignment.end, children: [...?actions, const WindowButtons()]),
) ),
],
),
),
actions: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [...?actions, const WindowButtons()],
)),
content: useBodyContainer content: useBodyContainer
? Container( ? Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@ -85,55 +74,63 @@ class WindowButtons extends StatelessWidget {
return SizedBox( return SizedBox(
width: 138, width: 138,
height: 50, height: 50,
child: WindowCaption( child: WindowCaption(brightness: theme.brightness, backgroundColor: Colors.transparent),
brightness: theme.brightness,
backgroundColor: Colors.transparent,
),
); );
} }
} }
List<Widget> makeMarkdownView(String description, {String? attachmentsUrl}) { List<Widget> makeMarkdownView(String description, {String? attachmentsUrl}) {
return MarkdownGenerator().buildWidgets(description, return MarkdownGenerator().buildWidgets(
config: MarkdownConfig(configs: [ description,
LinkConfig(onTap: (url) { config: MarkdownConfig(
if (url.startsWith("/") && attachmentsUrl != null) { configs: [
url = "$attachmentsUrl/$url"; LinkConfig(
} onTap: (url) {
launchUrlString(url); if (url.startsWith("/") && attachmentsUrl != null) {
}), url = "$attachmentsUrl/$url";
ImgConfig(builder: (String url, Map<String, String> attributes) { }
if (url.startsWith("/") && attachmentsUrl != null) { launchUrlString(url);
url = "$attachmentsUrl/$url"; },
} ),
return ExtendedImage.network( ImgConfig(
url, builder: (String url, Map<String, String> attributes) {
loadStateChanged: (ExtendedImageState state) { if (url.startsWith("/") && attachmentsUrl != null) {
switch (state.extendedImageLoadState) { url = "$attachmentsUrl/$url";
case LoadState.loading: }
return Center( return ExtendedImage.network(
child: Padding( url,
padding: const EdgeInsets.all(8.0), loadStateChanged: (ExtendedImageState state) {
child: Column( switch (state.extendedImageLoadState) {
children: [ case LoadState.loading:
const ProgressRing(), return Center(
const SizedBox(height: 12), child: Padding(
Text(S.current.app_common_loading_images) padding: const EdgeInsets.all(8.0),
], child: Column(
children: [
const ProgressRing(),
const SizedBox(height: 12),
Text(S.current.app_common_loading_images),
],
),
), ),
), );
); case LoadState.completed:
case LoadState.completed: return ExtendedRawImage(image: state.extendedImageInfo?.image);
return ExtendedRawImage( case LoadState.failed:
image: state.extendedImageInfo?.image, return Button(
); onPressed: () {
case LoadState.failed: launchUrlString(url);
return Text("Loading Image error $url"); },
} child: Text("Loading Image error $url"),
}, );
); }
}) },
])); );
},
),
],
),
);
} }
ColorFilter makeSvgColor(Color color) { ColorFilter makeSvgColor(Color color) {
@ -142,22 +139,20 @@ ColorFilter makeSvgColor(Color color) {
CustomTransitionPage<T> myPageBuilder<T>(BuildContext context, GoRouterState state, Widget child) { CustomTransitionPage<T> myPageBuilder<T>(BuildContext context, GoRouterState state, Widget child) {
return CustomTransitionPage( return CustomTransitionPage(
child: child, child: child,
transitionDuration: const Duration(milliseconds: 150), transitionDuration: const Duration(milliseconds: 150),
reverseTransitionDuration: const Duration(milliseconds: 150), reverseTransitionDuration: const Duration(milliseconds: 150),
transitionsBuilder: transitionsBuilder:
(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) { (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return SlideTransition( return SlideTransition(
position: Tween<Offset>( position: Tween<Offset>(
begin: const Offset(0.0, 1.0), begin: const Offset(0.0, 1.0),
end: const Offset(0.0, 0.0), end: const Offset(0.0, 0.0),
).animate(CurvedAnimation( ).animate(CurvedAnimation(parent: animation, curve: Curves.easeInOut)),
parent: animation, child: child,
curve: Curves.easeInOut, );
)), },
child: child, );
);
});
} }
class LoadingWidget<T> extends HookConsumerWidget { class LoadingWidget<T> extends HookConsumerWidget {
@ -192,9 +187,7 @@ class LoadingWidget<T> extends HookConsumerWidget {
onPressed: () { onPressed: () {
_loadData(dataState, errorMsg); _loadData(dataState, errorMsg);
}, },
child: Center( child: Center(child: Text(errorMsg.value)),
child: Text(errorMsg.value),
),
); );
} }
if (dataState.value == null && data == null) return makeLoading(context); if (dataState.value == null && data == null) return makeLoading(context);

View File

@ -306,14 +306,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.0+7.7.0" version: "1.0.0+7.7.0"
dart_rss:
dependency: "direct main"
description:
name: dart_rss
sha256: "73539d4b7153b47beef8b51763ca55dcb6fc0bb412b29e0f5e74e93fabfd1ac6"
url: "https://pub.dev"
source: hosted
version: "3.0.3"
dart_style: dart_style:
dependency: transitive dependency: transitive
description: description:
@ -1610,7 +1602,7 @@ packages:
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
xml: xml:
dependency: "direct main" dependency: transitive
description: description:
name: xml name: xml
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"

View File

@ -47,9 +47,7 @@ dependencies:
freezed_annotation: ^3.1.0 freezed_annotation: ^3.1.0
meta: ^1.16.0 meta: ^1.16.0
hexcolor: ^3.0.1 hexcolor: ^3.0.1
dart_rss: ^3.0.3
html: ^0.15.6 html: ^0.15.6
xml: ^6.6.1
fixnum: ^1.1.1 fixnum: ^1.1.1
rust_builder: rust_builder:
path: rust_builder path: rust_builder