Skip to content

Commit

Permalink
feat: add forum for Danbooru (#291)
Browse files Browse the repository at this point in the history
  • Loading branch information
khoadng committed Jun 25, 2023
1 parent 19d068a commit 78aa8c4
Show file tree
Hide file tree
Showing 33 changed files with 1,026 additions and 34 deletions.
16 changes: 16 additions & 0 deletions lib/api/danbooru/danbooru_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -300,4 +300,20 @@ abstract class DanbooruApi {
Future<HttpResponse> deleteFavoriteGroup(
@Path() int groupId,
);

@GET('/forum_topics.json')
Future<HttpResponse> getForumTopics({
@Query('page') int? page,
@Query('search[order]') String? order,
@Query('limit') int? limit,
@Query('only') String? only,
});

@GET('/forum_posts.json')
Future<HttpResponse> getForumPosts({
@Query('page') String? page,
@Query('search[topic_id]') int? topicId,
@Query('limit') int? limit,
@Query('only') String? only,
});
}
52 changes: 52 additions & 0 deletions lib/boorus/core/feats/dtext/bbcode.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
part of 'dtext_grammar.dart';

Parser taggedElement(String tag) => (string('[$tag') &
ref0(attribute).optional() &
string(']') &
(string('[/$tag]').not() & any()).star().flatten() &
string('[/$tag]'))
.map((value) => BBCode(tag, value[3], value[1]));

Parser attribute() => (char('=') & (char(']').not() & any()).star().flatten())
.map((value) => value[1]);

Parser bbcode() =>
ref1(taggedElement, 'b') |
ref1(taggedElement, 'i') |
ref1(taggedElement, 'u') |
ref1(taggedElement, 's') |
ref1(taggedElement, 'spoiler') |
ref1(taggedElement, 'expand') |
ref1(taggedElement, 'quote');

enum BBCodeTagType {
bold,
italic,
underline,
strikethrough,
spoiler,
expand,
quote,
}

class BBCode {
BBCode(
this.tag,
this.text,
this.attributes,
);
final String tag;
final String text;
final String? attributes;

BBCodeTagType get type => switch (tag) {
'b' => BBCodeTagType.bold,
'i' => BBCodeTagType.italic,
'u' => BBCodeTagType.underline,
's' => BBCodeTagType.strikethrough,
'spoiler' => BBCodeTagType.spoiler,
'expand' => BBCodeTagType.expand,
'quote' => BBCodeTagType.quote,
_ => throw Exception('Unknown tag type: $tag')
};
}
7 changes: 7 additions & 0 deletions lib/boorus/core/feats/dtext/common.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
part of 'dtext_grammar.dart';

Parser url() =>
char('<').optional() &
(string('http://') | string('https://')) &
pattern('a-zA-Z0-9./-_,?=&;%:+').plus().flatten() &
char('>').optional();
33 changes: 33 additions & 0 deletions lib/boorus/core/feats/dtext/dtext_grammar.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Package imports:
import 'package:petitparser/petitparser.dart';

part 'common.dart';
part 'link.dart';
part 'bbcode.dart';
part 'line_break.dart';

class DTextGrammarDefinition extends GrammarDefinition {
DTextGrammarDefinition({
required this.tagSearchUrl,
});

final String tagSearchUrl;

@override
Parser start() => ref0(document);

Parser document() => (ref0(bbcode) |
ref0(link) |
ref1(internalLink, tagSearchUrl) |
ref0(lineBreak) |
ref0(normalText))
.star();

Parser normalText() => (ref0(bbcode).not() &
ref0(lineBreak).not() &
ref1(internalLink, tagSearchUrl).not() &
ref0(link).not() &
any())
.plus()
.flatten();
}
46 changes: 46 additions & 0 deletions lib/boorus/core/feats/dtext/html_converter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Project imports:
import 'package:boorusama/boorus/core/feats/boorus/boorus.dart';
import 'dtext_grammar.dart';

String dtext(
String value, {
required Booru booru,
}) {
final tagSearchUrl = '${booru.url}/posts?tags=';
final result =
DTextGrammarDefinition(tagSearchUrl: tagSearchUrl).build().parse(value);
return result.isSuccess ? grammarToHtmlString(result.value) : value;
}

String grammarToHtmlString(List<dynamic> value) {
final buffer = StringBuffer();
for (final element in value) {
final data = mapDataToString(element);
buffer.write(data);
}
return buffer.toString();
}

String mapDataToString(dynamic data) => switch (data) {
BBCode c => parseBBcodeToHtml(c),
LineBreakElement => '<br>',
UrlElement url => parseUrl(url),
String => data,
_ => data.toString(),
};

String parseUrl(UrlElement url) {
final displayText = url.displayText ?? url.url;
return '<a href="${url.url}">$displayText</a>';
}

String parseBBcodeToHtml(BBCode text) => switch (text.tag) {
'b' => '<b>${text.text}</b>',
'i' => '<i>${text.text}</i>',
'u' => '<u>${text.text}</u>',
's' => '<s>${text.text}</s>',
'expand' =>
'<details><summary>${text.attributes ?? 'Show'}</summary>${text.text}</details>',
'quote' => '<blockquote>${text.text}</blockquote>',
_ => text.text
};
7 changes: 7 additions & 0 deletions lib/boorus/core/feats/dtext/line_break.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
part of 'dtext_grammar.dart';

Parser lineBreak() => string(r'\r\n').map((value) => const LineBreakElement());

class LineBreakElement {
const LineBreakElement();
}
45 changes: 45 additions & 0 deletions lib/boorus/core/feats/dtext/link.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
part of 'dtext_grammar.dart';

Parser link() =>
ref0(urlRawLink) | ref0(customTextLink) | ref0(markdownStyleLink);

Parser internalLink(String baseUrl) =>
ref1(tagSearchLink, baseUrl) | ref1(wikiLink, baseUrl);

Parser urlRawLink() => url().flatten().map((value) => UrlElement(value));
Parser markdownStyleLink() => (char('[') &
pattern('^]').star().flatten() &
char(']') &
char('(') &
ref0(url).flatten() &
char(')'))
.map((value) => UrlElement(value[1], displayText: value[3]));

Parser customTextLink() => (char('"') &
pattern('^"').star().flatten() &
char('"') &
char(':') &
char('[') &
ref0(url).flatten() &
char(']'))
.map((value) => UrlElement(value[5], displayText: value[1]));

Parser tagSearchLink(String searchUrl) => (string('{{') &
pattern('^}').star().flatten() &
string('}}'))
.map((value) => UrlElement('$searchUrl${value[1]}', displayText: value[1]));

Parser wikiLink(String wikiUrl) => (string('[[') &
pattern('^]').star().flatten() &
string(']]'))
.map((value) => UrlElement('$wikiUrl${value[1]}', displayText: value[1]));

class UrlElement {
final String url;
final String? displayText;

UrlElement(this.url, {this.displayText});

@override
String toString() => 'UrlElement{url: $url, displayText: $displayText}';
}
26 changes: 6 additions & 20 deletions lib/boorus/core/widgets/posts/information_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:boorusama/dart.dart';
import 'package:boorusama/flutter.dart';
import 'package:boorusama/foundation/theme/theme_mode.dart';
import 'package:boorusama/functional.dart';
import 'package:boorusama/widgets/compact_chip.dart';
import 'package:boorusama/widgets/widgets.dart';

class InformationSection extends StatelessWidget {
Expand Down Expand Up @@ -79,29 +80,14 @@ class InformationSection extends StatelessWidget {
Flexible(
child: artistTags.firstOrNull.toOption().fold(
() => const SizedBox.shrink(),
(artist) => Material(
borderRadius: BorderRadius.circular(6),
color: getTagColor(
(artist) => CompactChip(
label: artist.removeUnderscoreWithSpace(),
onTap: () =>
onArtistTagTap?.call(context, artist),
backgroundColor: getTagColor(
TagCategory.artist,
ThemeMode.amoledDark,
),
child: InkWell(
borderRadius: BorderRadius.circular(6),
onTap: () =>
onArtistTagTap?.call(context, artist),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 2,
horizontal: 4,
),
child: Text(
artist.removeUnderscoreWithSpace(),
style: const TextStyle(
fontWeight: FontWeight.w600,
),
),
),
),
),
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Project imports:
import 'package:boorusama/boorus/danbooru/feats/favorites/favorites.dart';
import 'package:boorusama/boorus/danbooru/feats/users/users.dart';

class FavoriteGroupDto {
FavoriteGroupDto({
Expand Down
2 changes: 0 additions & 2 deletions lib/boorus/danbooru/feats/favorites/favorites.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ export 'app/favorite_groups_provider.dart';
export 'app/favorites_notifier.dart';
export 'app/favorites_provider.dart';
export 'app/favorite_utils.dart';
export 'data/creator_dto.dart';
export 'data/favorite_dto.dart';
export 'data/favorite_group_dto.dart';
export 'data/favorite_group_repository.dart';
export 'data/favorite_post_repository_api.dart';
export 'models/creator.dart';
export 'models/favorite.dart';
export 'models/favorite_group.dart';
export 'models/favorite_group_repository.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import 'package:equatable/equatable.dart';

// Project imports:
import 'package:boorusama/boorus/danbooru/feats/favorites/models/creator.dart';
import 'package:boorusama/boorus/danbooru/feats/users/creator.dart';

class FavoriteGroup extends Equatable {
const FavoriteGroup({
Expand Down
40 changes: 40 additions & 0 deletions lib/boorus/danbooru/feats/forums/danbooru_forum_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Package imports:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_infinite_scroll/riverpod_infinite_scroll.dart';

// Project imports:
import 'package:boorusama/boorus/danbooru/danbooru_provider.dart';
import 'package:boorusama/boorus/danbooru/feats/forums/forums.dart';
import 'package:boorusama/boorus/danbooru/feats/forums/posts/danbooru_forum_post_repository.dart';
import 'package:boorusama/boorus/danbooru/feats/forums/posts/danbooru_forum_posts_notifier.dart';

final danbooruForumTopicRepoProvider =
Provider<DanbooruForumTopicRepository>((ref) {
return DanbooruForumTopicRepositoryApi(
api: ref.watch(danbooruApiProvider),
);
});

final danbooruForumTopicsProvider = StateNotifierProvider.autoDispose<
DanbooruForumTopicsNotifier, PagedState<int, DanbooruForumTopic>>((ref) {
return DanbooruForumTopicsNotifier(
repo: ref.watch(danbooruForumTopicRepoProvider),
);
});

final danbooruForumPostRepoProvider =
Provider<DanbooruForumPostRepository>((ref) {
return DanbooruForumPostRepositoryApi(
api: ref.watch(danbooruApiProvider),
);
});

final danbooruForumPostsProvider = StateNotifierProvider.autoDispose.family<
DanbooruForumPostsNotifier,
PagedState<int, DanbooruForumPost>,
int>((ref, topicId) {
return DanbooruForumPostsNotifier(
topicId: topicId,
repo: ref.watch(danbooruForumPostRepoProvider),
);
});
7 changes: 7 additions & 0 deletions lib/boorus/danbooru/feats/forums/forums.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export 'danbooru_forum_provider.dart';
export 'posts/danbooru_forum_post.dart';
export 'posts/danbooru_forum_post_dto.dart';
export 'topics/danbooru_forum_topic.dart';
export 'topics/danbooru_forum_topic_dto.dart';
export 'topics/danbooru_forum_topic_repository.dart';
export 'topics/danbooru_forum_topics_notifier.dart';
Loading

0 comments on commit 78aa8c4

Please sign in to comment.