From cc765236488705b890559731e74e2296c66ca4dd Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 1 Nov 2024 22:23:26 +0800 Subject: [PATCH] Update cloud logger --- .../Setting/setting_appearance_screen.dart | 18 +- lib/Screens/Token/token_layout.dart | 195 +++++++--------- lib/TokenUtils/Otp/otp.dart | 2 +- lib/TokenUtils/import_token_util.dart | 218 +++++++++--------- lib/Utils/app_provider.dart | 11 + lib/Utils/hive_util.dart | 1 + lib/Utils/ilogger.dart | 2 +- lib/l10n/intl_en.arb | 2 + lib/l10n/intl_ja_JP.arb | 2 + lib/l10n/intl_zh_CN.arb | 2 + lib/l10n/intl_zh_TW.arb | 2 + lib/main.dart | 23 ++ .../flutter_cloud/lib/cloud_logger.dart | 93 ++++++++ third-party/flutter_cloud/lib/dropbox.dart | 90 +++----- third-party/flutter_cloud/lib/onedrive.dart | 85 +++---- .../flutter_cloud/lib/onedrive_response.dart | 14 ++ .../flutter_cloud/lib/token_manager.dart | 30 +-- 17 files changed, 450 insertions(+), 340 deletions(-) create mode 100644 third-party/flutter_cloud/lib/cloud_logger.dart diff --git a/lib/Screens/Setting/setting_appearance_screen.dart b/lib/Screens/Setting/setting_appearance_screen.dart index bd88bd7b..260b189c 100644 --- a/lib/Screens/Setting/setting_appearance_screen.dart +++ b/lib/Screens/Setting/setting_appearance_screen.dart @@ -62,6 +62,7 @@ class _AppearanceSettingScreenState extends State HiveUtil.getBool(HiveUtil.hideBottombarWhenScrollingKey); final GlobalKey _setAutoBackupPasswordKey = GlobalKey(); bool hideProgressBar = HiveUtil.getBool(HiveUtil.hideProgressBarKey); + bool showEye = HiveUtil.getBool(HiveUtil.showEyeKey); @override void initState() { @@ -221,6 +222,7 @@ class _AppearanceSettingScreenState extends State ItemBuilder.buildRadioItem( context: context, title: S.current.showSortButton, + bottomRadius: true, value: showSortButton, onTap: () { setState(() { @@ -229,10 +231,11 @@ class _AppearanceSettingScreenState extends State }); }, ), + const SizedBox(height: 10), ItemBuilder.buildRadioItem( context: context, + topRadius: true, value: hideProgressBar, - bottomRadius: true, title: S.current.hideProgressBar, description: S.current.hideProgressBarTip, onTap: () { @@ -242,6 +245,19 @@ class _AppearanceSettingScreenState extends State }); }, ), + ItemBuilder.buildRadioItem( + context: context, + value: showEye, + bottomRadius: true, + title: S.current.showEye, + description: S.current.showEyeTip, + onTap: () { + setState(() { + showEye = !showEye; + appProvider.showEye = showEye; + }); + }, + ), ]; } diff --git a/lib/Screens/Token/token_layout.dart b/lib/Screens/Token/token_layout.dart index 6728b0fa..92a6ed33 100644 --- a/lib/Screens/Token/token_layout.dart +++ b/lib/Screens/Token/token_layout.dart @@ -450,6 +450,61 @@ class TokenLayoutState extends State ); } + _buildVisibleLayout(Function(bool) builder) { + return ChangeNotifierProvider.value( + value: tokenLayoutNotifier, + child: Selector( + selector: (context, tokenLayoutNotifier) => + tokenLayoutNotifier.codeVisiable, + builder: (context, codeVisiable, child) => builder(codeVisiable), + ), + ); + } + + _buildVisibleLayoutWithEye(Function(bool) builder) { + return _buildVisibleLayout( + (codeVisiable) => Selector( + selector: (context, provider) => provider.showEye, + builder: (context, showEye, child) => + showEye ? builder(codeVisiable) : builder(true), + ), + ); + } + + _buildEyeButton({ + double padding = 8, + Color? color, + }) { + return _buildVisibleLayout( + (codeVisiable) { + if (codeVisiable) return emptyWidget; + return Selector( + selector: (context, provider) => provider.showEye, + builder: (context, showEye, child) => showEye + ? Container( + child: ItemBuilder.buildIconButton( + onTap: () { + HapticFeedback.lightImpact(); + tokenLayoutNotifier.codeVisiable = + !tokenLayoutNotifier.codeVisiable; + setState(() {}); + }, + padding: EdgeInsets.all(padding), + icon: Icon( + Icons.visibility_outlined, + size: 20, + color: color ?? + Theme.of(context).textTheme.bodyMedium?.color, + ), + context: context, + ), + ) + : emptyWidget, + ); + }, + ); + } + _buildHOTPRefreshButton({ double padding = 8, Color? color, @@ -492,13 +547,10 @@ class TokenLayoutState extends State AlignmentGeometry alignment = Alignment.centerLeft, bool forceNoType = false, }) { - return ChangeNotifierProvider.value( - value: tokenLayoutNotifier, - child: Selector( - selector: (context, tokenLayoutNotifier) => - tokenLayoutNotifier.codeVisiable, - builder: (context, codeVisiable, child) => - Selector( + return _buildVisibleLayout( + (codeVisiable) => ChangeNotifierProvider.value( + value: tokenLayoutNotifier, + child: Selector( selector: (context, tokenLayoutNotifier) => tokenLayoutNotifier.code, builder: (context, code, child) => Container( alignment: alignment, @@ -552,7 +604,7 @@ class TokenLayoutState extends State : Container( width: 24, height: 24, - margin: const EdgeInsets.only(left: 8), + margin: const EdgeInsets.only(left: 8, right: 4), child: Stack( children: [ ValueListenableBuilder( @@ -602,7 +654,9 @@ class TokenLayoutState extends State } _processTap() { - tokenLayoutNotifier.codeVisiable = true; + if (!appProvider.showEye) { + tokenLayoutNotifier.codeVisiable = true; + } updateCode(); if (HiveUtil.getBool(HiveUtil.clickToCopyKey)) { if (HiveUtil.getBool(HiveUtil.autoCopyNextCodeKey) && @@ -658,6 +712,7 @@ class TokenLayoutState extends State ?.apply(fontWeightDelta: 2), ), ), + if (!isHOTP) _buildEyeButton(padding: 6), if (isHOTP) _buildHOTPRefreshButton(padding: 6), ], ), @@ -751,6 +806,11 @@ class TokenLayoutState extends State padding: 4, color: textTheme.labelSmall?.color, ), + if (!isHOTP) + _buildEyeButton( + padding: 4, + color: textTheme.labelSmall?.color, + ), ItemBuilder.buildIconButton( context: context, padding: const EdgeInsets.all(4), @@ -780,109 +840,6 @@ class TokenLayoutState extends State ); } - _buildTileLayout() { - return ItemBuilder.buildClickItem( - Material( - color: widget.token.pinned - ? Theme.of(context).primaryColor.withOpacity(0.15) - : Theme.of(context).canvasColor, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - clipBehavior: Clip.hardEdge, - child: InkWell( - onTap: _processTap, - borderRadius: BorderRadius.circular(12), - child: Stack( - alignment: Alignment.bottomCenter, - children: [ - Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12), - ), - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Column( - children: [ - const SizedBox(height: 12), - Row( - children: [ - ItemBuilder.buildTokenImage(widget.token, size: 36), - const SizedBox(width: 8), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - widget.token.issuer, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context) - .textTheme - .titleMedium - ?.apply(fontWeightDelta: 2), - ), - Text( - widget.token.account, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: Theme.of(context).textTheme.bodySmall, - ), - ], - ), - ), - if (isHOTP) _buildHOTPRefreshButton(), - ItemBuilder.buildIconButton( - context: context, - icon: Icon(Icons.edit_rounded, - color: Theme.of(context).iconTheme.color, - size: 20), - onTap: _processEdit), - ItemBuilder.buildIconButton( - context: context, - icon: Icon(Icons.qr_code_rounded, - color: Theme.of(context).iconTheme.color, - size: 20), - onTap: _processViewQrCode), - ItemBuilder.buildIconButton( - context: context, - icon: Icon(Icons.more_vert_rounded, - color: Theme.of(context).iconTheme.color, - size: 20), - onTap: showContextMenu, - ), - ], - ), - const SizedBox(height: 2), - Container( - constraints: - const BoxConstraints(minHeight: 60, maxHeight: 60), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - _buildCodeLayout(fontSize: 28, letterSpacing: 10) - ], - ), - ], - ), - ), - ], - ), - ), - Selector( - selector: (context, provider) => provider.hideProgressBar, - builder: (context, hideProgressBar, child) => - _buildLinearProgress(hideProgressBar), - ), - ], - ), - ), - ), - ); - } - _buildSpotlightLayout() { return ItemBuilder.buildClickItem( Material( @@ -943,7 +900,11 @@ class TokenLayoutState extends State ), ), const SizedBox(width: 20), - isHOTP ? _buildHOTPRefreshButton() : _buildCircleProgress(), + if (!isHOTP) _buildEyeButton(), + if (isHOTP) _buildHOTPRefreshButton(), + if (!isHOTP) + _buildVisibleLayoutWithEye((codeVisible) => + codeVisible ? _buildCircleProgress() : emptyWidget), const SizedBox(width: 2), ], ), @@ -983,7 +944,13 @@ class TokenLayoutState extends State ), ), _buildCodeLayout(), - if (!isHOTP) _buildCircleProgress(), + const SizedBox(width: 4), + if (!isHOTP) + _buildEyeButton( + padding: 6, color: Theme.of(context).primaryColor), + if (!isHOTP) + _buildVisibleLayoutWithEye((codeVisible) => + codeVisible ? _buildCircleProgress() : emptyWidget), if (isHOTP) _buildHOTPRefreshButton( padding: 6, color: Theme.of(context).primaryColor), diff --git a/lib/TokenUtils/Otp/otp.dart b/lib/TokenUtils/Otp/otp.dart index df25be2d..a04b9174 100644 --- a/lib/TokenUtils/Otp/otp.dart +++ b/lib/TokenUtils/Otp/otp.dart @@ -223,7 +223,7 @@ class OTP { static void _showHOTPWarning(BlockHashBase mac) { if (mac == sha256 || mac == sha512) { - ILogger.warn("OTP", + ILogger.warning("OTP", 'Using non-SHA1 hashing with HOTP is not part of the RFC for HOTP and may cause incompatibilities between different library implementatiions. This library attempts to match behavior with other libraries as best it can.'); } } diff --git a/lib/TokenUtils/import_token_util.dart b/lib/TokenUtils/import_token_util.dart index fa862c9b..87045483 100644 --- a/lib/TokenUtils/import_token_util.dart +++ b/lib/TokenUtils/import_token_util.dart @@ -100,8 +100,7 @@ class ImportAnalysis { } class ImportTokenUtil { - static Future> parseRawUri( - List rawUris, { + static Future> parseRawUri(List rawUris, { bool autoPopup = true, BuildContext? context, }) async { @@ -143,8 +142,7 @@ class ImportTokenUtil { return [tokens, categories]; } - static Future> analyzeImageFile( - String filepath, { + static Future> analyzeImageFile(String filepath, { required BuildContext context, bool showLoading = true, }) async { @@ -178,17 +176,17 @@ class ImportTokenUtil { BottomSheetBuilder.showBottomSheet( context, responsive: true, - (context) => TokenOptionBottomSheet( - token: res[0].first, - isNewToken: true, - ), + (context) => + TokenOptionBottomSheet( + token: res[0].first, + isNewToken: true, + ), ); } return res; } - static Future> analyzeImage( - Uint8List? imageBytes, { + static Future> analyzeImage(Uint8List? imageBytes, { required BuildContext context, bool showLoading = true, bool doDismissLoading = false, @@ -244,17 +242,17 @@ class ImportTokenUtil { BottomSheetBuilder.showBottomSheet( context, responsive: true, - (context) => TokenOptionBottomSheet( - token: tokens.first, - isNewToken: true, - ), + (context) => + TokenOptionBottomSheet( + token: tokens.first, + isNewToken: true, + ), ); } return [tokens, categories]; } - static importUriFile( - String filePath, { + static importUriFile(String filePath, { bool showLoading = true, }) async { if (showLoading) { @@ -285,11 +283,10 @@ class ImportTokenUtil { } } - static Future importOldEncryptFile( - String filePath, - String password, { - bool showLoading = true, - }) async { + static Future importOldEncryptFile(String filePath, + String password, { + bool showLoading = true, + }) async { if (showLoading) { CustomLoadingDialog.showLoading(title: S.current.importing); } @@ -302,7 +299,7 @@ class ImportTokenUtil { List? tokens = await compute((_) async { Uint8List content = file.readAsBytesSync(); List? tokens = - await BackupEncryptionOld().decrypt(content, password); + await BackupEncryptionOld().decrypt(content, password); return tokens; }, null); if (tokens == null) { @@ -332,7 +329,7 @@ class ImportTokenUtil { static _showImportPasswordDialog(BuildContext context, String path) { InputValidateAsyncController validateAsyncController = - InputValidateAsyncController( + InputValidateAsyncController( controller: TextEditingController(), listen: false, validator: (text) async { @@ -351,32 +348,32 @@ class ImportTokenUtil { context, responsive: true, useWideLandscape: true, - (context) => InputBottomSheet( - validator: (value) { - if (value.isEmpty) { - return S.current.autoBackupPasswordCannotBeEmpty; - } - return null; - }, - checkSyncValidator: false, - validateAsyncController: validateAsyncController, - title: S.current.inputImportPasswordTitle, - message: S.current.inputImportPasswordTip, - hint: S.current.inputImportPasswordHint, - inputFormatters: [ - RegexInputFormatter.onlyNumberAndLetterAndSymbol, - ], - tailingType: InputItemTailingType.password, - onValidConfirm: (password) async {}, - ), + (context) => + InputBottomSheet( + validator: (value) { + if (value.isEmpty) { + return S.current.autoBackupPasswordCannotBeEmpty; + } + return null; + }, + checkSyncValidator: false, + validateAsyncController: validateAsyncController, + title: S.current.inputImportPasswordTitle, + message: S.current.inputImportPasswordTip, + hint: S.current.inputImportPasswordHint, + inputFormatters: [ + RegexInputFormatter.onlyNumberAndLetterAndSymbol, + ], + tailingType: InputItemTailingType.password, + onValidConfirm: (password) async {}, + ), ); } - static importEncryptFileWrapper( - BuildContext context, - String filePath, { - bool showLoading = true, - }) async { + static importEncryptFileWrapper(BuildContext context, + String filePath, { + bool showLoading = true, + }) async { operation() { _showImportPasswordDialog(context, filePath); } @@ -390,11 +387,10 @@ class ImportTokenUtil { } } - static Future importEncryptFile( - String filePath, - String password, { - bool showLoading = true, - }) async { + static Future importEncryptFile(String filePath, + String password, { + bool showLoading = true, + }) async { if (showLoading) { CustomLoadingDialog.showLoading(title: S.current.importing); } @@ -430,8 +426,7 @@ class ImportTokenUtil { } } - static Future importBackupFile( - Uint8List content, { + static Future importBackupFile(Uint8List content, { String? password, bool showLoading = true, String? loadingText, @@ -462,8 +457,7 @@ class ImportTokenUtil { } } - static Future importUint8List( - Uint8List content, { + static Future importUint8List(Uint8List content, { String? password, }) async { String tmpPassword = password ?? await ConfigDao.getBackupPassword(); @@ -483,8 +477,7 @@ class ImportTokenUtil { return true; } - static Future> importText( - String content, { + static Future> importText(String content, { String emptyTip = "", String noTokenToast = "", bool showLoading = true, @@ -523,7 +516,7 @@ class ImportTokenUtil { ImportAnalysis analysis = ImportAnalysis(); for (var line in lines) { List tmp = - await OtpTokenParser.parseCloudOtpauthCategoryMigration(line); + await OtpTokenParser.parseCloudOtpauthCategoryMigration(line); categories.addAll(tmp); } analysis.parseCategorySuccess = categories.length; @@ -532,11 +525,9 @@ class ImportTokenUtil { return categories; } - static importFromCloud( - BuildContext context, - Uint8List? res, - ProgressDialog dialog, - ) async { + static importFromCloud(BuildContext context, + Uint8List? res, + ProgressDialog dialog,) async { dialog.updateMessage( msg: S.current.importing, showProgress: false, @@ -553,7 +544,7 @@ class ImportTokenUtil { dialog.dismiss(); if (!success) { InputValidateAsyncController validateAsyncController = - InputValidateAsyncController( + InputValidateAsyncController( listen: false, validator: (text) async { if (text.isEmpty) { @@ -581,24 +572,25 @@ class ImportTokenUtil { context, responsive: true, useWideLandscape: true, - (context) => InputBottomSheet( - validator: (value) { - if (value.isEmpty) { - return S.current.autoBackupPasswordCannotBeEmpty; - } - return null; - }, - checkSyncValidator: false, - validateAsyncController: validateAsyncController, - title: S.current.inputImportPasswordTitle, - message: S.current.inputImportPasswordTip, - hint: S.current.inputImportPasswordHint, - inputFormatters: [ - RegexInputFormatter.onlyNumberAndLetterAndSymbol, - ], - tailingType: InputItemTailingType.password, - onValidConfirm: (password) async {}, - ), + (context) => + InputBottomSheet( + validator: (value) { + if (value.isEmpty) { + return S.current.autoBackupPasswordCannotBeEmpty; + } + return null; + }, + checkSyncValidator: false, + validateAsyncController: validateAsyncController, + title: S.current.inputImportPasswordTitle, + message: S.current.inputImportPasswordTip, + hint: S.current.inputImportPasswordHint, + inputFormatters: [ + RegexInputFormatter.onlyNumberAndLetterAndSymbol, + ], + tailingType: InputItemTailingType.password, + onValidConfirm: (password) async {}, + ), ); } } @@ -617,22 +609,22 @@ class ImportTokenUtil { return uidMap; } - static OtpToken? checkTokenExist(OtpToken token, List tokenList) { - for (OtpToken otpToken in tokenList) { - if (otpToken.issuer.trim() == token.issuer.trim() && - otpToken.account.trim() == token.account.trim() && - (otpToken.secret.trim() == token.secret.trim() || - otpToken.secret.trimPadding() == token.secret.trimPadding())) { + static OtpToken? checkTokenExist(OtpToken toCheckToken, + List checkList) { + for (OtpToken otpToken in checkList) { + if (otpToken.issuer.trim() == toCheckToken.issuer.trim() && + otpToken.account.trim() == toCheckToken.account.trim() && + (otpToken.secret.trim() == toCheckToken.secret.trim() || + otpToken.secret.trimPadding() == + toCheckToken.secret.trimPadding())) { return otpToken; } } return null; } - static bool checkCategoryExist( - TokenCategory category, - List categoryList, - ) { + static bool checkCategoryExist(TokenCategory category, + List categoryList,) { for (TokenCategory tokenCategory in categoryList) { if (tokenCategory.uid == category.uid && tokenCategory.title != category.title) { @@ -646,10 +638,10 @@ class ImportTokenUtil { } static Future mergeTokensAndCategories( - List tokenList, - List categoryList, { - bool performInsert = true, - }) async { + List tokenList, + List categoryList, { + bool performInsert = true, + }) async { ImportAnalysis analysis = ImportAnalysis(); analysis.importSuccess = await mergeTokens(tokenList); Map uidMap = await getAlreadyExistUid(tokenList); @@ -660,30 +652,34 @@ class ImportTokenUtil { return analysis; } - static Future mergeTokens( - List tokenList, { + static Future mergeTokens(List toMergeTokenList, { bool performInsert = true, }) async { List already = await TokenDao.listTokens(); - List newTokenList = []; - for (OtpToken otpToken in tokenList) { - if (otpToken.issuer.isEmpty) otpToken.issuer = otpToken.account; - otpToken.imagePath = TokenImageUtil.matchBrandLogo(otpToken) ?? ""; - OtpToken? alreadyToken = checkTokenExist(otpToken, already); - if (alreadyToken == null && - checkTokenExist(otpToken, newTokenList) == null) { - newTokenList.add(otpToken); + List finalMergeTokenList = []; + for (OtpToken toMergeToken in toMergeTokenList) { + if (toMergeToken.issuer.isEmpty) { + toMergeToken.issuer = toMergeToken.account; } + toMergeToken.imagePath = + TokenImageUtil.matchBrandLogo(toMergeToken) ?? ""; + OtpToken? alreadyToken = checkTokenExist(toMergeToken, already); + if (alreadyToken == null && + checkTokenExist(toMergeToken, finalMergeTokenList) == null) { + finalMergeTokenList.add(toMergeToken); + } else {} + } + for (var token in finalMergeTokenList) { + if (token.uid.isEmpty) token.uid = Utils.generateUid(); } if (performInsert) { - await TokenDao.insertTokens(newTokenList); + await TokenDao.insertTokens(finalMergeTokenList); homeScreenState?.refresh(); } - return newTokenList.length; + return finalMergeTokenList.length; } - static Future mergeCategories( - List categoryList, { + static Future mergeCategories(List categoryList, { bool performInsert = true, }) async { Map categoryCount = {}; @@ -691,7 +687,7 @@ class ImportTokenUtil { if (categoryCount.containsKey(category.title)) { categoryCount[category.title] = categoryCount[category.title]! + 1; category.title = - "${category.title}(${categoryCount[category.title]! - 1})"; + "${category.title}(${categoryCount[category.title]! - 1})"; } else { categoryCount[category.title] = 1; } diff --git a/lib/Utils/app_provider.dart b/lib/Utils/app_provider.dart index 99c31ac7..2d805a65 100644 --- a/lib/Utils/app_provider.dart +++ b/lib/Utils/app_provider.dart @@ -210,6 +210,17 @@ class AppProvider with ChangeNotifier { notifyListeners(); } + bool _showEye = HiveUtil.getBool(HiveUtil.showEyeKey); + + bool get showEye => _showEye; + + set showEye(bool value) { + _showEye = value; + HiveUtil.put(HiveUtil.showEyeKey, value); + notifyListeners(); + } + + bool _enableLandscapeInTablet = HiveUtil.getBool(HiveUtil.enableLandscapeInTabletKey); diff --git a/lib/Utils/hive_util.dart b/lib/Utils/hive_util.dart index bad46a9a..09fc3143 100644 --- a/lib/Utils/hive_util.dart +++ b/lib/Utils/hive_util.dart @@ -70,6 +70,7 @@ class HiveUtil { static const String hideProgressBarKey = "hideProgressBar"; static const String autoHideCodeKey = "autoHideCode"; static const String defaultHideCodeKey = "defaultHideCode"; + static const String showEyeKey = "showEye"; //Appearance static const String showCloudBackupButtonKey = "showCloudBackupButton"; diff --git a/lib/Utils/ilogger.dart b/lib/Utils/ilogger.dart index 8a9595d8..f5a18728 100644 --- a/lib/Utils/ilogger.dart +++ b/lib/Utils/ilogger.dart @@ -112,7 +112,7 @@ class ILogger { log(Level.error, tag, message, error, stackTrace); } - static void warn(String tag, String message, + static void warning(String tag, String message, [Object? error, StackTrace? stackTrace]) { log(Level.warning, tag, message, error, stackTrace); } diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index e49d5a88..8bea9aef 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -124,6 +124,8 @@ "defaultHideCodeTip": "Hide the code by default when opening the app or changing the token", "hideProgressBar": "Hide Progress Bar", "hideProgressBarTip": "Hide the countdown progress bar of the token", + "showEye": "Show view icon", + "showEyeTip": "When the view icon is displayed, the code can only be displayed by clicking on the view icon; when it is not displayed, click on the token to display the code", "copyTimes": "Copy Times", "currentCopyTimes": "Current Copy Times: {times}", "currentCounter": "Current Count: {counter}", diff --git a/lib/l10n/intl_ja_JP.arb b/lib/l10n/intl_ja_JP.arb index 9ef289e2..d51c9c3a 100644 --- a/lib/l10n/intl_ja_JP.arb +++ b/lib/l10n/intl_ja_JP.arb @@ -124,6 +124,8 @@ "defaultHideCodeTip": "アプリを開くかトークンを変更すると、デフォルトでコードが隠れます", "hideProgressBar": "進捗バーを隠す", "hideProgressBarTip": "トークンのカウントダウン進捗バーを隠す", + "showEye": "ビューアイコンを表示", + "showEyeTip": "表示アイコンが表示されている場合は、表示アイコンをクリックすることによってのみコードを表示できます。表示されていない場合は、トークンをクリックしてコードを表示します", "copyTimes": "コピー回数", "currentCopyTimes": "現在のコピー回数:{times}", "currentCounter": "現在のカウント:{counter}", diff --git a/lib/l10n/intl_zh_CN.arb b/lib/l10n/intl_zh_CN.arb index 638c6345..4143390c 100644 --- a/lib/l10n/intl_zh_CN.arb +++ b/lib/l10n/intl_zh_CN.arb @@ -124,6 +124,8 @@ "defaultHideCodeTip": "打开应用或更改令牌时,默认隐藏代码", "hideProgressBar": "隐藏进度条", "hideProgressBarTip": "隐藏令牌的倒计时进度条", + "showEye": "显示查看图标", + "showEyeTip": "显示查看图标时只有点击查看图标才能显示代码;不显示时点击令牌即可显示代码", "copyTimes": "复制次数", "currentCopyTimes": "当前复制次数:{times}", "currentCounter": "当前计数:{counter}", diff --git a/lib/l10n/intl_zh_TW.arb b/lib/l10n/intl_zh_TW.arb index 7544d28f..122103b4 100644 --- a/lib/l10n/intl_zh_TW.arb +++ b/lib/l10n/intl_zh_TW.arb @@ -124,6 +124,8 @@ "defaultHideCodeTip": "開啟應用程式或變更令牌時,預設隱藏程式碼", "hideProgressBar": "隱藏進度列", "hideProgressBarTip": "隱藏令牌的倒數進度列", + "showEye": "顯示檢視圖示", + "showEyeTip": "顯示檢視圖示時只有點擊檢視圖示才能顯示代碼;不顯示時點選令牌即可顯示代碼", "copyTimes": "複製次數", "currentCopyTimes": "目前複製次數:{times}", "currentCounter": "目前計數:{counter}", diff --git a/lib/main.dart b/lib/main.dart index ac55b4a7..cb0f8c85 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -28,6 +28,7 @@ import 'package:cloudotp/Widgets/Item/item_builder.dart'; import 'package:ente_crypto_dart/ente_crypto_dart.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_cloud/cloud_logger.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; @@ -111,6 +112,7 @@ Future initApp(WidgetsBinding widgetsBinding) async { await BiometricUtil.initStorage(); await TokenImageUtil.loadBrandLogos(); ResponsiveUtil.init(); + initCloudLogger(); if (ResponsiveUtil.isAndroid()) { await initDisplayMode(); await RequestHeaderUtil.initAndroidInfo(); @@ -172,6 +174,27 @@ Future onError(FlutterErrorDetails details) async { } } +initCloudLogger() { + CloudLogger.logTrace = (tag, message, [e, t]) { + ILogger.trace(tag, message, e, t); + }; + CloudLogger.logDebug = (tag, message, [e, t]) { + ILogger.debug(tag, message, e, t); + }; + CloudLogger.logInfo = (tag, message, [e, t]) { + ILogger.info(tag, message, e, t); + }; + CloudLogger.logWarning = (tag, message, [e, t]) { + ILogger.warning(tag, message, e, t); + }; + CloudLogger.logError = (tag, message, [e, t]) { + ILogger.error(tag, message, e, t); + }; + CloudLogger.logFatal = (tag, message, [e, t]) { + ILogger.fatal(tag, message, e, t); + }; +} + class MyApp extends StatelessWidget { final Widget home; final String title; diff --git a/third-party/flutter_cloud/lib/cloud_logger.dart b/third-party/flutter_cloud/lib/cloud_logger.dart new file mode 100644 index 00000000..26cb600c --- /dev/null +++ b/third-party/flutter_cloud/lib/cloud_logger.dart @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024 Robert-Stackflow. + * + * This program is free software: you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . + */ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart'; + +class CloudLogger { + static Function(String tag, String message, [dynamic e, dynamic t])? logTrace; + static Function(String tag, String message, [dynamic e, dynamic t])? logDebug; + static Function(String tag, String message, [dynamic e, dynamic t])? logInfo; + static Function(String tag, String message, [dynamic e, dynamic t])? + logWarning; + static Function(String tag, String message, [dynamic e, dynamic t])? logError; + static Function(String tag, String message, [dynamic e, dynamic t])? logFatal; + + static void trace(String tag, String message, [dynamic e, dynamic t]) { + if (logTrace != null) { + logTrace!(tag, message, e, t); + } else { + debugPrint('TRACE: $tag: $message $e $t'); + } + } + + static void debug(String tag, String message, [dynamic e, dynamic t]) { + if (logDebug != null) { + logDebug!(tag, message, e, t); + } else { + debugPrint('DEBUG: $tag: $message $e $t'); + } + } + + static void info(String tag, String message, [dynamic e, dynamic t]) { + if (logInfo != null) { + logInfo!(tag, message, e, t); + } else { + debugPrint('INFO: $tag: $message $e $t'); + } + } + + static void infoResponse(String tag, String message, Response response) { + if (logInfo != null) { + logInfo!(tag, "$message [${response.statusCode}] [${response.body}]"); + } else { + debugPrint( + 'INFO for response: $tag: $message [${response.statusCode}] [${response.body}]'); + } + } + + static void errorResponse(String tag, String message, Response response) { + if (logError != null) { + logError!(tag, "$message [${response.statusCode}] [${response.body}]"); + } else { + debugPrint( + 'ERROR for response: $tag: $message [${response.statusCode}] [${response.body}]'); + } + } + + static void warning(String tag, String message, [dynamic e, dynamic t]) { + if (logWarning != null) { + logWarning!(tag, message, e, t); + } else { + debugPrint('WARNING: $tag: $message $e $t'); + } + } + + static void error(String tag, String message, [dynamic e, dynamic t]) { + if (logError != null) { + logError!(tag, message, e, t); + } else { + debugPrint('ERROR: $tag: $message $e $t'); + } + } + + static void fatal(String tag, String message, [dynamic e, dynamic t]) { + if (logFatal != null) { + logFatal!(tag, message, e, t); + } else { + debugPrint('FATAL: $tag: $message $e $t'); + } + } +} diff --git a/third-party/flutter_cloud/lib/dropbox.dart b/third-party/flutter_cloud/lib/dropbox.dart index d7488d5c..00cfcf53 100644 --- a/third-party/flutter_cloud/lib/dropbox.dart +++ b/third-party/flutter_cloud/lib/dropbox.dart @@ -10,6 +10,7 @@ import 'package:flutter_cloud/status.dart'; import 'package:flutter_cloud/token_manager.dart'; import 'package:http/http.dart' as http; +import 'cloud_logger.dart'; import 'dropbox_response.dart'; import 'oauth2_helper.dart'; @@ -35,6 +36,8 @@ class Dropbox with ChangeNotifier { final String clientId; late final String state; + static const String TAG = "Dropbox"; + Dropbox({ required this.clientId, required this.callbackUrl, @@ -118,7 +121,7 @@ class Dropbox with ChangeNotifier { } on PlatformException { return false; } catch (err, trace) { - debugPrint("# Dropbox -> connect: $err\n$trace"); + CloudLogger.error(TAG, "Error while connect:", err, trace); return false; } } @@ -131,10 +134,9 @@ class Dropbox with ChangeNotifier { uri, headers: {"Authorization": "Bearer $accessToken"}, ); - debugPrint( - "# Dropbox -> disconnect: revoke access token: ${resp.statusCode}"); + CloudLogger.infoResponse(TAG, "Revoke access token", resp); } catch (err, trace) { - debugPrint("# Dropbox -> disconnect: $err\n$trace"); + CloudLogger.error(TAG, "Error while disconnect:", err, trace); } finally { await _tokenManager.clearStoredToken(); notifyListeners(); @@ -197,14 +199,11 @@ class Dropbox with ChangeNotifier { final resp = await post(url); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# Dropbox -> getInfo success: ${jsonDecode(resp.body)}"); - + CloudLogger.infoResponse(TAG, "Get info success", resp); final usageResp = await post(storageUrl); if (usageResp.statusCode == 200 || usageResp.statusCode == 201) { - debugPrint( - "# Dropbox -> getStorageInfo success: ${jsonDecode(usageResp.body)}"); - + CloudLogger.infoResponse(TAG, "Get storage info success", usageResp); return DropboxResponse.fromResponse( response: usageResp, userInfo: DropboxUserInfo.fromJson( @@ -212,23 +211,21 @@ class Dropbox with ChangeNotifier { message: "Get Info successfully.", ); } else { - debugPrint( - "# Dropbox -> getStorageInfo failed: ${usageResp.statusCode} # Body: ${usageResp.body}"); + CloudLogger.errorResponse(TAG, "Get storage info failed", usageResp); return DropboxResponse.fromResponse( response: usageResp, message: "Error while get storage info.", ); } } else { - debugPrint( - "# Dropbox -> getInfo failed: ${resp.statusCode} # Body: ${resp.body}"); + CloudLogger.error(TAG, "Get info failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Error while get info.", ); } - } catch (err) { - debugPrint("# Dropbox -> getInfo error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Get info error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } @@ -259,22 +256,21 @@ class Dropbox with ChangeNotifier { if (item['.tag'] == "folder") continue; files.add(DropboxFileInfo.fromJson(item)); } - debugPrint("# Dropbox -> list successfully"); + CloudLogger.infoResponse(TAG, "List files success", resp); return DropboxResponse.fromResponse( response: resp, files: files, message: "List files successfully.", ); } else { - debugPrint( - "# Dropbox -> list failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "List files failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Error while listing files.", ); } - } catch (err) { - debugPrint("# Dropbox -> list error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "List files error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } @@ -295,21 +291,20 @@ class Dropbox with ChangeNotifier { ); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# Dropbox -> pull successfully"); + CloudLogger.infoResponse(TAG, "pull successfully", resp); return DropboxResponse.fromResponse( response: resp, message: "Download successfully.", ); } else { - debugPrint( - "# Dropbox -> pull failed : ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "pull failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Error while downloading file.", ); } - } catch (err) { - debugPrint("# Dropbox -> pull: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "pull error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } @@ -327,21 +322,20 @@ class Dropbox with ChangeNotifier { ); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# Dropbox -> delete successfully"); + CloudLogger.infoResponse(TAG, "delete successfully", resp); return DropboxResponse.fromResponse( response: resp, message: "Delete successfully.", ); } else { - debugPrint( - "# Dropbox -> delete failed ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "delete failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Error while deleting file.", ); } - } catch (err) { - debugPrint("# Dropbox -> delete error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "delete error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } @@ -363,21 +357,20 @@ class Dropbox with ChangeNotifier { ); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# Dropbox -> deleteBatch successfully"); + CloudLogger.infoResponse(TAG, "deleteBatch successfully", resp); return DropboxResponse.fromResponse( response: resp, message: "Delete batch successfully.", ); } else { - debugPrint( - "# Dropbox -> deleteBatch failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "deleteBatch failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Error while deleting file.", ); } - } catch (err) { - debugPrint("# Dropbox -> deleteBatch error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "deleteBatch error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } @@ -407,40 +400,21 @@ class Dropbox with ChangeNotifier { if (resp.statusCode == 200 || resp.statusCode == 201) { onProgress?.call(1, 1); - debugPrint("# Dropbox -> Upload successfully"); + CloudLogger.infoResponse(TAG, "Upload successfully", resp); return DropboxResponse.fromResponse( response: resp, message: "Upload finished.", ); } else { - debugPrint( - "# Dropbox -> Upload failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.error(TAG, "Upload failed", resp); return DropboxResponse.fromResponse( response: resp, message: "Upload failed.", ); } - } catch (err) { - debugPrint("# Dropbox -> Upload error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Upload error", err, trace); return DropboxResponse(message: "Unexpected exception: $err"); } } } - -class UploadStatus { - final int index; - final int total; - final int start; - final int end; - final String contentLength; - final String range; - - UploadStatus( - this.index, - this.total, - this.start, - this.end, - this.contentLength, - this.range, - ); -} diff --git a/third-party/flutter_cloud/lib/onedrive.dart b/third-party/flutter_cloud/lib/onedrive.dart index 4647c9a4..d1c1f1a8 100644 --- a/third-party/flutter_cloud/lib/onedrive.dart +++ b/third-party/flutter_cloud/lib/onedrive.dart @@ -10,6 +10,7 @@ import 'package:flutter_cloud/status.dart'; import 'package:flutter_cloud/token_manager.dart'; import 'package:http/http.dart' as http; +import 'cloud_logger.dart'; import 'oauth2_helper.dart'; import 'onedrive_response.dart'; @@ -38,6 +39,8 @@ class OneDrive with ChangeNotifier { late final String state; + static const String TAG = "Ondrive"; + OneDrive({ required this.clientId, required this.callbackUrl, @@ -117,8 +120,8 @@ class OneDrive with ChangeNotifier { } } on PlatformException { return false; - } catch (err) { - debugPrint("# OneDrive -> connect error: $err"); + } catch (e, t) { + CloudLogger.error(TAG, "# OneDrive -> connect error", e, t); return false; } } @@ -200,23 +203,23 @@ class OneDrive with ChangeNotifier { if (resp.statusCode == 200 || resp.statusCode == 201) { OneDriveUserInfo userInfo = OneDriveUserInfo.fromJson(jsonDecode(resp.body)); - debugPrint("# OneDrive -> get info successfully: $userInfo"); + CloudLogger.infoResponse( + TAG, "# OneDrive -> get info successfully: $userInfo", resp); return OneDriveResponse.fromResponse( response: resp, userInfo: userInfo, message: "Get Info successfully.", ); } else { - debugPrint( - "# OneDrive -> get info failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "# OneDrive -> get info failed: ", resp); return OneDriveResponse.fromResponse( response: resp, message: "Error while get info.", ); } - } catch (err) { - debugPrint("# OneDrive -> getInfo error: $err"); - return OneDriveResponse(message: "Unexpected exception: $err"); + } catch (e, t) { + CloudLogger.error(TAG, "# OneDrive -> getInfo error", e, t); + return OneDriveResponse(message: "Unexpected exception: $e"); } } @@ -238,23 +241,23 @@ class OneDrive with ChangeNotifier { for (var item in body['value']) { files.add(OneDriveFileInfo.fromJson(item)); } - debugPrint("# OneDrive -> list successfully"); + CloudLogger.infoResponse( + TAG, "# OneDrive -> list successfully: $files", resp); return OneDriveResponse.fromResponse( response: resp, files: files, message: "List files successfully.", ); } else { - debugPrint( - "# OneDrive -> list failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "# OneDrive -> list failed: ", resp); return OneDriveResponse.fromResponse( response: resp, message: "Error while listing files.", ); } - } catch (err) { - debugPrint("# OneDrive -> list: $err"); - return OneDriveResponse(message: "Unexpected exception: $err"); + } catch (e, t) { + CloudLogger.error(TAG, "# OneDrive -> list error", e, t); + return OneDriveResponse(message: "Unexpected exception: $e"); } } @@ -268,21 +271,20 @@ class OneDrive with ChangeNotifier { final resp = await get(url); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# OneDrive -> pull successfully"); + CloudLogger.info(TAG, "# OneDrive -> pull successfully"); return OneDriveResponse.fromResponse( response: resp, message: "Download successfully.", ); } else { - debugPrint( - "# OneDrive -> pull failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "# OneDrive -> pull failed", resp); return OneDriveResponse.fromResponse( response: resp, message: "Error while downloading file.", ); } - } catch (err) { - debugPrint("# OneDrive -> pull: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "# OneDrive -> pull error", err, trace); return OneDriveResponse(message: "Unexpected exception: $err"); } } @@ -299,22 +301,22 @@ class OneDrive with ChangeNotifier { if (resp.statusCode == 200 || resp.statusCode == 201 || resp.statusCode == 204) { - debugPrint("# OneDrive -> delete successfully"); + CloudLogger.infoResponse( + TAG, "# OneDrive -> delete successfully", resp); return OneDriveResponse.fromResponse( response: resp, message: "Delete successfully.", ); } else { - debugPrint( - "# OneDrive -> delete failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "# OneDrive -> delete failed", resp); return OneDriveResponse.fromResponse( response: resp, message: "Error while deleting file.", ); } - } catch (err) { - debugPrint("# OneDrive -> delete: $err"); - return OneDriveResponse(message: "Unexpected exception: $err"); + } catch (e, t) { + CloudLogger.error(TAG, "# OneDrive -> delete error", e, t); + return OneDriveResponse(message: "Unexpected exception: $e"); } } @@ -336,8 +338,10 @@ class OneDrive with ChangeNotifier { var resp = await post(url); - debugPrint( - "# OneDrive -> Upload Create Session: ${DateTime.now().difference(now).inMilliseconds} ms"); + CloudLogger.infoResponse( + TAG, + "# OneDrive -> Upload Create Session: ${DateTime.now().difference(now).inMilliseconds} ms", + resp); if (resp.statusCode == 200) { final Map respJson = jsonDecode(resp.body); @@ -364,22 +368,24 @@ class OneDrive with ChangeNotifier { body: pageData, ); - debugPrint( - "# OneDrive -> Upload [${pageIndex + 1}/$maxPage]: ${DateTime.now().difference(now).inMilliseconds} ms, start: $start, end: $end, contentLength: $contentLength, range: $range"); + CloudLogger.infoResponse( + TAG, + "# OneDrive -> Upload [${pageIndex + 1}/$maxPage]: ${DateTime.now().difference(now).inMilliseconds} ms, start: $start, end: $end, contentLength: $contentLength, range: $range", + resp); if (resp.statusCode == 202) { onProgress?.call(pageIndex + 1, maxPage); continue; } else if (resp.statusCode == 200 || resp.statusCode == 201) { onProgress?.call(pageIndex + 1, maxPage); - debugPrint("# OneDrive -> Upload finished"); + CloudLogger.infoResponse( + TAG, "# OneDrive -> Upload finished", resp); return OneDriveResponse.fromResponse( response: resp, message: "Upload finished.", ); } else { - debugPrint( - "# OneDrive -> Upload failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse(TAG, "# OneDrive -> Upload failed", resp); return OneDriveResponse.fromResponse( response: resp, message: "Upload failed.", @@ -387,8 +393,8 @@ class OneDrive with ChangeNotifier { } } } - } catch (err) { - debugPrint("# OneDrive -> Upload error: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "# OneDrive -> Upload error", err, trace); return OneDriveResponse(message: "Unexpected exception: $err"); } @@ -418,13 +424,14 @@ class OneDrive with ChangeNotifier { ); if (resp.statusCode == 200 || resp.statusCode == 201) { - debugPrint("# OneDrive -> create folder success: ${resp.body}"); + CloudLogger.infoResponse( + TAG, "# OneDrive -> create folder success", resp); } else { - debugPrint( - "# OneDrive -> create folder failed: ${resp.statusCode}\n# Body: ${resp.body}"); + CloudLogger.errorResponse( + TAG, "# OneDrive -> create folder failed", resp); } - } catch (err) { - debugPrint("# OneDrive -> create folder: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "# OneDrive -> create folder error", err, trace); } } } diff --git a/third-party/flutter_cloud/lib/onedrive_response.dart b/third-party/flutter_cloud/lib/onedrive_response.dart index 80b2b495..390697ad 100644 --- a/third-party/flutter_cloud/lib/onedrive_response.dart +++ b/third-party/flutter_cloud/lib/onedrive_response.dart @@ -1,4 +1,5 @@ import 'dart:typed_data'; + import 'package:flutter_cloud/status.dart'; import 'package:http/http.dart' as http; @@ -128,4 +129,17 @@ class OneDriveFileInfo { fileMimeType: json['file'] != null ? json['file']['mimeType'] ?? "" : "", ); } + + @override + String toString() { + return "OneDriveFileInfo(" + "id: $id, " + "name: $name, " + "size: $size, " + "createdDateTime: $createdDateTime, " + "lastModifiedDateTime: $lastModifiedDateTime, " + "description: $description, " + "fileMimeType: $fileMimeType" + ")"; + } } diff --git a/third-party/flutter_cloud/lib/token_manager.dart b/third-party/flutter_cloud/lib/token_manager.dart index 9db96576..a45f83c8 100644 --- a/third-party/flutter_cloud/lib/token_manager.dart +++ b/third-party/flutter_cloud/lib/token_manager.dart @@ -1,9 +1,10 @@ import 'dart:convert'; -import 'package:flutter/cupertino.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:http/http.dart' as http; +import 'cloud_logger.dart'; + FlutterSecureStorage secureStorage = const FlutterSecureStorage(); abstract class ITokenManager { @@ -30,6 +31,7 @@ class DefaultTokenManager extends ITokenManager { final String accessTokenKey; final String refreshTokenKey; final String idTokenKey; + static const String TAG = "TokenManager"; DefaultTokenManager({ required this.tokenEndpoint, @@ -56,8 +58,8 @@ class DefaultTokenManager extends ITokenManager { key: refreshTokenKey, value: body['refresh_token']); await secureStorage.write(key: idTokenKey, value: body['id_token'] ?? ""); return true; - } catch (err) { - debugPrint("# DefaultTokenManager -> _saveTokenMap: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Error saving token response", err, trace); return false; } } @@ -72,8 +74,8 @@ class DefaultTokenManager extends ITokenManager { return false; } return true; - } catch (err) { - debugPrint("# DefaultTokenManager -> getAccessToken: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Error checking if authorized", err, trace); return false; } } @@ -86,8 +88,8 @@ class DefaultTokenManager extends ITokenManager { secureStorage.delete(key: accessTokenKey), secureStorage.delete(key: refreshTokenKey), ]); - } catch (err) { - debugPrint("# DefaultTokenManager -> clearStoredToken: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Error clearing stored token", err, trace); } } @@ -113,8 +115,8 @@ class DefaultTokenManager extends ITokenManager { } return accessToken; - } catch (err) { - debugPrint("# DefaultTokenManager -> getAccessToken: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Error getting access token", err, trace); return null; } } @@ -136,19 +138,17 @@ class DefaultTokenManager extends ITokenManager { final resp = await http.post(Uri.parse(tokenEndpoint), body: body); if (resp.statusCode != 200) { - debugPrint( - "# DefaultTokenManager -> _refreshToken: ${resp.statusCode}\n# Body: ${resp.body}"); - + CloudLogger.errorResponse(TAG, "Error refreshing token", resp); await clearStoredToken(); return null; } - debugPrint("# Refresh token: Success"); + CloudLogger.infoResponse(TAG, "Refresh token: Success", resp); final Map tokenMap = jsonDecode(resp.body); await saveTokenResp(resp); return tokenMap; - } catch (err) { - debugPrint("# DefaultTokenManager -> _refreshToken: $err"); + } catch (err, trace) { + CloudLogger.error(TAG, "Error refreshing token", err, trace); if (err is! http.ClientException) { await clearStoredToken(); }