♻️ Update event calander loading

This commit is contained in:
LittleSheep 2025-05-10 02:24:58 +08:00
parent 1822142df5
commit d678cc571a
3 changed files with 380 additions and 82 deletions

View File

@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:gap/gap.dart'; import 'package:gap/gap.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/activity.dart'; import 'package:island/models/activity.dart';
@ -13,11 +14,24 @@ import 'package:styled_widget/styled_widget.dart';
import 'package:table_calendar/table_calendar.dart'; import 'package:table_calendar/table_calendar.dart';
part 'event_calendar.g.dart'; part 'event_calendar.g.dart';
part 'event_calendar.freezed.dart';
@freezed
abstract class EventCalendarQuery with _$EventCalendarQuery {
const factory EventCalendarQuery({
required String? uname,
required int year,
required int month,
}) = _EventCalendarQuery;
}
@riverpod @riverpod
Future<List<SnEventCalendarEntry>> myselfAccountEventCalendar(Ref ref) async { Future<List<SnEventCalendarEntry>> accountEventCalendar(
Ref ref,
EventCalendarQuery query,
) async {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.get('/accounts/me/calendar'); final resp = await client.get('/accounts/${query.uname ?? 'me'}/calendar');
return resp.data return resp.data
.map((e) => SnEventCalendarEntry.fromJson(e)) .map((e) => SnEventCalendarEntry.fromJson(e))
.cast<SnEventCalendarEntry>() .cast<SnEventCalendarEntry>()
@ -30,10 +44,21 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final events = ref.watch(myselfAccountEventCalendarProvider); final selectedMonth = useState(DateTime.now().month);
final selectedYear = useState(DateTime.now().year);
final selectedDay = useState(DateTime.now()); final selectedDay = useState(DateTime.now());
final events = ref.watch(
accountEventCalendarProvider(
EventCalendarQuery(
uname: 'me',
year: selectedYear.value,
month: selectedMonth.value,
),
),
);
return AppScaffold( return AppScaffold(
appBar: AppBar( appBar: AppBar(
leading: const PageBackButton(), leading: const PageBackButton(),
@ -41,15 +66,15 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
), ),
body: Column( body: Column(
children: [ children: [
SizedBox( TableCalendar(
height: 340,
child: events.when(
data: (events) {
return TableCalendar(
locale: EasyLocalization.of(context)!.locale.toString(), locale: EasyLocalization.of(context)!.locale.toString(),
firstDay: DateTime.utc(2010, 10, 16), firstDay: DateTime.now().add(Duration(days: -3650)),
lastDay: DateTime.utc(2030, 3, 14), lastDay: DateTime.now().add(Duration(days: 3650)),
focusedDay: DateTime.now(), focusedDay: DateTime.utc(
selectedYear.value,
selectedMonth.value,
DateTime.now().day,
),
calendarFormat: CalendarFormat.month, calendarFormat: CalendarFormat.month,
selectedDayPredicate: (day) { selectedDayPredicate: (day) {
return isSameDay(selectedDay.value, day); return isSameDay(selectedDay.value, day);
@ -57,12 +82,17 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
onDaySelected: (value, _) { onDaySelected: (value, _) {
selectedDay.value = value; selectedDay.value = value;
}, },
onPageChanged: (focusedDay) {
selectedMonth.value = focusedDay.month;
selectedYear.value = focusedDay.year;
},
eventLoader: (day) { eventLoader: (day) {
return events return events.value
.where((e) => isSameDay(e.date, day)) ?.where((e) => isSameDay(e.date, day))
.expand((e) => [...e.statuses, e.checkInResult]) .expand((e) => [...e.statuses, e.checkInResult])
.where((e) => e != null) .where((e) => e != null)
.toList(); .toList() ??
[];
}, },
calendarBuilders: CalendarBuilders( calendarBuilders: CalendarBuilders(
dowBuilder: (context, day) { dowBuilder: (context, day) {
@ -90,15 +120,8 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
return null; return null;
}, },
), ),
);
},
loading: () => const Center(child: CircularProgressIndicator()),
error:
(error, stack) =>
Center(child: Text('Error loading calendar: $error')),
), ),
), const Divider(height: 1).padding(top: 8),
const Divider(height: 1),
AnimatedSwitcher( AnimatedSwitcher(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: Builder( child: Builder(
@ -107,30 +130,27 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
events.value events.value
?.where((e) => isSameDay(e.date, selectedDay.value)) ?.where((e) => isSameDay(e.date, selectedDay.value))
.firstOrNull; .firstOrNull;
if (event == null) {
return Center(child: Text('eventCalanderEmpty').tr());
}
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Text(DateFormat.EEEE().format(event.date)) Text(DateFormat.EEEE().format(selectedDay.value))
.fontSize(16) .fontSize(16)
.bold() .bold()
.textColor( .textColor(
Theme.of(context).colorScheme.onSecondaryContainer, Theme.of(context).colorScheme.onSecondaryContainer,
), ),
Text(DateFormat.yMd().format(event.date)) Text(DateFormat.yMd().format(selectedDay.value))
.fontSize(12) .fontSize(12)
.textColor( .textColor(
Theme.of(context).colorScheme.onSecondaryContainer, Theme.of(context).colorScheme.onSecondaryContainer,
), ),
const Gap(16), const Gap(16),
if (event.checkInResult != null) if (event?.checkInResult != null)
Column( Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Text( Text(
'checkInResultLevel${event.checkInResult!.level}', 'checkInResultLevel${event!.checkInResult!.level}',
).tr().fontSize(16).bold(), ).tr().fontSize(16).bold(),
for (final tip in event.checkInResult!.tips) for (final tip in event.checkInResult!.tips)
Row( Row(
@ -156,7 +176,8 @@ class MyselfEventCalendarScreen extends HookConsumerWidget {
).padding(top: 8), ).padding(top: 8),
], ],
), ),
if (event.checkInResult == null && event.statuses.isEmpty) if (event?.checkInResult == null &&
(event?.statuses.isEmpty ?? true))
Text('eventCalanderEmpty').tr(), Text('eventCalanderEmpty').tr(),
], ],
).padding(vertical: 24, horizontal: 24); ).padding(vertical: 24, horizontal: 24);

View File

@ -0,0 +1,148 @@
// dart format width=80
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// 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 'event_calendar.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$EventCalendarQuery {
String? get uname; int get year; int get month;
/// Create a copy of EventCalendarQuery
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$EventCalendarQueryCopyWith<EventCalendarQuery> get copyWith => _$EventCalendarQueryCopyWithImpl<EventCalendarQuery>(this as EventCalendarQuery, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is EventCalendarQuery&&(identical(other.uname, uname) || other.uname == uname)&&(identical(other.year, year) || other.year == year)&&(identical(other.month, month) || other.month == month));
}
@override
int get hashCode => Object.hash(runtimeType,uname,year,month);
@override
String toString() {
return 'EventCalendarQuery(uname: $uname, year: $year, month: $month)';
}
}
/// @nodoc
abstract mixin class $EventCalendarQueryCopyWith<$Res> {
factory $EventCalendarQueryCopyWith(EventCalendarQuery value, $Res Function(EventCalendarQuery) _then) = _$EventCalendarQueryCopyWithImpl;
@useResult
$Res call({
String? uname, int year, int month
});
}
/// @nodoc
class _$EventCalendarQueryCopyWithImpl<$Res>
implements $EventCalendarQueryCopyWith<$Res> {
_$EventCalendarQueryCopyWithImpl(this._self, this._then);
final EventCalendarQuery _self;
final $Res Function(EventCalendarQuery) _then;
/// Create a copy of EventCalendarQuery
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? uname = freezed,Object? year = null,Object? month = null,}) {
return _then(_self.copyWith(
uname: freezed == uname ? _self.uname : uname // ignore: cast_nullable_to_non_nullable
as String?,year: null == year ? _self.year : year // ignore: cast_nullable_to_non_nullable
as int,month: null == month ? _self.month : month // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
/// @nodoc
class _EventCalendarQuery implements EventCalendarQuery {
const _EventCalendarQuery({required this.uname, required this.year, required this.month});
@override final String? uname;
@override final int year;
@override final int month;
/// Create a copy of EventCalendarQuery
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$EventCalendarQueryCopyWith<_EventCalendarQuery> get copyWith => __$EventCalendarQueryCopyWithImpl<_EventCalendarQuery>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _EventCalendarQuery&&(identical(other.uname, uname) || other.uname == uname)&&(identical(other.year, year) || other.year == year)&&(identical(other.month, month) || other.month == month));
}
@override
int get hashCode => Object.hash(runtimeType,uname,year,month);
@override
String toString() {
return 'EventCalendarQuery(uname: $uname, year: $year, month: $month)';
}
}
/// @nodoc
abstract mixin class _$EventCalendarQueryCopyWith<$Res> implements $EventCalendarQueryCopyWith<$Res> {
factory _$EventCalendarQueryCopyWith(_EventCalendarQuery value, $Res Function(_EventCalendarQuery) _then) = __$EventCalendarQueryCopyWithImpl;
@override @useResult
$Res call({
String? uname, int year, int month
});
}
/// @nodoc
class __$EventCalendarQueryCopyWithImpl<$Res>
implements _$EventCalendarQueryCopyWith<$Res> {
__$EventCalendarQueryCopyWithImpl(this._self, this._then);
final _EventCalendarQuery _self;
final $Res Function(_EventCalendarQuery) _then;
/// Create a copy of EventCalendarQuery
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? uname = freezed,Object? year = null,Object? month = null,}) {
return _then(_EventCalendarQuery(
uname: freezed == uname ? _self.uname : uname // ignore: cast_nullable_to_non_nullable
as String?,year: null == year ? _self.year : year // ignore: cast_nullable_to_non_nullable
as int,month: null == month ? _self.month : month // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
// dart format on

View File

@ -6,26 +6,155 @@ part of 'event_calendar.dart';
// RiverpodGenerator // RiverpodGenerator
// ************************************************************************** // **************************************************************************
String _$myselfAccountEventCalendarHash() => String _$accountEventCalendarHash() =>
r'd3faad342d5104e87ff6597ab459e65cb5f4ef97'; r'57405caaf53a83d121b6bb4b70540134fb581525';
/// See also [myselfAccountEventCalendar]. /// Copied from Dart SDK
@ProviderFor(myselfAccountEventCalendar) class _SystemHash {
final myselfAccountEventCalendarProvider = _SystemHash._();
AutoDisposeFutureProvider<List<SnEventCalendarEntry>>.internal(
myselfAccountEventCalendar, static int combine(int hash, int value) {
name: r'myselfAccountEventCalendarProvider', // ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [accountEventCalendar].
@ProviderFor(accountEventCalendar)
const accountEventCalendarProvider = AccountEventCalendarFamily();
/// See also [accountEventCalendar].
class AccountEventCalendarFamily
extends Family<AsyncValue<List<SnEventCalendarEntry>>> {
/// See also [accountEventCalendar].
const AccountEventCalendarFamily();
/// See also [accountEventCalendar].
AccountEventCalendarProvider call(EventCalendarQuery query) {
return AccountEventCalendarProvider(query);
}
@override
AccountEventCalendarProvider getProviderOverride(
covariant AccountEventCalendarProvider provider,
) {
return call(provider.query);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'accountEventCalendarProvider';
}
/// See also [accountEventCalendar].
class AccountEventCalendarProvider
extends AutoDisposeFutureProvider<List<SnEventCalendarEntry>> {
/// See also [accountEventCalendar].
AccountEventCalendarProvider(EventCalendarQuery query)
: this._internal(
(ref) => accountEventCalendar(ref as AccountEventCalendarRef, query),
from: accountEventCalendarProvider,
name: r'accountEventCalendarProvider',
debugGetCreateSourceHash: debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') const bool.fromEnvironment('dart.vm.product')
? null ? null
: _$myselfAccountEventCalendarHash, : _$accountEventCalendarHash,
dependencies: AccountEventCalendarFamily._dependencies,
allTransitiveDependencies:
AccountEventCalendarFamily._allTransitiveDependencies,
query: query,
);
AccountEventCalendarProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.query,
}) : super.internal();
final EventCalendarQuery query;
@override
Override overrideWith(
FutureOr<List<SnEventCalendarEntry>> Function(
AccountEventCalendarRef provider,
)
create,
) {
return ProviderOverride(
origin: this,
override: AccountEventCalendarProvider._internal(
(ref) => create(ref as AccountEventCalendarRef),
from: from,
name: null,
dependencies: null, dependencies: null,
allTransitiveDependencies: null, allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
query: query,
),
); );
}
@override
AutoDisposeFutureProviderElement<List<SnEventCalendarEntry>> createElement() {
return _AccountEventCalendarProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is AccountEventCalendarProvider && other.query == query;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, query.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead') @Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element // ignore: unused_element
typedef MyselfAccountEventCalendarRef = mixin AccountEventCalendarRef
AutoDisposeFutureProviderRef<List<SnEventCalendarEntry>>; on AutoDisposeFutureProviderRef<List<SnEventCalendarEntry>> {
/// The parameter `query` of this provider.
EventCalendarQuery get query;
}
class _AccountEventCalendarProviderElement
extends AutoDisposeFutureProviderElement<List<SnEventCalendarEntry>>
with AccountEventCalendarRef {
_AccountEventCalendarProviderElement(super.provider);
@override
EventCalendarQuery get query =>
(origin as AccountEventCalendarProvider).query;
}
// ignore_for_file: type=lint // ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package // ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package