Merge pull request #116 from krawieck/api-v2
This commit is contained in:
commit
67e9ea9a3b
|
@ -1,4 +1,4 @@
|
|||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import 'util/hot_rank.dart';
|
||||
|
||||
|
@ -25,13 +25,16 @@ extension on CommentSortType {
|
|||
a.comment.computedHotRank.compareTo(b.comment.computedHotRank);
|
||||
|
||||
case CommentSortType.new_:
|
||||
return (b, a) => a.comment.published.compareTo(b.comment.published);
|
||||
return (b, a) =>
|
||||
a.comment.comment.published.compareTo(b.comment.comment.published);
|
||||
|
||||
case CommentSortType.old:
|
||||
return (b, a) => b.comment.published.compareTo(a.comment.published);
|
||||
return (b, a) =>
|
||||
b.comment.comment.published.compareTo(a.comment.comment.published);
|
||||
|
||||
case CommentSortType.top:
|
||||
return (b, a) => a.comment.score.compareTo(b.comment.score);
|
||||
return (b, a) =>
|
||||
a.comment.counts.score.compareTo(b.comment.counts.score);
|
||||
}
|
||||
|
||||
throw Exception('unreachable');
|
||||
|
@ -50,15 +53,16 @@ class CommentTree {
|
|||
static List<CommentTree> fromList(List<CommentView> comments) {
|
||||
CommentTree gatherChildren(CommentTree parent) {
|
||||
for (final el in comments) {
|
||||
if (el.parentId == parent.comment.id) {
|
||||
if (el.comment.parentId == parent.comment.comment.id) {
|
||||
parent.children.add(gatherChildren(CommentTree(el)));
|
||||
}
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
final topLevelParents =
|
||||
comments.where((e) => e.parentId == null).map((e) => CommentTree(e));
|
||||
final topLevelParents = comments
|
||||
.where((e) => e.comment.parentId == null)
|
||||
.map((e) => CommentTree(e));
|
||||
|
||||
final result = topLevelParents.map(gatherChildren).toList();
|
||||
return result;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../pages/settings.dart';
|
||||
import '../util/goto.dart';
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
|
@ -32,10 +32,9 @@ class AddAccountPage extends HookWidget {
|
|||
final selectedInstance = useState(instanceHost);
|
||||
final icon = useState<String>(null);
|
||||
useEffect(() {
|
||||
LemmyApi(selectedInstance.value)
|
||||
.v1
|
||||
.getSite()
|
||||
.then((site) => icon.value = site.site.icon);
|
||||
LemmyApiV2(selectedInstance.value)
|
||||
.run(GetSite())
|
||||
.then((site) => icon.value = site.siteView.site.icon);
|
||||
return null;
|
||||
}, [selectedInstance.value]);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/debounce.dart';
|
||||
import '../hooks/stores.dart';
|
||||
|
@ -33,7 +33,7 @@ class AddInstancePage extends HookWidget {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
icon.value = (await LemmyApi(inst).v1.getSite()).site.icon;
|
||||
icon.value = (await LemmyApiV2(inst).run(GetSite())).siteView.site.icon;
|
||||
isSite.value = true;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
|
@ -75,7 +75,7 @@ class AddInstancePage extends HookWidget {
|
|||
),
|
||||
body: ListView(
|
||||
children: [
|
||||
if (isSite.value == true)
|
||||
if (isSite.value == true && icon.value != null)
|
||||
SizedBox(
|
||||
height: 150,
|
||||
child: FullscreenableImage(
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../util/goto.dart';
|
||||
import '../widgets/markdown_text.dart';
|
||||
|
@ -55,23 +55,23 @@ class CommunitiesListItem extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListTile(
|
||||
title: Text(community.name),
|
||||
subtitle: community.description != null
|
||||
title: Text(community.community.name),
|
||||
subtitle: community.community.description != null
|
||||
? Opacity(
|
||||
opacity: 0.7,
|
||||
child: MarkdownText(
|
||||
community.description,
|
||||
community.community.description,
|
||||
instanceHost: community.instanceHost,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
onTap: () =>
|
||||
goToCommunity.byId(context, community.instanceHost, community.id),
|
||||
leading: community.icon != null
|
||||
onTap: () => goToCommunity.byId(
|
||||
context, community.instanceHost, community.community.id),
|
||||
leading: community.community.icon != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: community.icon,
|
||||
imageUrl: community.community.icon,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:fuzzy/fuzzy.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/refreshable.dart';
|
||||
|
@ -33,8 +33,9 @@ class CommunitiesTab extends HookWidget {
|
|||
getInstances() {
|
||||
final futures = accountsStore.loggedInInstances
|
||||
.map(
|
||||
(instanceHost) =>
|
||||
LemmyApi(instanceHost).v1.getSite().then((e) => e.site),
|
||||
(instanceHost) => LemmyApiV2(instanceHost)
|
||||
.run(GetSite())
|
||||
.then((e) => e.siteView.site),
|
||||
)
|
||||
.toList();
|
||||
|
||||
|
@ -44,14 +45,13 @@ class CommunitiesTab extends HookWidget {
|
|||
getCommunities() {
|
||||
final futures = accountsStore.loggedInInstances
|
||||
.map(
|
||||
(instanceHost) => LemmyApi(instanceHost)
|
||||
.v1
|
||||
.getUserDetails(
|
||||
(instanceHost) => LemmyApiV2(instanceHost)
|
||||
.run(GetUserDetails(
|
||||
sort: SortType.active,
|
||||
savedOnly: false,
|
||||
userId:
|
||||
accountsStore.defaultTokenFor(instanceHost).payload.id,
|
||||
)
|
||||
))
|
||||
.then((e) => e.follows),
|
||||
)
|
||||
.toList();
|
||||
|
@ -108,8 +108,8 @@ class CommunitiesTab extends HookWidget {
|
|||
|
||||
final instances = instancesRefreshable.snapshot.data;
|
||||
final communities = communitiesRefreshable.snapshot.data
|
||||
..forEach(
|
||||
(e) => e.sort((a, b) => a.communityName.compareTo(b.communityName)));
|
||||
..forEach((e) =>
|
||||
e.sort((a, b) => a.community.name.compareTo(b.community.name)));
|
||||
|
||||
final filterIcon = () {
|
||||
if (filterController.text.isEmpty) {
|
||||
|
@ -127,12 +127,12 @@ class CommunitiesTab extends HookWidget {
|
|||
|
||||
filterCommunities(List<CommunityFollowerView> comm) {
|
||||
final matches = Fuzzy(
|
||||
comm.map((e) => e.communityName).toList(),
|
||||
comm.map((e) => e.community.name).toList(),
|
||||
options: FuzzyOptions(threshold: 0.5),
|
||||
).search(filterController.text).map((e) => e.item);
|
||||
|
||||
return matches
|
||||
.map((match) => comm.firstWhere((e) => e.communityName == match));
|
||||
.map((match) => comm.firstWhere((e) => e.community.name == match));
|
||||
}
|
||||
|
||||
toggleCollapse(int i) => isCollapsed.value =
|
||||
|
@ -203,18 +203,18 @@ class CommunitiesTab extends HookWidget {
|
|||
onTap: () => goToCommunity.byId(
|
||||
context,
|
||||
accountsStore.loggedInInstances.elementAt(i),
|
||||
comm.communityId),
|
||||
comm.community.id),
|
||||
dense: true,
|
||||
leading: VerticalDivider(
|
||||
color: theme.hintColor,
|
||||
),
|
||||
title: Row(
|
||||
children: [
|
||||
if (comm.communityIcon != null)
|
||||
if (comm.community.icon != null)
|
||||
CachedNetworkImage(
|
||||
height: 30,
|
||||
width: 30,
|
||||
imageUrl: comm.communityIcon,
|
||||
imageUrl: comm.community.icon,
|
||||
imageBuilder: (context, imageProvider) =>
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
|
@ -231,14 +231,14 @@ class CommunitiesTab extends HookWidget {
|
|||
const SizedBox(width: 30),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
'''!${comm.communityName}${comm.isLocal ? '' : '@${comm.originInstanceHost}'}''',
|
||||
'''!${comm.community.name}${comm.community.local ? '' : '@${comm.community.originInstanceHost}'}''',
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: _CommunitySubscribeToggle(
|
||||
key: ValueKey(comm.communityId),
|
||||
key: ValueKey(comm.community.id),
|
||||
instanceHost: comm.instanceHost,
|
||||
communityId: comm.communityId,
|
||||
communityId: comm.community.id,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
@ -272,11 +272,11 @@ class _CommunitySubscribeToggle extends HookWidget {
|
|||
delayed.start();
|
||||
|
||||
try {
|
||||
await LemmyApi(instanceHost).v1.followCommunity(
|
||||
communityId: communityId,
|
||||
follow: !subbed.value,
|
||||
auth: accountsStore.defaultTokenFor(instanceHost).raw,
|
||||
);
|
||||
await LemmyApiV2(instanceHost).run(FollowCommunity(
|
||||
communityId: communityId,
|
||||
follow: !subbed.value,
|
||||
auth: accountsStore.defaultTokenFor(instanceHost).raw,
|
||||
));
|
||||
subbed.value = !subbed.value;
|
||||
} on Exception catch (err) {
|
||||
Scaffold.of(context).showSnackBar(SnackBar(
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:esys_flutter_share/esys_flutter_share.dart';
|
|||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
|
@ -45,8 +45,8 @@ class CommunityPage extends HookWidget {
|
|||
_community = null;
|
||||
CommunityPage.fromCommunityView(this._community)
|
||||
: instanceHost = _community.instanceHost,
|
||||
communityId = _community.id,
|
||||
communityName = _community.name;
|
||||
communityId = _community.community.id,
|
||||
communityName = _community.community.name;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -57,15 +57,15 @@ class CommunityPage extends HookWidget {
|
|||
final token = accountsStore.defaultTokenFor(instanceHost);
|
||||
|
||||
if (communityId != null) {
|
||||
return LemmyApi(instanceHost).v1.getCommunity(
|
||||
id: communityId,
|
||||
auth: token?.raw,
|
||||
);
|
||||
return LemmyApiV2(instanceHost).run(GetCommunity(
|
||||
id: communityId,
|
||||
auth: token?.raw,
|
||||
));
|
||||
} else {
|
||||
return LemmyApi(instanceHost).v1.getCommunity(
|
||||
name: communityName,
|
||||
auth: token?.raw,
|
||||
);
|
||||
return LemmyApiV2(instanceHost).run(GetCommunity(
|
||||
name: communityName,
|
||||
auth: token?.raw,
|
||||
));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -73,7 +73,7 @@ class CommunityPage extends HookWidget {
|
|||
|
||||
final community = () {
|
||||
if (fullCommunitySnap.hasData) {
|
||||
return fullCommunitySnap.data.community;
|
||||
return fullCommunitySnap.data.communityView;
|
||||
} else if (_community != null) {
|
||||
return _community;
|
||||
} else {
|
||||
|
@ -111,7 +111,7 @@ class CommunityPage extends HookWidget {
|
|||
|
||||
// FUNCTIONS
|
||||
void _share() =>
|
||||
Share.text('Share instance', community.actorId, 'text/plain');
|
||||
Share.text('Share instance', community.community.actorId, 'text/plain');
|
||||
|
||||
void _openMoreMenu() {
|
||||
showModalBottomSheet(
|
||||
|
@ -123,8 +123,9 @@ class CommunityPage extends HookWidget {
|
|||
ListTile(
|
||||
leading: const Icon(Icons.open_in_browser),
|
||||
title: const Text('Open in browser'),
|
||||
onTap: () async => await ul.canLaunch(community.actorId)
|
||||
? ul.launch(community.actorId)
|
||||
onTap: () async => await ul
|
||||
.canLaunch(community.community.actorId)
|
||||
? ul.launch(community.community.actorId)
|
||||
: Scaffold.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("can't open in browser"))),
|
||||
),
|
||||
|
@ -133,11 +134,10 @@ class CommunityPage extends HookWidget {
|
|||
title: const Text('Nerd stuff'),
|
||||
onTap: () {
|
||||
showInfoTablePopup(context, {
|
||||
'id': community.id,
|
||||
'actorId': community.actorId,
|
||||
'created by': '@${community.creatorName}',
|
||||
'hot rank': community.hotRank,
|
||||
'published': community.published,
|
||||
'id': community.community.id,
|
||||
'actorId': community.community.actorId,
|
||||
'created by': '@${community.creator.name}',
|
||||
'published': community.community.published,
|
||||
});
|
||||
},
|
||||
),
|
||||
|
@ -160,7 +160,7 @@ class CommunityPage extends HookWidget {
|
|||
backgroundColor: theme.cardColor,
|
||||
brightness: theme.brightness,
|
||||
iconTheme: theme.iconTheme,
|
||||
title: Text('!${community.name}',
|
||||
title: Text('!${community.community.name}',
|
||||
style: TextStyle(color: colorOnCard)),
|
||||
actions: [
|
||||
IconButton(icon: const Icon(Icons.share), onPressed: _share),
|
||||
|
@ -190,26 +190,26 @@ class CommunityPage extends HookWidget {
|
|||
children: [
|
||||
InfinitePostList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(community.instanceHost).v1.getPosts(
|
||||
type: PostListingType.community,
|
||||
sort: sort,
|
||||
communityId: community.id,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
),
|
||||
LemmyApiV2(community.instanceHost).run(GetPosts(
|
||||
type: PostListingType.community,
|
||||
sort: sort,
|
||||
communityId: community.community.id,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
)),
|
||||
),
|
||||
InfiniteCommentList(
|
||||
fetcher: (page, batchSize, sortType) =>
|
||||
LemmyApi(community.instanceHost).v1.getComments(
|
||||
communityId: community.id,
|
||||
auth: accountsStore
|
||||
.defaultTokenFor(community.instanceHost)
|
||||
?.raw,
|
||||
type: CommentListingType.community,
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
)),
|
||||
LemmyApiV2(community.instanceHost).run(GetComments(
|
||||
communityId: community.community.id,
|
||||
auth: accountsStore
|
||||
.defaultTokenFor(community.instanceHost)
|
||||
?.raw,
|
||||
type: CommentListingType.community,
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
))),
|
||||
_AboutTab(
|
||||
community: community,
|
||||
moderators: fullCommunitySnap.data?.moderators,
|
||||
|
@ -237,7 +237,7 @@ class _CommunityOverview extends StatelessWidget {
|
|||
final theme = Theme.of(context);
|
||||
final shadow = BoxShadow(color: theme.canvasColor, blurRadius: 5);
|
||||
|
||||
final icon = community.icon != null
|
||||
final icon = community.community.icon != null
|
||||
? Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
|
@ -256,9 +256,9 @@ class _CommunityOverview extends StatelessWidget {
|
|||
width: 83,
|
||||
height: 83,
|
||||
child: FullscreenableImage(
|
||||
url: community.icon,
|
||||
url: community.community.icon,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: community.icon,
|
||||
imageUrl: community.community.icon,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
|
@ -277,11 +277,11 @@ class _CommunityOverview extends StatelessWidget {
|
|||
: null;
|
||||
|
||||
return Stack(children: [
|
||||
if (community.banner != null)
|
||||
if (community.community.banner != null)
|
||||
FullscreenableImage(
|
||||
url: community.banner,
|
||||
url: community.community.banner,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: community.banner,
|
||||
imageUrl: community.community.banner,
|
||||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
|
@ -289,7 +289,7 @@ class _CommunityOverview extends StatelessWidget {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 45),
|
||||
child: Column(children: [
|
||||
if (community.icon != null) icon,
|
||||
if (community.community.icon != null) icon,
|
||||
// NAME
|
||||
Center(
|
||||
child: Padding(
|
||||
|
@ -304,17 +304,17 @@ class _CommunityOverview extends StatelessWidget {
|
|||
text: '!',
|
||||
style: TextStyle(fontWeight: FontWeight.w200)),
|
||||
TextSpan(
|
||||
text: community.name,
|
||||
text: community.community.name,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600)),
|
||||
const TextSpan(
|
||||
text: '@',
|
||||
style: TextStyle(fontWeight: FontWeight.w200)),
|
||||
TextSpan(
|
||||
text: community.originInstanceHost,
|
||||
text: community.community.originInstanceHost,
|
||||
style: const TextStyle(fontWeight: FontWeight.w600),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => goToInstance(
|
||||
context, community.originInstanceHost),
|
||||
context, community.community.originInstanceHost),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -326,7 +326,7 @@ class _CommunityOverview extends StatelessWidget {
|
|||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 8, left: 20, right: 20),
|
||||
child: Text(
|
||||
community.title,
|
||||
community.community.title,
|
||||
textAlign: TextAlign.center,
|
||||
style:
|
||||
TextStyle(fontWeight: FontWeight.w300, shadows: [shadow]),
|
||||
|
@ -346,7 +346,7 @@ class _CommunityOverview extends StatelessWidget {
|
|||
padding: EdgeInsets.only(right: 3),
|
||||
child: Icon(Icons.people, size: 20),
|
||||
),
|
||||
Text(compactNumber(community.numberOfSubscribers)),
|
||||
Text(compactNumber(community.counts.subscribers)),
|
||||
const Spacer(
|
||||
flex: 4,
|
||||
),
|
||||
|
@ -416,10 +416,10 @@ class _AboutTab extends StatelessWidget {
|
|||
return ListView(
|
||||
padding: const EdgeInsets.only(top: 20),
|
||||
children: [
|
||||
if (community.description != null) ...[
|
||||
if (community.community.description != null) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15),
|
||||
child: MarkdownText(community.description,
|
||||
child: MarkdownText(community.community.description,
|
||||
instanceHost: community.instanceHost),
|
||||
),
|
||||
const _Divider(),
|
||||
|
@ -435,13 +435,13 @@ class _AboutTab extends StatelessWidget {
|
|||
child: _Badge('X users online'),
|
||||
),
|
||||
_Badge(
|
||||
'''${community.numberOfSubscribers} subscriber${pluralS(community.numberOfSubscribers)}'''),
|
||||
'''${community.counts.subscribers} subscriber${pluralS(community.counts.subscribers)}'''),
|
||||
_Badge(
|
||||
'''${community.numberOfPosts} post${pluralS(community.numberOfPosts)}'''),
|
||||
'''${community.counts.posts} post${pluralS(community.counts.posts)}'''),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 15),
|
||||
child: _Badge(
|
||||
'''${community.numberOfComments} comment${pluralS(community.numberOfComments)}'''),
|
||||
'''${community.counts.comments} comment${pluralS(community.counts.comments)}'''),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -454,7 +454,7 @@ class _AboutTab extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
onPressed: goToCategories,
|
||||
child: Text(community.categoryName),
|
||||
child: Text(community.category.name),
|
||||
),
|
||||
),
|
||||
const _Divider(),
|
||||
|
@ -475,9 +475,12 @@ class _AboutTab extends StatelessWidget {
|
|||
child: Text('Mods:', style: theme.textTheme.subtitle2),
|
||||
),
|
||||
for (final mod in moderators)
|
||||
// TODO: add user picture, maybe make it into reusable component
|
||||
ListTile(
|
||||
title: Text(mod.userPreferredUsername ?? '@${mod.userName}'),
|
||||
onTap: () => goToUser.byId(context, mod.instanceHost, mod.userId),
|
||||
title: Text(
|
||||
mod.moderator.preferredUsername ?? '@${mod.moderator.name}'),
|
||||
onTap: () =>
|
||||
goToUser.byId(context, mod.instanceHost, mod.moderator.id),
|
||||
),
|
||||
]
|
||||
],
|
||||
|
@ -536,10 +539,10 @@ class _FollowButton extends HookWidget {
|
|||
subscribe(Jwt token) async {
|
||||
delayed.start();
|
||||
try {
|
||||
await LemmyApi(community.instanceHost).v1.followCommunity(
|
||||
communityId: community.id,
|
||||
await LemmyApiV2(community.instanceHost).run(FollowCommunity(
|
||||
communityId: community.community.id,
|
||||
follow: !isSubbed.value,
|
||||
auth: token.raw);
|
||||
auth: token.raw));
|
||||
isSubbed.value = !isSubbed.value;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
|
|
|
@ -2,7 +2,8 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/pictrs.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/image_picker.dart';
|
||||
|
@ -26,20 +27,20 @@ class CreatePostFab extends HookWidget {
|
|||
|
||||
return FloatingActionButton(
|
||||
onPressed: loggedInAction((_) => showCupertinoModalPopup(
|
||||
context: context, builder: (_) => CreatePost())),
|
||||
context: context, builder: (_) => CreatePostPage())),
|
||||
child: const Icon(Icons.add),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Modal for creating a post to some community in some instance
|
||||
class CreatePost extends HookWidget {
|
||||
class CreatePostPage extends HookWidget {
|
||||
final CommunityView community;
|
||||
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
|
||||
|
||||
CreatePost() : community = null;
|
||||
CreatePost.toCommunity(this.community);
|
||||
CreatePostPage() : community = null;
|
||||
CreatePostPage.toCommunity(this.community);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -58,16 +59,15 @@ class CreatePost extends HookWidget {
|
|||
final pictrsDeleteToken = useState<PictrsUploadFile>(null);
|
||||
|
||||
final allCommunitiesSnap = useMemoFuture(
|
||||
() => LemmyApi(selectedInstance.value)
|
||||
.v1
|
||||
.listCommunities(
|
||||
sort: SortType.hot,
|
||||
limit: 9999,
|
||||
auth: accStore.defaultTokenFor(selectedInstance.value).raw,
|
||||
)
|
||||
() => LemmyApiV2(selectedInstance.value)
|
||||
.run(ListCommunities(
|
||||
sort: SortType.hot,
|
||||
limit: 9999,
|
||||
auth: accStore.defaultTokenFor(selectedInstance.value).raw,
|
||||
))
|
||||
.then(
|
||||
(value) {
|
||||
value.sort((a, b) => a.name.compareTo(b.name));
|
||||
value.sort((a, b) => a.community.name.compareTo(b.community.name));
|
||||
return value;
|
||||
},
|
||||
),
|
||||
|
@ -82,7 +82,7 @@ class CreatePost extends HookWidget {
|
|||
imageUploadLoading.value = true;
|
||||
|
||||
final token = accStore.defaultTokenFor(selectedInstance.value);
|
||||
final pictrs = LemmyApi(selectedInstance.value).pictrs;
|
||||
final pictrs = PictrsApi(selectedInstance.value);
|
||||
final upload =
|
||||
await pictrs.upload(filePath: pic.path, auth: token.raw);
|
||||
pictrsDeleteToken.value = upload.files[0];
|
||||
|
@ -100,8 +100,7 @@ class CreatePost extends HookWidget {
|
|||
}
|
||||
|
||||
removePicture() {
|
||||
LemmyApi(selectedInstance.value)
|
||||
.pictrs
|
||||
PictrsApi(selectedInstance.value)
|
||||
.delete(pictrsDeleteToken.value)
|
||||
.catchError((_) {});
|
||||
|
||||
|
@ -135,15 +134,16 @@ class CreatePost extends HookWidget {
|
|||
border: OutlineInputBorder()),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<String>(
|
||||
value: selectedCommunity.value?.name,
|
||||
value: selectedCommunity.value?.community?.name,
|
||||
hint: const Text('Community'),
|
||||
onChanged: (val) => selectedCommunity.value =
|
||||
allCommunitiesSnap.data.firstWhere((e) => e.name == val),
|
||||
onChanged: (val) => selectedCommunity.value = allCommunitiesSnap.data
|
||||
.firstWhere((e) => e.community.name == val),
|
||||
items: allCommunitiesSnap.hasData
|
||||
? allCommunitiesSnap.data
|
||||
// FIXME: use id instead of name cuz it breaks with federation
|
||||
.map((e) => DropdownMenuItem(
|
||||
value: e.name,
|
||||
child: Text(e.name),
|
||||
value: e.community.name,
|
||||
child: Text(e.community.name),
|
||||
))
|
||||
.toList()
|
||||
: const [
|
||||
|
@ -219,19 +219,20 @@ class CreatePost extends HookWidget {
|
|||
return;
|
||||
}
|
||||
|
||||
final api = LemmyApi(selectedInstance.value).v1;
|
||||
final api = LemmyApiV2(selectedInstance.value);
|
||||
|
||||
final token = accStore.defaultTokenFor(selectedInstance.value);
|
||||
|
||||
delayed.start();
|
||||
try {
|
||||
final res = await api.createPost(
|
||||
url: urlController.text.isEmpty ? null : urlController.text,
|
||||
body: bodyController.text.isEmpty ? null : bodyController.text,
|
||||
nsfw: nsfw.value,
|
||||
name: titleController.text,
|
||||
communityId: selectedCommunity.value.id,
|
||||
auth: token.raw);
|
||||
final res = await api.run(CreatePost(
|
||||
url: urlController.text.isEmpty ? null : urlController.text,
|
||||
body: bodyController.text.isEmpty ? null : bodyController.text,
|
||||
nsfw: nsfw.value,
|
||||
name: titleController.text,
|
||||
communityId: selectedCommunity.value.community.id,
|
||||
auth: token.raw,
|
||||
));
|
||||
unawaited(goToReplace(context, (_) => FullPostPage.fromPostView(res)));
|
||||
return;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/logged_in_action.dart';
|
||||
import '../hooks/refreshable.dart';
|
||||
|
@ -25,15 +25,17 @@ class FullPostPage extends HookWidget {
|
|||
assert(instanceHost != null),
|
||||
post = null;
|
||||
FullPostPage.fromPostView(this.post)
|
||||
: id = post.id,
|
||||
: id = post.post.id,
|
||||
instanceHost = post.instanceHost;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final accStore = useAccountsStore();
|
||||
final fullPostRefreshable = useRefreshable(() => LemmyApi(instanceHost)
|
||||
.v1
|
||||
.getPost(id: id, auth: accStore.defaultTokenFor(instanceHost)?.raw));
|
||||
final fullPostRefreshable =
|
||||
useRefreshable(() => LemmyApiV2(instanceHost).run(GetPost(
|
||||
id: id,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
)));
|
||||
final loggedInAction = useLoggedInAction(instanceHost);
|
||||
final newComments = useState(const <CommentView>[]);
|
||||
|
||||
|
@ -58,7 +60,7 @@ class FullPostPage extends HookWidget {
|
|||
// VARIABLES
|
||||
|
||||
final post = fullPostRefreshable.snapshot.hasData
|
||||
? fullPostRefreshable.snapshot.data.post
|
||||
? fullPostRefreshable.snapshot.data.postView
|
||||
: this.post;
|
||||
|
||||
final fullPost = fullPostRefreshable.snapshot.data;
|
||||
|
@ -78,7 +80,7 @@ class FullPostPage extends HookWidget {
|
|||
}
|
||||
}
|
||||
|
||||
sharePost() => Share.text('Share post', post.apId, 'text/plain');
|
||||
sharePost() => Share.text('Share post', post.post.apId, 'text/plain');
|
||||
|
||||
comment() async {
|
||||
final newComment = await showCupertinoModalPopup<CommentView>(
|
||||
|
@ -98,7 +100,7 @@ class FullPostPage extends HookWidget {
|
|||
SavePostButton(post),
|
||||
IconButton(
|
||||
icon: Icon(moreIcon),
|
||||
onPressed: () => Post.showMoreMenu(context, post)),
|
||||
onPressed: () => PostWidget.showMoreMenu(context, post)),
|
||||
],
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
|
@ -109,11 +111,11 @@ class FullPostPage extends HookWidget {
|
|||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [
|
||||
Post(post, fullPost: true),
|
||||
PostWidget(post, fullPost: true),
|
||||
if (fullPostRefreshable.snapshot.hasData)
|
||||
CommentSection(
|
||||
newComments.value.followedBy(fullPost.comments).toList(),
|
||||
postCreatorId: fullPost.post.creatorId)
|
||||
postCreatorId: fullPost.postView.creator.id)
|
||||
else if (fullPostRefreshable.snapshot.hasError)
|
||||
Padding(
|
||||
padding:
|
||||
|
|
|
@ -4,7 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/infinite_scroll.dart';
|
||||
import '../hooks/memo_future.dart';
|
||||
|
@ -35,10 +35,11 @@ class HomeTab extends HookWidget {
|
|||
final instancesIcons = useMemoFuture(() async {
|
||||
final instances = accStore.instances.toList(growable: false);
|
||||
final sites = await Future.wait(instances
|
||||
.map((e) => LemmyApi(e).v1.getSite().catchError((e) => null)));
|
||||
.map((e) => LemmyApiV2(e).run(GetSite()).catchError((e) => null)));
|
||||
|
||||
return {
|
||||
for (var i = 0; i < sites.length; i++) instances[i]: sites[i].site.icon
|
||||
for (var i = 0; i < sites.length; i++)
|
||||
instances[i]: sites[i].siteView.site.icon
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -262,13 +263,13 @@ class InfiniteHomeList extends HookWidget {
|
|||
}();
|
||||
|
||||
final futures =
|
||||
instances.map((instanceHost) => LemmyApi(instanceHost).v1.getPosts(
|
||||
instances.map((instanceHost) => LemmyApiV2(instanceHost).run(GetPosts(
|
||||
type: listingType,
|
||||
sort: sort,
|
||||
page: page,
|
||||
limit: limit,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
));
|
||||
)));
|
||||
final posts = await Future.wait(futures);
|
||||
final newPosts = <PostView>[];
|
||||
final longest = posts.map((e) => e.length).reduce(max);
|
||||
|
@ -286,13 +287,13 @@ class InfiniteHomeList extends HookWidget {
|
|||
|
||||
Future<List<PostView>> Function(int, int) fetcherFromInstance(
|
||||
String instanceHost, PostListingType listingType, SortType sort) =>
|
||||
(page, batchSize) => LemmyApi(instanceHost).v1.getPosts(
|
||||
(page, batchSize) => LemmyApiV2(instanceHost).run(GetPosts(
|
||||
type: listingType,
|
||||
sort: sort,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
);
|
||||
));
|
||||
|
||||
return InfiniteScroll<PostView>(
|
||||
prepend: Column(
|
||||
|
@ -305,7 +306,7 @@ class InfiniteHomeList extends HookWidget {
|
|||
),
|
||||
builder: (post) => Column(
|
||||
children: [
|
||||
Post(post),
|
||||
PostWidget(post),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'package:esys_flutter_share/esys_flutter_share.dart';
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import '../hooks/stores.dart';
|
||||
|
@ -30,9 +30,9 @@ class InstancePage extends HookWidget {
|
|||
|
||||
InstancePage({@required this.instanceHost})
|
||||
: assert(instanceHost != null),
|
||||
siteFuture = LemmyApi(instanceHost).v1.getSite(),
|
||||
siteFuture = LemmyApiV2(instanceHost).run(GetSite()),
|
||||
communitiesFuture =
|
||||
LemmyApi(instanceHost).v1.listCommunities(sort: SortType.hot);
|
||||
LemmyApiV2(instanceHost).run(ListCommunities(sort: SortType.hot));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -80,8 +80,8 @@ class InstancePage extends HookWidget {
|
|||
leading: const Icon(Icons.open_in_browser),
|
||||
title: const Text('Open in browser'),
|
||||
onTap: () async => await ul
|
||||
.canLaunch('https://${site.site.instanceHost}')
|
||||
? ul.launch('https://${site.site.instanceHost}')
|
||||
.canLaunch('https://${site.instanceHost}')
|
||||
? ul.launch('https://${site.instanceHost}')
|
||||
: Scaffold.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("can't open in browser"))),
|
||||
),
|
||||
|
@ -91,12 +91,12 @@ class InstancePage extends HookWidget {
|
|||
onTap: () {
|
||||
showInfoTablePopup(context, {
|
||||
'url': instanceHost,
|
||||
'creator': '@${site.site.creatorName}',
|
||||
'creator': '@${site.siteView.creator.name}',
|
||||
'version': site.version,
|
||||
'enableDownvotes': site.site.enableDownvotes,
|
||||
'enableNsfw': site.site.enableNsfw,
|
||||
'published': site.site.published,
|
||||
'updated': site.site.updated,
|
||||
'enableDownvotes': site.siteView.site.enableDownvotes,
|
||||
'enableNsfw': site.siteView.site.enableNsfw,
|
||||
'published': site.siteView.site.published,
|
||||
'updated': site.siteView.site.updated,
|
||||
});
|
||||
},
|
||||
),
|
||||
|
@ -119,7 +119,7 @@ class InstancePage extends HookWidget {
|
|||
backgroundColor: theme.cardColor,
|
||||
iconTheme: theme.iconTheme,
|
||||
title: Text(
|
||||
site.site.name,
|
||||
site.siteView.site.name,
|
||||
style: TextStyle(color: colorOnCard),
|
||||
),
|
||||
actions: [
|
||||
|
@ -130,11 +130,11 @@ class InstancePage extends HookWidget {
|
|||
],
|
||||
flexibleSpace: FlexibleSpaceBar(
|
||||
background: Stack(children: [
|
||||
if (site.site.banner != null)
|
||||
if (site.siteView.site.banner != null)
|
||||
FullscreenableImage(
|
||||
url: site.site.banner,
|
||||
url: site.siteView.site.banner,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: site.site.banner,
|
||||
imageUrl: site.siteView.site.banner,
|
||||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
|
@ -144,20 +144,20 @@ class InstancePage extends HookWidget {
|
|||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 40),
|
||||
child: site.site.icon == null
|
||||
child: site.siteView.site.icon == null
|
||||
? const SizedBox(height: 100, width: 100)
|
||||
: FullscreenableImage(
|
||||
url: site.site.icon,
|
||||
url: site.siteView.site.icon,
|
||||
child: CachedNetworkImage(
|
||||
width: 100,
|
||||
height: 100,
|
||||
imageUrl: site.site.icon,
|
||||
imageUrl: site.siteView.site.icon,
|
||||
errorWidget: (_, __, ___) =>
|
||||
const Icon(Icons.warning),
|
||||
),
|
||||
),
|
||||
),
|
||||
Text(site.site.name,
|
||||
Text(site.siteView.site.name,
|
||||
style: theme.textTheme.headline6),
|
||||
Text(instanceHost, style: theme.textTheme.caption)
|
||||
],
|
||||
|
@ -186,23 +186,23 @@ class InstancePage extends HookWidget {
|
|||
children: [
|
||||
InfinitePostList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(instanceHost).v1.getPosts(
|
||||
// TODO: switch between all and subscribed
|
||||
type: PostListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
)),
|
||||
LemmyApiV2(instanceHost).run(GetPosts(
|
||||
// TODO: switch between all and subscribed
|
||||
type: PostListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
))),
|
||||
InfiniteCommentList(
|
||||
fetcher: (page, batchSize, sort) =>
|
||||
LemmyApi(instanceHost).v1.getComments(
|
||||
type: CommentListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
)),
|
||||
LemmyApiV2(instanceHost).run(GetComments(
|
||||
type: CommentListingType.all,
|
||||
sort: sort,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
))),
|
||||
_AboutTab(site,
|
||||
communitiesFuture: communitiesFuture,
|
||||
instanceHost: instanceHost),
|
||||
|
@ -268,13 +268,13 @@ class _AboutTab extends HookWidget {
|
|||
context,
|
||||
(_) => CommunitiesListPage(
|
||||
fetcher: (page, batchSize, sortType) =>
|
||||
LemmyApi(instanceHost).v1.listCommunities(
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
),
|
||||
title: 'Communities of ${site.site.name}',
|
||||
LemmyApiV2(instanceHost).run(ListCommunities(
|
||||
sort: sortType,
|
||||
limit: batchSize,
|
||||
page: page,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
)),
|
||||
title: 'Communities of ${site.siteView.site.name}',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -287,7 +287,7 @@ class _AboutTab extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||
child: MarkdownText(
|
||||
site.site.description,
|
||||
site.siteView.site.description,
|
||||
instanceHost: instanceHost,
|
||||
),
|
||||
),
|
||||
|
@ -299,10 +299,10 @@ class _AboutTab extends HookWidget {
|
|||
children: [
|
||||
const SizedBox(width: 7),
|
||||
const _Badge('X users online'),
|
||||
_Badge('${site.site.numberOfUsers} users'),
|
||||
_Badge('${site.site.numberOfCommunities} communities'),
|
||||
_Badge('${site.site.numberOfPosts} posts'),
|
||||
_Badge('${site.site.numberOfComments} comments'),
|
||||
_Badge('${site.siteView.counts.users} users'),
|
||||
_Badge('${site.siteView.counts.communities} communities'),
|
||||
_Badge('${site.siteView.counts.posts} posts'),
|
||||
_Badge('${site.siteView.counts.comments} comments'),
|
||||
const SizedBox(width: 15),
|
||||
],
|
||||
),
|
||||
|
@ -317,15 +317,15 @@ class _AboutTab extends HookWidget {
|
|||
),
|
||||
),
|
||||
if (commSnap.hasData)
|
||||
...commSnap.data.take(6).map((e) => ListTile(
|
||||
onTap: () =>
|
||||
goToCommunity.byId(context, e.instanceHost, e.id),
|
||||
title: Text(e.name),
|
||||
leading: e.icon != null
|
||||
...commSnap.data.take(6).map((c) => ListTile(
|
||||
onTap: () => goToCommunity.byId(
|
||||
context, c.instanceHost, c.community.id),
|
||||
title: Text(c.community.name),
|
||||
leading: c.community.icon != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: e.icon,
|
||||
imageUrl: c.community.icon,
|
||||
errorWidget: (_, __, ___) =>
|
||||
const SizedBox(width: 50, height: 50),
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
|
@ -362,20 +362,20 @@ class _AboutTab extends HookWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
...site.admins.map((e) => ListTile(
|
||||
title: Text((e.preferredUsername == null ||
|
||||
e.preferredUsername.isEmpty)
|
||||
? '@${e.name}'
|
||||
: e.preferredUsername),
|
||||
subtitle: e.bio != null
|
||||
? MarkdownText(e.bio, instanceHost: instanceHost)
|
||||
...site.admins.map((u) => ListTile(
|
||||
title: Text((u.user.preferredUsername == null ||
|
||||
u.user.preferredUsername.isEmpty)
|
||||
? '@${u.user.name}'
|
||||
: u.user.preferredUsername),
|
||||
subtitle: u.user.bio != null
|
||||
? MarkdownText(u.user.bio, instanceHost: instanceHost)
|
||||
: null,
|
||||
onTap: () => goToUser.byId(context, instanceHost, e.id),
|
||||
leading: e.avatar != null
|
||||
onTap: () => goToUser.byId(context, instanceHost, u.user.id),
|
||||
leading: u.user.avatar != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: e.avatar,
|
||||
imageUrl: u.user.avatar,
|
||||
errorWidget: (_, __, ___) =>
|
||||
const SizedBox(width: 50, height: 50),
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
|
@ -396,7 +396,6 @@ class _AboutTab extends HookWidget {
|
|||
title: const Center(child: Text('Modlog')),
|
||||
onTap: goToModLog,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -2,13 +2,15 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/pictrs.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/image_picker.dart';
|
||||
import '../hooks/ref.dart';
|
||||
import '../hooks/stores.dart';
|
||||
import '../util/pictrs.dart';
|
||||
import '../widgets/bottom_safe.dart';
|
||||
|
||||
/// Page for managing things like username, email, avatar etc
|
||||
/// This page will assume the manage account is logged in and
|
||||
|
@ -28,9 +30,8 @@ class ManageAccountPage extends HookWidget {
|
|||
final theme = Theme.of(context);
|
||||
|
||||
final userFuture = useMemoized(() async {
|
||||
final site = await LemmyApi(instanceHost)
|
||||
.v1
|
||||
.getSite(auth: accountStore.tokenFor(instanceHost, username).raw);
|
||||
final site = await LemmyApiV2(instanceHost).run(
|
||||
GetSite(auth: accountStore.tokenFor(instanceHost, username).raw));
|
||||
|
||||
return site.myUser;
|
||||
});
|
||||
|
@ -45,7 +46,7 @@ class ManageAccountPage extends HookWidget {
|
|||
Text('@$instanceHost@$username', style: theme.textTheme.headline6),
|
||||
centerTitle: true,
|
||||
),
|
||||
body: FutureBuilder<User>(
|
||||
body: FutureBuilder<UserSafeSettings>(
|
||||
future: userFuture,
|
||||
builder: (_, userSnap) {
|
||||
if (userSnap.hasError) {
|
||||
|
@ -67,7 +68,7 @@ class _ManageAccount extends HookWidget {
|
|||
: assert(user != null),
|
||||
super(key: key);
|
||||
|
||||
final User user;
|
||||
final UserSafeSettings user;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -104,35 +105,35 @@ class _ManageAccount extends HookWidget {
|
|||
saveDelayedLoading.start();
|
||||
|
||||
try {
|
||||
await LemmyApi(user.instanceHost).v1.saveUserSettings(
|
||||
showNsfw: showNsfw.value,
|
||||
theme: user.theme,
|
||||
defaultSortType: defaultSortType.value,
|
||||
defaultListingType: defaultListingType.value,
|
||||
lang: user.lang,
|
||||
showAvatars: showAvatars.value,
|
||||
sendNotificationsToEmail: sendNotificationsToEmail.value,
|
||||
auth: token.raw,
|
||||
avatar: avatar.current,
|
||||
banner: banner.current,
|
||||
newPassword: newPasswordController.text.isEmpty
|
||||
? null
|
||||
: newPasswordController.text,
|
||||
newPasswordVerify: newPasswordVerifyController.text.isEmpty
|
||||
? null
|
||||
: newPasswordVerifyController.text,
|
||||
oldPassword: oldPasswordController.text.isEmpty
|
||||
? null
|
||||
: oldPasswordController.text,
|
||||
matrixUserId: matrixUserController.text.isEmpty
|
||||
? null
|
||||
: matrixUserController.text,
|
||||
preferredUsername: displayNameController.text.isEmpty
|
||||
? null
|
||||
: displayNameController.text,
|
||||
bio: bioController.text.isEmpty ? null : bioController.text,
|
||||
email: emailController.text.isEmpty ? null : emailController.text,
|
||||
);
|
||||
await LemmyApiV2(user.instanceHost).run(SaveUserSettings(
|
||||
showNsfw: showNsfw.value,
|
||||
theme: user.theme,
|
||||
defaultSortType: defaultSortType.value,
|
||||
defaultListingType: defaultListingType.value,
|
||||
lang: user.lang,
|
||||
showAvatars: showAvatars.value,
|
||||
sendNotificationsToEmail: sendNotificationsToEmail.value,
|
||||
auth: token.raw,
|
||||
avatar: avatar.current,
|
||||
banner: banner.current,
|
||||
newPassword: newPasswordController.text.isEmpty
|
||||
? null
|
||||
: newPasswordController.text,
|
||||
newPasswordVerify: newPasswordVerifyController.text.isEmpty
|
||||
? null
|
||||
: newPasswordVerifyController.text,
|
||||
oldPassword: oldPasswordController.text.isEmpty
|
||||
? null
|
||||
: oldPasswordController.text,
|
||||
matrixUserId: matrixUserController.text.isEmpty
|
||||
? null
|
||||
: matrixUserController.text,
|
||||
preferredUsername: displayNameController.text.isEmpty
|
||||
? null
|
||||
: displayNameController.text,
|
||||
bio: bioController.text.isEmpty ? null : bioController.text,
|
||||
email: emailController.text.isEmpty ? null : emailController.text,
|
||||
));
|
||||
|
||||
informAcceptedAvatarRef.current();
|
||||
informAcceptedBannerRef.current();
|
||||
|
@ -186,10 +187,10 @@ class _ManageAccount extends HookWidget {
|
|||
deleteDelayedLoading.start();
|
||||
|
||||
try {
|
||||
await LemmyApi(user.instanceHost).v1.deleteAccount(
|
||||
password: deleteAccountPasswordController.text,
|
||||
auth: token.raw,
|
||||
);
|
||||
await LemmyApiV2(user.instanceHost).run(DeleteAccount(
|
||||
password: deleteAccountPasswordController.text,
|
||||
auth: token.raw,
|
||||
));
|
||||
|
||||
accountsStore.removeAccount(user.instanceHost, user.name);
|
||||
Navigator.of(context).pop();
|
||||
|
@ -430,6 +431,7 @@ class _ManageAccount extends HookWidget {
|
|||
),
|
||||
child: const Text('DELETE ACCOUNT'),
|
||||
),
|
||||
const BottomSafe(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
@ -439,7 +441,7 @@ class _ManageAccount extends HookWidget {
|
|||
class _ImagePicker extends HookWidget {
|
||||
final String name;
|
||||
final String initialUrl;
|
||||
final User user;
|
||||
final UserSafeSettings user;
|
||||
final ValueChanged<String> onChange;
|
||||
|
||||
/// _ImagePicker will set the ref to a callback that can inform _ImagePicker
|
||||
|
@ -478,10 +480,10 @@ class _ImagePicker extends HookWidget {
|
|||
if (pic != null) {
|
||||
delayedLoading.start();
|
||||
|
||||
final upload = await LemmyApi(user.instanceHost).pictrs.upload(
|
||||
filePath: pic.path,
|
||||
auth: accountsStore.tokenFor(user.instanceHost, user.name).raw,
|
||||
);
|
||||
final upload = await PictrsApi(user.instanceHost).upload(
|
||||
filePath: pic.path,
|
||||
auth: accountsStore.tokenFor(user.instanceHost, user.name).raw,
|
||||
);
|
||||
pictrsDeleteToken.value = upload.files[0];
|
||||
url.value =
|
||||
pathToPictrs(user.instanceHost, pictrsDeleteToken.value.file);
|
||||
|
@ -497,8 +499,7 @@ class _ImagePicker extends HookWidget {
|
|||
}
|
||||
|
||||
removePicture({bool updateState = true}) {
|
||||
LemmyApi(user.instanceHost)
|
||||
.pictrs
|
||||
PictrsApi(user.instanceHost)
|
||||
.delete(pictrsDeleteToken.value)
|
||||
.catchError((_) {});
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../comment_tree.dart';
|
||||
import '../hooks/stores.dart';
|
||||
|
@ -82,14 +82,14 @@ class _SearchResultsList extends HookWidget {
|
|||
|
||||
return SortableInfiniteList(
|
||||
fetcher: (page, batchSize, sort) async {
|
||||
final s = await LemmyApi(instanceHost).v1.search(
|
||||
q: query,
|
||||
sort: sort,
|
||||
type: type,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
);
|
||||
final s = await LemmyApiV2(instanceHost).run(Search(
|
||||
q: query,
|
||||
sort: sort,
|
||||
type: type,
|
||||
auth: accStore.defaultTokenFor(instanceHost)?.raw,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
));
|
||||
|
||||
switch (s.type) {
|
||||
case SearchType.comments:
|
||||
|
@ -107,7 +107,7 @@ class _SearchResultsList extends HookWidget {
|
|||
builder: (data) {
|
||||
switch (type) {
|
||||
case SearchType.comments:
|
||||
return Comment(
|
||||
return CommentWidget(
|
||||
CommentTree(data as CommentView),
|
||||
postCreatorId: null,
|
||||
);
|
||||
|
@ -116,10 +116,10 @@ class _SearchResultsList extends HookWidget {
|
|||
case SearchType.posts:
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: Post(data as PostView),
|
||||
child: PostWidget(data as PostView),
|
||||
);
|
||||
case SearchType.users:
|
||||
return UsersListItem(user: data as UserView);
|
||||
return UsersListItem(user: data as UserViewSafe);
|
||||
default:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../widgets/user_profile.dart';
|
||||
|
||||
|
@ -9,20 +9,20 @@ import '../widgets/user_profile.dart';
|
|||
class UserPage extends HookWidget {
|
||||
final int userId;
|
||||
final String instanceHost;
|
||||
final Future<UserDetails> _userDetails;
|
||||
final Future<FullUserView> _userDetails;
|
||||
|
||||
UserPage({@required this.userId, @required this.instanceHost})
|
||||
: assert(userId != null),
|
||||
assert(instanceHost != null),
|
||||
_userDetails = LemmyApi(instanceHost).v1.getUserDetails(
|
||||
userId: userId, savedOnly: true, sort: SortType.active);
|
||||
_userDetails = LemmyApiV2(instanceHost).run(GetUserDetails(
|
||||
userId: userId, savedOnly: true, sort: SortType.active));
|
||||
|
||||
UserPage.fromName({@required this.instanceHost, @required String username})
|
||||
: assert(instanceHost != null),
|
||||
assert(username != null),
|
||||
userId = null,
|
||||
_userDetails = LemmyApi(instanceHost).v1.getUserDetails(
|
||||
username: username, savedOnly: true, sort: SortType.active);
|
||||
_userDetails = LemmyApiV2(instanceHost).run(GetUserDetails(
|
||||
username: username, savedOnly: true, sort: SortType.active));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -30,7 +30,7 @@ class UserPage extends HookWidget {
|
|||
|
||||
final body = () {
|
||||
if (userDetailsSnap.hasData) {
|
||||
return UserProfile.fromUserDetails(userDetailsSnap.data);
|
||||
return UserProfile.fromFullUserView(userDetailsSnap.data);
|
||||
} else if (userDetailsSnap.hasError) {
|
||||
return const Center(child: Text('Could not find that user.'));
|
||||
} else {
|
||||
|
@ -52,7 +52,7 @@ class UserPage extends HookWidget {
|
|||
IconButton(
|
||||
icon: const Icon(Icons.share),
|
||||
onPressed: () => Share.text('Share user',
|
||||
userDetailsSnap.data.user.actorId, 'text/plain'),
|
||||
userDetailsSnap.data.userView.user.actorId, 'text/plain'),
|
||||
)
|
||||
]
|
||||
],
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../util/goto.dart';
|
||||
import '../widgets/markdown_text.dart';
|
||||
|
@ -8,7 +8,7 @@ import '../widgets/markdown_text.dart';
|
|||
/// Infinite list of Users fetched by the given fetcher
|
||||
class UsersListPage extends StatelessWidget {
|
||||
final String title;
|
||||
final List<UserView> users;
|
||||
final List<UserViewSafe> users;
|
||||
|
||||
const UsersListPage({Key key, @required this.users, this.title})
|
||||
: assert(users != null),
|
||||
|
@ -34,7 +34,7 @@ class UsersListPage extends StatelessWidget {
|
|||
}
|
||||
|
||||
class UsersListItem extends StatelessWidget {
|
||||
final UserView user;
|
||||
final UserViewSafe user;
|
||||
|
||||
const UsersListItem({Key key, @required this.user})
|
||||
: assert(user != null),
|
||||
|
@ -42,25 +42,25 @@ class UsersListItem extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) => ListTile(
|
||||
title: Text(
|
||||
(user.preferredUsername == null || user.preferredUsername.isEmpty)
|
||||
? '@${user.name}'
|
||||
: user.preferredUsername),
|
||||
subtitle: user.bio != null
|
||||
title: Text((user.user.preferredUsername == null ||
|
||||
user.user.preferredUsername.isEmpty)
|
||||
? '@${user.user.name}'
|
||||
: user.user.preferredUsername),
|
||||
subtitle: user.user.bio != null
|
||||
? Opacity(
|
||||
opacity: 0.5,
|
||||
child: MarkdownText(
|
||||
user.bio,
|
||||
user.user.bio,
|
||||
instanceHost: user.instanceHost,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
onTap: () => goToUser.byId(context, user.instanceHost, user.id),
|
||||
leading: user.avatar != null
|
||||
onTap: () => goToUser.byId(context, user.instanceHost, user.user.id),
|
||||
leading: user.user.avatar != null
|
||||
? CachedNetworkImage(
|
||||
height: 50,
|
||||
width: 50,
|
||||
imageUrl: user.avatar,
|
||||
imageUrl: user.user.avatar,
|
||||
errorWidget: (_, __, ___) =>
|
||||
const SizedBox(height: 50, width: 50),
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'dart:collection';
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../util/unawaited.dart';
|
||||
|
@ -215,14 +215,13 @@ class AccountsStore extends ChangeNotifier {
|
|||
throw Exception('No such instance was added');
|
||||
}
|
||||
|
||||
final lemmy = LemmyApi(instanceHost).v1;
|
||||
|
||||
final token = await lemmy.login(
|
||||
final lemmy = LemmyApiV2(instanceHost);
|
||||
final token = await lemmy.run(Login(
|
||||
usernameOrEmail: usernameOrEmail,
|
||||
password: password,
|
||||
);
|
||||
));
|
||||
final userData =
|
||||
await lemmy.getSite(auth: token.raw).then((value) => value.myUser);
|
||||
await lemmy.run(GetSite(auth: token.raw)).then((value) => value.myUser);
|
||||
|
||||
_tokens[instanceHost][userData.name] = token;
|
||||
|
||||
|
@ -244,7 +243,7 @@ class AccountsStore extends ChangeNotifier {
|
|||
|
||||
if (!assumeValid) {
|
||||
try {
|
||||
await LemmyApi(instanceHost).v1.getSite();
|
||||
await LemmyApiV2(instanceHost).run(GetSite());
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (_) {
|
||||
throw Exception('This instance seems to not exist');
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../cleanup_url.dart';
|
||||
|
||||
|
@ -10,30 +10,41 @@ import '../cleanup_url.dart';
|
|||
|
||||
// [.isLocal] is true iff `.originInstanceHost == .instanceHost`
|
||||
|
||||
extension GetInstanceCommunityView on CommunityView {
|
||||
extension GetInstanceCommunitySafe on CommunitySafe {
|
||||
String get originInstanceHost => _extract(actorId);
|
||||
bool get isLocal => originInstanceHost == instanceHost;
|
||||
// bool get isLocal => originInstanceHost == instanceHost;
|
||||
}
|
||||
|
||||
extension GetInstanceUserView on UserView {
|
||||
extension GetInstanceUserSafe on UserSafe {
|
||||
String get originInstanceHost => _extract(actorId);
|
||||
bool get isLocal => originInstanceHost == instanceHost;
|
||||
// bool get isLocal => originInstanceHost == instanceHost;
|
||||
}
|
||||
|
||||
extension GetInstanceCommunityFollowerView on CommunityFollowerView {
|
||||
String get originInstanceHost => _extract(communityActorId);
|
||||
bool get isLocal => originInstanceHost == instanceHost;
|
||||
}
|
||||
|
||||
extension GetInstancePostView on PostView {
|
||||
extension GetInstancePostView on Post {
|
||||
String get originInstanceHost => _extract(apId);
|
||||
bool get isLocal => originInstanceHost == instanceHost;
|
||||
// bool get isLocal => originInstanceHost == instanceHost;
|
||||
}
|
||||
|
||||
extension GetInstanceCommentView on CommentView {
|
||||
extension GetInstanceCommentView on Comment {
|
||||
String get originInstanceHost => _extract(apId);
|
||||
bool get isLocal => originInstanceHost == instanceHost;
|
||||
// bool get isLocal => originInstanceHost == instanceHost;
|
||||
}
|
||||
|
||||
// TODO: change it to something more robust? regex?
|
||||
String _extract(String s) => cleanUpUrl(s.split('/')[2]);
|
||||
|
||||
extension DisplayName on UserSafe {
|
||||
String get displayName {
|
||||
final name = () {
|
||||
if (preferredUsername != null && preferredUsername != '') {
|
||||
return preferredUsername;
|
||||
} else {
|
||||
return '@${this.name}';
|
||||
}
|
||||
}();
|
||||
|
||||
if (!local) return '$name@$originInstanceHost';
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'dart:math' show log, max, pow, ln10;
|
||||
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
/// Calculates hot rank
|
||||
/// because API always claims it's `0`
|
||||
|
@ -17,5 +17,6 @@ double _calculateHotRank(int score, DateTime time) {
|
|||
}
|
||||
|
||||
extension CommentHotRank on CommentView {
|
||||
double get computedHotRank => _calculateHotRank(score, published);
|
||||
double get computedHotRank =>
|
||||
_calculateHotRank(counts.score, comment.published);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class BottomSafe extends StatelessWidget {
|
||||
final double additionalPadding;
|
||||
const BottomSafe([this.additionalPadding = 0]);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => SizedBox(
|
||||
height: MediaQuery.of(context).padding.bottom + additionalPadding);
|
||||
}
|
|
@ -4,13 +4,14 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
import '../comment_tree.dart';
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/logged_in_action.dart';
|
||||
import '../hooks/stores.dart';
|
||||
import '../util/extensions/api.dart';
|
||||
import '../util/goto.dart';
|
||||
import '../util/intl.dart';
|
||||
|
@ -21,7 +22,7 @@ import 'markdown_text.dart';
|
|||
import 'write_comment.dart';
|
||||
|
||||
/// A single comment that renders its replies
|
||||
class Comment extends HookWidget {
|
||||
class CommentWidget extends HookWidget {
|
||||
final int indent;
|
||||
final int postCreatorId;
|
||||
final CommentTree commentTree;
|
||||
|
@ -37,7 +38,7 @@ class Comment extends HookWidget {
|
|||
Colors.indigo,
|
||||
];
|
||||
|
||||
Comment(
|
||||
CommentWidget(
|
||||
this.commentTree, {
|
||||
this.indent = 0,
|
||||
@required this.postCreatorId,
|
||||
|
@ -48,48 +49,52 @@ class Comment extends HookWidget {
|
|||
_showCommentInfo(BuildContext context) {
|
||||
final com = commentTree.comment;
|
||||
showInfoTablePopup(context, {
|
||||
'id': com.id,
|
||||
'creatorId': com.creatorId,
|
||||
'postId': com.postId,
|
||||
'postName': com.postName,
|
||||
'parentId': com.parentId,
|
||||
'removed': com.removed,
|
||||
'read': com.read,
|
||||
'published': com.published,
|
||||
'updated': com.updated,
|
||||
'deleted': com.deleted,
|
||||
'apId': com.apId,
|
||||
'local': com.local,
|
||||
'communityId': com.communityId,
|
||||
'communityActorId': com.communityActorId,
|
||||
'communityLocal': com.communityLocal,
|
||||
'communityName': com.communityName,
|
||||
'communityIcon': com.communityIcon,
|
||||
'banned': com.banned,
|
||||
'bannedFromCommunity': com.bannedFromCommunity,
|
||||
'creatorActirId': com.creatorActorId,
|
||||
'userId': com.userId,
|
||||
'upvotes': com.upvotes,
|
||||
'downvotes': com.downvotes,
|
||||
'score': com.score,
|
||||
'% of upvotes': '${100 * (com.upvotes / (com.upvotes + com.downvotes))}%',
|
||||
'hotRank': com.hotRank,
|
||||
'hotRankActive': com.hotRankActive,
|
||||
'id': com.comment.id,
|
||||
'creatorId': com.comment.creatorId,
|
||||
'postId': com.comment.postId,
|
||||
'postName': com.post.name,
|
||||
'parentId': com.comment.parentId,
|
||||
'removed': com.comment.removed,
|
||||
'read': com.comment.read,
|
||||
'published': com.comment.published,
|
||||
'updated': com.comment.updated,
|
||||
'deleted': com.comment.deleted,
|
||||
'apId': com.comment.apId,
|
||||
'local': com.comment.local,
|
||||
'communityId': com.community.id,
|
||||
'communityActorId': com.community.actorId,
|
||||
'communityLocal': com.community.local,
|
||||
'communityName': com.community.name,
|
||||
'communityIcon': com.community.icon,
|
||||
'banned': com.creator.banned,
|
||||
'bannedFromCommunity': com.creatorBannedFromCommunity,
|
||||
'creatorActirId': com.creator.actorId,
|
||||
'userId': com.creator.id,
|
||||
'upvotes': com.counts.upvotes,
|
||||
'downvotes': com.counts.downvotes,
|
||||
'score': com.counts.score,
|
||||
'% of upvotes':
|
||||
'''${100 * (com.counts.upvotes / (com.counts.upvotes + com.counts.downvotes))}%''',
|
||||
});
|
||||
}
|
||||
|
||||
bool get isOP => commentTree.comment.creatorId == postCreatorId;
|
||||
bool get isMine =>
|
||||
commentTree.comment.creatorId == commentTree.comment.userId;
|
||||
bool get isOP =>
|
||||
commentTree.comment.comment.creatorId ==
|
||||
commentTree.comment.post.creatorId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
|
||||
final accStore = useAccountsStore();
|
||||
|
||||
final isMine = commentTree.comment.comment.creatorId ==
|
||||
accStore.defaultTokenFor(commentTree.comment.instanceHost).payload.id;
|
||||
final selectable = useState(false);
|
||||
final showRaw = useState(false);
|
||||
final collapsed = useState(false);
|
||||
final myVote = useState(commentTree.comment.myVote ?? VoteType.none);
|
||||
final isDeleted = useState(commentTree.comment.deleted);
|
||||
final isDeleted = useState(commentTree.comment.comment.deleted);
|
||||
final delayedVoting = useDelayedLoading();
|
||||
final delayedDeletion = useDelayedLoading();
|
||||
final loggedInAction = useLoggedInAction(commentTree.comment.instanceHost);
|
||||
|
@ -98,14 +103,17 @@ class Comment extends HookWidget {
|
|||
final comment = commentTree.comment;
|
||||
|
||||
handleDelete(Jwt token) async {
|
||||
final api = LemmyApi(token.payload.iss).v1;
|
||||
final api = LemmyApiV2(token.payload.iss);
|
||||
|
||||
delayedDeletion.start();
|
||||
Navigator.of(context).pop();
|
||||
try {
|
||||
final res = await api.deleteComment(
|
||||
editId: comment.id, deleted: !isDeleted.value, auth: token.raw);
|
||||
isDeleted.value = res.deleted;
|
||||
final res = await api.run(DeleteComment(
|
||||
commentId: comment.comment.id,
|
||||
deleted: !isDeleted.value,
|
||||
auth: token.raw,
|
||||
));
|
||||
isDeleted.value = res.commentView.comment.deleted;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
Scaffold.of(context).showSnackBar(
|
||||
|
@ -128,22 +136,22 @@ class Comment extends HookWidget {
|
|||
ListTile(
|
||||
leading: const Icon(Icons.open_in_browser),
|
||||
title: const Text('Open in browser'),
|
||||
onTap: () async => await ul.canLaunch(com.apId)
|
||||
? ul.launch(com.apId)
|
||||
onTap: () async => await ul.canLaunch(com.comment.apId)
|
||||
? ul.launch(com.comment.apId)
|
||||
: Scaffold.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("can't open in browser"))),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.share),
|
||||
title: const Text('Share url'),
|
||||
onTap: () =>
|
||||
Share.text('Share comment url', com.apId, 'text/plain'),
|
||||
onTap: () => Share.text(
|
||||
'Share comment url', com.comment.apId, 'text/plain'),
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.share),
|
||||
title: const Text('Share text'),
|
||||
onTap: () =>
|
||||
Share.text('Share comment text', com.content, 'text/plain'),
|
||||
onTap: () => Share.text(
|
||||
'Share comment text', com.comment.content, 'text/plain'),
|
||||
),
|
||||
ListTile(
|
||||
leading: Icon(
|
||||
|
@ -191,13 +199,13 @@ class Comment extends HookWidget {
|
|||
}
|
||||
|
||||
vote(VoteType vote, Jwt token) async {
|
||||
final api = LemmyApi(token.payload.iss).v1;
|
||||
final api = LemmyApiV2(token.payload.iss);
|
||||
|
||||
delayedVoting.start();
|
||||
try {
|
||||
final res = await api.createCommentLike(
|
||||
commentId: comment.id, score: vote, auth: token.raw);
|
||||
myVote.value = res.myVote;
|
||||
final res = await api.run(CreateCommentLike(
|
||||
commentId: comment.comment.id, score: vote, auth: token.raw));
|
||||
myVote.value = res.commentView.myVote;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
Scaffold.of(context)
|
||||
|
@ -208,20 +216,7 @@ class Comment extends HookWidget {
|
|||
}
|
||||
|
||||
// decide which username to use
|
||||
final username = () {
|
||||
final name = () {
|
||||
if (comment.creatorPreferredUsername != null &&
|
||||
comment.creatorPreferredUsername != '') {
|
||||
return comment.creatorPreferredUsername;
|
||||
} else {
|
||||
return '@${comment.creatorName}';
|
||||
}
|
||||
}();
|
||||
|
||||
if (!comment.isLocal) return '$name@${comment.originInstanceHost}';
|
||||
|
||||
return name;
|
||||
}();
|
||||
final username = comment.creator.displayName;
|
||||
|
||||
final body = () {
|
||||
if (isDeleted.value) {
|
||||
|
@ -231,7 +226,7 @@ class Comment extends HookWidget {
|
|||
style: TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
);
|
||||
} else if (comment.removed) {
|
||||
} else if (comment.comment.removed) {
|
||||
return const Flexible(
|
||||
child: Text(
|
||||
'comment deleted by moderator',
|
||||
|
@ -243,7 +238,7 @@ class Comment extends HookWidget {
|
|||
child: Opacity(
|
||||
opacity: 0.3,
|
||||
child: Text(
|
||||
commentTree.comment.content,
|
||||
commentTree.comment.comment.content,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
|
@ -256,10 +251,10 @@ class Comment extends HookWidget {
|
|||
return Flexible(
|
||||
child: showRaw.value
|
||||
? selectable.value
|
||||
? SelectableText(commentTree.comment.content)
|
||||
: Text(commentTree.comment.content)
|
||||
? SelectableText(commentTree.comment.comment.content)
|
||||
: Text(commentTree.comment.comment.content)
|
||||
: MarkdownText(
|
||||
commentTree.comment.content,
|
||||
commentTree.comment.comment.content,
|
||||
instanceHost: commentTree.comment.instanceHost,
|
||||
selectable: selectable.value,
|
||||
));
|
||||
|
@ -269,13 +264,15 @@ class Comment extends HookWidget {
|
|||
final actions = collapsed.value
|
||||
? const SizedBox.shrink()
|
||||
: Row(children: [
|
||||
if (selectable.value && !isDeleted.value && !comment.removed)
|
||||
if (selectable.value &&
|
||||
!isDeleted.value &&
|
||||
!comment.comment.removed)
|
||||
_CommentAction(
|
||||
icon: Icons.content_copy,
|
||||
tooltip: 'copy',
|
||||
onPressed: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: commentTree.comment.content))
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: commentTree.comment.comment.content))
|
||||
.then((_) => Scaffold.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('comment copied to clipboard'))));
|
||||
|
@ -285,7 +282,7 @@ class Comment extends HookWidget {
|
|||
_CommentAction(
|
||||
icon: Icons.link,
|
||||
onPressed: () =>
|
||||
goToPost(context, comment.instanceHost, comment.postId),
|
||||
goToPost(context, comment.instanceHost, comment.post.id),
|
||||
tooltip: 'go to post',
|
||||
),
|
||||
_CommentAction(
|
||||
|
@ -295,7 +292,7 @@ class Comment extends HookWidget {
|
|||
tooltip: 'more',
|
||||
),
|
||||
_SaveComment(commentTree.comment),
|
||||
if (!isDeleted.value && !comment.removed)
|
||||
if (!isDeleted.value && !comment.comment.removed)
|
||||
_CommentAction(
|
||||
icon: Icons.reply,
|
||||
onPressed: loggedInAction((_) => reply()),
|
||||
|
@ -340,14 +337,14 @@ class Comment extends HookWidget {
|
|||
child: Column(
|
||||
children: [
|
||||
Row(children: [
|
||||
if (comment.creatorAvatar != null)
|
||||
if (comment.creator.avatar != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 5),
|
||||
child: InkWell(
|
||||
onTap: () => goToUser.byId(
|
||||
context, comment.instanceHost, comment.creatorId),
|
||||
context, comment.instanceHost, comment.creator.id),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: comment.creatorAvatar,
|
||||
imageUrl: comment.creator.avatar,
|
||||
height: 20,
|
||||
width: 20,
|
||||
imageBuilder: (context, imageProvider) => Container(
|
||||
|
@ -365,18 +362,19 @@ class Comment extends HookWidget {
|
|||
),
|
||||
InkWell(
|
||||
onTap: () => goToUser.byId(
|
||||
context, comment.instanceHost, comment.creatorId),
|
||||
context, comment.instanceHost, comment.creator.id),
|
||||
child: Text(username,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).accentColor,
|
||||
)),
|
||||
),
|
||||
if (isOP) _CommentTag('OP', Theme.of(context).accentColor),
|
||||
if (comment.banned) const _CommentTag('BANNED', Colors.red),
|
||||
if (comment.bannedFromCommunity)
|
||||
if (comment.creator.banned)
|
||||
const _CommentTag('BANNED', Colors.red),
|
||||
if (comment.creatorBannedFromCommunity)
|
||||
const _CommentTag('BANNED FROM COMMUNITY', Colors.red),
|
||||
const Spacer(),
|
||||
if (collapsed.value && commentTree.children.length > 0) ...[
|
||||
if (collapsed.value && commentTree.children.isNotEmpty) ...[
|
||||
_CommentTag('+${commentTree.children.length}',
|
||||
Theme.of(context).accentColor),
|
||||
const SizedBox(width: 7),
|
||||
|
@ -390,10 +388,10 @@ class Comment extends HookWidget {
|
|||
size: const Size.square(16),
|
||||
child: const CircularProgressIndicator())
|
||||
else
|
||||
Text(compactNumber(comment.score +
|
||||
Text(compactNumber(comment.counts.score +
|
||||
(wasVoted ? 0 : myVote.value.value))),
|
||||
const Text(' · '),
|
||||
Text(timeago.format(comment.published)),
|
||||
Text(timeago.format(comment.comment.published)),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -407,7 +405,7 @@ class Comment extends HookWidget {
|
|||
),
|
||||
if (!collapsed.value)
|
||||
for (final c in newReplies.value.followedBy(commentTree.children))
|
||||
Comment(
|
||||
CommentWidget(
|
||||
c,
|
||||
indent: indent + 1,
|
||||
postCreatorId: postCreatorId,
|
||||
|
@ -430,13 +428,16 @@ class _SaveComment extends HookWidget {
|
|||
final delayed = useDelayedLoading();
|
||||
|
||||
handleSave(Jwt token) async {
|
||||
final api = LemmyApi(comment.instanceHost).v1;
|
||||
final api = LemmyApiV2(comment.instanceHost);
|
||||
|
||||
delayed.start();
|
||||
try {
|
||||
final res = await api.saveComment(
|
||||
commentId: comment.id, save: !isSaved.value, auth: token.raw);
|
||||
isSaved.value = res.saved;
|
||||
final res = await api.run(SaveComment(
|
||||
commentId: comment.comment.id,
|
||||
save: !isSaved.value,
|
||||
auth: token.raw,
|
||||
));
|
||||
isSaved.value = res.commentView.saved;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
Scaffold.of(context)
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../comment_tree.dart';
|
||||
import 'bottom_modal.dart';
|
||||
import 'bottom_safe.dart';
|
||||
import 'comment.dart';
|
||||
|
||||
/// Manages comments section, sorts them
|
||||
|
@ -29,7 +30,7 @@ class CommentSection extends HookWidget {
|
|||
}) : comments =
|
||||
CommentTree.sortList(sortType, CommentTree.fromList(rawComments)),
|
||||
rawComments = rawComments
|
||||
..sort((b, a) => a.published.compareTo(b.published)),
|
||||
..sort((b, a) => a.comment.published.compareTo(b.comment.published)),
|
||||
assert(postCreatorId != null);
|
||||
|
||||
@override
|
||||
|
@ -99,13 +100,14 @@ class CommentSection extends HookWidget {
|
|||
)
|
||||
else if (sorting.value == CommentSortType.chat)
|
||||
for (final com in rawComments)
|
||||
Comment(
|
||||
CommentWidget(
|
||||
CommentTree(com),
|
||||
postCreatorId: postCreatorId,
|
||||
)
|
||||
else
|
||||
for (final com in comments) Comment(com, postCreatorId: postCreatorId),
|
||||
const SizedBox(height: 50),
|
||||
for (final com in comments)
|
||||
CommentWidget(com, postCreatorId: postCreatorId),
|
||||
const BottomSafe(50),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
||||
import '../hooks/ref.dart';
|
||||
import 'bottom_safe.dart';
|
||||
|
||||
class InfiniteScrollController {
|
||||
VoidCallback clear;
|
||||
|
@ -82,7 +83,7 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
if (i == data.value.length) {
|
||||
// if there are no more, skip
|
||||
if (!hasMore.current) {
|
||||
return const SizedBox.shrink();
|
||||
return const BottomSafe();
|
||||
}
|
||||
|
||||
// if it's already fetching more, skip
|
||||
|
@ -98,7 +99,10 @@ class InfiniteScroll<T> extends HookWidget {
|
|||
}).whenComplete(() => isFetching.current = false);
|
||||
}
|
||||
|
||||
return loadingWidget;
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: loadingWidget,
|
||||
);
|
||||
}
|
||||
|
||||
// not last element, render list item
|
||||
|
|
|
@ -5,7 +5,7 @@ import 'package:flutter/gestures.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||
|
||||
|
@ -47,12 +47,13 @@ MediaType whatType(String url) {
|
|||
}
|
||||
|
||||
/// A post overview card
|
||||
class Post extends HookWidget {
|
||||
class PostWidget extends HookWidget {
|
||||
final PostView post;
|
||||
final String instanceHost;
|
||||
final bool fullPost;
|
||||
|
||||
Post(this.post, {this.fullPost = false}) : instanceHost = post.instanceHost;
|
||||
PostWidget(this.post, {this.fullPost = false})
|
||||
: instanceHost = post.instanceHost;
|
||||
|
||||
// == ACTIONS ==
|
||||
|
||||
|
@ -66,8 +67,8 @@ class Post extends HookWidget {
|
|||
ListTile(
|
||||
leading: const Icon(Icons.open_in_browser),
|
||||
title: const Text('Open in browser'),
|
||||
onTap: () async => await ul.canLaunch(post.apId)
|
||||
? ul.launch(post.apId)
|
||||
onTap: () async => await ul.canLaunch(post.post.apId)
|
||||
? ul.launch(post.post.apId)
|
||||
: Scaffold.of(context).showSnackBar(
|
||||
const SnackBar(content: Text("can't open in browser"))),
|
||||
),
|
||||
|
@ -76,19 +77,16 @@ class Post extends HookWidget {
|
|||
title: const Text('Nerd stuff'),
|
||||
onTap: () {
|
||||
showInfoTablePopup(context, {
|
||||
'id': post.id,
|
||||
'apId': post.apId,
|
||||
'upvotes': post.upvotes,
|
||||
'downvotes': post.downvotes,
|
||||
'score': post.score,
|
||||
'id': post.post.id,
|
||||
'apId': post.post.apId,
|
||||
'upvotes': post.counts.upvotes,
|
||||
'downvotes': post.counts.downvotes,
|
||||
'score': post.counts.score,
|
||||
'% of upvotes':
|
||||
'''${(100 * (post.upvotes / (post.upvotes + post.downvotes))).toInt()}%''',
|
||||
'hotRank': post.hotRank,
|
||||
'hotRank active': post.hotRankActive,
|
||||
'local': post.local,
|
||||
'published': post.published,
|
||||
'updated': post.updated ?? 'never',
|
||||
'newestActivityTime': post.newestActivityTime,
|
||||
'''${(100 * (post.counts.upvotes / (post.counts.upvotes + post.counts.downvotes))).toInt()}%''',
|
||||
'local': post.post.local,
|
||||
'published': post.post.published,
|
||||
'updated': post.post.updated ?? 'never',
|
||||
});
|
||||
},
|
||||
),
|
||||
|
@ -104,12 +102,12 @@ class Post extends HookWidget {
|
|||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
void _openLink() => linkLauncher(
|
||||
context: context, url: post.url, instanceHost: instanceHost);
|
||||
context: context, url: post.post.url, instanceHost: instanceHost);
|
||||
|
||||
final urlDomain = () {
|
||||
if (whatType(post.url) == MediaType.none) return null;
|
||||
if (whatType(post.post.url) == MediaType.none) return null;
|
||||
|
||||
final url = post.url.split('/')[2];
|
||||
final url = post.post.url.split('/')[2]; // TODO: change to Url(str).host
|
||||
if (url.startsWith('www.')) return url.substring(4);
|
||||
return url;
|
||||
}();
|
||||
|
@ -122,12 +120,12 @@ class Post extends HookWidget {
|
|||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (post.communityIcon != null)
|
||||
if (post.community.icon != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: InkWell(
|
||||
onTap: () => goToCommunity.byId(
|
||||
context, instanceHost, post.communityId),
|
||||
context, instanceHost, post.community.id),
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: 40,
|
||||
|
@ -141,7 +139,7 @@ class Post extends HookWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
imageUrl: post.communityIcon,
|
||||
imageUrl: post.community.icon,
|
||||
errorWidget: (context, url, error) =>
|
||||
Text(error.toString()),
|
||||
),
|
||||
|
@ -165,22 +163,22 @@ class Post extends HookWidget {
|
|||
text: '!',
|
||||
style: TextStyle(fontWeight: FontWeight.w300)),
|
||||
TextSpan(
|
||||
text: post.communityName,
|
||||
text: post.community.name,
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.w600),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => goToCommunity.byId(
|
||||
context, instanceHost, post.communityId)),
|
||||
context, instanceHost, post.community.id)),
|
||||
const TextSpan(
|
||||
text: '@',
|
||||
style: TextStyle(fontWeight: FontWeight.w300)),
|
||||
TextSpan(
|
||||
text: post.originInstanceHost,
|
||||
text: post.post.originInstanceHost,
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.w600),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => goToInstance(
|
||||
context, post.originInstanceHost)),
|
||||
context, post.post.originInstanceHost)),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
@ -197,29 +195,32 @@ class Post extends HookWidget {
|
|||
text: 'by',
|
||||
style: TextStyle(fontWeight: FontWeight.w300)),
|
||||
TextSpan(
|
||||
text:
|
||||
''' ${post.creatorPreferredUsername ?? post.creatorName}''',
|
||||
text: ' ${post.creator.displayName}',
|
||||
style:
|
||||
const TextStyle(fontWeight: FontWeight.w600),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () => goToUser.byId(
|
||||
context, post.instanceHost, post.creatorId),
|
||||
context,
|
||||
post.instanceHost,
|
||||
post.creator.id,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
''' · ${timeago.format(post.published, locale: 'en_short')}'''),
|
||||
if (post.locked) const TextSpan(text: ' · 🔒'),
|
||||
if (post.stickied) const TextSpan(text: ' · 📌'),
|
||||
if (post.nsfw) const TextSpan(text: ' · '),
|
||||
if (post.nsfw)
|
||||
''' · ${timeago.format(post.post.published, locale: 'en_short')}'''),
|
||||
if (post.post.locked) const TextSpan(text: ' · 🔒'),
|
||||
if (post.post.stickied)
|
||||
const TextSpan(text: ' · 📌'),
|
||||
if (post.post.nsfw) const TextSpan(text: ' · '),
|
||||
if (post.post.nsfw)
|
||||
const TextSpan(
|
||||
text: 'NSFW',
|
||||
style: TextStyle(color: Colors.red)),
|
||||
if (urlDomain != null)
|
||||
TextSpan(text: ' · $urlDomain'),
|
||||
if (post.removed)
|
||||
if (post.post.removed)
|
||||
const TextSpan(text: ' · REMOVED'),
|
||||
if (post.deleted)
|
||||
if (post.post.deleted)
|
||||
const TextSpan(text: ' · DELETED'),
|
||||
],
|
||||
))
|
||||
|
@ -250,15 +251,15 @@ class Post extends HookWidget {
|
|||
Expanded(
|
||||
flex: 100,
|
||||
child: Text(
|
||||
post.name,
|
||||
post.post.name,
|
||||
textAlign: TextAlign.left,
|
||||
softWrap: true,
|
||||
style: const TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.w600),
|
||||
),
|
||||
),
|
||||
if (whatType(post.url) == MediaType.other &&
|
||||
post.thumbnailUrl != null) ...[
|
||||
if (whatType(post.post.url) == MediaType.other &&
|
||||
post.post.thumbnailUrl != null) ...[
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
onTap: _openLink,
|
||||
|
@ -266,7 +267,7 @@ class Post extends HookWidget {
|
|||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: post.thumbnailUrl,
|
||||
imageUrl: post.post.thumbnailUrl,
|
||||
width: 70,
|
||||
height: 70,
|
||||
fit: BoxFit.cover,
|
||||
|
@ -291,7 +292,7 @@ class Post extends HookWidget {
|
|||
|
||||
/// assemble link preview
|
||||
Widget linkPreview() {
|
||||
assert(post.url != null);
|
||||
assert(post.post.url != null);
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
|
@ -315,14 +316,14 @@ class Post extends HookWidget {
|
|||
]),
|
||||
Row(children: [
|
||||
Flexible(
|
||||
child: Text(post.embedTitle ?? '',
|
||||
child: Text(post.post.embedTitle ?? '',
|
||||
style: theme.textTheme.subtitle1
|
||||
.apply(fontWeightDelta: 2)))
|
||||
]),
|
||||
if (post.embedDescription != null &&
|
||||
post.embedDescription.isNotEmpty)
|
||||
if (post.post.embedDescription != null &&
|
||||
post.post.embedDescription.isNotEmpty)
|
||||
Row(children: [
|
||||
Flexible(child: Text(post.embedDescription))
|
||||
Flexible(child: Text(post.post.embedDescription))
|
||||
]),
|
||||
],
|
||||
),
|
||||
|
@ -334,12 +335,12 @@ class Post extends HookWidget {
|
|||
|
||||
/// assemble image
|
||||
Widget postImage() {
|
||||
assert(post.url != null);
|
||||
assert(post.post.url != null);
|
||||
|
||||
return FullscreenableImage(
|
||||
url: post.url,
|
||||
url: post.post.url,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: post.url,
|
||||
imageUrl: post.post.url,
|
||||
errorWidget: (_, __, ___) => const Icon(Icons.warning),
|
||||
progressIndicatorBuilder: (context, url, progress) =>
|
||||
CircularProgressIndicator(value: progress.progress),
|
||||
|
@ -356,7 +357,8 @@ class Post extends HookWidget {
|
|||
Expanded(
|
||||
flex: 999,
|
||||
child: Text(
|
||||
''' ${NumberFormat.compact().format(post.numberOfComments)} comment${post.numberOfComments == 1 ? '' : 's'}''',
|
||||
' ${NumberFormat.compact().format(post.counts.comments)}'
|
||||
' comment${post.counts.comments == 1 ? '' : 's'}',
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
),
|
||||
|
@ -365,7 +367,9 @@ class Post extends HookWidget {
|
|||
if (!fullPost)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.share),
|
||||
onPressed: () => Share.text('Share post url', post.apId,
|
||||
onPressed: () => Share.text(
|
||||
'Share post url',
|
||||
post.post.apId,
|
||||
'text/plain')), // TODO: find a way to mark it as url
|
||||
if (!fullPost) SavePostButton(post),
|
||||
_Voting(post),
|
||||
|
@ -387,16 +391,17 @@ class Post extends HookWidget {
|
|||
children: [
|
||||
info(),
|
||||
title(),
|
||||
if (whatType(post.url) != MediaType.other &&
|
||||
whatType(post.url) != MediaType.none)
|
||||
if (whatType(post.post.url) != MediaType.other &&
|
||||
whatType(post.post.url) != MediaType.none)
|
||||
postImage()
|
||||
else if (post.url != null && post.url.isNotEmpty)
|
||||
else if (post.post.url != null && post.post.url.isNotEmpty)
|
||||
linkPreview(),
|
||||
if (post.body != null)
|
||||
if (post.post.body != null)
|
||||
// TODO: trim content
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: MarkdownText(post.body, instanceHost: instanceHost)),
|
||||
child:
|
||||
MarkdownText(post.post.body, instanceHost: instanceHost)),
|
||||
actions(),
|
||||
],
|
||||
),
|
||||
|
@ -421,12 +426,12 @@ class _Voting extends HookWidget {
|
|||
final loggedInAction = useLoggedInAction(post.instanceHost);
|
||||
|
||||
vote(VoteType vote, Jwt token) async {
|
||||
final api = LemmyApi(post.instanceHost).v1;
|
||||
final api = LemmyApiV2(post.instanceHost);
|
||||
|
||||
loading.start();
|
||||
try {
|
||||
final res = await api.createPostLike(
|
||||
postId: post.id, score: vote, auth: token.raw);
|
||||
final res = await api.run(
|
||||
CreatePostLike(postId: post.post.id, score: vote, auth: token.raw));
|
||||
myVote.value = res.myVote;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
|
@ -455,7 +460,7 @@ class _Voting extends HookWidget {
|
|||
width: 20, height: 20, child: CircularProgressIndicator())
|
||||
else
|
||||
Text(NumberFormat.compact()
|
||||
.format(post.score + (wasVoted ? 0 : myVote.value.value))),
|
||||
.format(post.counts.score + (wasVoted ? 0 : myVote.value.value))),
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_downward,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import 'bottom_modal.dart';
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/logged_in_action.dart';
|
||||
|
@ -20,12 +20,12 @@ class SavePostButton extends HookWidget {
|
|||
final loggedInAction = useLoggedInAction(post.instanceHost);
|
||||
|
||||
savePost(Jwt token) async {
|
||||
final api = LemmyApi(post.instanceHost).v1;
|
||||
final api = LemmyApiV2(post.instanceHost);
|
||||
|
||||
loading.start();
|
||||
try {
|
||||
final res = await api.savePost(
|
||||
postId: post.id, save: !isSaved.value, auth: token.raw);
|
||||
final res = await api.run(SavePost(
|
||||
postId: post.post.id, save: !isSaved.value, auth: token.raw));
|
||||
isSaved.value = res.saved;
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../comment_tree.dart';
|
||||
import '../hooks/infinite_scroll.dart';
|
||||
|
@ -57,7 +57,7 @@ class InfinitePostList extends StatelessWidget {
|
|||
onStyleChange: () {},
|
||||
builder: (post) => Column(
|
||||
children: [
|
||||
Post(post),
|
||||
PostWidget(post),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
|
@ -72,7 +72,7 @@ class InfiniteCommentList extends StatelessWidget {
|
|||
const InfiniteCommentList({@required this.fetcher}) : assert(fetcher != null);
|
||||
|
||||
Widget build(BuildContext context) => SortableInfiniteList<CommentView>(
|
||||
builder: (comment) => Comment(
|
||||
builder: (comment) => CommentWidget(
|
||||
CommentTree(comment),
|
||||
postCreatorId: null,
|
||||
detached: true,
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
import 'package:timeago/timeago.dart' as timeago;
|
||||
|
||||
import '../hooks/stores.dart';
|
||||
|
@ -17,16 +17,16 @@ import 'sortable_infinite_list.dart';
|
|||
|
||||
/// Shared widget of UserPage and ProfileTab
|
||||
class UserProfile extends HookWidget {
|
||||
final Future<UserDetails> _userDetails;
|
||||
final Future<FullUserView> _userDetails;
|
||||
final String instanceHost;
|
||||
|
||||
UserProfile({@required int userId, @required this.instanceHost})
|
||||
: _userDetails = LemmyApi(instanceHost).v1.getUserDetails(
|
||||
userId: userId, savedOnly: false, sort: SortType.active);
|
||||
: _userDetails = LemmyApiV2(instanceHost).run(GetUserDetails(
|
||||
userId: userId, savedOnly: false, sort: SortType.active));
|
||||
|
||||
UserProfile.fromUserDetails(UserDetails userDetails)
|
||||
: _userDetails = Future.value(userDetails),
|
||||
instanceHost = userDetails.user.instanceHost;
|
||||
UserProfile.fromFullUserView(FullUserView fullUserView)
|
||||
: _userDetails = Future.value(fullUserView),
|
||||
instanceHost = fullUserView.instanceHost;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@ -47,7 +47,7 @@ class UserProfile extends HookWidget {
|
|||
);
|
||||
}
|
||||
|
||||
final userView = userDetailsSnap.data.user;
|
||||
final userView = userDetailsSnap.data.userView;
|
||||
|
||||
return DefaultTabController(
|
||||
length: 3,
|
||||
|
@ -78,27 +78,25 @@ class UserProfile extends HookWidget {
|
|||
// TODO: first batch is already fetched on render
|
||||
// TODO: comment and post come from the same endpoint, could be shared
|
||||
InfinitePostList(
|
||||
fetcher: (page, batchSize, sort) => LemmyApi(instanceHost)
|
||||
.v1
|
||||
.getUserDetails(
|
||||
userId: userView.id,
|
||||
fetcher: (page, batchSize, sort) => LemmyApiV2(instanceHost)
|
||||
.run(GetUserDetails(
|
||||
userId: userView.user.id,
|
||||
savedOnly: false,
|
||||
sort: SortType.active,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
)
|
||||
))
|
||||
.then((val) => val.posts),
|
||||
),
|
||||
InfiniteCommentList(
|
||||
fetcher: (page, batchSize, sort) => LemmyApi(instanceHost)
|
||||
.v1
|
||||
.getUserDetails(
|
||||
userId: userView.id,
|
||||
fetcher: (page, batchSize, sort) => LemmyApiV2(instanceHost)
|
||||
.run(GetUserDetails(
|
||||
userId: userView.user.id,
|
||||
savedOnly: false,
|
||||
sort: SortType.active,
|
||||
page: page,
|
||||
limit: batchSize,
|
||||
)
|
||||
))
|
||||
.then((val) => val.comments),
|
||||
),
|
||||
_AboutTab(userDetailsSnap.data),
|
||||
|
@ -113,7 +111,7 @@ class UserProfile extends HookWidget {
|
|||
/// Such as his nickname, no. of posts, no. of posts,
|
||||
/// banner, avatar etc.
|
||||
class _UserOverview extends HookWidget {
|
||||
final UserView userView;
|
||||
final UserViewSafe userView;
|
||||
|
||||
const _UserOverview(this.userView);
|
||||
|
||||
|
@ -125,12 +123,12 @@ class _UserOverview extends HookWidget {
|
|||
|
||||
return Stack(
|
||||
children: [
|
||||
if (userView.banner != null)
|
||||
if (userView.user.banner != null)
|
||||
// TODO: for some reason doesnt react to presses
|
||||
FullscreenableImage(
|
||||
url: userView.banner,
|
||||
url: userView.user.banner,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: userView.banner,
|
||||
imageUrl: userView.user.banner,
|
||||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||||
),
|
||||
)
|
||||
|
@ -174,7 +172,7 @@ class _UserOverview extends HookWidget {
|
|||
SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
if (userView.avatar != null)
|
||||
if (userView.user.avatar != null)
|
||||
SizedBox(
|
||||
width: 80,
|
||||
height: 80,
|
||||
|
@ -190,9 +188,9 @@ class _UserOverview extends HookWidget {
|
|||
child: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||
child: FullscreenableImage(
|
||||
url: userView.avatar,
|
||||
url: userView.user.avatar,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: userView.avatar,
|
||||
imageUrl: userView.user.avatar,
|
||||
errorWidget: (_, __, ___) => const SizedBox.shrink(),
|
||||
),
|
||||
),
|
||||
|
@ -200,14 +198,14 @@ class _UserOverview extends HookWidget {
|
|||
),
|
||||
),
|
||||
Padding(
|
||||
padding: userView.avatar != null
|
||||
padding: userView.user.avatar != null
|
||||
? const EdgeInsets.only(top: 8)
|
||||
: const EdgeInsets.only(top: 70),
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(top: userView.avatar == null ? 10 : 0),
|
||||
padding: EdgeInsets.only(
|
||||
top: userView.user.avatar == null ? 10 : 0),
|
||||
child: Text(
|
||||
userView.preferredUsername ?? userView.name,
|
||||
userView.user.preferredUsername ?? userView.user.name,
|
||||
style: theme.textTheme.headline6,
|
||||
),
|
||||
),
|
||||
|
@ -218,14 +216,14 @@ class _UserOverview extends HookWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'@${userView.name}@',
|
||||
'@${userView.user.name}@',
|
||||
style: theme.textTheme.caption,
|
||||
),
|
||||
InkWell(
|
||||
onTap: () =>
|
||||
goToInstance(context, userView.originInstanceHost),
|
||||
onTap: () => goToInstance(
|
||||
context, userView.user.originInstanceHost),
|
||||
child: Text(
|
||||
userView.originInstanceHost,
|
||||
userView.user.originInstanceHost,
|
||||
style: theme.textTheme.caption,
|
||||
),
|
||||
)
|
||||
|
@ -248,8 +246,8 @@ class _UserOverview extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Text(
|
||||
'${compactNumber(userView.numberOfPosts)}'
|
||||
' Post${pluralS(userView.numberOfPosts)}',
|
||||
'${compactNumber(userView.counts.postCount)}'
|
||||
' Post${pluralS(userView.counts.postCount)}',
|
||||
style: TextStyle(color: colorOnTopOfAccentColor),
|
||||
),
|
||||
),
|
||||
|
@ -269,8 +267,8 @@ class _UserOverview extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Text(
|
||||
'${compactNumber(userView.numberOfComments)}'
|
||||
' Comment${pluralS(userView.numberOfComments)}',
|
||||
'${compactNumber(userView.counts.commentCount)}'
|
||||
''' Comment${pluralS(userView.counts.commentCount)}''',
|
||||
style:
|
||||
TextStyle(color: colorOnTopOfAccentColor),
|
||||
),
|
||||
|
@ -285,7 +283,7 @@ class _UserOverview extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Text(
|
||||
'Joined ${timeago.format(userView.published)}',
|
||||
'Joined ${timeago.format(userView.user.published)}',
|
||||
style: theme.textTheme.bodyText1,
|
||||
),
|
||||
),
|
||||
|
@ -301,7 +299,8 @@ class _UserOverview extends HookWidget {
|
|||
Padding(
|
||||
padding: const EdgeInsets.only(left: 4),
|
||||
child: Text(
|
||||
DateFormat('MMM dd, yyyy').format(userView.published),
|
||||
DateFormat('MMM dd, yyyy')
|
||||
.format(userView.user.published),
|
||||
style: theme.textTheme.bodyText1,
|
||||
),
|
||||
),
|
||||
|
@ -318,19 +317,21 @@ class _UserOverview extends HookWidget {
|
|||
}
|
||||
|
||||
class _AboutTab extends HookWidget {
|
||||
final UserDetails userDetails;
|
||||
final FullUserView userDetails;
|
||||
|
||||
const _AboutTab(this.userDetails);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
final instanceHost = userDetails.user.instanceHost;
|
||||
final instanceHost = userDetails.userView.user.instanceHost;
|
||||
|
||||
final accStore = useAccountsStore();
|
||||
|
||||
final isOwnedAccount = accStore.loggedInInstances.contains(instanceHost) &&
|
||||
accStore.usernamesFor(instanceHost).contains(userDetails.user.name);
|
||||
accStore
|
||||
.usernamesFor(instanceHost)
|
||||
.contains(userDetails.userView.user.name);
|
||||
|
||||
const wallPadding = EdgeInsets.symmetric(horizontal: 15);
|
||||
|
||||
|
@ -378,10 +379,10 @@ class _AboutTab extends HookWidget {
|
|||
),
|
||||
onTap: () {}, // TODO: go to account editing
|
||||
),
|
||||
if (userDetails.user.bio != null) ...[
|
||||
if (userDetails.userView.user.bio != null) ...[
|
||||
Padding(
|
||||
padding: wallPadding,
|
||||
child: MarkdownText(userDetails.user.bio,
|
||||
child: MarkdownText(userDetails.userView.user.bio,
|
||||
instanceHost: instanceHost)),
|
||||
divider,
|
||||
],
|
||||
|
@ -396,9 +397,9 @@ class _AboutTab extends HookWidget {
|
|||
),
|
||||
for (final comm
|
||||
in userDetails.moderates
|
||||
..sort((a, b) => a.communityName.compareTo(b.communityName)))
|
||||
..sort((a, b) => a.community.name.compareTo(b.community.name)))
|
||||
communityTile(
|
||||
comm.communityName, comm.communityIcon, comm.communityId),
|
||||
comm.community.name, comm.community.icon, comm.community.id),
|
||||
divider
|
||||
],
|
||||
ListTile(
|
||||
|
@ -412,9 +413,9 @@ class _AboutTab extends HookWidget {
|
|||
if (userDetails.follows.isNotEmpty)
|
||||
for (final comm
|
||||
in userDetails.follows
|
||||
..sort((a, b) => a.communityName.compareTo(b.communityName)))
|
||||
..sort((a, b) => a.community.name.compareTo(b.community.name)))
|
||||
communityTile(
|
||||
comm.communityName, comm.communityIcon, comm.communityId)
|
||||
comm.community.name, comm.community.icon, comm.community.id)
|
||||
else
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 8),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||
import 'package:lemmy_api_client/v2.dart';
|
||||
|
||||
import '../hooks/delayed_loading.dart';
|
||||
import '../hooks/stores.dart';
|
||||
|
@ -32,7 +32,7 @@ class WriteComment extends HookWidget {
|
|||
|
||||
final preview = () {
|
||||
final body = MarkdownText(
|
||||
comment?.content ?? post.body ?? '',
|
||||
comment?.comment?.content ?? post.post.body ?? '',
|
||||
instanceHost: instanceHost,
|
||||
);
|
||||
|
||||
|
@ -40,7 +40,7 @@ class WriteComment extends HookWidget {
|
|||
return Column(
|
||||
children: [
|
||||
Text(
|
||||
post.name,
|
||||
post.post.name,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
|
@ -53,18 +53,19 @@ class WriteComment extends HookWidget {
|
|||
}();
|
||||
|
||||
handleSubmit() async {
|
||||
final api = LemmyApi(instanceHost).v1;
|
||||
final api = LemmyApiV2(instanceHost);
|
||||
|
||||
final token = accStore.defaultTokenFor(instanceHost);
|
||||
|
||||
delayed.start();
|
||||
try {
|
||||
final res = await api.createComment(
|
||||
content: controller.text,
|
||||
postId: post?.id ?? comment.postId,
|
||||
parentId: comment?.id,
|
||||
auth: token.raw);
|
||||
Navigator.of(context).pop(res);
|
||||
final res = await api.run(CreateComment(
|
||||
content: controller.text,
|
||||
postId: post?.post?.id ?? comment.post.id,
|
||||
parentId: comment?.recipient?.id,
|
||||
auth: token.raw,
|
||||
));
|
||||
Navigator.of(context).pop(res.commentView);
|
||||
// ignore: avoid_catches_without_on_clauses
|
||||
} catch (e) {
|
||||
print(e);
|
||||
|
|
67
pubspec.lock
67
pubspec.lock
|
@ -35,7 +35,7 @@ packages:
|
|||
name: cached_network_image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
version: "2.5.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -91,7 +91,7 @@ packages:
|
|||
name: effective_dart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.4"
|
||||
version: "1.3.0"
|
||||
esys_flutter_share:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -138,7 +138,7 @@ packages:
|
|||
name: flutter_cache_manager
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "2.1.1"
|
||||
flutter_hooks:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -191,13 +191,20 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
freezed_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: freezed_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.0"
|
||||
fuzzy:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: fuzzy
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.3"
|
||||
version: "0.3.0"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -225,7 +232,7 @@ packages:
|
|||
name: image_picker
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.7+12"
|
||||
version: "0.6.7+21"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -246,7 +253,7 @@ packages:
|
|||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
latinize:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -260,7 +267,7 @@ packages:
|
|||
name: lemmy_api_client
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.9.0"
|
||||
version: "0.10.0"
|
||||
markdown:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -302,7 +309,7 @@ packages:
|
|||
name: package_info
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.3"
|
||||
version: "0.4.3+2"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -316,7 +323,7 @@ packages:
|
|||
name: path_provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.6.22"
|
||||
version: "1.6.27"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -330,21 +337,21 @@ packages:
|
|||
name: path_provider_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4+4"
|
||||
version: "0.0.4+8"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
version: "1.0.4"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.4+1"
|
||||
version: "0.0.4+3"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -365,7 +372,7 @@ packages:
|
|||
name: photo_view
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.10.2"
|
||||
version: "0.10.3"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -393,35 +400,35 @@ packages:
|
|||
name: provider
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "4.3.2+2"
|
||||
version: "4.3.3"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.24.1"
|
||||
version: "0.25.0"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.5.12+2"
|
||||
version: "0.5.12+4"
|
||||
shared_preferences_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2+2"
|
||||
version: "0.0.2+4"
|
||||
shared_preferences_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.1+10"
|
||||
version: "0.0.1+11"
|
||||
shared_preferences_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -442,7 +449,7 @@ packages:
|
|||
name: shared_preferences_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.1+1"
|
||||
version: "0.0.2+2"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -461,14 +468,14 @@ packages:
|
|||
name: sqflite
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.1+2"
|
||||
version: "1.3.2+2"
|
||||
sqflite_common:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sqflite_common
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.2+1"
|
||||
version: "1.0.3+1"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -517,7 +524,7 @@ packages:
|
|||
name: timeago
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.28"
|
||||
version: "2.0.29"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -531,21 +538,21 @@ packages:
|
|||
name: url_launcher
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.7.8"
|
||||
version: "5.7.10"
|
||||
url_launcher_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_linux
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.1+3"
|
||||
version: "0.0.1+4"
|
||||
url_launcher_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_macos
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.1+8"
|
||||
version: "0.0.1+9"
|
||||
url_launcher_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -559,14 +566,14 @@ packages:
|
|||
name: url_launcher_web
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.1.5"
|
||||
version: "0.1.5+1"
|
||||
url_launcher_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: url_launcher_windows
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.1+1"
|
||||
version: "0.0.1+3"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -587,7 +594,7 @@ packages:
|
|||
name: win32
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.3"
|
||||
version: "1.7.4"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -610,5 +617,5 @@ packages:
|
|||
source: hosted
|
||||
version: "2.2.1"
|
||||
sdks:
|
||||
dart: ">=2.10.0 <2.11.0"
|
||||
flutter: ">=1.22.0 <2.0.0"
|
||||
dart: ">=2.10.2 <2.11.0"
|
||||
flutter: ">=1.22.2 <2.0.0"
|
||||
|
|
|
@ -43,7 +43,7 @@ dependencies:
|
|||
# utils
|
||||
timeago: ^2.0.27
|
||||
fuzzy: <1.0.0
|
||||
lemmy_api_client: ^0.9.0
|
||||
lemmy_api_client: ^0.10.0
|
||||
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
|
Loading…
Reference in New Issue