✨ Event dairy
This commit is contained in:
		@@ -941,5 +941,6 @@
 | 
			
		||||
  "pinPostReplyDisabledHint": "This post is not a reply",
 | 
			
		||||
  "pin": "Pin",
 | 
			
		||||
  "unpinPostHint": "Are you sure you want to unpin this post?",
 | 
			
		||||
  "all": "All"
 | 
			
		||||
  "all": "All",
 | 
			
		||||
  "statusPresent": "Present"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -855,5 +855,6 @@
 | 
			
		||||
  "newSecretGenerated": "已生成新密钥",
 | 
			
		||||
  "copySecretHint": "请复制此密钥并将其存放在安全的地方。您将无法再次看到它。",
 | 
			
		||||
  "expiresIn": "过期时间(秒)",
 | 
			
		||||
  "isOidc": "OIDC 兼容"
 | 
			
		||||
  "isOidc": "OIDC 兼容",
 | 
			
		||||
  "statusPresent": "至今"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ sealed class SnEventCalendarEntry with _$SnEventCalendarEntry {
 | 
			
		||||
  const factory SnEventCalendarEntry({
 | 
			
		||||
    required DateTime date,
 | 
			
		||||
    required SnCheckInResult? checkInResult,
 | 
			
		||||
    required List<dynamic> statuses,
 | 
			
		||||
    required List<SnAccountStatus> statuses,
 | 
			
		||||
  }) = _SnEventCalendarEntry;
 | 
			
		||||
 | 
			
		||||
  factory SnEventCalendarEntry.fromJson(Map<String, dynamic> json) =>
 | 
			
		||||
 
 | 
			
		||||
@@ -861,7 +861,7 @@ as String,
 | 
			
		||||
/// @nodoc
 | 
			
		||||
mixin _$SnEventCalendarEntry {
 | 
			
		||||
 | 
			
		||||
 DateTime get date; SnCheckInResult? get checkInResult; List<dynamic> get statuses;
 | 
			
		||||
 DateTime get date; SnCheckInResult? get checkInResult; List<SnAccountStatus> get statuses;
 | 
			
		||||
/// Create a copy of SnEventCalendarEntry
 | 
			
		||||
/// with the given fields replaced by the non-null parameter values.
 | 
			
		||||
@JsonKey(includeFromJson: false, includeToJson: false)
 | 
			
		||||
@@ -894,7 +894,7 @@ abstract mixin class $SnEventCalendarEntryCopyWith<$Res>  {
 | 
			
		||||
  factory $SnEventCalendarEntryCopyWith(SnEventCalendarEntry value, $Res Function(SnEventCalendarEntry) _then) = _$SnEventCalendarEntryCopyWithImpl;
 | 
			
		||||
@useResult
 | 
			
		||||
$Res call({
 | 
			
		||||
 DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses
 | 
			
		||||
 DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -916,7 +916,7 @@ class _$SnEventCalendarEntryCopyWithImpl<$Res>
 | 
			
		||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as SnCheckInResult?,statuses: null == statuses ? _self.statuses : statuses // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as List<dynamic>,
 | 
			
		||||
as List<SnAccountStatus>,
 | 
			
		||||
  ));
 | 
			
		||||
}
 | 
			
		||||
/// Create a copy of SnEventCalendarEntry
 | 
			
		||||
@@ -1010,7 +1010,7 @@ return $default(_that);case _:
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
 | 
			
		||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,{required TResult orElse(),}) {final _that = this;
 | 
			
		||||
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,{required TResult orElse(),}) {final _that = this;
 | 
			
		||||
switch (_that) {
 | 
			
		||||
case _SnEventCalendarEntry() when $default != null:
 | 
			
		||||
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
 | 
			
		||||
@@ -1031,7 +1031,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _:
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
 | 
			
		||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)  $default,) {final _that = this;
 | 
			
		||||
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)  $default,) {final _that = this;
 | 
			
		||||
switch (_that) {
 | 
			
		||||
case _SnEventCalendarEntry():
 | 
			
		||||
return $default(_that.date,_that.checkInResult,_that.statuses);}
 | 
			
		||||
@@ -1048,7 +1048,7 @@ return $default(_that.date,_that.checkInResult,_that.statuses);}
 | 
			
		||||
/// }
 | 
			
		||||
/// ```
 | 
			
		||||
 | 
			
		||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<dynamic> statuses)?  $default,) {final _that = this;
 | 
			
		||||
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( DateTime date,  SnCheckInResult? checkInResult,  List<SnAccountStatus> statuses)?  $default,) {final _that = this;
 | 
			
		||||
switch (_that) {
 | 
			
		||||
case _SnEventCalendarEntry() when $default != null:
 | 
			
		||||
return $default(_that.date,_that.checkInResult,_that.statuses);case _:
 | 
			
		||||
@@ -1063,13 +1063,13 @@ return $default(_that.date,_that.checkInResult,_that.statuses);case _:
 | 
			
		||||
@JsonSerializable()
 | 
			
		||||
 | 
			
		||||
class _SnEventCalendarEntry implements SnEventCalendarEntry {
 | 
			
		||||
  const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<dynamic> statuses}): _statuses = statuses;
 | 
			
		||||
  const _SnEventCalendarEntry({required this.date, required this.checkInResult, required final  List<SnAccountStatus> statuses}): _statuses = statuses;
 | 
			
		||||
  factory _SnEventCalendarEntry.fromJson(Map<String, dynamic> json) => _$SnEventCalendarEntryFromJson(json);
 | 
			
		||||
 | 
			
		||||
@override final  DateTime date;
 | 
			
		||||
@override final  SnCheckInResult? checkInResult;
 | 
			
		||||
 final  List<dynamic> _statuses;
 | 
			
		||||
@override List<dynamic> get statuses {
 | 
			
		||||
 final  List<SnAccountStatus> _statuses;
 | 
			
		||||
@override List<SnAccountStatus> get statuses {
 | 
			
		||||
  if (_statuses is EqualUnmodifiableListView) return _statuses;
 | 
			
		||||
  // ignore: implicit_dynamic_type
 | 
			
		||||
  return EqualUnmodifiableListView(_statuses);
 | 
			
		||||
@@ -1109,7 +1109,7 @@ abstract mixin class _$SnEventCalendarEntryCopyWith<$Res> implements $SnEventCal
 | 
			
		||||
  factory _$SnEventCalendarEntryCopyWith(_SnEventCalendarEntry value, $Res Function(_SnEventCalendarEntry) _then) = __$SnEventCalendarEntryCopyWithImpl;
 | 
			
		||||
@override @useResult
 | 
			
		||||
$Res call({
 | 
			
		||||
 DateTime date, SnCheckInResult? checkInResult, List<dynamic> statuses
 | 
			
		||||
 DateTime date, SnCheckInResult? checkInResult, List<SnAccountStatus> statuses
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -1131,7 +1131,7 @@ class __$SnEventCalendarEntryCopyWithImpl<$Res>
 | 
			
		||||
date: null == date ? _self.date : date // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as DateTime,checkInResult: freezed == checkInResult ? _self.checkInResult : checkInResult // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as SnCheckInResult?,statuses: null == statuses ? _self._statuses : statuses // ignore: cast_nullable_to_non_nullable
 | 
			
		||||
as List<dynamic>,
 | 
			
		||||
as List<SnAccountStatus>,
 | 
			
		||||
  ));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -87,7 +87,10 @@ _SnEventCalendarEntry _$SnEventCalendarEntryFromJson(
 | 
			
		||||
          : SnCheckInResult.fromJson(
 | 
			
		||||
            json['check_in_result'] as Map<String, dynamic>,
 | 
			
		||||
          ),
 | 
			
		||||
  statuses: json['statuses'] as List<dynamic>,
 | 
			
		||||
  statuses:
 | 
			
		||||
      (json['statuses'] as List<dynamic>)
 | 
			
		||||
          .map((e) => SnAccountStatus.fromJson(e as Map<String, dynamic>))
 | 
			
		||||
          .toList(),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
Map<String, dynamic> _$SnEventCalendarEntryToJson(
 | 
			
		||||
@@ -95,5 +98,5 @@ Map<String, dynamic> _$SnEventCalendarEntryToJson(
 | 
			
		||||
) => <String, dynamic>{
 | 
			
		||||
  'date': instance.date.toIso8601String(),
 | 
			
		||||
  'check_in_result': instance.checkInResult?.toJson(),
 | 
			
		||||
  'statuses': instance.statuses,
 | 
			
		||||
  'statuses': instance.statuses.map((e) => e.toJson()).toList(),
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@ import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter_hooks/flutter_hooks.dart';
 | 
			
		||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
 | 
			
		||||
import 'package:island/models/account.dart';
 | 
			
		||||
import 'package:island/models/activity.dart';
 | 
			
		||||
import 'package:material_symbols_icons/symbols.dart';
 | 
			
		||||
import 'package:styled_widget/styled_widget.dart';
 | 
			
		||||
import 'package:island/widgets/account/event_details_widget.dart';
 | 
			
		||||
import 'package:table_calendar/table_calendar.dart';
 | 
			
		||||
@@ -87,24 +89,56 @@ class EventCalendarWidget extends HookConsumerWidget {
 | 
			
		||||
              return Center(child: Text(text));
 | 
			
		||||
            },
 | 
			
		||||
            markerBuilder: (context, day, events) {
 | 
			
		||||
              var checkInResult =
 | 
			
		||||
              final checkInResult =
 | 
			
		||||
                  events.whereType<SnCheckInResult>().firstOrNull;
 | 
			
		||||
              final statuses = events.whereType<SnAccountStatus>().toList();
 | 
			
		||||
 | 
			
		||||
              final textColor =
 | 
			
		||||
                  isSameDay(selectedDay.value, day)
 | 
			
		||||
                      ? Theme.of(context).colorScheme.onPrimary
 | 
			
		||||
                      : isSameDay(DateTime.now(), day)
 | 
			
		||||
                      ? Theme.of(context).colorScheme.onPrimary
 | 
			
		||||
                      : Theme.of(context).colorScheme.onSurface;
 | 
			
		||||
 | 
			
		||||
              final shadow =
 | 
			
		||||
                  isSameDay(selectedDay.value, day) ||
 | 
			
		||||
                          isSameDay(DateTime.now(), day)
 | 
			
		||||
                      ? [
 | 
			
		||||
                        Shadow(
 | 
			
		||||
                          color: Colors.black.withOpacity(0.5),
 | 
			
		||||
                          offset: const Offset(0, 1),
 | 
			
		||||
                          blurRadius: 4,
 | 
			
		||||
                        ),
 | 
			
		||||
                      ]
 | 
			
		||||
                      : null;
 | 
			
		||||
 | 
			
		||||
              if (checkInResult != null) {
 | 
			
		||||
                return Positioned(
 | 
			
		||||
                  top: 32,
 | 
			
		||||
                  child: Text(
 | 
			
		||||
                    'checkInResultT${checkInResult.level}'.tr(),
 | 
			
		||||
                    style: TextStyle(
 | 
			
		||||
                      fontSize: 9,
 | 
			
		||||
                      color:
 | 
			
		||||
                          isSameDay(selectedDay.value, day)
 | 
			
		||||
                              ? Theme.of(context).colorScheme.onPrimaryContainer
 | 
			
		||||
                              : isSameDay(DateTime.now(), day)
 | 
			
		||||
                              ? Theme.of(
 | 
			
		||||
                                context,
 | 
			
		||||
                              ).colorScheme.onSecondaryContainer
 | 
			
		||||
                              : Theme.of(context).colorScheme.onSurface,
 | 
			
		||||
                    ),
 | 
			
		||||
                  child: Row(
 | 
			
		||||
                    spacing: 2,
 | 
			
		||||
                    children: [
 | 
			
		||||
                      Text(
 | 
			
		||||
                        'checkInResultT${checkInResult.level}'.tr(),
 | 
			
		||||
                        style: TextStyle(
 | 
			
		||||
                          fontSize: 9,
 | 
			
		||||
                          color: textColor,
 | 
			
		||||
                          shadows: shadow,
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      if (statuses.isNotEmpty) ...[
 | 
			
		||||
                        Icon(
 | 
			
		||||
                          switch (statuses.first.attitude) {
 | 
			
		||||
                            0 => Symbols.sentiment_satisfied,
 | 
			
		||||
                            2 => Symbols.sentiment_dissatisfied,
 | 
			
		||||
                            _ => Symbols.sentiment_neutral,
 | 
			
		||||
                          },
 | 
			
		||||
                          size: 12,
 | 
			
		||||
                          color: textColor,
 | 
			
		||||
                          shadows: shadow,
 | 
			
		||||
                        ),
 | 
			
		||||
                      ],
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                );
 | 
			
		||||
              }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:gap/gap.dart';
 | 
			
		||||
import 'package:island/models/activity.dart';
 | 
			
		||||
import 'package:island/services/time.dart';
 | 
			
		||||
import 'package:material_symbols_icons/symbols.dart';
 | 
			
		||||
import 'package:styled_widget/styled_widget.dart';
 | 
			
		||||
 | 
			
		||||
@@ -53,6 +54,33 @@ class EventDetailsWidget extends StatelessWidget {
 | 
			
		||||
                    ),
 | 
			
		||||
                  ],
 | 
			
		||||
                ).padding(top: 8),
 | 
			
		||||
              if (event!.statuses.isNotEmpty) ...[
 | 
			
		||||
                const Gap(16),
 | 
			
		||||
                Text('statusLabel').tr().fontSize(16).bold(),
 | 
			
		||||
              ],
 | 
			
		||||
              for (final status in event!.statuses) ...[
 | 
			
		||||
                Row(
 | 
			
		||||
                  spacing: 8,
 | 
			
		||||
                  children: [
 | 
			
		||||
                    Icon(switch (status.attitude) {
 | 
			
		||||
                      0 => Symbols.sentiment_satisfied,
 | 
			
		||||
                      2 => Symbols.sentiment_dissatisfied,
 | 
			
		||||
                      _ => Symbols.sentiment_neutral,
 | 
			
		||||
                    }),
 | 
			
		||||
                    Expanded(
 | 
			
		||||
                      child: Column(
 | 
			
		||||
                        crossAxisAlignment: CrossAxisAlignment.start,
 | 
			
		||||
                        children: [
 | 
			
		||||
                          Text(status.label),
 | 
			
		||||
                          Text(
 | 
			
		||||
                            '${status.createdAt.formatSystem()} - ${status.clearedAt?.formatSystem() ?? 'present'.tr()}',
 | 
			
		||||
                          ).fontSize(11).opacity(0.8),
 | 
			
		||||
                        ],
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                  ],
 | 
			
		||||
                ).padding(vertical: 8),
 | 
			
		||||
              ],
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        if (event?.checkInResult == null && (event?.statuses.isEmpty ?? true))
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user