mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-28 18:03:14 +08:00
Show the backlinks of a Note
This is the initial proof of concept and doesn't look very pretty. It's also not very efficient. Related to #141
This commit is contained in:
@ -437,6 +437,11 @@ class Link {
|
|||||||
other is Note &&
|
other is Note &&
|
||||||
runtimeType == other.runtimeType &&
|
runtimeType == other.runtimeType &&
|
||||||
filePath == other.filePath;
|
filePath == other.filePath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Link{term: $term, filePath: $filePath}';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinkExtractor implements md.NodeVisitor {
|
class LinkExtractor implements md.NodeVisitor {
|
||||||
|
@ -458,8 +458,33 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
|||||||
Set<String> getNoteTagsRecursively() {
|
Set<String> getNoteTagsRecursively() {
|
||||||
return _fetchTags(this, {});
|
return _fetchTags(this, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Note>> matchNotes(NoteMatcherAsync pred) async {
|
||||||
|
var matchedNotes = <Note>[];
|
||||||
|
await _matchNotes(matchedNotes, pred);
|
||||||
|
return matchedNotes;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<Note>> _matchNotes(
|
||||||
|
List<Note> matchedNotes,
|
||||||
|
NoteMatcherAsync pred,
|
||||||
|
) async {
|
||||||
|
for (var note in _notes) {
|
||||||
|
var matches = await pred(note);
|
||||||
|
if (matches) {
|
||||||
|
matchedNotes.add(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var folder in _folders) {
|
||||||
|
await folder._matchNotes(matchedNotes, pred);
|
||||||
|
}
|
||||||
|
return matchedNotes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef NoteMatcherAsync = Future<bool> Function(Note n);
|
||||||
|
|
||||||
Set<String> _fetchTags(NotesFolder folder, Set<String> tags) {
|
Set<String> _fetchTags(NotesFolder folder, Set<String> tags) {
|
||||||
for (var note in folder.notes) {
|
for (var note in folder.notes) {
|
||||||
tags.addAll(note.tags);
|
tags.addAll(note.tags);
|
||||||
|
@ -47,6 +47,7 @@ class NoteViewer extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final rootFolder = Provider.of<NotesFolderFS>(context);
|
||||||
var view = EditorScrollView(
|
var view = EditorScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
@ -58,7 +59,6 @@ class NoteViewer extends StatelessWidget {
|
|||||||
styleSheet: markdownStyleSheet,
|
styleSheet: markdownStyleSheet,
|
||||||
onTapLink: (String link) {
|
onTapLink: (String link) {
|
||||||
if (link.startsWith('./')) {
|
if (link.startsWith('./')) {
|
||||||
final rootFolder = Provider.of<NotesFolderFS>(context);
|
|
||||||
var spec = link.substring(2);
|
var spec = link.substring(2);
|
||||||
var note = rootFolder.getNoteWithSpec(spec);
|
var note = rootFolder.getNoteWithSpec(spec);
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
@ -75,6 +75,7 @@ class NoteViewer extends StatelessWidget {
|
|||||||
url, note.parent.folderPath + p.separator, null, null),
|
url, note.parent.folderPath + p.separator, null, null),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
NoteBacklinkRenderer(note: note, rootFolder: rootFolder),
|
||||||
// _buildFooter(context),
|
// _buildFooter(context),
|
||||||
],
|
],
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -181,3 +182,86 @@ Widget _handleDataSchemeUri(Uri uri, final double width, final double height) {
|
|||||||
}
|
}
|
||||||
return const SizedBox();
|
return const SizedBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class NoteBacklinkRenderer extends StatefulWidget {
|
||||||
|
final Note note;
|
||||||
|
final NotesFolderFS rootFolder;
|
||||||
|
|
||||||
|
NoteBacklinkRenderer({
|
||||||
|
@required this.note,
|
||||||
|
@required this.rootFolder,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
_NoteBacklinkRendererState createState() => _NoteBacklinkRendererState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NoteBacklinkRendererState extends State<NoteBacklinkRenderer> {
|
||||||
|
List<Note> linkedNotes = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
_initStateAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _initStateAsync() async {
|
||||||
|
var predicate = (Note n) async {
|
||||||
|
var links = await n.fetchLinks();
|
||||||
|
var matchedLink = links.firstWhere(
|
||||||
|
(l) => l.filePath == widget.note.filePath,
|
||||||
|
orElse: () => null,
|
||||||
|
);
|
||||||
|
return matchedLink != null;
|
||||||
|
};
|
||||||
|
|
||||||
|
var l = await widget.rootFolder.matchNotes(predicate);
|
||||||
|
if (!mounted) return;
|
||||||
|
setState(() {
|
||||||
|
linkedNotes = l;
|
||||||
|
print("linkedNote $linkedNotes");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (linkedNotes.isEmpty) {
|
||||||
|
return Container();
|
||||||
|
}
|
||||||
|
|
||||||
|
var textTheme = Theme.of(context).textTheme;
|
||||||
|
var c = Column(
|
||||||
|
children: <Widget>[
|
||||||
|
Text('BackLinks', style: textTheme.headline5),
|
||||||
|
const SizedBox(height: 8.0),
|
||||||
|
for (var n in linkedNotes) _buildNoteLink(n),
|
||||||
|
],
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0.0, 16.0, 0.0, 16.0),
|
||||||
|
child: c,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildNoteLink(Note note) {
|
||||||
|
var textTheme = Theme.of(context).textTheme;
|
||||||
|
var title = note.title;
|
||||||
|
if (title.isEmpty) {
|
||||||
|
title = note.fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(0.0, 8.0, 0, 8.0),
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
openNoteEditor(context, note);
|
||||||
|
},
|
||||||
|
child: Text('- $title', style: textTheme.bodyText1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user