feat: implement some api; add md editor to app; login and signup logic.

This commit is contained in:
2021-12-30 20:04:00 +08:00
parent 1a0e8f8de7
commit 853132f1a8
61 changed files with 3205 additions and 149 deletions
+2 -3
View File
@@ -1,10 +1,9 @@
import 'package:flutter/cupertino.dart';
/// [UOS设计指南](https://docs.uniontech.com/zh/content/t_dbG3kBK9iDf9B963ok)
const double localManagerPanelWidth = 260;
const double marketPanelWidth = 300;
const double marketOrMePanelWidth = 300;
const shortDuration = const Duration(milliseconds: 100);
@@ -39,5 +38,5 @@ const List<String> builtInCommands = [
enum PanelType {
local_manager,
market,
market_or_me,
}
+3
View File
@@ -2,4 +2,7 @@ class SPKeys {
static final String brightnessMode = 'BRIGHTNESS_MODE';
static final String appliedSchemeId = 'APPLIED_SCHEME_ID';
static final String userLanguage = 'USER_LANGUAGE';
static final String accessToken = 'USER_ACCESS_TOKEN';
static final String loginEmail = 'USER_LOGIN_EMAIL';
static final String ignoredUpdateVersion = 'IGNORED_UPDATE_VERSION';
}
+2
View File
@@ -1,3 +1,5 @@
extension StringNotNull on String? {
bool get notNull => this != null && this != '';
bool get isNull => !notNull;
}
+135
View File
@@ -0,0 +1,135 @@
import 'dart:convert';
import 'dart:io';
import 'package:dde_gesture_manager/constants/sp_keys.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:dde_gesture_manager_api/apis.dart';
import 'package:dde_gesture_manager_api/models.dart';
import 'package:http/http.dart' as http;
typedef T BeanBuilder<T>(Map res);
typedef T HandleRespBuild<T>(http.Response resp);
getStatusCodeFunc<int>(Map resp) => resp["statusCode"];
class HttpErrorCode extends Error {
int statusCode;
HttpErrorCode(this.statusCode, {this.message});
String? message;
@override
String toString() => '[$statusCode] $message';
}
class Api {
static _handleHttpError(e) {
if (e is SocketException) {
Notificator.error(
H().topContext,
title: LocaleKeys.info_server_error_title.tr(),
description: LocaleKeys.info_server_error_description.tr(),
);
} else {
throw e;
}
}
static HandleRespBuild<T> _handleRespBuild<T>(BeanBuilder<T> builder) => (http.Response resp) {
if (builder == getStatusCodeFunc) return builder({"statusCode": resp.statusCode});
T res;
try {
res = builder(json.decode(resp.body));
} catch (e) {
throw HttpErrorCode(resp.statusCode, message: resp.body);
}
return res;
};
static Future<T> _get<T>(
String path,
BeanBuilder<T> builder, {
Map<String, dynamic>? queryParams,
bool ignoreToken = false,
bool ignoreErrorHandle = false,
}) =>
http
.get(
Uri(
scheme: Apis.apiScheme,
host: Apis.apiHost,
port: Apis.apiPort,
queryParameters: queryParams,
path: path,
),
headers: <String, String>{
HttpHeaders.contentTypeHeader: ContentType.json.value,
}..addAll(
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
)
.then(
_handleRespBuild<T>(builder),
onError: (e) {
if (ignoreErrorHandle)
throw e;
else
return _handleHttpError(e);
},
);
static Future<T> _post<T>(
String path,
BeanBuilder<T> builder, {
Map<String, dynamic>? body,
bool ignoreToken = false,
bool ignoreErrorHandle = false,
}) =>
http
.post(
Uri(
scheme: Apis.apiScheme,
host: Apis.apiHost,
port: Apis.apiPort,
path: path,
),
body: jsonEncode(body),
headers: <String, String>{
HttpHeaders.contentTypeHeader: ContentType.json.value,
}..addAll(
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
)
.then(
_handleRespBuild<T>(builder),
onError: (e) {
if (ignoreErrorHandle)
throw e;
else
return _handleHttpError(e);
},
);
static Future<LoginSuccess?> loginOrSignup({
required String email,
required String password,
}) =>
_post<LoginSuccess?>(
Apis.auth.loginOrSignup,
LoginSuccessSerializer.fromMap,
body: {
UserFields.email: email,
UserFields.password: password,
},
ignoreToken: true,
);
static Future<AppVersion?> checkAppVersion({ignoreErrorHandle = false}) => _get<AppVersion?>(
Apis.system.appVersion,
AppVersionSerializer.fromMap,
ignoreToken: true,
ignoreErrorHandle: ignoreErrorHandle,
);
}
+40 -1
View File
@@ -1,5 +1,6 @@
import 'package:dde_gesture_manager/builder/provider_annotation.dart';
import 'package:dde_gesture_manager/constants/sp_keys.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
enum BrightnessMode {
@@ -14,11 +15,49 @@ class Configs {
BrightnessMode? brightnessMode;
@ProviderModelProp()
String? appliedSchemeId;
String? get appliedSchemeId => _appliedSchemeId;
set appliedSchemeId(String? schemeId) {
_appliedSchemeId = schemeId;
if (schemeId.notNull)
H().sp.updateString(SPKeys.appliedSchemeId, schemeId!);
else
H().sp.remove(SPKeys.appliedSchemeId);
}
String? _appliedSchemeId;
@ProviderModelProp()
String? get accessToken => _accessToken;
set accessToken(String? token) {
_accessToken = token;
if (token.notNull)
H().sp.updateString(SPKeys.accessToken, token!);
else
H().sp.remove(SPKeys.accessToken);
}
String? _accessToken;
@ProviderModelProp()
String? get email => _email;
set email(String? emailAddress) {
_email = emailAddress;
if (emailAddress.notNull)
H().sp.updateString(SPKeys.loginEmail, emailAddress!);
else
H().sp.remove(SPKeys.loginEmail);
}
String? _email;
Configs() {
this.brightnessMode =
BrightnessMode.values[H().sp.getInt(SPKeys.brightnessMode)?.clamp(0, BrightnessMode.values.length - 1) ?? 0];
this.appliedSchemeId = H().sp.getString(SPKeys.appliedSchemeId);
this.accessToken = H().sp.getString(SPKeys.accessToken);
this.email = H().sp.getString(SPKeys.loginEmail);
}
}
+6 -1
View File
@@ -6,5 +6,10 @@ class ContentLayout {
bool? localManagerOpened;
@ProviderModelProp()
bool? marketOpened;
bool? marketOrMeOpened;
@ProviderModelProp()
bool? currentIsMarket = true;
bool get isMarket => currentIsMarket ?? true;
}
+4 -4
View File
@@ -3,7 +3,7 @@ import 'package:dde_gesture_manager/models/content_layout.provider.dart';
import 'package:dde_gesture_manager/models/scheme.provider.dart';
import 'package:dde_gesture_manager/pages/gesture_editor.dart';
import 'package:dde_gesture_manager/pages/local_manager.dart';
import 'package:dde_gesture_manager/pages/market.dart';
import 'package:dde_gesture_manager/pages/market_or_me.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:flutter/material.dart';
@@ -31,7 +31,7 @@ class _ContentState extends State<Content> {
ChangeNotifierProvider(
create: (context) => ContentLayoutProvider()
..localManagerOpened = preferredPanelsStatus.localManagerPanelOpened
..marketOpened = preferredPanelsStatus.marketPanelOpened,
..marketOrMeOpened = preferredPanelsStatus.marketOrMePanelOpened,
),
ChangeNotifierProvider(
create: (context) => CopiedGesturePropProvider.empty(),
@@ -42,7 +42,7 @@ class _ContentState extends State<Content> {
Future.microtask(
() => context.read<ContentLayoutProvider>().setProps(
localManagerOpened: preferredPanelsStatus.localManagerPanelOpened,
marketOpened: preferredPanelsStatus.marketPanelOpened,
marketOrMeOpened: preferredPanelsStatus.marketOrMePanelOpened,
),
);
}
@@ -52,7 +52,7 @@ class _ContentState extends State<Content> {
children: [
LocalManager(),
GestureEditor(),
Market(),
MarketOrMe(),
],
);
},
+3 -3
View File
@@ -68,12 +68,12 @@ class GestureEditor extends StatelessWidget {
),
).tr(),
Visibility(
visible: layoutProvider.marketOpened == false,
visible: layoutProvider.marketOrMeOpened == false,
child: DButton(
width: defaultButtonHeight,
onTap: () => H.openPanel(context, PanelType.market),
onTap: () => H.openPanel(context, PanelType.market_or_me),
child: Icon(
CupertinoIcons.cart,
layoutProvider.isMarket ? CupertinoIcons.cart : CupertinoIcons.person,
),
),
),
-3
View File
@@ -1,6 +1,5 @@
import 'package:collection/collection.dart';
import 'package:dde_gesture_manager/constants/constants.dart';
import 'package:dde_gesture_manager/constants/sp_keys.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/models/configs.provider.dart';
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
@@ -9,7 +8,6 @@ import 'package:dde_gesture_manager/models/local_schemes_provider.dart';
import 'package:dde_gesture_manager/models/scheme.dart';
import 'package:dde_gesture_manager/models/scheme.provider.dart';
import 'package:dde_gesture_manager/models/settings.provider.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/widgets/dde_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
@@ -247,7 +245,6 @@ class _LocalManagerState extends State<LocalManager> {
var appliedId =
localSchemes.firstWhere((ele) => ele.path == _selectedItemPath).scheme.id!;
appliedId.sout();
H().sp.updateString(SPKeys.appliedSchemeId, appliedId);
context.read<ConfigsProvider>().setProps(appliedSchemeId: appliedId);
},
),
-65
View File
@@ -1,65 +0,0 @@
import 'package:dde_gesture_manager/constants/constants.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
import 'package:dde_gesture_manager/widgets/dde_button.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Market extends StatelessWidget {
const Market({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var isOpen = context.watch<ContentLayoutProvider>().marketOpened == true;
return AnimatedContainer(
duration: mediumDuration,
curve: Curves.easeInOut,
width: isOpen ? marketPanelWidth : 0,
child: OverflowBox(
alignment: Alignment.centerLeft,
maxWidth: marketPanelWidth,
minWidth: marketPanelWidth,
child: Material(
color: context.t.backgroundColor,
elevation: isOpen ? 10 : 0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
DButton(
width: defaultButtonHeight - 2,
height: defaultButtonHeight - 2,
onTap: () => context.read<ContentLayoutProvider>().setProps(marketOpened: !isOpen),
child: Icon(
CupertinoIcons.chevron_right_2,
size: 20,
),
),
Flexible(
child: Center(
child: Text(
LocaleKeys.market_title,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
),
).tr(),
),
),
Container(width: defaultButtonHeight),
],
),
],
),
),
),
),
);
}
}
+117
View File
@@ -0,0 +1,117 @@
import 'package:auto_size_text/auto_size_text.dart';
import 'package:dde_gesture_manager/constants/constants.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/models/configs.provider.dart';
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
import 'package:dde_gesture_manager/widgets/dde_button.dart';
import 'package:dde_gesture_manager/widgets/login.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class MarketOrMe extends StatelessWidget {
const MarketOrMe({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
var layoutProvider = context.watch<ContentLayoutProvider>();
bool isOpen = layoutProvider.marketOrMeOpened == true;
bool isMarket = layoutProvider.isMarket;
bool showLogin = context.watch<ConfigsProvider>().accessToken.isNull && !isMarket;
return AnimatedContainer(
duration: mediumDuration,
curve: Curves.easeInOut,
width: isOpen ? marketOrMePanelWidth * (showLogin ? 1.5 : 1) : 0,
child: OverflowBox(
alignment: Alignment.centerLeft,
maxWidth: marketOrMePanelWidth * (showLogin ? 1.5 : 1),
minWidth: marketOrMePanelWidth * (showLogin ? 1.5 : 1),
child: Material(
color: context.t.backgroundColor,
elevation: isOpen ? 10 : 0,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
DButton(
width: defaultButtonHeight - 2,
height: defaultButtonHeight - 2,
onTap: () => context.read<ContentLayoutProvider>().setProps(marketOrMeOpened: !isOpen),
child: Icon(
CupertinoIcons.chevron_right_2,
size: 20,
),
),
Flexible(
child: Center(
child: Text(
isMarket ? LocaleKeys.market_title : LocaleKeys.me_title,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
),
).tr(),
),
),
DButton(
width: defaultButtonHeight - 2,
height: defaultButtonHeight - 2,
onTap: () => context.read<ContentLayoutProvider>().setProps(currentIsMarket: !isMarket),
child: Icon(
!isMarket ? CupertinoIcons.cart : CupertinoIcons.person,
size: 20,
),
),
],
),
if (isMarket) buildMarketContent(context),
if (!isMarket) buildMeContent(context),
],
),
),
),
),
);
}
Widget buildMeContent(BuildContext context) {
var accessToken = context.watch<ConfigsProvider>().accessToken;
if (accessToken.isNull) return LoginWidget();
return Padding(
padding: EdgeInsets.symmetric(vertical: 10),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Icon(Icons.person, size: defaultButtonHeight),
Flexible(
child: AutoSizeText(
context.watch<ConfigsProvider>().email ?? '',
style: TextStyle(
fontSize: 18,
),
maxLines: 1,
),
),
DButton.logout(
enabled: true,
onTap: () => context.read<ConfigsProvider>().setProps(accessToken: '', email: ''),
),
],
),
],
),
);
}
Widget buildMarketContent(BuildContext context) {
return Container();
}
}
+19 -11
View File
@@ -29,34 +29,42 @@ class H {
initSharedPreference() async {
_sp = await SharedPreferences.getInstance();
}
late BuildContext _topContext;
BuildContext get topContext => _topContext;
initTopContext(BuildContext context) {
_topContext = context;
}
static void openPanel(BuildContext context, PanelType panelType) {
var windowWidth = MediaQuery.of(context).size.width;
if (windowWidth < minWindowSize.width + localManagerPanelWidth + marketPanelWidth) {
if (windowWidth < minWindowSize.width + localManagerPanelWidth + marketOrMePanelWidth) {
context.read<ContentLayoutProvider>().setProps(
localManagerOpened: panelType == PanelType.local_manager,
marketOpened: panelType == PanelType.market,
marketOrMeOpened: panelType == PanelType.market_or_me,
);
} else {
switch (panelType) {
case PanelType.local_manager:
return context.read<ContentLayoutProvider>().setProps(localManagerOpened: true);
case PanelType.market:
return context.read<ContentLayoutProvider>().setProps(marketOpened: true);
case PanelType.market_or_me:
return context.read<ContentLayoutProvider>().setProps(marketOrMeOpened: true);
}
}
}
static PreferredPanelsStatus getPreferredPanelsStatus(double windowWidth) {
var preferredPanelsStatus = PreferredPanelsStatus(localManagerPanelOpened: true, marketPanelOpened: true);
if (windowWidth > minWindowSize.width + localManagerPanelWidth + marketPanelWidth)
var preferredPanelsStatus = PreferredPanelsStatus(localManagerPanelOpened: true, marketOrMePanelOpened: true);
if (windowWidth > minWindowSize.width + localManagerPanelWidth + marketOrMePanelWidth)
return preferredPanelsStatus;
else if (windowWidth < minWindowSize.width + localManagerPanelWidth)
return preferredPanelsStatus
..marketPanelOpened = false
..marketOrMePanelOpened = false
..localManagerPanelOpened = false;
else
return preferredPanelsStatus..marketPanelOpened = false;
return preferredPanelsStatus..marketOrMePanelOpened = false;
}
static Gesture getGestureByName(String gestureName) => Gesture.values.findByName(gestureName) ?? Gesture.swipe;
@@ -108,15 +116,15 @@ class H {
class PreferredPanelsStatus {
bool localManagerPanelOpened;
bool marketPanelOpened;
bool marketOrMePanelOpened;
PreferredPanelsStatus({
required this.localManagerPanelOpened,
required this.marketPanelOpened,
required this.marketOrMePanelOpened,
});
@override
String toString() {
return 'PreferredPanelsStatus{localManagerPanelOpened: $localManagerPanelOpened, marketPanelOpened: $marketPanelOpened}';
return 'PreferredPanelsStatus{localManagerPanelOpened: $localManagerPanelOpened, marketOrMePanelOpened: $marketOrMePanelOpened}';
}
}
+35
View File
@@ -3,13 +3,22 @@ import 'package:dde_gesture_manager/constants/sp_keys.dart';
import 'package:dde_gesture_manager/constants/supported_locales.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/generated/codegen_loader.g.dart';
import 'package:dde_gesture_manager/http/api.dart';
import 'package:dde_gesture_manager/models/settings.provider.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:dde_gesture_manager_api/apis.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
import 'package:gsettings/gsettings.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:window_manager/window_manager.dart';
bool _updateChecked = false;
Future<void> initEvents(BuildContext context) async {
H().initTopContext(context);
var isDark = MediaQuery.of(context).platformBrightness == Brightness.dark;
if (isDark) {
context.read<SettingsProvider>().setProps(isDarkMode: isDark);
@@ -39,6 +48,32 @@ Future<void> initEvents(BuildContext context) async {
});
}
}
if (!_updateChecked)
Api.checkAppVersion(ignoreErrorHandle: true).then((value) async {
_updateChecked = true;
var info = await PackageInfo.fromPlatform();
var _buildNumber = int.parse(info.buildNumber);
var _newVersionCode = value?.versionCode ?? 0;
var _ignoredVersionCode = H().sp.getInt(SPKeys.ignoredUpdateVersion) ?? 0;
if (_buildNumber < _newVersionCode && _ignoredVersionCode < _newVersionCode) {
Notificator.showConfirm(
title: LocaleKeys.info_new_version_title.tr(namedArgs: {'version': '${value?.versionName}'}),
description: LocaleKeys.info_new_version_description_for_startup.tr(namedArgs: {
'yes': LocaleKeys.str_yes.tr(),
'no': LocaleKeys.str_no.tr(),
}),
).then((confirmed) async {
if (confirmed == CustomButton.positiveButton) {
if (await canLaunch(Apis.appNewVersionUrl)) {
await launch(Apis.appNewVersionUrl);
}
} else if (confirmed == CustomButton.negativeButton) {
H().sp.updateInt(SPKeys.ignoredUpdateVersion, value?.versionCode ?? 0);
}
});
}
});
}
Future<void> initConfigs() async {
+1
View File
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
Future<void> initEvents(BuildContext context) async {
H().initTopContext(context);
var isDark = MediaQuery.of(context).platformBrightness == Brightness.dark;
context.read<SettingsProvider>().setProps(isDarkMode: isDark);
}
+3 -2
View File
@@ -1,5 +1,6 @@
import 'package:cherry_toast/cherry_toast.dart';
import 'package:cherry_toast/resources/arrays.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
@@ -27,8 +28,8 @@ class Notificator {
return AlertImpl().showConfirm(
windowTitle: title,
text: description,
positiveButtonTitle: positiveButtonTitle,
negativeButtonTitle: negativeButtonTitle,
positiveButtonTitle: positiveButtonTitle ?? LocaleKeys.str_yes.tr(),
negativeButtonTitle: negativeButtonTitle ?? LocaleKeys.str_no.tr(),
);
}
+17
View File
@@ -107,6 +107,23 @@ class DButton extends StatefulWidget {
message: LocaleKeys.operation_paste.tr(),
));
factory DButton.logout({
Key? key,
required enabled,
GestureTapCallback? onTap,
height = defaultButtonHeight,
width = defaultButtonHeight,
}) =>
DButton(
key: key,
width: width,
height: height,
onTap: enabled ? onTap : null,
child: Tooltip(
child: Opacity(opacity: enabled ? 1 : 0.4, child: const Icon(Icons.logout_rounded, size: 20)),
message: LocaleKeys.operation_logout.tr(),
));
factory DButton.dropdown({
Key? key,
width = 60.0,
+9 -1
View File
@@ -2,6 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:dde_gesture_manager/constants/constants.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/models/settings.provider.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:flutter/material.dart';
import 'package:markdown_editor_ot/markdown_editor.dart';
import 'package:url_launcher/url_launcher.dart';
@@ -77,11 +78,18 @@ class _DMarkdownFieldState extends State<DMarkdownField> {
});
},
child: MouseRegion(
cursor: widget.readOnly ? SystemMouseCursors.basic : SystemMouseCursors.click,
cursor: widget.readOnly ? SystemMouseCursors.basic : SystemMouseCursors.text,
child: MdPreview(
text: _previewText ?? '',
padding: EdgeInsets.only(left: 15),
onTapLink: _launchURL,
onCodeCopied: () {
Notificator.success(
context,
title: LocaleKeys.info_code_copied_titte.tr(),
description: LocaleKeys.info_code_copied_description.tr(),
);
},
widgetImage: (imageUrl) => CachedNetworkImage(
imageUrl: imageUrl,
placeholder: (context, url) => const SizedBox(
+102
View File
@@ -0,0 +1,102 @@
import 'dart:io';
import 'package:dde_gesture_manager/constants/sp_keys.dart';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:dde_gesture_manager/http/api.dart';
import 'package:dde_gesture_manager/models/configs.provider.dart';
import 'package:dde_gesture_manager/models/settings.provider.dart';
import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:flutter/material.dart';
import 'package:flutter_login/flutter_login.dart';
class LoginWidget extends StatefulWidget {
const LoginWidget({
Key? key,
}) : super(key: key);
@override
_LoginWidgetState createState() => _LoginWidgetState();
}
class _LoginWidgetState extends State<LoginWidget> {
ValueKey<int> _key = ValueKey(0);
@override
Widget build(BuildContext context) {
return Expanded(
child: OverflowBox(
alignment: Alignment.topCenter,
child: Container(
child: ScrollConfiguration(
behavior: const ScrollBehavior().copyWith(
physics: const NeverScrollableScrollPhysics(),
),
child: FlutterLogin(
key: _key,
onLogin: (loginData) async {
try {
var res = await Api.loginOrSignup(email: loginData.name, password: loginData.password);
if (res != null && res.token.notNull)
context.read<ConfigsProvider>().setProps(accessToken: res.token, email: loginData.name);
} catch (e) {
if (!(e is HttpErrorCode)) return;
var code = e.statusCode;
if (code == HttpStatus.unauthorized)
Notificator.error(
context,
title: LocaleKeys.info_login_failed_title.tr(),
description: LocaleKeys.info_login_failed_description.tr(),
);
else if (code == HttpStatus.notFound)
Notificator.info(
context,
title: LocaleKeys.info_sign_up_hint_title.tr(),
description: LocaleKeys.info_sign_up_hint_description.tr(),
);
else
throw e;
}
},
onSubmitAnimationCompleted: () {
var token = H().sp.getString(SPKeys.accessToken);
if (token.isNull)
setState(() {
_key = ValueKey(_key.value + 1);
});
else if (context.read<ConfigsProvider>().accessToken != token)
context
.read<ConfigsProvider>()
.setProps(accessToken: token, email: H().sp.getString(SPKeys.loginEmail));
},
onRecoverPassword: (_) {},
hideForgotPasswordButton: true,
disableCustomPageTransformer: true,
messages: LoginMessages(
userHint: LocaleKeys.me_login_email_hint.tr(),
passwordHint: LocaleKeys.me_login_password_hint.tr(),
loginButton: LocaleKeys.me_login_login_or_signup.tr(),
),
userValidator: (value) {
if (FlutterLogin.defaultEmailValidator(value) != null) {
return LocaleKeys.me_login_email_error_hint.tr();
}
},
passwordValidator: (value) {
if (value!.isEmpty || value.length < 8 || value.length > 16) {
return LocaleKeys.me_login_password_hint.tr();
}
},
theme: LoginTheme(
pageColorDark: Colors.transparent,
pageColorLight: Colors.transparent,
primaryColor: context.watch<SettingsProvider>().currentActiveColor,
footerBackgroundColor: Colors.transparent,
),
),
),
),
),
);
}
}
+31 -19
View File
@@ -1,11 +1,12 @@
import 'dart:convert';
import 'package:dde_gesture_manager/extensions.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:http/http.dart' as http;
import 'package:dde_gesture_manager/http/api.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:dde_gesture_manager_api/apis.dart';
import 'package:dde_gesture_manager_api/models.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_alert/flutter_platform_alert.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
class VersionChecker extends StatelessWidget {
const VersionChecker({Key? key}) : super(key: key);
@@ -22,20 +23,31 @@ class VersionChecker extends StatelessWidget {
Text(
'${LocaleKeys.version_current.tr()} : ${snapshot.data?.version ?? ''}',
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: TextButton(
child: Text(LocaleKeys.version_check_update).tr(),
onPressed: () {
http.get(Uri.parse('http://127.0.0.1:3000' + Apis.system.appVersion)).then((value) {
var appVersion = AppVersionSerializer.fromMap(json.decode(value.body));
appVersion.versionName.sout();
appVersion.versionCode.sout();
appVersion.sout();
});
},
if (!kIsWeb)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 3),
child: TextButton(
child: Text(LocaleKeys.version_check_update).tr(),
onPressed: () {
Api.checkAppVersion().then((value) {
if (value != null && (value.versionCode ?? 0) > int.parse(snapshot.data?.buildNumber ?? '0')) {
Notificator.showConfirm(
title: LocaleKeys.info_new_version_title.tr(namedArgs: {'version': '${value.versionName}'}),
description: LocaleKeys.info_new_version_description_for_manual.tr(),
).then((value) async {
if (value == CustomButton.positiveButton) {
if (await canLaunch(Apis.appNewVersionUrl)) {
await launch(Apis.appNewVersionUrl);
}
}
});
} else {
Notificator.info(context, title: LocaleKeys.info_new_version_title_already_latest.tr());
}
});
},
),
),
),
],
),
);