Transition to API v3 (#196)

This commit is contained in:
Filip Krawczyk 2021-04-05 20:14:39 +02:00 committed by GitHub
parent a6daffe478
commit bac846fea9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 343 additions and 361 deletions

View File

@ -4,10 +4,14 @@
- Share buttons on windows/linux now copy the data to the clipboard
### Changed
- Transitioned to Lemmy API v3
### Fixed
- Quote blocks in posts and comments are now much prettier
- Code blocks nwo have monospace font. As they should
- Code blocks now have monospace font. As they should
- Switching accounts in the profile tab now correctly reacts to the change
## v0.3.0 - 2021-02-25

View File

@ -1,6 +1,4 @@
PODS:
- esys_flutter_share (0.0.1):
- Flutter
- Flutter (1.0.0)
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
@ -11,20 +9,22 @@ PODS:
- Flutter
- path_provider (0.0.1):
- Flutter
- share (0.0.1):
- Flutter
- shared_preferences (0.0.1):
- Flutter
- sqflite (0.0.1):
- sqflite (0.0.2):
- Flutter
- FMDB (~> 2.7.2)
- FMDB (>= 2.7.5)
- url_launcher (0.0.1):
- Flutter
DEPENDENCIES:
- esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
- Flutter (from `Flutter`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- share (from `.symlinks/plugins/share/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
@ -34,8 +34,6 @@ SPEC REPOS:
- FMDB
EXTERNAL SOURCES:
esys_flutter_share:
:path: ".symlinks/plugins/esys_flutter_share/ios"
Flutter:
:path: Flutter
image_picker:
@ -44,6 +42,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
share:
:path: ".symlinks/plugins/share/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
sqflite:
@ -52,16 +52,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher/ios"
SPEC CHECKSUMS:
esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
image_picker: 50e7c7ff960e5f58faa4d1f4af84a771c671bc4a
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
share: 0b2c3e82132f5888bccca3351c504d0003b3b410
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
COCOAPODS: 1.9.3
COCOAPODS: 1.10.1

View File

@ -1,4 +1,4 @@
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'util/hot_rank.dart';

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../pages/settings.dart';
import '../util/goto.dart';

View File

@ -5,4 +5,5 @@ import 'package:flutter_hooks/flutter_hooks.dart';
/// [keys] can be used to rebuild the Future
AsyncSnapshot<T> useMemoFuture<T>(Future<T> Function() valueBuilder,
[List<Object> keys = const <dynamic>[]]) =>
useFuture(useMemoized<Future<T>>(valueBuilder, keys), preserveState: false);
useFuture(useMemoized<Future<T>>(valueBuilder, keys),
preserveState: false, initialData: null);

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
extension SortTypeL10n on SortType {
String tr(BuildContext context) {

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:url_launcher/url_launcher.dart' as ul;
import '../hooks/delayed_loading.dart';
@ -32,7 +32,7 @@ class AddAccountPage extends HookWidget {
final icon = useState<String>(null);
useEffect(() {
LemmyApiV2(selectedInstance.value)
LemmyApiV3(selectedInstance.value)
.run(const GetSite())
.then((site) => icon.value = site.siteView.site.icon);
return null;

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/debounce.dart';
import '../hooks/stores.dart';
@ -32,7 +32,7 @@ class AddInstancePage extends HookWidget {
}
try {
icon.value =
(await LemmyApiV2(inst).run(const GetSite())).siteView.site.icon;
(await LemmyApiV3(inst).run(const GetSite())).siteView.site.icon;
isSite.value = true;
// ignore: avoid_catches_without_on_clauses
} catch (e) {

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../util/goto.dart';
import '../widgets/avatar.dart';

View File

@ -4,7 +4,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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
import '../hooks/refreshable.dart';
@ -35,7 +35,7 @@ class CommunitiesTab extends HookWidget {
getInstances() {
final futures = accountsStore.loggedInInstances
.map(
(instanceHost) => LemmyApiV2(instanceHost)
(instanceHost) => LemmyApiV3(instanceHost)
.run(const GetSite())
.then((e) => e.siteView.site),
)
@ -47,12 +47,12 @@ class CommunitiesTab extends HookWidget {
getCommunities() {
final futures = accountsStore.loggedInInstances
.map(
(instanceHost) => LemmyApiV2(instanceHost)
.run(GetUserDetails(
(instanceHost) => LemmyApiV3(instanceHost)
.run(GetPersonDetails(
sort: SortType.active,
savedOnly: false,
userId:
accountsStore.defaultTokenFor(instanceHost).payload.id,
personId:
accountsStore.defaultTokenFor(instanceHost).payload.sub,
auth: accountsStore.defaultTokenFor(instanceHost).raw,
))
.then((e) => e.follows),
@ -252,7 +252,7 @@ class _CommunitySubscribeToggle extends HookWidget {
delayed.start();
try {
await LemmyApiV2(instanceHost).run(FollowCommunity(
await LemmyApiV3(instanceHost).run(FollowCommunity(
communityId: communityId,
follow: !subbed.value,
auth: accountsStore.defaultTokenFor(instanceHost).raw,

View File

@ -2,7 +2,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:url_launcher/url_launcher.dart' as ul;
import '../hooks/delayed_loading.dart';
@ -62,12 +62,12 @@ class CommunityPage extends HookWidget {
final token = accountsStore.defaultTokenFor(instanceHost);
if (communityId != null) {
return LemmyApiV2(instanceHost).run(GetCommunity(
return LemmyApiV3(instanceHost).run(GetCommunity(
id: communityId,
auth: token?.raw,
));
} else {
return LemmyApiV2(instanceHost).run(GetCommunity(
return LemmyApiV3(instanceHost).run(GetCommunity(
name: communityName,
auth: token?.raw,
));
@ -186,17 +186,18 @@ class CommunityPage extends HookWidget {
children: [
InfinitePostList(
fetcher: (page, batchSize, sort) =>
LemmyApiV2(community.instanceHost).run(GetPosts(
LemmyApiV3(community.instanceHost).run(GetPosts(
type: PostListingType.community,
sort: sort,
communityId: community.community.id,
page: page,
limit: batchSize,
savedOnly: false,
)),
),
InfiniteCommentList(
fetcher: (page, batchSize, sortType) =>
LemmyApiV2(community.instanceHost).run(GetComments(
LemmyApiV3(community.instanceHost).run(GetComments(
communityId: community.community.id,
auth: accountsStore
.defaultTokenFor(community.instanceHost)
@ -205,6 +206,7 @@ class CommunityPage extends HookWidget {
sort: sortType,
limit: batchSize,
page: page,
savedOnly: false,
))),
_AboutTab(
community: community,
@ -372,10 +374,6 @@ class _AboutTab extends StatelessWidget {
@required this.onlineUsers,
}) : super(key: key);
void goToCategories() {
print('GO TO CATEGORIES');
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
@ -413,14 +411,6 @@ class _AboutTab extends StatelessWidget {
),
),
const _Divider(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: OutlinedButton(
onPressed: goToCategories,
child: Text(community.category.name),
),
),
const _Divider(),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: OutlinedButton(
@ -446,7 +436,7 @@ class _AboutTab extends StatelessWidget {
ListTile(
title: Text(
mod.moderator.preferredUsername ?? '@${mod.moderator.name}'),
onTap: () => goToUser.fromUserSafe(context, mod.moderator),
onTap: () => goToUser.fromPersonSafe(context, mod.moderator),
),
]
],
@ -480,7 +470,7 @@ class _FollowButton extends HookWidget {
subscribe(Jwt token) async {
delayed.start();
try {
await LemmyApiV2(community.instanceHost).run(FollowCommunity(
await LemmyApiV3(community.instanceHost).run(FollowCommunity(
communityId: community.community.id,
follow: !isSubbed.value,
auth: token.raw));

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:image_picker/image_picker.dart';
import 'package:lemmy_api_client/pictrs.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
import '../hooks/image_picker.dart';
@ -64,7 +64,7 @@ class CreatePostPage extends HookWidget {
final pictrsDeleteToken = useState<PictrsUploadFile>(null);
final allCommunitiesSnap = useMemoFuture(
() => LemmyApiV2(selectedInstance.value)
() => LemmyApiV3(selectedInstance.value)
.run(ListCommunities(
type: PostListingType.all,
sort: SortType.hot,
@ -233,7 +233,7 @@ class CreatePostPage extends HookWidget {
return;
}
final api = LemmyApiV2(selectedInstance.value);
final api = LemmyApiV3(selectedInstance.value);
final token = accStore.defaultTokenFor(selectedInstance.value);

View File

@ -2,7 +2,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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/logged_in_action.dart';
import '../hooks/refreshable.dart';
@ -36,7 +36,7 @@ class FullPostPage extends HookWidget {
final scrollController = useScrollController();
final fullPostRefreshable =
useRefreshable(() => LemmyApiV2(instanceHost).run(GetPost(
useRefreshable(() => LemmyApiV3(instanceHost).run(GetPost(
id: id,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
)));

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/infinite_scroll.dart';
import '../hooks/memo_future.dart';
@ -34,7 +34,7 @@ class HomeTab extends HookWidget {
final instancesIcons = useMemoFuture(() async {
final instances = accStore.instances.toList(growable: false);
final sites = await Future.wait(instances.map(
(e) => LemmyApiV2(e).run(const GetSite()).catchError((e) => null)));
(e) => LemmyApiV3(e).run(const GetSite()).catchError((e) => null)));
return {
for (var i = 0; i < sites.length; i++)
@ -286,11 +286,12 @@ class InfiniteHomeList extends HookWidget {
final futures = [
for (final instanceHost in instances)
LemmyApiV2(instanceHost).run(GetPosts(
LemmyApiV3(instanceHost).run(GetPosts(
type: listingType,
sort: sort,
page: page,
limit: limit,
savedOnly: false,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
))
];
@ -308,11 +309,12 @@ class InfiniteHomeList extends HookWidget {
FetcherWithSorting<PostView> fetcherFromInstance(
String instanceHost, PostListingType listingType) =>
(page, batchSize, sort) => LemmyApiV2(instanceHost).run(GetPosts(
(page, batchSize, sort) => LemmyApiV3(instanceHost).run(GetPosts(
type: listingType,
sort: sort,
page: page,
limit: batchSize,
savedOnly: false,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
));

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:matrix4_transform/matrix4_transform.dart';
import '../hooks/delayed_loading.dart';
@ -106,7 +106,7 @@ class InboxPage extends HookWidget {
controller: isc,
defaultSort: SortType.new_,
fetcher: (page, batchSize, sortType) =>
LemmyApiV2(selected.value).run(GetReplies(
LemmyApiV3(selected.value).run(GetReplies(
auth: accStore.defaultTokenFor(selected.value).raw,
sort: sortType,
limit: batchSize,
@ -119,19 +119,19 @@ class InboxPage extends HookWidget {
hideOnRead: unreadOnly.value,
),
),
SortableInfiniteList<UserMentionView>(
SortableInfiniteList<PersonMentionView>(
noItems: const Text('no mentions'),
controller: isc,
defaultSort: SortType.new_,
fetcher: (page, batchSize, sortType) =>
LemmyApiV2(selected.value).run(GetUserMentions(
LemmyApiV3(selected.value).run(GetPersonMentions(
auth: accStore.defaultTokenFor(selected.value).raw,
sort: sortType,
limit: batchSize,
page: page,
unreadOnly: unreadOnly.value,
)),
itemBuilder: (umv) => CommentWidget.fromUserMentionView(
itemBuilder: (umv) => CommentWidget.fromPersonMentionView(
umv,
hideOnRead: unreadOnly.value,
),
@ -142,7 +142,7 @@ class InboxPage extends HookWidget {
child: Text('no messages'),
),
controller: isc,
fetcher: (page, batchSize) => LemmyApiV2(selected.value).run(
fetcher: (page, batchSize) => LemmyApiV3(selected.value).run(
GetPrivateMessages(
auth: accStore.defaultTokenFor(selected.value).raw,
limit: batchSize,
@ -189,7 +189,7 @@ class PrivateMessageTile extends HookWidget {
final toMe = useMemoized(() =>
pmv.value.recipient.originInstanceHost == pmv.value.instanceHost &&
pmv.value.recipient.id ==
accStore.defaultTokenFor(pmv.value.instanceHost)?.payload?.id);
accStore.defaultTokenFor(pmv.value.instanceHost)?.payload?.sub);
final otherSide =
useMemoized(() => toMe ? pmv.value.creator : pmv.value.recipient);
@ -285,7 +285,7 @@ class PrivateMessageTile extends HookWidget {
),
InkWell(
borderRadius: BorderRadius.circular(10),
onTap: () => goToUser.fromUserSafe(context, otherSide),
onTap: () => goToUser.fromPersonSafe(context, otherSide),
child: Row(
children: [
if (otherSide.avatar != null)

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:url_launcher/url_launcher.dart' as ul;
import '../hooks/stores.dart';
@ -32,14 +32,14 @@ class InstancePage extends HookWidget {
InstancePage({@required this.instanceHost})
: assert(instanceHost != null),
siteFuture = LemmyApiV2(instanceHost).run(const GetSite()),
communitiesFuture = LemmyApiV2(instanceHost).run(const ListCommunities(
siteFuture = LemmyApiV3(instanceHost).run(const GetSite()),
communitiesFuture = LemmyApiV3(instanceHost).run(const ListCommunities(
type: PostListingType.local, sort: SortType.hot, limit: 6));
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final siteSnap = useFuture(siteFuture);
final siteSnap = useFuture(siteFuture, initialData: null);
final colorOnCard = textColorBasedOnBackground(theme.cardColor);
final accStore = useAccountsStore();
final scrollController = useScrollController();
@ -177,21 +177,23 @@ class InstancePage extends HookWidget {
children: [
InfinitePostList(
fetcher: (page, batchSize, sort) =>
LemmyApiV2(instanceHost).run(GetPosts(
LemmyApiV3(instanceHost).run(GetPosts(
// TODO: switch between all and subscribed
type: PostListingType.all,
sort: sort,
limit: batchSize,
page: page,
savedOnly: false,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
))),
InfiniteCommentList(
fetcher: (page, batchSize, sort) =>
LemmyApiV2(instanceHost).run(GetComments(
LemmyApiV3(instanceHost).run(GetComments(
type: CommentListingType.all,
sort: sort,
limit: batchSize,
page: page,
savedOnly: false,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
))),
_AboutTab(site,
@ -228,14 +230,14 @@ class _AboutTab extends HookWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final commSnap = useFuture(communitiesFuture);
final commSnap = useFuture(communitiesFuture, initialData: null);
final accStore = useAccountsStore();
void goToCommunities() {
goTo(
context,
(_) => CommunitiesListPage(
fetcher: (page, batchSize, sortType) => LemmyApiV2(instanceHost).run(
fetcher: (page, batchSize, sortType) => LemmyApiV3(instanceHost).run(
ListCommunities(
type: PostListingType.local,
sort: sortType,
@ -325,12 +327,12 @@ class _AboutTab extends HookWidget {
),
for (final u in site.admins)
ListTile(
title: Text(u.user.originDisplayName),
subtitle: u.user.bio != null
? MarkdownText(u.user.bio, instanceHost: instanceHost)
title: Text(u.person.originDisplayName),
subtitle: u.person.bio != null
? MarkdownText(u.person.bio, instanceHost: instanceHost)
: null,
onTap: () => goToUser.fromUserSafe(context, u.user),
leading: Avatar(url: u.user.avatar),
onTap: () => goToUser.fromPersonSafe(context, u.person),
leading: Avatar(url: u.person.avatar),
),
const _Divider(),
ListTile(

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:image_picker/image_picker.dart';
import 'package:lemmy_api_client/pictrs.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
import '../hooks/image_picker.dart';
@ -31,7 +31,7 @@ class ManageAccountPage extends HookWidget {
final accountStore = useAccountsStore();
final userFuture = useMemoized(() async {
final site = await LemmyApiV2(instanceHost).run(
final site = await LemmyApiV3(instanceHost).run(
GetSite(auth: accountStore.tokenFor(instanceHost, username).raw));
return site.myUser;
@ -41,7 +41,7 @@ class ManageAccountPage extends HookWidget {
appBar: AppBar(
title: Text('@$instanceHost@$username'),
),
body: FutureBuilder<UserSafeSettings>(
body: FutureBuilder<LocalUserSettingsView>(
future: userFuture,
builder: (_, userSnap) {
if (userSnap.hasError) {
@ -63,7 +63,7 @@ class _ManageAccount extends HookWidget {
: assert(user != null),
super(key: key);
final UserSafeSettings user;
final LocalUserSettingsView user;
@override
Widget build(BuildContext context) {
@ -73,18 +73,20 @@ class _ManageAccount extends HookWidget {
final deleteDelayedLoading = useDelayedLoading();
final displayNameController =
useTextEditingController(text: user.preferredUsername);
final bioController = useTextEditingController(text: user.bio);
final emailController = useTextEditingController(text: user.email);
useTextEditingController(text: user.person.preferredUsername);
final bioController = useTextEditingController(text: user.person.bio);
final emailController =
useTextEditingController(text: user.localUser.email);
final matrixUserController =
useTextEditingController(text: user.matrixUserId);
final avatar = useRef(user.avatar);
final banner = useRef(user.banner);
final showAvatars = useState(user.showAvatars);
final showNsfw = useState(user.showNsfw);
final sendNotificationsToEmail = useState(user.sendNotificationsToEmail);
final defaultListingType = useState(user.defaultListingType);
final defaultSortType = useState(user.defaultSortType);
useTextEditingController(text: user.person.matrixUserId);
final avatar = useRef(user.person.avatar);
final banner = useRef(user.person.banner);
final showAvatars = useState(user.localUser.showAvatars);
final showNsfw = useState(user.localUser.showNsfw);
final sendNotificationsToEmail =
useState(user.localUser.sendNotificationsToEmail);
final defaultListingType = useState(user.localUser.defaultListingType);
final defaultSortType = useState(user.localUser.defaultSortType);
final newPasswordController = useTextEditingController();
final newPasswordVerifyController = useTextEditingController();
final oldPasswordController = useTextEditingController();
@ -94,18 +96,18 @@ class _ManageAccount extends HookWidget {
final deleteAccountPasswordController = useTextEditingController();
final token = accountsStore.tokenFor(user.instanceHost, user.name);
final token = accountsStore.tokenFor(user.instanceHost, user.person.name);
handleSubmit() async {
saveDelayedLoading.start();
try {
await LemmyApiV2(user.instanceHost).run(SaveUserSettings(
await LemmyApiV3(user.instanceHost).run(SaveUserSettings(
showNsfw: showNsfw.value,
theme: user.theme,
theme: user.localUser.theme,
defaultSortType: defaultSortType.value,
defaultListingType: defaultListingType.value,
lang: user.lang,
lang: user.localUser.lang,
showAvatars: showAvatars.value,
sendNotificationsToEmail: sendNotificationsToEmail.value,
auth: token.raw,
@ -150,7 +152,7 @@ class _ManageAccount extends HookWidget {
context: context,
builder: (context) => AlertDialog(
title: Text(
'${L10n.of(context).delete_account} @${user.instanceHost}@${user.name}'),
'${L10n.of(context).delete_account} @${user.instanceHost}@${user.person.name}'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
@ -182,12 +184,13 @@ class _ManageAccount extends HookWidget {
deleteDelayedLoading.start();
try {
await LemmyApiV2(user.instanceHost).run(DeleteAccount(
await LemmyApiV3(user.instanceHost).run(DeleteAccount(
password: deleteAccountPasswordController.text,
auth: token.raw,
));
accountsStore.removeAccount(user.instanceHost, user.name);
await accountsStore.removeAccount(
user.instanceHost, user.person.name);
Navigator.of(context).pop();
} on Exception catch (err) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
@ -354,7 +357,7 @@ class _ManageAccount extends HookWidget {
class _ImagePicker extends HookWidget {
final String name;
final String initialUrl;
final UserSafeSettings user;
final LocalUserSettingsView user;
final ValueChanged<String> onChange;
/// _ImagePicker will set the ref to a callback that can inform _ImagePicker
@ -395,7 +398,8 @@ class _ImagePicker extends HookWidget {
final upload = await PictrsApi(user.instanceHost).upload(
filePath: pic.path,
auth: accountsStore.tokenFor(user.instanceHost, user.name).raw,
auth:
accountsStore.tokenFor(user.instanceHost, user.person.name).raw,
);
pictrsDeleteToken.value = upload.files[0];
url.value =

View File

@ -1,7 +1,7 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../util/extensions/api.dart';
import '../util/extensions/datetime.dart';
@ -36,7 +36,7 @@ class ModlogPage extends HookWidget {
final isDone = useState(false);
final modlogFut = useMemoized(
() => LemmyApiV2(instanceHost).run(
() => LemmyApiV3(instanceHost).run(
GetModlog(
communityId: communityId,
page: page.value,
@ -128,7 +128,7 @@ class _ModlogTable extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
InlineSpan user(UserSafe user) => TextSpan(
InlineSpan user(PersonSafe user) => TextSpan(
children: [
WidgetSpan(
child: Avatar(
@ -307,7 +307,7 @@ class _ModlogTable extends StatelessWidget {
const TextSpan(text: 'banned ')
else
const TextSpan(text: 'unbanned '),
user(bannedFromCommunity.bannedUser),
user(bannedFromCommunity.bannedPerson),
const TextSpan(text: ' from community '),
community(bannedFromCommunity.community),
],
@ -325,7 +325,7 @@ class _ModlogTable extends StatelessWidget {
const TextSpan(text: 'banned ')
else
const TextSpan(text: 'unbanned '),
user(banned.bannedUser),
user(banned.bannedPerson),
],
style: TextStyle(color: theme.colorScheme.onSurface),
),
@ -341,7 +341,7 @@ class _ModlogTable extends StatelessWidget {
const TextSpan(text: 'removed ')
else
const TextSpan(text: 'appointed '),
user(addedToCommunity.moddedUser),
user(addedToCommunity.moddedPerson),
const TextSpan(text: ' as mod of '),
community(addedToCommunity.community),
],
@ -359,7 +359,7 @@ class _ModlogTable extends StatelessWidget {
const TextSpan(text: 'removed ')
else
const TextSpan(text: 'apointed '),
user(added.moddedUser),
user(added.moddedPerson),
const TextSpan(text: ' as admin'),
],
style: TextStyle(color: theme.colorScheme.onSurface),
@ -400,7 +400,7 @@ class _ModlogTable extends StatelessWidget {
class _ModlogEntry {
final DateTime when;
final UserSafe mod;
final PersonSafe mod;
final Widget action;
final String reason;

View File

@ -91,7 +91,7 @@ class UserProfileTab extends HookWidget {
actions: actions,
),
body: UserProfile(
userId: accountsStore.defaultToken.payload.id,
userId: accountsStore.defaultToken.payload.sub,
instanceHost: accountsStore.defaultInstanceHost,
),
);

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/stores.dart';
import '../l10n/l10n.dart';
@ -29,33 +29,29 @@ class SavedPage extends HookWidget {
children: [
InfinitePostList(
fetcher: (page, batchSize, sortType) =>
LemmyApiV2(accountStore.defaultInstanceHost)
.run(
GetUserDetails(
userId: accountStore.defaultToken.payload.id,
sort: sortType,
savedOnly: true,
page: page,
limit: batchSize,
auth: accountStore.defaultToken.raw,
),
)
.then((value) => value.posts),
LemmyApiV3(accountStore.defaultInstanceHost).run(
GetPosts(
type: PostListingType.all,
sort: sortType,
savedOnly: true,
page: page,
limit: batchSize,
auth: accountStore.defaultToken.raw,
),
),
),
InfiniteCommentList(
fetcher: (page, batchSize, sortType) =>
LemmyApiV2(accountStore.defaultInstanceHost)
.run(
GetUserDetails(
userId: accountStore.defaultToken.payload.id,
sort: sortType,
savedOnly: true,
page: page,
limit: batchSize,
auth: accountStore.defaultToken.raw,
),
)
.then((value) => value.comments),
LemmyApiV3(accountStore.defaultInstanceHost).run(
GetComments(
type: CommentListingType.all,
sort: sortType,
savedOnly: true,
page: page,
limit: batchSize,
auth: accountStore.defaultToken.raw,
),
),
),
],
),

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/stores.dart';
import '../l10n/l10n.dart';
@ -81,7 +81,7 @@ class _SearchResultsList extends HookWidget {
return SortableInfiniteList(
fetcher: (page, batchSize, sort) async {
final s = await LemmyApiV2(instanceHost).run(Search(
final s = await LemmyApiV3(instanceHost).run(Search(
q: query,
sort: sort,
type: type,
@ -115,7 +115,7 @@ class _SearchResultsList extends HookWidget {
child: PostWidget(data as PostView),
);
case SearchType.users:
return UsersListItem(user: data as UserViewSafe);
return UsersListItem(user: data as PersonViewSafe);
default:
throw UnimplementedError();
}

View File

@ -127,7 +127,7 @@ class AccountsConfigPage extends HookWidget {
),
) ??
false) {
accountsStore.removeInstance(instanceHost);
await accountsStore.removeInstance(instanceHost);
}
}
@ -151,7 +151,7 @@ class AccountsConfigPage extends HookWidget {
),
) ??
false) {
accountsStore.removeAccount(instanceHost, username);
return accountsStore.removeAccount(instanceHost, username);
}
}

View File

@ -1,7 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/logged_in_action.dart';
import '../util/share.dart';
@ -12,28 +12,28 @@ import 'write_message.dart';
class UserPage extends HookWidget {
final int userId;
final String instanceHost;
final Future<FullUserView> _userDetails;
final Future<FullPersonView> _userDetails;
UserPage({@required this.userId, @required this.instanceHost})
: assert(userId != null),
assert(instanceHost != null),
_userDetails = LemmyApiV2(instanceHost).run(GetUserDetails(
userId: userId, savedOnly: true, sort: SortType.active));
_userDetails = LemmyApiV3(instanceHost).run(GetPersonDetails(
personId: userId, savedOnly: true, sort: SortType.active));
UserPage.fromName({@required this.instanceHost, @required String username})
: assert(instanceHost != null),
assert(username != null),
userId = null,
_userDetails = LemmyApiV2(instanceHost).run(GetUserDetails(
_userDetails = LemmyApiV3(instanceHost).run(GetPersonDetails(
username: username, savedOnly: true, sort: SortType.active));
@override
Widget build(BuildContext context) {
final userDetailsSnap = useFuture(_userDetails);
final userDetailsSnap = useFuture(_userDetails, initialData: null);
final body = () {
if (userDetailsSnap.hasData) {
return UserProfile.fromFullUserView(userDetailsSnap.data);
return UserProfile.fromFullPersonView(userDetailsSnap.data);
} else if (userDetailsSnap.hasError) {
return const Center(child: Text('Could not find that user.'));
} else {
@ -46,11 +46,11 @@ class UserPage extends HookWidget {
appBar: AppBar(
actions: [
if (userDetailsSnap.hasData) ...[
SendMessageButton(userDetailsSnap.data.userView.user),
SendMessageButton(userDetailsSnap.data.personView.person),
IconButton(
icon: const Icon(Icons.share),
onPressed: () => share(
userDetailsSnap.data.userView.user.actorId,
userDetailsSnap.data.personView.person.actorId,
context: context,
),
),
@ -63,7 +63,7 @@ class UserPage extends HookWidget {
}
class SendMessageButton extends HookWidget {
final UserSafe user;
final PersonSafe user;
const SendMessageButton(this.user);

View File

@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart';
@ -9,7 +9,7 @@ import '../widgets/markdown_text.dart';
/// Infinite list of Users fetched by the given fetcher
class UsersListPage extends StatelessWidget {
final String title;
final List<UserViewSafe> users;
final List<PersonViewSafe> 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 UserViewSafe user;
final PersonViewSafe user;
const UsersListItem({Key key, @required this.user})
: assert(user != null),
@ -42,17 +42,17 @@ class UsersListItem extends StatelessWidget {
@override
Widget build(BuildContext context) => ListTile(
title: Text(user.user.originDisplayName),
subtitle: user.user.bio != null
title: Text(user.person.originDisplayName),
subtitle: user.person.bio != null
? Opacity(
opacity: 0.5,
child: MarkdownText(
user.user.bio,
user.person.bio,
instanceHost: user.instanceHost,
),
)
: null,
onTap: () => goToUser.fromUserSafe(context, user.user),
leading: Avatar(url: user.user.avatar),
onTap: () => goToUser.fromPersonSafe(context, user.person),
leading: Avatar(url: user.person.avatar),
);
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/stores.dart';
import '../l10n/l10n.dart';
@ -10,7 +10,7 @@ import '../widgets/markdown_text.dart';
/// Page for writing and editing a private message
class WriteMessagePage extends HookWidget {
final UserSafe recipient;
final PersonSafe recipient;
final String instanceHost;
/// if it's non null then this page is used for edit
@ -47,7 +47,7 @@ class WriteMessagePage extends HookWidget {
if (_isEdit) {
loading.value = true;
try {
final msg = await LemmyApiV2(instanceHost).run(EditPrivateMessage(
final msg = await LemmyApiV3(instanceHost).run(EditPrivateMessage(
auth: accStore.defaultTokenFor(instanceHost)?.raw,
privateMessageId: privateMessage.id,
content: bodyController.text,
@ -64,7 +64,7 @@ class WriteMessagePage extends HookWidget {
} else {
loading.value = true;
try {
await LemmyApiV2(instanceHost).run(CreatePrivateMessage(
await LemmyApiV3(instanceHost).run(CreatePrivateMessage(
auth: accStore.defaultTokenFor(instanceHost)?.raw,
content: bodyController.text,
recipientId: recipient.id,

View File

@ -3,17 +3,15 @@ import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../util/unawaited.dart';
part 'accounts_store.g.dart';
/// Store that manages all accounts
@JsonSerializable()
class AccountsStore extends ChangeNotifier {
static const prefsKey = 'v1:AccountsStore';
static const prefsKey = 'v2:AccountsStore';
static final _prefs = SharedPreferences.getInstance();
/// Map containing JWT tokens of specific users.
@ -50,7 +48,7 @@ class AccountsStore extends ChangeNotifier {
}
/// automatically sets default accounts
void _assignDefaultAccounts() {
Future<void> _assignDefaultAccounts() async {
// remove dangling defaults
defaultAccounts.entries
.map((dft) {
@ -80,7 +78,8 @@ class AccountsStore extends ChangeNotifier {
if (!defaultAccounts.containsKey(instanceHost)) {
// select first account in this instance, if any
if (!isAnonymousFor(instanceHost)) {
setDefaultAccountFor(instanceHost, usernamesFor(instanceHost).first);
await setDefaultAccountFor(
instanceHost, usernamesFor(instanceHost).first);
}
}
}
@ -91,7 +90,8 @@ class AccountsStore extends ChangeNotifier {
for (final instanceHost in instances) {
// select first account in this instance, if any
if (!isAnonymousFor(instanceHost)) {
setDefaultAccount(instanceHost, usernamesFor(instanceHost).first);
await setDefaultAccount(
instanceHost, usernamesFor(instanceHost).first);
}
}
}
@ -147,19 +147,19 @@ class AccountsStore extends ChangeNotifier {
}
/// sets globally default account
void setDefaultAccount(String instanceHost, String username) {
Future<void> setDefaultAccount(String instanceHost, String username) {
defaultAccount = '$username@$instanceHost';
notifyListeners();
save();
return save();
}
/// sets default account for given instance
void setDefaultAccountFor(String instanceHost, String username) {
Future<void> setDefaultAccountFor(String instanceHost, String username) {
defaultAccounts[instanceHost] = username;
notifyListeners();
save();
return save();
}
/// An instance is considered anonymous if it was not
@ -198,7 +198,7 @@ class AccountsStore extends ChangeNotifier {
throw Exception('No such instance was added');
}
final lemmy = LemmyApiV2(instanceHost);
final lemmy = LemmyApiV3(instanceHost);
final token = await lemmy.run(Login(
usernameOrEmail: usernameOrEmail,
password: password,
@ -206,11 +206,11 @@ class AccountsStore extends ChangeNotifier {
final userData =
await lemmy.run(GetSite(auth: token.raw)).then((value) => value.myUser);
tokens[instanceHost][userData.name] = token;
tokens[instanceHost][userData.person.name] = token;
_assignDefaultAccounts();
await _assignDefaultAccounts();
notifyListeners();
unawaited(save());
return save();
}
/// adds a new instance with no accounts associated with it.
@ -226,7 +226,7 @@ class AccountsStore extends ChangeNotifier {
if (!assumeValid) {
try {
await LemmyApiV2(instanceHost).run(const GetSite());
await LemmyApiV3(instanceHost).run(const GetSite());
// ignore: avoid_catches_without_on_clauses
} catch (_) {
throw Exception('This instance seems to not exist');
@ -235,25 +235,25 @@ class AccountsStore extends ChangeNotifier {
tokens[instanceHost] = HashMap();
_assignDefaultAccounts();
await _assignDefaultAccounts();
notifyListeners();
unawaited(save());
return save();
}
/// This also removes all accounts assigned to this instance
void removeInstance(String instanceHost) {
Future<void> removeInstance(String instanceHost) async {
tokens.remove(instanceHost);
_assignDefaultAccounts();
await _assignDefaultAccounts();
notifyListeners();
save();
return save();
}
void removeAccount(String instanceHost, String username) {
Future<void> removeAccount(String instanceHost, String username) async {
tokens[instanceHost].remove(username);
_assignDefaultAccounts();
await _assignDefaultAccounts();
notifyListeners();
save();
return save();
}
}

View File

@ -1,6 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
@ -22,7 +22,7 @@ Future<void> delayedAction<T>({
T val;
try {
delayedLoading.start();
val = await LemmyApiV2(instanceHost).run<T>(query);
val = await LemmyApiV3(instanceHost).run<T>(query);
onSuccess?.call(val);
// ignore: avoid_catches_without_on_clauses
} catch (e) {

View File

@ -1,4 +1,4 @@
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../cleanup_url.dart';
@ -12,7 +12,7 @@ extension GetOriginInstanceCommunitySafe on CommunitySafe {
String get originInstanceHost => _extract(actorId);
}
extension GetOriginInstanceUserSafe on UserSafe {
extension GetOriginInstancePersonSafe on PersonSafe {
String get originInstanceHost => _extract(actorId);
}
@ -32,7 +32,7 @@ extension CommunityDisplayNames on CommunitySafe {
local ? displayName : '!$name@$originInstanceHost';
}
extension UserDisplayNames on UserSafe {
extension UserDisplayNames on PersonSafe {
String get displayName {
if (preferredUsername != null && preferredUsername.isNotEmpty) {
return preferredUsername;

View File

@ -1,6 +1,6 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../pages/community.dart';
import '../pages/full_post.dart';
@ -59,8 +59,8 @@ abstract class goToUser {
BuildContext context, String instanceHost, String userName) =>
throw UnimplementedError('need to create UserProfile constructor first');
static void fromUserSafe(BuildContext context, UserSafe userSafe) =>
goToUser.byId(context, userSafe.instanceHost, userSafe.id);
static void fromPersonSafe(BuildContext context, PersonSafe personSafe) =>
goToUser.byId(context, personSafe.instanceHost, personSafe.id);
}
void goToPost(BuildContext context, String instanceHost, int postId) => goTo(

View File

@ -1,6 +1,6 @@
import 'dart:math' show log, max, pow, ln10;
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
/// Calculates hot rank
/// because API always claims it's `0`

View File

@ -2,7 +2,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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:url_launcher/url_launcher.dart' as ul;
import '../comment_tree.dart';
@ -64,15 +64,15 @@ class CommentWidget extends HookWidget {
hideOnRead: hideOnRead,
);
CommentWidget.fromUserMentionView(
UserMentionView userMentionView, {
CommentWidget.fromPersonMentionView(
PersonMentionView userMentionView, {
bool hideOnRead = false,
}) : this(
CommentTree(CommentView.fromJson(userMentionView.toJson())),
hideOnRead: hideOnRead,
canBeMarkedAsRead: true,
detached: true,
userMentionId: userMentionView.userMention.id,
userMentionId: userMentionView.personMention.id,
);
_showCommentInfo(BuildContext context) {
@ -95,7 +95,10 @@ class CommentWidget extends HookWidget {
final accStore = useAccountsStore();
final isMine = commentTree.comment.comment.creatorId ==
accStore.defaultTokenFor(commentTree.comment.instanceHost)?.payload?.id;
accStore
.defaultTokenFor(commentTree.comment.instanceHost)
?.payload
?.sub;
final selectable = useState(false);
final showRaw = useState(false);
final collapsed = useState(false);
@ -345,7 +348,7 @@ class CommentWidget extends HookWidget {
padding: const EdgeInsets.only(right: 5),
child: InkWell(
onTap: () =>
goToUser.fromUserSafe(context, comment.creator),
goToUser.fromPersonSafe(context, comment.creator),
child: Avatar(
url: comment.creator.avatar,
radius: 10,
@ -355,7 +358,7 @@ class CommentWidget extends HookWidget {
),
InkWell(
onTap: () =>
goToUser.fromUserSafe(context, comment.creator),
goToUser.fromPersonSafe(context, comment.creator),
child: Text(comment.creator.originDisplayName,
style: TextStyle(
color: theme.accentColor,
@ -446,17 +449,17 @@ class _MarkAsRead extends HookWidget {
},
);
Future<void> handleMarkMentionAsSeen() => delayedAction<UserMentionView>(
Future<void> handleMarkMentionAsSeen() => delayedAction<PersonMentionView>(
context: context,
delayedLoading: delayedRead,
instanceHost: instanceHost,
query: MarkUserMentionAsRead(
userMentionId: userMentionId,
query: MarkPersonMentionAsRead(
personMentionId: userMentionId,
read: !isRead.value,
auth: accStore.defaultTokenFor(instanceHost)?.raw,
),
onSuccess: (val) {
isRead.value = val.userMention.read;
isRead.value = val.personMention.read;
onChanged?.call(isRead.value);
},
);

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../comment_tree.dart';
import '../l10n/l10n.dart';

View File

@ -34,7 +34,7 @@ class MarkdownText extends StatelessWidget {
// TODO: use a font from google fonts maybe? the defaults aren't very pretty
.copyWith(fontFamily: Platform.isIOS ? 'Courier' : 'monospace'),
),
onTapLink: (href) {
onTapLink: (text, href, title) {
linkLauncher(context: context, url: href, instanceHost: instanceHost)
.catchError(
(e) => ScaffoldMessenger.of(context).showSnackBar(SnackBar(

View File

@ -4,7 +4,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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:url_launcher/url_launcher.dart' as ul;
import '../hooks/delayed_loading.dart';
@ -191,7 +191,7 @@ class PostWidget extends HookWidget {
style: const TextStyle(
fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer()
..onTap = () => goToUser.fromUserSafe(
..onTap = () => goToUser.fromPersonSafe(
context,
post.creator,
),
@ -496,7 +496,7 @@ class _Voting extends HookWidget {
final loggedInAction = useLoggedInAction(post.instanceHost);
vote(VoteType vote, Jwt token) async {
final api = LemmyApiV2(post.instanceHost);
final api = LemmyApiV3(post.instanceHost);
loading.start();
try {

View File

@ -1,6 +1,6 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../l10n/l10n.dart';
import 'radio_picker.dart';

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
import '../hooks/logged_in_action.dart';
@ -20,7 +20,7 @@ class SavePostButton extends HookWidget {
final loggedInAction = useLoggedInAction(post.instanceHost);
savePost(Jwt token) async {
final api = LemmyApiV2(post.instanceHost);
final api = LemmyApiV3(post.instanceHost);
loading.start();
try {

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../comment_tree.dart';
import '../hooks/infinite_scroll.dart';

View File

@ -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/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/memo_future.dart';
import '../hooks/stores.dart';
@ -22,16 +22,16 @@ class UserProfile extends HookWidget {
final String instanceHost;
final int userId;
final FullUserView _fullUserView;
final FullPersonView _fullUserView;
const UserProfile({@required this.userId, @required this.instanceHost})
: assert(userId != null),
assert(instanceHost != null),
_fullUserView = null;
UserProfile.fromFullUserView(this._fullUserView)
UserProfile.fromFullPersonView(this._fullUserView)
: assert(_fullUserView != null),
userId = _fullUserView.userView.user.id,
userId = _fullUserView.personView.person.id,
instanceHost = _fullUserView.instanceHost;
@override
@ -41,8 +41,8 @@ class UserProfile extends HookWidget {
final userDetailsSnap = useMemoFuture(() async {
if (_fullUserView != null) return _fullUserView;
return await LemmyApiV2(instanceHost).run(GetUserDetails(
userId: userId,
return await LemmyApiV3(instanceHost).run(GetPersonDetails(
personId: userId,
savedOnly: false,
sort: SortType.active,
auth: accountsStore.defaultTokenFor(instanceHost)?.raw,
@ -63,7 +63,7 @@ class UserProfile extends HookWidget {
);
}
final userView = userDetailsSnap.data.userView;
final userView = userDetailsSnap.data.personView;
return DefaultTabController(
length: 3,
@ -96,9 +96,9 @@ 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) => LemmyApiV2(instanceHost)
.run(GetUserDetails(
userId: userView.user.id,
fetcher: (page, batchSize, sort) => LemmyApiV3(instanceHost)
.run(GetPersonDetails(
personId: userView.person.id,
savedOnly: false,
sort: SortType.active,
page: page,
@ -108,9 +108,9 @@ class UserProfile extends HookWidget {
.then((val) => val.posts),
),
InfiniteCommentList(
fetcher: (page, batchSize, sort) => LemmyApiV2(instanceHost)
.run(GetUserDetails(
userId: userView.user.id,
fetcher: (page, batchSize, sort) => LemmyApiV3(instanceHost)
.run(GetPersonDetails(
personId: userView.person.id,
savedOnly: false,
sort: SortType.active,
page: page,
@ -131,7 +131,7 @@ class UserProfile extends HookWidget {
/// Such as his nickname, no. of posts, no. of posts,
/// banner, avatar etc.
class _UserOverview extends HookWidget {
final UserViewSafe userView;
final PersonViewSafe userView;
const _UserOverview(this.userView);
@ -143,12 +143,12 @@ class _UserOverview extends HookWidget {
return Stack(
children: [
if (userView.user.banner != null)
if (userView.person.banner != null)
// TODO: for some reason doesnt react to presses
FullscreenableImage(
url: userView.user.banner,
url: userView.person.banner,
child: CachedNetworkImage(
imageUrl: userView.user.banner,
imageUrl: userView.person.banner,
errorWidget: (_, __, ___) => const SizedBox.shrink(),
),
)
@ -192,7 +192,7 @@ class _UserOverview extends HookWidget {
SafeArea(
child: Column(
children: [
if (userView.user.avatar != null)
if (userView.person.avatar != null)
SizedBox(
width: 80,
height: 80,
@ -207,21 +207,21 @@ class _UserOverview extends HookWidget {
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: FullscreenableImage(
url: userView.user.avatar,
url: userView.person.avatar,
child: CachedNetworkImage(
imageUrl: userView.user.avatar,
imageUrl: userView.person.avatar,
errorWidget: (_, __, ___) => const SizedBox.shrink(),
),
),
),
),
),
if (userView.user.avatar != null)
if (userView.person.avatar != null)
const SizedBox(height: 8)
else
const SizedBox(height: 80),
Text(
userView.user.displayName,
userView.person.displayName,
style: theme.textTheme.headline6,
),
const SizedBox(height: 4),
@ -229,14 +229,14 @@ class _UserOverview extends HookWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'@${userView.user.name}@',
'@${userView.person.name}@',
style: theme.textTheme.caption,
),
InkWell(
onTap: () =>
goToInstance(context, userView.user.originInstanceHost),
onTap: () => goToInstance(
context, userView.person.originInstanceHost),
child: Text(
userView.user.originInstanceHost,
userView.person.originInstanceHost,
style: theme.textTheme.caption,
),
)
@ -284,7 +284,7 @@ class _UserOverview extends HookWidget {
),
const SizedBox(height: 15),
Text(
'Joined ${userView.user.published.fancy}',
'Joined ${userView.person.published.fancy}',
style: theme.textTheme.bodyText1,
),
Row(
@ -298,7 +298,7 @@ class _UserOverview extends HookWidget {
padding: const EdgeInsets.only(left: 4),
child: Text(
DateFormat('MMM dd, yyyy')
.format(userView.user.published),
.format(userView.person.published),
style: theme.textTheme.bodyText1,
),
),
@ -314,21 +314,21 @@ class _UserOverview extends HookWidget {
}
class _AboutTab extends HookWidget {
final FullUserView userDetails;
final FullPersonView userDetails;
const _AboutTab(this.userDetails);
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final instanceHost = userDetails.userView.user.instanceHost;
final instanceHost = userDetails.personView.person.instanceHost;
final accStore = useAccountsStore();
final isOwnedAccount = accStore.loggedInInstances.contains(instanceHost) &&
accStore
.usernamesFor(instanceHost)
.contains(userDetails.userView.user.name);
.contains(userDetails.personView.person.name);
const wallPadding = EdgeInsets.symmetric(horizontal: 15);
@ -365,13 +365,13 @@ class _AboutTab extends HookWidget {
context,
(_) => ManageAccountPage(
instanceHost: userDetails.instanceHost,
username: userDetails.userView.user.name),
username: userDetails.personView.person.name),
),
),
if (userDetails.userView.user.bio != null) ...[
if (userDetails.personView.person.bio != null) ...[
Padding(
padding: wallPadding,
child: MarkdownText(userDetails.userView.user.bio,
child: MarkdownText(userDetails.personView.person.bio,
instanceHost: instanceHost)),
divider,
],

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v2.dart';
import 'package:lemmy_api_client/v3.dart';
import '../hooks/delayed_loading.dart';
import '../hooks/stores.dart';
@ -28,10 +28,11 @@ class WriteComment extends HookWidget {
final accStore = useAccountsStore();
final preview = () {
final body = MarkdownText(
comment?.content ?? post.body,
instanceHost: post.instanceHost,
);
final body = () {
final text = comment?.content ?? post.body;
if (text == null) return const SizedBox.shrink();
return MarkdownText(text, instanceHost: post.instanceHost);
}();
if (post != null) {
return Column(
@ -50,7 +51,7 @@ class WriteComment extends HookWidget {
}();
handleSubmit() async {
final api = LemmyApiV2(post.instanceHost);
final api = LemmyApiV3(post.instanceHost);
final token = accStore.defaultTokenFor(post.instanceHost);

View File

@ -7,28 +7,28 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "14.0.0"
version: "19.0.0"
analyzer:
dependency: transitive
description:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "0.41.2"
version: "1.3.0"
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
version: "3.1.2"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
version: "2.0.0"
async:
dependency: transitive
description:
@ -49,42 +49,42 @@ packages:
name: build
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.2"
version: "2.0.0"
build_config:
dependency: transitive
description:
name: build_config
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.5"
version: "0.4.7"
build_daemon:
dependency: transitive
description:
name: build_daemon
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.9"
version: "2.1.10"
build_resolvers:
dependency: transitive
description:
name: build_resolvers
url: "https://pub.dartlang.org"
source: hosted
version: "1.5.3"
version: "2.0.0"
build_runner:
dependency: "direct dev"
description:
name: build_runner
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.1"
version: "1.12.2"
build_runner_core:
dependency: transitive
description:
name: build_runner_core
url: "https://pub.dartlang.org"
source: hosted
version: "6.1.7"
version: "6.1.12"
built_collection:
dependency: transitive
description:
@ -98,14 +98,14 @@ packages:
name: built_value
url: "https://pub.dartlang.org"
source: hosted
version: "8.0.2"
version: "8.0.4"
cached_network_image:
dependency: "direct main"
description:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "2.5.0"
version: "2.5.1"
characters:
dependency: transitive
description:
@ -126,7 +126,7 @@ packages:
name: checked_yaml
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "2.0.1"
cli_util:
dependency: transitive
description:
@ -147,7 +147,7 @@ packages:
name: code_builder
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.0"
version: "3.7.0"
collection:
dependency: transitive
description:
@ -161,14 +161,14 @@ packages:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "3.0.0"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.5"
version: "3.0.0"
cupertino_icons:
dependency: "direct main"
description:
@ -182,7 +182,7 @@ packages:
name: dart_style
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.12"
version: "2.0.0"
fake_async:
dependency: transitive
description:
@ -196,7 +196,7 @@ packages:
name: ffi
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.3"
version: "1.0.0"
file:
dependency: transitive
description:
@ -229,21 +229,21 @@ packages:
name: flutter_cache_manager
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.1.2"
flutter_hooks:
dependency: "direct main"
description:
name: flutter_hooks
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.2"
version: "0.16.0"
flutter_launcher_icons:
dependency: "direct dev"
description:
name: flutter_launcher_icons
url: "https://pub.dartlang.org"
source: hosted
version: "0.8.1"
version: "0.9.0"
flutter_localizations:
dependency: "direct main"
description: flutter
@ -255,14 +255,14 @@ packages:
name: flutter_markdown
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.4"
version: "0.6.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.11"
version: "2.0.0"
flutter_slidable:
dependency: "direct main"
description:
@ -293,7 +293,7 @@ packages:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0"
version: "0.14.1"
fuzzy:
dependency: "direct main"
description:
@ -307,56 +307,63 @@ packages:
name: glob
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "2.0.1"
graphs:
dependency: transitive
description:
name: graphs
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
version: "1.0.0"
http:
dependency: transitive
description:
name: http
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.2"
version: "0.13.1"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0"
version: "3.0.0"
http_parser:
dependency: transitive
description:
name: http_parser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.4"
version: "4.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.19"
version: "3.0.2"
image_picker:
dependency: "direct main"
description:
name: image_picker
url: "https://pub.dartlang.org"
source: hosted
version: "0.6.7+21"
version: "0.7.3"
image_picker_for_web:
dependency: transitive
description:
name: image_picker_for_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
image_picker_platform_interface:
dependency: transitive
description:
name: image_picker_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "2.0.0"
intl:
dependency: "direct main"
description:
@ -370,7 +377,7 @@ packages:
name: io
url: "https://pub.dartlang.org"
source: hosted
version: "0.3.5"
version: "1.0.0"
js:
dependency: transitive
description:
@ -384,14 +391,14 @@ packages:
name: json_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
version: "4.0.1"
json_serializable:
dependency: "direct dev"
description:
name: json_serializable
url: "https://pub.dartlang.org"
source: hosted
version: "3.5.1"
version: "4.1.0"
latinize:
dependency: transitive
description:
@ -405,21 +412,21 @@ packages:
name: lemmy_api_client
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.0"
version: "0.13.0"
logging:
dependency: transitive
description:
name: logging
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
version: "1.0.1"
markdown:
dependency: "direct main"
description:
name: markdown
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.8"
version: "4.0.0"
matcher:
dependency: transitive
description:
@ -461,21 +468,7 @@ packages:
name: nested
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4"
node_interop:
dependency: transitive
description:
name: node_interop
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.1"
node_io:
dependency: transitive
description:
name: node_io
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.1"
version: "1.0.0"
octo_image:
dependency: transitive
description:
@ -489,14 +482,14 @@ packages:
name: package_config
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.3"
version: "2.0.0"
package_info:
dependency: "direct main"
description:
name: package_info
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.3+2"
version: "0.4.3+4"
path:
dependency: transitive
description:
@ -510,49 +503,49 @@ packages:
name: path_provider
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.27"
version: "2.0.1"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.1+2"
version: "2.0.0"
path_provider_macos:
dependency: transitive
description:
name: path_provider_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+8"
version: "2.0.0"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.4"
version: "2.0.0"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.4+3"
version: "2.0.0"
pedantic:
dependency: transitive
description:
name: pedantic
url: "https://pub.dartlang.org"
source: hosted
version: "1.9.2"
version: "1.11.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.0"
version: "4.0.2"
photo_view:
dependency: "direct main"
description:
@ -587,7 +580,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
version: "4.1.0"
version: "4.2.1"
provider:
dependency: "direct main"
description:
@ -608,7 +601,7 @@ packages:
name: pubspec_parse
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.8"
version: "1.0.0"
rxdart:
dependency: transitive
description:
@ -629,14 +622,7 @@ packages:
name: shared_preferences
url: "https://pub.dartlang.org"
source: hosted
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+4"
version: "0.5.7+3"
shared_preferences_macos:
dependency: transitive
description:
@ -658,27 +644,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2+7"
shared_preferences_windows:
dependency: transitive
description:
name: shared_preferences_windows
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2+2"
shelf:
dependency: transitive
description:
name: shelf
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.9"
version: "1.1.0"
shelf_web_socket:
dependency: transitive
description:
name: shelf_web_socket
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.4+1"
version: "1.0.1"
sky_engine:
dependency: transitive
description: flutter
@ -690,7 +669,7 @@ packages:
name: source_gen
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.10+3"
version: "1.0.0"
source_span:
dependency: transitive
description:
@ -704,14 +683,14 @@ packages:
name: sqflite
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.2+2"
version: "2.0.0+3"
sqflite_common:
dependency: transitive
description:
name: sqflite_common
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.3+1"
version: "2.0.0+2"
stack_trace:
dependency: transitive
description:
@ -746,7 +725,7 @@ packages:
name: synchronized
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.0+2"
version: "3.0.0"
term_glyph:
dependency: transitive
description:
@ -767,14 +746,14 @@ packages:
name: timeago
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.29"
version: "2.0.30"
timing:
dependency: transitive
description:
name: timing
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1+3"
version: "1.0.0"
typed_data:
dependency: transitive
description:
@ -816,7 +795,7 @@ packages:
name: url_launcher_web
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.5+1"
version: "0.1.5+3"
url_launcher_windows:
dependency: transitive
description:
@ -830,7 +809,7 @@ packages:
name: uuid
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.2"
version: "3.0.3"
vector_math:
dependency: transitive
description:
@ -844,42 +823,42 @@ packages:
name: watcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.7+15"
version: "1.0.0"
web_socket_channel:
dependency: transitive
description:
name: web_socket_channel
url: "https://pub.dartlang.org"
source: hosted
version: "1.2.0"
version: "2.0.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
source: hosted
version: "1.7.4"
version: "2.0.5"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.2"
version: "0.2.0"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "4.5.1"
version: "5.0.2"
yaml:
dependency: transitive
description:
name: yaml
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
version: "3.1.0"
sdks:
dart: ">=2.12.0-259.9.beta <3.0.0"
flutter: ">=1.22.2"
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.24.0-10"

View File

@ -25,8 +25,8 @@ dependencies:
flutter_speed_dial: ^1.2.5
flutter_slidable: ^0.5.7
photo_view: ^0.10.2
markdown: ^2.1.8
flutter_markdown: ^0.4.3
markdown: ^4.0.0
flutter_markdown: ^0.6.1
cached_network_image: ^2.2.0+1
modal_bottom_sheet: ^1.0.0+1
@ -35,19 +35,19 @@ dependencies:
url_launcher: ^5.5.1
shared_preferences: ">=0.5.0 <2.0.0"
package_info: ^0.4.3
image_picker: ^0.6.7
image_picker: ^0.7.3
# state management
flutter_hooks: ^0.13.2
flutter_hooks: ^0.16.0
provider: ^4.3.1
# utils
timeago: ^2.0.27
fuzzy: <1.0.0
lemmy_api_client: ^0.12.0
lemmy_api_client: ^0.13.0
intl: ^0.17.0
matrix4_transform: ^1.1.7
json_annotation: ^3.1.1
json_annotation: ^4.0.1
flutter:
sdk: flutter
@ -61,8 +61,8 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_launcher_icons: ^0.8.1
json_serializable: ^3.5.1
flutter_launcher_icons: ^0.9.0
json_serializable: ^4.1.0
build_runner: ^1.11.1
flutter_icons: