mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-15 07:56:11 +08:00
186 lines
5.7 KiB
Dart
186 lines
5.7 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_markdown/flutter_markdown.dart';
|
|
import 'package:gitjournal/folder_views/common.dart';
|
|
import 'package:gitjournal/utils.dart';
|
|
import 'package:gitjournal/widgets/editor_scroll_view.dart';
|
|
import 'package:gitjournal/widgets/notes_backlinks.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
import 'package:path/path.dart' as p;
|
|
|
|
import 'package:gitjournal/core/note.dart';
|
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
|
|
|
class NoteViewer extends StatelessWidget {
|
|
final Note note;
|
|
const NoteViewer({Key key, @required this.note}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
ThemeData theme = Theme.of(context);
|
|
theme = theme.copyWith(
|
|
textTheme: theme.textTheme.copyWith(
|
|
subtitle1: theme.textTheme.subtitle1,
|
|
),
|
|
);
|
|
|
|
// Copied from MarkdownStyleSheet except Grey is replaced with Highlight color
|
|
var markdownStyleSheet = MarkdownStyleSheet.fromTheme(theme).copyWith(
|
|
code: theme.textTheme.bodyText2.copyWith(
|
|
backgroundColor: theme.dialogBackgroundColor,
|
|
fontFamily: "monospace",
|
|
fontSize: theme.textTheme.bodyText2.fontSize * 0.85,
|
|
),
|
|
tableBorder: TableBorder.all(color: theme.highlightColor, width: 0),
|
|
tableCellsDecoration: BoxDecoration(color: theme.dialogBackgroundColor),
|
|
codeblockDecoration: BoxDecoration(
|
|
color: theme.dialogBackgroundColor,
|
|
borderRadius: BorderRadius.circular(2.0),
|
|
),
|
|
horizontalRuleDecoration: BoxDecoration(
|
|
border: Border(
|
|
top: BorderSide(width: 5.0, color: theme.highlightColor),
|
|
),
|
|
),
|
|
);
|
|
|
|
final rootFolder = Provider.of<NotesFolderFS>(context);
|
|
var view = EditorScrollView(
|
|
child: Column(
|
|
children: <Widget>[
|
|
if (note.canHaveMetadata) NoteTitleHeader(note.title),
|
|
Padding(
|
|
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
|
|
child: MarkdownBody(
|
|
data: note.body,
|
|
styleSheet: markdownStyleSheet,
|
|
onTapLink: (String link) {
|
|
if (link.startsWith('./')) {
|
|
var spec = link.substring(2);
|
|
var note = rootFolder.getNoteWithSpec(spec);
|
|
if (note != null) {
|
|
openNoteEditor(context, note);
|
|
} else {
|
|
showSnackbar(context, "Link '$link' not found");
|
|
}
|
|
} else {
|
|
print("Launching " + link);
|
|
launch(link);
|
|
}
|
|
},
|
|
imageBuilder: (url) => kDefaultImageBuilder(
|
|
url, note.parent.folderPath + p.separator, null, null),
|
|
),
|
|
),
|
|
NoteBacklinkRenderer(note: note, rootFolder: rootFolder),
|
|
// _buildFooter(context),
|
|
],
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
),
|
|
);
|
|
|
|
return view;
|
|
}
|
|
|
|
/*
|
|
Widget _buildFooter(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
|
|
child: Row(
|
|
children: <Widget>[
|
|
IconButton(
|
|
icon: Icon(Icons.arrow_left),
|
|
tooltip: 'Previous Entry',
|
|
onPressed: showPrevNoteFunc,
|
|
),
|
|
Expanded(
|
|
flex: 10,
|
|
child: Text(''),
|
|
),
|
|
IconButton(
|
|
icon: Icon(Icons.arrow_right),
|
|
tooltip: 'Next Entry',
|
|
onPressed: showNextNoteFunc,
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
*/
|
|
}
|
|
|
|
class NoteTitleHeader extends StatelessWidget {
|
|
final String header;
|
|
NoteTitleHeader(this.header);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
var textTheme = Theme.of(context).textTheme;
|
|
return Padding(
|
|
padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
|
|
child: Text(header, style: textTheme.headline6),
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Copied from flutter_markdown
|
|
// But it uses CachedNetworkImage
|
|
//
|
|
typedef Widget ImageBuilder(
|
|
Uri uri, String imageDirectory, double width, double height);
|
|
|
|
final ImageBuilder kDefaultImageBuilder = (
|
|
Uri uri,
|
|
String imageDirectory,
|
|
double width,
|
|
double height,
|
|
) {
|
|
if (uri.scheme == 'http' || uri.scheme == 'https') {
|
|
return CachedNetworkImage(
|
|
imageUrl: uri.toString(),
|
|
width: width,
|
|
height: height,
|
|
placeholder: (context, url) => const CircularProgressIndicator(),
|
|
errorWidget: (context, url, error) => const Icon(Icons.error),
|
|
);
|
|
} else if (uri.scheme == 'data') {
|
|
return _handleDataSchemeUri(uri, width, height);
|
|
} else if (uri.scheme == "resource") {
|
|
return Image.asset(uri.path, width: width, height: height);
|
|
} else {
|
|
Uri fileUri = imageDirectory != null
|
|
? Uri.parse(imageDirectory + uri.toString())
|
|
: uri;
|
|
if (fileUri.scheme == 'http' || fileUri.scheme == 'https') {
|
|
return CachedNetworkImage(
|
|
imageUrl: fileUri.toString(),
|
|
width: width,
|
|
height: height,
|
|
placeholder: (context, url) => const CircularProgressIndicator(),
|
|
errorWidget: (context, url, error) => const Icon(Icons.error),
|
|
);
|
|
} else {
|
|
return Image.file(File.fromUri(fileUri), width: width, height: height);
|
|
}
|
|
}
|
|
};
|
|
|
|
Widget _handleDataSchemeUri(Uri uri, final double width, final double height) {
|
|
final String mimeType = uri.data.mimeType;
|
|
if (mimeType.startsWith('image/')) {
|
|
return Image.memory(
|
|
uri.data.contentAsBytes(),
|
|
width: width,
|
|
height: height,
|
|
);
|
|
} else if (mimeType.startsWith('text/')) {
|
|
return Text(uri.data.contentAsString());
|
|
}
|
|
return const SizedBox();
|
|
}
|