Skip to content

Commit 295a6d9

Browse files
committed
update code
1 parent 0608c20 commit 295a6d9

20 files changed

+1115
-67
lines changed

assets/config.yaml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# https://yaml-multiline.info/
2+
3+
defaultRawTemplate: |-
4+
Level {{ level }}
5+
6+
Question:
7+
{{ question }}
8+
9+
Hints:
10+
{{ hints }}
11+
12+
Test:
13+
{{ test }}
14+
15+
Solution:
16+
{{ solution }}
17+
18+
defaultProgramTemplate: |-
19+
# Level {{ level }}
20+
#
21+
# Question:
22+
# {{ question }}
23+
#
24+
# Hints:
25+
# {{ hints }}
26+
#
27+
# Test:
28+
# {{ test }}
29+
#
30+
# Solution:
31+
# {{ solution }}

assets/fonts/FZLanTYJW_Xian.ttf

3.82 MB
Binary file not shown.

assets/fonts/romantic_garden.ttf

8.88 MB
Binary file not shown.

assets/i18n/en.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"title": "Colorful Classroom",
3+
"question": "Question",
4+
"setting": "Setting",
5+
"zh": "Chinese",
6+
"en": "English",
7+
"notification": "Notification",
8+
"feedback": "Feedback",
9+
"about": "About",
10+
"language": "Language",
11+
"theme_color": "Theme Color",
12+
"night_mode": "Night Mode",
13+
"exit": "Exit"
14+
}

assets/i18n/zh.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"title": "彩色课堂",
3+
"question": "问题",
4+
"setting": "设置",
5+
"zh": "中文",
6+
"en": "英文",
7+
"notification": "消息",
8+
"feedback": "反馈",
9+
"about": "关于",
10+
"language": "语言",
11+
"theme_color": "主题颜色",
12+
"night_mode": "夜晚模式",
13+
"exit": "退出"
14+
}

lib/app.dart

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_localizations/flutter_localizations.dart';
3+
import 'package:flutter_redux/flutter_redux.dart';
4+
import 'package:flutter_translate/flutter_translate.dart';
5+
import 'package:python_exercise_builder/pages/home_page.dart';
6+
import 'package:python_exercise_builder/redux.dart';
7+
import 'package:redux/redux.dart';
8+
import 'package:redux_logging/redux_logging.dart';
9+
import 'package:redux_thunk/redux_thunk.dart';
10+
11+
// https://github.com/brianegan/flutter_redux/issues/51
12+
// https://github.com/brianegan/flutter_redux/issues/143
13+
Store<AppState> store = Store<AppState>(
14+
reducer,
15+
initialState: AppState.initState(),
16+
middleware: [thunkMiddleware, LoggingMiddleware.printer()],
17+
);
18+
19+
class App extends StatelessWidget {
20+
@override
21+
Widget build(BuildContext context) {
22+
var localizationDelegate = LocalizedApp.of(context).delegate;
23+
return StoreProvider<AppState>(
24+
store: store,
25+
child: StoreConnector<AppState, Store<AppState>>(
26+
converter: (store) => store,
27+
builder: (_, store) {
28+
// print('app build, locale: ${store.state.themeData}, title: ${translate('title')}');
29+
// https://flutterigniter.com/dismiss-keyboard-form-lose-focus/
30+
// https://github.com/flutter/flutter/issues/17895
31+
return GestureDetector(
32+
onTap: () {
33+
print('MaterialApp onTap');
34+
FocusScopeNode currentFocus = FocusScope.of(context);
35+
if (!currentFocus.hasPrimaryFocus) {
36+
// currentFocus.unfocus();
37+
FocusScope.of(context).requestFocus(new FocusNode());
38+
}
39+
},
40+
child: MaterialApp(
41+
locale: store.state.locale,
42+
localizationsDelegates: [
43+
GlobalMaterialLocalizations.delegate,
44+
GlobalWidgetsLocalizations.delegate,
45+
localizationDelegate
46+
],
47+
supportedLocales: localizationDelegate.supportedLocales,
48+
theme: ThemeData(
49+
fontFamily: "romantic_garden, FZLanTingYuan",
50+
primarySwatch: store.state.appThemeData.primarySwatch,
51+
brightness: store.state.appThemeData.brightness,
52+
toggleableActiveColor: store.state.appThemeData.primarySwatch,
53+
accentColor: store.state.appThemeData.primarySwatch,
54+
// see more on https://stackoverflow.com/questions/50196913/how-to-change-navigation-animation-using-flutter
55+
// Add the line below to get horizontal sliding transitions for routes.
56+
pageTransitionsTheme: PageTransitionsTheme(builders: {
57+
TargetPlatform.android: OpenUpwardsPageTransitionsBuilder(),
58+
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
59+
}),
60+
visualDensity: VisualDensity.adaptivePlatformDensity,
61+
),
62+
home: HomePage(title: 'Python Exercise Builder'),
63+
),
64+
);
65+
},
66+
),
67+
);
68+
}
69+
}

lib/flutter_configuration.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import 'package:flutter/services.dart' show rootBundle;
2+
import 'package:yaml_config/yaml_config.dart';
3+
4+
class FlutterConfiguration extends YamlConfig {
5+
String defaultRawTemplate;
6+
String defaultProgramTemplate;
7+
8+
@override
9+
void init() {
10+
defaultRawTemplate = get('defaultRawTemplate');
11+
defaultProgramTemplate = get('defaultProgramTemplate');
12+
print('config parsed with result: ${this}');
13+
}
14+
15+
FlutterConfiguration(String text) : super(text);
16+
17+
static Future<FlutterConfiguration> fromAsset(String asset) {
18+
return rootBundle.loadString(asset).then((text) => FlutterConfiguration(text));
19+
}
20+
21+
@override
22+
String toString() {
23+
return 'FlutterConfiguration{defaultRawTemplate: $defaultRawTemplate, defaultProgramTemplate: $defaultProgramTemplate}';
24+
}
25+
}

lib/main.dart

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,18 @@
11
import 'package:flutter/material.dart';
2-
import 'package:python_exercise_builder/pages/home_page.dart';
2+
import 'package:flutter_translate/flutter_translate.dart';
3+
import 'package:python_exercise_builder/flutter_configuration.dart';
34

4-
void main() {
5-
runApp(App());
6-
}
5+
import 'app.dart';
76

8-
class App extends StatelessWidget {
9-
// This widget is the root of your application.
10-
@override
11-
Widget build(BuildContext context) {
12-
return MaterialApp(
13-
title: 'Flutter Demo',
14-
theme: ThemeData(
15-
primarySwatch: Colors.blue,
16-
visualDensity: VisualDensity.adaptivePlatformDensity,
17-
),
18-
home: HomePage(title: 'Python Exercise Builder'),
19-
);
20-
}
21-
}
7+
/// global configuration from yaml
8+
FlutterConfiguration config;
229

10+
void main() async {
11+
WidgetsFlutterBinding.ensureInitialized();
12+
config = await FlutterConfiguration.fromAsset('assets/config.yaml');
13+
var delegate = await LocalizationDelegate.create(
14+
fallbackLocale: 'en_US',
15+
supportedLocales: ['en_US', 'zh_CN'],
16+
);
17+
runApp(LocalizedApp(delegate, App()));
18+
}

lib/pages/config_page.dart

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_form_builder/flutter_form_builder.dart';
3+
import 'package:flutter_translate/flutter_translate.dart';
4+
import 'package:python_exercise_builder/config.dart';
5+
import 'package:cross_local_storage/cross_local_storage.dart';
6+
import 'package:python_exercise_builder/main.dart';
7+
8+
class ConfigPage extends StatefulWidget {
9+
ConfigPage({Key key}) : super(key: key);
10+
11+
@override
12+
_ConfigPageState createState() => _ConfigPageState();
13+
}
14+
15+
class _ConfigPageState extends State<ConfigPage> {
16+
final GlobalKey<FormBuilderState> _fbKey = GlobalKey<FormBuilderState>();
17+
bool _loading = false;
18+
String rawTemplate, programTemplate;
19+
20+
@override
21+
void initState() {
22+
super.initState();
23+
loadData();
24+
}
25+
26+
void loadData() async {
27+
_loading = true;
28+
var prefs = await LocalStorage.getInstance();
29+
rawTemplate = prefs.getString('rawTemplate') ?? config.defaultRawTemplate;
30+
programTemplate = prefs.getString('programTemplate') ?? config.defaultProgramTemplate;
31+
setState(() {
32+
_loading = false;
33+
});
34+
}
35+
36+
saveData() async {
37+
var prefs = await LocalStorage.getInstance();
38+
await prefs.setString('rawTemplate', rawTemplate);
39+
await prefs.setString('programTemplate', programTemplate);
40+
}
41+
42+
@override
43+
Widget build(BuildContext context) {
44+
var spacer = SizedBox(height: defaultMargin);
45+
return Scaffold(
46+
appBar: AppBar(title: Text(translate('setting'))),
47+
body: _loading
48+
? Center(child: CircularProgressIndicator())
49+
: Padding(
50+
padding: const EdgeInsets.all(defaultMargin),
51+
child: SingleChildScrollView(
52+
child: Column(
53+
children: [
54+
FormBuilder(
55+
key: _fbKey,
56+
initialValue: {
57+
'rawTemplate': rawTemplate,
58+
'programTemplate': programTemplate,
59+
},
60+
autovalidate: true,
61+
child: Column(
62+
children: <Widget>[
63+
FormBuilderTextField(
64+
attribute: "rawTemplate",
65+
maxLines: 10,
66+
decoration: InputDecoration(
67+
labelText: "rawTemplate",
68+
border: const OutlineInputBorder(),
69+
),
70+
),
71+
spacer,
72+
FormBuilderTextField(
73+
attribute: "programTemplate",
74+
maxLines: 10,
75+
decoration: InputDecoration(
76+
labelText: "programTemplate",
77+
border: const OutlineInputBorder(),
78+
),
79+
),
80+
],
81+
),
82+
)
83+
],
84+
),
85+
),
86+
),
87+
floatingActionButton: FloatingActionButton(
88+
child: Icon(Icons.save),
89+
onPressed: () async {
90+
if (_fbKey.currentState.saveAndValidate()) {
91+
rawTemplate = _fbKey.currentState.value['rawTemplate'];
92+
programTemplate = _fbKey.currentState.value['programTemplate'];
93+
saveData();
94+
Navigator.of(context).pop();
95+
}
96+
},
97+
),
98+
);
99+
}
100+
}

lib/pages/home_page.dart

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import 'package:cross_local_storage/cross_local_storage.dart';
12
import 'package:flutter/material.dart';
3+
import 'package:flutter_translate/flutter_translate.dart';
4+
import 'package:python_exercise_builder/main.dart';
25
import 'package:python_exercise_builder/pages/question_page.dart';
36
import 'package:python_exercise_builder/pages/setting_page.dart';
47

@@ -12,9 +15,24 @@ class HomePage extends StatefulWidget {
1215

1316
class _HomePageState extends State<HomePage> {
1417
static List<Widget> _pages = <Widget>[QuestionPage(), SettingPage()];
15-
1618
int _currentIndex = 0;
1719

20+
@override
21+
void initState() {
22+
super.initState();
23+
initialize();
24+
}
25+
26+
initialize() async {
27+
var prefs = await LocalStorage.getInstance();
28+
if (prefs.getString('rawTemplate') == null) {
29+
prefs.setString('rawTemplate', config.defaultRawTemplate);
30+
}
31+
if (prefs.getString('programTemplate') == null) {
32+
prefs.setString('programTemplate', config.defaultProgramTemplate);
33+
}
34+
}
35+
1836
void _onItemTapped(int index) {
1937
setState(() {
2038
_currentIndex = index;
@@ -24,26 +42,25 @@ class _HomePageState extends State<HomePage> {
2442
@override
2543
Widget build(BuildContext context) {
2644
return Scaffold(
27-
body: SafeArea(
28-
child: IndexedStack(
29-
index: _currentIndex,
30-
children: _pages,
31-
),
45+
body: IndexedStack(
46+
sizing: StackFit.expand,
47+
index: _currentIndex,
48+
children: _pages,
3249
),
3350
bottomNavigationBar: BottomNavigationBar(
3451
type: BottomNavigationBarType.fixed,
35-
items: const <BottomNavigationBarItem>[
52+
items: <BottomNavigationBarItem>[
3653
BottomNavigationBarItem(
3754
icon: Icon(
3855
Icons.question_answer,
3956
),
40-
title: Text('Question'),
57+
title: Text(translate('question')),
4158
),
4259
BottomNavigationBarItem(
4360
icon: Icon(
4461
Icons.settings,
4562
),
46-
title: Text('Settings'),
63+
title: Text(translate('setting')),
4764
),
4865
],
4966
currentIndex: _currentIndex,

0 commit comments

Comments
 (0)