git-touch-android-ios-app/lib/widgets/markdown_view.dart

138 lines
4.5 KiB
Dart
Raw Normal View History

import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
2019-09-30 14:49:22 +02:00
import 'package:git_touch/models/theme.dart';
import 'package:git_touch/screens/issue.dart';
2019-11-06 14:56:52 +01:00
import 'package:git_touch/screens/object.dart';
2019-09-30 14:49:22 +02:00
import 'package:git_touch/screens/repository.dart';
import 'package:git_touch/screens/user.dart';
2019-09-14 11:19:33 +02:00
import 'package:git_touch/utils/utils.dart';
import 'package:primer/primer.dart';
2019-09-30 14:49:22 +02:00
import 'package:provider/provider.dart';
import 'package:uri/uri.dart';
2019-11-06 14:56:52 +01:00
import 'package:path/path.dart' as path;
class MarkdownView extends StatelessWidget {
final String text;
2019-11-06 14:56:52 +01:00
final List<String> basePaths;
2019-11-06 14:56:52 +01:00
MarkdownView(this.text, {this.basePaths});
2019-09-13 18:31:33 +02:00
static const _basicStyle =
TextStyle(fontSize: 16, color: PrimerColors.gray900, height: 1.5);
static final _hStyle =
_basicStyle.copyWith(fontWeight: FontWeight.w600, height: 1.25);
2019-09-30 14:49:22 +02:00
Map<String, String> matchPattern(String url, String pattern) {
var uri = Uri.parse(url);
return UriParser(UriTemplate(pattern)).match(uri)?.parameters;
}
@override
Widget build(BuildContext context) {
return MarkdownBody(
2019-09-30 14:49:22 +02:00
onTapLink: (url) {
2019-11-06 14:56:52 +01:00
if (basePaths != null &&
!url.startsWith('https://') &&
!url.startsWith('http://')) {
// Treat as relative path
final x = basePaths.sublist(3).join('/');
var y = path.join(x, url);
if (y.startsWith('/')) y = y.substring(1);
final paths = path.split(y);
return Provider.of<ThemeModel>(context).pushRoute(
context,
(_) => ObjectScreen(
basePaths[0],
basePaths[1],
basePaths[2],
paths: paths,
),
);
}
2019-09-30 14:49:22 +02:00
// TODO: Relative paths
if (url.startsWith('https://github.com')) {
Map<String, String> m;
m = matchPattern(url, '/{owner}/{name}/pull/{number}');
if (m != null) {
return Provider.of<ThemeModel>(context).pushRoute(
context,
(_) => IssueScreen(
2019-11-02 17:02:41 +01:00
m['owner'],
m['name'],
int.parse(m['number']),
2019-09-30 14:49:22 +02:00
isPullRequest: true,
));
}
m = matchPattern(url, '/{owner}/{name}/issues/{number}');
if (m != null) {
return Provider.of<ThemeModel>(context).pushRoute(
context,
(_) => IssueScreen(
2019-11-02 17:02:41 +01:00
m['owner'],
m['name'],
int.parse(m['number']),
2019-09-30 14:49:22 +02:00
));
}
m = matchPattern(url, '/{owner}/{name}');
if (m != null) {
return Provider.of<ThemeModel>(context).pushRoute(
context, (_) => RepositoryScreen(m['owner'], m['name']));
}
m = matchPattern(url, '/{login}');
if (m != null) {
return Provider.of<ThemeModel>(context)
.pushRoute(context, (_) => UserScreen(m['login']));
}
}
launchUrl(url);
},
data: text,
styleSheet: MarkdownStyleSheet(
2019-09-13 18:31:33 +02:00
a: _basicStyle.copyWith(color: PrimerColors.blue500),
p: _basicStyle,
code: _basicStyle.copyWith(
fontSize: 16 * 0.85,
height: 1.45,
2019-10-02 10:09:54 +02:00
fontFamily: CommonStyle.monospace,
2019-09-13 18:31:33 +02:00
),
h1: _hStyle.copyWith(fontSize: 32),
h2: _hStyle.copyWith(fontSize: 24),
h3: _hStyle.copyWith(fontSize: 20),
h4: _hStyle,
h5: _hStyle.copyWith(fontSize: 14),
h6: _hStyle.copyWith(fontSize: 16 * 0.85, color: PrimerColors.gray500),
em: _basicStyle.copyWith(fontStyle: FontStyle.italic),
strong: _basicStyle.copyWith(fontWeight: FontWeight.w600),
blockquote: _basicStyle.copyWith(color: PrimerColors.gray500),
img: _basicStyle,
blockSpacing: 16,
listIndent: 32,
blockquotePadding: 16, // FIXME: only horizontal
blockquoteDecoration: BoxDecoration(
2019-09-13 18:31:33 +02:00
border: Border(left: BorderSide(color: Color(0xffdfe2e5), width: 4)),
),
codeblockPadding: 16,
codeblockDecoration: BoxDecoration(
2019-09-13 18:31:33 +02:00
color: PrimerColors.gray100,
borderRadius: BorderRadius.circular(3),
),
horizontalRuleDecoration: BoxDecoration(
2019-09-13 18:31:33 +02:00
border: Border(
top: BorderSide(width: 4, color: PrimerColors.gray200),
),
),
),
// syntaxHighlighter: , // TODO:
);
}
}