Skip to content

Commit 61bffa5

Browse files
authored
Merge pull request #122 from jwr1/piefed-support
Add PieFed support and additional Lemmy support
2 parents b285174 + 24240f2 commit 61bffa5

58 files changed

Lines changed: 3465 additions & 2008 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Interstellar
22

3-
An app for Mbin and Lemmy; connecting you to the fediverse.
3+
An app for Mbin/Lemmy/PieFed, connecting you to the fediverse.
44

55
## Downloads
66

@@ -33,7 +33,7 @@ You can ask questions, report bugs, make suggestions, etc., to any of the follow
3333

3434
## Contributing
3535

36-
Interstellar uses [Flutter](https://flutter.dev) as its framework, so make sure you have the [Flutter SDK installed](https://docs.flutter.dev/get-started/install) before doing anything else. Then, run `flutter doctor -v` to see instructions for setting up different build platforms (e.g. android studio for APKs). While developing on Linux, you will also need to install `libmpv` from your distro. Once all that's done, use `dart run build_runner build` to build the generated code for models (this only needs to run once unless you modify one of the models). Finally, you can use `flutter run` to develop, and `flutter build {platform}` for release files.
36+
Interstellar uses [Flutter](https://flutter.dev) as its framework, so make sure you have the [Flutter SDK installed](https://docs.flutter.dev/get-started/install) before doing anything else. Then, run `flutter doctor -v` to see instructions for setting up different build platforms (e.g. android studio for APKs). While developing on Linux, you will also need to install `libmpv` from your distro. Once all that's done, use `dart run build_runner build -d` to build the generated code for models (this only needs to run once unless you modify one of the models). Finally, you can use `flutter run` to develop, and `flutter build {platform}` for release files.
3737

3838
### Generating app icon
3939

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<p><i>Interstellar</i> is a free and open source, Fediverse client, allowing you to access your Mbin and Lemmy accounts and interact with your favorite communities.</p>
1+
<p><i>Interstellar</i> is a free and open source, Fediverse client, allowing you to access your Mbin/Lemmy/PieFed accounts and interact with your favorite communities.</p>

lib/src/api/api.dart

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import 'dart:convert';
2-
31
import 'package:http/http.dart' as http;
42
import 'package:interstellar/src/api/bookmark.dart';
3+
import 'package:interstellar/src/api/client.dart';
54
import 'package:interstellar/src/api/comments.dart';
65
import 'package:interstellar/src/api/domains.dart';
76
import 'package:interstellar/src/api/magazine_moderation.dart';
@@ -14,53 +13,45 @@ import 'package:interstellar/src/api/search.dart';
1413
import 'package:interstellar/src/api/threads.dart';
1514
import 'package:interstellar/src/api/users.dart';
1615
import 'package:interstellar/src/controller/server.dart';
17-
import 'package:interstellar/src/utils/utils.dart';
1816

1917
class API {
20-
final ServerSoftware software;
21-
final http.Client httpClient;
22-
final String server;
18+
final ServerClient client;
2319

2420
final APIComments comments;
2521
final MbinAPIDomains domains;
2622
final APIThreads threads;
2723
final APIMagazines magazines;
2824
final APIMagazineModeration magazineModeration;
29-
final MbinAPIMessages messages;
25+
final APIMessages messages;
3026
final APIModeration moderation;
31-
final MbinAPINotifications notifications;
27+
final APINotifications notifications;
3228
final MbinAPIMicroblogs microblogs;
3329
final APISearch search;
3430
final APIUsers users;
3531
final APIBookmark bookmark;
3632

37-
API(
38-
this.software,
39-
this.httpClient,
40-
this.server,
41-
) : comments = APIComments(software, httpClient, server),
42-
domains = MbinAPIDomains(software, httpClient, server),
43-
threads = APIThreads(software, httpClient, server),
44-
magazines = APIMagazines(software, httpClient, server),
45-
magazineModeration =
46-
APIMagazineModeration(software, httpClient, server),
47-
messages = MbinAPIMessages(software, httpClient, server),
48-
moderation = APIModeration(software, httpClient, server),
49-
notifications = MbinAPINotifications(software, httpClient, server),
50-
microblogs = MbinAPIMicroblogs(software, httpClient, server),
51-
search = APISearch(software, httpClient, server),
52-
users = APIUsers(software, httpClient, server),
53-
bookmark = APIBookmark(software, httpClient, server);
33+
API(this.client)
34+
: comments = APIComments(client),
35+
domains = MbinAPIDomains(client),
36+
threads = APIThreads(client),
37+
magazines = APIMagazines(client),
38+
magazineModeration = APIMagazineModeration(client),
39+
messages = APIMessages(client),
40+
moderation = APIModeration(client),
41+
notifications = APINotifications(client),
42+
microblogs = MbinAPIMicroblogs(client),
43+
search = APISearch(client),
44+
users = APIUsers(client),
45+
bookmark = APIBookmark(client);
5446
}
5547

5648
Future<ServerSoftware?> getServerSoftware(String server) async {
5749
final response = await http.get(Uri.https(server, '/nodeinfo/2.0.json'));
5850

59-
httpErrorHandler(response, message: 'Failed to load nodeinfo');
60-
6151
try {
62-
return ServerSoftware.values
63-
.byName(jsonDecode(response.body)['software']['name']);
52+
return ServerSoftware.values.byName(((response.bodyJson['software']
53+
as Map<String, Object?>)['name'] as String)
54+
.toLowerCase());
6455
} catch (_) {
6556
return null;
6657
}

lib/src/api/bookmark.dart

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
import 'dart:convert';
2-
3-
import 'package:http/http.dart' as http;
1+
import 'package:interstellar/src/api/client.dart';
42
import 'package:interstellar/src/controller/server.dart';
53
import 'package:interstellar/src/models/bookmark_list.dart';
64
import 'package:interstellar/src/models/post.dart';
75
import 'package:interstellar/src/utils/models.dart';
8-
import 'package:interstellar/src/utils/utils.dart';
96

107
enum BookmarkListSubject {
118
thread,
@@ -34,70 +31,78 @@ enum BookmarkListSubject {
3431
}
3532

3633
class APIBookmark {
37-
final ServerSoftware software;
38-
final http.Client httpClient;
39-
final String server;
34+
final ServerClient client;
4035

41-
APIBookmark(
42-
this.software,
43-
this.httpClient,
44-
this.server,
45-
);
36+
APIBookmark(this.client);
4637

4738
Future<List<BookmarkListModel>> getBookmarkLists() async {
48-
switch (software) {
39+
switch (client.software) {
4940
case ServerSoftware.mbin:
50-
const path = '/api/bookmark-lists';
51-
52-
final response = await httpClient.get(Uri.https(server, path));
41+
const path = '/bookmark-lists';
5342

54-
httpErrorHandler(response, message: 'Failed to get bookmark lists');
43+
final response = await client.get(path);
5544

56-
return BookmarkListListModel.fromMbin(
57-
jsonDecode(response.body) as Map<String, dynamic>)
58-
.items;
45+
return BookmarkListListModel.fromMbin(response.bodyJson).items;
5946

6047
case ServerSoftware.lemmy:
6148
throw Exception('Bookmark lists not on Lemmy');
49+
50+
case ServerSoftware.piefed:
51+
throw Exception('Bookmark lists not on piefed');
6252
}
6353
}
6454

6555
Future<List<String>?> addBookmarkToDefault({
6656
required BookmarkListSubject subjectType,
6757
required int subjectId,
6858
}) async {
69-
switch (software) {
59+
switch (client.software) {
7060
case ServerSoftware.mbin:
71-
final path = '/api/bos/$subjectId/${subjectType.toJson()}';
72-
73-
final response = await httpClient.put(Uri.https(server, path));
61+
final path = '/bos/$subjectId/${subjectType.toJson()}';
7462

75-
httpErrorHandler(response, message: 'Failed to add bookmark');
63+
final response = await client.put(path);
7664

77-
return optionalStringList(
78-
(jsonDecode(response.body) as Map<String, dynamic>)['bookmarks']);
65+
return optionalStringList((response.bodyJson['bookmarks']));
7966

8067
case ServerSoftware.lemmy:
8168
final path = switch (subjectType) {
82-
BookmarkListSubject.thread => '/api/v3/post/save',
83-
BookmarkListSubject.threadComment => '/api/v3/comment/save',
69+
BookmarkListSubject.thread => '/post/save',
70+
BookmarkListSubject.threadComment => '/comment/save',
8471
_ => throw Exception('Tried to bookmark microblog on Lemmy')
8572
};
8673

87-
final response = await httpClient.put(
88-
Uri.https(server, path),
89-
headers: {'Content-Type': 'application/json'},
90-
body: jsonEncode({
74+
final response = await client.put(
75+
path,
76+
body: {
9177
switch (subjectType) {
9278
BookmarkListSubject.thread => 'post_id',
9379
BookmarkListSubject.threadComment => 'comment_id',
9480
_ => throw Exception('Tried to bookmark microblog on Lemmy')
9581
}: subjectId,
9682
'save': true,
97-
}),
83+
},
9884
);
9985

100-
httpErrorHandler(response, message: 'Failed to add bookmark');
86+
return [''];
87+
88+
case ServerSoftware.piefed:
89+
final path = switch (subjectType) {
90+
BookmarkListSubject.thread => '/post/save',
91+
BookmarkListSubject.threadComment => '/comment/save',
92+
_ => throw Exception('Tried to bookmark microblog on piefed')
93+
};
94+
95+
final response = await client.put(
96+
path,
97+
body: {
98+
switch (subjectType) {
99+
BookmarkListSubject.thread => 'post_id',
100+
BookmarkListSubject.threadComment => 'comment_id',
101+
_ => throw Exception('Tried to bookmark microblog on piefed')
102+
}: subjectId,
103+
'save': true,
104+
},
105+
);
101106

102107
return [''];
103108
}
@@ -108,58 +113,73 @@ class APIBookmark {
108113
required int subjectId,
109114
required String listName,
110115
}) async {
111-
switch (software) {
116+
switch (client.software) {
112117
case ServerSoftware.mbin:
113-
final path = '/api/bol/$subjectId/${subjectType.toJson()}/$listName';
114-
115-
final response = await httpClient.put(Uri.https(server, path));
118+
final path = '/bol/$subjectId/${subjectType.toJson()}/$listName';
116119

117-
httpErrorHandler(response, message: 'Failed to add bookmark');
120+
final response = await client.put(path);
118121

119-
return optionalStringList(
120-
(jsonDecode(response.body) as Map<String, dynamic>)['bookmarks']);
122+
return optionalStringList((response.bodyJson['bookmarks']));
121123

122124
case ServerSoftware.lemmy:
123125
throw Exception('Bookmark lists not on Lemmy');
126+
127+
case ServerSoftware.piefed:
128+
throw Exception('Bookmark lists not on piefed');
124129
}
125130
}
126131

127132
Future<List<String>?> removeBookmarkFromAll({
128133
required BookmarkListSubject subjectType,
129134
required int subjectId,
130135
}) async {
131-
switch (software) {
136+
switch (client.software) {
132137
case ServerSoftware.mbin:
133-
final path = '/api/rbo/$subjectId/${subjectType.toJson()}';
134-
135-
final response = await httpClient.delete(Uri.https(server, path));
138+
final path = '/rbo/$subjectId/${subjectType.toJson()}';
136139

137-
httpErrorHandler(response, message: 'Failed to remove bookmark');
140+
final response = await client.delete(path);
138141

139-
return optionalStringList(
140-
(jsonDecode(response.body) as Map<String, dynamic>)['bookmarks']);
142+
return optionalStringList((response.bodyJson['bookmarks']));
141143

142144
case ServerSoftware.lemmy:
143145
final path = switch (subjectType) {
144-
BookmarkListSubject.thread => '/api/v3/post/save',
145-
BookmarkListSubject.threadComment => '/api/v3/comment/save',
146+
BookmarkListSubject.thread => '/post/save',
147+
BookmarkListSubject.threadComment => '/comment/save',
146148
_ => throw Exception('Tried to bookmark microblog on Lemmy')
147149
};
148150

149-
final response = await httpClient.put(
150-
Uri.https(server, path),
151-
headers: {'Content-Type': 'application/json'},
152-
body: jsonEncode({
151+
final response = await client.put(
152+
path,
153+
body: {
153154
switch (subjectType) {
154155
BookmarkListSubject.thread => 'post_id',
155156
BookmarkListSubject.threadComment => 'comment_id',
156157
_ => throw Exception('Tried to bookmark microblog on Lemmy')
157158
}: subjectId,
158159
'save': false,
159-
}),
160+
},
160161
);
161162

162-
httpErrorHandler(response, message: 'Failed to remove bookmark');
163+
return [];
164+
165+
case ServerSoftware.piefed:
166+
final path = switch (subjectType) {
167+
BookmarkListSubject.thread => '/post/save',
168+
BookmarkListSubject.threadComment => '/comment/save',
169+
_ => throw Exception('Tried to bookmark microblog on piefed')
170+
};
171+
172+
final response = await client.put(
173+
path,
174+
body: {
175+
switch (subjectType) {
176+
BookmarkListSubject.thread => 'post_id',
177+
BookmarkListSubject.threadComment => 'comment_id',
178+
_ => throw Exception('Tried to bookmark microblog on piefed')
179+
}: subjectId,
180+
'save': false,
181+
},
182+
);
163183

164184
return [];
165185
}
@@ -170,19 +190,19 @@ class APIBookmark {
170190
required int subjectId,
171191
required String listName,
172192
}) async {
173-
switch (software) {
193+
switch (client.software) {
174194
case ServerSoftware.mbin:
175-
final path = '/api/rbol/$subjectId/${subjectType.toJson()}/$listName';
176-
177-
final response = await httpClient.delete(Uri.https(server, path));
195+
final path = '/rbol/$subjectId/${subjectType.toJson()}/$listName';
178196

179-
httpErrorHandler(response, message: 'Failed to remove bookmark');
197+
final response = await client.delete(path);
180198

181-
return optionalStringList(
182-
(jsonDecode(response.body) as Map<String, dynamic>)['bookmarks']);
199+
return optionalStringList((response.bodyJson['bookmarks']));
183200

184201
case ServerSoftware.lemmy:
185202
throw Exception('Bookmark lists not on Lemmy');
203+
204+
case ServerSoftware.piefed:
205+
throw Exception('Bookmark lists not on piefed');
186206
}
187207
}
188208
}

0 commit comments

Comments
 (0)