Skip to content

Commit 640cd19

Browse files
committed
feat: add support to write a content warning for posts
1 parent d44f41f commit 640cd19

File tree

7 files changed

+41
-12
lines changed

7 files changed

+41
-12
lines changed

lib/data/status.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ class Status {
5353
// Status visibility
5454
final StatusVisibility visibility;
5555

56+
// Spoiler text (content warning)
57+
final String spoilerText;
58+
5659
Status({
5760
required this.id,
5861
required this.createdAt,
@@ -65,6 +68,7 @@ class Status {
6568
required this.reblogsCount,
6669
required this.repliesCount,
6770
required this.visibility,
71+
required this.spoilerText,
6872
this.reblog,
6973
});
7074

@@ -83,6 +87,7 @@ class Status {
8387
reblogsCount: data["reblogs_count"]!,
8488
repliesCount: data["replies_count"]!,
8589
visibility: StatusVisibility.values.byName(data["visibility"]!),
90+
spoilerText: data["spoiler_text"]!,
8691
reblog: data["reblog"] == null ? null : Status.fromJson(data["reblog"]),
8792
);
8893
}

lib/services/api.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -272,12 +272,15 @@ class ApiService {
272272
/// on the user's timeline. Returns the (new) [Status] instance the API
273273
/// responds with.
274274
Future<Status> postStatus(String content,
275-
{Status? replyToStatus, StatusVisibility? visibility}) async {
275+
{Status? replyToStatus,
276+
StatusVisibility visibility = StatusVisibility.public,
277+
String spoilerText = ""}) async {
276278
final apiUrl = "${instanceUrl!}/api/v1/statuses";
277279
// TODO: Support sensitivity, language, scheduling, polls and media
278280
Map<String, String> body = {
279281
"status": content,
280-
"visibility": (visibility ?? StatusVisibility.public).name,
282+
"visibility": visibility.name,
283+
"spoiler_text": spoilerText,
281284
};
282285
if (replyToStatus != null) {
283286
body["in_reply_to_id"] = replyToStatus.id;

lib/widgets/status_form.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ class StatusFormState extends State<StatusForm> {
7272
/// value set on the input field on this class.
7373
final statusController = TextEditingController();
7474

75+
/// Controller for the `spoilerText` text field, to preserve and access the
76+
/// value set on the input field on this class.
77+
final spoilerTextController = TextEditingController();
78+
7579
/// Selected visibility for the status.
7680
StatusVisibility selectedVisibility = StatusVisibility.public;
7781

@@ -128,6 +132,13 @@ class StatusFormState extends State<StatusForm> {
128132
});
129133
},
130134
),
135+
TextFormField(
136+
keyboardType: TextInputType.text,
137+
decoration: InputDecoration(
138+
helperText: "Content warning (optional)",
139+
),
140+
controller: spoilerTextController,
141+
),
131142
FeathrActionButton(
132143
onPressed: () async {
133144
if (_formKey.currentState!.validate()) {
@@ -140,6 +151,7 @@ class StatusFormState extends State<StatusForm> {
140151
statusController.text,
141152
replyToStatus: widget.replyToStatus,
142153
visibility: selectedVisibility,
154+
spoilerText: spoilerTextController.text,
143155
);
144156
} catch (e) {
145157
// Show an error message if the status couldn't be posted

test/data_test/status_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void main() {
1414
"favourites_count": 1,
1515
"reblogs_count": 0,
1616
"replies_count": 0,
17+
"spoiler_text": "",
1718
"account": {
1819
"id": "this is an id",
1920
"username": "username123",
@@ -38,6 +39,7 @@ void main() {
3839
"favourites_count": 1,
3940
"reblogs_count": 0,
4041
"replies_count": 0,
42+
"spoiler_text": "",
4143
"account": {
4244
"id": "this is an id",
4345
"username": "username123",
@@ -59,6 +61,7 @@ void main() {
5961
"favourites_count": 1,
6062
"replies_count": 0,
6163
"reblogs_count": 0,
64+
"spoiler_text": "",
6265
"account": {
6366
"id": "this is another id",
6467
"username": "username456",

test/services_test/api_test.dart

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void main() {
115115
httpClient: mockClient))
116116
.thenAnswer(
117117
(_) async => http.Response(
118-
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
118+
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
119119
200,
120120
),
121121
);
@@ -186,7 +186,7 @@ void main() {
186186
httpClient: mockClient))
187187
.thenAnswer(
188188
(_) async => http.Response(
189-
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"private","content":"<p>I am a toot!</p>","favourited":false,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
189+
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"private","content":"<p>I am a toot!</p>","favourited":false,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
190190
200,
191191
),
192192
);
@@ -254,7 +254,7 @@ void main() {
254254
httpClient: mockClient))
255255
.thenAnswer(
256256
(_) async => http.Response(
257-
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"unlisted","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
257+
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"unlisted","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
258258
200,
259259
),
260260
);
@@ -322,7 +322,7 @@ void main() {
322322
httpClient: mockClient))
323323
.thenAnswer(
324324
(_) async => http.Response(
325-
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":false,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
325+
'{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":false,"bookmarked":false,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}',
326326
200,
327327
),
328328
);
@@ -386,7 +386,7 @@ void main() {
386386
httpClient: mockClient))
387387
.thenAnswer(
388388
(_) async => http.Response(
389-
'{"reblog":{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}}',
389+
'{"reblog":{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}}',
390390
200,
391391
),
392392
);
@@ -453,7 +453,7 @@ void main() {
453453
httpClient: mockClient))
454454
.thenAnswer(
455455
(_) async => http.Response(
456-
'{"reblog":{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}}',
456+
'{"reblog":{"id":"$testStatusId","created_at": "2025-01-01T00:00:00Z","visibility":"public","content":"<p>I am a toot!</p>","favourited":true,"bookmarked":true,"reblogged":true,"favourites_count":1,"reblogs_count":3,"replies_count":2,"spoiler_text":"","account":{"id":"this is an id","username":"username123","acct":"username123","display_name":"user display name","locked":false,"bot":true,"avatar":"avatar-url","header":"header-url"}}}',
457457
200,
458458
),
459459
);
@@ -698,7 +698,7 @@ void main() {
698698
httpClient: mockClient,
699699
)).thenAnswer(
700700
(_) async => http.Response(
701-
'[{"id": "1", "created_at": "2025-01-01T00:00:00Z", "visibility": "public", "content": "<p>Status 1</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "account": {"id": "account1", "username": "user1", "acct": "user1", "display_name": "User One", "locked": false, "bot": false, "avatar": "avatar1-url", "header": "header1-url"}}, {"id": "2", "created_at": "2025-01-02T00:00:00Z", "visibility": "public", "content": "<p>Status 2</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "account": {"id": "account2", "username": "user2", "acct": "user2", "display_name": "User Two", "locked": false, "bot": false, "avatar": "avatar2-url", "header": "header2-url"}}]',
701+
'[{"id": "1", "created_at": "2025-01-01T00:00:00Z", "visibility": "public", "content": "<p>Status 1</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "spoiler_text": "", "account": {"id": "account1", "username": "user1", "acct": "user1", "display_name": "User One", "locked": false, "bot": false, "avatar": "avatar1-url", "header": "header1-url"}}, {"id": "2", "created_at": "2025-01-02T00:00:00Z", "visibility": "public", "content": "<p>Status 2</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "spoiler_text": "", "account": {"id": "account2", "username": "user2", "acct": "user2", "display_name": "User Two", "locked": false, "bot": false, "avatar": "avatar2-url", "header": "header2-url"}}]',
702702
200,
703703
),
704704
);
@@ -728,11 +728,15 @@ void main() {
728728

729729
when(mockHelper.post(
730730
"https://example.org/api/v1/statuses",
731-
body: {"status": "Hello, world!", "visibility": "public"},
731+
body: {
732+
"status": "Hello, world!",
733+
"visibility": "public",
734+
"spoiler_text": ""
735+
},
732736
httpClient: mockClient,
733737
)).thenAnswer(
734738
(_) async => http.Response(
735-
'{"id": "1", "created_at": "2025-01-01T00:00:00Z", "visibility": "public", "content": "<p>Hello, world!</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "account": {"id": "account1", "username": "user1", "acct": "user1", "display_name": "User One", "locked": false, "bot": false, "avatar": "avatar1-url", "header": "header1-url"}}',
739+
'{"id": "1", "created_at": "2025-01-01T00:00:00Z", "visibility": "public", "content": "<p>Hello, world!</p>", "favourited": false, "bookmarked": false, "reblogged": false, "favourites_count": 0, "reblogs_count": 0, "replies_count": 2, "spoiler_text": "", "account": {"id": "account1", "username": "user1", "acct": "user1", "display_name": "User One", "locked": false, "bot": false, "avatar": "avatar1-url", "header": "header1-url"}}',
736740
200,
737741
),
738742
);

test/widgets_test/status_card_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ void main() {
2424
favouritesCount: 10,
2525
reblogsCount: 5,
2626
repliesCount: 2,
27-
visibility: StatusVisibility.public);
27+
visibility: StatusVisibility.public,
28+
spoilerText: "");
2829

2930
await tester.pumpWidget(
3031
MaterialApp(

test/widgets_test/status_form_test.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ void main() {
2828
expect(find.text('What\'s on your mind?'), findsOneWidget);
2929
expect(find.text('Post'), findsOneWidget);
3030
expect(find.text('This field should not be empty'), findsNothing);
31+
expect(find.text('Content warning (optional)'), findsOneWidget);
3132

3233
// Attempting to post without a value
3334
await tester.tap(find.text('Post'));

0 commit comments

Comments
 (0)