hmmm
This commit is contained in:
parent
383fb16298
commit
c6fe34e66e
|
@ -1,5 +1,7 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:localization/localization.dart';
|
||||||
import 'package:loris/business_logic/account/account.dart';
|
import 'package:loris/business_logic/account/account.dart';
|
||||||
import 'package:loris/business_logic/timeline/media.dart';
|
import 'package:loris/business_logic/timeline/media.dart';
|
||||||
import '../../global.dart' as global;
|
import '../../global.dart' as global;
|
||||||
|
@ -25,6 +27,32 @@ extension VisibilityExtension on Visibility {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String get name {
|
||||||
|
switch (this) {
|
||||||
|
case Visibility.direct:
|
||||||
|
return "direct-visibility".i18n();
|
||||||
|
case Visibility.private:
|
||||||
|
return "private-visibility".i18n();
|
||||||
|
case Visibility.public:
|
||||||
|
return "public-visibility".i18n();
|
||||||
|
case Visibility.unlisted:
|
||||||
|
return "unlisted-visibility".i18n();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconData get icon {
|
||||||
|
switch (this) {
|
||||||
|
case Visibility.direct:
|
||||||
|
return Icons.message;
|
||||||
|
case Visibility.private:
|
||||||
|
return Icons.lock;
|
||||||
|
case Visibility.public:
|
||||||
|
return Icons.public;
|
||||||
|
case Visibility.unlisted:
|
||||||
|
return Icons.lock_open;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PostModel implements Comparable {
|
class PostModel implements Comparable {
|
||||||
|
|
|
@ -40,6 +40,13 @@
|
||||||
"interacted-with-you": "interacted with you",
|
"interacted-with-you": "interacted with you",
|
||||||
"on-remote-instance": "on remote instance",
|
"on-remote-instance": "on remote instance",
|
||||||
"reblog": "reblog",
|
"reblog": "reblog",
|
||||||
"like": "like"
|
"like": "like",
|
||||||
|
"load-older-notifications": "load older notifications",
|
||||||
|
"copied-post-by": "copied link to post by:",
|
||||||
|
"copy-url-to-clipboard": "copy url to clipboard",
|
||||||
|
"unlisted-visibility": "unlisted",
|
||||||
|
"public-visibility": "public",
|
||||||
|
"private-visibility": "private",
|
||||||
|
"direct-visibility": "dm"
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:localization/localization.dart';
|
import 'package:localization/localization.dart';
|
||||||
import 'package:loris/business_logic/notifications/notifs.dart';
|
import 'package:loris/business_logic/notifications/notifs.dart';
|
||||||
import 'package:loris/pages/notifications/single_notif.dart';
|
import 'package:loris/pages/notifications/single_notif.dart';
|
||||||
|
import 'package:loris/partials/loadingbox.dart';
|
||||||
import '../../business_logic/websocket.dart' as websocket;
|
import '../../business_logic/websocket.dart' as websocket;
|
||||||
|
|
||||||
final notifStream = StreamController<int>.broadcast();
|
final notifStream = StreamController<int>.broadcast();
|
||||||
|
@ -41,6 +42,21 @@ class _NotificationsState extends State<Notifications> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reload() {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_controller.animateTo(
|
||||||
|
0,
|
||||||
|
duration: const Duration(seconds: 1),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
);
|
||||||
|
maxIdData = {};
|
||||||
|
notifs = [const LoadingBox()];
|
||||||
|
});
|
||||||
|
loadMore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -96,7 +112,19 @@ class _NotificationsState extends State<Notifications> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Container(),
|
Container(
|
||||||
|
color: Theme.of(context).colorScheme.surface,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
reload();
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.refresh))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.separated(
|
child: ListView.separated(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
|
|
@ -231,9 +231,11 @@ class _InteractionButtonState extends State<InteractionButton> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return Column(
|
return SingleChildScrollView(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
child: Column(
|
||||||
children: c,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: c,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,11 @@ class Post extends StatefulWidget {
|
||||||
required this.model,
|
required this.model,
|
||||||
Key? key,
|
Key? key,
|
||||||
this.reblogVisible = true,
|
this.reblogVisible = true,
|
||||||
|
this.hideSensitive = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final tl.PostModel model;
|
final tl.PostModel model;
|
||||||
final bool reblogVisible;
|
final bool reblogVisible;
|
||||||
|
final bool hideSensitive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<Post> createState() => _PostState();
|
State<Post> createState() => _PostState();
|
||||||
|
@ -35,6 +37,7 @@ class _PostState extends State<Post> {
|
||||||
content: widget.model.content,
|
content: widget.model.content,
|
||||||
spoilerText: widget.model.spoilerText,
|
spoilerText: widget.model.spoilerText,
|
||||||
media: widget.model.attachments,
|
media: widget.model.attachments,
|
||||||
|
forceShow: !widget.hideSensitive,
|
||||||
),
|
),
|
||||||
PostActionBar(model: widget.model),
|
PostActionBar(model: widget.model),
|
||||||
RebloggedBy(
|
RebloggedBy(
|
||||||
|
@ -163,11 +166,13 @@ class PostBody extends StatefulWidget {
|
||||||
required this.spoilerText,
|
required this.spoilerText,
|
||||||
required this.content,
|
required this.content,
|
||||||
required this.media,
|
required this.media,
|
||||||
|
required this.forceShow,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final String content;
|
final String content;
|
||||||
final String spoilerText;
|
final String spoilerText;
|
||||||
final bool sensitive;
|
final bool sensitive;
|
||||||
|
final bool forceShow;
|
||||||
final List<MediaAttachmentModel> media;
|
final List<MediaAttachmentModel> media;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -178,11 +183,15 @@ class _PostBodyState extends State<PostBody> {
|
||||||
bool visible = false;
|
bool visible = false;
|
||||||
String cwButtonText = "show".i18n();
|
String cwButtonText = "show".i18n();
|
||||||
Icon cwButtonIcon = const Icon(Icons.visibility);
|
Icon cwButtonIcon = const Icon(Icons.visibility);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
visible = !widget.sensitive;
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (!widget.sensitive) {
|
|
||||||
visible = true;
|
|
||||||
}
|
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.fromLTRB(0, 6, 0, 6),
|
padding: const EdgeInsets.fromLTRB(0, 6, 0, 6),
|
||||||
|
@ -190,44 +199,50 @@ class _PostBodyState extends State<PostBody> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: widget.sensitive,
|
visible: widget.forceShow ? false : widget.sensitive,
|
||||||
child: SelectableText.rich(
|
child: Column(
|
||||||
TextSpan(
|
children: [
|
||||||
text: "",
|
SelectableText.rich(
|
||||||
children: [
|
TextSpan(
|
||||||
WidgetSpan(
|
children: [
|
||||||
child: OutlinedButton.icon(
|
WidgetSpan(
|
||||||
onPressed: () {
|
child: OutlinedButton.icon(
|
||||||
setState(() {
|
onPressed: () {
|
||||||
visible = !visible;
|
setState(() {
|
||||||
if (visible) {
|
visible = !visible;
|
||||||
cwButtonIcon = const Icon(Icons.visibility_off);
|
if (visible) {
|
||||||
cwButtonText = "hide".i18n();
|
cwButtonIcon = const Icon(Icons.visibility_off);
|
||||||
} else {
|
cwButtonText = "hide".i18n();
|
||||||
cwButtonText = "show".i18n();
|
} else {
|
||||||
cwButtonIcon = const Icon(Icons.visibility);
|
cwButtonText = "show".i18n();
|
||||||
}
|
cwButtonIcon = const Icon(Icons.visibility);
|
||||||
});
|
}
|
||||||
},
|
});
|
||||||
icon: cwButtonIcon,
|
},
|
||||||
label: Text(cwButtonText),
|
icon: cwButtonIcon,
|
||||||
),
|
label: Text(cwButtonText),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const WidgetSpan(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 8,
|
||||||
|
)),
|
||||||
|
TextSpan(text: widget.spoilerText),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
const WidgetSpan(
|
),
|
||||||
child: SizedBox(
|
const SizedBox(
|
||||||
width: 8,
|
height: 8,
|
||||||
)),
|
)
|
||||||
TextSpan(text: widget.spoilerText),
|
],
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: visible,
|
visible: visible || widget.forceShow,
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
PostTextRenderer(htmlInput: widget.content),
|
PostTextRenderer(input: widget.content),
|
||||||
MediaAttachments(models: widget.media),
|
MediaAttachments(models: widget.media),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,43 +4,106 @@ import 'package:loris/business_logic/interactions/interactions.dart';
|
||||||
import 'package:loris/business_logic/timeline/timeline.dart';
|
import 'package:loris/business_logic/timeline/timeline.dart';
|
||||||
import 'package:loris/partials/interaction_button.dart';
|
import 'package:loris/partials/interaction_button.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
import 'package:clipboard/clipboard.dart';
|
||||||
|
|
||||||
void popupPostOptions(context, PostModel model) {
|
void popupPostOptions(context, PostModel model) {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) => PostOptions(model: model),
|
||||||
List<Widget?> c = [
|
|
||||||
SelectableText("post-options".i18n(),
|
|
||||||
style: Theme.of(context).textTheme.displayMedium),
|
|
||||||
SelectableText(model.createdAt),
|
|
||||||
TextButton.icon(
|
|
||||||
onPressed: () {
|
|
||||||
launchUrl(
|
|
||||||
Uri.parse(model.uri),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
icon: const Icon(Icons.open_in_browser),
|
|
||||||
label: Text("show-in-browser".i18n()),
|
|
||||||
),
|
|
||||||
model.visibility.boostable
|
|
||||||
? InteractionButton(
|
|
||||||
model: model,
|
|
||||||
type: InteractionType.reblog,
|
|
||||||
extended: true,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
InteractionButton(
|
|
||||||
model: model,
|
|
||||||
type: InteractionType.favorite,
|
|
||||||
extended: true,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
return Scrollable(
|
|
||||||
viewportBuilder: ((context, position) =>
|
|
||||||
Column(mainAxisAlignment: MainAxisAlignment.center, children: [
|
|
||||||
for (var i in c)
|
|
||||||
if (i != null) i
|
|
||||||
])));
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PostOptions extends StatefulWidget {
|
||||||
|
const PostOptions({Key? key, required this.model}) : super(key: key);
|
||||||
|
final PostModel model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PostOptions> createState() => _PostOptionsState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PostOptionsState extends State<PostOptions> {
|
||||||
|
bool justCopied = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Widget?> c = [
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
SelectableText("post-options".i18n(),
|
||||||
|
style: Theme.of(context).textTheme.displayMedium),
|
||||||
|
SelectableText(
|
||||||
|
widget.model.createdAt
|
||||||
|
.replaceAll("T", " ")
|
||||||
|
.replaceAll("-", ".")
|
||||||
|
.substring(0, 19),
|
||||||
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Icon(widget.model.visibility.icon),
|
||||||
|
SelectableText(widget.model.visibility.name),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
FlutterClipboard.copy(widget.model.uri);
|
||||||
|
setState(() {
|
||||||
|
justCopied = true;
|
||||||
|
});
|
||||||
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
justCopied = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.copy),
|
||||||
|
label: Text(
|
||||||
|
justCopied
|
||||||
|
? "${"copied-post-by".i18n()} ${widget.model.account.acct}"
|
||||||
|
: "copy-url-to-clipboard".i18n(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
launchUrl(
|
||||||
|
Uri.parse(widget.model.uri),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.open_in_browser),
|
||||||
|
label: Text(
|
||||||
|
"show-in-browser".i18n(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
widget.model.visibility.boostable
|
||||||
|
? InteractionButton(
|
||||||
|
model: widget.model,
|
||||||
|
type: InteractionType.reblog,
|
||||||
|
extended: true,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
InteractionButton(
|
||||||
|
model: widget.model,
|
||||||
|
type: InteractionType.favorite,
|
||||||
|
extended: true,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
for (var i in c)
|
||||||
|
if (i != null) i
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,59 +1,29 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:html/dom.dart' as dom;
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'package:html/parser.dart' as parser;
|
import 'package:html2md/html2md.dart' as html2md;
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
class PostTextRenderer extends StatelessWidget {
|
class PostTextRenderer extends StatelessWidget {
|
||||||
const PostTextRenderer({
|
const PostTextRenderer({
|
||||||
required this.htmlInput,
|
required this.input,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
final String htmlInput;
|
final String input;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
dom.Document document = parser.parse(htmlInput);
|
MarkdownStyleSheet mdStyle = MarkdownStyleSheet(
|
||||||
final List<InlineSpan> children =
|
a: TextStyle(color: Theme.of(context).colorScheme.secondary));
|
||||||
createSpansFromDoc(document.body!.children);
|
String s = html2md.convert(input);
|
||||||
return SelectableText.rich(
|
return MarkdownBody(
|
||||||
TextSpan(
|
onTapLink: ((text, href, title) {
|
||||||
style: Theme.of(context).textTheme.bodyMedium,
|
if (href != null) {
|
||||||
text: "",
|
launchUrl(Uri.parse(href));
|
||||||
children: children,
|
}
|
||||||
),
|
}),
|
||||||
|
styleSheet: mdStyle,
|
||||||
|
data: s,
|
||||||
|
selectable: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<InlineSpan> createSpansFromDoc(List<dom.Element> elements) {
|
|
||||||
List<InlineSpan> result = [];
|
|
||||||
for (int i = 0; i < elements.length; i += 1) {
|
|
||||||
final e = elements[i];
|
|
||||||
result.add(
|
|
||||||
getSpanForElement(
|
|
||||||
e,
|
|
||||||
elements.length,
|
|
||||||
i,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineSpan getSpanForElement(dom.Element e, int bodyLength, int pos) {
|
|
||||||
if (e.toString() == "<html p>") {
|
|
||||||
return handleParagraph(e, bodyLength, pos);
|
|
||||||
}
|
|
||||||
return TextSpan(text: e.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
InlineSpan handleParagraph(dom.Element e, int bodyLength, int pos) {
|
|
||||||
String text = e.text;
|
|
||||||
return WidgetSpan(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.fromLTRB(0, 4, 0, 4),
|
|
||||||
child: SelectableText(
|
|
||||||
text,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,17 +1,53 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:localization/localization.dart';
|
||||||
import 'package:loris/partials/post.dart';
|
import 'package:loris/partials/post.dart';
|
||||||
import '../business_logic/timeline/timeline.dart' as logic;
|
import '../business_logic/timeline/timeline.dart' as logic;
|
||||||
import '../global.dart' as global;
|
import '../global.dart' as global;
|
||||||
|
|
||||||
class Thread extends StatelessWidget {
|
class Thread extends StatefulWidget {
|
||||||
const Thread({required this.model, Key? key}) : super(key: key);
|
const Thread({required this.model, Key? key}) : super(key: key);
|
||||||
final logic.ThreadModel model;
|
final logic.ThreadModel model;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<Thread> createState() => _ThreadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ThreadState extends State<Thread> {
|
||||||
|
bool anySensitivePosts = false;
|
||||||
|
bool showSensitive = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
List<Post> posts = [];
|
List<Widget> c = [];
|
||||||
for (int i = 0; i < model.posts.length; i++) {
|
for (var element in widget.model.posts) {
|
||||||
posts.add(Post(model: model.posts[i]));
|
c.add(Post(
|
||||||
|
model: element,
|
||||||
|
hideSensitive: !showSensitive,
|
||||||
|
));
|
||||||
|
if (element.sensitive) {
|
||||||
|
anySensitivePosts = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (anySensitivePosts && c.length > 1) {
|
||||||
|
c.insert(
|
||||||
|
0,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
OutlinedButton.icon(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
showSensitive = !showSensitive;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon:
|
||||||
|
Icon(showSensitive ? Icons.visibility_off : Icons.visibility),
|
||||||
|
label: Text(showSensitive ? "hide".i18n() : "show".i18n()),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
|
@ -35,7 +71,7 @@ class Thread extends StatelessWidget {
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: posts,
|
children: c,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||||
import 'dracula.dart' as color_dracula;
|
import 'dracula.dart' as color_dracula;
|
||||||
|
|
||||||
// color schemes to pick from can be added here
|
// color schemes to pick from can be added here
|
||||||
|
|
39
pubspec.lock
39
pubspec.lock
|
@ -1,6 +1,13 @@
|
||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -29,6 +36,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
clipboard:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: clipboard
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.3"
|
||||||
clock:
|
clock:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -84,7 +98,7 @@ packages:
|
||||||
name: file
|
name: file
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.1.2"
|
version: "6.1.4"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -102,6 +116,13 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_markdown:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_markdown
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.10+5"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -119,6 +140,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.0"
|
version: "0.15.0"
|
||||||
|
html2md:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: html2md
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.6"
|
||||||
http:
|
http:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -161,6 +189,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
markdown:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: markdown
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -431,7 +466,7 @@ packages:
|
||||||
name: xdg_directories
|
name: xdg_directories
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.2.0+1"
|
version: "0.2.0+2"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.17.3 <3.0.0"
|
dart: ">=2.17.3 <3.0.0"
|
||||||
flutter: ">=3.0.0"
|
flutter: ">=3.0.0"
|
||||||
|
|
|
@ -44,6 +44,10 @@ dependencies:
|
||||||
shelf: ^1.3.1
|
shelf: ^1.3.1
|
||||||
html: ^0.15.0
|
html: ^0.15.0
|
||||||
web_socket_channel: ^2.2.0
|
web_socket_channel: ^2.2.0
|
||||||
|
clipboard: ^0.1.3
|
||||||
|
flutter_markdown: ^0.6.10+5
|
||||||
|
markdown: ^5.0.0
|
||||||
|
html2md: ^1.2.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Reference in New Issue