Fix federation errors and rename all instanceUrl to instanceHost

This commit is contained in:
shilangyu 2020-12-31 13:58:23 +00:00
parent a9e5113890
commit 58f964ab66
26 changed files with 210 additions and 256 deletions

View File

@ -14,13 +14,13 @@ import 'stores.dart';
Function( Function(
Function(Jwt token) action, [ Function(Jwt token) action, [
String message, String message,
]) useLoggedInAction(String instanceUrl, {bool any = false}) { ]) useLoggedInAction(String instanceHost, {bool any = false}) {
final context = useContext(); final context = useContext();
final store = useAccountsStore(); final store = useAccountsStore();
return (Function(Jwt token) action, [message]) { return (Function(Jwt token) action, [message]) {
if (any && store.hasNoAccount || if (any && store.hasNoAccount ||
!any && store.isAnonymousFor(instanceUrl)) { !any && store.isAnonymousFor(instanceHost)) {
return () { return () {
Scaffold.of(context).showSnackBar(SnackBar( Scaffold.of(context).showSnackBar(SnackBar(
content: Text(message ?? 'you have to be logged in to do that'), content: Text(message ?? 'you have to be logged in to do that'),
@ -30,7 +30,7 @@ Function(
)); ));
}; };
} }
final token = store.defaultTokenFor(instanceUrl); final token = store.defaultTokenFor(instanceHost);
return () => action(token); return () => action(token);
}; };
} }

View File

@ -13,10 +13,10 @@ import 'add_instance.dart';
/// A modal where an account can be added for a given instance /// A modal where an account can be added for a given instance
class AddAccountPage extends HookWidget { class AddAccountPage extends HookWidget {
final String instanceUrl; final String instanceHost;
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey(); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
AddAccountPage({@required this.instanceUrl}) : assert(instanceUrl != null); AddAccountPage({@required this.instanceHost}) : assert(instanceHost != null);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -29,7 +29,7 @@ class AddAccountPage extends HookWidget {
final accountsStore = useAccountsStore(); final accountsStore = useAccountsStore();
final loading = useDelayedLoading(); final loading = useDelayedLoading();
final selectedInstance = useState(instanceUrl); final selectedInstance = useState(instanceHost);
final icon = useState<String>(null); final icon = useState<String>(null);
useEffect(() { useEffect(() {
LemmyApi(selectedInstance.value) LemmyApi(selectedInstance.value)

View File

@ -2,7 +2,6 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../widgets/markdown_text.dart'; import '../widgets/markdown_text.dart';
import '../widgets/sortable_infinite_list.dart'; import '../widgets/sortable_infinite_list.dart';
@ -44,12 +43,12 @@ class CommunitiesListPage extends StatelessWidget {
opacity: 0.5, opacity: 0.5,
child: MarkdownText( child: MarkdownText(
community.description, community.description,
instanceUrl: community.instanceUrl, instanceHost: community.instanceHost,
), ),
) )
: null, : null,
onTap: () => goToCommunity.byId( onTap: () => goToCommunity.byId(
context, community.instanceUrl, community.id), context, community.instanceHost, community.id),
leading: community.icon != null leading: community.icon != null
? CachedNetworkImage( ? CachedNetworkImage(
height: 50, height: 50,

View File

@ -32,8 +32,8 @@ class CommunitiesTab extends HookWidget {
final instancesSnap = useMemoFuture(() { final instancesSnap = useMemoFuture(() {
final futures = accountsStore.loggedInInstances final futures = accountsStore.loggedInInstances
.map( .map(
(instanceUrl) => (instanceHost) =>
LemmyApi(instanceUrl).v1.getSite().then((e) => e.site), LemmyApi(instanceHost).v1.getSite().then((e) => e.site),
) )
.toList(); .toList();
@ -42,12 +42,13 @@ class CommunitiesTab extends HookWidget {
final communitiesSnap = useMemoFuture(() { final communitiesSnap = useMemoFuture(() {
final futures = accountsStore.loggedInInstances final futures = accountsStore.loggedInInstances
.map( .map(
(instanceUrl) => LemmyApi(instanceUrl) (instanceHost) => LemmyApi(instanceHost)
.v1 .v1
.getUserDetails( .getUserDetails(
sort: SortType.active, sort: SortType.active,
savedOnly: false, savedOnly: false,
userId: accountsStore.defaultTokenFor(instanceUrl).payload.id, userId:
accountsStore.defaultTokenFor(instanceHost).payload.id,
) )
.then((e) => e.follows), .then((e) => e.follows),
) )
@ -208,7 +209,7 @@ class CommunitiesTab extends HookWidget {
], ],
), ),
trailing: _CommunitySubscribeToggle( trailing: _CommunitySubscribeToggle(
instanceUrl: comm.communityActorId.split('/')[2], instanceHost: comm.communityActorId.split('/')[2],
communityId: comm.communityId, communityId: comm.communityId,
), ),
), ),
@ -223,11 +224,11 @@ class CommunitiesTab extends HookWidget {
class _CommunitySubscribeToggle extends HookWidget { class _CommunitySubscribeToggle extends HookWidget {
final int communityId; final int communityId;
final String instanceUrl; final String instanceHost;
_CommunitySubscribeToggle( _CommunitySubscribeToggle(
{@required this.instanceUrl, @required this.communityId}) {@required this.instanceHost, @required this.communityId})
: assert(instanceUrl != null), : assert(instanceHost != null),
assert(communityId != null); assert(communityId != null);
@override @override
@ -241,10 +242,10 @@ class _CommunitySubscribeToggle extends HookWidget {
delayed.start(); delayed.start();
try { try {
await LemmyApi(instanceUrl).v1.followCommunity( await LemmyApi(instanceHost).v1.followCommunity(
communityId: communityId, communityId: communityId,
follow: !subbed.value, follow: !subbed.value,
auth: accountsStore.defaultTokenFor(instanceUrl).raw, auth: accountsStore.defaultTokenFor(instanceHost).raw,
); );
subbed.value = !subbed.value; subbed.value = !subbed.value;
} on Exception catch (err) { } on Exception catch (err) {

View File

@ -10,7 +10,6 @@ import '../hooks/delayed_loading.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../hooks/memo_future.dart'; import '../hooks/memo_future.dart';
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/intl.dart'; import '../util/intl.dart';
import '../util/more_icon.dart'; import '../util/more_icon.dart';
@ -25,26 +24,26 @@ import '../widgets/sortable_infinite_list.dart';
/// Displays posts, comments, and general info about the given community /// Displays posts, comments, and general info about the given community
class CommunityPage extends HookWidget { class CommunityPage extends HookWidget {
final CommunityView _community; final CommunityView _community;
final String instanceUrl; final String instanceHost;
final String communityName; final String communityName;
final int communityId; final int communityId;
CommunityPage.fromName({ CommunityPage.fromName({
@required this.communityName, @required this.communityName,
@required this.instanceUrl, @required this.instanceHost,
}) : assert(communityName != null), }) : assert(communityName != null),
assert(instanceUrl != null), assert(instanceHost != null),
communityId = null, communityId = null,
_community = null; _community = null;
CommunityPage.fromId({ CommunityPage.fromId({
@required this.communityId, @required this.communityId,
@required this.instanceUrl, @required this.instanceHost,
}) : assert(communityId != null), }) : assert(communityId != null),
assert(instanceUrl != null), assert(instanceHost != null),
communityName = null, communityName = null,
_community = null; _community = null;
CommunityPage.fromCommunityView(this._community) CommunityPage.fromCommunityView(this._community)
: instanceUrl = _community.instanceUrl, : instanceHost = _community.instanceHost,
communityId = _community.id, communityId = _community.id,
communityName = _community.name; communityName = _community.name;
@ -54,15 +53,15 @@ class CommunityPage extends HookWidget {
final accountsStore = useAccountsStore(); final accountsStore = useAccountsStore();
final fullCommunitySnap = useMemoFuture(() { final fullCommunitySnap = useMemoFuture(() {
final token = accountsStore.defaultTokenFor(instanceUrl); final token = accountsStore.defaultTokenFor(instanceHost);
if (communityId != null) { if (communityId != null) {
return LemmyApi(instanceUrl).v1.getCommunity( return LemmyApi(instanceHost).v1.getCommunity(
id: communityId, id: communityId,
auth: token?.raw, auth: token?.raw,
); );
} else { } else {
return LemmyApi(instanceUrl).v1.getCommunity( return LemmyApi(instanceHost).v1.getCommunity(
name: communityName, name: communityName,
auth: token?.raw, auth: token?.raw,
); );
@ -169,7 +168,7 @@ class CommunityPage extends HookWidget {
], ],
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
background: background:
_CommunityOverview(community, instanceUrl: instanceUrl), _CommunityOverview(community, instanceHost: instanceHost),
), ),
), ),
SliverPersistentHeader( SliverPersistentHeader(
@ -191,7 +190,7 @@ class CommunityPage extends HookWidget {
children: [ children: [
InfinitePostList( InfinitePostList(
fetcher: (page, batchSize, sort) => fetcher: (page, batchSize, sort) =>
LemmyApi(community.instanceUrl).v1.getPosts( LemmyApi(community.instanceHost).v1.getPosts(
type: PostListingType.community, type: PostListingType.community,
sort: sort, sort: sort,
communityId: community.id, communityId: community.id,
@ -201,10 +200,10 @@ class CommunityPage extends HookWidget {
), ),
InfiniteCommentList( InfiniteCommentList(
fetcher: (page, batchSize, sortType) => fetcher: (page, batchSize, sortType) =>
LemmyApi(community.instanceUrl).v1.getComments( LemmyApi(community.instanceHost).v1.getComments(
communityId: community.id, communityId: community.id,
auth: accountsStore auth: accountsStore
.defaultTokenFor(community.instanceUrl) .defaultTokenFor(community.instanceHost)
?.raw, ?.raw,
type: CommentListingType.community, type: CommentListingType.community,
sort: sortType, sort: sortType,
@ -225,12 +224,12 @@ class CommunityPage extends HookWidget {
class _CommunityOverview extends StatelessWidget { class _CommunityOverview extends StatelessWidget {
final CommunityView community; final CommunityView community;
final String instanceUrl; final String instanceHost;
_CommunityOverview( _CommunityOverview(
this.community, { this.community, {
@required this.instanceUrl, @required this.instanceHost,
}) : assert(instanceUrl != null), }) : assert(instanceHost != null),
assert(goToInstance != null); assert(goToInstance != null);
@override @override
@ -316,10 +315,10 @@ class _CommunityOverview extends StatelessWidget {
text: '@', text: '@',
style: TextStyle(fontWeight: FontWeight.w200)), style: TextStyle(fontWeight: FontWeight.w200)),
TextSpan( TextSpan(
text: instanceUrl, text: instanceHost,
style: TextStyle(fontWeight: FontWeight.w600), style: TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => goToInstance(context, instanceUrl)), ..onTap = () => goToInstance(context, instanceHost)),
], ],
), ),
), ),
@ -423,7 +422,7 @@ class _AboutTab extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 15), padding: const EdgeInsets.symmetric(horizontal: 15),
child: MarkdownText(community.description, child: MarkdownText(community.description,
instanceUrl: community.instanceUrl), instanceHost: community.instanceHost),
), ),
_Divider(), _Divider(),
], ],
@ -480,7 +479,7 @@ class _AboutTab extends StatelessWidget {
for (final mod in moderators) for (final mod in moderators)
ListTile( ListTile(
title: Text(mod.userPreferredUsername ?? '@${mod.userName}'), title: Text(mod.userPreferredUsername ?? '@${mod.userName}'),
onTap: () => goToUser.byId(context, mod.instanceUrl, mod.userId), onTap: () => goToUser.byId(context, mod.instanceHost, mod.userId),
), ),
] ]
], ],
@ -530,14 +529,14 @@ class _FollowButton extends HookWidget {
final isSubbed = useState(community.subscribed ?? false); final isSubbed = useState(community.subscribed ?? false);
final delayed = useDelayedLoading(const Duration(milliseconds: 500)); final delayed = useDelayedLoading(const Duration(milliseconds: 500));
final loggedInAction = useLoggedInAction(community.instanceUrl); final loggedInAction = useLoggedInAction(community.instanceHost);
final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor); final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor);
subscribe(Jwt token) async { subscribe(Jwt token) async {
delayed.start(); delayed.start();
try { try {
await LemmyApi(community.instanceUrl).v1.followCommunity( await LemmyApi(community.instanceHost).v1.followCommunity(
communityId: community.id, communityId: community.id,
follow: !isSubbed.value, follow: !isSubbed.value,
auth: token.raw); auth: token.raw);

View File

@ -9,7 +9,6 @@ import '../hooks/image_picker.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../hooks/memo_future.dart'; import '../hooks/memo_future.dart';
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/extensions/spaced.dart'; import '../util/extensions/spaced.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/pictrs.dart'; import '../util/pictrs.dart';
@ -46,7 +45,7 @@ class CreatePost extends HookWidget {
final bodyController = useTextEditingController(); final bodyController = useTextEditingController();
final accStore = useAccountsStore(); final accStore = useAccountsStore();
final selectedInstance = final selectedInstance =
useState(community?.instanceUrl ?? accStore.loggedInInstances.first); useState(community?.instanceHost ?? accStore.loggedInInstances.first);
final selectedCommunity = useState(community); final selectedCommunity = useState(community);
final showFancy = useState(false); final showFancy = useState(false);
final nsfw = useState(false); final nsfw = useState(false);
@ -203,7 +202,7 @@ class CreatePost extends HookWidget {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: MarkdownText( child: MarkdownText(
bodyController.text, bodyController.text,
instanceUrl: selectedInstance.value, instanceHost: selectedInstance.value,
), ),
), ),
], ],

View File

@ -7,7 +7,6 @@ import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../hooks/memo_future.dart'; import '../hooks/memo_future.dart';
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/more_icon.dart'; import '../util/more_icon.dart';
import '../widgets/comment_section.dart'; import '../widgets/comment_section.dart';
import '../widgets/post.dart'; import '../widgets/post.dart';
@ -17,24 +16,24 @@ import '../widgets/write_comment.dart';
/// Displays a post with its comment section /// Displays a post with its comment section
class FullPostPage extends HookWidget { class FullPostPage extends HookWidget {
final int id; final int id;
final String instanceUrl; final String instanceHost;
final PostView post; final PostView post;
FullPostPage({@required this.id, @required this.instanceUrl}) FullPostPage({@required this.id, @required this.instanceHost})
: assert(id != null), : assert(id != null),
assert(instanceUrl != null), assert(instanceHost != null),
post = null; post = null;
FullPostPage.fromPostView(this.post) FullPostPage.fromPostView(this.post)
: id = post.id, : id = post.id,
instanceUrl = post.instanceUrl; instanceHost = post.instanceHost;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final accStore = useAccountsStore(); final accStore = useAccountsStore();
final fullPostSnap = useMemoFuture(() => LemmyApi(instanceUrl) final fullPostSnap = useMemoFuture(() => LemmyApi(instanceHost)
.v1 .v1
.getPost(id: id, auth: accStore.defaultTokenFor(instanceUrl)?.raw)); .getPost(id: id, auth: accStore.defaultTokenFor(instanceHost)?.raw));
final loggedInAction = useLoggedInAction(instanceUrl); final loggedInAction = useLoggedInAction(instanceHost);
final newComments = useState(const <CommentView>[]); final newComments = useState(const <CommentView>[]);
// FALLBACK VIEW // FALLBACK VIEW

View File

@ -118,10 +118,10 @@ class HomeTab extends HookWidget {
? () => showCupertinoModalPopup( ? () => showCupertinoModalPopup(
context: context, context: context,
builder: (_) => builder: (_) =>
AddAccountPage(instanceUrl: instance)) AddAccountPage(instanceHost: instance))
: () => pop(_SelectedList( : () => pop(_SelectedList(
listingType: PostListingType.subscribed, listingType: PostListingType.subscribed,
instanceUrl: instance, instanceHost: instance,
)), )),
leading: SizedBox(width: 20), leading: SizedBox(width: 20),
), ),
@ -129,7 +129,7 @@ class HomeTab extends HookWidget {
title: Text('All'), title: Text('All'),
onTap: () => pop(_SelectedList( onTap: () => pop(_SelectedList(
listingType: PostListingType.all, listingType: PostListingType.all,
instanceUrl: instance, instanceHost: instance,
)), )),
leading: SizedBox(width: 20), leading: SizedBox(width: 20),
), ),
@ -149,9 +149,9 @@ class HomeTab extends HookWidget {
final first = selectedList.value.listingType == PostListingType.subscribed final first = selectedList.value.listingType == PostListingType.subscribed
? 'Subscribed' ? 'Subscribed'
: 'All'; : 'All';
final last = selectedList.value.instanceUrl == null final last = selectedList.value.instanceHost == null
? '' ? ''
: '@${selectedList.value.instanceUrl}'; : '@${selectedList.value.instanceHost}';
return '$first$last'; return '$first$last';
}(); }();
@ -256,12 +256,12 @@ class InfiniteHomeList extends HookWidget {
}(); }();
final futures = final futures =
instances.map((instanceUrl) => LemmyApi(instanceUrl).v1.getPosts( instances.map((instanceHost) => LemmyApi(instanceHost).v1.getPosts(
type: listingType, type: listingType,
sort: sort, sort: sort,
page: page, page: page,
limit: limit, limit: limit,
auth: accStore.defaultTokenFor(instanceUrl)?.raw, auth: accStore.defaultTokenFor(instanceHost)?.raw,
)); ));
final posts = await Future.wait(futures); final posts = await Future.wait(futures);
final newPosts = <PostView>[]; final newPosts = <PostView>[];
@ -277,13 +277,13 @@ class InfiniteHomeList extends HookWidget {
} }
Future<List<PostView>> Function(int, int) fetcherFromInstance( Future<List<PostView>> Function(int, int) fetcherFromInstance(
String instanceUrl, PostListingType listingType, SortType sort) => String instanceHost, PostListingType listingType, SortType sort) =>
(page, batchSize) => LemmyApi(instanceUrl).v1.getPosts( (page, batchSize) => LemmyApi(instanceHost).v1.getPosts(
type: listingType, type: listingType,
sort: sort, sort: sort,
page: page, page: page,
limit: batchSize, limit: batchSize,
auth: accStore.defaultTokenFor(instanceUrl)?.raw, auth: accStore.defaultTokenFor(instanceHost)?.raw,
); );
return InfiniteScroll<PostView>( return InfiniteScroll<PostView>(
@ -303,11 +303,11 @@ class InfiniteHomeList extends HookWidget {
], ],
), ),
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
fetchMore: selectedList.instanceUrl == null fetchMore: selectedList.instanceHost == null
? (page, limit) => ? (page, limit) =>
generalFetcher(page, limit, sort.value, selectedList.listingType) generalFetcher(page, limit, sort.value, selectedList.listingType)
: fetcherFromInstance( : fetcherFromInstance(
selectedList.instanceUrl, selectedList.instanceHost,
selectedList.listingType, selectedList.listingType,
sort.value, sort.value,
), ),
@ -318,13 +318,13 @@ class InfiniteHomeList extends HookWidget {
} }
class _SelectedList { class _SelectedList {
final String instanceUrl; final String instanceHost;
final PostListingType listingType; final PostListingType listingType;
_SelectedList({ _SelectedList({
@required this.listingType, @required this.listingType,
this.instanceUrl, this.instanceHost,
}); });
String toString() => String toString() =>
'SelectedList({instanceUrl: $instanceUrl, listingType: $listingType})'; 'SelectedList({instanceHost: $instanceHost, listingType: $listingType})';
} }

View File

@ -6,7 +6,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/more_icon.dart'; import '../util/more_icon.dart';
import '../util/text_color.dart'; import '../util/text_color.dart';
@ -20,18 +19,18 @@ import 'users_list.dart';
/// Displays posts, comments, and general info about the given instance /// Displays posts, comments, and general info about the given instance
class InstancePage extends HookWidget { class InstancePage extends HookWidget {
final String instanceUrl; final String instanceHost;
final Future<FullSiteView> siteFuture; final Future<FullSiteView> siteFuture;
final Future<List<CommunityView>> communitiesFuture; final Future<List<CommunityView>> communitiesFuture;
void _share() => void _share() =>
Share.text('Share instance', 'https://$instanceUrl', 'text/plain'); Share.text('Share instance', 'https://$instanceHost', 'text/plain');
InstancePage({@required this.instanceUrl}) InstancePage({@required this.instanceHost})
: assert(instanceUrl != null), : assert(instanceHost != null),
siteFuture = LemmyApi(instanceUrl).v1.getSite(), siteFuture = LemmyApi(instanceHost).v1.getSite(),
communitiesFuture = communitiesFuture =
LemmyApi(instanceUrl).v1.listCommunities(sort: SortType.hot); LemmyApi(instanceHost).v1.listCommunities(sort: SortType.hot);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -70,7 +69,7 @@ class InstancePage extends HookWidget {
void _openMoreMenu(BuildContext c) { void _openMoreMenu(BuildContext c) {
showInfoTablePopup(context, { showInfoTablePopup(context, {
'url': instanceUrl, 'url': instanceHost,
'creator': '@${site.site.creatorName}', 'creator': '@${site.site.creatorName}',
'version': site.version, 'version': site.version,
'enableDownvotes': site.site.enableDownvotes, 'enableDownvotes': site.site.enableDownvotes,
@ -132,7 +131,7 @@ class InstancePage extends HookWidget {
), ),
Text(site.site.name, Text(site.site.name,
style: theme.textTheme.headline6), style: theme.textTheme.headline6),
Text(instanceUrl, style: theme.textTheme.caption) Text(instanceHost, style: theme.textTheme.caption)
], ],
), ),
), ),
@ -159,26 +158,26 @@ class InstancePage extends HookWidget {
children: [ children: [
InfinitePostList( InfinitePostList(
fetcher: (page, batchSize, sort) => fetcher: (page, batchSize, sort) =>
LemmyApi(instanceUrl).v1.getPosts( LemmyApi(instanceHost).v1.getPosts(
// TODO: switch between all and subscribed // TODO: switch between all and subscribed
type: PostListingType.all, type: PostListingType.all,
sort: sort, sort: sort,
limit: batchSize, limit: batchSize,
page: page, page: page,
auth: accStore.defaultTokenFor(instanceUrl)?.raw, auth: accStore.defaultTokenFor(instanceHost)?.raw,
)), )),
InfiniteCommentList( InfiniteCommentList(
fetcher: (page, batchSize, sort) => fetcher: (page, batchSize, sort) =>
LemmyApi(instanceUrl).v1.getComments( LemmyApi(instanceHost).v1.getComments(
type: CommentListingType.all, type: CommentListingType.all,
sort: sort, sort: sort,
limit: batchSize, limit: batchSize,
page: page, page: page,
auth: accStore.defaultTokenFor(instanceUrl)?.raw, auth: accStore.defaultTokenFor(instanceHost)?.raw,
)), )),
_AboutTab(site, _AboutTab(site,
communitiesFuture: communitiesFuture, communitiesFuture: communitiesFuture,
instanceUrl: instanceUrl), instanceHost: instanceHost),
], ],
), ),
), ),
@ -211,12 +210,12 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
class _AboutTab extends HookWidget { class _AboutTab extends HookWidget {
final FullSiteView site; final FullSiteView site;
final Future<List<CommunityView>> communitiesFuture; final Future<List<CommunityView>> communitiesFuture;
final String instanceUrl; final String instanceHost;
const _AboutTab(this.site, const _AboutTab(this.site,
{@required this.communitiesFuture, @required this.instanceUrl}) {@required this.communitiesFuture, @required this.instanceHost})
: assert(communitiesFuture != null), : assert(communitiesFuture != null),
assert(instanceUrl != null); assert(instanceHost != null);
void goToUser(int id) { void goToUser(int id) {
print('GO TO USER $id'); print('GO TO USER $id');
@ -245,11 +244,11 @@ class _AboutTab extends HookWidget {
context, context,
(_) => CommunitiesListPage( (_) => CommunitiesListPage(
fetcher: (page, batchSize, sortType) => fetcher: (page, batchSize, sortType) =>
LemmyApi(instanceUrl).v1.listCommunities( LemmyApi(instanceHost).v1.listCommunities(
sort: sortType, sort: sortType,
limit: batchSize, limit: batchSize,
page: page, page: page,
auth: accStore.defaultTokenFor(instanceUrl)?.raw, auth: accStore.defaultTokenFor(instanceHost)?.raw,
), ),
title: 'Communities of ${site.site.name}', title: 'Communities of ${site.site.name}',
), ),
@ -265,7 +264,7 @@ class _AboutTab extends HookWidget {
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15), padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
child: MarkdownText( child: MarkdownText(
site.site.description, site.site.description,
instanceUrl: instanceUrl, instanceHost: instanceHost,
), ),
), ),
_Divider(), _Divider(),
@ -296,7 +295,7 @@ class _AboutTab extends HookWidget {
if (commSnap.hasData) if (commSnap.hasData)
...commSnap.data.take(6).map((e) => ListTile( ...commSnap.data.take(6).map((e) => ListTile(
onTap: () => onTap: () =>
goToCommunity.byId(context, e.instanceUrl, e.id), goToCommunity.byId(context, e.instanceHost, e.id),
title: Text(e.name), title: Text(e.name),
leading: e.icon != null leading: e.icon != null
? CachedNetworkImage( ? CachedNetworkImage(
@ -345,7 +344,7 @@ class _AboutTab extends HookWidget {
? '@${e.name}' ? '@${e.name}'
: e.preferredUsername), : e.preferredUsername),
subtitle: e.bio != null subtitle: e.bio != null
? MarkdownText(e.bio, instanceUrl: instanceUrl) ? MarkdownText(e.bio, instanceHost: instanceHost)
: null, : null,
onTap: () => goToUser(e.id), onTap: () => goToUser(e.id),
leading: e.avatar != null leading: e.avatar != null

View File

@ -85,9 +85,9 @@ class UserProfileTab extends HookWidget {
builder: (ctx) { builder: (ctx) {
final userTags = <String>[]; final userTags = <String>[];
accountsStore.tokens.forEach((instanceUrl, value) { accountsStore.tokens.forEach((instanceHost, value) {
value.forEach((username, _) { value.forEach((username, _) {
userTags.add('$username@$instanceUrl'); userTags.add('$username@$instanceHost');
}); });
}); });
@ -100,7 +100,7 @@ class UserProfileTab extends HookWidget {
value: tag, value: tag,
title: Text(tag), title: Text(tag),
groupValue: '${accountsStore.defaultUsername}' groupValue: '${accountsStore.defaultUsername}'
'@${accountsStore.defaultInstanceUrl}', '@${accountsStore.defaultInstanceHost}',
onChanged: (selected) { onChanged: (selected) {
final userTag = selected.split('@'); final userTag = selected.split('@');
accountsStore.setDefaultAccount( accountsStore.setDefaultAccount(
@ -119,7 +119,7 @@ class UserProfileTab extends HookWidget {
), ),
body: UserProfile( body: UserProfile(
userId: accountsStore.defaultToken.payload.id, userId: accountsStore.defaultToken.payload.id,
instanceUrl: accountsStore.defaultInstanceUrl, instanceHost: accountsStore.defaultInstanceHost,
), ),
); );
} }

View File

@ -99,12 +99,12 @@ class AccountsConfigPage extends HookWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final accountsStore = useAccountsStore(); final accountsStore = useAccountsStore();
removeInstanceDialog(String instanceUrl) async { removeInstanceDialog(String instanceHost) async {
if (await showDialog<bool>( if (await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text('Remove instance?'), title: Text('Remove instance?'),
content: Text('Are you sure you want to remove $instanceUrl?'), content: Text('Are you sure you want to remove $instanceHost?'),
actions: [ actions: [
FlatButton( FlatButton(
child: Text('no'), child: Text('no'),
@ -118,17 +118,17 @@ class AccountsConfigPage extends HookWidget {
), ),
) ?? ) ??
false) { false) {
accountsStore.removeInstance(instanceUrl); accountsStore.removeInstance(instanceHost);
} }
} }
Future<void> removeUserDialog(String instanceUrl, String username) async { Future<void> removeUserDialog(String instanceHost, String username) async {
if (await showDialog<bool>( if (await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text('Remove user?'), title: Text('Remove user?'),
content: Text( content: Text(
'Are you sure you want to remove $username@$instanceUrl?'), 'Are you sure you want to remove $username@$instanceHost?'),
actions: [ actions: [
FlatButton( FlatButton(
child: Text('no'), child: Text('no'),
@ -142,7 +142,7 @@ class AccountsConfigPage extends HookWidget {
), ),
) ?? ) ??
false) { false) {
accountsStore.removeAccount(instanceUrl, username); accountsStore.removeAccount(instanceHost, username);
} }
} }
@ -171,7 +171,7 @@ class AccountsConfigPage extends HookWidget {
onTap: () => showCupertinoModalPopup( onTap: () => showCupertinoModalPopup(
context: context, context: context,
builder: (_) => builder: (_) =>
AddAccountPage(instanceUrl: accountsStore.instances.last)), AddAccountPage(instanceHost: accountsStore.instances.last)),
), ),
SpeedDialChild( SpeedDialChild(
child: Icon(Icons.dns), child: Icon(Icons.dns),
@ -263,7 +263,7 @@ class AccountsConfigPage extends HookWidget {
onTap: () { onTap: () {
showCupertinoModalPopup( showCupertinoModalPopup(
context: context, context: context,
builder: (_) => AddAccountPage(instanceUrl: entry.key)); builder: (_) => AddAccountPage(instanceHost: entry.key));
}, },
), ),
] ]

View File

@ -8,20 +8,20 @@ import '../widgets/user_profile.dart';
/// Page showing posts, comments, and general info about a user. /// Page showing posts, comments, and general info about a user.
class UserPage extends HookWidget { class UserPage extends HookWidget {
final int userId; final int userId;
final String instanceUrl; final String instanceHost;
final Future<UserDetails> _userDetails; final Future<UserDetails> _userDetails;
UserPage({@required this.userId, @required this.instanceUrl}) UserPage({@required this.userId, @required this.instanceHost})
: assert(userId != null), : assert(userId != null),
assert(instanceUrl != null), assert(instanceHost != null),
_userDetails = LemmyApi(instanceUrl).v1.getUserDetails( _userDetails = LemmyApi(instanceHost).v1.getUserDetails(
userId: userId, savedOnly: true, sort: SortType.active); userId: userId, savedOnly: true, sort: SortType.active);
UserPage.fromName({@required this.instanceUrl, @required String username}) UserPage.fromName({@required this.instanceHost, @required String username})
: assert(instanceUrl != null), : assert(instanceHost != null),
assert(username != null), assert(username != null),
userId = null, userId = null,
_userDetails = LemmyApi(instanceUrl).v1.getUserDetails( _userDetails = LemmyApi(instanceHost).v1.getUserDetails(
username: username, savedOnly: true, sort: SortType.active); username: username, savedOnly: true, sort: SortType.active);
@override @override

View File

@ -2,7 +2,6 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../util/extensions/api.dart';
import '../widgets/markdown_text.dart'; import '../widgets/markdown_text.dart';
/// Infinite list of Users fetched by the given fetcher /// Infinite list of Users fetched by the given fetcher
@ -42,7 +41,7 @@ class UsersListPage extends StatelessWidget {
opacity: 0.5, opacity: 0.5,
child: MarkdownText( child: MarkdownText(
users[i].bio, users[i].bio,
instanceUrl: users[i].instanceUrl, instanceHost: users[i].instanceHost,
), ),
) )
: null, : null,

View File

@ -12,16 +12,16 @@ class AccountsStore extends ChangeNotifier {
/// Map containing JWT tokens of specific users. /// Map containing JWT tokens of specific users.
/// If a token is in this map, the user is considered logged in /// If a token is in this map, the user is considered logged in
/// for that account. /// for that account.
/// `tokens['instanceUrl']['username']` /// `tokens['instanceHost']['username']`
HashMap<String, HashMap<String, Jwt>> get tokens => _tokens; HashMap<String, HashMap<String, Jwt>> get tokens => _tokens;
HashMap<String, HashMap<String, Jwt>> _tokens; HashMap<String, HashMap<String, Jwt>> _tokens;
/// default account for a given instance /// default account for a given instance
/// map where keys are instanceUrls and values are usernames /// map where keys are instanceHosts and values are usernames
HashMap<String, String> _defaultAccounts; HashMap<String, String> _defaultAccounts;
/// default account for the app /// default account for the app
/// It is in a form of `username@instanceUrl` /// It is in a form of `username@instanceHost`
String _defaultAccount; String _defaultAccount;
Future<void> load() async { Future<void> load() async {
@ -87,12 +87,12 @@ class AccountsStore extends ChangeNotifier {
} }
// set local defaults // set local defaults
for (final instanceUrl in instances) { for (final instanceHost in instances) {
// if this instance is not in defaults // if this instance is not in defaults
if (!_defaultAccounts.containsKey(instanceUrl)) { if (!_defaultAccounts.containsKey(instanceHost)) {
// select first account in this instance, if any // select first account in this instance, if any
if (!isAnonymousFor(instanceUrl)) { if (!isAnonymousFor(instanceHost)) {
setDefaultAccountFor(instanceUrl, tokens[instanceUrl].keys.first); setDefaultAccountFor(instanceHost, tokens[instanceHost].keys.first);
} }
} }
} }
@ -100,10 +100,10 @@ class AccountsStore extends ChangeNotifier {
// set global default // set global default
if (_defaultAccount == null) { if (_defaultAccount == null) {
// select first account of first instance // select first account of first instance
for (final instanceUrl in instances) { for (final instanceHost in instances) {
// select first account in this instance, if any // select first account in this instance, if any
if (!isAnonymousFor(instanceUrl)) { if (!isAnonymousFor(instanceHost)) {
setDefaultAccount(instanceUrl, tokens[instanceUrl].keys.first); setDefaultAccount(instanceHost, tokens[instanceHost].keys.first);
} }
} }
} }
@ -117,7 +117,7 @@ class AccountsStore extends ChangeNotifier {
return _defaultAccount.split('@')[0]; return _defaultAccount.split('@')[0];
} }
String get defaultInstanceUrl { String get defaultInstanceHost {
if (_defaultAccount == null) { if (_defaultAccount == null) {
return null; return null;
} }
@ -125,12 +125,12 @@ class AccountsStore extends ChangeNotifier {
return _defaultAccount.split('@')[1]; return _defaultAccount.split('@')[1];
} }
String defaultUsernameFor(String instanceUrl) { String defaultUsernameFor(String instanceHost) {
if (isAnonymousFor(instanceUrl)) { if (isAnonymousFor(instanceHost)) {
return null; return null;
} }
return _defaultAccounts[instanceUrl]; return _defaultAccounts[instanceHost];
} }
Jwt get defaultToken { Jwt get defaultToken {
@ -142,25 +142,25 @@ class AccountsStore extends ChangeNotifier {
return tokens[userTag[1]][userTag[0]]; return tokens[userTag[1]][userTag[0]];
} }
Jwt defaultTokenFor(String instanceUrl) { Jwt defaultTokenFor(String instanceHost) {
if (isAnonymousFor(instanceUrl)) { if (isAnonymousFor(instanceHost)) {
return null; return null;
} }
return tokens[instanceUrl][_defaultAccounts[instanceUrl]]; return tokens[instanceHost][_defaultAccounts[instanceHost]];
} }
/// sets globally default account /// sets globally default account
void setDefaultAccount(String instanceUrl, String username) { void setDefaultAccount(String instanceHost, String username) {
_defaultAccount = '$username@$instanceUrl'; _defaultAccount = '$username@$instanceHost';
notifyListeners(); notifyListeners();
save(); save();
} }
/// sets default account for given instance /// sets default account for given instance
void setDefaultAccountFor(String instanceUrl, String username) { void setDefaultAccountFor(String instanceHost, String username) {
_defaultAccounts[instanceUrl] = username; _defaultAccounts[instanceHost] = username;
notifyListeners(); notifyListeners();
save(); save();
@ -168,12 +168,12 @@ class AccountsStore extends ChangeNotifier {
/// An instance is considered anonymous if it was not /// An instance is considered anonymous if it was not
/// added or there are no accounts assigned to it. /// added or there are no accounts assigned to it.
bool isAnonymousFor(String instanceUrl) { bool isAnonymousFor(String instanceHost) {
if (!instances.contains(instanceUrl)) { if (!instances.contains(instanceHost)) {
return true; return true;
} }
return tokens[instanceUrl].isEmpty; return tokens[instanceHost].isEmpty;
} }
/// `true` if no added instance has an account assigned to it /// `true` if no added instance has an account assigned to it
@ -190,15 +190,15 @@ class AccountsStore extends ChangeNotifier {
/// if it's the first account for an instance the account is /// if it's the first account for an instance the account is
/// set as default for that instance /// set as default for that instance
Future<void> addAccount( Future<void> addAccount(
String instanceUrl, String instanceHost,
String usernameOrEmail, String usernameOrEmail,
String password, String password,
) async { ) async {
if (!instances.contains(instanceUrl)) { if (!instances.contains(instanceHost)) {
throw Exception('No such instance was added'); throw Exception('No such instance was added');
} }
final lemmy = LemmyApi(instanceUrl).v1; final lemmy = LemmyApi(instanceHost).v1;
final token = await lemmy.login( final token = await lemmy.login(
usernameOrEmail: usernameOrEmail, usernameOrEmail: usernameOrEmail,
@ -207,7 +207,7 @@ class AccountsStore extends ChangeNotifier {
final userData = final userData =
await lemmy.getSite(auth: token.raw).then((value) => value.myUser); await lemmy.getSite(auth: token.raw).then((value) => value.myUser);
tokens[instanceUrl][userData.name] = token; tokens[instanceHost][userData.name] = token;
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();
@ -218,23 +218,23 @@ class AccountsStore extends ChangeNotifier {
/// Additionally makes a test `GET /site` request to check if the instance exists. /// Additionally makes a test `GET /site` request to check if the instance exists.
/// Check is skipped when [assumeValid] is `true` /// Check is skipped when [assumeValid] is `true`
Future<void> addInstance( Future<void> addInstance(
String instanceUrl, { String instanceHost, {
bool assumeValid = false, bool assumeValid = false,
}) async { }) async {
if (instances.contains(instanceUrl)) { if (instances.contains(instanceHost)) {
throw Exception('This instance has already been added'); throw Exception('This instance has already been added');
} }
if (!assumeValid) { if (!assumeValid) {
try { try {
await LemmyApi(instanceUrl).v1.getSite(); await LemmyApi(instanceHost).v1.getSite();
// ignore: avoid_catches_without_on_clauses // ignore: avoid_catches_without_on_clauses
} catch (_) { } catch (_) {
throw Exception('This instance seems to not exist'); throw Exception('This instance seems to not exist');
} }
} }
tokens[instanceUrl] = HashMap(); tokens[instanceHost] = HashMap();
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();
@ -242,16 +242,16 @@ class AccountsStore extends ChangeNotifier {
} }
/// This also removes all accounts assigned to this instance /// This also removes all accounts assigned to this instance
void removeInstance(String instanceUrl) { void removeInstance(String instanceHost) {
tokens.remove(instanceUrl); tokens.remove(instanceHost);
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();
save(); save();
} }
void removeAccount(String instanceUrl, String username) { void removeAccount(String instanceHost, String username) {
tokens[instanceUrl].remove(username); tokens[instanceHost].remove(username);
_assignDefaultAccounts(); _assignDefaultAccounts();
notifyListeners(); notifyListeners();

View File

@ -15,7 +15,7 @@ import 'util/goto.dart';
Future<void> linkLauncher({ Future<void> linkLauncher({
@required BuildContext context, @required BuildContext context,
@required String url, @required String url,
@required String instanceUrl, @required String instanceHost,
}) async { }) async {
push(Widget Function() builder) { push(Widget Function() builder) {
goTo(context, (c) => builder()); goTo(context, (c) => builder());
@ -28,14 +28,14 @@ Future<void> linkLauncher({
// CHECK IF LINK TO USER // CHECK IF LINK TO USER
if (url.startsWith('/u/')) { if (url.startsWith('/u/')) {
return push( return push(() =>
() => UserPage.fromName(instanceUrl: instanceUrl, username: chonks[2])); UserPage.fromName(instanceHost: instanceHost, username: chonks[2]));
} }
// CHECK IF LINK TO COMMUNITY // CHECK IF LINK TO COMMUNITY
if (url.startsWith('/c/')) { if (url.startsWith('/c/')) {
return push(() => CommunityPage.fromName( return push(() => CommunityPage.fromName(
communityName: chonks[2], instanceUrl: instanceUrl)); communityName: chonks[2], instanceHost: instanceHost));
} }
// CHECK IF REDIRECTS TO A PAGE ON ONE OF ADDED INSTANCES // CHECK IF REDIRECTS TO A PAGE ON ONE OF ADDED INSTANCES
@ -48,7 +48,7 @@ Future<void> linkLauncher({
if (matchedInstance != null && instances.any((e) => e == match.group(1))) { if (matchedInstance != null && instances.any((e) => e == match.group(1))) {
if (rest.isEmpty || rest == '/') { if (rest.isEmpty || rest == '/') {
return push(() => InstancePage(instanceUrl: matchedInstance)); return push(() => InstancePage(instanceHost: matchedInstance));
} }
final split = rest.split('/'); final split = rest.split('/');
switch (split[1]) { switch (split[1]) {

View File

@ -1,35 +0,0 @@
import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../cleanup_url.dart';
// Extensions to lemmy api objects which give a [.instanceUrl] getter
// allowing for a convenient way of knowing from which instance did this
// object come from
// TODO: change it to something more robust? regex?
extension GetInstanceCommunityView on CommunityView {
String get instanceUrl => _extract(actorId);
}
extension GetInstanceUserView on UserView {
String get instanceUrl => _extract(actorId);
}
extension GetInstanceCommunityModeratorView on CommunityModeratorView {
String get instanceUrl => _extract(userActorId);
}
extension GetInstancePostView on PostView {
String get instanceUrl => _extract(apId);
}
extension GetInstanceUser on User {
String get instanceUrl => _extract(actorId);
}
extension GetInstanceCommentView on CommentView {
String get instanceUrl => _extract(apId);
}
String _extract(String s) => cleanUpUrl(s.split('/')[2]);

View File

@ -25,41 +25,42 @@ Future<dynamic> goToReplace(
builder: builder, builder: builder,
)); ));
void goToInstance(BuildContext context, String instanceUrl) => void goToInstance(BuildContext context, String instanceHost) =>
goTo(context, (context) => InstancePage(instanceUrl: instanceUrl)); goTo(context, (context) => InstancePage(instanceHost: instanceHost));
// ignore: camel_case_types // ignore: camel_case_types
abstract class goToCommunity { abstract class goToCommunity {
/// Navigates to `CommunityPage` /// Navigates to `CommunityPage`
static void byId(BuildContext context, String instanceUrl, int communityId) => static void byId(
BuildContext context, String instanceHost, int communityId) =>
goTo( goTo(
context, context,
(context) => CommunityPage.fromId( (context) => CommunityPage.fromId(
instanceUrl: instanceUrl, communityId: communityId), instanceHost: instanceHost, communityId: communityId),
); );
static void byName( static void byName(
BuildContext context, String instanceUrl, String communityName) => BuildContext context, String instanceHost, String communityName) =>
goTo( goTo(
context, context,
(context) => CommunityPage.fromName( (context) => CommunityPage.fromName(
instanceUrl: instanceUrl, communityName: communityName), instanceHost: instanceHost, communityName: communityName),
); );
} }
// ignore: camel_case_types // ignore: camel_case_types
abstract class goToUser { abstract class goToUser {
static void byId(BuildContext context, String instanceUrl, int userId) => static void byId(BuildContext context, String instanceHost, int userId) =>
goTo(context, goTo(context,
(context) => UserPage(instanceUrl: instanceUrl, userId: userId)); (context) => UserPage(instanceHost: instanceHost, userId: userId));
static void byName( static void byName(
BuildContext context, String instanceUrl, String userName) => BuildContext context, String instanceHost, String userName) =>
throw UnimplementedError('need to create UserProfile constructor first'); throw UnimplementedError('need to create UserProfile constructor first');
} }
void goToPost(BuildContext context, String instanceUrl, int postId) => goTo( void goToPost(BuildContext context, String instanceHost, int postId) => goTo(
context, (context) => FullPostPage(instanceUrl: instanceUrl, id: postId)); context, (context) => FullPostPage(instanceHost: instanceHost, id: postId));
void goToMedia(BuildContext context, String url) => Navigator.push( void goToMedia(BuildContext context, String url) => Navigator.push(
context, context,

View File

@ -1,2 +1,2 @@
String pathToPictrs(String instanceUrl, String imgId) => String pathToPictrs(String instanceHost, String imgId) =>
'https://$instanceUrl/pictrs/image/$imgId'; 'https://$instanceHost/pictrs/image/$imgId';

View File

@ -11,7 +11,6 @@ import 'package:url_launcher/url_launcher.dart' as ul;
import '../comment_tree.dart'; import '../comment_tree.dart';
import '../hooks/delayed_loading.dart'; import '../hooks/delayed_loading.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/intl.dart'; import '../util/intl.dart';
import '../util/text_color.dart'; import '../util/text_color.dart';
@ -75,7 +74,7 @@ class Comment extends HookWidget {
final isDeleted = useState(commentTree.comment.deleted); final isDeleted = useState(commentTree.comment.deleted);
final delayedVoting = useDelayedLoading(); final delayedVoting = useDelayedLoading();
final delayedDeletion = useDelayedLoading(); final delayedDeletion = useDelayedLoading();
final loggedInAction = useLoggedInAction(commentTree.comment.instanceUrl); final loggedInAction = useLoggedInAction(commentTree.comment.instanceHost);
final newReplies = useState(const <CommentTree>[]); final newReplies = useState(const <CommentTree>[]);
final comment = commentTree.comment; final comment = commentTree.comment;
@ -237,7 +236,7 @@ class Comment extends HookWidget {
: Text(commentTree.comment.content) : Text(commentTree.comment.content)
: MarkdownText( : MarkdownText(
commentTree.comment.content, commentTree.comment.content,
instanceUrl: commentTree.comment.instanceUrl, instanceHost: commentTree.comment.instanceHost,
selectable: selectable.value, selectable: selectable.value,
)); ));
} }
@ -305,7 +304,7 @@ class Comment extends HookWidget {
padding: const EdgeInsets.only(right: 5), padding: const EdgeInsets.only(right: 5),
child: InkWell( child: InkWell(
onTap: () => goToUser.byId( onTap: () => goToUser.byId(
context, comment.instanceUrl, comment.creatorId), context, comment.instanceHost, comment.creatorId),
child: CachedNetworkImage( child: CachedNetworkImage(
imageUrl: comment.creatorAvatar, imageUrl: comment.creatorAvatar,
height: 20, height: 20,
@ -329,7 +328,7 @@ class Comment extends HookWidget {
color: Theme.of(context).accentColor, color: Theme.of(context).accentColor,
)), )),
onTap: () => goToUser.byId( onTap: () => goToUser.byId(
context, comment.instanceUrl, comment.creatorId), context, comment.instanceHost, comment.creatorId),
), ),
if (isOP) _CommentTag('OP', Theme.of(context).accentColor), if (isOP) _CommentTag('OP', Theme.of(context).accentColor),
if (comment.banned) _CommentTag('BANNED', Colors.red), if (comment.banned) _CommentTag('BANNED', Colors.red),
@ -394,12 +393,12 @@ class _SaveComment extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loggedInAction = useLoggedInAction(comment.instanceUrl); final loggedInAction = useLoggedInAction(comment.instanceHost);
final isSaved = useState(comment.saved ?? false); final isSaved = useState(comment.saved ?? false);
final delayed = useDelayedLoading(const Duration(milliseconds: 500)); final delayed = useDelayedLoading(const Duration(milliseconds: 500));
handleSave(Jwt token) async { handleSave(Jwt token) async {
final api = LemmyApi(comment.instanceUrl).v1; final api = LemmyApi(comment.instanceHost).v1;
delayed.start(); delayed.start();
try { try {

View File

@ -8,12 +8,13 @@ import 'fullscreenable_image.dart';
/// A Markdown renderer with link/image handling /// A Markdown renderer with link/image handling
class MarkdownText extends StatelessWidget { class MarkdownText extends StatelessWidget {
final String instanceUrl; final String instanceHost;
final String text; final String text;
final bool selectable; final bool selectable;
MarkdownText(this.text, {@required this.instanceUrl, this.selectable = false}) MarkdownText(this.text,
: assert(instanceUrl != null); {@required this.instanceHost, this.selectable = false})
: assert(instanceHost != null);
@override @override
Widget build(BuildContext context) => MarkdownBody( Widget build(BuildContext context) => MarkdownBody(
@ -21,7 +22,7 @@ class MarkdownText extends StatelessWidget {
data: text, data: text,
extensionSet: md.ExtensionSet.gitHubWeb, extensionSet: md.ExtensionSet.gitHubWeb,
onTapLink: (href) { onTapLink: (href) {
linkLauncher(context: context, url: href, instanceUrl: instanceUrl) linkLauncher(context: context, url: href, instanceHost: instanceHost)
.catchError((e) => Scaffold.of(context).showSnackBar(SnackBar( .catchError((e) => Scaffold.of(context).showSnackBar(SnackBar(
content: Row( content: Row(
children: [ children: [

View File

@ -13,7 +13,6 @@ import '../hooks/delayed_loading.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../pages/full_post.dart'; import '../pages/full_post.dart';
import '../url_launcher.dart'; import '../url_launcher.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/more_icon.dart'; import '../util/more_icon.dart';
import 'bottom_modal.dart'; import 'bottom_modal.dart';
@ -49,10 +48,10 @@ MediaType whatType(String url) {
/// A post overview card /// A post overview card
class Post extends HookWidget { class Post extends HookWidget {
final PostView post; final PostView post;
final String instanceUrl; final String instanceHost;
final bool fullPost; final bool fullPost;
Post(this.post, {this.fullPost = false}) : instanceUrl = post.instanceUrl; Post(this.post, {this.fullPost = false}) : instanceHost = post.instanceHost;
// == ACTIONS == // == ACTIONS ==
@ -103,8 +102,8 @@ class Post extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
void _openLink() => void _openLink() => linkLauncher(
linkLauncher(context: context, url: post.url, instanceUrl: instanceUrl); context: context, url: post.url, instanceHost: instanceHost);
final urlDomain = () { final urlDomain = () {
if (whatType(post.url) == MediaType.none) return null; if (whatType(post.url) == MediaType.none) return null;
@ -127,7 +126,7 @@ class Post extends HookWidget {
padding: const EdgeInsets.only(right: 10), padding: const EdgeInsets.only(right: 10),
child: InkWell( child: InkWell(
onTap: () => goToCommunity.byId( onTap: () => goToCommunity.byId(
context, instanceUrl, post.communityId), context, instanceHost, post.communityId),
child: SizedBox( child: SizedBox(
height: 40, height: 40,
width: 40, width: 40,
@ -168,16 +167,16 @@ class Post extends HookWidget {
style: TextStyle(fontWeight: FontWeight.w600), style: TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => goToCommunity.byId( ..onTap = () => goToCommunity.byId(
context, instanceUrl, post.communityId)), context, instanceHost, post.communityId)),
TextSpan( TextSpan(
text: '@', text: '@',
style: TextStyle(fontWeight: FontWeight.w300)), style: TextStyle(fontWeight: FontWeight.w300)),
TextSpan( TextSpan(
text: instanceUrl, text: instanceHost,
style: TextStyle(fontWeight: FontWeight.w600), style: TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = ..onTap =
() => goToInstance(context, instanceUrl)), () => goToInstance(context, instanceHost)),
], ],
), ),
) )
@ -199,7 +198,7 @@ class Post extends HookWidget {
style: TextStyle(fontWeight: FontWeight.w600), style: TextStyle(fontWeight: FontWeight.w600),
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => goToUser.byId( ..onTap = () => goToUser.byId(
context, post.instanceUrl, post.creatorId), context, post.instanceHost, post.creatorId),
), ),
TextSpan( TextSpan(
text: text:
@ -377,10 +376,7 @@ class Post extends HookWidget {
child: InkWell( child: InkWell(
onTap: fullPost onTap: fullPost
? null ? null
: () => goTo( : () => goTo(context, (context) => FullPostPage.fromPostView(post)),
context,
(context) =>
FullPostPage.fromPostView(post)), //, instanceUrl, post.id),
child: Column( child: Column(
children: [ children: [
info(), info(),
@ -394,7 +390,7 @@ class Post extends HookWidget {
// TODO: trim content // TODO: trim content
Padding( Padding(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
child: MarkdownText(post.body, instanceUrl: instanceUrl)), child: MarkdownText(post.body, instanceHost: instanceHost)),
actions(), actions(),
], ],
), ),
@ -416,10 +412,10 @@ class _Voting extends HookWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final myVote = useState(post.myVote ?? VoteType.none); final myVote = useState(post.myVote ?? VoteType.none);
final loading = useDelayedLoading(Duration(milliseconds: 500)); final loading = useDelayedLoading(Duration(milliseconds: 500));
final loggedInAction = useLoggedInAction(post.instanceUrl); final loggedInAction = useLoggedInAction(post.instanceHost);
vote(VoteType vote, Jwt token) async { vote(VoteType vote, Jwt token) async {
final api = LemmyApi(post.instanceUrl).v1; final api = LemmyApi(post.instanceHost).v1;
loading.start(); loading.start();
try { try {

View File

@ -4,7 +4,6 @@ import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../hooks/delayed_loading.dart'; import '../hooks/delayed_loading.dart';
import '../hooks/logged_in_action.dart'; import '../hooks/logged_in_action.dart';
import '../util/extensions/api.dart';
// TODO: sync this button between post and fullpost. the same with voting // TODO: sync this button between post and fullpost. the same with voting
@ -18,10 +17,10 @@ class SavePostButton extends HookWidget {
final isSaved = useState(post.saved ?? false); final isSaved = useState(post.saved ?? false);
final savedIcon = isSaved.value ? Icons.bookmark : Icons.bookmark_border; final savedIcon = isSaved.value ? Icons.bookmark : Icons.bookmark_border;
final loading = useDelayedLoading(Duration(milliseconds: 500)); final loading = useDelayedLoading(Duration(milliseconds: 500));
final loggedInAction = useLoggedInAction(post.instanceUrl); final loggedInAction = useLoggedInAction(post.instanceHost);
savePost(Jwt token) async { savePost(Jwt token) async {
final api = LemmyApi(post.instanceUrl).v1; final api = LemmyApi(post.instanceHost).v1;
loading.start(); loading.start();
try { try {

View File

@ -6,7 +6,6 @@ import 'package:lemmy_api_client/lemmy_api_client.dart';
import 'package:timeago/timeago.dart' as timeago; import 'package:timeago/timeago.dart' as timeago;
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import '../util/goto.dart'; import '../util/goto.dart';
import '../util/intl.dart'; import '../util/intl.dart';
import '../util/text_color.dart'; import '../util/text_color.dart';
@ -18,15 +17,15 @@ import 'sortable_infinite_list.dart';
/// Shared widget of UserPage and ProfileTab /// Shared widget of UserPage and ProfileTab
class UserProfile extends HookWidget { class UserProfile extends HookWidget {
final Future<UserDetails> _userDetails; final Future<UserDetails> _userDetails;
final String instanceUrl; final String instanceHost;
UserProfile({@required int userId, @required this.instanceUrl}) UserProfile({@required int userId, @required this.instanceHost})
: _userDetails = LemmyApi(instanceUrl).v1.getUserDetails( : _userDetails = LemmyApi(instanceHost).v1.getUserDetails(
userId: userId, savedOnly: false, sort: SortType.active); userId: userId, savedOnly: false, sort: SortType.active);
UserProfile.fromUserDetails(UserDetails userDetails) UserProfile.fromUserDetails(UserDetails userDetails)
: _userDetails = Future.value(userDetails), : _userDetails = Future.value(userDetails),
instanceUrl = userDetails.user.instanceUrl; instanceHost = userDetails.user.instanceHost;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -78,7 +77,7 @@ class UserProfile extends HookWidget {
// TODO: first batch is already fetched on render // TODO: first batch is already fetched on render
// TODO: comment and post come from the same endpoint, could be shared // TODO: comment and post come from the same endpoint, could be shared
InfinitePostList( InfinitePostList(
fetcher: (page, batchSize, sort) => LemmyApi(instanceUrl) fetcher: (page, batchSize, sort) => LemmyApi(instanceHost)
.v1 .v1
.getUserDetails( .getUserDetails(
userId: userView.id, userId: userView.id,
@ -90,7 +89,7 @@ class UserProfile extends HookWidget {
.then((val) => val.posts), .then((val) => val.posts),
), ),
InfiniteCommentList( InfiniteCommentList(
fetcher: (page, batchSize, sort) => LemmyApi(instanceUrl) fetcher: (page, batchSize, sort) => LemmyApi(instanceHost)
.v1 .v1
.getUserDetails( .getUserDetails(
userId: userView.id, userId: userView.id,
@ -222,9 +221,9 @@ class _UserOverview extends HookWidget {
style: theme.textTheme.caption, style: theme.textTheme.caption,
), ),
InkWell( InkWell(
onTap: () => goToInstance(context, userView.instanceUrl), onTap: () => goToInstance(context, userView.instanceHost),
child: Text( child: Text(
'${userView.instanceUrl}', '${userView.instanceHost}',
style: theme.textTheme.caption, style: theme.textTheme.caption,
), ),
) )
@ -324,12 +323,12 @@ class _AboutTab extends HookWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final instanceUrl = userDetails.user.instanceUrl; final instanceHost = userDetails.user.instanceHost;
final accStore = useAccountsStore(); final accStore = useAccountsStore();
final isOwnedAccount = accStore.loggedInInstances.contains(instanceUrl) && final isOwnedAccount = accStore.loggedInInstances.contains(instanceHost) &&
accStore.tokens[instanceUrl].containsKey(userDetails.user.name); accStore.tokens[instanceHost].containsKey(userDetails.user.name);
const wallPadding = EdgeInsets.symmetric(horizontal: 15); const wallPadding = EdgeInsets.symmetric(horizontal: 15);
@ -341,7 +340,7 @@ class _AboutTab extends HookWidget {
communityTile(String name, String icon, int id) => ListTile( communityTile(String name, String icon, int id) => ListTile(
dense: true, dense: true,
onTap: () => goToCommunity.byId(context, instanceUrl, id), onTap: () => goToCommunity.byId(context, instanceHost, id),
title: Text('!$name'), title: Text('!$name'),
leading: icon != null leading: icon != null
? CachedNetworkImage( ? CachedNetworkImage(
@ -379,8 +378,8 @@ class _AboutTab extends HookWidget {
if (userDetails.user.bio != null) ...[ if (userDetails.user.bio != null) ...[
Padding( Padding(
padding: wallPadding, padding: wallPadding,
child: child: MarkdownText(userDetails.user.bio,
MarkdownText(userDetails.user.bio, instanceUrl: instanceUrl)), instanceHost: instanceHost)),
divider, divider,
], ],
if (userDetails.moderates.isNotEmpty) ...[ if (userDetails.moderates.isNotEmpty) ...[

View File

@ -4,7 +4,6 @@ import 'package:lemmy_api_client/lemmy_api_client.dart';
import '../hooks/delayed_loading.dart'; import '../hooks/delayed_loading.dart';
import '../hooks/stores.dart'; import '../hooks/stores.dart';
import '../util/extensions/api.dart';
import 'markdown_text.dart'; import 'markdown_text.dart';
/// Modal for writing a comment to a given post/comment (aka reply) /// Modal for writing a comment to a given post/comment (aka reply)
@ -14,14 +13,14 @@ class WriteComment extends HookWidget {
final PostView post; final PostView post;
final CommentView comment; final CommentView comment;
final String instanceUrl; final String instanceHost;
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey(); final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey();
WriteComment.toPost(this.post) WriteComment.toPost(this.post)
: instanceUrl = post.instanceUrl, : instanceHost = post.instanceHost,
comment = null; comment = null;
WriteComment.toComment(this.comment) WriteComment.toComment(this.comment)
: instanceUrl = comment.instanceUrl, : instanceHost = comment.instanceHost,
post = null; post = null;
@override @override
@ -34,7 +33,7 @@ class WriteComment extends HookWidget {
final preview = () { final preview = () {
final body = MarkdownText( final body = MarkdownText(
comment?.content ?? post.body ?? '', comment?.content ?? post.body ?? '',
instanceUrl: instanceUrl, instanceHost: instanceHost,
); );
if (post != null) { if (post != null) {
@ -54,9 +53,9 @@ class WriteComment extends HookWidget {
}(); }();
handleSubmit() async { handleSubmit() async {
final api = LemmyApi(instanceUrl).v1; final api = LemmyApi(instanceHost).v1;
final token = accStore.defaultTokenFor(instanceUrl); final token = accStore.defaultTokenFor(instanceHost);
delayed.start(); delayed.start();
try { try {
@ -115,7 +114,7 @@ class WriteComment extends HookWidget {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: MarkdownText( child: MarkdownText(
controller.text, controller.text,
instanceUrl: instanceUrl, instanceHost: instanceHost,
), ),
) )
], ],

View File

@ -260,7 +260,7 @@ packages:
name: lemmy_api_client name: lemmy_api_client
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.8.0" version: "0.8.2"
markdown: markdown:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -43,7 +43,7 @@ dependencies:
# utils # utils
timeago: ^2.0.27 timeago: ^2.0.27
fuzzy: <1.0.0 fuzzy: <1.0.0
lemmy_api_client: ^0.8.0 lemmy_api_client: ^0.8.2
flutter: flutter:
sdk: flutter sdk: flutter