diff --git a/lib/business_logic/account/account.dart b/lib/business_logic/account/account.dart index 7bd072a..91036c5 100644 --- a/lib/business_logic/account/account.dart +++ b/lib/business_logic/account/account.dart @@ -198,9 +198,10 @@ Future?>> getPostsForAccount( headers.addAll(global.defaultHeaders); final params = { "limit": global.settings!.batchSize.toString(), - if (maxid != null) "maxid": maxid, + if (maxid != null) "max_id": maxid, }; final uri = Uri( + scheme: "https", host: identity.instanceUrl, path: "/api/v1/accounts/${model.id}/statuses", queryParameters: params, @@ -211,17 +212,16 @@ Future?>> getPostsForAccount( return MapEntry(r.statusCode, null); } - final List> rb = jsonDecode(r.body); + final List rb = jsonDecode(r.body); List threads = []; - // ignore: avoid_function_literals_in_foreach_calls - rb.forEach((element) async { + for (var element in rb) { threads.add( await PostModel.fromJson( element, model.identity, ).getThread(), ); - }); + } return MapEntry(r.statusCode, threads); } diff --git a/lib/dialogues/makepost.dart b/lib/dialogues/makepost.dart index 64806c5..2f74bfe 100644 --- a/lib/dialogues/makepost.dart +++ b/lib/dialogues/makepost.dart @@ -168,7 +168,7 @@ class _MakePostState extends State { }, ), ), - OutlinedButton.icon( + ElevatedButton.icon( label: Text( "send-post".i18n(), ), diff --git a/lib/pages/profile_view/profile_view.dart b/lib/pages/profile_view/profile_view.dart index ea92692..c252eef 100644 --- a/lib/pages/profile_view/profile_view.dart +++ b/lib/pages/profile_view/profile_view.dart @@ -4,9 +4,12 @@ import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; import 'package:loris/business_logic/account/account.dart'; import 'package:loris/business_logic/settings.dart'; +import 'package:loris/business_logic/timeline/timeline.dart'; +import 'package:loris/partials/loadingbox.dart'; import 'package:loris/partials/post.dart'; import 'package:loris/partials/post_text_renderer.dart'; import 'package:loris/global.dart' as global; +import 'package:loris/partials/thread.dart'; class ProfileView extends StatefulWidget { const ProfileView({ @@ -25,6 +28,9 @@ class _ProfileViewState extends State { Map relationships = {}; String activeIdentity = ""; bool loading = true; + List threads = []; + String? maxid; + final ScrollController _scrollController = ScrollController(); Future addRelationship(AccountModel m) async { final r = await getRelationship(m.identity, m.id); @@ -50,12 +56,39 @@ class _ProfileViewState extends State { await addRelationship(m.values.first!); } if (i >= global.settings!.identities.length) { + if (mounted) { + setState(() { + loading = false; + }); + } + } + } + + void loadPosts() async { + if (threads.isNotEmpty) { + maxid = threads.last.posts.last.id; + } + + final t = await getPostsForAccount(identities[activeIdentity]!, maxid); + if (t.value == null) { + return; + } + if (mounted) { setState(() { - loading = false; + threads.addAll(t.value!); }); } } + void reloadPosts() async { + _scrollController.animateTo(0, + duration: const Duration(seconds: 1), curve: Curves.ease); + setState(() { + threads = []; + }); + loadPosts(); + } + void update() async { int i = 0; await Future.forEach>( @@ -74,6 +107,7 @@ class _ProfileViewState extends State { @override void dispose() { + _scrollController.dispose(); _relationshipStream.close(); super.dispose(); } @@ -83,6 +117,15 @@ class _ProfileViewState extends State { activeIdentity = widget.model.identity; identities.addAll({widget.model.identity: widget.model}); update(); + loadPosts(); + _scrollController.addListener(() { + if (_scrollController.offset >= + _scrollController.position.maxScrollExtent - + MediaQuery.of(context).size.height && + !_scrollController.position.outOfRange) { + loadPosts(); + } + }); _relationshipStream.stream.listen((event) { setState(() { relationships.addEntries([event]); @@ -106,6 +149,13 @@ class _ProfileViewState extends State { ), ); }); + + final profileViewDisplay = ProfileViewDisplay( + accountModel: identities[activeIdentity]!, + relationshipModel: relationships[activeIdentity], + relationshipStream: _relationshipStream, + ); + return SimpleDialog( alignment: Alignment.center, title: DisplayName( @@ -136,16 +186,31 @@ class _ProfileViewState extends State { setState(() { activeIdentity = value.toString(); }); + reloadPosts(); }, ), ), ], ), - ProfileViewDisplay( - accountModel: identities[activeIdentity]!, - relationshipModel: relationships[activeIdentity], - stream: _relationshipStream, - ) + Container( + constraints: global.getConstraints(context), + width: global.getWidth(context), + height: MediaQuery.of(context).size.height * 2 / 3, + child: ListView.builder( + controller: _scrollController, + shrinkWrap: true, + itemCount: threads.length + 2, + itemBuilder: (context, index) { + if (index == 0) { + return profileViewDisplay; + } else if (index > 0 && index <= threads.length) { + return Thread(model: threads[index - 1]); + } + + return const LoadingBox(); + }, + ), + ), ], ); } @@ -247,11 +312,11 @@ class ProfileViewDisplay extends StatelessWidget { super.key, required this.accountModel, this.relationshipModel, - required this.stream, + required this.relationshipStream, }); final AccountModel accountModel; final RelationshipModel? relationshipModel; - final StreamController stream; + final StreamController relationshipStream; static const d = SizedBox( height: 8, ); @@ -275,11 +340,8 @@ class ProfileViewDisplay extends StatelessWidget { AccountInteractionButtons( account: accountModel, relationship: relationshipModel!, - stream: stream, + stream: relationshipStream, ), - AccountPostList( - accountModel: accountModel, - ), ]; return Container( @@ -293,29 +355,6 @@ class ProfileViewDisplay extends StatelessWidget { } } -class AccountPostList extends StatefulWidget { - const AccountPostList({ - super.key, - required this.accountModel, - }); - final AccountModel accountModel; - - @override - State createState() => _AccountPostListState(); -} - -class _AccountPostListState extends State { - @override - Widget build(BuildContext context) { - return Container( - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height, - ), - child: ListView(), - ); - } -} - class AccountInteractionButton extends StatefulWidget { const AccountInteractionButton({ super.key, diff --git a/lib/partials/post.dart b/lib/partials/post.dart index d580d17..ac8b6f0 100644 --- a/lib/partials/post.dart +++ b/lib/partials/post.dart @@ -231,7 +231,7 @@ class _PostBodyState extends State { TextSpan( children: [ WidgetSpan( - child: OutlinedButton.icon( + child: ElevatedButton.icon( onPressed: () { setState(() { visible = !visible; diff --git a/lib/partials/thread.dart b/lib/partials/thread.dart index 4a0b0e5..20b9f70 100644 --- a/lib/partials/thread.dart +++ b/lib/partials/thread.dart @@ -57,7 +57,7 @@ class _ThreadState extends State { Expanded( child: SelectableText(s), ), - OutlinedButton.icon( + ElevatedButton.icon( onPressed: () { setState(() { showSensitive = !showSensitive;