feat: add startup bulletin; switch to edit mode when click text on md preview.

dev
DebuggerX 3 years ago
parent 49ec2a641e
commit 0c87b714c4

@ -5,6 +5,9 @@ class Apis {
static const appNewVersionUrl = 'https://www.debuggerx.com/2022/01/21/dgm-changelog?from=app'; static const appNewVersionUrl = 'https://www.debuggerx.com/2022/01/21/dgm-changelog?from=app';
static appBulletinUrl(bool isWeb) =>
'https://www.debuggerx.com/dgm_web/bulletin.json?from=app_${isWeb ? 'web' : 'linux'}';
static appManualUrl(bool isWeb) => static appManualUrl(bool isWeb) =>
'https://www.debuggerx.com/2022/01/21/dgm-manual?from=app_${isWeb ? 'web' : 'linux'}'; 'https://www.debuggerx.com/2022/01/21/dgm-manual?from=app_${isWeb ? 'web' : 'linux'}';

@ -19,6 +19,7 @@ class MarkdownBuilder implements md.NodeVisitor {
this.defaultTextStyle, { this.defaultTextStyle, {
this.tagTextStyle = defaultTagTextStyle, this.tagTextStyle = defaultTagTextStyle,
required this.onCodeCopied, required this.onCodeCopied,
this.richTap,
}); });
final _widgets = <Widget>[]; final _widgets = <Widget>[];
@ -30,6 +31,7 @@ class MarkdownBuilder implements md.NodeVisitor {
final BuildContext context; final BuildContext context;
final LinkTap linkTap; final LinkTap linkTap;
final VoidCallback? richTap;
final WidgetImage widgetImage; final WidgetImage widgetImage;
final double maxWidth; final double maxWidth;
final Function onCodeCopied; final Function onCodeCopied;
@ -125,6 +127,7 @@ class MarkdownBuilder implements md.NodeVisitor {
children: last.textSpans, children: last.textSpans,
style: last.textStyle, style: last.textStyle,
), ),
onTap: richTap,
); );
} }
} }

@ -14,6 +14,7 @@ class Markdown extends StatefulWidget {
required this.onCodeCopied, required this.onCodeCopied,
this.maxWidth, this.maxWidth,
this.textStyle, this.textStyle,
this.richTap,
}) : super(key: key); }) : super(key: key);
final String data; final String data;
@ -28,6 +29,8 @@ class Markdown extends StatefulWidget {
final Function onCodeCopied; final Function onCodeCopied;
final VoidCallback? richTap;
@override @override
MarkdownState createState() => MarkdownState(); MarkdownState createState() => MarkdownState();
} }
@ -62,6 +65,7 @@ class MarkdownState extends State<Markdown> {
widget.maxWidth ?? MediaQuery.of(context).size.width, widget.maxWidth ?? MediaQuery.of(context).size.width,
widget.textStyle ?? defaultTextStyle(context), widget.textStyle ?? defaultTextStyle(context),
onCodeCopied: widget.onCodeCopied, onCodeCopied: widget.onCodeCopied,
richTap: widget.richTap,
).build(nodes); ).build(nodes);
} }
} }

@ -11,6 +11,7 @@ class MdPreview extends StatefulWidget {
required this.widgetImage, required this.widgetImage,
required this.onCodeCopied, required this.onCodeCopied,
this.textStyle, this.textStyle,
this.richTap,
}) : super(key: key); }) : super(key: key);
final String text; final String text;
@ -24,6 +25,8 @@ class MdPreview extends StatefulWidget {
/// If [onTapLink] is null,it will open the link with your default browser. /// If [onTapLink] is null,it will open the link with your default browser.
final TapLinkCallback? onTapLink; final TapLinkCallback? onTapLink;
final VoidCallback? richTap;
@override @override
State<StatefulWidget> createState() => MdPreviewState(); State<StatefulWidget> createState() => MdPreviewState();
} }
@ -50,6 +53,7 @@ class MdPreviewState extends State<MdPreview>
image: widget.widgetImage, image: widget.widgetImage,
textStyle: widget.textStyle, textStyle: widget.textStyle,
onCodeCopied: widget.onCodeCopied, onCodeCopied: widget.onCodeCopied,
richTap: widget.richTap,
); );
}, },
), ),

@ -12,3 +12,6 @@ sed -i -e "s!$wasmLocation!.!" \
-e "s!https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols!./assets/assets/css/Noto-Sans-Symbols.css!" \ -e "s!https://fonts.googleapis.com/css2?family=Noto+Sans+Symbols!./assets/assets/css/Noto-Sans-Symbols.css!" \
-e "s!https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat!./assets/assets/css/Noto-Color-Emoji-Compat.css!" \ -e "s!https://fonts.googleapis.com/css2?family=Noto+Color+Emoji+Compat!./assets/assets/css/Noto-Color-Emoji-Compat.css!" \
build/web/main.dart.js build/web/main.dart.js
# git init && git add . && git commit -m 'update' && git remote add origin git@github.com:debuggerx01/dgm_web.git && git push --set-upstream origin master -f

@ -5,4 +5,5 @@ class SPKeys {
static final String accessToken = 'USER_ACCESS_TOKEN'; static final String accessToken = 'USER_ACCESS_TOKEN';
static final String loginEmail = 'USER_LOGIN_EMAIL'; static final String loginEmail = 'USER_LOGIN_EMAIL';
static final String ignoredUpdateVersion = 'IGNORED_UPDATE_VERSION'; static final String ignoredUpdateVersion = 'IGNORED_UPDATE_VERSION';
static final String readBulletinId = 'READ_BULLETIN_ID';
} }

@ -63,6 +63,8 @@ class Api {
return res; return res;
}; };
static final _fullPathRegExp = RegExp('http(s?)://');
static Future<T?> _get<T>( static Future<T?> _get<T>(
String path, String path,
BeanBuilder<T> builder, { BeanBuilder<T> builder, {
@ -72,13 +74,15 @@ class Api {
}) => }) =>
http http
.get( .get(
Uri( path.startsWith(_fullPathRegExp)
scheme: Apis.apiScheme, ? Uri.parse(path)
host: Apis.apiHost, : Uri(
port: Apis.apiPort, scheme: Apis.apiScheme,
queryParameters: queryParams, host: Apis.apiHost,
path: path, port: Apis.apiPort,
), queryParameters: queryParams,
path: path,
),
headers: <String, String>{ headers: <String, String>{
HttpHeaders.contentTypeHeader: ContentType.json.toString(), HttpHeaders.contentTypeHeader: ContentType.json.toString(),
}..addAll( }..addAll(
@ -103,12 +107,14 @@ class Api {
}) => }) =>
http http
.post( .post(
Uri( path.startsWith(_fullPathRegExp)
scheme: Apis.apiScheme, ? Uri.parse(path)
host: Apis.apiHost, : Uri(
port: Apis.apiPort, scheme: Apis.apiScheme,
path: path, host: Apis.apiHost,
), port: Apis.apiPort,
path: path,
),
body: jsonEncode(body), body: jsonEncode(body),
headers: <String, String>{ headers: <String, String>{
HttpHeaders.contentTypeHeader: ContentType.json.toString(), HttpHeaders.contentTypeHeader: ContentType.json.toString(),
@ -199,6 +205,26 @@ class Api {
Apis.scheme.userLikes, Apis.scheme.userLikes,
(e) => (e['list'] as List).cast<int>(), (e) => (e['list'] as List).cast<int>(),
); );
static Future<AppBulletinResp?> checkBulletin(bool isWeb) => _get(
Apis.appBulletinUrl(isWeb),
AppBulletinResp.fromMap,
ignoreErrorHandle: true,
ignoreToken: true,
).catchError((_) {});
}
class AppBulletinResp {
int? id;
bool? once;
String? title;
String? content;
AppBulletinResp.fromMap(Map map)
: id = map['id'],
once = map['once'],
title = map['title'],
content = map['content'];
} }
class MarketSchemeTransMetaDataResp { class MarketSchemeTransMetaDataResp {

@ -11,6 +11,7 @@ import 'package:dde_gesture_manager/themes/dark.dart';
import 'package:dde_gesture_manager/themes/light.dart'; import 'package:dde_gesture_manager/themes/light.dart';
import 'package:dde_gesture_manager/utils/helper.dart'; import 'package:dde_gesture_manager/utils/helper.dart';
import 'package:dde_gesture_manager/utils/init.dart'; import 'package:dde_gesture_manager/utils/init.dart';
import 'package:dde_gesture_manager/utils/notificator.dart';
import 'package:dde_gesture_manager/utils/simple_throttle.dart'; import 'package:dde_gesture_manager/utils/simple_throttle.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -89,6 +90,7 @@ class MyApp extends StatelessWidget {
Sentry.captureMessage, Sentry.captureMessage,
timeout: const Duration(days: 1), timeout: const Duration(days: 1),
)?.call('App launched'); )?.call('App launched');
SimpleThrottle.throttledFunc(_checkBulletin, timeout: const Duration(days: 1))?.call(context);
}); });
return Container(); return Container();
}), }),
@ -112,3 +114,14 @@ void _checkAuthStatus(BuildContext context) {
H().lastCheckAuthStatusTime = DateTime.now(); H().lastCheckAuthStatusTime = DateTime.now();
} }
} }
void _checkBulletin(BuildContext context) {
Api.checkBulletin(kIsWeb).then((value) {
if (value != null && value.id != null) {
if (value.once == false || (H().sp.getInt(SPKeys.readBulletinId) ?? 0) < value.id!) {
Notificator.showAlert(title: value.title ?? '', description: value.content ?? '');
}
H().sp.setInt(SPKeys.readBulletinId, value.id!);
}
});
}

@ -46,6 +46,14 @@ class _DMarkdownFieldState extends State<DMarkdownField> {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
} }
VoidCallback? get _onMdPreviewTap => widget.readOnly
? null
: () {
setState(() {
_previewText = null;
});
};
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Focus( return Focus(
@ -62,19 +70,14 @@ class _DMarkdownFieldState extends State<DMarkdownField> {
), ),
child: isPreview child: isPreview
? GestureDetector( ? GestureDetector(
onTap: widget.readOnly onTap: _onMdPreviewTap,
? null
: () {
setState(() {
_previewText = null;
});
},
child: MouseRegion( child: MouseRegion(
cursor: widget.readOnly ? SystemMouseCursors.basic : SystemMouseCursors.text, cursor: widget.readOnly ? SystemMouseCursors.basic : SystemMouseCursors.text,
child: MdPreview( child: MdPreview(
text: _previewText ?? '', text: _previewText ?? '',
padding: EdgeInsets.only(left: 15), padding: EdgeInsets.only(left: 15),
onTapLink: H.launchURL, onTapLink: H.launchURL,
richTap: _onMdPreviewTap,
textStyle: context.t.textTheme.bodyText2, textStyle: context.t.textTheme.bodyText2,
onCodeCopied: () { onCodeCopied: () {
Notificator.success( Notificator.success(

@ -0,0 +1,6 @@
{
"id": 1,
"once": true,
"title": "欢迎",
"content": "感谢使用本工具,使用前建议先点击右下角阅读使用说明哦~"
}
Loading…
Cancel
Save