import 'dart:ui'; import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:isekai_wiki/components/isekai_page_scaffold.dart'; import 'package:isekai_wiki/global.dart'; import 'package:isekai_wiki/models/site_config.dart'; import 'package:isekai_wiki/pages/tab_page.dart'; import 'package:isekai_wiki/utils/dialog.dart'; import 'package:roundcheckbox/roundcheckbox.dart'; import '../utils/error.dart'; class WelcomePageController extends GetxController { var isLoading = false.obs; var policyAccepted = false.obs; void handleClickPolicyLink() { openUrl(Global.privacyPolicyUrl, inApp: false); } Future handleClickContinue() async { isLoading.value = true; var siteConfig = Get.find(); try { await showLoading(Get.overlayContext!, callback: () async { await siteConfig.loadFromRemote(); }); // 加载完成后跳转到首页 Navigator.of(Get.context!).pushReplacement( CupertinoPageRoute( builder: (_) => const IsekaiWikiTabsPage(), ), ); } catch (err, stack) { // ignore: prefer_interpolation_to_compose_strings alert(Get.overlayContext!, "无法加载站点配置:" + ErrorUtils.getErrorMessage(err), title: "错误"); if (kDebugMode) { print("Exception in logout: $err"); stack.printError(); } } isLoading.value = false; } } class WelcomePage extends StatelessWidget { const WelcomePage({super.key}); @override Widget build(BuildContext context) { var c = Get.put(WelcomePageController()); return IsekaiPageScaffold( backgroundColor: CupertinoColors.white, child: Stack( fit: StackFit.expand, children: [ Container( decoration: const BoxDecoration( image: DecorationImage( image: ExactAssetImage('assets/images/title.png'), fit: BoxFit.cover, ), ), child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( decoration: BoxDecoration(color: Colors.black.withOpacity(0.4)), ), ), ), SafeArea( child: OrientationBuilder( builder: (context, orientation) => Padding( padding: orientation == Orientation.portrait ? const EdgeInsets.only( top: 48, right: 20, bottom: 32, left: 20) : const EdgeInsets.symmetric(horizontal: 20, vertical: 32), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Flexible( flex: 0, child: Padding( padding: const EdgeInsets.symmetric( vertical: 24, horizontal: 8), child: _buildSiteTitle(context, c), ), ), ], ), const SizedBox(height: 36), _buildActions(context, c), ], ), ), ), ), ], ), ); } Widget _buildSiteTitle(BuildContext context, WelcomePageController c) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ MediaQuery( data: MediaQueryData(textScaleFactor: 1), child: Text( Global.siteTitle, style: TextStyle( fontSize: 48, color: Colors.white, fontWeight: FontWeight.bold), ), ), Text( Global.siteDescription, style: TextStyle(fontSize: 18, color: Colors.white), ), ], ); } Widget _buildActions(BuildContext context, WelcomePageController c) { var theme = CupertinoTheme.of(context); var scaleFactor = MediaQuery.of(context).textScaleFactor; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ GestureDetector( behavior: HitTestBehavior.translucent, onTap: () { c.policyAccepted.value = !c.policyAccepted.value; }, child: Row( children: [ Obx( () => RoundCheckBox( size: 24 * scaleFactor, isChecked: c.policyAccepted.value, animationDuration: Duration.zero, checkedColor: theme.primaryColor, checkedWidget: Icon( Icons.check, color: Colors.white, size: 18 * scaleFactor, ), onTap: (checked) { c.policyAccepted.value = checked ?? false; }, ), ), const SizedBox( width: 10, ), const Text( "已阅读并同意", style: TextStyle(color: Colors.white), ), CupertinoButton( padding: EdgeInsets.zero, onPressed: c.handleClickPolicyLink, child: const Text( "隐私政策", style: TextStyle(color: Colors.lightBlue), ), ) ], ), ), const SizedBox( height: 18, ), Obx( () => CupertinoButton.filled( disabledColor: theme.primaryColor.withOpacity(0.6), onPressed: c.policyAccepted.value && !c.isLoading.value ? c.handleClickContinue : null, child: const Text("继续"), ), ), ], ); } }