mirror of
https://github.com/wgh136/pixes.git
synced 2025-09-27 21:07:24 +00:00
following users page
This commit is contained in:
@@ -89,8 +89,18 @@ abstract class MultiPageLoadingState<T extends StatefulWidget, S extends Object>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void reset() {
|
||||||
void initState() {
|
setState(() {
|
||||||
|
_isFirstLoading = true;
|
||||||
|
_isLoading = false;
|
||||||
|
_data = null;
|
||||||
|
_error = null;
|
||||||
|
_page = 1;
|
||||||
|
});
|
||||||
|
firstLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void firstLoad() {
|
||||||
loadData(_page).then((value) {
|
loadData(_page).then((value) {
|
||||||
if(value.success) {
|
if(value.success) {
|
||||||
_page++;
|
_page++;
|
||||||
@@ -105,6 +115,11 @@ abstract class MultiPageLoadingState<T extends StatefulWidget, S extends Object>
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
firstLoad();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -340,5 +340,5 @@ class UserPreview {
|
|||||||
account = json['account'],
|
account = json['account'],
|
||||||
avatar = json['profile_image_urls']['medium'],
|
avatar = json['profile_image_urls']['medium'],
|
||||||
isFollowed = json['is_followed'],
|
isFollowed = json['is_followed'],
|
||||||
isBlocking = json['is_access_blocking_user'];
|
isBlocking = json['is_access_blocking_user'] ?? false;
|
||||||
}
|
}
|
||||||
|
@@ -324,4 +324,16 @@ class Network {
|
|||||||
return Res.error(res.errorMessage);
|
return Res.error(res.errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Res<List<UserPreview>>> getFollowing(String uid, String type, [String? nextUrl]) async {
|
||||||
|
var path = nextUrl ?? "/v1/user/following?filter=for_android&user_id=$uid&restrict=$type";
|
||||||
|
var res = await apiGet(path);
|
||||||
|
if (res.success) {
|
||||||
|
return Res(
|
||||||
|
(res.data["user_previews"] as List).map((e) => UserPreview.fromJson(e["user"])).toList(),
|
||||||
|
subData: res.data["next_url"]);
|
||||||
|
} else {
|
||||||
|
return Res.error(res.errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
82
lib/pages/following_users_page.dart
Normal file
82
lib/pages/following_users_page.dart
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:pixes/appdata.dart';
|
||||||
|
import 'package:pixes/components/loading.dart';
|
||||||
|
import 'package:pixes/components/segmented_button.dart';
|
||||||
|
import 'package:pixes/foundation/app.dart';
|
||||||
|
import 'package:pixes/network/network.dart';
|
||||||
|
import 'package:pixes/utils/translation.dart';
|
||||||
|
|
||||||
|
import '../components/grid.dart';
|
||||||
|
import '../components/user_preview.dart';
|
||||||
|
|
||||||
|
class FollowingUsersPage extends StatefulWidget {
|
||||||
|
const FollowingUsersPage(this.uid, {super.key});
|
||||||
|
|
||||||
|
final String uid;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<FollowingUsersPage> createState() => _FollowingUsersPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _FollowingUsersPageState extends MultiPageLoadingState<FollowingUsersPage, UserPreview> {
|
||||||
|
String type = "public";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget buildContent(BuildContext context, final List<UserPreview> data) {
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text("Following".tl,
|
||||||
|
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),)
|
||||||
|
.paddingVertical(12).paddingLeft(16),
|
||||||
|
const Spacer(),
|
||||||
|
if(widget.uid == appdata.account?.user.id)
|
||||||
|
SegmentedButton(
|
||||||
|
value: type,
|
||||||
|
options: [
|
||||||
|
SegmentedButtonOption("public", "Public".tl),
|
||||||
|
SegmentedButtonOption("private", "Private".tl),
|
||||||
|
],
|
||||||
|
onPressed: (s) {
|
||||||
|
type = s;
|
||||||
|
reset();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16,)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SliverGridViewWithFixedItemHeight(
|
||||||
|
delegate: SliverChildBuilderDelegate(
|
||||||
|
(context, index) {
|
||||||
|
if(index == data.length - 1){
|
||||||
|
nextPage();
|
||||||
|
}
|
||||||
|
return UserPreviewWidget(data[index]);
|
||||||
|
},
|
||||||
|
childCount: data.length
|
||||||
|
),
|
||||||
|
maxCrossAxisExtent: 520,
|
||||||
|
itemHeight: 114,
|
||||||
|
).sliverPaddingHorizontal(8)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String? nextUrl;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Res<List<UserPreview>>> loadData(page) async{
|
||||||
|
if(nextUrl == "end") {
|
||||||
|
return Res.error("No more data");
|
||||||
|
}
|
||||||
|
var res = await Network().getFollowing(widget.uid, type, nextUrl);
|
||||||
|
if(!res.error) {
|
||||||
|
nextUrl = res.subData;
|
||||||
|
nextUrl ??= "end";
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +1,12 @@
|
|||||||
import 'package:fluent_ui/fluent_ui.dart';
|
import 'package:fluent_ui/fluent_ui.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||||
import 'package:pixes/components/loading.dart';
|
import 'package:pixes/components/loading.dart';
|
||||||
import 'package:pixes/components/md.dart';
|
import 'package:pixes/components/md.dart';
|
||||||
import 'package:pixes/foundation/app.dart';
|
import 'package:pixes/foundation/app.dart';
|
||||||
import 'package:pixes/foundation/image_provider.dart';
|
import 'package:pixes/foundation/image_provider.dart';
|
||||||
import 'package:pixes/network/network.dart';
|
import 'package:pixes/network/network.dart';
|
||||||
|
import 'package:pixes/pages/following_users_page.dart';
|
||||||
import 'package:pixes/utils/translation.dart';
|
import 'package:pixes/utils/translation.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
@@ -53,13 +55,18 @@ class _UserInfoPageState extends LoadingState<UserInfoPage, UserDetails> {
|
|||||||
),
|
),
|
||||||
),),
|
),),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(data!.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w500)),
|
Text(data!.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text.rich(
|
Text.rich(
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: 'Follows: '.tl),
|
TextSpan(text: 'Follows: '.tl),
|
||||||
TextSpan(text: '${data!.totalFollowUsers}', style: const TextStyle(fontWeight: FontWeight.w500)),
|
TextSpan(
|
||||||
|
text: '${data!.totalFollowUsers}',
|
||||||
|
recognizer: TapGestureRecognizer()
|
||||||
|
..onTap = (() => context.to(() => FollowingUsersPage(widget.id))),
|
||||||
|
style: TextStyle(fontWeight: FontWeight.bold, color: FluentTheme.of(context).accentColor)
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
style: const TextStyle(fontSize: 14),
|
style: const TextStyle(fontSize: 14),
|
||||||
|
Reference in New Issue
Block a user