Implement FeedSource for lemmy feed view
This commit is contained in:
parent
abb128016f
commit
a9931f2ebd
|
@ -28,6 +28,6 @@ void main() async {
|
|||
// Load user settings
|
||||
final settingsController = SettingsController();
|
||||
await settingsController.loadSettings();
|
||||
|
||||
print(settingsController.api);
|
||||
runApp(MyApp(settingsController: settingsController));
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import 'package:interstellar/src/api/entries.dart';
|
|||
import 'package:interstellar/src/api/magazines.dart';
|
||||
import 'package:interstellar/src/api/messages.dart';
|
||||
import 'package:interstellar/src/api/notifications.dart';
|
||||
import 'package:interstellar/src/api/oauth.dart';
|
||||
import 'package:interstellar/src/api/posts.dart';
|
||||
import 'package:interstellar/src/api/search.dart';
|
||||
import 'package:interstellar/src/api/users.dart';
|
||||
|
@ -19,7 +18,6 @@ class API {
|
|||
final http.Client httpClient;
|
||||
final String server;
|
||||
|
||||
final KbinAPIOAuth oauth;
|
||||
final KbinAPIComments comments;
|
||||
final KbinAPIDomains domains;
|
||||
final APIThreads entries;
|
||||
|
@ -34,8 +32,7 @@ class API {
|
|||
this.software,
|
||||
this.httpClient,
|
||||
this.server,
|
||||
) : oauth = KbinAPIOAuth(software, httpClient, server),
|
||||
comments = KbinAPIComments(software, httpClient, server),
|
||||
) : comments = KbinAPIComments(software, httpClient, server),
|
||||
domains = KbinAPIDomains(software, httpClient, server),
|
||||
entries = APIThreads(software, httpClient, server),
|
||||
magazines = APIMagazines(software, httpClient, server),
|
||||
|
|
|
@ -23,6 +23,7 @@ class APIThreads {
|
|||
|
||||
Future<PostListModel> list(
|
||||
FeedSource source, {
|
||||
int? sourceId,
|
||||
String? page,
|
||||
FeedSort? sort,
|
||||
List<String>? langs,
|
||||
|
@ -31,7 +32,15 @@ class APIThreads {
|
|||
switch (software) {
|
||||
case ServerSoftware.kbin:
|
||||
case ServerSoftware.mbin:
|
||||
final path = source.getEntriesPath();
|
||||
final path = switch (source) {
|
||||
FeedSource.all => '/api/entries',
|
||||
FeedSource.subscribed => '/api/entries/subscribed',
|
||||
FeedSource.moderated => '/api/entries/moderated',
|
||||
FeedSource.favorited => '/api/entries/favourited',
|
||||
FeedSource.magazine => '/api/magazine/${sourceId!}/entries',
|
||||
FeedSource.user => '/api/users/${sourceId!}/entries',
|
||||
FeedSource.domain => '/api/users/${sourceId!}/entries',
|
||||
};
|
||||
final query = queryParams({
|
||||
'p': page,
|
||||
'sort': sort?.name,
|
||||
|
@ -50,7 +59,17 @@ class APIThreads {
|
|||
const path = '/api/v3/post/list';
|
||||
final query = queryParams({
|
||||
'page_cursor': page,
|
||||
});
|
||||
}..addAll(switch (source) {
|
||||
FeedSource.all => {'type_': 'All'},
|
||||
FeedSource.subscribed => {'type_': 'Subscribed'},
|
||||
FeedSource.moderated => {'type_': 'ModeratorView'},
|
||||
FeedSource.favorited => {'liked_only': 'true'},
|
||||
FeedSource.magazine => {'community_id': sourceId!.toString()},
|
||||
FeedSource.user =>
|
||||
throw Exception('User source not allowed for lemmy'),
|
||||
FeedSource.domain =>
|
||||
throw Exception('Domain source not allowed for lemmy'),
|
||||
}));
|
||||
|
||||
final response = await httpClient.get(Uri.https(server, path, query));
|
||||
|
||||
|
|
|
@ -1,75 +1,18 @@
|
|||
enum FeedSort { active, hot, newest, oldest, top, commented }
|
||||
|
||||
abstract class FeedSource {
|
||||
String getEntriesPath();
|
||||
String? getPostsPath();
|
||||
enum FeedSource {
|
||||
all,
|
||||
subscribed,
|
||||
moderated,
|
||||
favorited,
|
||||
magazine,
|
||||
user,
|
||||
domain,
|
||||
}
|
||||
|
||||
class FeedSourceAll implements FeedSource {
|
||||
const FeedSourceAll();
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/entries';
|
||||
@override
|
||||
String getPostsPath() => '/api/posts';
|
||||
}
|
||||
|
||||
class FeedSourceSub implements FeedSource {
|
||||
const FeedSourceSub();
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/entries/subscribed';
|
||||
@override
|
||||
String getPostsPath() => '/api/posts/subscribed';
|
||||
}
|
||||
|
||||
class FeedSourceMod implements FeedSource {
|
||||
const FeedSourceMod();
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/entries/moderated';
|
||||
@override
|
||||
String getPostsPath() => '/api/posts/moderated';
|
||||
}
|
||||
|
||||
class FeedSourceFav implements FeedSource {
|
||||
const FeedSourceFav();
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/entries/favourited';
|
||||
@override
|
||||
String getPostsPath() => '/api/posts/favourited';
|
||||
}
|
||||
|
||||
class FeedSourceMagazine implements FeedSource {
|
||||
final int id;
|
||||
|
||||
const FeedSourceMagazine(this.id);
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/magazine/$id/entries';
|
||||
@override
|
||||
String getPostsPath() => '/api/magazine/$id/posts';
|
||||
}
|
||||
|
||||
class FeedSourceUser implements FeedSource {
|
||||
final int id;
|
||||
|
||||
const FeedSourceUser(this.id);
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/users/$id/entries';
|
||||
@override
|
||||
String getPostsPath() => '/api/users/$id/posts';
|
||||
}
|
||||
|
||||
class FeedSourceDomain implements FeedSource {
|
||||
final int id;
|
||||
|
||||
const FeedSourceDomain(this.id);
|
||||
|
||||
@override
|
||||
String getEntriesPath() => '/api/domain/$id/entries';
|
||||
@override
|
||||
String? getPostsPath() => null;
|
||||
enum FeedSort {
|
||||
active,
|
||||
hot,
|
||||
newest,
|
||||
oldest,
|
||||
top,
|
||||
commented,
|
||||
}
|
||||
|
|
|
@ -47,8 +47,14 @@ class APIMagazines {
|
|||
|
||||
case ServerSoftware.lemmy:
|
||||
const path = '/api/v3/community/list';
|
||||
final query = queryParams({
|
||||
'limit': '50',
|
||||
'listingType': 'All',
|
||||
'sort': 'TopAll',
|
||||
'page': page?.toString(),
|
||||
});
|
||||
|
||||
final response = await httpClient.get(Uri.https(server, path));
|
||||
final response = await httpClient.get(Uri.https(server, path, query));
|
||||
|
||||
httpErrorHandler(response, message: 'Failed to load magazines');
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
||||
import 'package:interstellar/src/utils/utils.dart';
|
||||
import 'package:interstellar/src/widgets/redirect_listen.dart';
|
||||
|
||||
|
@ -20,37 +19,25 @@ const oauthScopes = [
|
|||
'moderate'
|
||||
];
|
||||
|
||||
class KbinAPIOAuth {
|
||||
final ServerSoftware software;
|
||||
final http.Client httpClient;
|
||||
final String server;
|
||||
Future<String> registerOauthApp(String instanceHost) async {
|
||||
const path = '/api/client';
|
||||
|
||||
KbinAPIOAuth(
|
||||
this.software,
|
||||
this.httpClient,
|
||||
this.server,
|
||||
final response = await http.post(
|
||||
Uri.https(instanceHost, path),
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'name': oauthName,
|
||||
'contactEmail': oauthContact,
|
||||
'public': true,
|
||||
'redirectUris': [redirectUri],
|
||||
'grants': oauthGrants,
|
||||
'scopes': oauthScopes
|
||||
}),
|
||||
);
|
||||
|
||||
Future<String> registerApp(String instanceHost) async {
|
||||
const path = '/api/client';
|
||||
httpErrorHandler(response, message: 'Failed to register client');
|
||||
|
||||
final response = await httpClient.post(
|
||||
Uri.https(instanceHost, path),
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'name': oauthName,
|
||||
'contactEmail': oauthContact,
|
||||
'public': true,
|
||||
'redirectUris': [redirectUri],
|
||||
'grants': oauthGrants,
|
||||
'scopes': oauthScopes
|
||||
}),
|
||||
);
|
||||
|
||||
httpErrorHandler(response, message: 'Failed to register client');
|
||||
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['identifier'];
|
||||
}
|
||||
return (jsonDecode(response.body) as Map<String, dynamic>)['identifier'];
|
||||
}
|
||||
|
|
|
@ -23,16 +23,23 @@ class APIPosts {
|
|||
|
||||
Future<PostListModel> list(
|
||||
FeedSource source, {
|
||||
int? sourceId,
|
||||
String? page,
|
||||
FeedSort? sort,
|
||||
List<String>? langs,
|
||||
bool? usePreferredLangs,
|
||||
}) async {
|
||||
if (source.getPostsPath() == null) {
|
||||
throw Exception('Failed to load posts');
|
||||
}
|
||||
final path = switch (source) {
|
||||
FeedSource.all => '/api/posts',
|
||||
FeedSource.subscribed => '/api/posts/subscribed',
|
||||
FeedSource.moderated => '/api/posts/moderated',
|
||||
FeedSource.favorited => '/api/posts/favourited',
|
||||
FeedSource.magazine => '/api/magazine/${sourceId!}/posts',
|
||||
FeedSource.user => '/api/users/${sourceId!}/posts',
|
||||
FeedSource.domain =>
|
||||
throw Exception('Domain source not allowed for microblog'),
|
||||
};
|
||||
|
||||
final path = source.getPostsPath()!;
|
||||
final query = queryParams({
|
||||
'p': page,
|
||||
'sort': sort?.name,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:interstellar/src/models/user.dart';
|
||||
import 'package:interstellar/src/utils/models.dart';
|
||||
import 'package:interstellar/src/widgets/markdown_mention.dart';
|
||||
|
||||
part 'magazine.freezed.dart';
|
||||
|
||||
|
@ -52,31 +51,26 @@ class DetailedMagazineModel with _$DetailedMagazineModel {
|
|||
required bool? isBlockedByUser,
|
||||
}) = _DetailedMagazineModel;
|
||||
|
||||
factory DetailedMagazineModel.fromKbin(Map<String, Object?> json) {
|
||||
final magazine = DetailedMagazineModel(
|
||||
id: json['magazineId'] as int,
|
||||
name: json['name'] as String,
|
||||
title: json['title'] as String,
|
||||
icon: kbinGetImageUrl(json['icon'] as Map<String, Object?>?),
|
||||
description: json['description'] as String?,
|
||||
rules: json['rules'] as String?,
|
||||
moderators: ((json['moderators'] ?? []) as List<dynamic>)
|
||||
.map((user) => UserModel.fromKbin(user as Map<String, Object?>))
|
||||
.toList(),
|
||||
subscriptionsCount: json['subscriptionsCount'] as int,
|
||||
threadCount: json['entryCount'] as int,
|
||||
threadCommentCount: json['entryCommentCount'] as int,
|
||||
microblogCount: json['postCount'] as int,
|
||||
microblogCommentCount: json['postCommentCount'] as int,
|
||||
isAdult: json['isAdult'] as bool,
|
||||
isUserSubscribed: json['isUserSubscribed'] as bool?,
|
||||
isBlockedByUser: json['isBlockedByUser'] as bool?,
|
||||
);
|
||||
|
||||
magazineMentionCache[magazine.name] = magazine;
|
||||
|
||||
return magazine;
|
||||
}
|
||||
factory DetailedMagazineModel.fromKbin(Map<String, Object?> json) =>
|
||||
DetailedMagazineModel(
|
||||
id: json['magazineId'] as int,
|
||||
name: json['name'] as String,
|
||||
title: json['title'] as String,
|
||||
icon: kbinGetImageUrl(json['icon'] as Map<String, Object?>?),
|
||||
description: json['description'] as String?,
|
||||
rules: json['rules'] as String?,
|
||||
moderators: ((json['moderators'] ?? []) as List<dynamic>)
|
||||
.map((user) => UserModel.fromKbin(user as Map<String, Object?>))
|
||||
.toList(),
|
||||
subscriptionsCount: json['subscriptionsCount'] as int,
|
||||
threadCount: json['entryCount'] as int,
|
||||
threadCommentCount: json['entryCommentCount'] as int,
|
||||
microblogCount: json['postCount'] as int,
|
||||
microblogCommentCount: json['postCommentCount'] as int,
|
||||
isAdult: json['isAdult'] as bool,
|
||||
isUserSubscribed: json['isUserSubscribed'] as bool?,
|
||||
isBlockedByUser: json['isBlockedByUser'] as bool?,
|
||||
);
|
||||
|
||||
factory DetailedMagazineModel.fromLemmy(Map<String, Object?> json) {
|
||||
final lemmyCommunity = json['community'] as Map<String, Object?>;
|
||||
|
@ -100,8 +94,6 @@ class DetailedMagazineModel with _$DetailedMagazineModel {
|
|||
isBlockedByUser: json['blocked'] as bool?,
|
||||
);
|
||||
|
||||
magazineMentionCache[magazine.name] = magazine;
|
||||
|
||||
return magazine;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:interstellar/src/utils/models.dart';
|
||||
import 'package:interstellar/src/widgets/markdown_mention.dart';
|
||||
|
||||
part 'user.freezed.dart';
|
||||
|
||||
|
@ -38,26 +37,20 @@ class DetailedUserModel with _$DetailedUserModel {
|
|||
required bool? isBlockedByUser,
|
||||
}) = _DetailedUserModel;
|
||||
|
||||
factory DetailedUserModel.fromKbin(Map<String, Object?> json) {
|
||||
final user = DetailedUserModel(
|
||||
id: json['userId'] as int,
|
||||
name: json['username'] as String,
|
||||
avatar: kbinGetImageUrl(json['avatar'] as Map<String, Object?>?),
|
||||
cover: kbinGetImageUrl(json['cover'] as Map<String, Object?>?),
|
||||
createdAt: DateTime.parse(json['createdAt'] as String),
|
||||
isBot: json['isBot'] as bool,
|
||||
about: json['about'] as String?,
|
||||
followersCount: json['followersCount'] as int,
|
||||
isFollowedByUser: json['isFollowedByUser'] as bool?,
|
||||
isFollowerOfUser: json['isFollowerOfUser'] as bool?,
|
||||
isBlockedByUser: json['isBlockedByUser'] as bool?,
|
||||
);
|
||||
|
||||
userMentionCache[
|
||||
user.name.startsWith('@') ? user.name.substring(1) : user.name] = user;
|
||||
|
||||
return user;
|
||||
}
|
||||
factory DetailedUserModel.fromKbin(Map<String, Object?> json) =>
|
||||
DetailedUserModel(
|
||||
id: json['userId'] as int,
|
||||
name: json['username'] as String,
|
||||
avatar: kbinGetImageUrl(json['avatar'] as Map<String, Object?>?),
|
||||
cover: kbinGetImageUrl(json['cover'] as Map<String, Object?>?),
|
||||
createdAt: DateTime.parse(json['createdAt'] as String),
|
||||
isBot: json['isBot'] as bool,
|
||||
about: json['about'] as String?,
|
||||
followersCount: json['followersCount'] as int,
|
||||
isFollowedByUser: json['isFollowedByUser'] as bool?,
|
||||
isFollowerOfUser: json['isFollowerOfUser'] as bool?,
|
||||
isBlockedByUser: json['isBlockedByUser'] as bool?,
|
||||
);
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
|
|
@ -41,7 +41,8 @@ class _DomainScreenState extends State<DomainScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FeedScreen(
|
||||
source: FeedSourceDomain(widget.domainId),
|
||||
source: FeedSource.domain,
|
||||
sourceId: widget.domainId,
|
||||
title: _data?.name ?? '',
|
||||
details: _data != null
|
||||
? Padding(
|
||||
|
|
|
@ -12,42 +12,47 @@ class ExploreScreen extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: 3,
|
||||
length: context.watch<SettingsController>().serverSoftware ==
|
||||
ServerSoftware.lemmy
|
||||
? 2
|
||||
: 4,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
'Explore ${context.watch<SettingsController>().instanceHost}'),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const SearchScreen(),
|
||||
),
|
||||
);
|
||||
},
|
||||
icon: const Icon(Icons.search))
|
||||
],
|
||||
bottom: const TabBar(tabs: [
|
||||
Tab(
|
||||
bottom: TabBar(tabs: [
|
||||
const Tab(
|
||||
text: 'Magazines',
|
||||
icon: Icon(Icons.article),
|
||||
),
|
||||
Tab(
|
||||
text: 'People',
|
||||
icon: Icon(Icons.account_circle),
|
||||
),
|
||||
Tab(
|
||||
text: 'Domains',
|
||||
icon: Icon(Icons.public),
|
||||
if (context.watch<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy)
|
||||
const Tab(
|
||||
text: 'People',
|
||||
icon: Icon(Icons.account_circle),
|
||||
),
|
||||
if (context.watch<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy)
|
||||
const Tab(
|
||||
text: 'Domains',
|
||||
icon: Icon(Icons.public),
|
||||
),
|
||||
const Tab(
|
||||
text: 'Search',
|
||||
icon: Icon(Icons.search),
|
||||
),
|
||||
]),
|
||||
),
|
||||
body: const TabBarView(
|
||||
body: TabBarView(
|
||||
children: [
|
||||
MagazinesScreen(),
|
||||
UsersScreen(),
|
||||
DomainsScreen(),
|
||||
const MagazinesScreen(),
|
||||
if (context.watch<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy)
|
||||
const UsersScreen(),
|
||||
if (context.watch<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy)
|
||||
const DomainsScreen(),
|
||||
const SearchScreen(),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -45,7 +45,8 @@ class _MagazineScreenState extends State<MagazineScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FeedScreen(
|
||||
source: FeedSourceMagazine(widget.magazineId),
|
||||
source: FeedSource.magazine,
|
||||
sourceId: widget.magazineId,
|
||||
title: _data?.name ?? '',
|
||||
details: _data != null
|
||||
? Padding(
|
||||
|
|
|
@ -22,8 +22,8 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
|
|||
KbinAPIMagazinesSort sort = KbinAPIMagazinesSort.hot;
|
||||
String search = "";
|
||||
|
||||
final PagingController<String, DetailedMagazineModel> _pagingController =
|
||||
PagingController(firstPageKey: '1');
|
||||
final PagingController<int, DetailedMagazineModel> _pagingController =
|
||||
PagingController(firstPageKey: 1);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -32,11 +32,11 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
|
|||
_pagingController.addPageRequestListener(_fetchPage);
|
||||
}
|
||||
|
||||
Future<void> _fetchPage(String pageKey) async {
|
||||
Future<void> _fetchPage(int pageKey) async {
|
||||
try {
|
||||
final newPage =
|
||||
await context.read<SettingsController>().api.magazines.list(
|
||||
page: int.parse(pageKey),
|
||||
page: pageKey,
|
||||
filter: filter,
|
||||
sort: sort,
|
||||
search: search.isEmpty ? null : search,
|
||||
|
@ -50,7 +50,14 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
|
|||
final newItems =
|
||||
newPage.items.where((e) => !currentItemIds.contains(e.id)).toList();
|
||||
|
||||
_pagingController.appendPage(newItems, newPage.nextPage);
|
||||
_pagingController.appendPage(
|
||||
newItems,
|
||||
context.read<SettingsController>().serverSoftware ==
|
||||
ServerSoftware.lemmy
|
||||
? (newPage.items.isEmpty ? null : pageKey + 1)
|
||||
: (newPage.nextPage == null
|
||||
? null
|
||||
: int.parse(newPage.nextPage!)));
|
||||
} catch (error, st) {
|
||||
print(error);
|
||||
print(st);
|
||||
|
|
|
@ -54,7 +54,8 @@ class _UserScreenState extends State<UserScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FeedScreen(
|
||||
source: FeedSourceUser(widget.userId),
|
||||
source: FeedSource.user,
|
||||
sourceId: widget.userId,
|
||||
title: _data?.name ?? '',
|
||||
details: _data != null
|
||||
? Column(
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:provider/provider.dart';
|
|||
|
||||
class FeedScreen extends StatefulWidget {
|
||||
final FeedSource? source;
|
||||
final int? sourceId;
|
||||
final String? title;
|
||||
final Widget? details;
|
||||
final Widget? floatingActionButton;
|
||||
|
@ -20,6 +21,7 @@ class FeedScreen extends StatefulWidget {
|
|||
const FeedScreen({
|
||||
super.key,
|
||||
this.source,
|
||||
this.sourceId,
|
||||
this.title,
|
||||
this.details,
|
||||
this.floatingActionButton,
|
||||
|
@ -37,7 +39,8 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_mode = (widget.source ?? const FeedSourceAll()).getPostsPath() != null
|
||||
_mode = context.read<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy
|
||||
? context.read<SettingsController>().defaultFeedType
|
||||
: PostType.thread;
|
||||
_sort = widget.source == null
|
||||
|
@ -82,7 +85,10 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||
),
|
||||
),
|
||||
actions: [
|
||||
if ((widget.source ?? const FeedSourceAll()).getPostsPath() != null)
|
||||
// Domain FeedSource is not available for microblogs
|
||||
if (widget.source != FeedSource.domain &&
|
||||
context.read<SettingsController>().serverSoftware !=
|
||||
ServerSoftware.lemmy)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 8),
|
||||
child: IconButton(
|
||||
|
@ -156,6 +162,7 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||
body: widget.source != null
|
||||
? FeedScreenBody(
|
||||
source: widget.source!,
|
||||
sourceId: widget.sourceId,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
|
@ -165,25 +172,25 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||
TabBarView(
|
||||
children: [
|
||||
FeedScreenBody(
|
||||
source: const FeedSourceSub(),
|
||||
source: FeedSource.subscribed,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
),
|
||||
FeedScreenBody(
|
||||
source: const FeedSourceMod(),
|
||||
source: FeedSource.moderated,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
),
|
||||
FeedScreenBody(
|
||||
source: const FeedSourceFav(),
|
||||
source: FeedSource.favorited,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
),
|
||||
FeedScreenBody(
|
||||
source: const FeedSourceAll(),
|
||||
source: FeedSource.all,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
|
@ -191,7 +198,7 @@ class _FeedScreenState extends State<FeedScreen> {
|
|||
],
|
||||
),
|
||||
otherwise: FeedScreenBody(
|
||||
source: const FeedSourceAll(),
|
||||
source: FeedSource.all,
|
||||
sort: _sort,
|
||||
mode: _mode,
|
||||
details: widget.details,
|
||||
|
@ -260,6 +267,7 @@ const SelectionMenu<FeedSort> feedSortSelect = SelectionMenu(
|
|||
|
||||
class FeedScreenBody extends StatefulWidget {
|
||||
final FeedSource source;
|
||||
final int? sourceId;
|
||||
final FeedSort sort;
|
||||
final PostType mode;
|
||||
final Widget? details;
|
||||
|
@ -267,6 +275,7 @@ class FeedScreenBody extends StatefulWidget {
|
|||
const FeedScreenBody({
|
||||
super.key,
|
||||
required this.source,
|
||||
this.sourceId,
|
||||
required this.sort,
|
||||
required this.mode,
|
||||
this.details,
|
||||
|
@ -292,6 +301,7 @@ class _FeedScreenBodyState extends State<FeedScreenBody> {
|
|||
PostListModel newPage = await (switch (widget.mode) {
|
||||
PostType.thread => context.read<SettingsController>().api.entries.list(
|
||||
widget.source,
|
||||
sourceId: widget.sourceId,
|
||||
page: pageKey.isEmpty ? null : pageKey,
|
||||
sort: widget.sort,
|
||||
usePreferredLangs: whenLoggedIn(context,
|
||||
|
@ -300,6 +310,7 @@ class _FeedScreenBodyState extends State<FeedScreenBody> {
|
|||
),
|
||||
PostType.microblog => context.read<SettingsController>().api.posts.list(
|
||||
widget.source,
|
||||
sourceId: widget.sourceId,
|
||||
page: pageKey.isEmpty ? null : pageKey,
|
||||
sort: widget.sort,
|
||||
usePreferredLangs: whenLoggedIn(context,
|
||||
|
|
|
@ -54,7 +54,7 @@ class _LoginSelectScreenState extends State<LoginSelectScreen> {
|
|||
|
||||
await context
|
||||
.read<SettingsController>()
|
||||
.setServer(software, _instanceHostController.text);
|
||||
.saveServer(software, _instanceHostController.text);
|
||||
|
||||
// Check BuildContext
|
||||
if (!mounted) return;
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:interstellar/src/api/api.dart';
|
||||
import 'package:interstellar/src/api/comments.dart';
|
||||
import 'package:interstellar/src/api/feed_source.dart';
|
||||
import 'package:interstellar/src/api/oauth.dart';
|
||||
import 'package:interstellar/src/models/post.dart';
|
||||
import 'package:interstellar/src/utils/jwt_http_client.dart';
|
||||
import 'package:interstellar/src/utils/themes.dart';
|
||||
|
@ -137,7 +138,7 @@ class SettingsController with ChangeNotifier {
|
|||
as Map<String, dynamic>)
|
||||
.map((key, value) => MapEntry(key, Account.fromJson(value)));
|
||||
_selectedAccount = prefs.getString('selectedAccount') ?? '@kbin.earth';
|
||||
updateAPI();
|
||||
await updateAPI();
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -300,7 +301,9 @@ class SettingsController with ChangeNotifier {
|
|||
await prefs.setString('defaultCreateLang', newDefaultCreateLang);
|
||||
}
|
||||
|
||||
Future<void> setServer(ServerSoftware software, String server) async {
|
||||
Future<void> saveServer(ServerSoftware software, String server) async {
|
||||
if (_servers.containsKey(server)) return;
|
||||
|
||||
_servers[server] = Server(software);
|
||||
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
@ -318,7 +321,7 @@ class SettingsController with ChangeNotifier {
|
|||
throw Exception('Tried to register oauth for lemmy');
|
||||
}
|
||||
|
||||
String oauthIdentifier = await _api.oauth.registerApp(server);
|
||||
String oauthIdentifier = await registerOauthApp(server);
|
||||
_servers[server] = Server(software, oauthIdentifier: oauthIdentifier);
|
||||
|
||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
|
|
|
@ -99,6 +99,7 @@ class SettingsScreen extends StatelessWidget {
|
|||
ListTile(
|
||||
title: const Text('Default Feed Type'),
|
||||
leading: const Icon(Icons.tab),
|
||||
enabled: controller.serverSoftware != ServerSoftware.lemmy,
|
||||
onTap: () async {
|
||||
controller.updateDefaultFeedType(
|
||||
await feedTypeSelect.inquireSelection(
|
||||
|
|
|
@ -150,9 +150,7 @@ class MentionWidgetState extends State<MentionWidget> {
|
|||
final modifier = widget.name[0];
|
||||
final split = widget.name.substring(1).split('@');
|
||||
final name = split[0];
|
||||
final host = (split.length > 1)
|
||||
? split[1]
|
||||
: widget.originInstance;
|
||||
final host = (split.length > 1) ? split[1] : widget.originInstance;
|
||||
final cacheKey = '$name@$host';
|
||||
|
||||
setState(() {
|
||||
|
@ -164,7 +162,9 @@ class MentionWidgetState extends State<MentionWidget> {
|
|||
if (!userMentionCache.containsKey(cacheKey)) {
|
||||
userMentionCache[cacheKey] =
|
||||
await context.read<SettingsController>().api.users.getByName(
|
||||
'@$name@$host',
|
||||
host == context.read<SettingsController>().instanceHost
|
||||
? name
|
||||
: '@$name@$host',
|
||||
);
|
||||
}
|
||||
final user = userMentionCache[cacheKey]!;
|
||||
|
@ -183,7 +183,9 @@ class MentionWidgetState extends State<MentionWidget> {
|
|||
if (!magazineMentionCache.containsKey(cacheKey)) {
|
||||
magazineMentionCache[cacheKey] =
|
||||
await context.read<SettingsController>().api.magazines.getByName(
|
||||
'$name@$host',
|
||||
host == context.read<SettingsController>().instanceHost
|
||||
? name
|
||||
: '$name@$host',
|
||||
);
|
||||
}
|
||||
final magazine = magazineMentionCache[cacheKey]!;
|
||||
|
|
Loading…
Reference in New Issue