1
0
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:
Rongjian Zhang 2019-09-15 17:36:09 +08:00
parent 9bc5c2b96a
commit a47d84a6cc
18 changed files with 275 additions and 44 deletions

View File

@ -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
View 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();
}
}

View File

@ -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:
},
);
}
}
}

View File

@ -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)
];

View File

@ -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)
];

View File

@ -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,

View File

@ -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),

View File

@ -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()),
);
}

View 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),
),
)
],
);
},
);
}
}

View File

@ -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),

View File

@ -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;
}

View File

@ -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',

View File

@ -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,

View File

@ -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,

View File

@ -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 {

View File

@ -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),
),
),

View File

@ -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(

View File

@ -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