Skip to content

Commit

Permalink
feat: preserve hashtags in post form (#464)
Browse files Browse the repository at this point in the history
* test: add test for MfmKeyboard

* refactor: split MfmKeyboard

* refactor: return Note when post

* feat: preserve hashtags

* fix: change underline color
  • Loading branch information
poppingmoon authored Nov 9, 2024
1 parent 04cfd12 commit ceff6f7
Show file tree
Hide file tree
Showing 21 changed files with 1,500 additions and 502 deletions.
19 changes: 19 additions & 0 deletions lib/extension/notes_create_request_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,23 @@ extension NotesCreateRequestExtension on NotesCreateRequest {
)
: null,
);

NotesCreateRequest addHashtags(List<String>? hashtags) {
if (hashtags case final hashtags? when hashtags.isNotEmpty) {
if (text case final text? when text.isNotEmpty) {
if (text.split('\n').last.trim().isEmpty) {
return copyWith(
text: '$text${hashtags.map((tag) => '#$tag').join(' ')}',
);
} else {
return copyWith(
text: '$text ${hashtags.map((tag) => '#$tag').join(' ')}',
);
}
} else {
return copyWith(text: hashtags.map((tag) => '#$tag').join(' '));
}
}
return this;
}
}
2 changes: 2 additions & 0 deletions lib/model/account_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ class AccountSettings with _$AccountSettings {

// PostForm
@Default([]) List<String> hashtags,
@Default(false) bool postFormUseHashtags,
@Default([]) List<String> postFormHashtags,
}) = _AccountSettings;

factory AccountSettings.fromJson(Map<String, Object?> json) =>
Expand Down
76 changes: 64 additions & 12 deletions lib/model/account_settings.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ mixin _$AccountSettings {
List<String> get recentlyUsedUsers =>
throw _privateConstructorUsedError; // PostForm
List<String> get hashtags => throw _privateConstructorUsedError;
bool get postFormUseHashtags => throw _privateConstructorUsedError;
List<String> get postFormHashtags => throw _privateConstructorUsedError;

/// Serializes this AccountSettings to a JSON map.
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
Expand Down Expand Up @@ -92,7 +94,9 @@ abstract class $AccountSettingsCopyWith<$Res> {
List<MuteWord> hardMutedWords,
List<String> mutedEmojis,
List<String> recentlyUsedUsers,
List<String> hashtags});
List<String> hashtags,
bool postFormUseHashtags,
List<String> postFormHashtags});
}

/// @nodoc
Expand Down Expand Up @@ -134,6 +138,8 @@ class _$AccountSettingsCopyWithImpl<$Res, $Val extends AccountSettings>
Object? mutedEmojis = null,
Object? recentlyUsedUsers = null,
Object? hashtags = null,
Object? postFormUseHashtags = null,
Object? postFormHashtags = null,
}) {
return _then(_value.copyWith(
keepCw: null == keepCw
Expand Down Expand Up @@ -232,6 +238,14 @@ class _$AccountSettingsCopyWithImpl<$Res, $Val extends AccountSettings>
? _value.hashtags
: hashtags // ignore: cast_nullable_to_non_nullable
as List<String>,
postFormUseHashtags: null == postFormUseHashtags
? _value.postFormUseHashtags
: postFormUseHashtags // ignore: cast_nullable_to_non_nullable
as bool,
postFormHashtags: null == postFormHashtags
? _value.postFormHashtags
: postFormHashtags // ignore: cast_nullable_to_non_nullable
as List<String>,
) as $Val);
}
}
Expand Down Expand Up @@ -268,7 +282,9 @@ abstract class _$$AccountSettingsImplCopyWith<$Res>
List<MuteWord> hardMutedWords,
List<String> mutedEmojis,
List<String> recentlyUsedUsers,
List<String> hashtags});
List<String> hashtags,
bool postFormUseHashtags,
List<String> postFormHashtags});
}

/// @nodoc
Expand Down Expand Up @@ -308,6 +324,8 @@ class __$$AccountSettingsImplCopyWithImpl<$Res>
Object? mutedEmojis = null,
Object? recentlyUsedUsers = null,
Object? hashtags = null,
Object? postFormUseHashtags = null,
Object? postFormHashtags = null,
}) {
return _then(_$AccountSettingsImpl(
keepCw: null == keepCw
Expand Down Expand Up @@ -406,6 +424,14 @@ class __$$AccountSettingsImplCopyWithImpl<$Res>
? _value._hashtags
: hashtags // ignore: cast_nullable_to_non_nullable
as List<String>,
postFormUseHashtags: null == postFormUseHashtags
? _value.postFormUseHashtags
: postFormUseHashtags // ignore: cast_nullable_to_non_nullable
as bool,
postFormHashtags: null == postFormHashtags
? _value._postFormHashtags
: postFormHashtags // ignore: cast_nullable_to_non_nullable
as List<String>,
));
}
}
Expand Down Expand Up @@ -437,15 +463,18 @@ class _$AccountSettingsImpl implements _AccountSettings {
final List<MuteWord> hardMutedWords = const [],
final List<String> mutedEmojis = const [],
final List<String> recentlyUsedUsers = const [],
final List<String> hashtags = const []})
final List<String> hashtags = const [],
this.postFormUseHashtags = false,
final List<String> postFormHashtags = const []})
: _pinnedEmojisForReaction = pinnedEmojisForReaction,
_pinnedEmojis = pinnedEmojis,
_recentlyUsedEmojis = recentlyUsedEmojis,
_mutedWords = mutedWords,
_hardMutedWords = hardMutedWords,
_mutedEmojis = mutedEmojis,
_recentlyUsedUsers = recentlyUsedUsers,
_hashtags = hashtags;
_hashtags = hashtags,
_postFormHashtags = postFormHashtags;

factory _$AccountSettingsImpl.fromJson(Map<String, dynamic> json) =>
_$$AccountSettingsImplFromJson(json);
Expand Down Expand Up @@ -580,9 +609,22 @@ class _$AccountSettingsImpl implements _AccountSettings {
return EqualUnmodifiableListView(_hashtags);
}

@override
@JsonKey()
final bool postFormUseHashtags;
final List<String> _postFormHashtags;
@override
@JsonKey()
List<String> get postFormHashtags {
if (_postFormHashtags is EqualUnmodifiableListView)
return _postFormHashtags;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_postFormHashtags);
}

@override
String toString() {
return 'AccountSettings(keepCw: $keepCw, rememberNoteVisibility: $rememberNoteVisibility, defaultNoteVisibility: $defaultNoteVisibility, defaultNoteLocalOnly: $defaultNoteLocalOnly, rememberRenoteVisibility: $rememberRenoteVisibility, defaultRenoteVisibility: $defaultRenoteVisibility, defaultRenoteLocalOnly: $defaultRenoteLocalOnly, reactionAcceptance: $reactionAcceptance, visibility: $visibility, localOnly: $localOnly, renoteVisibility: $renoteVisibility, renoteLocalOnly: $renoteLocalOnly, pinnedEmojisForReaction: $pinnedEmojisForReaction, pinnedEmojis: $pinnedEmojis, recentlyUsedEmojis: $recentlyUsedEmojis, defaultReaction: $defaultReaction, uploadFolder: $uploadFolder, keepOriginalUploading: $keepOriginalUploading, keepOriginalFilename: $keepOriginalFilename, mutedWords: $mutedWords, hardMutedWords: $hardMutedWords, mutedEmojis: $mutedEmojis, recentlyUsedUsers: $recentlyUsedUsers, hashtags: $hashtags)';
return 'AccountSettings(keepCw: $keepCw, rememberNoteVisibility: $rememberNoteVisibility, defaultNoteVisibility: $defaultNoteVisibility, defaultNoteLocalOnly: $defaultNoteLocalOnly, rememberRenoteVisibility: $rememberRenoteVisibility, defaultRenoteVisibility: $defaultRenoteVisibility, defaultRenoteLocalOnly: $defaultRenoteLocalOnly, reactionAcceptance: $reactionAcceptance, visibility: $visibility, localOnly: $localOnly, renoteVisibility: $renoteVisibility, renoteLocalOnly: $renoteLocalOnly, pinnedEmojisForReaction: $pinnedEmojisForReaction, pinnedEmojis: $pinnedEmojis, recentlyUsedEmojis: $recentlyUsedEmojis, defaultReaction: $defaultReaction, uploadFolder: $uploadFolder, keepOriginalUploading: $keepOriginalUploading, keepOriginalFilename: $keepOriginalFilename, mutedWords: $mutedWords, hardMutedWords: $hardMutedWords, mutedEmojis: $mutedEmojis, recentlyUsedUsers: $recentlyUsedUsers, hashtags: $hashtags, postFormUseHashtags: $postFormUseHashtags, postFormHashtags: $postFormHashtags)';
}

@override
Expand All @@ -597,11 +639,9 @@ class _$AccountSettingsImpl implements _AccountSettings {
other.defaultNoteVisibility == defaultNoteVisibility) &&
(identical(other.defaultNoteLocalOnly, defaultNoteLocalOnly) ||
other.defaultNoteLocalOnly == defaultNoteLocalOnly) &&
(identical(
other.rememberRenoteVisibility, rememberRenoteVisibility) ||
(identical(other.rememberRenoteVisibility, rememberRenoteVisibility) ||
other.rememberRenoteVisibility == rememberRenoteVisibility) &&
(identical(
other.defaultRenoteVisibility, defaultRenoteVisibility) ||
(identical(other.defaultRenoteVisibility, defaultRenoteVisibility) ||
other.defaultRenoteVisibility == defaultRenoteVisibility) &&
(identical(other.defaultRenoteLocalOnly, defaultRenoteLocalOnly) ||
other.defaultRenoteLocalOnly == defaultRenoteLocalOnly) &&
Expand Down Expand Up @@ -637,7 +677,11 @@ class _$AccountSettingsImpl implements _AccountSettings {
.equals(other._mutedEmojis, _mutedEmojis) &&
const DeepCollectionEquality()
.equals(other._recentlyUsedUsers, _recentlyUsedUsers) &&
const DeepCollectionEquality().equals(other._hashtags, _hashtags));
const DeepCollectionEquality().equals(other._hashtags, _hashtags) &&
(identical(other.postFormUseHashtags, postFormUseHashtags) ||
other.postFormUseHashtags == postFormUseHashtags) &&
const DeepCollectionEquality()
.equals(other._postFormHashtags, _postFormHashtags));
}

@JsonKey(includeFromJson: false, includeToJson: false)
Expand Down Expand Up @@ -667,7 +711,9 @@ class _$AccountSettingsImpl implements _AccountSettings {
const DeepCollectionEquality().hash(_hardMutedWords),
const DeepCollectionEquality().hash(_mutedEmojis),
const DeepCollectionEquality().hash(_recentlyUsedUsers),
const DeepCollectionEquality().hash(_hashtags)
const DeepCollectionEquality().hash(_hashtags),
postFormUseHashtags,
const DeepCollectionEquality().hash(_postFormHashtags)
]);

/// Create a copy of AccountSettings
Expand Down Expand Up @@ -712,7 +758,9 @@ abstract class _AccountSettings implements AccountSettings {
final List<MuteWord> hardMutedWords,
final List<String> mutedEmojis,
final List<String> recentlyUsedUsers,
final List<String> hashtags}) = _$AccountSettingsImpl;
final List<String> hashtags,
final bool postFormUseHashtags,
final List<String> postFormHashtags}) = _$AccountSettingsImpl;

factory _AccountSettings.fromJson(Map<String, dynamic> json) =
_$AccountSettingsImpl.fromJson;
Expand Down Expand Up @@ -766,6 +814,10 @@ abstract class _AccountSettings implements AccountSettings {
List<String> get recentlyUsedUsers; // PostForm
@override
List<String> get hashtags;
@override
bool get postFormUseHashtags;
@override
List<String> get postFormHashtags;

/// Create a copy of AccountSettings
/// with the given fields replaced by the non-null parameter values.
Expand Down
7 changes: 7 additions & 0 deletions lib/model/account_settings.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions lib/provider/account_settings_notifier_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,14 @@ class AccountSettingsNotifier extends _$AccountSettingsNotifier {
state = state.copyWith(hashtags: hashtags);
await _save();
}

Future<void> setPostFormUseHashtags(bool postFormUseHashtags) async {
state = state.copyWith(postFormUseHashtags: postFormUseHashtags);
await _save();
}

Future<void> setPostFormHashtags(List<String> postFormHashtags) async {
state = state.copyWith(postFormHashtags: postFormHashtags);
await _save();
}
}
2 changes: 1 addition & 1 deletion lib/provider/account_settings_notifier_provider.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions lib/provider/post_form_hashtags_notifier_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'package:collection/collection.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

import '../model/account.dart';
import 'account_settings_notifier_provider.dart';

part 'post_form_hashtags_notifier_provider.g.dart';

@Riverpod(keepAlive: true)
class PostFormHashtagsNotifier extends _$PostFormHashtagsNotifier {
@override
List<String> build(Account account) {
return ref.watch(
accountSettingsNotifierProvider(account)
.select((settings) => settings.postFormHashtags),
);
}

// ignore: use_setters_to_change_properties
void updateHashtags(List<String> hashtags) {
state = hashtags;
}

void updateFromString(String text) {
updateHashtags(
text
.split(RegExp(r'\s'))
.map((tag) => tag.trim())
.map((tag) => tag.startsWith('#') ? tag.substring(1) : tag)
.where((tag) => tag.isNotEmpty)
.toList(),
);
}

Future<void> save() async {
if (!state.equals(
ref.read(accountSettingsNotifierProvider(account)).postFormHashtags,
)) {
await ref
.read(accountSettingsNotifierProvider(account).notifier)
.setPostFormHashtags(state);
}
}
}
Loading

0 comments on commit ceff6f7

Please sign in to comment.