mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-30 11:33:34 +08:00
InlineTags: Add settings page
And support multiple prefixes. This is disabled for now as it hasn't been fully integrated.
This commit is contained in:
@ -90,6 +90,11 @@ settings:
|
|||||||
remoteSync:
|
remoteSync:
|
||||||
auto: Automatic
|
auto: Automatic
|
||||||
manual: Manual
|
manual: Manual
|
||||||
|
tags:
|
||||||
|
title: Tags Settings
|
||||||
|
subtitle: Configure how inline tags are parsed
|
||||||
|
enable: Parse Inline Tags
|
||||||
|
prefixes: Inline Tags Prefixes
|
||||||
|
|
||||||
editors:
|
editors:
|
||||||
checklist:
|
checklist:
|
||||||
|
@ -1,16 +1,21 @@
|
|||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:meta/meta.dart';
|
||||||
|
|
||||||
class InlineTagsProcessor {
|
class InlineTagsProcessor {
|
||||||
// FIXME: Make me configurable
|
final Set<String> tagPrefixes;
|
||||||
final List<String> tagPrefixes = ['#'];
|
|
||||||
|
|
||||||
void process(Note note) {}
|
InlineTagsProcessor({@required this.tagPrefixes});
|
||||||
|
|
||||||
Set<String> extractTags(String text) {
|
Set<String> extractTags(String text) {
|
||||||
var tags = <String>{};
|
var tags = <String>{};
|
||||||
|
|
||||||
for (var prefix in tagPrefixes) {
|
for (var prefix in tagPrefixes) {
|
||||||
var regexp = RegExp(r'(^|\s)' + prefix + r'([^ ]+)(\s|$)');
|
// FIXME: Do not hardcode this
|
||||||
|
var p = prefix;
|
||||||
|
if (p == '+') {
|
||||||
|
p = '\\+';
|
||||||
|
}
|
||||||
|
|
||||||
|
var regexp = RegExp(r'(^|\s)' + p + r'([^ ]+)(\s|$)');
|
||||||
var matches = regexp.allMatches(text);
|
var matches = regexp.allMatches(text);
|
||||||
for (var match in matches) {
|
for (var match in matches) {
|
||||||
var tag = match.group(2);
|
var tag = match.group(2);
|
||||||
@ -19,7 +24,7 @@ class InlineTagsProcessor {
|
|||||||
tag = tag.substring(0, tag.length - 1);
|
tag = tag.substring(0, tag.length - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var all = tag.split('#');
|
var all = tag.split(prefix);
|
||||||
for (var t in all) {
|
for (var t in all) {
|
||||||
tags.add(t.trim());
|
tags.add(t.trim());
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
|
|
||||||
class Features {
|
class Features {
|
||||||
static bool perFolderConfig = false;
|
static bool perFolderConfig = false;
|
||||||
|
static bool inlineTags = false;
|
||||||
|
|
||||||
static final all = <Feature>[
|
static final all = <Feature>[
|
||||||
Feature.basicSearch,
|
Feature.basicSearch,
|
||||||
|
@ -14,6 +14,7 @@ import 'package:gitjournal/screens/settings_experimental.dart';
|
|||||||
import 'package:gitjournal/screens/settings_git_remote.dart';
|
import 'package:gitjournal/screens/settings_git_remote.dart';
|
||||||
import 'package:gitjournal/screens/settings_images.dart';
|
import 'package:gitjournal/screens/settings_images.dart';
|
||||||
import 'package:gitjournal/screens/settings_note_metadata.dart';
|
import 'package:gitjournal/screens/settings_note_metadata.dart';
|
||||||
|
import 'package:gitjournal/screens/settings_tags.dart';
|
||||||
import 'package:gitjournal/screens/settings_widgets.dart';
|
import 'package:gitjournal/screens/settings_widgets.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:gitjournal/state_container.dart';
|
import 'package:gitjournal/state_container.dart';
|
||||||
@ -241,6 +242,18 @@ class SettingsListState extends State<SettingsList> {
|
|||||||
Navigator.of(context).push(route);
|
Navigator.of(context).push(route);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
if (Features.inlineTags)
|
||||||
|
ListTile(
|
||||||
|
title: Text(tr("settings.tags.title")),
|
||||||
|
subtitle: Text(tr("settings.tags.subtitle")),
|
||||||
|
onTap: () {
|
||||||
|
var route = MaterialPageRoute(
|
||||||
|
builder: (context) => SettingsTagsScreen(),
|
||||||
|
settings: const RouteSettings(name: '/settings/tags'),
|
||||||
|
);
|
||||||
|
Navigator.of(context).push(route);
|
||||||
|
},
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(tr('settings.images.title')),
|
title: Text(tr('settings.images.title')),
|
||||||
subtitle: Text(tr('settings.images.subtitle')),
|
subtitle: Text(tr('settings.images.subtitle')),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@ -66,6 +67,8 @@ class Settings extends ChangeNotifier {
|
|||||||
bool zenMode = false;
|
bool zenMode = false;
|
||||||
bool saveTitleInH1 = true;
|
bool saveTitleInH1 = true;
|
||||||
|
|
||||||
|
Set<String> inlineTagPrefixes = {'#'};
|
||||||
|
|
||||||
void load(SharedPreferences pref) {
|
void load(SharedPreferences pref) {
|
||||||
onBoardingCompleted = pref.getBool("onBoardingCompleted") ?? false;
|
onBoardingCompleted = pref.getBool("onBoardingCompleted") ?? false;
|
||||||
|
|
||||||
@ -142,6 +145,8 @@ class Settings extends ChangeNotifier {
|
|||||||
|
|
||||||
zenMode = pref.getBool("zenMode") ?? zenMode;
|
zenMode = pref.getBool("zenMode") ?? zenMode;
|
||||||
saveTitleInH1 = pref.getBool("saveTitleInH1") ?? saveTitleInH1;
|
saveTitleInH1 = pref.getBool("saveTitleInH1") ?? saveTitleInH1;
|
||||||
|
inlineTagPrefixes =
|
||||||
|
pref.getStringList("inlineTagPrefixes")?.toSet() ?? inlineTagPrefixes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future save() async {
|
Future save() async {
|
||||||
@ -220,6 +225,8 @@ class Settings extends ChangeNotifier {
|
|||||||
defaultSet.experimentalMarkdownToolbar);
|
defaultSet.experimentalMarkdownToolbar);
|
||||||
_setBool(pref, "zenMode", zenMode, defaultSet.zenMode);
|
_setBool(pref, "zenMode", zenMode, defaultSet.zenMode);
|
||||||
_setBool(pref, "saveTitleInH1", saveTitleInH1, defaultSet.saveTitleInH1);
|
_setBool(pref, "saveTitleInH1", saveTitleInH1, defaultSet.saveTitleInH1);
|
||||||
|
_setStringSet(pref, "inlineTagPrefixes", inlineTagPrefixes,
|
||||||
|
defaultSet.inlineTagPrefixes);
|
||||||
|
|
||||||
pref.setInt("settingsVersion", version);
|
pref.setInt("settingsVersion", version);
|
||||||
|
|
||||||
@ -252,6 +259,21 @@ class Settings extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _setStringSet(
|
||||||
|
SharedPreferences pref,
|
||||||
|
String key,
|
||||||
|
Set<String> value,
|
||||||
|
Set<String> defaultValue,
|
||||||
|
) async {
|
||||||
|
final eq = const SetEquality().equals;
|
||||||
|
|
||||||
|
if (eq(value, defaultValue)) {
|
||||||
|
await pref.remove(key);
|
||||||
|
} else {
|
||||||
|
await pref.setStringList(key, value.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Map<String, String> toMap() {
|
Map<String, String> toMap() {
|
||||||
return <String, String>{
|
return <String, String>{
|
||||||
"onBoardingCompleted": onBoardingCompleted.toString(),
|
"onBoardingCompleted": onBoardingCompleted.toString(),
|
||||||
@ -289,6 +311,7 @@ class Settings extends ChangeNotifier {
|
|||||||
'experimentalMarkdownToolbar': experimentalMarkdownToolbar.toString(),
|
'experimentalMarkdownToolbar': experimentalMarkdownToolbar.toString(),
|
||||||
'zenMode': zenMode.toString(),
|
'zenMode': zenMode.toString(),
|
||||||
'saveTitleInH1': saveTitleInH1.toString(),
|
'saveTitleInH1': saveTitleInH1.toString(),
|
||||||
|
'inlineTagPrefixes': inlineTagPrefixes.join(' '),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ void main() {
|
|||||||
test('Should parse simple tags', () {
|
test('Should parse simple tags', () {
|
||||||
var body = "#hello Hi\nthere how#are you #doing now? #dog";
|
var body = "#hello Hi\nthere how#are you #doing now? #dog";
|
||||||
|
|
||||||
var p = InlineTagsProcessor();
|
var p = InlineTagsProcessor(tagPrefixes: {'#'});
|
||||||
var tags = p.extractTags(body);
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
expect(tags, {'hello', 'doing', 'dog'});
|
expect(tags, {'hello', 'doing', 'dog'});
|
||||||
@ -15,7 +15,7 @@ void main() {
|
|||||||
test('Ignore . at the end of a tag', () {
|
test('Ignore . at the end of a tag', () {
|
||||||
var body = "Hi there #tag.";
|
var body = "Hi there #tag.";
|
||||||
|
|
||||||
var p = InlineTagsProcessor();
|
var p = InlineTagsProcessor(tagPrefixes: {'#'});
|
||||||
var tags = p.extractTags(body);
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
expect(tags, {'tag'});
|
expect(tags, {'tag'});
|
||||||
@ -24,7 +24,7 @@ void main() {
|
|||||||
test('#a#b should be counted as two tags', () {
|
test('#a#b should be counted as two tags', () {
|
||||||
var body = "Hi there #a#b";
|
var body = "Hi there #a#b";
|
||||||
|
|
||||||
var p = InlineTagsProcessor();
|
var p = InlineTagsProcessor(tagPrefixes: {'#'});
|
||||||
var tags = p.extractTags(body);
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
expect(tags, {'a', 'b'});
|
expect(tags, {'a', 'b'});
|
||||||
@ -33,7 +33,7 @@ void main() {
|
|||||||
test('Non Ascii tags', () {
|
test('Non Ascii tags', () {
|
||||||
var body = "Hi #fíre gone";
|
var body = "Hi #fíre gone";
|
||||||
|
|
||||||
var p = InlineTagsProcessor();
|
var p = InlineTagsProcessor(tagPrefixes: {'#'});
|
||||||
var tags = p.extractTags(body);
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
expect(tags, {'fíre'});
|
expect(tags, {'fíre'});
|
||||||
@ -42,12 +42,18 @@ void main() {
|
|||||||
test('Tags with a -', () {
|
test('Tags with a -', () {
|
||||||
var body = "Hi #future-me. How are you?";
|
var body = "Hi #future-me. How are you?";
|
||||||
|
|
||||||
var p = InlineTagsProcessor();
|
var p = InlineTagsProcessor(tagPrefixes: {'#'});
|
||||||
var tags = p.extractTags(body);
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
expect(tags, {'future-me'});
|
expect(tags, {'future-me'});
|
||||||
});
|
});
|
||||||
|
|
||||||
// + should work as a prefix
|
test('Multiple Prefixes', () {
|
||||||
// @ should work as a prefix
|
var body = "Hi +one+two @foo #doo";
|
||||||
|
|
||||||
|
var p = InlineTagsProcessor(tagPrefixes: {'#', '+', '@'});
|
||||||
|
var tags = p.extractTags(body);
|
||||||
|
|
||||||
|
expect(tags, {'one', 'two', 'foo', 'doo'});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user