mirror of
https://github.com/git-touch/git-touch
synced 2025-01-19 02:40:05 +01:00
parent
9db5a201a3
commit
5795413f25
@ -33,6 +33,12 @@ class AppBrightnessType {
|
||||
];
|
||||
}
|
||||
|
||||
class AppMarkdownType {
|
||||
static const flutter = 0;
|
||||
static const webview = 1;
|
||||
static const values = [AppMarkdownType.flutter, AppMarkdownType.webview];
|
||||
}
|
||||
|
||||
class PickerItem<T> {
|
||||
final T value;
|
||||
final String text;
|
||||
@ -99,12 +105,12 @@ class Palette {
|
||||
}
|
||||
|
||||
class ThemeModel with ChangeNotifier {
|
||||
String markdownCss;
|
||||
|
||||
int _theme;
|
||||
int get theme => _theme;
|
||||
bool get ready => _theme != null;
|
||||
|
||||
String markdownCss;
|
||||
|
||||
Brightness systemBrightness = Brightness.light;
|
||||
void setSystemBrightness(Brightness v) {
|
||||
if (v != systemBrightness) {
|
||||
@ -138,6 +144,30 @@ class ThemeModel with ChangeNotifier {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// markdown render engine
|
||||
int _markdown;
|
||||
int get markdown => _markdown;
|
||||
Future<void> setMarkdown(int v) async {
|
||||
_markdown = v;
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setInt(StorageKeys.markdown, v);
|
||||
Fimber.d('write markdown engine: $v');
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<String> getMarkdownFuture(
|
||||
BuildContext context, {
|
||||
@required Future<String> Function() md,
|
||||
@required Future<String> Function() html,
|
||||
}) {
|
||||
switch (markdown) {
|
||||
case AppMarkdownType.webview:
|
||||
return html();
|
||||
default:
|
||||
return md();
|
||||
}
|
||||
}
|
||||
|
||||
final router = FluroRouter();
|
||||
|
||||
final paletteLight = Palette(
|
||||
@ -170,7 +200,10 @@ class ThemeModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
markdownCss = await rootBundle.loadString('images/github-markdown.css');
|
||||
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
|
||||
final v = prefs.getInt(StorageKeys.iTheme);
|
||||
Fimber.d('read theme: $v');
|
||||
if (AppThemeType.values.contains(v)) {
|
||||
@ -185,8 +218,10 @@ class ThemeModel with ChangeNotifier {
|
||||
if (AppBrightnessType.values.contains(b)) {
|
||||
_brightnessValue = b;
|
||||
}
|
||||
|
||||
markdownCss = await rootBundle.loadString('images/github-markdown.css');
|
||||
final m = prefs.getInt(StorageKeys.markdown);
|
||||
if (AppMarkdownType.values.contains(m)) {
|
||||
_markdown = m;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ class GhRepoScreen extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Provider.of<ThemeModel>(context);
|
||||
return RefreshStatefulScaffold<
|
||||
Tuple3<GhRepoRepository, Future<int>, Future<String>>>(
|
||||
Tuple3<GhRepoRepository, Future<int>, MarkdownViewData>>(
|
||||
title: AppBarTitle('Repository'),
|
||||
fetch: () async {
|
||||
final ghClient = context.read<AuthModel>().ghClient;
|
||||
@ -64,18 +64,27 @@ class GhRepoScreen extends StatelessWidget {
|
||||
.getJSON('/repos/$owner/$name/stats/contributors')
|
||||
.then((v) => (v as List).length);
|
||||
|
||||
final readmeFuture = ghClient.request(
|
||||
'GET',
|
||||
'/repos/$owner/$name/readme',
|
||||
headers: {HttpHeaders.acceptHeader: 'application/vnd.github.v3.html'},
|
||||
).then((res) {
|
||||
return res.body;
|
||||
}).catchError((err) {
|
||||
// 404
|
||||
return null;
|
||||
});
|
||||
final readmeFactory = (String acceptHeader) {
|
||||
return () {
|
||||
return ghClient.request(
|
||||
'GET',
|
||||
'/repos/$owner/$name/readme',
|
||||
headers: {HttpHeaders.acceptHeader: acceptHeader},
|
||||
).then((res) {
|
||||
return res.body;
|
||||
}).catchError((err) {
|
||||
// 404
|
||||
return null;
|
||||
});
|
||||
};
|
||||
};
|
||||
final readmeData = MarkdownViewData(
|
||||
context,
|
||||
md: readmeFactory('application/vnd.github.v3.raw'),
|
||||
html: readmeFactory('application/vnd.github.v3.html'),
|
||||
);
|
||||
|
||||
return Tuple3(repo, countFuture, readmeFuture);
|
||||
return Tuple3(repo, countFuture, readmeData);
|
||||
},
|
||||
actionBuilder: (data, setState) {
|
||||
final repo = data.item1;
|
||||
@ -97,7 +106,7 @@ class GhRepoScreen extends StatelessWidget {
|
||||
bodyBuilder: (data, setState) {
|
||||
final repo = data.item1;
|
||||
final contributionFuture = data.item2;
|
||||
final readmeFuture = data.item3;
|
||||
final readmeData = data.item3;
|
||||
|
||||
final ref = branch == null ? repo.defaultBranchRef : repo.ref;
|
||||
final license = repo.licenseInfo?.spdxId ?? repo.licenseInfo?.name;
|
||||
@ -332,16 +341,7 @@ class GhRepoScreen extends StatelessWidget {
|
||||
],
|
||||
],
|
||||
),
|
||||
FutureBuilder<String>(
|
||||
future: readmeFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Container();
|
||||
} else {
|
||||
return MarkdownWebView(snapshot.data);
|
||||
}
|
||||
},
|
||||
)
|
||||
MarkdownView(readmeData),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -24,7 +24,7 @@ class GlProjectScreen extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return RefreshStatefulScaffold<
|
||||
Tuple4<GitlabProject, Future<Map<String, double>>, Future<int>,
|
||||
Future<String>>>(
|
||||
MarkdownViewData>>(
|
||||
title: AppBarTitle('Project'),
|
||||
fetch: () async {
|
||||
final auth = context.read<AuthModel>();
|
||||
@ -41,25 +41,29 @@ class GlProjectScreen extends StatelessWidget {
|
||||
final memberCountFuture = auth
|
||||
.fetchGitlabWithPage('/projects/$id/members?per_page=1')
|
||||
.then((v) => v.total);
|
||||
final readmeFuture = p.readmeUrl == null
|
||||
? Future.sync(() => null)
|
||||
: auth
|
||||
.fetchWithGitlabToken(
|
||||
p.readmeUrl.replaceFirst(r'/blob/', '/raw/'))
|
||||
.then((md) async {
|
||||
// we should get the markdown content, then render it
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/16335
|
||||
final res = await auth.fetchGitlab('/markdown',
|
||||
isPost: true,
|
||||
body: {
|
||||
'text': md,
|
||||
'gfm': true,
|
||||
'project': '${p.namespace.name}/${p.name}'
|
||||
});
|
||||
return (res['html'] as String).normalizedHtml;
|
||||
});
|
||||
|
||||
return Tuple4(p, langFuture, memberCountFuture, readmeFuture);
|
||||
MarkdownViewData readmeData;
|
||||
if (p.readmeUrl != null) {
|
||||
final md = () => auth.fetchWithGitlabToken(
|
||||
p.readmeUrl.replaceFirst(r'/blob/', '/raw/'));
|
||||
readmeData = MarkdownViewData(
|
||||
context,
|
||||
md: md,
|
||||
html: () => md().then((md) async {
|
||||
// we should get the markdown content, then render it
|
||||
// https://gitlab.com/gitlab-org/gitlab/-/issues/16335
|
||||
final res = await auth.fetchGitlab('/markdown',
|
||||
isPost: true,
|
||||
body: {
|
||||
'text': md,
|
||||
'gfm': true,
|
||||
'project': '${p.namespace.name}/${p.name}'
|
||||
});
|
||||
return (res['html'] as String).normalizedHtml;
|
||||
}),
|
||||
);
|
||||
}
|
||||
return Tuple4(p, langFuture, memberCountFuture, readmeData);
|
||||
},
|
||||
actionBuilder: (t, setState) {
|
||||
return ActionButton(
|
||||
@ -73,7 +77,7 @@ class GlProjectScreen extends StatelessWidget {
|
||||
final p = t.item1;
|
||||
final langFuture = t.item2;
|
||||
final memberCountFuture = t.item3;
|
||||
final readmeFuture = t.item4;
|
||||
final readmeData = t.item4;
|
||||
|
||||
final theme = Provider.of<ThemeModel>(context);
|
||||
final auth = Provider.of<AuthModel>(context);
|
||||
@ -185,16 +189,7 @@ class GlProjectScreen extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
CommonStyle.verticalGap,
|
||||
FutureBuilder<String>(
|
||||
future: readmeFuture,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Container();
|
||||
} else {
|
||||
return MarkdownWebView(snapshot.data);
|
||||
}
|
||||
},
|
||||
),
|
||||
MarkdownView(readmeData),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
@ -126,6 +126,28 @@ class SettingsScreen extends StatelessWidget {
|
||||
url: '/choose-code-theme',
|
||||
rightWidget: Text('${code.fontFamily}, ${code.fontSize}pt'),
|
||||
),
|
||||
TableViewItem(
|
||||
text: Text('Markdown Render Engine'),
|
||||
rightWidget: Text(theme.markdown == AppMarkdownType.flutter
|
||||
? 'Flutter'
|
||||
: 'WebView'),
|
||||
onTap: () {
|
||||
theme.showActions(context, [
|
||||
for (var t in [
|
||||
Tuple2('Flutter', AppMarkdownType.flutter),
|
||||
Tuple2('WebView', AppMarkdownType.webview),
|
||||
])
|
||||
ActionItem(
|
||||
text: t.item1,
|
||||
onTap: (_) {
|
||||
if (theme.markdown != t.item2) {
|
||||
theme.setMarkdown(t.item2);
|
||||
}
|
||||
},
|
||||
)
|
||||
]);
|
||||
},
|
||||
),
|
||||
]),
|
||||
CommonStyle.verticalGap,
|
||||
TableView(headerText: 'feedback', items: [
|
||||
|
@ -25,6 +25,7 @@ class StorageKeys {
|
||||
static const codeThemeDark = 'code-theme-dark';
|
||||
static const iCodeFontSize = 'code-font-size';
|
||||
static const codeFontFamily = 'code-font-family';
|
||||
static const markdown = 'markdown';
|
||||
|
||||
static getDefaultStartTabKey(String platform) =>
|
||||
'default-start-tab-$platform';
|
||||
|
@ -8,6 +8,54 @@ import 'package:provider/provider.dart';
|
||||
import 'package:uri/uri.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class MarkdownViewData {
|
||||
final Future<String> future;
|
||||
MarkdownViewData(
|
||||
BuildContext context, {
|
||||
@required Future<String> Function() md,
|
||||
@required Future<String> Function() html,
|
||||
}) : future = context.read<ThemeModel>().markdown == AppMarkdownType.flutter
|
||||
? md()
|
||||
: html();
|
||||
}
|
||||
|
||||
class MarkdownView extends StatelessWidget {
|
||||
final MarkdownViewData data;
|
||||
MarkdownView(this.data);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Provider.of<ThemeModel>(context);
|
||||
|
||||
if (data?.future == null) return Container();
|
||||
|
||||
switch (theme.markdown) {
|
||||
case AppMarkdownType.flutter:
|
||||
return FutureBuilder<String>(
|
||||
future: data.future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Container();
|
||||
} else {
|
||||
return MarkdownFlutterView(snapshot.data);
|
||||
}
|
||||
},
|
||||
);
|
||||
default:
|
||||
return FutureBuilder<String>(
|
||||
future: data.future,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Container();
|
||||
} else {
|
||||
return MarkdownWebView(snapshot.data);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MarkdownWebView extends StatelessWidget {
|
||||
final String html;
|
||||
MarkdownWebView(this.html);
|
||||
|
Loading…
Reference in New Issue
Block a user