From 308689726e2402cd7a11e29c659a27ff277f9ded Mon Sep 17 00:00:00 2001 From: Calcitem Date: Sun, 23 May 2021 02:00:59 +0800 Subject: [PATCH] flutter: Popup Privacy Policy dialog when first run --- src/ui/flutter_app/lib/common/config.dart | 10 ++ src/ui/flutter_app/lib/l10n/intl_en.arb | 12 +++ src/ui/flutter_app/lib/l10n/intl_zh.arb | 3 + src/ui/flutter_app/lib/widgets/game_page.dart | 99 ++++++++++++++++++- 4 files changed, 123 insertions(+), 1 deletion(-) diff --git a/src/ui/flutter_app/lib/common/config.dart b/src/ui/flutter_app/lib/common/config.dart index 21138afe9..aab357cb2 100644 --- a/src/ui/flutter_app/lib/common/config.dart +++ b/src/ui/flutter_app/lib/common/config.dart @@ -24,6 +24,9 @@ import 'settings.dart'; class Config { static bool settingsLoaded = false; + static bool isPrivacyPolicyAccepted = false; + + // Preferences static bool toneEnabled = true; static bool aiMovesFirst = false; static bool aiIsLazy = false; @@ -72,6 +75,10 @@ class Config { final settings = await Settings.instance(); + Config.isPrivacyPolicyAccepted = + settings['IsPrivacyPolicyAccepted'] ?? false; + + // Preferences Config.toneEnabled = settings['ToneEnabled'] ?? true; Config.aiMovesFirst = settings['AiMovesFirst'] ?? false; Config.aiIsLazy = settings['AiIsLazy'] ?? false; @@ -140,6 +147,9 @@ class Config { static Future save() async { final settings = await Settings.instance(); + settings['IsPrivacyPolicyAccepted'] = Config.isPrivacyPolicyAccepted; + + // Preferences settings['ToneEnabled'] = Config.toneEnabled; settings['AiMovesFirst'] = Config.aiMovesFirst; settings['AiIsLazy'] = Config.aiIsLazy; diff --git a/src/ui/flutter_app/lib/l10n/intl_en.arb b/src/ui/flutter_app/lib/l10n/intl_en.arb index 1f81c9baf..44b58bf16 100644 --- a/src/ui/flutter_app/lib/l10n/intl_en.arb +++ b/src/ui/flutter_app/lib/l10n/intl_en.arb @@ -704,6 +704,18 @@ "@privacyPolicy": { "description": "Privacy Policy" }, + "privacyPolicy_Detail_1": "Please read carefully and make sure you fully understand and agree with this ", + "@privacyPolicy_Detail_1": { + "description": "Privacy Policy Detail 1" + }, + "privacyPolicy_Detail_2": ". If you do not agree to this Policy, please do not use this App. Using the App implies that you accept these terms. We do occasionally update these terms so please refer back to them in the future.", + "@privacyPolicy_Detail_2": { + "description": "Privacy Policy Detail 2" + }, + "accept": "Accept", + "@accept": { + "description": "Accept" + }, "undo": "Undo", "@undo": { "description": "Undo" diff --git a/src/ui/flutter_app/lib/l10n/intl_zh.arb b/src/ui/flutter_app/lib/l10n/intl_zh.arb index 5d1a7ba3e..459338c18 100644 --- a/src/ui/flutter_app/lib/l10n/intl_zh.arb +++ b/src/ui/flutter_app/lib/l10n/intl_zh.arb @@ -176,6 +176,9 @@ "cannotRemoveFromMill": "不能吃三连中的子。", "left": "剩余", "privacyPolicy": "隐私政策", + "privacyPolicy_Detail_1": "请您务必审慎阅读、充分理解《隐私政策》各条款,包括但不限于:\n为了改善我们向您提供的服务,基于您的明示授权,我们可能会获取您的设备型号、诊断数据、电子邮件地址等信息,您有权拒绝或取消授权。我们将在每次请求发送诊断数据前,通过弹窗形式征得您的明示同意。\n您可阅读《", + "privacyPolicy_Detail_2": "》了解详细信息。如您同意,请点击“同意”开始接受我们的服务。", + "accept": "同意", "undo": "悔棋", "undoOption": "悔棋", "undoOption_Detail": "允许悔棋", diff --git a/src/ui/flutter_app/lib/widgets/game_page.dart b/src/ui/flutter_app/lib/widgets/game_page.dart index d8de37d59..f567e3829 100644 --- a/src/ui/flutter_app/lib/widgets/game_page.dart +++ b/src/ui/flutter_app/lib/widgets/game_page.dart @@ -17,7 +17,10 @@ */ import 'dart:async'; +import 'dart:io'; +import 'package:devicelocale/devicelocale.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:sanmill/common/config.dart'; @@ -31,7 +34,9 @@ import 'package:sanmill/mill/rule.dart'; import 'package:sanmill/mill/types.dart'; import 'package:sanmill/services/audios.dart'; import 'package:sanmill/style/app_theme.dart'; +import 'package:sanmill/widgets/game_settings_page.dart'; import 'package:stack_trace/stack_trace.dart'; +import 'package:url_launcher/url_launcher.dart'; import 'board.dart'; import 'game_settings_page.dart'; @@ -80,6 +85,10 @@ class _GamePageState extends State with RouteAware { setState(() {}); isReady = true; timer.cancel(); + + if (!Config.isPrivacyPolicyAccepted) { + onShowPrivacyDialog(); + } } } @@ -674,7 +683,6 @@ class _GamePageState extends State with RouteAware { onInfoButtonPressed() { final analyzeText = getInfoText(); - showDialog( context: context, barrierDismissible: true, @@ -695,6 +703,84 @@ class _GamePageState extends State with RouteAware { ); } + setPrivacyPolicyAccepted(bool value) async { + setState(() { + Config.isPrivacyPolicyAccepted = value; + }); + + print("[config] isPrivacyPolicyAccepted: $value"); + + Config.save(); + } + + onShowPrivacyDialog() async { + String? locale = "en_US"; + late String privacyPolicyURL; + if (!Platform.isWindows) { + locale = await Devicelocale.currentLocale; + } + + print("[about] local = $locale"); + if (locale != null && locale.startsWith("zh_")) { + privacyPolicyURL = + 'https://gitee.com/calcitem/Sanmill/wikis/privacy_policy_zh'; + } else { + privacyPolicyURL = + 'https://github.com/calcitem/Sanmill/wiki/privacy_policy'; + } + + final ThemeData themeData = Theme.of(context); + final TextStyle? aboutTextStyle = themeData.textTheme.bodyText1; + final TextStyle linkStyle = + themeData.textTheme.bodyText1!.copyWith(color: themeData.accentColor); + + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: Text( + S.of(context).privacyPolicy, + ), + content: RichText( + text: TextSpan( + children: [ + TextSpan( + style: aboutTextStyle, + text: S.of(context).privacyPolicy_Detail_1, + ), + _LinkTextSpan( + style: linkStyle, + text: S.of(context).privacyPolicy, + url: privacyPolicyURL, + ), + TextSpan( + style: aboutTextStyle, + text: S.of(context).privacyPolicy_Detail_2, + ), + ], + ), + ), + actions: [ + TextButton( + child: Text(S.of(context).accept), + onPressed: () { + setPrivacyPolicyAccepted(true); + Navigator.of(context).pop(); + }), + Platform.isAndroid + ? TextButton( + child: Text(S.of(context).exit), + onPressed: () { + setPrivacyPolicyAccepted(false); + SystemChannels.platform + .invokeMethod('SystemNavigator.pop'); + }, + ) + : Container(height: 0.0, width: 0.0), + ], + )); + } + String getGameOverReasonString(GameOverReason? reason, String? winner) { //String winnerStr = // winner == Color.white ? S.of(context).white : S.of(context).black; @@ -1180,3 +1266,14 @@ class _GamePageState extends State with RouteAware { print('$tag Game Page didPop route: $route'); } } + +class _LinkTextSpan extends TextSpan { + _LinkTextSpan({TextStyle? style, required String url, String? text}) + : super( + style: style, + text: text ?? url, + recognizer: TapGestureRecognizer() + ..onTap = () { + launch(url, forceSafariVC: false); + }); +}