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:
Vishesh Handa
2020-05-26 15:28:34 +02:00
parent af69dd6e48
commit 96ed70f023
3 changed files with 115 additions and 1 deletions

View File

@ -437,6 +437,11 @@ class Link {
other is Note &&
runtimeType == other.runtimeType &&
filePath == other.filePath;
@override
String toString() {
return 'Link{term: $term, filePath: $filePath}';
}
}
class LinkExtractor implements md.NodeVisitor {

View File

@ -458,8 +458,33 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
Set<String> getNoteTagsRecursively() {
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) {
for (var note in folder.notes) {
tags.addAll(note.tags);

View File

@ -47,6 +47,7 @@ class NoteViewer extends StatelessWidget {
),
);
final rootFolder = Provider.of<NotesFolderFS>(context);
var view = EditorScrollView(
child: Column(
children: <Widget>[
@ -58,7 +59,6 @@ class NoteViewer extends StatelessWidget {
styleSheet: markdownStyleSheet,
onTapLink: (String link) {
if (link.startsWith('./')) {
final rootFolder = Provider.of<NotesFolderFS>(context);
var spec = link.substring(2);
var note = rootFolder.getNoteWithSpec(spec);
if (note != null) {
@ -75,6 +75,7 @@ class NoteViewer extends StatelessWidget {
url, note.parent.folderPath + p.separator, null, null),
),
),
NoteBacklinkRenderer(note: note, rootFolder: rootFolder),
// _buildFooter(context),
],
crossAxisAlignment: CrossAxisAlignment.start,
@ -181,3 +182,86 @@ Widget _handleDataSchemeUri(Uri uri, final double width, final double height) {
}
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),
),
);
}
}