mirror of
https://github.com/git-touch/git-touch
synced 2025-02-20 13:30:38 +01:00
feat: code settings
This commit is contained in:
parent
9bc5c2b96a
commit
a47d84a6cc
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:git_touch/models/code.dart';
|
||||
import 'package:git_touch/models/settings.dart';
|
||||
import 'package:git_touch/models/theme.dart';
|
||||
import 'package:git_touch/screens/issues.dart';
|
||||
@ -34,6 +35,7 @@ class _HomeState extends State<Home> {
|
||||
// FIXME:
|
||||
Provider.of<ThemeModel>(context).init();
|
||||
Provider.of<SettingsModel>(context).init();
|
||||
Provider.of<CodeModel>(context).init();
|
||||
});
|
||||
}
|
||||
|
||||
@ -134,7 +136,7 @@ class _HomeState extends State<Home> {
|
||||
}
|
||||
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoApp(
|
||||
home: CupertinoTheme(
|
||||
data: CupertinoThemeData(
|
||||
@ -181,6 +183,7 @@ class App extends StatelessWidget {
|
||||
ChangeNotifierProvider(builder: (context) => NotificationModel()),
|
||||
ChangeNotifierProvider(builder: (context) => ThemeModel()),
|
||||
ChangeNotifierProvider(builder: (context) => SettingsModel()),
|
||||
ChangeNotifierProvider(builder: (context) => CodeModel()),
|
||||
],
|
||||
child: Home(),
|
||||
);
|
||||
|
71
lib/models/code.dart
Normal file
71
lib/models/code.dart
Normal file
@ -0,0 +1,71 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_highlight/theme_map.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class CodeModel with ChangeNotifier {
|
||||
static const _kTheme = 'code-theme';
|
||||
static const _kFontSize = 'code-font-size';
|
||||
static const _kFontFamily = 'code-font-family';
|
||||
|
||||
static var themes = themeMap.keys.toList();
|
||||
static const fontSizes = [12, 13, 14, 15, 16, 17, 18, 19, 20];
|
||||
static const fontFamilies = ['System'];
|
||||
|
||||
String _theme = 'github';
|
||||
int _fontSize = 14;
|
||||
String _fontFamily = 'System';
|
||||
|
||||
String get theme => _theme;
|
||||
int get fontSize => _fontSize;
|
||||
String get fontFamily => _fontFamily;
|
||||
|
||||
init() async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
var vh = prefs.getString(_kTheme);
|
||||
var vs = prefs.getInt(_kFontSize);
|
||||
var vf = prefs.getString(_kFontFamily);
|
||||
|
||||
print('read code: $vh, $vs, $vf');
|
||||
if (themeMap.keys.contains(vh)) {
|
||||
_theme = vh;
|
||||
}
|
||||
if (fontSizes.contains(vs)) {
|
||||
_fontSize = vs;
|
||||
}
|
||||
if (fontFamilies.contains(vf)) {
|
||||
_fontFamily = vf;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setTheme(String v) async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
await prefs.setString(_kTheme, v);
|
||||
print('write code theme: $v');
|
||||
|
||||
_theme = v;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setFontSize(int v) async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
await prefs.setInt(_kFontSize, v);
|
||||
print('write code font size: $v');
|
||||
|
||||
_fontSize = v;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
setFontFamily(String v) async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
|
||||
await prefs.setString(_kFontFamily, v);
|
||||
print('write code font family: $v');
|
||||
|
||||
_fontFamily = v;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
@ -10,10 +10,10 @@ class DialogOption<T> {
|
||||
DialogOption({this.value, this.widget});
|
||||
}
|
||||
|
||||
class ThemeMap {
|
||||
class AppThemeMap {
|
||||
static const material = 0;
|
||||
static const cupertino = 1;
|
||||
static const values = [ThemeMap.material, ThemeMap.cupertino];
|
||||
static const values = [AppThemeMap.material, AppThemeMap.cupertino];
|
||||
}
|
||||
|
||||
class ThemeModel with ChangeNotifier {
|
||||
@ -28,12 +28,12 @@ class ThemeModel with ChangeNotifier {
|
||||
|
||||
int v = prefs.getInt(storageKey);
|
||||
print('read theme: $v');
|
||||
if (ThemeMap.values.contains(v)) {
|
||||
if (AppThemeMap.values.contains(v)) {
|
||||
_theme = v;
|
||||
} else if (Platform.isIOS) {
|
||||
_theme = ThemeMap.cupertino;
|
||||
_theme = AppThemeMap.cupertino;
|
||||
} else {
|
||||
_theme = ThemeMap.material;
|
||||
_theme = AppThemeMap.material;
|
||||
}
|
||||
|
||||
notifyListeners();
|
||||
@ -55,7 +55,7 @@ class ThemeModel with ChangeNotifier {
|
||||
bool fullscreenDialog = false,
|
||||
}) {
|
||||
switch (theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
Navigator.of(context).push(CupertinoPageRoute(
|
||||
builder: builder,
|
||||
fullscreenDialog: fullscreenDialog,
|
||||
@ -71,7 +71,7 @@ class ThemeModel with ChangeNotifier {
|
||||
|
||||
Future<bool> showConfirm(BuildContext context, String text) {
|
||||
switch (theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return showCupertinoDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
@ -130,7 +130,7 @@ class ThemeModel with ChangeNotifier {
|
||||
var cancelWidget = Text('Cancel');
|
||||
|
||||
switch (theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return showCupertinoDialog<T>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
@ -181,4 +181,38 @@ class ThemeModel with ChangeNotifier {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<T> showPicker<T>(
|
||||
BuildContext context, {
|
||||
@required int initialItem,
|
||||
@required List<Widget> children,
|
||||
@required Function(int) onSelectedItemChanged,
|
||||
}) {
|
||||
switch (theme) {
|
||||
case AppThemeMap.cupertino:
|
||||
return showCupertinoModalPopup<T>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return Container(
|
||||
height: 300,
|
||||
child: CupertinoPicker(
|
||||
backgroundColor: CupertinoColors.white,
|
||||
children: children,
|
||||
itemExtent: 40,
|
||||
scrollController:
|
||||
FixedExtentScrollController(initialItem: initialItem),
|
||||
onSelectedItemChanged: onSelectedItemChanged,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
default:
|
||||
return showModalBottomSheet<T>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return null; // TODO:
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ class _ListScaffoldState<T, K> extends State<ListScaffold<T, K>> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
List<Widget> slivers = [
|
||||
CupertinoSliverRefreshControl(onRefresh: _refresh)
|
||||
];
|
||||
|
@ -181,7 +181,7 @@ class _LongListScaffoldState<T, K> extends State<LongListScaffold<T, K>> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
List<Widget> slivers = [
|
||||
CupertinoSliverRefreshControl(onRefresh: _refresh)
|
||||
];
|
||||
|
@ -80,7 +80,7 @@ class _RefreshScaffoldState<T> extends State<RefreshScaffold<T>> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar: CupertinoNavigationBar(
|
||||
middle: widget.title,
|
||||
|
@ -41,7 +41,7 @@ class RefreshStatelessScaffold extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar:
|
||||
CupertinoNavigationBar(middle: title, trailing: trailing),
|
||||
|
@ -22,7 +22,7 @@ class SimpleScaffold extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoPageScaffold(
|
||||
navigationBar:
|
||||
CupertinoNavigationBar(middle: title, trailing: trailing),
|
||||
@ -32,11 +32,7 @@ class SimpleScaffold extends StatelessWidget {
|
||||
);
|
||||
default:
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: title,
|
||||
actions: actions,
|
||||
bottom: bottom,
|
||||
),
|
||||
appBar: AppBar(title: title, actions: actions, bottom: bottom),
|
||||
body: SingleChildScrollView(child: bodyBuilder()),
|
||||
);
|
||||
}
|
||||
|
105
lib/screens/code_settings.dart
Normal file
105
lib/screens/code_settings.dart
Normal file
@ -0,0 +1,105 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_highlight/flutter_highlight.dart';
|
||||
import 'package:flutter_highlight/theme_map.dart';
|
||||
import 'package:git_touch/models/code.dart';
|
||||
import 'package:git_touch/models/theme.dart';
|
||||
import 'package:git_touch/scaffolds/simple.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:git_touch/widgets/app_bar_title.dart';
|
||||
import 'package:git_touch/widgets/table_view.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class CodeSettingsScreen extends StatelessWidget {
|
||||
final String code;
|
||||
final String language;
|
||||
|
||||
CodeSettingsScreen(this.code, this.language);
|
||||
|
||||
static Timer _themeDebounce;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var codeProvider = Provider.of<CodeModel>(context);
|
||||
|
||||
return SimpleScaffold(
|
||||
title: AppBarTitle('Code theme'),
|
||||
bodyBuilder: () {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: <Widget>[
|
||||
TableView(
|
||||
items: [
|
||||
TableViewItem(
|
||||
text: Text('Syntax Highlighting'),
|
||||
rightWidget: Text(codeProvider.theme),
|
||||
onTap: () {
|
||||
Provider.of<ThemeModel>(context).showPicker(
|
||||
context,
|
||||
children: CodeModel.themes.map((k) => Text(k)).toList(),
|
||||
initialItem:
|
||||
CodeModel.themes.indexOf(codeProvider.theme),
|
||||
onSelectedItemChanged: (int value) {
|
||||
if (_themeDebounce?.isActive ?? false)
|
||||
_themeDebounce.cancel();
|
||||
_themeDebounce =
|
||||
Timer(const Duration(milliseconds: 500), () {
|
||||
Provider.of<CodeModel>(context)
|
||||
.setTheme(CodeModel.themes[value]);
|
||||
});
|
||||
},
|
||||
);
|
||||
}),
|
||||
TableViewItem(
|
||||
text: Text('Font Size'),
|
||||
rightWidget: Text(codeProvider.fontSize.toString()),
|
||||
onTap: () {
|
||||
Provider.of<ThemeModel>(context).showPicker(
|
||||
context,
|
||||
children: CodeModel.fontSizes
|
||||
.map((k) => Text(k.toString()))
|
||||
.toList(),
|
||||
initialItem:
|
||||
CodeModel.fontSizes.indexOf(codeProvider.fontSize),
|
||||
onSelectedItemChanged: (int value) {
|
||||
if (_themeDebounce?.isActive ?? false)
|
||||
_themeDebounce.cancel();
|
||||
_themeDebounce =
|
||||
Timer(const Duration(milliseconds: 500), () {
|
||||
Provider.of<CodeModel>(context)
|
||||
.setFontSize(CodeModel.fontSizes[value]);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
TableViewItem(
|
||||
text: Text('Font Family'),
|
||||
rightWidget: Text(codeProvider.fontFamily.toString()),
|
||||
onTap: () {
|
||||
// TODO:
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: HighlightView(
|
||||
code,
|
||||
language: language,
|
||||
theme: themeMap[codeProvider.theme],
|
||||
textStyle: TextStyle(
|
||||
fontSize: codeProvider.fontSize.toDouble(),
|
||||
fontFamily: monospaceFont,
|
||||
),
|
||||
padding: const EdgeInsets.all(10),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
@ -184,7 +184,7 @@ $key: pullRequest(number: ${item.number}) {
|
||||
|
||||
Widget _buildTitle() {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
// var textStyle = DefaultTextStyle.of(context).style;
|
||||
return DefaultTextStyle(
|
||||
style: TextStyle(fontSize: 16),
|
||||
|
@ -1,6 +1,10 @@
|
||||
import 'package:flutter_highlight/themes/github.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_highlight/theme_map.dart';
|
||||
import 'package:git_touch/models/code.dart';
|
||||
import 'package:git_touch/screens/code_settings.dart';
|
||||
import 'package:git_touch/screens/image_view.dart';
|
||||
import 'package:git_touch/widgets/app_bar_title.dart';
|
||||
import 'package:git_touch/widgets/link.dart';
|
||||
import 'package:git_touch/widgets/markdown_view.dart';
|
||||
import 'package:git_touch/widgets/table_view.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
@ -10,7 +14,6 @@ import 'package:git_touch/models/settings.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:git_touch/scaffolds/refresh.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:git_touch/widgets/link.dart';
|
||||
import 'package:primer/primer.dart';
|
||||
import 'package:seti/seti.dart';
|
||||
|
||||
@ -29,14 +32,16 @@ class ObjectScreen extends StatelessWidget {
|
||||
this.type = 'tree',
|
||||
});
|
||||
|
||||
String get expression => '$branch:' + paths.join('/');
|
||||
String get extname {
|
||||
String get _expression => '$branch:' + paths.join('/');
|
||||
String get _extname {
|
||||
if (paths.isEmpty) return '';
|
||||
var dotext = path.extension(paths.last);
|
||||
if (dotext.isEmpty) return '';
|
||||
return dotext.substring(1);
|
||||
}
|
||||
|
||||
String get _language => _extname.isEmpty ? 'plaintext' : _extname;
|
||||
|
||||
String get rawUrl =>
|
||||
'https://raw.githubusercontent.com/$owner/$name/$branch/' +
|
||||
paths.join('/'); // TODO:
|
||||
@ -111,8 +116,9 @@ class ObjectScreen extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBlob(payload) {
|
||||
switch (extname) {
|
||||
Widget _buildBlob(BuildContext context, payload) {
|
||||
var codeProvider = Provider.of<CodeModel>(context);
|
||||
switch (_extname) {
|
||||
case 'md':
|
||||
case 'markdown':
|
||||
return Padding(
|
||||
@ -124,10 +130,12 @@ class ObjectScreen extends StatelessWidget {
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: HighlightView(
|
||||
payload['text'],
|
||||
language: extname.isEmpty ? 'plaintext' : extname,
|
||||
theme: githubTheme,
|
||||
language: _language,
|
||||
theme: themeMap[codeProvider.theme],
|
||||
padding: EdgeInsets.all(10),
|
||||
textStyle: TextStyle(fontFamily: monospaceFont),
|
||||
textStyle: TextStyle(
|
||||
fontSize: codeProvider.fontSize.toDouble(),
|
||||
fontFamily: monospaceFont),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -140,7 +148,7 @@ class ObjectScreen extends StatelessWidget {
|
||||
onRefresh: () async {
|
||||
var data = await Provider.of<SettingsModel>(context).query('''{
|
||||
repository(owner: "$owner", name: "$name") {
|
||||
object(expression: "$expression") {
|
||||
object(expression: "$_expression") {
|
||||
$_subQuery
|
||||
}
|
||||
}
|
||||
@ -161,12 +169,25 @@ class ObjectScreen extends StatelessWidget {
|
||||
|
||||
return data['repository']['object'];
|
||||
},
|
||||
trailingBuilder: (payload) {
|
||||
switch (type) {
|
||||
case 'blob':
|
||||
return Link(
|
||||
child: Icon(Octicons.settings, size: 20),
|
||||
material: false,
|
||||
screenBuilder: (_) =>
|
||||
CodeSettingsScreen(payload['text'], _language),
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
},
|
||||
bodyBuilder: (payload) {
|
||||
switch (type) {
|
||||
case 'tree':
|
||||
return _buildTree(payload);
|
||||
case 'blob':
|
||||
return _buildBlob(payload);
|
||||
return _buildBlob(context, payload);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ class _SearchScreenState extends State<SearchScreen> {
|
||||
|
||||
Widget _buildInput() {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoTextField(
|
||||
// padding: EdgeInsets.all(10),
|
||||
placeholder: 'Type to search',
|
||||
|
@ -37,11 +37,11 @@ class SettingsScreen extends StatelessWidget {
|
||||
TableView(headerText: 'THEME', items: [
|
||||
TableViewItem(
|
||||
text: Text('Material'),
|
||||
rightWidget:
|
||||
_buildRightWidget(themeProvider.theme == ThemeMap.material),
|
||||
rightWidget: _buildRightWidget(
|
||||
themeProvider.theme == AppThemeMap.material),
|
||||
onTap: () {
|
||||
if (themeProvider.theme != ThemeMap.material) {
|
||||
themeProvider.setTheme(ThemeMap.material);
|
||||
if (themeProvider.theme != AppThemeMap.material) {
|
||||
themeProvider.setTheme(AppThemeMap.material);
|
||||
}
|
||||
},
|
||||
hideRightChevron: true,
|
||||
@ -49,10 +49,10 @@ class SettingsScreen extends StatelessWidget {
|
||||
TableViewItem(
|
||||
text: Text('Cupertino'),
|
||||
rightWidget: _buildRightWidget(
|
||||
themeProvider.theme == ThemeMap.cupertino),
|
||||
themeProvider.theme == AppThemeMap.cupertino),
|
||||
onTap: () {
|
||||
if (themeProvider.theme != ThemeMap.cupertino) {
|
||||
themeProvider.setTheme(ThemeMap.cupertino);
|
||||
if (themeProvider.theme != AppThemeMap.cupertino) {
|
||||
themeProvider.setTheme(AppThemeMap.cupertino);
|
||||
}
|
||||
},
|
||||
hideRightChevron: true,
|
||||
|
@ -148,7 +148,7 @@ class UserScreen extends StatelessWidget {
|
||||
var payload = data[0];
|
||||
if (isMe) {
|
||||
return Link(
|
||||
child: Icon(Icons.settings, size: 24),
|
||||
child: Icon(Icons.settings),
|
||||
screenBuilder: (_) => SettingsScreen(),
|
||||
material: false,
|
||||
fullscreenDialog: true,
|
||||
|
@ -30,7 +30,7 @@ class ActionButton extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return GestureDetector(
|
||||
child: Icon(iconData, size: 24),
|
||||
onTap: () async {
|
||||
|
@ -66,7 +66,8 @@ class Link extends StatelessWidget {
|
||||
color: bgColor ?? Colors.white,
|
||||
child: InkWell(
|
||||
child: child,
|
||||
splashColor: theme == ThemeMap.cupertino ? Colors.transparent : null,
|
||||
splashColor:
|
||||
theme == AppThemeMap.cupertino ? Colors.transparent : null,
|
||||
onTap: () => _onTap(context, theme),
|
||||
),
|
||||
),
|
||||
|
@ -12,7 +12,7 @@ class Loading extends StatelessWidget {
|
||||
// return Image.asset('images/loading.webp');
|
||||
|
||||
switch (Provider.of<ThemeModel>(context).theme) {
|
||||
case ThemeMap.cupertino:
|
||||
case AppThemeMap.cupertino:
|
||||
return CupertinoActivityIndicator(radius: 12);
|
||||
default:
|
||||
return Center(
|
||||
|
@ -16,7 +16,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
http: ^0.12.0
|
||||
rxdart: ^0.20.0
|
||||
rxdart: ^0.22.2
|
||||
uri: ^0.11.3
|
||||
intl: ^0.15.7
|
||||
url_launcher: ^5.0.2
|
||||
|
Loading…
x
Reference in New Issue
Block a user