feat(about): Add easter eggs

This commit is contained in:
ZhuJHua
2025-01-25 09:18:54 +08:00
parent 7a2fe21a21
commit 875edb6dba
3 changed files with 172 additions and 114 deletions

View File

@@ -1,4 +1,7 @@
import 'package:confetti/confetti.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:moodiary/router/app_routes.dart';
import 'package:moodiary/utils/package_util.dart';
import 'package:refreshed/refreshed.dart';
@@ -6,15 +9,36 @@ import 'package:url_launcher/url_launcher.dart';
import 'about_state.dart';
class AboutLogic extends GetxController {
class AboutLogic extends GetxController with GetSingleTickerProviderStateMixin {
final AboutState state = AboutState();
late final AnimationController _animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
)..repeat(reverse: true);
late final animation = Tween<double>(begin: -0.06, end: 0.06).animate(
CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
),
);
late final ConfettiController confettiController =
ConfettiController(duration: const Duration(seconds: 2));
@override
void onReady() async {
await getInfo();
super.onReady();
}
@override
void onClose() {
_animationController.dispose();
confettiController.dispose();
super.onClose();
}
Future<void> getInfo() async {
var packageInfo = await PackageUtil.getPackageInfo();
var deviceInfo = await PackageUtil.getInfo();
@@ -51,6 +75,11 @@ class AboutLogic extends GetxController {
await launchUrl(uri, mode: LaunchMode.platformDefault);
}
void playConfetti() {
HapticFeedback.selectionClick();
confettiController.play();
}
void toPrivacy() {
Get.toNamed(AppRoutes.privacyPage);
}

View File

@@ -1,3 +1,6 @@
import 'dart:math';
import 'package:confetti/confetti.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:moodiary/components/base/button.dart';
@@ -34,10 +37,22 @@ class AboutPage extends StatelessWidget {
spacing: 16.0,
mainAxisSize: MainAxisSize.min,
children: [
Text(
state.appName,
style: textStyle.titleLarge
?.copyWith(color: colorScheme.onSurface),
GestureDetector(
onTap: logic.playConfetti,
child: AnimatedBuilder(
animation: logic.animation,
builder: (context, child) {
return Transform.rotate(
angle: logic.animation.value,
child: child,
);
},
child: Text(
state.appName,
style: textStyle.titleLarge
?.copyWith(color: colorScheme.onSurface),
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
@@ -72,114 +87,134 @@ class AboutPage extends StatelessWidget {
leading: const PageBackButton(),
),
body: SafeArea(
child: ListView(
padding: const EdgeInsets.all(4.0),
child: Stack(
children: [
GetBuilder<AboutLogic>(builder: (_) {
return buildLogoTitle();
}),
const SizedBox(height: 16.0),
Card.outlined(
color: colorScheme.surfaceContainerLow,
child: Column(
children: [
AdaptiveListTile(
leading: const Icon(Icons.update_rounded),
title: Text(l10n.aboutUpdate),
isFirst: true,
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await UpdateUtil.checkShouldUpdate(state.appVersion,
handle: true);
},
),
AdaptiveListTile(
leading: const Icon(Icons.source_rounded),
title: Text(l10n.aboutSource),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await logic.toSource();
},
),
AdaptiveListTile(
leading: const Icon(Icons.file_copy_rounded),
title: Text(l10n.aboutUserAgreement),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
logic.toAgreement();
},
),
AdaptiveListTile(
leading: const Icon(Icons.privacy_tip_rounded),
title: Text(l10n.aboutPrivacyPolicy),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
logic.toPrivacy();
},
),
AdaptiveListTile(
leading: const Icon(Icons.bug_report_rounded),
title: Text(l10n.aboutBugReport),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await logic.toReportPage();
},
),
AdaptiveListTile(
leading: const Icon(Icons.attach_money_rounded),
title: Text(l10n.aboutDonate),
isLast: true,
trailing: const Icon(Icons.chevron_right_rounded),
onTap: logic.toSponsor,
ListView(
padding: const EdgeInsets.all(16.0),
physics: const ClampingScrollPhysics(),
children: [
GetBuilder<AboutLogic>(builder: (_) {
return buildLogoTitle();
}),
const SizedBox(height: 16.0),
Card.outlined(
color: colorScheme.surfaceContainerLow,
child: Column(
children: [
AdaptiveListTile(
leading: const Icon(Icons.update_rounded),
title: Text(l10n.aboutUpdate),
isFirst: true,
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await UpdateUtil.checkShouldUpdate(state.appVersion,
handle: true);
},
),
AdaptiveListTile(
leading: const Icon(Icons.source_rounded),
title: Text(l10n.aboutSource),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await logic.toSource();
},
),
AdaptiveListTile(
leading: const Icon(Icons.file_copy_rounded),
title: Text(l10n.aboutUserAgreement),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
logic.toAgreement();
},
),
AdaptiveListTile(
leading: const Icon(Icons.privacy_tip_rounded),
title: Text(l10n.aboutPrivacyPolicy),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () {
logic.toPrivacy();
},
),
AdaptiveListTile(
leading: const Icon(Icons.bug_report_rounded),
title: Text(l10n.aboutBugReport),
trailing: const Icon(Icons.chevron_right_rounded),
onTap: () async {
await logic.toReportPage();
},
),
AdaptiveListTile(
leading: const Icon(Icons.attach_money_rounded),
title: Text(l10n.aboutDonate),
isLast: true,
trailing: const Icon(Icons.chevron_right_rounded),
onTap: logic.toSponsor,
),
],
),
),
const SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4.0,
children: [
const FaIcon(
FontAwesomeIcons.flutter,
size: 16,
color: Colors.lightBlue,
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
FaIcon(
FontAwesomeIcons.dartLang,
size: 16,
color: colorScheme.onSurface.withValues(alpha: 0.8),
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
FaIcon(
FontAwesomeIcons.rust,
size: 16,
color: colorScheme.onSurface.withValues(alpha: 0.8),
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
const FaIcon(
FontAwesomeIcons.solidHeart,
size: 16,
color: Colors.pinkAccent,
),
],
)
],
),
Align(
alignment: Alignment.topCenter,
child: ConfettiWidget(
confettiController: logic.confettiController,
blastDirectionality: BlastDirectionality.directional,
blastDirection: pi / 2,
emissionFrequency: 0.1,
colors: const [
Colors.green,
Colors.blue,
Colors.yellow,
Colors.red,
],
),
),
const SizedBox(height: 16.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4.0,
children: [
const FaIcon(
FontAwesomeIcons.flutter,
size: 16,
color: Colors.lightBlue,
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
FaIcon(
FontAwesomeIcons.dartLang,
size: 16,
color: colorScheme.onSurface.withValues(alpha: 0.8),
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
FaIcon(
FontAwesomeIcons.rust,
size: 16,
color: colorScheme.onSurface.withValues(alpha: 0.8),
),
const SizedBox(
height: 12,
child: VerticalDivider(
thickness: 2,
),
),
const FaIcon(
FontAwesomeIcons.solidHeart,
size: 16,
color: Colors.pinkAccent,
),
],
)
],
),
),

View File

@@ -5,12 +5,6 @@ class SponsorLogic extends GetxController {
late final ConfettiController confettiController =
ConfettiController(duration: const Duration(seconds: 2));
@override
void onReady() {
confettiController.play();
super.onReady();
}
@override
void onClose() {
confettiController.dispose();