Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
d699cac9b1 | |||
c0428e12c1 | |||
55f434ff05 | |||
f2b3bdda2d | |||
1f6bf33b0e | |||
e2027b1a32 | |||
2b3a58b55e | |||
6ac536412a | |||
52f8ffe4e4 | |||
aca81431aa | |||
1fadd850b7 | |||
ed2a9a21b6 | |||
57279eb3e4 | |||
c403a2914a | |||
bcb176344c |
@ -181,6 +181,8 @@
|
|||||||
"settingsAppearance": "Appearance",
|
"settingsAppearance": "Appearance",
|
||||||
"settingsAppBarTransparent": "Transparent App Bar",
|
"settingsAppBarTransparent": "Transparent App Bar",
|
||||||
"settingsAppBarTransparentDescription": "Enable transparent effect for the app bar.",
|
"settingsAppBarTransparentDescription": "Enable transparent effect for the app bar.",
|
||||||
|
"settingsDrawerPreferCollapse": "Prefer Drawer Collapse",
|
||||||
|
"settingsDrawerPreferCollapseDescription": "Make the drawer to collapse even when the screen is wide enough.",
|
||||||
"settingsBackgroundImage": "Background Image",
|
"settingsBackgroundImage": "Background Image",
|
||||||
"settingsBackgroundImageDescription": "Set the background image that will be applied globally.",
|
"settingsBackgroundImageDescription": "Set the background image that will be applied globally.",
|
||||||
"settingsBackgroundImageClear": "Clear Existing Background Image",
|
"settingsBackgroundImageClear": "Clear Existing Background Image",
|
||||||
|
@ -185,6 +185,8 @@
|
|||||||
"settingsThemeMaterial3Description": "将应用主题设置为 Material 3 设计范式的主题。",
|
"settingsThemeMaterial3Description": "将应用主题设置为 Material 3 设计范式的主题。",
|
||||||
"settingsAppBarTransparent": "透明顶栏",
|
"settingsAppBarTransparent": "透明顶栏",
|
||||||
"settingsAppBarTransparentDescription": "为顶栏启用透明效果。",
|
"settingsAppBarTransparentDescription": "为顶栏启用透明效果。",
|
||||||
|
"settingsDrawerPreferCollapse": "侧边栏偏好折叠",
|
||||||
|
"settingsDrawerPreferCollapseDescription": "将侧边栏优先折叠,即使屏幕宽度足够大去放下整个侧边栏。",
|
||||||
"settingsColorScheme": "主题色",
|
"settingsColorScheme": "主题色",
|
||||||
"settingsColorSchemeDescription": "设置应用主题色。",
|
"settingsColorSchemeDescription": "设置应用主题色。",
|
||||||
"settingsColorSeed": "预设色彩主题",
|
"settingsColorSeed": "预设色彩主题",
|
||||||
|
@ -185,6 +185,8 @@
|
|||||||
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
|
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
|
||||||
"settingsAppBarTransparent": "透明頂欄",
|
"settingsAppBarTransparent": "透明頂欄",
|
||||||
"settingsAppBarTransparentDescription": "為頂欄啓用透明效果。",
|
"settingsAppBarTransparentDescription": "為頂欄啓用透明效果。",
|
||||||
|
"settingsDrawerPreferCollapse": "側邊欄偏好摺疊",
|
||||||
|
"settingsDrawerPreferCollapseDescription": "將側邊欄優先摺疊,即使屏幕寬度足夠大去放下整個側邊欄。",
|
||||||
"settingsColorScheme": "主題色",
|
"settingsColorScheme": "主題色",
|
||||||
"settingsColorSchemeDescription": "設置應用主題色。",
|
"settingsColorSchemeDescription": "設置應用主題色。",
|
||||||
"settingsColorSeed": "預設色彩主題",
|
"settingsColorSeed": "預設色彩主題",
|
||||||
|
@ -185,6 +185,8 @@
|
|||||||
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
|
"settingsThemeMaterial3Description": "將應用主題設置為 Material 3 設計範式的主題。",
|
||||||
"settingsAppBarTransparent": "透明頂欄",
|
"settingsAppBarTransparent": "透明頂欄",
|
||||||
"settingsAppBarTransparentDescription": "為頂欄啟用透明效果。",
|
"settingsAppBarTransparentDescription": "為頂欄啟用透明效果。",
|
||||||
|
"settingsDrawerPreferCollapse": "側邊欄偏好摺疊",
|
||||||
|
"settingsDrawerPreferCollapseDescription": "將側邊欄優先摺疊,即使屏幕寬度足夠大去放下整個側邊欄。",
|
||||||
"settingsColorScheme": "主題色",
|
"settingsColorScheme": "主題色",
|
||||||
"settingsColorSchemeDescription": "設置應用主題色。",
|
"settingsColorSchemeDescription": "設置應用主題色。",
|
||||||
"settingsColorSeed": "預設色彩主題",
|
"settingsColorSeed": "預設色彩主題",
|
||||||
|
@ -83,7 +83,6 @@ class ChatMessageController extends ChangeNotifier {
|
|||||||
if (member.id == profile?.id) break;
|
if (member.id == profile?.id) break;
|
||||||
if (!typingMembers.any((x) => x.id == member.id)) {
|
if (!typingMembers.any((x) => x.id == member.id)) {
|
||||||
typingMembers.add(member);
|
typingMembers.add(member);
|
||||||
print('Typing member: ${typingMembers.map((ele) => member.id)}');
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
typingInactiveTimer[member.id]?.cancel();
|
typingInactiveTimer[member.id]?.cancel();
|
||||||
|
@ -154,7 +154,10 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
final TextEditingController descriptionController = TextEditingController();
|
final TextEditingController descriptionController = TextEditingController();
|
||||||
final TextEditingController aliasController = TextEditingController();
|
final TextEditingController aliasController = TextEditingController();
|
||||||
|
|
||||||
PostWriteController() {
|
bool _temporarySaveActive = false;
|
||||||
|
|
||||||
|
PostWriteController({bool doLoadFromTemporary = true}) {
|
||||||
|
_temporarySaveActive = doLoadFromTemporary;
|
||||||
titleController.addListener(() {
|
titleController.addListener(() {
|
||||||
_temporaryPlanSave();
|
_temporaryPlanSave();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -166,7 +169,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
contentController.addListener(() {
|
contentController.addListener(() {
|
||||||
_temporaryPlanSave();
|
_temporaryPlanSave();
|
||||||
});
|
});
|
||||||
_temporaryLoad();
|
if (doLoadFromTemporary) _temporaryLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
String mode = kTitleMap.keys.first;
|
String mode = kTitleMap.keys.first;
|
||||||
@ -317,6 +320,7 @@ class PostWriteController extends ChangeNotifier {
|
|||||||
Timer? _temporarySaveTimer;
|
Timer? _temporarySaveTimer;
|
||||||
|
|
||||||
void _temporaryPlanSave() {
|
void _temporaryPlanSave() {
|
||||||
|
if (!_temporarySaveActive) return;
|
||||||
_temporarySaveTimer?.cancel();
|
_temporarySaveTimer?.cancel();
|
||||||
_temporarySaveTimer = Timer(const Duration(seconds: 1), () {
|
_temporarySaveTimer = Timer(const Duration(seconds: 1), () {
|
||||||
_temporarySave();
|
_temporarySave();
|
||||||
|
@ -258,6 +258,10 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
|
|||||||
|
|
||||||
Future<void> _initialize() async {
|
Future<void> _initialize() async {
|
||||||
try {
|
try {
|
||||||
|
final cfg = context.read<ConfigProvider>();
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
cfg.calcDrawerSize(context);
|
||||||
|
});
|
||||||
final home = context.read<HomeWidgetProvider>();
|
final home = context.read<HomeWidgetProvider>();
|
||||||
await home.initialize();
|
await home.initialize();
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
@ -298,6 +302,17 @@ class _AppSplashScreenState extends State<_AppSplashScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return widget.child;
|
final cfg = context.read<ConfigProvider>();
|
||||||
|
return NotificationListener<SizeChangedLayoutNotification>(
|
||||||
|
onNotification: (notification) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
cfg.calcDrawerSize(context);
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
child: SizeChangedLayoutNotifier(
|
||||||
|
child: widget.child,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:surface/providers/widget.dart';
|
import 'package:surface/providers/widget.dart';
|
||||||
|
|
||||||
@ -12,6 +13,7 @@ const kNetworkServerStoreKey = 'app_server_url';
|
|||||||
const kAppbarTransparentStoreKey = 'app_bar_transparent';
|
const kAppbarTransparentStoreKey = 'app_bar_transparent';
|
||||||
const kAppBackgroundStoreKey = 'app_has_background';
|
const kAppBackgroundStoreKey = 'app_has_background';
|
||||||
const kAppColorSchemeStoreKey = 'app_color_scheme';
|
const kAppColorSchemeStoreKey = 'app_color_scheme';
|
||||||
|
const kAppDrawerPreferCollapse = 'app_drawer_prefer_collapse';
|
||||||
|
|
||||||
const Map<String, FilterQuality> kImageQualityLevel = {
|
const Map<String, FilterQuality> kImageQualityLevel = {
|
||||||
'settingsImageQualityLowest': FilterQuality.none,
|
'settingsImageQualityLowest': FilterQuality.none,
|
||||||
@ -33,6 +35,24 @@ class ConfigProvider extends ChangeNotifier {
|
|||||||
prefs = await SharedPreferences.getInstance();
|
prefs = await SharedPreferences.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool drawerIsCollapsed = false;
|
||||||
|
bool drawerIsExpanded = false;
|
||||||
|
|
||||||
|
void calcDrawerSize(BuildContext context) {
|
||||||
|
final rpb = ResponsiveBreakpoints.of(context);
|
||||||
|
final newDrawerIsCollapsed = rpb.smallerOrEqualTo(MOBILE);
|
||||||
|
final newDrawerIsExpanded = rpb.largerThan(TABLET)
|
||||||
|
? (prefs.getBool(kAppDrawerPreferCollapse) ?? false)
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
: false;
|
||||||
|
if (newDrawerIsExpanded != drawerIsExpanded || newDrawerIsCollapsed != drawerIsCollapsed) {
|
||||||
|
drawerIsExpanded = newDrawerIsExpanded;
|
||||||
|
drawerIsCollapsed = newDrawerIsCollapsed;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FilterQuality get imageQuality {
|
FilterQuality get imageQuality {
|
||||||
return kImageQualityLevel.values.elementAtOrNull(prefs.getInt('app_image_quality') ?? 3) ?? FilterQuality.high;
|
return kImageQualityLevel.values.elementAtOrNull(prefs.getInt('app_image_quality') ?? 3) ?? FilterQuality.high;
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<void> connect({noRetry = false}) async {
|
Future<void> connect({noRetry = false}) async {
|
||||||
if (!_ua.isAuthorized) return;
|
if (!_ua.isAuthorized) return;
|
||||||
if (isConnected) {
|
if (isConnected || conn != null) {
|
||||||
disconnect();
|
disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ class WebSocketProvider extends ChangeNotifier {
|
|||||||
onError: (err) {
|
onError: (err) {
|
||||||
isConnected = false;
|
isConnected = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
Future.delayed(const Duration(seconds: 11), () => connect());
|
Future.delayed(const Duration(seconds: 1), () => connect());
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -206,10 +206,11 @@ class _NotificationScreenState extends State<NotificationScreen> {
|
|||||||
style: Theme.of(context).textTheme.titleSmall,
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
),
|
),
|
||||||
if (nty.subtitle != null) const Gap(4),
|
if (nty.subtitle != null) const Gap(4),
|
||||||
MarkdownTextContent(
|
SelectionArea(
|
||||||
|
child: MarkdownTextContent(
|
||||||
content: nty.body,
|
content: nty.body,
|
||||||
isAutoWarp: true,
|
isAutoWarp: true,
|
||||||
isSelectable: true,
|
),
|
||||||
),
|
),
|
||||||
if ([
|
if ([
|
||||||
'interactive.feedback',
|
'interactive.feedback',
|
||||||
|
@ -96,6 +96,8 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
)
|
)
|
||||||
: Text('postDetail').tr(),
|
: Text('postDetail').tr(),
|
||||||
),
|
),
|
||||||
|
@ -54,7 +54,9 @@ class PostEditorScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PostEditorScreenState extends State<PostEditorScreen> {
|
class _PostEditorScreenState extends State<PostEditorScreen> {
|
||||||
final PostWriteController _writeController = PostWriteController();
|
late final PostWriteController _writeController = PostWriteController(
|
||||||
|
doLoadFromTemporary: widget.postEditId == null,
|
||||||
|
);
|
||||||
|
|
||||||
bool _isFetching = false;
|
bool _isFetching = false;
|
||||||
|
|
||||||
|
@ -240,6 +240,19 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
CheckboxListTile(
|
||||||
|
secondary: const Icon(Symbols.left_panel_close),
|
||||||
|
title: Text('settingsDrawerPreferCollapse').tr(),
|
||||||
|
subtitle: Text('settingsDrawerPreferCollapseDescription').tr(),
|
||||||
|
contentPadding: const EdgeInsets.only(left: 24, right: 17),
|
||||||
|
value: _prefs.getBool(kAppDrawerPreferCollapse) ?? false,
|
||||||
|
onChanged: (value) {
|
||||||
|
_prefs.setBool(kAppDrawerPreferCollapse, value ?? false);
|
||||||
|
final cfg = context.read<ConfigProvider>();
|
||||||
|
cfg.calcDrawerSize(context);
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
|
@ -48,7 +48,7 @@ Future<ThemeData> createAppTheme(
|
|||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
elevation: hasAppBarBlurry ? 0 : null,
|
elevation: hasAppBarBlurry ? 0 : null,
|
||||||
backgroundColor: hasAppBarBlurry ? colorScheme.surfaceContainer.withAlpha(200) : colorScheme.primary,
|
backgroundColor: hasAppBarBlurry ? colorScheme.primary.withOpacity(0.3) : colorScheme.primary,
|
||||||
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
|
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
|
||||||
),
|
),
|
||||||
scaffoldBackgroundColor: Colors.transparent,
|
scaffoldBackgroundColor: Colors.transparent,
|
||||||
|
@ -329,7 +329,7 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
|
|||||||
)
|
)
|
||||||
else
|
else
|
||||||
Text(
|
Text(
|
||||||
'${item.size} Bytes',
|
item.size.formatBytes(),
|
||||||
style: metaTextStyle,
|
style: metaTextStyle,
|
||||||
),
|
),
|
||||||
if (item.metadata['width'] != null && item.metadata['height'] != null)
|
if (item.metadata['width'] != null && item.metadata['height'] != null)
|
||||||
|
@ -124,7 +124,7 @@ class ChatMessage extends StatelessWidget {
|
|||||||
dateFormatter.format(data.createdAt.toLocal()),
|
dateFormatter.format(data.createdAt.toLocal()),
|
||||||
).fontSize(13),
|
).fontSize(13),
|
||||||
],
|
],
|
||||||
),
|
).height(21),
|
||||||
if (isCompact) const Gap(8),
|
if (isCompact) const Gap(8),
|
||||||
if (data.preload?.quoteEvent != null)
|
if (data.preload?.quoteEvent != null)
|
||||||
StyledWidget(Container(
|
StyledWidget(Container(
|
||||||
@ -150,7 +150,12 @@ class ChatMessage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
)).padding(bottom: 4, top: 4),
|
)).padding(bottom: 4, top: 4),
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
'messages.new' => _ChatMessageText(data: data),
|
'messages.new' => _ChatMessageText(
|
||||||
|
data: data,
|
||||||
|
onReply: onReply,
|
||||||
|
onEdit: onEdit,
|
||||||
|
onDelete: onDelete,
|
||||||
|
),
|
||||||
_ => _ChatMessageSystemNotify(data: data),
|
_ => _ChatMessageSystemNotify(data: data),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -181,20 +186,73 @@ class ChatMessage extends StatelessWidget {
|
|||||||
|
|
||||||
class _ChatMessageText extends StatelessWidget {
|
class _ChatMessageText extends StatelessWidget {
|
||||||
final SnChatMessage data;
|
final SnChatMessage data;
|
||||||
|
final Function(SnChatMessage)? onReply;
|
||||||
|
final Function(SnChatMessage)? onEdit;
|
||||||
|
final Function(SnChatMessage)? onDelete;
|
||||||
|
|
||||||
const _ChatMessageText({required this.data});
|
const _ChatMessageText({required this.data, this.onReply, this.onEdit, this.onDelete});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final ua = context.read<UserProvider>();
|
||||||
|
|
||||||
|
final isOwner = ua.isAuthorized && data.sender.accountId == ua.user?.id;
|
||||||
|
|
||||||
if (data.body['text'] != null && data.body['text'].isNotEmpty) {
|
if (data.body['text'] != null && data.body['text'].isNotEmpty) {
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
MarkdownTextContent(
|
SelectionArea(
|
||||||
|
contextMenuBuilder: (context, editableTextState) {
|
||||||
|
final List<ContextMenuButtonItem> items = editableTextState.contextMenuButtonItems;
|
||||||
|
|
||||||
|
if (onReply != null) {
|
||||||
|
items.insert(
|
||||||
|
0,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: 'reply'.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
ContextMenuController.removeAny();
|
||||||
|
onReply?.call(data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isOwner && onEdit != null) {
|
||||||
|
items.insert(
|
||||||
|
1,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: 'edit'.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
ContextMenuController.removeAny();
|
||||||
|
onEdit?.call(data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (isOwner && onDelete != null) {
|
||||||
|
items.insert(
|
||||||
|
2,
|
||||||
|
ContextMenuButtonItem(
|
||||||
|
label: 'delete'.tr(),
|
||||||
|
onPressed: () {
|
||||||
|
ContextMenuController.removeAny();
|
||||||
|
onDelete?.call(data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AdaptiveTextSelectionToolbar.buttonItems(
|
||||||
|
anchors: editableTextState.contextMenuAnchors,
|
||||||
|
buttonItems: items,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: MarkdownTextContent(
|
||||||
content: data.body['text'],
|
content: data.body['text'],
|
||||||
isSelectable: true,
|
|
||||||
isAutoWarp: true,
|
isAutoWarp: true,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
if (data.updatedAt != data.createdAt)
|
if (data.updatedAt != data.createdAt)
|
||||||
Text(
|
Text(
|
||||||
'messageEditedHint'.tr(),
|
'messageEditedHint'.tr(),
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_animate/flutter_animate.dart';
|
import 'package:flutter_animate/flutter_animate.dart';
|
||||||
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
|
|
||||||
class ContextMenuArea extends StatelessWidget {
|
class ContextMenuArea extends StatelessWidget {
|
||||||
final ContextMenu contextMenu;
|
final ContextMenu contextMenu;
|
||||||
@ -22,11 +23,10 @@ class ContextMenuArea extends StatelessWidget {
|
|||||||
return Listener(
|
return Listener(
|
||||||
onPointerDown: (event) {
|
onPointerDown: (event) {
|
||||||
mousePosition = event.position;
|
mousePosition = event.position;
|
||||||
final isCollapseDrawer = ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE);
|
final cfg = context.read<ConfigProvider>();
|
||||||
if (!isCollapseDrawer) {
|
if (!cfg.drawerIsCollapsed) {
|
||||||
final isExpandDrawer = ResponsiveBreakpoints.of(context).largerThan(TABLET);
|
|
||||||
// Leave padding for side navigation
|
// Leave padding for side navigation
|
||||||
mousePosition = isExpandDrawer
|
mousePosition = cfg.drawerIsExpanded
|
||||||
? mousePosition.copyWith(dx: mousePosition.dx - 304 * 2)
|
? mousePosition.copyWith(dx: mousePosition.dx - 304 * 2)
|
||||||
: mousePosition.copyWith(dx: mousePosition.dx - 72 * 2);
|
: mousePosition.copyWith(dx: mousePosition.dx - 72 * 2);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'dart:ui';
|
|
||||||
|
|
||||||
import 'package:dismissible_page/dismissible_page.dart';
|
import 'package:dismissible_page/dismissible_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
@ -7,22 +5,18 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:markdown/markdown.dart' as markdown;
|
import 'package:markdown/markdown.dart' as markdown;
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/sn_sticker.dart';
|
import 'package:surface/providers/sn_sticker.dart';
|
||||||
import 'package:surface/types/attachment.dart';
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/widgets/attachment/attachment_item.dart';
|
import 'package:surface/widgets/attachment/attachment_item.dart';
|
||||||
import 'package:surface/widgets/universal_image.dart';
|
import 'package:surface/widgets/universal_image.dart';
|
||||||
import 'package:syntax_highlight/syntax_highlight.dart';
|
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
import 'package:path/path.dart';
|
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
import 'attachment/attachment_zoom.dart';
|
import 'attachment/attachment_zoom.dart';
|
||||||
|
|
||||||
class MarkdownTextContent extends StatelessWidget {
|
class MarkdownTextContent extends StatelessWidget {
|
||||||
final String content;
|
final String content;
|
||||||
final bool isSelectable;
|
|
||||||
final bool isAutoWarp;
|
final bool isAutoWarp;
|
||||||
final bool isEnlargeSticker;
|
final bool isEnlargeSticker;
|
||||||
final TextScaler? textScaler;
|
final TextScaler? textScaler;
|
||||||
@ -31,14 +25,14 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
const MarkdownTextContent({
|
const MarkdownTextContent({
|
||||||
super.key,
|
super.key,
|
||||||
required this.content,
|
required this.content,
|
||||||
this.isSelectable = false,
|
|
||||||
this.isAutoWarp = false,
|
this.isAutoWarp = false,
|
||||||
this.isEnlargeSticker = false,
|
this.isEnlargeSticker = false,
|
||||||
this.textScaler,
|
this.textScaler,
|
||||||
this.attachments,
|
this.attachments,
|
||||||
});
|
});
|
||||||
|
|
||||||
Widget _buildContent(BuildContext context) {
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
return Markdown(
|
return Markdown(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
@ -70,10 +64,10 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
||||||
color: Theme.of(context).colorScheme.surface.withOpacity(0.5),
|
color: Theme.of(context).colorScheme.surface.withOpacity(0.5),
|
||||||
)),
|
),
|
||||||
builders: {
|
code: GoogleFonts.robotoMono(height: 1),
|
||||||
'code': _MarkdownTextCodeElement(),
|
),
|
||||||
},
|
builders: {},
|
||||||
softLineBreak: true,
|
softLineBreak: true,
|
||||||
extensionSet: markdown.ExtensionSet(
|
extensionSet: markdown.ExtensionSet(
|
||||||
<markdown.BlockSyntax>[
|
<markdown.BlockSyntax>[
|
||||||
@ -206,14 +200,6 @@ class MarkdownTextContent extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
if (isSelectable) {
|
|
||||||
return SelectionArea(child: _buildContent(context));
|
|
||||||
}
|
|
||||||
return _buildContent(context);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _UserNameCardInlineSyntax extends markdown.InlineSyntax {
|
class _UserNameCardInlineSyntax extends markdown.InlineSyntax {
|
||||||
@ -253,46 +239,3 @@ class _CustomEmoteInlineSyntax extends markdown.InlineSyntax {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MarkdownTextCodeElement extends MarkdownElementBuilder {
|
|
||||||
@override
|
|
||||||
Widget? visitElementAfter(
|
|
||||||
markdown.Element element,
|
|
||||||
TextStyle? preferredStyle,
|
|
||||||
) {
|
|
||||||
var language = '';
|
|
||||||
|
|
||||||
if (element.attributes['class'] != null) {
|
|
||||||
String lg = element.attributes['class'] as String;
|
|
||||||
language = lg.substring(9).trim();
|
|
||||||
}
|
|
||||||
return SizedBox(
|
|
||||||
child: FutureBuilder(
|
|
||||||
future: (() async {
|
|
||||||
final docPath = '../../../';
|
|
||||||
final highlightingPath = join(docPath, 'assets/highlighting', language);
|
|
||||||
await Highlighter.initialize([highlightingPath]);
|
|
||||||
return Highlighter(
|
|
||||||
language: highlightingPath,
|
|
||||||
theme: PlatformDispatcher.instance.platformBrightness == Brightness.light
|
|
||||||
? await HighlighterTheme.loadLightTheme()
|
|
||||||
: await HighlighterTheme.loadDarkTheme(),
|
|
||||||
);
|
|
||||||
})(),
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
final highlighter = snapshot.data!;
|
|
||||||
return Text.rich(
|
|
||||||
highlighter.highlight(element.textContent.trim()),
|
|
||||||
style: GoogleFonts.robotoMono(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
element.textContent.trim(),
|
|
||||||
style: GoogleFonts.robotoMono(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
).padding(all: 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:bitsdojo_window/bitsdojo_window.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/navigation.dart';
|
import 'package:surface/providers/navigation.dart';
|
||||||
import 'package:surface/widgets/version_label.dart';
|
import 'package:surface/widgets/version_label.dart';
|
||||||
|
|
||||||
@ -28,8 +32,9 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final nav = context.watch<NavigationProvider>();
|
final nav = context.watch<NavigationProvider>();
|
||||||
|
final cfg = context.watch<ConfigProvider>();
|
||||||
|
|
||||||
final backgroundColor = ResponsiveBreakpoints.of(context).largerThan(TABLET) ? Colors.transparent : null;
|
final backgroundColor = cfg.drawerIsExpanded ? Colors.transparent : null;
|
||||||
|
|
||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
listenable: nav,
|
listenable: nav,
|
||||||
@ -44,6 +49,18 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
|||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
selectedIndex: nav.currentIndex,
|
selectedIndex: nav.currentIndex,
|
||||||
children: [
|
children: [
|
||||||
|
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS))
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: Theme.of(context).dividerColor,
|
||||||
|
width: 1 / MediaQuery.of(context).devicePixelRatio,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: WindowTitleBarBox(),
|
||||||
|
),
|
||||||
Column(
|
Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -6,8 +6,10 @@ import 'package:flutter/foundation.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:responsive_framework/responsive_framework.dart';
|
import 'package:responsive_framework/responsive_framework.dart';
|
||||||
import 'package:styled_widget/styled_widget.dart';
|
import 'package:styled_widget/styled_widget.dart';
|
||||||
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/navigation.dart';
|
import 'package:surface/providers/navigation.dart';
|
||||||
import 'package:surface/widgets/connection_indicator.dart';
|
import 'package:surface/widgets/connection_indicator.dart';
|
||||||
import 'package:surface/widgets/dialog.dart';
|
import 'package:surface/widgets/dialog.dart';
|
||||||
@ -57,10 +59,11 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cfg = context.watch<ConfigProvider>();
|
||||||
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
|
||||||
|
|
||||||
final isCollapseDrawer = ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE);
|
final isCollapseDrawer = cfg.drawerIsCollapsed;
|
||||||
final isExpandDrawer = ResponsiveBreakpoints.of(context).largerThan(TABLET);
|
final isExpandedDrawer = cfg.drawerIsExpanded;
|
||||||
|
|
||||||
final routeName = GoRouter.of(context).routerDelegate.currentConfiguration.last.route.name;
|
final routeName = GoRouter.of(context).routerDelegate.currentConfiguration.last.route.name;
|
||||||
final isShowBottomNavigation = NavigationProvider.kShowBottomNavScreen.contains(routeName)
|
final isShowBottomNavigation = NavigationProvider.kShowBottomNavScreen.contains(routeName)
|
||||||
@ -81,7 +84,7 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: isExpandDrawer ? AppNavigationDrawer(elevation: 0) : AppRailNavigation(),
|
child: isExpandedDrawer ? AppNavigationDrawer(elevation: 0) : AppRailNavigation(),
|
||||||
),
|
),
|
||||||
Expanded(child: body),
|
Expanded(child: body),
|
||||||
],
|
],
|
||||||
@ -147,7 +150,7 @@ class AppRootScaffold extends StatelessWidget {
|
|||||||
Expanded(child: innerWidget),
|
Expanded(child: innerWidget),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
drawer: !isExpandDrawer ? AppNavigationDrawer() : null,
|
drawer: !isExpandedDrawer ? AppNavigationDrawer() : null,
|
||||||
drawerEdgeDragWidth: isPopable ? 0 : null,
|
drawerEdgeDragWidth: isPopable ? 0 : null,
|
||||||
bottomNavigationBar: isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
bottomNavigationBar: isShowBottomNavigation ? AppBottomNavigationBar() : null,
|
||||||
),
|
),
|
||||||
|
@ -20,6 +20,7 @@ import 'package:styled_widget/styled_widget.dart';
|
|||||||
import 'package:surface/providers/config.dart';
|
import 'package:surface/providers/config.dart';
|
||||||
import 'package:surface/providers/sn_network.dart';
|
import 'package:surface/providers/sn_network.dart';
|
||||||
import 'package:surface/providers/userinfo.dart';
|
import 'package:surface/providers/userinfo.dart';
|
||||||
|
import 'package:surface/types/attachment.dart';
|
||||||
import 'package:surface/types/post.dart';
|
import 'package:surface/types/post.dart';
|
||||||
import 'package:surface/types/reaction.dart';
|
import 'package:surface/types/reaction.dart';
|
||||||
import 'package:surface/widgets/account/account_image.dart';
|
import 'package:surface/widgets/account/account_image.dart';
|
||||||
@ -112,7 +113,7 @@ class PostItem extends StatelessWidget {
|
|||||||
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await FileSaver.instance.saveFile(name: 'Solar Network Post #${data.id}', file: imageFile);
|
await FileSaver.instance.saveFile(name: 'Solar Network Post #${data.id}.png', file: imageFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
await imageFile.delete();
|
await imageFile.delete();
|
||||||
@ -198,6 +199,10 @@ class PostItem extends StatelessWidget {
|
|||||||
).center();
|
).center();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final displayableAttachments = data.preload?.attachments
|
||||||
|
?.where((ele) => ele?.mediaType != SnMediaType.image || data.type != 'article')
|
||||||
|
.toList();
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -247,9 +252,9 @@ class PostItem extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if ((data.preload?.attachments?.isNotEmpty ?? false) && data.type != 'article')
|
if (displayableAttachments?.isNotEmpty ?? false)
|
||||||
AttachmentList(
|
AttachmentList(
|
||||||
data: data.preload!.attachments!,
|
data: displayableAttachments!,
|
||||||
bordered: true,
|
bordered: true,
|
||||||
gridded: true,
|
gridded: true,
|
||||||
maxHeight: showFullPost ? null : 480,
|
maxHeight: showFullPost ? null : 480,
|
||||||
@ -874,13 +879,17 @@ class _PostContentBody extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (data.body['content'] == null) return const SizedBox.shrink();
|
if (data.body['content'] == null) return const SizedBox.shrink();
|
||||||
return MarkdownTextContent(
|
final content = MarkdownTextContent(
|
||||||
isSelectable: isSelectable,
|
|
||||||
isEnlargeSticker: true,
|
isEnlargeSticker: true,
|
||||||
textScaler: isEnlarge ? TextScaler.linear(1.1) : null,
|
textScaler: isEnlarge ? TextScaler.linear(1.1) : null,
|
||||||
content: data.body['content'],
|
content: data.body['content'],
|
||||||
attachments: data.preload?.attachments,
|
attachments: data.preload?.attachments,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isSelectable) {
|
||||||
|
return SelectionArea(child: content);
|
||||||
|
}
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ class PostMiniEditor extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _PostMiniEditorState extends State<PostMiniEditor> {
|
class _PostMiniEditorState extends State<PostMiniEditor> {
|
||||||
final PostWriteController _writeController = PostWriteController();
|
final PostWriteController _writeController = PostWriteController(doLoadFromTemporary: false);
|
||||||
|
|
||||||
bool _isFetching = false;
|
bool _isFetching = false;
|
||||||
|
|
||||||
|
@ -55,7 +55,9 @@ class UniversalImage extends StatelessWidget {
|
|||||||
? null
|
? null
|
||||||
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
|
||||||
if (loadingProgress == null) return child;
|
if (loadingProgress == null) return child;
|
||||||
return Center(
|
return Container(
|
||||||
|
constraints: BoxConstraints(maxHeight: 80),
|
||||||
|
child: Center(
|
||||||
child: TweenAnimationBuilder(
|
child: TweenAnimationBuilder(
|
||||||
tween: Tween(
|
tween: Tween(
|
||||||
begin: 0,
|
begin: 0,
|
||||||
@ -68,6 +70,7 @@ class UniversalImage extends StatelessWidget {
|
|||||||
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
|
value: loadingProgress.expectedTotalBytes != null ? value.toDouble() : null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
errorBuilder: noErrorWidget
|
errorBuilder: noErrorWidget
|
||||||
|
22
pubspec.lock
22
pubspec.lock
@ -618,10 +618,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: fl_chart
|
name: fl_chart
|
||||||
sha256: c724234b05e378383e958f3e82ca84a3e1e3c06a0898462044dd8a24b1ee9864
|
sha256: "10ddaf334fe84d59333a12d153043e366f243e0bdfff2df0313e1e249f5bf926"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.70.0"
|
version: "0.70.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -700,10 +700,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_markdown
|
name: flutter_markdown
|
||||||
sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e"
|
sha256: e37f4c69a07b07bb92622ef6b131a53c9aae48f64b176340af9e8e5238718487
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.4+3"
|
version: "0.7.5"
|
||||||
flutter_native_splash:
|
flutter_native_splash:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description:
|
description:
|
||||||
@ -822,10 +822,10 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: go_router
|
name: go_router
|
||||||
sha256: "2fd11229f59e23e967b0775df8d5948a519cd7e1e8b6e849729e010587b46539"
|
sha256: "7c2d40b59890a929824f30d442e810116caf5088482629c894b9e4478c67472d"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "14.6.2"
|
version: "14.6.3"
|
||||||
google_fonts:
|
google_fonts:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1863,14 +1863,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.3.0+3"
|
version: "3.3.0+3"
|
||||||
syntax_highlight:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: syntax_highlight
|
|
||||||
sha256: ee33b6aa82cc722bb9b40152a792181dee222353b486c0255fde666a3e3a4997
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.4.0"
|
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -2177,4 +2169,4 @@ packages:
|
|||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.6.0 <4.0.0"
|
dart: ">=3.6.0 <4.0.0"
|
||||||
flutter: ">=3.27.0"
|
flutter: ">=3.24.0"
|
||||||
|
@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 2.2.1+47
|
version: 2.2.2+51
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.5.4
|
sdk: ^3.5.4
|
||||||
@ -54,7 +54,6 @@ dependencies:
|
|||||||
flutter_markdown: ^0.7.4+1
|
flutter_markdown: ^0.7.4+1
|
||||||
url_launcher: ^6.3.1
|
url_launcher: ^6.3.1
|
||||||
flutter_animate: ^4.5.0
|
flutter_animate: ^4.5.0
|
||||||
syntax_highlight: ^0.4.0
|
|
||||||
google_fonts: ^6.2.1
|
google_fonts: ^6.2.1
|
||||||
path: ^1.9.0
|
path: ^1.9.0
|
||||||
relative_time: ^5.0.0
|
relative_time: ^5.0.0
|
||||||
|
Reference in New Issue
Block a user