🐛 Bug fixes
This commit is contained in:
		| @@ -433,6 +433,7 @@ | ||||
|   "updateCheckStrictly": "Strict mode", | ||||
|   "updateCheckStrictlyDesc": "If enabled, the app will ask for updating once the local version is different from remote one.", | ||||
|   "updateMayAvailable": "App version @version is available, you can update from app store or our website.", | ||||
|   "updateNow": "Update now", | ||||
|   "termAccept": "I've read and agree to Solar Network's Terms", | ||||
|   "termAcceptDesc": "Including but not limited to \"User Agreement\" and \"Privacy Policy\"", | ||||
|   "termAcceptLink": "View terms", | ||||
|   | ||||
| @@ -428,6 +428,7 @@ | ||||
|   "update": "更新", | ||||
|   "updateCheckStrictly": "严格模式", | ||||
|   "updateCheckStrictlyDesc": "如果启用,应用程序将会在本地版本与远程版本不同时询问更新,而不会检查版本号大小。", | ||||
|   "updateNow": "立即更新", | ||||
|   "updateMayAvailable": "版本 @version 现已可用,你可以前往应用商店或是我们的官网下载更新。", | ||||
|   "termAccept": "我已阅读并同意 Solar Network 各项条款", | ||||
|   "termAcceptDesc": "包括但不限于《用户守则》和《隐私政策》", | ||||
|   | ||||
| @@ -42,6 +42,28 @@ class _BootstrapperShellState extends State<BootstrapperShell> { | ||||
|  | ||||
|   final Completer _bootCompleter = Completer(); | ||||
|  | ||||
|   void _updateNow(String localVersionString, String remoteVersionString) { | ||||
|     context | ||||
|         .showConfirmDialog( | ||||
|       'updateAvailable'.tr, | ||||
|       'updateAvailableDesc'.trParams({ | ||||
|         'from': localVersionString, | ||||
|         'to': remoteVersionString, | ||||
|       }), | ||||
|     ) | ||||
|         .then((result) { | ||||
|       if (result) { | ||||
|         final model = UpdateModel( | ||||
|           'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk', | ||||
|           'solian-app-arm64-v8a-release.apk', | ||||
|           'ic_launcher', | ||||
|           'https://testflight.apple.com/join/YJ0lmN6O', | ||||
|         ); | ||||
|         AzhonAppUpdate.update(model); | ||||
|       } | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   Future<void> _checkForUpdate() async { | ||||
|     if (PlatformInfo.isWeb) return; | ||||
|     try { | ||||
| @@ -70,25 +92,7 @@ class _BootstrapperShellState extends State<BootstrapperShell> { | ||||
|               remoteBuildNumber > localBuildNumber) || | ||||
|           (remoteVersionString != localVersionString && strictUpdate)) { | ||||
|         if (PlatformInfo.isAndroid) { | ||||
|           context | ||||
|               .showConfirmDialog( | ||||
|             'updateAvailable'.tr, | ||||
|             'updateAvailableDesc'.trParams({ | ||||
|               'from': localVersionString, | ||||
|               'to': remoteVersionString, | ||||
|             }), | ||||
|           ) | ||||
|               .then((result) { | ||||
|             if (result) { | ||||
|               final model = UpdateModel( | ||||
|                 'https://files.solsynth.dev/d/production01/solian/app-arm64-v8a-release.apk', | ||||
|                 'solian-app-arm64-v8a-release.apk', | ||||
|                 'ic_launcher', | ||||
|                 'https://testflight.apple.com/join/YJ0lmN6O', | ||||
|               ); | ||||
|               AzhonAppUpdate.update(model); | ||||
|             } | ||||
|           }); | ||||
|           _updateNow(localVersionString, remoteVersionString); | ||||
|         } else { | ||||
|           context.showInfoDialog( | ||||
|             'updateAvailable'.tr, | ||||
| @@ -97,9 +101,19 @@ class _BootstrapperShellState extends State<BootstrapperShell> { | ||||
|         } | ||||
|       } else if (remoteVersionString != localVersionString) { | ||||
|         _bootCompleter.future.then((_) { | ||||
|           context.showSnackbar('updateMayAvailable'.trParams({ | ||||
|             'version': remoteVersionString, | ||||
|           })); | ||||
|           context.showSnackbar( | ||||
|             'updateMayAvailable'.trParams({ | ||||
|               'version': remoteVersionString, | ||||
|             }), | ||||
|             action: PlatformInfo.isAndroid | ||||
|                 ? SnackBarAction( | ||||
|                     label: 'updateNow'.tr, | ||||
|                     onPressed: () { | ||||
|                       _updateNow(localVersionString, remoteVersionString); | ||||
|                     }, | ||||
|                   ) | ||||
|                 : null, | ||||
|           ); | ||||
|         }); | ||||
|       } | ||||
|     } catch (e) { | ||||
|   | ||||
| @@ -193,96 +193,99 @@ class _AccountProfilePageState extends State<AccountProfilePage> { | ||||
|                 toolbarHeight: AppTheme.toolbarHeight(context), | ||||
|                 leadingWidth: 24, | ||||
|                 automaticallyImplyLeading: false, | ||||
|                 flexibleSpace: Row( | ||||
|                   children: [ | ||||
|                     AppBarLeadingButton.adaptive(context) ?? const Gap(8), | ||||
|                     const Gap(8), | ||||
|                     if (_userinfo != null) | ||||
|                       AccountAvatar(content: _userinfo!.avatar, radius: 16), | ||||
|                     const Gap(12), | ||||
|                     Expanded( | ||||
|                       child: Column( | ||||
|                         mainAxisAlignment: MainAxisAlignment.center, | ||||
|                         crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                         children: [ | ||||
|                           if (_userinfo != null) | ||||
|                             Text( | ||||
|                               _userinfo!.nick, | ||||
|                               style: Theme.of(context).textTheme.bodyLarge, | ||||
|                             ), | ||||
|                           if (_userinfo != null) | ||||
|                             Text( | ||||
|                               '@${_userinfo!.name}', | ||||
|                               style: Theme.of(context).textTheme.bodySmall, | ||||
|                             ), | ||||
|                         ], | ||||
|                       ), | ||||
|                     ), | ||||
|                     if (_userinfo != null && _subscription == null) | ||||
|                       OutlinedButton( | ||||
|                         style: const ButtonStyle( | ||||
|                           visualDensity: | ||||
|                               VisualDensity(horizontal: -4, vertical: -2), | ||||
|                 flexibleSpace: SizedBox( | ||||
|                   height: 56, | ||||
|                   child: Row( | ||||
|                     children: [ | ||||
|                       AppBarLeadingButton.adaptive(context) ?? const Gap(8), | ||||
|                       const Gap(8), | ||||
|                       if (_userinfo != null) | ||||
|                         AccountAvatar(content: _userinfo!.avatar, radius: 16), | ||||
|                       const Gap(12), | ||||
|                       Expanded( | ||||
|                         child: Column( | ||||
|                           mainAxisAlignment: MainAxisAlignment.center, | ||||
|                           crossAxisAlignment: CrossAxisAlignment.start, | ||||
|                           children: [ | ||||
|                             if (_userinfo != null) | ||||
|                               Text( | ||||
|                                 _userinfo!.nick, | ||||
|                                 style: Theme.of(context).textTheme.bodyLarge, | ||||
|                               ), | ||||
|                             if (_userinfo != null) | ||||
|                               Text( | ||||
|                                 '@${_userinfo!.name}', | ||||
|                                 style: Theme.of(context).textTheme.bodySmall, | ||||
|                               ), | ||||
|                           ], | ||||
|                         ), | ||||
|                         onPressed: _isSubscribing | ||||
|                             ? null | ||||
|                             : () async { | ||||
|                                 setState(() => _isSubscribing = true); | ||||
|                                 _subscription = | ||||
|                                     await Get.find<SubscriptionProvider>() | ||||
|                                         .subscribeToUser(_userinfo!.id); | ||||
|                                 setState(() => _isSubscribing = false); | ||||
|                               }, | ||||
|                         child: Text('subscribe'.tr), | ||||
|                       ) | ||||
|                     else if (_userinfo != null) | ||||
|                       OutlinedButton( | ||||
|                         style: const ButtonStyle( | ||||
|                           visualDensity: | ||||
|                               VisualDensity(horizontal: -4, vertical: -2), | ||||
|                       ), | ||||
|                       if (_userinfo != null && _subscription == null) | ||||
|                         OutlinedButton( | ||||
|                           style: const ButtonStyle( | ||||
|                             visualDensity: | ||||
|                                 VisualDensity(horizontal: -4, vertical: -2), | ||||
|                           ), | ||||
|                           onPressed: _isSubscribing | ||||
|                               ? null | ||||
|                               : () async { | ||||
|                                   setState(() => _isSubscribing = true); | ||||
|                                   _subscription = | ||||
|                                       await Get.find<SubscriptionProvider>() | ||||
|                                           .subscribeToUser(_userinfo!.id); | ||||
|                                   setState(() => _isSubscribing = false); | ||||
|                                 }, | ||||
|                           child: Text('subscribe'.tr), | ||||
|                         ) | ||||
|                       else if (_userinfo != null) | ||||
|                         OutlinedButton( | ||||
|                           style: const ButtonStyle( | ||||
|                             visualDensity: | ||||
|                                 VisualDensity(horizontal: -4, vertical: -2), | ||||
|                           ), | ||||
|                           onPressed: _isSubscribing | ||||
|                               ? null | ||||
|                               : () async { | ||||
|                                   setState(() => _isSubscribing = true); | ||||
|                                   await Get.find<SubscriptionProvider>() | ||||
|                                       .unsubscribeFromUser(_userinfo!.id); | ||||
|                                   _subscription = null; | ||||
|                                   setState(() => _isSubscribing = false); | ||||
|                                 }, | ||||
|                           child: Text('unsubscribe'.tr), | ||||
|                         ), | ||||
|                         onPressed: _isSubscribing | ||||
|                             ? null | ||||
|                             : () async { | ||||
|                                 setState(() => _isSubscribing = true); | ||||
|                                 await Get.find<SubscriptionProvider>() | ||||
|                                     .unsubscribeFromUser(_userinfo!.id); | ||||
|                                 _subscription = null; | ||||
|                                 setState(() => _isSubscribing = false); | ||||
|                               }, | ||||
|                         child: Text('unsubscribe'.tr), | ||||
|                       if (_userinfo != null && | ||||
|                           !_relationshipProvider.hasFriend(_userinfo!)) | ||||
|                         IconButton( | ||||
|                           icon: const Icon(Icons.person_add), | ||||
|                           onPressed: _isMakingFriend | ||||
|                               ? null | ||||
|                               : () async { | ||||
|                                   setState(() => _isMakingFriend = true); | ||||
|                                   try { | ||||
|                                     await _relationshipProvider | ||||
|                                         .makeFriend(widget.name); | ||||
|                                     context.showSnackbar( | ||||
|                                       'accountFriendRequestSent'.tr, | ||||
|                                     ); | ||||
|                                   } catch (e) { | ||||
|                                     context.showErrorDialog(e); | ||||
|                                   } finally { | ||||
|                                     setState(() => _isMakingFriend = false); | ||||
|                                   } | ||||
|                                 }, | ||||
|                         ) | ||||
|                       else | ||||
|                         const IconButton( | ||||
|                           icon: Icon(Icons.handshake), | ||||
|                           onPressed: null, | ||||
|                         ), | ||||
|                       SizedBox( | ||||
|                         width: AppTheme.isLargeScreen(context) ? 8 : 16, | ||||
|                       ), | ||||
|                     if (_userinfo != null && | ||||
|                         !_relationshipProvider.hasFriend(_userinfo!)) | ||||
|                       IconButton( | ||||
|                         icon: const Icon(Icons.person_add), | ||||
|                         onPressed: _isMakingFriend | ||||
|                             ? null | ||||
|                             : () async { | ||||
|                                 setState(() => _isMakingFriend = true); | ||||
|                                 try { | ||||
|                                   await _relationshipProvider | ||||
|                                       .makeFriend(widget.name); | ||||
|                                   context.showSnackbar( | ||||
|                                     'accountFriendRequestSent'.tr, | ||||
|                                   ); | ||||
|                                 } catch (e) { | ||||
|                                   context.showErrorDialog(e); | ||||
|                                 } finally { | ||||
|                                   setState(() => _isMakingFriend = false); | ||||
|                                 } | ||||
|                               }, | ||||
|                       ) | ||||
|                     else | ||||
|                       const IconButton( | ||||
|                         icon: Icon(Icons.handshake), | ||||
|                         onPressed: null, | ||||
|                       ), | ||||
|                     SizedBox( | ||||
|                       width: AppTheme.isLargeScreen(context) ? 8 : 16, | ||||
|                     ), | ||||
|                   ], | ||||
|                 ), | ||||
|                     ], | ||||
|                   ), | ||||
|                 ).paddingOnly(top: MediaQuery.of(context).padding.top), | ||||
|                 bottom: TabBar( | ||||
|                   tabs: [ | ||||
|                     Tab(text: 'profilePage'.tr), | ||||
| @@ -296,128 +299,132 @@ class _AccountProfilePageState extends State<AccountProfilePage> { | ||||
|           body: TabBarView( | ||||
|             physics: const NeverScrollableScrollPhysics(), | ||||
|             children: [ | ||||
|               Column( | ||||
|               ListView( | ||||
|                 children: [ | ||||
|                   const Gap(16), | ||||
|                   AccountHeadingWidget( | ||||
|                     name: _userinfo!.name, | ||||
|                     nick: _userinfo!.nick, | ||||
|                     desc: _userinfo!.description, | ||||
|                     badges: _userinfo!.badges, | ||||
|                     banner: _userinfo!.banner, | ||||
|                     avatar: _userinfo!.avatar, | ||||
|                     status: Get.find<StatusProvider>() | ||||
|                         .getSomeoneStatus(_userinfo!.name), | ||||
|                     detail: _userinfo, | ||||
|                     profile: _userinfo!.profile, | ||||
|                     extraWidgets: [ | ||||
|                       if (_dailySignRecords.isNotEmpty) | ||||
|                         Card( | ||||
|                           child: SizedBox( | ||||
|                             height: 180, | ||||
|                             width: max(640, MediaQuery.of(context).size.width), | ||||
|                             child: LineChart( | ||||
|                               LineChartData( | ||||
|                                 lineBarsData: [ | ||||
|                                   LineChartBarData( | ||||
|                                     isCurved: true, | ||||
|                                     isStrokeCapRound: true, | ||||
|                                     isStrokeJoinRound: true, | ||||
|                                     color: | ||||
|                                         Theme.of(context).colorScheme.primary, | ||||
|                                     belowBarData: BarAreaData( | ||||
|                                       show: true, | ||||
|                                       gradient: LinearGradient( | ||||
|                                         colors: List.filled( | ||||
|                                           _dailySignRecords.length, | ||||
|                                           Theme.of(context) | ||||
|                                               .colorScheme | ||||
|                                               .primary | ||||
|                                               .withOpacity(0.3), | ||||
|                                         ).toList(), | ||||
|                                       ), | ||||
|                                     ), | ||||
|                                     spots: _dailySignRecords | ||||
|                                         .map( | ||||
|                                           (x) => FlSpot( | ||||
|                                             x.createdAt | ||||
|                                                 .copyWith( | ||||
|                                                   hour: 0, | ||||
|                                                   minute: 0, | ||||
|                                                   second: 0, | ||||
|                                                   millisecond: 0, | ||||
|                                                   microsecond: 0, | ||||
|                                                 ) | ||||
|                                                 .millisecondsSinceEpoch | ||||
|                                                 .toDouble(), | ||||
|                                             x.resultTier.toDouble(), | ||||
|                                           ), | ||||
|                                         ) | ||||
|                                         .toList(), | ||||
|                                   ) | ||||
|                                 ], | ||||
|                                 lineTouchData: LineTouchData( | ||||
|                                   touchTooltipData: LineTouchTooltipData( | ||||
|                                     getTooltipItems: (spots) => spots | ||||
|                                         .map((spot) => LineTooltipItem( | ||||
|                                               '${DailySignHistoryChartDialog.signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                               TextStyle( | ||||
|                                                 color: Theme.of(context) | ||||
|                                                     .colorScheme | ||||
|                                                     .onSurface, | ||||
|                                               ), | ||||
|                                             )) | ||||
|                                         .toList(), | ||||
|                                     getTooltipColor: (_) => Theme.of(context) | ||||
|                                         .colorScheme | ||||
|                                         .surfaceContainerHigh, | ||||
|                                   ), | ||||
|                                 ), | ||||
|                                 titlesData: FlTitlesData( | ||||
|                                   topTitles: const AxisTitles( | ||||
|                                     sideTitles: SideTitles(showTitles: false), | ||||
|                                   ), | ||||
|                                   rightTitles: const AxisTitles( | ||||
|                                     sideTitles: SideTitles(showTitles: false), | ||||
|                                   ), | ||||
|                                   leftTitles: AxisTitles( | ||||
|                                     sideTitles: SideTitles( | ||||
|                                       showTitles: true, | ||||
|                                       reservedSize: 40, | ||||
|                                       interval: 1, | ||||
|                                       getTitlesWidget: (value, _) => Align( | ||||
|                                         alignment: Alignment.centerRight, | ||||
|                                         child: Text( | ||||
|                                           DailySignHistoryChartDialog | ||||
|                                               .signSymbols[value.toInt()], | ||||
|                                           textAlign: TextAlign.right, | ||||
|                                         ).paddingOnly(right: 8), | ||||
|                                       ), | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                   bottomTitles: AxisTitles( | ||||
|                                     sideTitles: SideTitles( | ||||
|                                       showTitles: true, | ||||
|                                       reservedSize: 28, | ||||
|                                       interval: 86400000, | ||||
|                                       getTitlesWidget: (value, _) => Text( | ||||
|                                         DateFormat('dd').format( | ||||
|                                           DateTime.fromMillisecondsSinceEpoch( | ||||
|                                             value.toInt(), | ||||
|                                           ), | ||||
|                   CenteredContainer( | ||||
|                     child: AccountHeadingWidget( | ||||
|                       name: _userinfo!.name, | ||||
|                       nick: _userinfo!.nick, | ||||
|                       desc: _userinfo!.description, | ||||
|                       badges: _userinfo!.badges, | ||||
|                       banner: _userinfo!.banner, | ||||
|                       avatar: _userinfo!.avatar, | ||||
|                       status: Get.find<StatusProvider>() | ||||
|                           .getSomeoneStatus(_userinfo!.name), | ||||
|                       detail: _userinfo, | ||||
|                       profile: _userinfo!.profile, | ||||
|                       extraWidgets: [ | ||||
|                         if (_dailySignRecords.isNotEmpty) | ||||
|                           Card( | ||||
|                             child: SizedBox( | ||||
|                               height: 180, | ||||
|                               width: | ||||
|                                   max(640, MediaQuery.of(context).size.width), | ||||
|                               child: LineChart( | ||||
|                                 LineChartData( | ||||
|                                   lineBarsData: [ | ||||
|                                     LineChartBarData( | ||||
|                                       isCurved: true, | ||||
|                                       isStrokeCapRound: true, | ||||
|                                       isStrokeJoinRound: true, | ||||
|                                       color: | ||||
|                                           Theme.of(context).colorScheme.primary, | ||||
|                                       belowBarData: BarAreaData( | ||||
|                                         show: true, | ||||
|                                         gradient: LinearGradient( | ||||
|                                           colors: List.filled( | ||||
|                                             _dailySignRecords.length, | ||||
|                                             Theme.of(context) | ||||
|                                                 .colorScheme | ||||
|                                                 .primary | ||||
|                                                 .withOpacity(0.3), | ||||
|                                           ).toList(), | ||||
|                                         ), | ||||
|                                         textAlign: TextAlign.center, | ||||
|                                       ).paddingOnly(top: 8), | ||||
|                                       ), | ||||
|                                       spots: _dailySignRecords | ||||
|                                           .map( | ||||
|                                             (x) => FlSpot( | ||||
|                                               x.createdAt | ||||
|                                                   .copyWith( | ||||
|                                                     hour: 0, | ||||
|                                                     minute: 0, | ||||
|                                                     second: 0, | ||||
|                                                     millisecond: 0, | ||||
|                                                     microsecond: 0, | ||||
|                                                   ) | ||||
|                                                   .millisecondsSinceEpoch | ||||
|                                                   .toDouble(), | ||||
|                                               x.resultTier.toDouble(), | ||||
|                                             ), | ||||
|                                           ) | ||||
|                                           .toList(), | ||||
|                                     ) | ||||
|                                   ], | ||||
|                                   lineTouchData: LineTouchData( | ||||
|                                     touchTooltipData: LineTouchTooltipData( | ||||
|                                       getTooltipItems: (spots) => spots | ||||
|                                           .map((spot) => LineTooltipItem( | ||||
|                                                 '${DailySignHistoryChartDialog.signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                                 TextStyle( | ||||
|                                                   color: Theme.of(context) | ||||
|                                                       .colorScheme | ||||
|                                                       .onSurface, | ||||
|                                                 ), | ||||
|                                               )) | ||||
|                                           .toList(), | ||||
|                                       getTooltipColor: (_) => Theme.of(context) | ||||
|                                           .colorScheme | ||||
|                                           .surfaceContainerHigh, | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                   titlesData: FlTitlesData( | ||||
|                                     topTitles: const AxisTitles( | ||||
|                                       sideTitles: SideTitles(showTitles: false), | ||||
|                                     ), | ||||
|                                     rightTitles: const AxisTitles( | ||||
|                                       sideTitles: SideTitles(showTitles: false), | ||||
|                                     ), | ||||
|                                     leftTitles: AxisTitles( | ||||
|                                       sideTitles: SideTitles( | ||||
|                                         showTitles: true, | ||||
|                                         reservedSize: 40, | ||||
|                                         interval: 1, | ||||
|                                         getTitlesWidget: (value, _) => Align( | ||||
|                                           alignment: Alignment.centerRight, | ||||
|                                           child: Text( | ||||
|                                             DailySignHistoryChartDialog | ||||
|                                                 .signSymbols[value.toInt()], | ||||
|                                             textAlign: TextAlign.right, | ||||
|                                           ).paddingOnly(right: 8), | ||||
|                                         ), | ||||
|                                       ), | ||||
|                                     ), | ||||
|                                     bottomTitles: AxisTitles( | ||||
|                                       sideTitles: SideTitles( | ||||
|                                         showTitles: true, | ||||
|                                         reservedSize: 28, | ||||
|                                         interval: 86400000, | ||||
|                                         getTitlesWidget: (value, _) => Text( | ||||
|                                           DateFormat('dd').format( | ||||
|                                             DateTime.fromMillisecondsSinceEpoch( | ||||
|                                               value.toInt(), | ||||
|                                             ), | ||||
|                                           ), | ||||
|                                           textAlign: TextAlign.center, | ||||
|                                         ).paddingOnly(top: 8), | ||||
|                                       ), | ||||
|                                     ), | ||||
|                                   ), | ||||
|                                   gridData: const FlGridData(show: false), | ||||
|                                   borderData: FlBorderData(show: false), | ||||
|                                 ), | ||||
|                                 gridData: const FlGridData(show: false), | ||||
|                                 borderData: FlBorderData(show: false), | ||||
|                               ), | ||||
|                             ), | ||||
|                           ).marginOnly(right: 24, left: 12, bottom: 8, top: 24), | ||||
|                         ) | ||||
|                     ], | ||||
|                             ).marginOnly( | ||||
|                                 right: 24, left: 12, bottom: 8, top: 24), | ||||
|                           ) | ||||
|                       ], | ||||
|                     ), | ||||
|                   ), | ||||
|                 ], | ||||
|               ), | ||||
|   | ||||
| @@ -21,6 +21,7 @@ class AttachmentItem extends StatefulWidget { | ||||
|   final bool showBadge; | ||||
|   final bool showHideButton; | ||||
|   final bool autoload; | ||||
|   final bool isDense; | ||||
|   final BoxFit fit; | ||||
|   final String? badge; | ||||
|   final Function? onHide; | ||||
| @@ -34,6 +35,7 @@ class AttachmentItem extends StatefulWidget { | ||||
|     this.showBadge = true, | ||||
|     this.showHideButton = true, | ||||
|     this.autoload = false, | ||||
|     this.isDense = false, | ||||
|     this.onHide, | ||||
|   }); | ||||
|  | ||||
| @@ -53,6 +55,7 @@ class _AttachmentItemState extends State<AttachmentItem> { | ||||
|           fit: widget.fit, | ||||
|           showBadge: widget.showBadge, | ||||
|           showHideButton: widget.showHideButton, | ||||
|           isDense: widget.isDense, | ||||
|           onHide: widget.onHide, | ||||
|         ); | ||||
|       case 'video': | ||||
| @@ -120,6 +123,7 @@ class _AttachmentItemImage extends StatelessWidget { | ||||
|   final bool showBadge; | ||||
|   final bool showHideButton; | ||||
|   final BoxFit fit; | ||||
|   final bool isDense; | ||||
|   final String? badge; | ||||
|   final Function? onHide; | ||||
|  | ||||
| @@ -128,6 +132,7 @@ class _AttachmentItemImage extends StatelessWidget { | ||||
|     required this.item, | ||||
|     required this.showBadge, | ||||
|     required this.showHideButton, | ||||
|     required this.isDense, | ||||
|     required this.fit, | ||||
|     this.badge, | ||||
|     this.onHide, | ||||
| @@ -146,6 +151,7 @@ class _AttachmentItemImage extends StatelessWidget { | ||||
|               '/attachments/${item.rid}', | ||||
|             ), | ||||
|             fit: fit, | ||||
|             isDense: isDense, | ||||
|           ), | ||||
|           if (showBadge && badge != null) | ||||
|             Positioned( | ||||
|   | ||||
| @@ -338,6 +338,7 @@ class AttachmentListEntry extends StatelessWidget { | ||||
|               badge: showBadge ? badgeContent : null, | ||||
|               showHideButton: !item!.isMature || showMature, | ||||
|               autoload: autoload, | ||||
|               isDense: isDense, | ||||
|               onHide: () { | ||||
|                 onReveal(false); | ||||
|               }, | ||||
|   | ||||
| @@ -42,61 +42,168 @@ class DailySignHistoryChartDialog extends StatelessWidget { | ||||
|                 child: CircularProgressIndicator(), | ||||
|               ), | ||||
|             ) | ||||
|           : Column( | ||||
|               mainAxisSize: MainAxisSize.min, | ||||
|               crossAxisAlignment: CrossAxisAlignment.start, | ||||
|               children: [ | ||||
|                 Text( | ||||
|                   'dailySignHistoryRecent'.tr, | ||||
|                   style: Theme.of(context).textTheme.titleMedium, | ||||
|                 ).paddingOnly(bottom: 18), | ||||
|                 SizedBox( | ||||
|                   height: 180, | ||||
|                   width: max(640, MediaQuery.of(context).size.width), | ||||
|                   child: LineChart( | ||||
|                     LineChartData( | ||||
|                       lineBarsData: [ | ||||
|                         LineChartBarData( | ||||
|                           isCurved: true, | ||||
|                           isStrokeCapRound: true, | ||||
|                           isStrokeJoinRound: true, | ||||
|                           color: Theme.of(context).colorScheme.primary, | ||||
|                           belowBarData: BarAreaData( | ||||
|                             show: true, | ||||
|                             gradient: LinearGradient( | ||||
|                               colors: List.filled( | ||||
|                                 data!.length, | ||||
|                                 Theme.of(context) | ||||
|                                     .colorScheme | ||||
|                                     .primary | ||||
|                                     .withOpacity(0.3), | ||||
|                               ).toList(), | ||||
|           : SizedBox( | ||||
|               width: double.maxFinite, | ||||
|               child: ListView( | ||||
|                 shrinkWrap: true, | ||||
|                 children: [ | ||||
|                   Text( | ||||
|                     'dailySignHistoryRecent'.tr, | ||||
|                     style: Theme.of(context).textTheme.titleMedium, | ||||
|                   ).paddingOnly(bottom: 18), | ||||
|                   SizedBox( | ||||
|                     height: 180, | ||||
|                     width: max(640, MediaQuery.of(context).size.width), | ||||
|                     child: LineChart( | ||||
|                       LineChartData( | ||||
|                         lineBarsData: [ | ||||
|                           LineChartBarData( | ||||
|                             isCurved: true, | ||||
|                             isStrokeCapRound: true, | ||||
|                             isStrokeJoinRound: true, | ||||
|                             color: Theme.of(context).colorScheme.primary, | ||||
|                             belowBarData: BarAreaData( | ||||
|                               show: true, | ||||
|                               gradient: LinearGradient( | ||||
|                                 colors: List.filled( | ||||
|                                   data!.length, | ||||
|                                   Theme.of(context) | ||||
|                                       .colorScheme | ||||
|                                       .primary | ||||
|                                       .withOpacity(0.3), | ||||
|                                 ).toList(), | ||||
|                               ), | ||||
|                             ), | ||||
|                             spots: data! | ||||
|                                 .map( | ||||
|                                   (x) => FlSpot( | ||||
|                                     x.createdAt | ||||
|                                         .copyWith( | ||||
|                                           hour: 0, | ||||
|                                           minute: 0, | ||||
|                                           second: 0, | ||||
|                                           millisecond: 0, | ||||
|                                           microsecond: 0, | ||||
|                                         ) | ||||
|                                         .millisecondsSinceEpoch | ||||
|                                         .toDouble(), | ||||
|                                     x.resultTier.toDouble(), | ||||
|                                   ), | ||||
|                                 ) | ||||
|                                 .toList(), | ||||
|                           ) | ||||
|                         ], | ||||
|                         lineTouchData: LineTouchData( | ||||
|                           touchTooltipData: LineTouchTooltipData( | ||||
|                             getTooltipItems: (spots) => spots | ||||
|                                 .map((spot) => LineTooltipItem( | ||||
|                                       '${signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                       TextStyle( | ||||
|                                         color: Theme.of(context) | ||||
|                                             .colorScheme | ||||
|                                             .onSurface, | ||||
|                                       ), | ||||
|                                     )) | ||||
|                                 .toList(), | ||||
|                             getTooltipColor: (_) => Theme.of(context) | ||||
|                                 .colorScheme | ||||
|                                 .surfaceContainerHigh, | ||||
|                           ), | ||||
|                         ), | ||||
|                         titlesData: FlTitlesData( | ||||
|                           topTitles: const AxisTitles( | ||||
|                             sideTitles: SideTitles(showTitles: false), | ||||
|                           ), | ||||
|                           rightTitles: const AxisTitles( | ||||
|                             sideTitles: SideTitles(showTitles: false), | ||||
|                           ), | ||||
|                           leftTitles: AxisTitles( | ||||
|                             sideTitles: SideTitles( | ||||
|                               showTitles: true, | ||||
|                               reservedSize: 40, | ||||
|                               interval: 1, | ||||
|                               getTitlesWidget: (value, _) => Align( | ||||
|                                 alignment: Alignment.centerRight, | ||||
|                                 child: Text( | ||||
|                                   signSymbols[value.toInt()], | ||||
|                                   textAlign: TextAlign.right, | ||||
|                                 ).paddingOnly(right: 8), | ||||
|                               ), | ||||
|                             ), | ||||
|                           ), | ||||
|                           spots: data! | ||||
|                               .map( | ||||
|                                 (x) => FlSpot( | ||||
|                                   x.createdAt | ||||
|                                       .copyWith( | ||||
|                                         hour: 0, | ||||
|                                         minute: 0, | ||||
|                                         second: 0, | ||||
|                                         millisecond: 0, | ||||
|                                         microsecond: 0, | ||||
|                                       ) | ||||
|                                       .millisecondsSinceEpoch | ||||
|                                       .toDouble(), | ||||
|                                   x.resultTier.toDouble(), | ||||
|                           bottomTitles: AxisTitles( | ||||
|                             sideTitles: SideTitles( | ||||
|                               showTitles: true, | ||||
|                               reservedSize: 28, | ||||
|                               interval: 86400000, | ||||
|                               getTitlesWidget: (value, _) => Text( | ||||
|                                 DateFormat('dd').format( | ||||
|                                   DateTime.fromMillisecondsSinceEpoch( | ||||
|                                     value.toInt(), | ||||
|                                   ), | ||||
|                                 ), | ||||
|                               ) | ||||
|                               .toList(), | ||||
|                         ) | ||||
|                       ], | ||||
|                       lineTouchData: LineTouchData( | ||||
|                         touchTooltipData: LineTouchTooltipData( | ||||
|                                 textAlign: TextAlign.center, | ||||
|                               ).paddingOnly(top: 8), | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
|                         gridData: const FlGridData(show: false), | ||||
|                         borderData: FlBorderData(show: false), | ||||
|                       ), | ||||
|                     ), | ||||
|                   ).marginOnly(right: 24, bottom: 8, top: 8), | ||||
|                   const Gap(16), | ||||
|                   Text( | ||||
|                     'dailySignHistoryReward'.tr, | ||||
|                     style: Theme.of(context).textTheme.titleMedium, | ||||
|                   ).paddingOnly(bottom: 18), | ||||
|                   SizedBox( | ||||
|                     height: 180, | ||||
|                     width: max(640, MediaQuery.of(context).size.width), | ||||
|                     child: LineChart( | ||||
|                       LineChartData( | ||||
|                         lineBarsData: [ | ||||
|                           LineChartBarData( | ||||
|                             isCurved: true, | ||||
|                             isStrokeCapRound: true, | ||||
|                             isStrokeJoinRound: true, | ||||
|                             color: Theme.of(context).colorScheme.primary, | ||||
|                             belowBarData: BarAreaData( | ||||
|                               show: true, | ||||
|                               gradient: LinearGradient( | ||||
|                                 colors: List.filled( | ||||
|                                   data!.length, | ||||
|                                   Theme.of(context) | ||||
|                                       .colorScheme | ||||
|                                       .primary | ||||
|                                       .withOpacity(0.3), | ||||
|                                 ).toList(), | ||||
|                               ), | ||||
|                             ), | ||||
|                             spots: data! | ||||
|                                 .map( | ||||
|                                   (x) => FlSpot( | ||||
|                                     x.createdAt | ||||
|                                         .copyWith( | ||||
|                                           hour: 0, | ||||
|                                           minute: 0, | ||||
|                                           second: 0, | ||||
|                                           millisecond: 0, | ||||
|                                           microsecond: 0, | ||||
|                                         ) | ||||
|                                         .millisecondsSinceEpoch | ||||
|                                         .toDouble(), | ||||
|                                     x.resultExperience.toDouble(), | ||||
|                                   ), | ||||
|                                 ) | ||||
|                                 .toList(), | ||||
|                           ) | ||||
|                         ], | ||||
|                         lineTouchData: LineTouchData( | ||||
|                             touchTooltipData: LineTouchTooltipData( | ||||
|                           getTooltipItems: (spots) => spots | ||||
|                               .map((spot) => LineTooltipItem( | ||||
|                                     '${signSymbols[spot.y.toInt()]}\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                     '+${spot.y.toStringAsFixed(0)} EXP\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                     TextStyle( | ||||
|                                       color: Theme.of(context) | ||||
|                                           .colorScheme | ||||
| @@ -107,153 +214,50 @@ class DailySignHistoryChartDialog extends StatelessWidget { | ||||
|                           getTooltipColor: (_) => Theme.of(context) | ||||
|                               .colorScheme | ||||
|                               .surfaceContainerHigh, | ||||
|                         ), | ||||
|                       ), | ||||
|                       titlesData: FlTitlesData( | ||||
|                         topTitles: const AxisTitles( | ||||
|                           sideTitles: SideTitles(showTitles: false), | ||||
|                         ), | ||||
|                         rightTitles: const AxisTitles( | ||||
|                           sideTitles: SideTitles(showTitles: false), | ||||
|                         ), | ||||
|                         leftTitles: AxisTitles( | ||||
|                           sideTitles: SideTitles( | ||||
|                             showTitles: true, | ||||
|                             reservedSize: 40, | ||||
|                             interval: 1, | ||||
|                             getTitlesWidget: (value, _) => Align( | ||||
|                               alignment: Alignment.centerRight, | ||||
|                               child: Text( | ||||
|                                 signSymbols[value.toInt()], | ||||
|                                 textAlign: TextAlign.right, | ||||
|                               ).paddingOnly(right: 8), | ||||
|                             ), | ||||
|                         )), | ||||
|                         titlesData: FlTitlesData( | ||||
|                           topTitles: const AxisTitles( | ||||
|                             sideTitles: SideTitles(showTitles: false), | ||||
|                           ), | ||||
|                         ), | ||||
|                         bottomTitles: AxisTitles( | ||||
|                           sideTitles: SideTitles( | ||||
|                             showTitles: true, | ||||
|                             reservedSize: 28, | ||||
|                             interval: 86400000, | ||||
|                             getTitlesWidget: (value, _) => Text( | ||||
|                               DateFormat('dd').format( | ||||
|                                 DateTime.fromMillisecondsSinceEpoch( | ||||
|                                   value.toInt(), | ||||
|                                 ), | ||||
|                           rightTitles: const AxisTitles( | ||||
|                             sideTitles: SideTitles(showTitles: false), | ||||
|                           ), | ||||
|                           leftTitles: AxisTitles( | ||||
|                             sideTitles: SideTitles( | ||||
|                               showTitles: true, | ||||
|                               reservedSize: 40, | ||||
|                               getTitlesWidget: (value, _) => Align( | ||||
|                                 alignment: Alignment.centerRight, | ||||
|                                 child: Text( | ||||
|                                   value.toStringAsFixed(0), | ||||
|                                   textAlign: TextAlign.right, | ||||
|                                 ).paddingOnly(right: 8), | ||||
|                               ), | ||||
|                               textAlign: TextAlign.center, | ||||
|                             ).paddingOnly(top: 8), | ||||
|                           ), | ||||
|                         ), | ||||
|                       ), | ||||
|                       gridData: const FlGridData(show: false), | ||||
|                       borderData: FlBorderData(show: false), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ).marginOnly(right: 24, bottom: 8, top: 8), | ||||
|                 const Gap(16), | ||||
|                 Text( | ||||
|                   'dailySignHistoryReward'.tr, | ||||
|                   style: Theme.of(context).textTheme.titleMedium, | ||||
|                 ).paddingOnly(bottom: 18), | ||||
|                 SizedBox( | ||||
|                   height: 180, | ||||
|                   width: max(640, MediaQuery.of(context).size.width), | ||||
|                   child: LineChart( | ||||
|                     LineChartData( | ||||
|                       lineBarsData: [ | ||||
|                         LineChartBarData( | ||||
|                           isCurved: true, | ||||
|                           isStrokeCapRound: true, | ||||
|                           isStrokeJoinRound: true, | ||||
|                           color: Theme.of(context).colorScheme.primary, | ||||
|                           belowBarData: BarAreaData( | ||||
|                             show: true, | ||||
|                             gradient: LinearGradient( | ||||
|                               colors: List.filled( | ||||
|                                 data!.length, | ||||
|                                 Theme.of(context) | ||||
|                                     .colorScheme | ||||
|                                     .primary | ||||
|                                     .withOpacity(0.3), | ||||
|                               ).toList(), | ||||
|                             ), | ||||
|                           ), | ||||
|                           spots: data! | ||||
|                               .map( | ||||
|                                 (x) => FlSpot( | ||||
|                                   x.createdAt | ||||
|                                       .copyWith( | ||||
|                                         hour: 0, | ||||
|                                         minute: 0, | ||||
|                                         second: 0, | ||||
|                                         millisecond: 0, | ||||
|                                         microsecond: 0, | ||||
|                                       ) | ||||
|                                       .millisecondsSinceEpoch | ||||
|                                       .toDouble(), | ||||
|                                   x.resultExperience.toDouble(), | ||||
|                                 ), | ||||
|                               ) | ||||
|                               .toList(), | ||||
|                         ) | ||||
|                       ], | ||||
|                       lineTouchData: LineTouchData( | ||||
|                           touchTooltipData: LineTouchTooltipData( | ||||
|                         getTooltipItems: (spots) => spots | ||||
|                             .map((spot) => LineTooltipItem( | ||||
|                                   '+${spot.y.toStringAsFixed(0)} EXP\n${DateFormat('MM/dd').format(DateTime.fromMillisecondsSinceEpoch(spot.x.toInt()))}', | ||||
|                                   TextStyle( | ||||
|                                     color: | ||||
|                                         Theme.of(context).colorScheme.onSurface, | ||||
|                           bottomTitles: AxisTitles( | ||||
|                             sideTitles: SideTitles( | ||||
|                               showTitles: true, | ||||
|                               reservedSize: 28, | ||||
|                               interval: 86400000, | ||||
|                               getTitlesWidget: (value, _) => Text( | ||||
|                                 DateFormat('dd').format( | ||||
|                                   DateTime.fromMillisecondsSinceEpoch( | ||||
|                                     value.toInt(), | ||||
|                                   ), | ||||
|                                 )) | ||||
|                             .toList(), | ||||
|                         getTooltipColor: (_) => | ||||
|                             Theme.of(context).colorScheme.surfaceContainerHigh, | ||||
|                       )), | ||||
|                       titlesData: FlTitlesData( | ||||
|                         topTitles: const AxisTitles( | ||||
|                           sideTitles: SideTitles(showTitles: false), | ||||
|                         ), | ||||
|                         rightTitles: const AxisTitles( | ||||
|                           sideTitles: SideTitles(showTitles: false), | ||||
|                         ), | ||||
|                         leftTitles: AxisTitles( | ||||
|                           sideTitles: SideTitles( | ||||
|                             showTitles: true, | ||||
|                             reservedSize: 40, | ||||
|                             getTitlesWidget: (value, _) => Align( | ||||
|                               alignment: Alignment.centerRight, | ||||
|                               child: Text( | ||||
|                                 value.toStringAsFixed(0), | ||||
|                                 textAlign: TextAlign.right, | ||||
|                               ).paddingOnly(right: 8), | ||||
|                                 ), | ||||
|                                 textAlign: TextAlign.center, | ||||
|                               ).paddingOnly(top: 8), | ||||
|                             ), | ||||
|                           ), | ||||
|                         ), | ||||
|                         bottomTitles: AxisTitles( | ||||
|                           sideTitles: SideTitles( | ||||
|                             showTitles: true, | ||||
|                             reservedSize: 28, | ||||
|                             interval: 86400000, | ||||
|                             getTitlesWidget: (value, _) => Text( | ||||
|                               DateFormat('dd').format( | ||||
|                                 DateTime.fromMillisecondsSinceEpoch( | ||||
|                                   value.toInt(), | ||||
|                                 ), | ||||
|                               ), | ||||
|                               textAlign: TextAlign.center, | ||||
|                             ).paddingOnly(top: 8), | ||||
|                           ), | ||||
|                         ), | ||||
|                         gridData: const FlGridData(show: false), | ||||
|                         borderData: FlBorderData(show: false), | ||||
|                       ), | ||||
|                       gridData: const FlGridData(show: false), | ||||
|                       borderData: FlBorderData(show: false), | ||||
|                     ), | ||||
|                   ), | ||||
|                 ).marginOnly(right: 24, bottom: 8, top: 8), | ||||
|               ], | ||||
|                   ).marginOnly(right: 24, bottom: 8, top: 8), | ||||
|                 ], | ||||
|               ), | ||||
|             ), | ||||
|     ); | ||||
|   } | ||||
|   | ||||
| @@ -2,7 +2,7 @@ name: solian | ||||
| description: "The Solar Network App" | ||||
| publish_to: "none" | ||||
|  | ||||
| version: 1.2.2+3 | ||||
| version: 1.2.3+1 | ||||
|  | ||||
| environment: | ||||
|   sdk: ">=3.3.4 <4.0.0" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user