feat: add startup bulletin; switch to edit mode when click text on md preview.
This commit is contained in:
@@ -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';
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-13
@@ -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": "感谢使用本工具,使用前建议先点击右下角阅读使用说明哦~"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user