diff --git a/lib/api/user_api.dart b/lib/api/user_api.dart index 13fb12cb..cc40b06e 100755 --- a/lib/api/user_api.dart +++ b/lib/api/user_api.dart @@ -77,7 +77,7 @@ class UserAPI { if (uid == null) { return currentUser; } else { - return NetUtils.getWithCookieAndHeaderSet( + return NetUtils.getWithCookieAndHeaderSet( API.userInfo, data: {'uid': uid}, ); diff --git a/lib/constants/constants.dart b/lib/constants/constants.dart index a67c2fdb..23c17ad2 100644 --- a/lib/constants/constants.dart +++ b/lib/constants/constants.dart @@ -10,6 +10,7 @@ import 'package:openjmu/constants/constants.dart'; export 'package:dartx/dartx.dart'; export 'package:dio/dio.dart' show Response; export 'package:ff_annotation_route/ff_annotation_route.dart' show FFRoute, PageRouteType; +export 'package:hive/hive.dart' show Box; export 'package:oktoast/oktoast.dart' hide showToast; export 'package:pedantic/pedantic.dart'; export 'package:url_launcher/url_launcher.dart'; diff --git a/lib/openjmu_route_helper.dart b/lib/openjmu_route_helper.dart index 211e8693..179ccc19 100644 --- a/lib/openjmu_route_helper.dart +++ b/lib/openjmu_route_helper.dart @@ -12,40 +12,42 @@ import 'package:flutter/widgets.dart'; import 'openjmu_route.dart'; class FFNavigatorObserver extends NavigatorObserver { - final RouteChange routeChange; - FFNavigatorObserver({this.routeChange}); + final RouteChange routeChange; + @override - void didPop(Route route, Route previousRoute) { + void didPop(Route route, Route previousRoute) { super.didPop(route, previousRoute); _didRouteChange(previousRoute, route); } @override - void didPush(Route route, Route previousRoute) { + void didPush(Route route, Route previousRoute) { super.didPush(route, previousRoute); _didRouteChange(route, previousRoute); } @override - void didRemove(Route route, Route previousRoute) { + void didRemove(Route route, Route previousRoute) { super.didRemove(route, previousRoute); _didRouteChange(previousRoute, route); } @override - void didReplace({Route newRoute, Route oldRoute}) { + void didReplace({Route newRoute, Route oldRoute}) { super.didReplace(newRoute: newRoute, oldRoute: oldRoute); _didRouteChange(newRoute, oldRoute); } - void _didRouteChange(Route newRoute, Route oldRoute) { + void _didRouteChange(Route newRoute, Route oldRoute) { routeChange?.call(newRoute?.settings, oldRoute?.settings); } - FFRouteSettings getFFRouteSettings(Route route) { - if (route?.settings is FFRouteSettings) return route.settings; + FFRouteSettings getFFRouteSettings(Route route) { + if (route?.settings is FFRouteSettings) { + return route.settings as FFRouteSettings; + } return null; } } @@ -91,9 +93,9 @@ Widget _defaultTransitionsBuilder( } Route onGenerateRouteHelper(RouteSettings settings, {Widget notFoundFallback}) { - final routeResult = getRouteResult( + final RouteResult routeResult = getRouteResult( name: settings.name, - arguments: settings.arguments, + arguments: settings.arguments as Map, ); if (routeResult.showStatusBar != null || routeResult.routeName != null) { settings = FFRouteSettings( @@ -104,37 +106,38 @@ Route onGenerateRouteHelper(RouteSettings settings, {Widget notFoundFal showStatusBar: routeResult.showStatusBar, ); } - final page = routeResult.widget ?? + final Widget page = routeResult.widget ?? notFoundFallback ?? - Center(child: Text("${settings.name}\npage not found.")); + Center(child: Text('${settings.name}\npage not found.')); if (settings?.arguments is Map) { - RouteBuilder builder = (settings.arguments as Map)['routeBuilder']; - if (builder != null) return builder(page); + final RouteBuilder builder = + (settings.arguments as Map)['routeBuilder'] as RouteBuilder; + if (builder != null) { + return builder(page); + } } switch (routeResult.pageRouteType) { case PageRouteType.material: - return MaterialPageRoute(settings: settings, builder: (_) => page); + return MaterialPageRoute(settings: settings, builder: (_) => page); case PageRouteType.cupertino: - return CupertinoPageRoute(settings: settings, builder: (_) => page); + return CupertinoPageRoute(settings: settings, builder: (_) => page); case PageRouteType.transparent: - return FFTransparentPageRoute( + return FFTransparentPageRoute( settings: settings, pageBuilder: (_, __, ___) => page, ); default: return Platform.isIOS - ? CupertinoPageRoute(settings: settings, builder: (_) => page) - : MaterialPageRoute(settings: settings, builder: (_) => page); + ? CupertinoPageRoute(settings: settings, builder: (_) => page) + : MaterialPageRoute(settings: settings, builder: (_) => page); } } -typedef RouteBuilder = PageRoute Function(Widget page); +typedef RouteBuilder = PageRoute Function(Widget page); class FFRouteSettings extends RouteSettings { - final String routeName; - final bool showStatusBar; const FFRouteSettings({ this.routeName, this.showStatusBar, @@ -142,4 +145,7 @@ class FFRouteSettings extends RouteSettings { bool isInitialRoute = false, Object arguments, }) : super(name: name, isInitialRoute: isInitialRoute, arguments: arguments); + + final String routeName; + final bool showStatusBar; } diff --git a/lib/pages/login_page.dart b/lib/pages/login_page.dart index dd1468a1..31e7fdb8 100755 --- a/lib/pages/login_page.dart +++ b/lib/pages/login_page.dart @@ -443,28 +443,33 @@ class LoginPageState extends State with SingleTickerProviderStateMixi ); void loginButtonPressed(context) { - if (_formKey.currentState.validate()) { - _formKey.currentState.save(); - setState(() { - _login = true; - }); - DataUtils.login(_username, _password).then((result) { - if (result) { - navigatorState.pushNamedAndRemoveUntil( - Routes.OPENJMU_HOME, - (_) => false, - arguments: {'initAction': null}, - ); - } else { + try { + if (_formKey.currentState.validate()) { + _formKey.currentState.save(); + setState(() { + _login = true; + }); + DataUtils.login(_username, _password).then((result) { + if (result) { + navigatorState.pushNamedAndRemoveUntil( + Routes.OPENJMU_HOME, + (_) => false, + arguments: {'initAction': null}, + ); + } else { + _login = false; + if (mounted) setState(() {}); + } + }).catchError((e) { + debugPrint('Failed when login: $e'); + showCenterErrorToast('登录失败'); _login = false; if (mounted) setState(() {}); - } - }).catchError((e) { - debugPrint('Failed when login: $e'); - showToast('登录失败'); - _login = false; - if (mounted) setState(() {}); - }); + }); + } + } catch (e) { + debugPrint('Failed when login: $e'); + showCenterErrorToast('登录失败'); } } diff --git a/lib/pages/user/user_page.dart b/lib/pages/user/user_page.dart index 475b5a6e..21a12954 100755 --- a/lib/pages/user/user_page.dart +++ b/lib/pages/user/user_page.dart @@ -469,7 +469,10 @@ class _UserPageState extends State 'pics': [ ImageBean( id: widget.uid, - imageUrl: '${API.userAvatar}?uid=${widget.uid}&size=f640', + imageUrl: '${API.userAvatar}?' + 'uid=${widget.uid}' + '&size=f640' + '&_t=${UserAPI.avatarLastModified}', ), ], 'heroPrefix': 'user-page-avatar-', diff --git a/lib/providers/settings_provider.dart b/lib/providers/settings_provider.dart index a12c6d98..e8dcb509 100644 --- a/lib/providers/settings_provider.dart +++ b/lib/providers/settings_provider.dart @@ -10,7 +10,7 @@ import 'package:openjmu/constants/constants.dart'; class SettingsProvider extends ChangeNotifier { /// For test page. - /// TODO: Set this to false before release. + /// Set this to [false] before release. bool _debug = !kReleaseMode && false; bool get debug => _debug; set debug(bool value) { @@ -26,10 +26,10 @@ class SettingsProvider extends ChangeNotifier { notifyListeners(); } - List _homeStartUpIndex = [0, 0, 0]; + List _homeStartUpIndex = [0, 0, 0]; List get homeStartUpIndex => _homeStartUpIndex; set homeStartUpIndex(List value) { - _homeStartUpIndex = List.from(value); + _homeStartUpIndex = List.from(value); notifyListeners(); } @@ -72,12 +72,14 @@ class SettingsProvider extends ChangeNotifier { bool get launchFromSystemBrowser => _launchFromSystemBrowser; set launchFromSystemBrowser(bool value) { assert(value != null); - if (_launchFromSystemBrowser == value) return; + if (_launchFromSystemBrowser == value) { + return; + } _launchFromSystemBrowser = value; notifyListeners(); } - final fontScaleRange = [0.6, 1.4]; + final List fontScaleRange = [0.6, 1.4]; double _fontScale = 1.0; double get fontScale => _fontScale; set fontScale(double value) { @@ -99,7 +101,7 @@ class SettingsProvider extends ChangeNotifier { void reset() { _fontScale = 1.0; _homeSplashIndex = 0; - _homeStartUpIndex = [0, 0, 0]; + _homeStartUpIndex = [0, 0, 0]; _newAppCenterIcon = false; _hideShieldPost = true; _launchFromSystemBrowser = false; diff --git a/lib/utils/hive_field_utils.dart b/lib/utils/hive_field_utils.dart index c93cf58e..c5f3985a 100644 --- a/lib/utils/hive_field_utils.dart +++ b/lib/utils/hive_field_utils.dart @@ -12,116 +12,116 @@ class HiveFieldUtils { listen: false, ); - static final _box = HiveBoxes.settingsBox; + static final Box _box = HiveBoxes.settingsBox; - static final String brightnessDark = 'theme_brightness'; - static final String amoledDark = 'theme_AMOLEDDark'; - static final String colorThemeIndex = 'theme_colorThemeIndex'; - static final String brightnessPlatform = 'theme_brightness_platform'; - static final String settingHomeSplashIndex = 'setting_home_splash_index'; - static final String settingHomeStartUpIndex = 'setting_home_startup_index'; + static const String brightnessDark = 'theme_brightness'; + static const String amoledDark = 'theme_AMOLEDDark'; + static const String colorThemeIndex = 'theme_colorThemeIndex'; + static const String brightnessPlatform = 'theme_brightness_platform'; + static const String settingHomeSplashIndex = 'setting_home_splash_index'; + static const String settingHomeStartUpIndex = 'setting_home_startup_index'; - static final String settingFontScale = 'setting_font_scale'; - static final String settingNewIcons = 'setting_new_icons'; - static final String settingHideShieldPost = 'setting_hide_shield_post'; - static final String settingLaunchFromSystemBrowser = 'setting_launch_from_system_browser'; + static const String settingFontScale = 'setting_font_scale'; + static const String settingNewIcons = 'setting_new_icons'; + static const String settingHideShieldPost = 'setting_hide_shield_post'; + static const String settingLaunchFromSystemBrowser = 'setting_launch_from_system_browser'; - static final String deviceUuid = 'device_uuid'; - static final String devicePushToken = 'device_push_token'; + static const String deviceUuid = 'device_uuid'; + static const String devicePushToken = 'device_push_token'; /// 获取设置的主题色 - static int getColorThemeIndex() => _box?.get(colorThemeIndex) ?? 0; + static int getColorThemeIndex() => _box?.get(colorThemeIndex) as int ?? 0; /// 获取设置的夜间模式 - static bool getBrightnessDark() => _box?.get(brightnessDark) ?? false; + static bool getBrightnessDark() => _box?.get(brightnessDark) as bool ?? false; /// 获取设置的AMOLED夜间模式 - static bool getAMOLEDDark() => _box?.get(amoledDark) ?? false; + static bool getAMOLEDDark() => _box?.get(amoledDark) as bool ?? false; /// 获取设置的跟随系统夜间模式 - static bool getBrightnessPlatform() => _box?.get(brightnessPlatform) ?? true; + static bool getBrightnessPlatform() => _box?.get(brightnessPlatform) as bool ?? true; /// 设置选择的主题色 - static Future setColorTheme(int value) async => await _box?.put(colorThemeIndex, value); + static Future setColorTheme(int value) async => await _box?.put(colorThemeIndex, value); /// 设置选择的夜间模式 - static Future setBrightnessDark(bool value) async => await _box?.put(brightnessDark, value); + static Future setBrightnessDark(bool value) async => await _box?.put(brightnessDark, value); /// 设置AMOLED夜间模式 - static Future setAMOLEDDark(bool value) async => await _box?.put(amoledDark, value); + static Future setAMOLEDDark(bool value) async => await _box?.put(amoledDark, value); /// 设置跟随系统的夜间模式 - static Future setBrightnessPlatform(bool value) async => + static Future setBrightnessPlatform(bool value) async => await _box?.put(brightnessPlatform, value); /// 获取默认启动页index - static int getHomeSplashIndex() => _box?.get(settingHomeSplashIndex); + static int getHomeSplashIndex() => _box?.get(settingHomeSplashIndex) as int; /// 获取默认各页启动index - static List getHomeStartUpIndex() => _box?.get(settingHomeStartUpIndex)?.cast(); + static List getHomeStartUpIndex() => _box?.get(settingHomeStartUpIndex) as List; /// 获取字体缩放设置 - static double getFontScale() => _box?.get(settingFontScale); + static double getFontScale() => _box?.get(settingFontScale) as double; /// 获取新图标是否开启 - static bool getEnabledNewAppsIcon() => _box?.get(settingNewIcons); + static bool getEnabledNewAppsIcon() => _box?.get(settingNewIcons) as bool; /// 获取是否隐藏被屏蔽的动态 - static bool getEnabledHideShieldPost() => _box?.get(settingHideShieldPost); + static bool getEnabledHideShieldPost() => _box?.get(settingHideShieldPost) as bool; /// 获取是否通过系统浏览器打开网页 - static bool getLaunchFromSystemBrowser() => _box?.get(settingLaunchFromSystemBrowser); + static bool getLaunchFromSystemBrowser() => _box?.get(settingLaunchFromSystemBrowser) as bool; /// 设置首页的初始页 - static Future setHomeSplashIndex(int index) async { + static Future setHomeSplashIndex(int index) async { provider.homeSplashIndex = index; await _box?.put(settingHomeSplashIndex, index); } /// 设置首页各子页的初始页 - static Future setHomeStartUpIndex(List indexList) async { + static Future setHomeStartUpIndex(List indexList) async { provider.homeStartUpIndex = indexList; await _box?.put(settingHomeStartUpIndex, indexList); } /// 设置字体缩放 - static Future setFontScale(double scale) async { + static Future setFontScale(double scale) async { provider.fontScale = scale; await _box?.put(settingFontScale, scale); } /// 设置是否启用新应用图标 - static Future setEnabledNewAppsIcon(bool enable) async { + static Future setEnabledNewAppsIcon(bool enable) async { provider.newAppCenterIcon = enable; await _box?.put(settingNewIcons, enable); } /// 设置是否隐藏被屏蔽的动态 - static Future setEnabledHideShieldPost(bool enable) async { + static Future setEnabledHideShieldPost(bool enable) async { provider.hideShieldPost = enable; await _box?.put(settingHideShieldPost, enable); } /// 设置是否通过系统浏览器打开网页 - static Future setLaunchFromSystemBrowser(bool enable) async { + static Future setLaunchFromSystemBrowser(bool enable) async { provider.launchFromSystemBrowser = enable; await _box?.put(settingLaunchFromSystemBrowser, enable); } /// 获取设备PushToken - static String getDevicePushToken() => _box?.get(devicePushToken); + static String getDevicePushToken() => _box?.get(devicePushToken) as String; /// 获取设备Uuid - static String getDeviceUuid() => _box?.get(deviceUuid); + static String getDeviceUuid() => _box?.get(deviceUuid) as String; /// 写入PushToken - static Future setDevicePushToken(String value) async { + static Future setDevicePushToken(String value) async { DeviceUtils.devicePushToken = value; await _box?.put(devicePushToken, value); } /// 写入uuid - static Future setDeviceUuid(String value) async { + static Future setDeviceUuid(String value) async { DeviceUtils.deviceUuid = value; await _box?.put(deviceUuid, value); } diff --git a/lib/utils/net_utils.dart b/lib/utils/net_utils.dart index 9230a51b..8bb02f20 100755 --- a/lib/utils/net_utils.dart +++ b/lib/utils/net_utils.dart @@ -112,9 +112,9 @@ class NetUtils { static Future> getWithCookieAndHeaderSet( String url, { - data, - cookies, - headers, + Map data, + List cookies, + Map headers, }) async => await dio.get( url, diff --git a/lib/widgets/dialogs/confirmation_dialog.dart b/lib/widgets/dialogs/confirmation_dialog.dart index 799a79cf..6a5ff5be 100644 --- a/lib/widgets/dialogs/confirmation_dialog.dart +++ b/lib/widgets/dialogs/confirmation_dialog.dart @@ -10,19 +10,6 @@ import 'package:extended_text/extended_text.dart'; import 'package:extended_text_library/extended_text_library.dart'; class ConfirmationDialog extends StatelessWidget { - final String title; - final bool centerTitle; - final Widget child; - final String content; - final EdgeInsetsGeometry contentPadding; - final TextAlign contentAlignment; - final Color backgroundColor; - final bool showConfirm; - final String confirmLabel; - final String cancelLabel; - final VoidCallback onConfirm; - final VoidCallback onCancel; - const ConfirmationDialog({ Key key, this.title, @@ -43,8 +30,21 @@ class ConfirmationDialog extends StatelessWidget { ), super(key: key); + final String title; + final bool centerTitle; + final Widget child; + final String content; + final EdgeInsetsGeometry contentPadding; + final TextAlign contentAlignment; + final Color backgroundColor; + final bool showConfirm; + final String confirmLabel; + final String cancelLabel; + final VoidCallback onConfirm; + final VoidCallback onCancel; + static Future show( - context, { + BuildContext context, { String title, bool centerTitle = true, Widget child, @@ -72,7 +72,7 @@ class ConfirmationDialog extends StatelessWidget { false; } - Widget titleWidget(context) => Row( + Widget titleWidget(BuildContext context) => Row( mainAxisAlignment: centerTitle ? MainAxisAlignment.center : MainAxisAlignment.start, children: [ Text( @@ -84,7 +84,7 @@ class ConfirmationDialog extends StatelessWidget { ], ); - Widget confirmButton(context) { + Widget confirmButton(BuildContext context) { return Expanded( flex: 5, child: MaterialButton( @@ -111,7 +111,7 @@ class ConfirmationDialog extends StatelessWidget { ); } - Widget cancelButton(context) { + Widget cancelButton(BuildContext context) { return Expanded( flex: 5, child: MaterialButton( @@ -167,25 +167,25 @@ class ConfirmationDialog extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ if (title != null) titleWidget(context), - child != null - ? child - : Padding( - padding: - contentPadding ?? EdgeInsets.symmetric(vertical: suSetHeight(20.0)), - child: ExtendedText( - '$content', - style: TextStyle(fontSize: suSetSp(20.0), fontWeight: FontWeight.normal), - textAlign: contentAlignment, - specialTextSpanBuilder: RegExpSpecialTextSpanBuilder(), - onSpecialTextTap: (data) { - API.launchWeb(url: data['content'], title: '网页链接'); - }, - ), - ), + if (child != null) + child + else + Padding( + padding: contentPadding ?? EdgeInsets.symmetric(vertical: suSetHeight(20.0)), + child: ExtendedText( + '$content', + style: TextStyle(fontSize: suSetSp(20.0), fontWeight: FontWeight.normal), + textAlign: contentAlignment, + specialTextSpanBuilder: RegExpSpecialTextSpanBuilder(), + onSpecialTextTap: (dynamic data) { + API.launchWeb(url: data['content'] as String, title: '网页链接'); + }, + ), + ), Row( children: [ if (showConfirm) confirmButton(context), - if (showConfirm) Spacer(flex: 1), + if (showConfirm) const Spacer(flex: 1), cancelButton(context), ], ), @@ -212,7 +212,7 @@ class LinkText extends SpecialText { style: textStyle?.copyWith(decoration: TextDecoration.underline), recognizer: TapGestureRecognizer() ..onTap = () { - final data = {'content': toString()}; + final Map data = {'content': toString()}; if (onTap != null) onTap(data); }, ); diff --git a/lib/widgets/dialogs/edit_signature_dialog.dart b/lib/widgets/dialogs/edit_signature_dialog.dart index fcfcb30b..66651dcd 100755 --- a/lib/widgets/dialogs/edit_signature_dialog.dart +++ b/lib/widgets/dialogs/edit_signature_dialog.dart @@ -35,20 +35,20 @@ class EditSignatureDialogState extends State { }); } - void updateSignature(context) { + void updateSignature(BuildContext context) { Navigator.of(context).pop(); - final _loadingDialogController = LoadingDialogController(); + final LoadingDialogController _loadingDialogController = LoadingDialogController(); LoadingDialog.show( context, text: '正在更新签名', controller: _loadingDialogController, isGlobal: false, ); - UserAPI.setSignature(_textEditingController.text).then((response) { + UserAPI.setSignature(_textEditingController.text).then((dynamic _) { _loadingDialogController.changeState('success', '签名更新成功'); UserAPI.currentUser.signature = _textEditingController.text; Instances.eventBus.fire(SignatureUpdatedEvent(_textEditingController.text)); - }).catchError((e) { + }).catchError((dynamic e) { debugPrint(e.toString()); _loadingDialogController.changeState('failed', '签名更新失败'); }); @@ -102,9 +102,7 @@ class EditSignatureDialogState extends State { borderSide: BorderSide(color: Colors.grey[850]), ), hintText: UserAPI.currentUser.signature ?? '快来填写你的签名吧~', - hintStyle: TextStyle( - textBaseline: TextBaseline.alphabetic, - ), + hintStyle: const TextStyle(textBaseline: TextBaseline.alphabetic), ), cursorColor: currentThemeColor, ), diff --git a/lib/widgets/dialogs/forward_positioned.dart b/lib/widgets/dialogs/forward_positioned.dart index 3e360763..06731d1e 100755 --- a/lib/widgets/dialogs/forward_positioned.dart +++ b/lib/widgets/dialogs/forward_positioned.dart @@ -1,6 +1,6 @@ +import 'dart:async'; import 'dart:io'; import 'dart:math'; -import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; @@ -21,20 +21,20 @@ import 'package:openjmu/widgets/dialogs/mention_people_dialog.dart'; pageRouteType: PageRouteType.transparent, ) class ForwardPositioned extends StatefulWidget { - final Post post; - const ForwardPositioned({ Key key, @required this.post, }) : super(key: key); + final Post post; + @override State createState() => ForwardPositionedState(); } class ForwardPositionedState extends State { - final _forwardController = TextEditingController(); - final _focusNode = FocusNode(); + final TextEditingController _forwardController = TextEditingController(); + final FocusNode _focusNode = FocusNode(); File _image; int _imageID; @@ -59,15 +59,13 @@ class ForwardPositionedState extends State { // if (mounted) setState(() {}); // } - FormData createForm(File file) => FormData.from({ + FormData createForm(File file) => FormData.from({ 'image': UploadFileInfo(file, path.basename(file.path)), 'image_type': 0, }); - Future getImageRequest(FormData formData) async => NetUtils.postWithCookieAndHeaderSet( - API.postUploadImage, - data: formData, - ); + Future> getImageRequest(FormData formData) async => + NetUtils.postWithCookieAndHeaderSet(API.postUploadImage, data: formData); Widget get textField => ExtendedTextField( specialTextSpanBuilder: StackSpecialTextFieldSpanBuilder(), @@ -76,23 +74,16 @@ class ForwardPositionedState extends State { decoration: InputDecoration( contentPadding: EdgeInsets.all(suSetWidth(16.0)), border: OutlineInputBorder( - borderSide: BorderSide( - color: currentThemeColor, - ), + borderSide: BorderSide(color: currentThemeColor), ), focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color: currentThemeColor, - ), + borderSide: BorderSide(color: currentThemeColor), ), suffixIcon: _image != null ? Container( margin: EdgeInsets.only(right: suSetWidth(16.0)), width: suSetWidth(70.0), - child: Image.file( - _image, - fit: BoxFit.cover, - ), + child: Image.file(_image, fit: BoxFit.cover), ) : null, ), @@ -106,7 +97,7 @@ class ForwardPositionedState extends State { maxLines: 3, ); - Future _request(context) async { + Future _request(BuildContext context) async { setState(() { _forwarding = true; }); @@ -115,8 +106,9 @@ class ForwardPositionedState extends State { /// Sending image if it exist. if (_image != null) { - final Map data = (await getImageRequest(createForm(_image))).data; - _imageID = int.parse(data['image_id']); + final Map data = + (await getImageRequest(createForm(_image))).data as Map; + _imageID = int.parse(data['image_id'] as String); content += ' |$_imageID| '; } @@ -137,22 +129,26 @@ class ForwardPositionedState extends State { } else { showToast('转发失败'); } - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } } void updatePadStatus(bool active) { - final change = () { + final VoidCallback change = () { emoticonPadActive = active; - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } }; if (emoticonPadActive) { change(); } else { if (MediaQuery.of(context).viewInsets.bottom != 0.0) { - SystemChannels.textInput.invokeMethod('TextInput.hide').whenComplete( + SystemChannels.textInput.invokeMethod('TextInput.hide').whenComplete( () { - Future.delayed(300.milliseconds, null).whenComplete(change); + Future.delayed(300.milliseconds, null).whenComplete(change); }, ); } else { @@ -162,9 +158,9 @@ class ForwardPositionedState extends State { } void insertText(String text) { - final value = _forwardController.value; - final start = value.selection.baseOffset; - final end = value.selection.extentOffset; + final TextEditingValue value = _forwardController.value; + final int start = value.selection.baseOffset; + final int end = value.selection.extentOffset; if (value.selection.isValid) { String newText = ''; if (value.selection.isCollapsed) { @@ -185,7 +181,9 @@ class ForwardPositionedState extends State { extentOffset: end + text.length, ), ); - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } } @@ -196,14 +194,16 @@ class ForwardPositionedState extends State { controller: _forwardController, ); - void mentionPeople(context) { + void mentionPeople(BuildContext context) { showDialog( context: context, builder: (BuildContext context) => MentionPeopleDialog(), - ).then((user) { - if (_focusNode.canRequestFocus) _focusNode.requestFocus(); + ).then((dynamic user) { + if (_focusNode.canRequestFocus) { + _focusNode.requestFocus(); + } if (user != null) { - Future.delayed(250.milliseconds, () { + Future.delayed(250.milliseconds, () { insertText('@${user.nickname}<\/M>'); }); } @@ -217,9 +217,9 @@ class ForwardPositionedState extends State { RoundedCheckbox( activeColor: currentThemeColor, value: commentAtTheMeanTime, - onChanged: (value) { + onChanged: (dynamic value) { setState(() { - commentAtTheMeanTime = value; + commentAtTheMeanTime = value as bool; }); }, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, @@ -230,7 +230,7 @@ class ForwardPositionedState extends State { fontSize: suSetSp(20.0), ), ), - Spacer(), + const Spacer(), // GestureDetector( // behavior: HitTestBehavior.opaque, // onTap: _addImage, @@ -277,38 +277,39 @@ class ForwardPositionedState extends State { ), ), ), - !_forwarding - ? GestureDetector( - behavior: HitTestBehavior.opaque, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: suSetWidth(6.0), - ), - child: Icon( - Icons.send, - size: suSetWidth(32.0), - color: currentThemeColor, - ), - ), - onTap: () => _request(context), - ) - : Padding( - padding: EdgeInsets.symmetric( - horizontal: suSetWidth(14.0), - ), - child: SizedBox( - width: suSetWidth(12.0), - height: suSetWidth(12.0), - child: PlatformProgressIndicator(strokeWidth: 2.0), - ), + if (!_forwarding) + GestureDetector( + behavior: HitTestBehavior.opaque, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: suSetWidth(6.0), + ), + child: Icon( + Icons.send, + size: suSetWidth(32.0), + color: currentThemeColor, ), + ), + onTap: () => _request(context), + ) + else + Padding( + padding: EdgeInsets.symmetric( + horizontal: suSetWidth(14.0), + ), + child: SizedBox( + width: suSetWidth(12.0), + height: suSetWidth(12.0), + child: const PlatformProgressIndicator(strokeWidth: 2.0), + ), + ), ], ), ); @override Widget build(BuildContext context) { - final keyboardHeight = MediaQuery.of(context).viewInsets.bottom; + final double keyboardHeight = MediaQuery.of(context).viewInsets.bottom; if (keyboardHeight > 0) { emoticonPadActive = false; } diff --git a/lib/widgets/dialogs/loading_dialog.dart b/lib/widgets/dialogs/loading_dialog.dart index dc3c10d9..086dee85 100755 --- a/lib/widgets/dialogs/loading_dialog.dart +++ b/lib/widgets/dialogs/loading_dialog.dart @@ -5,10 +5,6 @@ import 'package:flutter/material.dart'; import 'package:openjmu/constants/constants.dart'; class LoadingDialog extends StatefulWidget { - final LoadingDialogController controller; - final String text; - final bool isGlobal; - const LoadingDialog({ Key key, this.text, @@ -16,16 +12,20 @@ class LoadingDialog extends StatefulWidget { this.isGlobal = false, }) : super(key: key); + final LoadingDialogController controller; + final String text; + final bool isGlobal; + @override State createState() => LoadingDialogState(); static void show( - context, { + BuildContext context, { LoadingDialogController controller, String text, bool isGlobal, }) { - showDialog( + showDialog( context: context, builder: (_) => LoadingDialog( controller: controller, @@ -40,14 +40,16 @@ class LoadingDialogState extends State { Duration duration = 1500.milliseconds; String type, text; VoidCallback customPop; - Widget icon = SpinKitWidget(); + Widget icon = const SpinKitWidget(); @override void initState() { super.initState(); widget.controller?.dialogState = this; - this.text = widget.text; - if (mounted) setState(() {}); + text = widget.text; + if (mounted) { + setState(() {}); + } } @override @@ -57,7 +59,7 @@ class LoadingDialogState extends State { } @override - void didUpdateWidget(oldWidget) { + void didUpdateWidget(LoadingDialog oldWidget) { super.didUpdateWidget(oldWidget); widget.controller?.dialogState = this; } @@ -72,26 +74,36 @@ class LoadingDialogState extends State { this.type = type; this.icon = icon; this.text = text; - if (duration != null) this.duration = duration; - if (customPop != null) this.customPop = customPop; - if (mounted) setState(() {}); + if (duration != null) { + duration = duration; + } + if (customPop != null) { + customPop = customPop; + } + if (mounted) { + setState(() {}); + } } void updateIcon(Widget icon) { this.icon = icon; - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } void updateText(String text) { this.text = text; - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } @override Widget build(BuildContext context) { if (!(widget.isGlobal ?? false)) { - if (this.type != null && this.type != 'loading') { - Future.delayed(duration, () { + if (type != null && type != 'loading') { + Future.delayed(duration, () { try { if (customPop != null) { customPop(); @@ -102,7 +114,7 @@ class LoadingDialogState extends State { debugPrint('Error when running pop in loading dialog: $e'); } }); - } else if (this.type == 'dismiss') { + } else if (type == 'dismiss') { try { if (customPop != null) { customPop(); @@ -158,15 +170,15 @@ class LoadingDialogState extends State { class LoadingDialogController { LoadingDialogState dialogState; - void updateText(text) { + void updateText(String text) { dialogState.updateText(text); } - void updateIcon(icon) { + void updateIcon(Widget icon) { dialogState.updateIcon(icon); } - void updateContent(type, icon, text, duration) { + void updateContent(String type, Widget icon, String text, Duration duration) { dialogState.updateContent(type: type, icon: icon, text: text, duration: duration); } @@ -190,7 +202,7 @@ class LoadingDialogController { dialogState.updateContent( type: 'failed', icon: RotationTransition( - turns: AlwaysStoppedAnimation(45 / 360), + turns: const AlwaysStoppedAnimation(45 / 360), child: Icon(Icons.add_circle, color: Colors.redAccent, size: suSetWidth(60.0)), ), text: text, @@ -200,7 +212,7 @@ class LoadingDialogController { case 'loading': dialogState.updateContent( type: 'loading', - icon: CircularProgressIndicator(), + icon: const CircularProgressIndicator(), text: text, duration: duration, ); @@ -208,7 +220,7 @@ class LoadingDialogController { case 'dismiss': dialogState.updateContent( type: 'dismiss', - icon: CircularProgressIndicator(), + icon: const CircularProgressIndicator(), text: text, duration: duration, ); diff --git a/lib/widgets/dialogs/manually_set_sid_dialog.dart b/lib/widgets/dialogs/manually_set_sid_dialog.dart index 27bb8ae8..d9becc76 100644 --- a/lib/widgets/dialogs/manually_set_sid_dialog.dart +++ b/lib/widgets/dialogs/manually_set_sid_dialog.dart @@ -30,11 +30,11 @@ class _ManuallySetSidDialogState extends State { }); } - void updateSid(context) { + void updateSid(BuildContext context) { UserAPI.currentUser.sid = sid; UserAPI.currentUser.ticket = sid; Navigator.of(context).pop(); - debugPrint("${UserAPI.currentUser}"); + debugPrint('${UserAPI.currentUser}'); } @override @@ -57,7 +57,7 @@ class _ManuallySetSidDialogState extends State { children: [ Center( child: Text( - "Set SID Manually (DEBUG)", + 'Set SID Manually (DEBUG)', style: Theme.of(context).textTheme.title, ), ), @@ -81,9 +81,7 @@ class _ManuallySetSidDialogState extends State { borderSide: BorderSide(color: Colors.grey[850]), ), hintText: currentUser.signature, - hintStyle: TextStyle( - textBaseline: TextBaseline.alphabetic, - ), + hintStyle: const TextStyle(textBaseline: TextBaseline.alphabetic), ), cursorColor: currentThemeColor, ), @@ -96,7 +94,7 @@ class _ManuallySetSidDialogState extends State { child: CupertinoDialogAction( isDefaultAction: true, child: Text( - "取消", + '取消', style: TextStyle(fontSize: suSetSp(18.0)), ), onPressed: () => Navigator.of(context).pop(), @@ -105,7 +103,7 @@ class _ManuallySetSidDialogState extends State { Expanded( child: CupertinoDialogAction( child: Text( - "保存", + '保存', style: TextStyle( color: canSave ? currentThemeColor : Theme.of(context).disabledColor, diff --git a/lib/widgets/dialogs/mention_people_dialog.dart b/lib/widgets/dialogs/mention_people_dialog.dart index fbfa1977..b1e12fe1 100755 --- a/lib/widgets/dialogs/mention_people_dialog.dart +++ b/lib/widgets/dialogs/mention_people_dialog.dart @@ -8,9 +8,9 @@ class MentionPeopleDialog extends StatefulWidget { } class EditSignatureDialogState extends State { - final _textEditingController = TextEditingController(); + final TextEditingController _textEditingController = TextEditingController(); String query = ''; - List users = []; + final List users = []; bool loading = false; @@ -18,7 +18,9 @@ class EditSignatureDialogState extends State { void initState() { _textEditingController.addListener(() { query = _textEditingController.text; - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } }); super.initState(); } @@ -31,19 +33,25 @@ class EditSignatureDialogState extends State { void requestSearch() { if (query.isEmpty || loading) { - if (query.isEmpty) showToast('要搜的人难道不配有名字吗?🤔'); + if (query.isEmpty) { + showToast('要搜的人难道不配有名字吗?🤔'); + } } else { loading = true; - if (mounted) setState(() {}); - UserAPI.searchUser(query).then((response) { + if (mounted) { + setState(() {}); + } + UserAPI.searchUser(query).then((dynamic response) { users.clear(); - response['data'].forEach((userData) { - users.add(User.fromJson(userData)); + response['data'].forEach((dynamic userData) { + users.add(User.fromJson(userData as Map)); }); loading = false; - if (mounted) setState(() {}); - }).catchError((e) { - debugPrint(e.toString()); + if (mounted) { + setState(() {}); + } + }).catchError((dynamic e) { + debugPrint('Failed when request search: $e'); loading = false; }); } @@ -51,10 +59,8 @@ class EditSignatureDialogState extends State { Widget get title => Center( child: Text( - "提到用户", - style: Theme.of(context).textTheme.title.copyWith( - fontSize: suSetSp(24.0), - ), + '提到用户', + style: Theme.of(context).textTheme.title.copyWith(fontSize: suSetSp(24.0)), ), ); @@ -66,8 +72,8 @@ class EditSignatureDialogState extends State { decoration: InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.zero, - hintText: "请输入名字进行搜索", - hintStyle: TextStyle(textBaseline: TextBaseline.alphabetic), + hintText: '请输入名字进行搜索', + hintStyle: const TextStyle(textBaseline: TextBaseline.alphabetic), ), textInputAction: TextInputAction.search, style: Theme.of(context).textTheme.body1.copyWith( @@ -77,7 +83,9 @@ class EditSignatureDialogState extends State { scrollPadding: EdgeInsets.zero, maxLines: 1, onChanged: (String value) { - if (value.length + 1 == 30) return null; + if (value.length + 1 == 30) { + return null; + } }, onSubmitted: (_) => requestSearch(), ), @@ -97,7 +105,7 @@ class EditSignatureDialogState extends State { constraints: BoxConstraints(maxHeight: Screens.height / 3), child: SingleChildScrollView( child: Wrap( - children: List.generate(users.length, (index) => user(index)), + children: List.generate(users.length, (int index) => user(index)), ), ), ); @@ -163,12 +171,13 @@ class EditSignatureDialogState extends State { child: Row( children: [ searchField, - !loading - ? searchButton - : SizedBox.fromSize( - size: Size.square(suSetWidth(32.0)), - child: PlatformProgressIndicator(), - ), + if (!loading) + searchButton + else + SizedBox.fromSize( + size: Size.square(suSetWidth(32.0)), + child: const PlatformProgressIndicator(), + ), ], ), ), diff --git a/lib/widgets/image/image_crop_helper.dart b/lib/widgets/image/image_crop_helper.dart index c4d3806a..af5c720c 100644 --- a/lib/widgets/image/image_crop_helper.dart +++ b/lib/widgets/image/image_crop_helper.dart @@ -1,62 +1,66 @@ import 'dart:isolate'; +import 'dart:typed_data'; +import 'package:flutter/material.dart' hide Image; import "package:isolate/load_balancer.dart"; import "package:isolate/isolate_runner.dart"; import 'package:extended_image/extended_image.dart'; import 'package:image/image.dart'; import 'package:image_editor/image_editor.dart'; -final loadBalancer = LoadBalancer.create(1, IsolateRunner.spawn); +final Future loadBalancer = LoadBalancer.create(1, IsolateRunner.spawn); Future isolateDecodeImage(List data) async { - final response = ReceivePort(); + final ReceivePort response = ReceivePort(); await Isolate.spawn(_isolateDecodeImage, response.sendPort); - final sendPort = await response.first; - final answer = ReceivePort(); - sendPort.send([answer.sendPort, data]); + final SendPort sendPort = await response.first as SendPort; + final ReceivePort answer = ReceivePort(); + sendPort.send([answer.sendPort, data]); return answer.first; } void _isolateDecodeImage(SendPort port) { - final rPort = ReceivePort(); + final ReceivePort rPort = ReceivePort(); port.send(rPort.sendPort); - rPort.listen((message) { - final send = message[0] as SendPort; - final data = message[1] as List; + rPort.listen((dynamic message) { + final SendPort send = message[0] as SendPort; + final List data = message[1] as List; send.send(decodeImage(data)); }); } Future isolateEncodeImage(Image src) async { - final response = ReceivePort(); + final ReceivePort response = ReceivePort(); await Isolate.spawn(_isolateEncodeImage, response.sendPort); - final sendPort = await response.first; - final answer = ReceivePort(); - sendPort.send([answer.sendPort, src]); + final SendPort sendPort = await response.first as SendPort; + final ReceivePort answer = ReceivePort(); + sendPort.send([answer.sendPort, src]); return answer.first; } void _isolateEncodeImage(SendPort port) { - final rPort = ReceivePort(); + final ReceivePort rPort = ReceivePort(); port.send(rPort.sendPort); - rPort.listen((message) { - final send = message[0] as SendPort; - final src = message[1] as Image; + rPort.listen((dynamic message) { + final SendPort send = message[0] as SendPort; + final Image src = message[1] as Image; send.send(encodeJpg(src)); }); } Future> cropImage({ExtendedImageEditorState state}) async { - final cropRect = state.getCropRect(); - final action = state.editAction; + final Rect cropRect = state.getCropRect(); + final EditActionDetails action = state.editAction; - final rotateAngle = action.rotateAngle.toInt(); - final flipHorizontal = action.flipY; - final flipVertical = action.flipX; - final img = state.rawImageData; + final int rotateAngle = action.rotateAngle.toInt(); + final bool flipHorizontal = action.flipY; + final bool flipVertical = action.flipX; + final Uint8List img = state.rawImageData; - ImageEditorOption option = ImageEditorOption(); + final ImageEditorOption option = ImageEditorOption(); - if (action.needCrop) option.addOption(ClipOption.fromRect(cropRect)); + if (action.needCrop) { + option.addOption(ClipOption.fromRect(cropRect)); + } if (action.needFlip) { option.addOption(FlipOption(horizontal: flipHorizontal, vertical: flipVertical)); @@ -66,7 +70,7 @@ Future> cropImage({ExtendedImageEditorState state}) async { option.addOption(RotateOption(rotateAngle)); } - final result = await ImageEditor.editImage( + final Uint8List result = await ImageEditor.editImage( image: img, imageEditorOption: option, ); diff --git a/lib/widgets/image/image_crop_page.dart b/lib/widgets/image/image_crop_page.dart index 01eecac7..f1f9747d 100755 --- a/lib/widgets/image/image_crop_page.dart +++ b/lib/widgets/image/image_crop_page.dart @@ -21,15 +21,15 @@ class ImageCropPage extends StatefulWidget { } class _ImageCropPageState extends State { - final _editorKey = GlobalKey(); - final _controller = LoadingDialogController(); + final GlobalKey _editorKey = GlobalKey(); + final LoadingDialogController _controller = LoadingDialogController(); File _file; bool _cropping = false; bool firstLoad = true; @override void initState() { - _openImage().catchError((e) {}); + _openImage().catchError((dynamic e) {}); super.initState(); } @@ -39,10 +39,14 @@ class _ImageCropPageState extends State { super.dispose(); } - Future _openImage() async { - final file = await ImagePicker.pickImage(source: ImageSource.gallery); - if (file != null) _file = file; - if (mounted) setState(() {}); + Future _openImage() async { + final File file = await ImagePicker.pickImage(source: ImageSource.gallery); + if (file != null) { + _file = file; + } + if (mounted) { + setState(() {}); + } resetCrop(); } @@ -58,8 +62,10 @@ class _ImageCropPageState extends State { _editorKey.currentState?.rotate(right: right); } - void _cropImage(context) async { - if (_cropping) return; + Future _cropImage(BuildContext context) async { + if (_cropping) { + return; + } LoadingDialog.show( context, text: '正在更新头像', @@ -67,10 +73,10 @@ class _ImageCropPageState extends State { ); _cropping = true; try { - final path = (await getApplicationDocumentsDirectory()).path; - final file = File('$path/_temp_avatar.jpg'); + final String path = (await getApplicationDocumentsDirectory()).path; + final File file = File('$path/_temp_avatar.jpg'); file.writeAsBytesSync(await cropImage(state: _editorKey.currentState)); - final compressedFile = await FlutterNativeImage.compressImage( + final File compressedFile = await FlutterNativeImage.compressImage( file.path, quality: 100, targetWidth: 640, @@ -83,10 +89,10 @@ class _ImageCropPageState extends State { } } - Future uploadImage(context, file) async { + Future uploadImage(BuildContext context, File file) async { try { - final formData = await createForm(file); - await NetUtils.postWithCookieSet(API.userAvatarUpload, data: formData); + final FormData formData = await createForm(file); + await NetUtils.postWithCookieSet(API.userAvatarUpload, data: formData); _controller.changeState('success', '头像更新成功'); _cropping = false; UserAPI.avatarLastModified = DateTime.now().millisecondsSinceEpoch; @@ -100,8 +106,8 @@ class _ImageCropPageState extends State { } } - Future createForm(File file) async { - return FormData.from({ + Future createForm(File file) async { + return FormData.from({ 'offset': 0, 'md5': md5.convert(await file.readAsBytes()), 'photo': UploadFileInfo(file, path.basename(file.path)), @@ -134,7 +140,7 @@ class _ImageCropPageState extends State { mode: ExtendedImageMode.editor, enableLoadState: true, extendedImageEditorKey: _editorKey, - initEditorConfigHandler: (state) { + initEditorConfigHandler: (ExtendedImageState state) { return EditorConfig( maxScale: 8.0, cropRectPadding: const EdgeInsets.all(30.0), @@ -165,7 +171,7 @@ class _ImageCropPageState extends State { ), ), highlightColor: Colors.red, - customBorder: CircleBorder(), + customBorder: const CircleBorder(), ), ), ), diff --git a/lib/widgets/image/image_viewer.dart b/lib/widgets/image/image_viewer.dart index 174e0f51..ab14df05 100755 --- a/lib/widgets/image/image_viewer.dart +++ b/lib/widgets/image/image_viewer.dart @@ -19,12 +19,6 @@ import 'package:openjmu/widgets/image/image_gesture_detector.dart'; pageRouteType: PageRouteType.transparent, ) class ImageViewer extends StatefulWidget { - final int index; - final List pics; - final bool needsClear; - final Post post; - final String heroPrefix; - const ImageViewer({ @required this.index, @required this.pics, @@ -33,19 +27,27 @@ class ImageViewer extends StatefulWidget { this.post, }); + final int index; + final List pics; + final bool needsClear; + final Post post; + final String heroPrefix; + @override ImageViewerState createState() => ImageViewerState(); } class ImageViewerState extends State with TickerProviderStateMixin { - final pageStreamController = StreamController.broadcast(); - final backgroundOpacityStreamController = StreamController.broadcast(); - final slidePageKey = GlobalKey(); + final StreamController pageStreamController = StreamController.broadcast(); + final StreamController backgroundOpacityStreamController = + StreamController.broadcast(); + final GlobalKey slidePageKey = + GlobalKey(); int currentIndex; bool popping = false; AnimationController _doubleTapAnimationController; - Animation _doubleTapCurveAnimation; + Animation _doubleTapCurveAnimation; Animation _doubleTapAnimation; VoidCallback _doubleTapListener; @@ -63,10 +65,7 @@ class ImageViewerState extends State with TickerProviderStateMixin _controller = PageController(initialPage: currentIndex); - _doubleTapAnimationController = AnimationController( - duration: const Duration(milliseconds: 200), - vsync: this, - ); + _doubleTapAnimationController = AnimationController(duration: 200.milliseconds, vsync: this); _doubleTapCurveAnimation = CurvedAnimation( parent: _doubleTapAnimationController, curve: Curves.linear, @@ -75,7 +74,7 @@ class ImageViewerState extends State with TickerProviderStateMixin @override void dispose() { - final provider = Provider.of(currentContext, listen: false); + final ThemesProvider provider = Provider.of(currentContext, listen: false); provider.setSystemUIDark(provider.dark); pageStreamController?.close(); backgroundOpacityStreamController?.close(); @@ -85,12 +84,14 @@ class ImageViewerState extends State with TickerProviderStateMixin } void pop() { - if (popping) return; + if (popping) { + return; + } popping = true; backgroundOpacityStreamController.add(0.0); } - Future _downloadImage(url, {AndroidDestinationType destination}) async { + Future _downloadImage(String url, {AndroidDestinationType destination}) async { String path; try { String imageId; @@ -100,21 +101,25 @@ class ImageViewerState extends State with TickerProviderStateMixin destination: AndroidDestinationType.custom(directory: 'OpenJMU'), ) : imageId = await ImageDownloader.downloadImage(url); - if (imageId == null) return; + if (imageId == null) { + return; + } path = await ImageDownloader.findPath(imageId); } on PlatformException catch (error) { showCenterToast(error.message); return; } - if (!mounted) return; + if (!mounted) { + return; + } showCenterToast('图片保存至:$path'); return; } void updateAnimation(ExtendedImageGestureState state) { - double begin = state.gestureDetails.totalScale; - double end = state.gestureDetails.totalScale == 1.0 ? 3.0 : 1.0; - Offset pointerDownPosition = state.pointerDownPosition; + final double begin = state.gestureDetails.totalScale; + final double end = state.gestureDetails.totalScale == 1.0 ? 3.0 : 1.0; + final Offset pointerDownPosition = state.pointerDownPosition; _doubleTapAnimation?.removeListener(_doubleTapListener); _doubleTapAnimationController @@ -126,7 +131,7 @@ class ImageViewerState extends State with TickerProviderStateMixin doubleTapPosition: pointerDownPosition, ); }; - _doubleTapAnimation = Tween( + _doubleTapAnimation = Tween( begin: begin, end: end, ).animate(_doubleTapCurveAnimation) @@ -135,7 +140,7 @@ class ImageViewerState extends State with TickerProviderStateMixin _doubleTapAnimationController.forward(); } - void onLongPress(context) { + void onLongPress(BuildContext context) { ConfirmationBottomSheet.show( context, children: [ @@ -158,12 +163,14 @@ class ImageViewerState extends State with TickerProviderStateMixin } bool slideEndHandler(Offset offset) { - final shouldEnd = offset.distance > Offset(Screens.width, Screens.height).distance / 7; - if (shouldEnd) pop(); + final bool shouldEnd = offset.distance > Offset(Screens.width, Screens.height).distance / 7; + if (shouldEnd) { + pop(); + } return shouldEnd; } - Widget pageBuilder(context, index) { + Widget pageBuilder(BuildContext context, int index) { return ImageGestureDetector( context: context, imageViewerState: this, @@ -181,7 +188,9 @@ class ImageViewerState extends State with TickerProviderStateMixin heroBuilderForSlidingPage: (Widget result) { if (index < widget.pics.length && widget.heroPrefix != null) { String tag = widget.heroPrefix; - if (widget.pics[index].postId != null) tag += '${widget.pics[index].postId}-'; + if (widget.pics[index].postId != null) { + tag += '${widget.pics[index].postId}-'; + } tag += '${widget.pics[index].id}'; return Hero( @@ -194,9 +203,9 @@ class ImageViewerState extends State with TickerProviderStateMixin BuildContext fromHeroContext, BuildContext toHeroContext, ) { - final Hero hero = flightDirection == HeroFlightDirection.pop + final Hero hero = (flightDirection == HeroFlightDirection.pop ? fromHeroContext.widget - : toHeroContext.widget; + : toHeroContext.widget) as Hero; return hero.child; }, ); @@ -219,10 +228,10 @@ class ImageViewerState extends State with TickerProviderStateMixin Widget loader; switch (state.extendedImageLoadState) { case LoadState.loading: - loader = SpinKitWidget(); + loader = const SpinKitWidget(); break; case LoadState.completed: - // TODO: GIF will setState and cause this flash. + // TODO(AlexVincent525): GIF will setState and cause this flash. // loader = FadeTransition( // opacity: Tween( // begin: 0.0, @@ -254,7 +263,7 @@ class ImageViewerState extends State with TickerProviderStateMixin slidePageBackgroundHandler: slidePageBackgroundHandler, slideEndHandler: slideEndHandler, resetPageDuration: widget.heroPrefix != null ? 300.milliseconds : 1.microseconds, - child: AnnotatedRegion( + child: AnnotatedRegion( value: SystemUiOverlayStyle.light, child: Material( type: MaterialType.transparency, @@ -278,7 +287,7 @@ class ImageViewerState extends State with TickerProviderStateMixin child: StreamBuilder( initialData: 1.0, stream: backgroundOpacityStreamController.stream, - builder: (context, data) => Opacity( + builder: (BuildContext context, AsyncSnapshot data) => Opacity( opacity: popping ? 0.0 : data.data, child: ViewAppBar( post: widget.post, @@ -295,7 +304,7 @@ class ImageViewerState extends State with TickerProviderStateMixin child: StreamBuilder( initialData: 1.0, stream: backgroundOpacityStreamController.stream, - builder: (context, data) => Opacity( + builder: (BuildContext context, AsyncSnapshot data) => Opacity( opacity: popping ? 0.0 : data.data, child: ImageList( controller: _controller, @@ -316,18 +325,18 @@ class ImageViewerState extends State with TickerProviderStateMixin } class ImageList extends StatelessWidget { - final PageController controller; - final StreamController pageStreamController; - final int index; - final List pics; - - ImageList({ + const ImageList({ this.controller, this.pageStreamController, this.index, this.pics, }); + final PageController controller; + final StreamController pageStreamController; + final int index; + final List pics; + @override Widget build(BuildContext context) { return Container( @@ -345,13 +354,13 @@ class ImageList extends StatelessWidget { child: StreamBuilder( initialData: index, stream: pageStreamController.stream, - builder: (context, data) => SizedBox( + builder: (BuildContext context, AsyncSnapshot data) => SizedBox( height: suSetHeight(52.0), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: List.generate( pics.length, - (i) => Container( + (int i) => Container( margin: EdgeInsets.symmetric(horizontal: suSetWidth(2.0)), width: suSetWidth(52.0), height: suSetWidth(52.0), @@ -395,15 +404,15 @@ class ImageList extends StatelessWidget { } class ViewAppBar extends StatelessWidget { - final Post post; - final VoidCallback onMoreClicked; - const ViewAppBar({ Key key, this.post, this.onMoreClicked, }) : super(key: key); + final Post post; + final VoidCallback onMoreClicked; + @override Widget build(BuildContext context) { return Material( @@ -442,7 +451,7 @@ class ViewAppBar extends StatelessWidget { ), ], ) - : SizedBox.shrink(), + : const SizedBox.shrink(), ), if (onMoreClicked != null) IconButton( @@ -458,19 +467,23 @@ class ViewAppBar extends StatelessWidget { } class ImageBean { - int id; - String imageUrl; - String imageThumbUrl; - int postId; - - ImageBean({this.id, this.imageUrl, this.imageThumbUrl, this.postId}); + const ImageBean({this.id, this.imageUrl, this.imageThumbUrl, this.postId}); + final int id; + final String imageUrl; + final String imageThumbUrl; + final int postId; Map toJson() { - return {'id': id, 'imageUrl': imageUrl, 'imageThumbUrl': imageThumbUrl, 'postId': postId}; + return { + 'id': id, + 'imageUrl': imageUrl, + 'imageThumbUrl': imageThumbUrl, + 'postId': postId, + }; } @override String toString() { - return 'ImageBean ${JsonEncoder.withIndent(' ').convert(toJson())}'; + return 'ImageBean ${const JsonEncoder.withIndent(' ').convert(toJson())}'; } } diff --git a/lib/widgets/messages/app_message_preview_widget.dart b/lib/widgets/messages/app_message_preview_widget.dart index b13db059..0a63d6ea 100644 --- a/lib/widgets/messages/app_message_preview_widget.dart +++ b/lib/widgets/messages/app_message_preview_widget.dart @@ -12,9 +12,6 @@ import 'package:openjmu/constants/constants.dart'; import 'package:openjmu/widgets/webapp_icon.dart'; class AppMessagePreviewWidget extends StatefulWidget { - final AppMessage message; - final double height; - const AppMessagePreviewWidget({ @required this.message, this.height = 70.0, @@ -22,6 +19,9 @@ class AppMessagePreviewWidget extends StatefulWidget { }) : assert(message != null), super(key: key); + final AppMessage message; + final double height; + @override _AppMessagePreviewWidgetState createState() => _AppMessagePreviewWidgetState(); } @@ -49,8 +49,8 @@ class _AppMessagePreviewWidgetState extends State super.dispose(); } - void timeFormat(_, {bool fromBuild = false}) { - final now = DateTime.now(); + void timeFormat(Timer _, {bool fromBuild = false}) { + final DateTime now = DateTime.now(); if (widget.message.sendTime.day == now.day && widget.message.sendTime.month == now.month && widget.message.sendTime.year == now.year) { @@ -60,14 +60,21 @@ class _AppMessagePreviewWidgetState extends State } else { formattedTime = DateFormat('yy-MM-dd HH:mm').format(widget.message.sendTime); } - if (mounted && !fromBuild) setState(() {}); + if (mounted && !fromBuild) { + setState(() {}); + } } Widget get unreadCounter => Consumer( - builder: (_, provider, __) { - final messages = provider.appsMessages[widget.message.appId]; - final unreadMessages = messages.where((message) => !message.read)?.toList(); - if (unreadMessages.isEmpty) return SizedBox.shrink(); + builder: (_, MessagesProvider provider, __) { + final List messages = provider.appsMessages[widget.message.appId]; + final List unreadMessages = messages + .where((dynamic message) => !(message as AppMessage).read) + ?.toList() + ?.cast(); + if (unreadMessages.isEmpty) { + return const SizedBox.shrink(); + } return Container( width: suSetWidth(28.0), height: suSetWidth(28.0), @@ -77,8 +84,8 @@ class _AppMessagePreviewWidgetState extends State ), child: Center( child: Selector( - selector: (_, provider) => provider.dark, - builder: (_, dark, __) { + selector: (_, ThemesProvider provider) => provider.dark, + builder: (_, bool dark, __) { return Text( '${unreadMessages.length}', style: TextStyle( @@ -95,21 +102,27 @@ class _AppMessagePreviewWidgetState extends State ); void updateApp() { - final provider = Provider.of(currentContext, listen: false); - app = provider.allApps.where((app) => app.appId == widget.message.appId).elementAt(0); + final WebAppsProvider provider = Provider.of(currentContext, listen: false); + app = provider.allApps + .where((dynamic app) => (app as WebApp).appId == widget.message.appId) + .elementAt(0); } void tryDecodeContent() { try { - final content = jsonDecode(widget.message.content); - widget.message.content = content['content']; + final Map content = + jsonDecode(widget.message.content) as Map; + widget.message.content = content['content'] as String; Provider.of(currentContext, listen: false).saveAppsMessages(); - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } catch (e) { return; } } + @override @mustCallSuper Widget build(BuildContext context) { super.build(context); @@ -120,21 +133,23 @@ class _AppMessagePreviewWidgetState extends State return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { - navigatorState.pushNamed(Routes.OPENJMU_CHAT_APP_MESSAGE_PAGE, arguments: {'app': app}); + navigatorState.pushNamed( + Routes.OPENJMU_CHAT_APP_MESSAGE_PAGE, + arguments: {'app': app}, + ); }, child: Container( - padding: EdgeInsets.symmetric(horizontal: suSetSp(16.0)), + padding: EdgeInsets.symmetric(horizontal: suSetWidth(16.0)), height: suSetHeight(widget.height), - decoration: BoxDecoration(), child: Row( children: [ Padding( - padding: EdgeInsets.only(right: suSetSp(16.0)), + padding: EdgeInsets.only(right: suSetWidth(16.0)), child: WebAppIcon(app: app), ), Expanded( child: SizedBox( - height: suSetSp(60.0), + height: suSetHeight(60.0), child: Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, @@ -142,7 +157,7 @@ class _AppMessagePreviewWidgetState extends State Row( children: [ SizedBox( - height: suSetSp(30.0), + height: suSetHeight(30.0), child: app != null ? Text( '${app.name ?? app.appId}', @@ -151,7 +166,7 @@ class _AppMessagePreviewWidgetState extends State fontWeight: FontWeight.w500, ), ) - : SizedBox.shrink(), + : const SizedBox.shrink(), ), Text( ' $formattedTime', @@ -159,7 +174,7 @@ class _AppMessagePreviewWidgetState extends State color: Theme.of(context).textTheme.body1.color.withOpacity(0.5), ), ), - Spacer(), + const Spacer(), unreadCounter, ], ), diff --git a/lib/widgets/messages/message_preview_widget.dart b/lib/widgets/messages/message_preview_widget.dart index 9df8d369..72ff3991 100644 --- a/lib/widgets/messages/message_preview_widget.dart +++ b/lib/widgets/messages/message_preview_widget.dart @@ -10,20 +10,22 @@ import 'package:intl/intl.dart'; import 'package:openjmu/constants/constants.dart'; class MessagePreviewWidget extends StatefulWidget { - final int uid; - final WebApp app; - final Message message; - final List unreadMessages; - const MessagePreviewWidget({ this.uid, this.app, @required this.message, @required this.unreadMessages, + this.height = 80.0, Key key, }) : assert(uid != null || app != null), super(key: key); + final int uid; + final WebApp app; + final Message message; + final List unreadMessages; + final double height; + @override _MessagePreviewWidgetState createState() => _MessagePreviewWidgetState(); } @@ -40,15 +42,17 @@ class _MessagePreviewWidgetState extends State @override void initState() { - UserAPI.getUserInfo(uid: widget.uid).then((response) { - user = UserInfo.fromJson(response.data); - if (mounted) setState(() {}); - }).catchError((e) { + UserAPI.getUserInfo(uid: widget.uid).then((dynamic response) { + user = UserInfo.fromJson((response as Response).data as Map); + if (mounted) { + setState(() {}); + } + }).catchError((dynamic e) { debugPrint('$e'); }); timeFormat(null); - timeUpdateTimer = Timer.periodic(const Duration(minutes: 1), timeFormat); + timeUpdateTimer = Timer.periodic(1.minutes, timeFormat); super.initState(); } @@ -59,8 +63,8 @@ class _MessagePreviewWidgetState extends State super.dispose(); } - void timeFormat(_) { - final now = DateTime.now(); + void timeFormat(Timer _) { + final DateTime now = DateTime.now(); if (widget.message.sendTime.day == now.day && widget.message.sendTime.month == now.month && widget.message.sendTime.year == now.year) { @@ -70,24 +74,22 @@ class _MessagePreviewWidgetState extends State } else { formattedTime = DateFormat('yy-MM-dd HH:mm').format(widget.message.sendTime); } - if (mounted) setState(() {}); + if (mounted) { + setState(() {}); + } } + @override @mustCallSuper Widget build(BuildContext context) { super.build(context); return Container( - padding: EdgeInsets.symmetric( - horizontal: suSetSp(16.0), - ), - height: suSetSp(90.0), - decoration: BoxDecoration(), + padding: EdgeInsets.symmetric(horizontal: suSetWidth(16.0)), + height: suSetHeight(widget.height), child: Row( children: [ Padding( - padding: EdgeInsets.only( - right: suSetSp(16.0), - ), + padding: EdgeInsets.only(right: suSetWidth(16.0)), child: UserAPI.getAvatar(size: 60.0, uid: widget.uid), ), Expanded( @@ -109,7 +111,7 @@ class _MessagePreviewWidgetState extends State fontWeight: FontWeight.w500, ), ) - : SizedBox.shrink(), + : const SizedBox.shrink(), ), Text( ' $formattedTime', @@ -117,7 +119,7 @@ class _MessagePreviewWidgetState extends State color: Theme.of(context).textTheme.body1.color.withOpacity(0.5), ), ), - Spacer(), + const Spacer(), Container( width: suSetWidth(28.0), height: suSetWidth(28.0), diff --git a/lib/widgets/rounded_check_box.dart b/lib/widgets/rounded_check_box.dart index 245f06c5..293c8ce2 100755 --- a/lib/widgets/rounded_check_box.dart +++ b/lib/widgets/rounded_check_box.dart @@ -255,7 +255,9 @@ class _RenderCheckbox extends RenderToggleable { @override set value(bool newValue) { - if (newValue == value) return; + if (newValue == value) { + return; + } _oldValue = value; super.value = newValue; } @@ -342,7 +344,7 @@ class _RenderCheckbox extends RenderToggleable { final Canvas canvas = context.canvas; paintRadialReaction(canvas, offset, size.center(Offset.zero)); - final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0); + final Offset origin = offset + (size / 2.0 - const Size.square(_kEdgeSize) / 2.0 as Offset); final AnimationStatus status = position.status; final double tNormalized = status == AnimationStatus.forward || status == AnimationStatus.completed diff --git a/lib/widgets/webapp_icon.dart b/lib/widgets/webapp_icon.dart index 4128f2b9..09c25f7a 100755 --- a/lib/widgets/webapp_icon.dart +++ b/lib/widgets/webapp_icon.dart @@ -6,18 +6,18 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:openjmu/constants/constants.dart'; class WebAppIcon extends StatelessWidget { - final WebApp app; - final double size; - const WebAppIcon({ Key key, @required this.app, this.size = 60.0, }) : super(key: key); + final WebApp app; + final double size; + Future loadAsset() async { try { - final _ = await rootBundle.load(iconPath); + await rootBundle.load(iconPath); return SvgPicture.asset(iconPath, width: suSetWidth(size), height: suSetWidth(size)); } catch (e) { debugPrint('Error when load webapp icon: $e.\nLoading fallback icon...'); @@ -39,14 +39,14 @@ class WebAppIcon extends StatelessWidget { @override Widget build(BuildContext context) { return Selector( - selector: (_, provider) => provider.newAppCenterIcon, - builder: (_, newAppCenterIcon, __) { - final shouldUseNew = !(currentUser?.isTeacher ?? false) || newAppCenterIcon; + selector: (_, SettingsProvider provider) => provider.newAppCenterIcon, + builder: (_, bool newAppCenterIcon, __) { + final bool shouldUseNew = !(currentUser?.isTeacher ?? false) || newAppCenterIcon; return shouldUseNew - ? FutureBuilder( - initialData: SizedBox.shrink(), + ? FutureBuilder( + initialData: const SizedBox.shrink(), future: loadAsset(), - builder: (_, snapshot) => SizedBox.fromSize( + builder: (_, AsyncSnapshot snapshot) => SizedBox.fromSize( size: Size.square(suSetWidth(size)), child: Center(child: snapshot.data), ), diff --git a/lib/widgets/webview/in_app_webview.dart b/lib/widgets/webview/in_app_webview.dart index e47cb2db..a4de81da 100755 --- a/lib/widgets/webview/in_app_webview.dart +++ b/lib/widgets/webview/in_app_webview.dart @@ -23,15 +23,6 @@ import 'package:openjmu/constants/constants.dart'; ], ) class InAppBrowserPage extends StatefulWidget { - final String url; - final String title; - final WebApp app; - final bool withCookie; - final bool withAppBar; - final bool withAction; - final bool withScaffold; - final bool keepAlive; - const InAppBrowserPage({ Key key, @required this.url, @@ -44,6 +35,15 @@ class InAppBrowserPage extends StatefulWidget { this.keepAlive = false, }) : super(key: key); + final String url; + final String title; + final WebApp app; + final bool withCookie; + final bool withAppBar; + final bool withAction; + final bool withScaffold; + final bool keepAlive; + @override _InAppBrowserPageState createState() => _InAppBrowserPageState(); } @@ -67,15 +67,17 @@ class _InAppBrowserPageState extends State with AutomaticKeepA } Instances.eventBus - ..on().listen((event) { - if (mounted) loadCourseSchedule(); + ..on().listen((CourseScheduleRefreshEvent event) { + if (mounted) { + loadCourseSchedule(); + } }); super.initState(); } @override void dispose() { - SystemChannels.textInput.invokeMethod('TextInput.hide'); + SystemChannels.textInput.invokeMethod('TextInput.hide'); super.dispose(); } @@ -87,21 +89,21 @@ class _InAppBrowserPageState extends State with AutomaticKeepA '&night=${currentIsDark ? 1 : 0}', ); } catch (e) { - debugPrint("$e"); + debugPrint('$e'); } } bool checkSchemeLoad(InAppWebViewController controller, String url) { - final protocolRegExp = RegExp(r'(http|https):\/\/([\w.]+\/?)\S*'); + final RegExp protocolRegExp = RegExp(r'(http|https):\/\/([\w.]+\/?)\S*'); if (!url.startsWith(protocolRegExp) && url.contains('://')) { debugPrint('Found scheme when load: $url'); if (Platform.isAndroid) { - Future.delayed(1.microseconds, () async { + Future.delayed(1.microseconds, () async { unawaited(controller.stopLoading()); debugPrint('Try to launch intent...'); - final appName = await ChannelUtils.getSchemeLaunchAppName(url); + final String appName = await ChannelUtils.getSchemeLaunchAppName(url); if (appName != null) { - final shouldLaunch = await waitForConfirmation(appName); + final bool shouldLaunch = await waitForConfirmation(appName); if (shouldLaunch) { await _launchURL(url: url); } @@ -123,7 +125,7 @@ class _InAppBrowserPageState extends State with AutomaticKeepA child: Text.rich( TextSpan( children: [ - TextSpan(text: '即将打开应用\n'), + const TextSpan(text: '即将打开应用\n'), TextSpan( text: '$applicationLabel', style: TextStyle(fontSize: suSetSp(20.0), fontWeight: FontWeight.bold), @@ -189,8 +191,8 @@ class _InAppBrowserPageState extends State with AutomaticKeepA ); } - void showMore(context) { - showModalBottomSheet( + void showMore(BuildContext context) { + showModalBottomSheet( shape: RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(suSetWidth(20.0)), @@ -242,16 +244,16 @@ class _InAppBrowserPageState extends State with AutomaticKeepA ); } - Future _launchURL({String url, bool forceSafariVC = true}) async { - final uri = Uri.encodeFull(url ?? this.url); + Future _launchURL({String url, bool forceSafariVC = true}) async { + final String uri = Uri.encodeFull(url ?? this.url); if (await canLaunch(uri)) { - await launch(uri, forceSafariVC: Platform.isIOS ? forceSafariVC : false); + await launch(uri, forceSafariVC: Platform.isIOS && forceSafariVC); } else { showCenterErrorToast('无法打开网址: $uri'); } } - Widget get appBar => PreferredSize( + PreferredSizeWidget get appBar => PreferredSize( preferredSize: Size.fromHeight(suSetHeight(kAppBarHeight)), child: Container( height: Screens.topSafeHeight + suSetHeight(kAppBarHeight), @@ -291,7 +293,7 @@ class _InAppBrowserPageState extends State with AutomaticKeepA ), ); - Widget get refreshIndicator => Center( + Widget get refreshIndicator => const Center( child: Padding( padding: EdgeInsets.symmetric(horizontal: 16.0), child: SizedBox( @@ -359,7 +361,7 @@ class _InAppBrowserPageState extends State with AutomaticKeepA useOnDownloadStart: true, useShouldOverrideUrlLoading: true, ), - // TODO: Currently zoom control in android was broken, need to find the root cause. + // TODO(AlexVincent525): Currently zoom control in android was broken, need to find the root cause. android: AndroidInAppWebViewOptions( allowFileAccessFromFileURLs: true, allowUniversalAccessFromFileURLs: true, @@ -400,19 +402,21 @@ class _InAppBrowserPageState extends State with AutomaticKeepA _webViewController = controller; this.url = url; - final _title = (await controller.getTitle())?.trim(); + final String _title = (await controller.getTitle())?.trim(); if (_title != null && _title.isNotEmpty && _title != this.url) { title = _title; } else { - final ogTitle = await controller.evaluateJavascript( + final String ogTitle = await controller.evaluateJavascript( source: 'var ogTitle = document.querySelector(\'[property="og:title"]\');\n' 'if (ogTitle != undefined) ogTitle.content;', - ); + ) as String; if (ogTitle != null) { title = ogTitle; } } - if (this.mounted) setState(() {}); + if (mounted) { + setState(() {}); + } }, onConsoleMessage: (InAppWebViewController controller, ConsoleMessage consoleMessage) { _webViewController = controller; @@ -425,7 +429,7 @@ class _InAppBrowserPageState extends State with AutomaticKeepA onDownloadStart: (InAppWebViewController controller, String url) { _webViewController = controller; - debugPrint("WebView started download from: $url"); + debugPrint('WebView started download from: $url'); NetUtils.download(url); }, onWebViewCreated: (InAppWebViewController controller) {