route) => false);
22 | });
23 | }
24 |
25 | @override
26 | Widget build(BuildContext context) {
27 | return Scaffold(
28 | backgroundColor: Colors.white,
29 | body: Center(
30 | child: CommonLogo()
31 | )
32 | );
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/assets/lang/lang_zh-CN.json:
--------------------------------------------------------------------------------
1 | {
2 | "global.title": "Flutter脚手架模板",
3 | "global.press.back.again": "继续点击返回退出应用",
4 | "login.title": "Flutter脚手架模板",
5 | "login.input.title": "用户名",
6 | "login.input.notempty.title": "请输入用户名",
7 | "login.input.password": "密码",
8 | "login.input.notempty.password": "请输入密码",
9 | "login.btn.login": "登录",
10 | "common.drawer.theme.setting": "主题设置",
11 | "common.drawer.dashboard": "面板",
12 | "common.drawer.operator.log": "操作记录",
13 | "common.drawer.pda.setting": "设置",
14 | "common.drawer.nothing": "功能还在开发中",
15 | "common.drawer.lang.setting": "语言切换",
16 |
17 | "dashboard.deliver.bill.title": "发货单作业",
18 | "dashboard.deliver.bill.pick": "拣货作业",
19 | "dashboard.deliver.bill.deliver": "发车作业",
20 | "dashboard.deliver.bill.audit": "审核作业",
21 | "dashboard.check.bill.title": "盘点作业",
22 | "dashboard.check.bill.auditing": "盲盘作业",
23 |
24 | "index.deliver.bill.pick.pageTitle": "我的拣货单",
25 | "index.deliver.bill.loading.pageTitle": "发车单页",
26 | "index.deliver.bill.audit.pageTitle": "发货单审核",
27 | "index.check.bill.check.pageTitle": "盘点单--盲盘"
28 | }
--------------------------------------------------------------------------------
/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // This is a basic Flutter widget test.
2 | //
3 | // To perform an interaction with a widget in your test, use the WidgetTester
4 | // utility that Flutter provides. For example, you can send tap and scroll
5 | // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // tree, read text, and verify that the values of widget properties are correct.
7 |
8 | import 'package:flutter_test/flutter_test.dart';
9 |
10 | void main() {
11 | testWidgets('Counter increments smoke test', (WidgetTester tester) async {
12 | // // Build our app and trigger a frame.
13 | // await tester.pumpWidget(MyApp());
14 | //
15 | // // Verify that our counter starts at 0.
16 | // expect(find.text('0'), findsOneWidget);
17 | // expect(find.text('1'), findsNothing);
18 | //
19 | // // Tap the '+' icon and trigger a frame.
20 | // await tester.tap(find.byIcon(Icons.add));
21 | // await tester.pump();
22 | //
23 | // // Verify that our counter has incremented.
24 | // expect(find.text('0'), findsNothing);
25 | // expect(find.text('1'), findsOneWidget);
26 | });
27 | }
28 |
--------------------------------------------------------------------------------
/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java:
--------------------------------------------------------------------------------
1 | package io.flutter.plugins;
2 |
3 | import io.flutter.plugin.common.PluginRegistry;
4 | import io.github.ponnamkarthik.toast.fluttertoast.FluttertoastPlugin;
5 | import io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin;
6 |
7 | /**
8 | * Generated file. Do not edit.
9 | */
10 | public final class GeneratedPluginRegistrant {
11 | public static void registerWith(PluginRegistry registry) {
12 | if (alreadyRegisteredWith(registry)) {
13 | return;
14 | }
15 | FluttertoastPlugin.registerWith(registry.registrarFor("io.github.ponnamkarthik.toast.fluttertoast.FluttertoastPlugin"));
16 | SharedPreferencesPlugin.registerWith(registry.registrarFor("io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin"));
17 | }
18 |
19 | private static boolean alreadyRegisteredWith(PluginRegistry registry) {
20 | final String key = GeneratedPluginRegistrant.class.getCanonicalName();
21 | if (registry.hasPlugin(key)) {
22 | return true;
23 | }
24 | registry.registrarFor(key);
25 | return false;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/lib/mock/mock_data/user_data.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_cli_project/infrastructure/base_model/PbResultDto.pb.dart';
2 | import 'package:flutter_cli_project/infrastructure/base_model/google/protobuf/any.pb.dart';
3 | import 'package:flutter_cli_project/login/dto/UserAuthenticateDto.pb.dart';
4 | import 'package:protobuf/protobuf.dart' as $pb;
5 |
6 | PbResultDto testMock({
7 | P body,
8 | Map param
9 | }) {
10 | PbResultDto r = PbResultDto();
11 | r.success = true;
12 | r.message = 'testMock';
13 | return r;
14 | }
15 |
16 | PbResultDto userAuthenticate({
17 | P body,
18 | Map param
19 | }) {
20 | UserAuthenticateReqDto req = body as UserAuthenticateReqDto;
21 | UserAuthenticateRespDto r = UserAuthenticateRespDto();
22 | if (req.userName == 'Weidan') {
23 | r.token = '112233';
24 | r.resourceCodes.addAll(['deliverBillPick', 'deliverBillPick2']);
25 | } else {
26 | r.token = '334455';
27 | r.resourceCodes.addAll(['deliverBillPick2']);
28 | }
29 |
30 | PbResultDto pbResultDto = PbResultDto();
31 | pbResultDto.data = Any.pack(r);
32 | return pbResultDto;
33 | }
--------------------------------------------------------------------------------
/lib/infrastructure/ioc_container.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_cli_project/infrastructure/net_tool_box.dart';
2 | import 'package:flutter_cli_project/repository/user_repository.dart';
3 |
4 | class IocContainer {
5 |
6 | static Map _beanMap = {
7 | 'userRepository': UserRepository(),
8 | 'INetTool': null,
9 | '_instance': IocContainer()
10 | };
11 |
12 | static dynamic getBean(String beanName) {
13 | var bean = _beanMap[beanName];
14 | if (bean == null) {
15 | _beanMap[beanName] = _initBean(beanName);
16 | bean = _beanMap[beanName];
17 | if (bean == null) {
18 | throw ArgumentError('bean not found!');
19 | }
20 | }
21 |
22 | return bean;
23 | }
24 |
25 | UserRepository get userRepository {
26 | return getBean('userRepository');
27 | }
28 |
29 | INetTool get netTool {
30 | return getBean('INetTool');
31 | }
32 |
33 | static instance() {
34 | return getBean('_instance');
35 | }
36 |
37 | static dynamic _initBean(String beanName) {
38 | switch (beanName) {
39 | case 'INetTool':
40 | return NetToolFactory.create();
41 | default:
42 | return null;
43 | }
44 |
45 | }
46 |
47 | }
--------------------------------------------------------------------------------
/assets/lang/lang_en-US.json:
--------------------------------------------------------------------------------
1 | {
2 | "global.title": "Flutter Cli Project",
3 | "global.press.back.again": "Press again to cancel the APP.",
4 | "login.title": "Flutter Cli Project",
5 | "login.input.title": "UserName",
6 | "login.input.notempty.title": "please input UserName",
7 | "login.input.password": "Password",
8 | "login.input.notempty.password": "please input Password",
9 | "login.btn.login": "Login",
10 | "common.drawer.theme.setting": "Theme Setting",
11 | "common.drawer.dashboard": "Dashboard",
12 | "common.drawer.operator.log": "Operator Log",
13 | "common.drawer.pda.setting": "Setting",
14 | "common.drawer.nothing": "Sorry, it can not service now.",
15 | "common.drawer.lang.setting": "Language Switch",
16 |
17 |
18 | "dashboard.deliver.bill.title": "Deliver Task",
19 | "dashboard.deliver.bill.pick": "Pick Task",
20 | "dashboard.deliver.bill.deliver": "Driving Task",
21 | "dashboard.deliver.bill.audit": "Audit Task",
22 | "dashboard.check.bill.title": "Check Bill Task",
23 | "dashboard.check.bill.auditing": "Check Task",
24 |
25 | "index.deliver.bill.pick.pageTitle": "My Deliver Bill",
26 | "index.deliver.bill.loading.pageTitle": "Loading Task",
27 | "index.deliver.bill.audit.pageTitle": "Deliver Bill Audit Task",
28 | "index.check.bill.check.pageTitle": "My Check Bill"
29 | }
--------------------------------------------------------------------------------
/lib/main_app/notfound_page.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_cli_project/components/common_scaffold.dart';
3 | import 'package:flutter_cli_project/components/profile_tile.dart';
4 |
5 | class NotFoundPage extends StatelessWidget {
6 | final appTitle;
7 | final title;
8 | final message;
9 | final IconData icon;
10 | final String image;
11 | final iconColor;
12 |
13 | NotFoundPage(
14 | {this.appTitle = "无人区",
15 | this.title = "走丢啦~~~",
16 | this.message = "页面没有找到,可能是迷路了",
17 | this.icon = Icons.map,
18 | this.image,
19 | this.iconColor = Colors.black});
20 |
21 | Widget bodyData() => Center(
22 | child: Column(
23 | mainAxisAlignment: MainAxisAlignment.center,
24 | children: [
25 | Icon(
26 | icon,
27 | size: 100.0,
28 | color: iconColor,
29 | ),
30 | SizedBox(
31 | height: 20.0,
32 | ),
33 | ProfileTile(
34 | title: title,
35 | subtitle: message,
36 | )
37 | ],
38 | ),
39 | );
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return CommonScaffold(
44 | body: bodyData(),
45 | showDrawer: false,
46 | title: appTitle,
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/lib/infrastructure/context_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/widgets.dart';
2 |
3 | class CurrentPageContext {
4 |
5 | static BuildContext context;
6 |
7 | static void set(BuildContext context) {
8 | CurrentPageContext.context = context;
9 | }
10 |
11 | static BuildContext get() {
12 | return CurrentPageContext.context;
13 | }
14 |
15 | }
16 |
17 | /// 用于有状态的页面的Context父类,可以用于记录当前的BuildContext
18 | abstract class PageStateFul extends StatefulWidget {
19 |
20 | @override
21 | State createState() {
22 | State state = createState0();
23 | CurrentPageContext.set(state.context);
24 | return state;
25 | }
26 |
27 | State createState0();
28 |
29 | }
30 |
31 | abstract class PageStateLess extends StatelessWidget {
32 |
33 | @override
34 | Widget build(BuildContext context) {
35 | CurrentPageContext.set(context);
36 | var widget = build0(context);
37 | return widget;
38 | }
39 |
40 | Widget build0(BuildContext context);
41 |
42 | }
43 |
44 | abstract class Page extends PageStateLess {
45 |
46 | final String routerPath;
47 |
48 | Page(this.routerPath);
49 |
50 | @override
51 | Widget build(BuildContext context) {
52 | return Hero(
53 | tag: routerPath,
54 | child: super.build(context),
55 | );
56 | }
57 |
58 | Widget build0(BuildContext context);
59 |
60 | }
--------------------------------------------------------------------------------
/test/net_tool_box_test.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter_test/flutter_test.dart';
2 | import 'package:flutter_cli_project/infrastructure/base_model/PbResultDto.pb.dart';
3 | import 'package:flutter_cli_project/infrastructure/net_tool_box.dart';
4 | import 'package:flutter_cli_project/mock/mock_holder.dart';
5 |
6 | void main() {
7 |
8 | // 需要配合后端
9 | test('GET请求测试', () async {
10 | var future = await NetTool().get('http://127.0.0.1:8205/pbtest');
11 | print(future.success);
12 | });
13 |
14 | // 需要配合后端
15 | test('POST请求测试', () async {
16 | var req = PbResultDto();
17 | req.message = '测试调用POSTJSON';
18 |
19 | var future = await NetTool().post('http://127.0.0.1:8205/pbtest', request: req);
20 | print(future.message);
21 | });
22 |
23 | // Mock测试
24 | INetTool mockNetTool = MockNetTool();
25 | MockData.initRouter();
26 |
27 | test('测试Mock请求工具', () async {
28 | var result = await mockNetTool.post('/v1/user/login');
29 | expect('testMock', result.message);
30 |
31 | result = await mockNetTool.post('/v1/user/login?b=2&a=1');
32 | expect('testMock', result.message);
33 |
34 | result = await mockNetTool.post('/v1/user/login?a=1&b=2');
35 | expect('testMock', result.message);
36 |
37 | result = await mockNetTool.post('/v1/user/login', queryParameters: {'a': '1', 'b': '2'});
38 | expect('testMock', result.message);
39 |
40 | });
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/lib/main_app/system_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:bloc/bloc.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter_cli_project/infrastructure/i18n_box.dart';
6 | import 'package:flutter_cli_project/personal/themes.dart';
7 |
8 | class SystemState{
9 |
10 | ThemeData theme;
11 | I18nBox i18nBox;
12 |
13 | SystemState(this.theme, this.i18nBox);
14 |
15 | }
16 |
17 | enum SystemAction { toggle_lang, toggle_theme }
18 |
19 | class SystemEvent {
20 |
21 | SystemAction _action;
22 | dynamic _data;
23 |
24 | SystemEvent(this._action, this._data);
25 |
26 | dynamic get data => _data;
27 |
28 | SystemAction get action => _action;
29 |
30 | }
31 |
32 | class SystemBloc extends Bloc {
33 |
34 | @override
35 | SystemState get initialState => SystemState(Themes.blackTheme, I18nBox.emptyInstance());
36 |
37 | @override
38 | Stream mapEventToState(SystemEvent event) async* {
39 | switch (event.action) {
40 | case SystemAction.toggle_lang:
41 | final _i18nBox = event.data as I18nBox;
42 | final _theme = state.theme;
43 | yield SystemState(_theme, _i18nBox);
44 | break;
45 | case SystemAction.toggle_theme:
46 | final _theme = event.data as ThemeData;
47 | final _i18nBox = state.i18nBox;
48 | yield SystemState(_theme, _i18nBox);
49 | break;
50 | }
51 | }
52 |
53 |
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/lib/infrastructure/profiles_loader.dart:
--------------------------------------------------------------------------------
1 | import 'dart:convert';
2 |
3 | import 'package:flutter/material.dart';
4 |
5 | import 'context_util.dart';
6 |
7 | /// 配置文件的读取器
8 | class ProfilesLoader {
9 |
10 | static Map _profileMap = {};
11 | static bool _isInit = false;
12 |
13 | static initProfile() async {
14 | if (!_isInit) {
15 | String profileJson = await DefaultAssetBundle
16 | .of(CurrentPageContext.get())
17 | .loadString('assets/profile-config.json');
18 | Map allProfile = JsonDecoder().convert(profileJson);
19 |
20 | _profileMap = Map();
21 | final String profileActive = allProfile['profile.active'];
22 |
23 | allProfile.forEach((key, value) {
24 | if (key == 'profile.active') {
25 | _profileMap['profile'] = value;
26 | return;
27 | }
28 | if (!key.contains(profileActive)) {
29 | return;
30 | }
31 | String pKey = key.substring(0, key.indexOf('.' + profileActive));
32 | _profileMap[pKey] = value;
33 | });
34 | _isInit = true;
35 | }
36 | }
37 |
38 | static profileActive() {
39 | return keyOf('profile');
40 | }
41 |
42 | static keyOf(String profileKey) {
43 | String value;
44 | do {
45 | if (_isInit) {
46 | value = _profileMap[profileKey];
47 | }
48 | } while(!_isInit);
49 |
50 | return value;
51 | }
52 |
53 | }
54 |
55 | class ProfileKeys {
56 | static const BASE_URL = 'baseURL';
57 | }
--------------------------------------------------------------------------------
/lib/repository/user_repository.dart:
--------------------------------------------------------------------------------
1 |
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_cli_project/infrastructure/ioc_container.dart';
4 | import 'package:flutter_cli_project/infrastructure/net_tool_box.dart';
5 | import 'package:flutter_cli_project/login/dto/UserAuthenticateDto.pb.dart';
6 |
7 | /// 用户数据仓库
8 | class UserRepository {
9 |
10 | /// 认证
11 | /// @param username 用户名
12 | /// @param password 密码
13 | /// @return 返回认证信息
14 | Future authenticate({
15 | @required String username,
16 | @required String password,
17 | }) async {
18 | INetTool netTool = IocContainer.instance().netTool;
19 | var req = UserAuthenticateReqDto();
20 | req.userName = username;
21 | req.password = password;
22 | var pbResult = await netTool.post('/v1/authenticate/login', request: req);
23 | var userAuthenticateRespDto = pbResult.data.unpackInto(UserAuthenticateRespDto());
24 | return userAuthenticateRespDto;
25 | }
26 |
27 | /// 删除Token
28 | Future deleteToToken() async {
29 | await Future.delayed(Duration(seconds: 1));
30 | return ;
31 | }
32 |
33 | /// 保存Token
34 | /// @param token 令牌
35 | Future persistToken(String token) async {
36 | // 保存
37 | await Future.delayed(Duration(seconds: 1));
38 | return ;
39 | }
40 |
41 | /// 判断是否有Token
42 | /// @return true: 有; false: 没有Token
43 | Future hasToken() async {
44 | // 读取Token
45 | await Future.delayed(Duration(seconds: 1));
46 | return false;
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/lib/infrastructure/base_model/PbResultDto.pbjson.dart:
--------------------------------------------------------------------------------
1 | ///
2 | // Generated code. Do not modify.
3 | // source: PbResultDto.proto
4 | //
5 | // @dart = 2.3
6 | // ignore_for_file: camel_case_types,non_constant_identifier_names,library_prefixes,unused_import,unused_shown_name,return_of_invalid_type
7 |
8 | const PbResultDto$json = const {
9 | '1': 'PbResultDto',
10 | '2': const [
11 | const {'1': 'success', '3': 1, '4': 1, '5': 8, '10': 'success'},
12 | const {'1': 'message', '3': 2, '4': 1, '5': 9, '10': 'message'},
13 | const {'1': 'code', '3': 3, '4': 1, '5': 9, '10': 'code'},
14 | const {'1': 'data', '3': 4, '4': 1, '5': 11, '6': '.google.protobuf.Any', '10': 'data'},
15 | const {'1': 'extra', '3': 5, '4': 3, '5': 11, '6': '.PbResultDto.ExtraEntry', '10': 'extra'},
16 | ],
17 | '3': const [PbResultDto_ExtraEntry$json],
18 | };
19 |
20 | const PbResultDto_ExtraEntry$json = const {
21 | '1': 'ExtraEntry',
22 | '2': const [
23 | const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
24 | const {'1': 'value', '3': 2, '4': 1, '5': 11, '6': '.ExtraMap', '10': 'value'},
25 | ],
26 | '7': const {'7': true},
27 | };
28 |
29 | const ExtraMap$json = const {
30 | '1': 'ExtraMap',
31 | '2': const [
32 | const {'1': 'extra', '3': 1, '4': 3, '5': 11, '6': '.ExtraMap.ExtraEntry', '10': 'extra'},
33 | ],
34 | '3': const [ExtraMap_ExtraEntry$json],
35 | };
36 |
37 | const ExtraMap_ExtraEntry$json = const {
38 | '1': 'ExtraEntry',
39 | '2': const [
40 | const {'1': 'key', '3': 1, '4': 1, '5': 9, '10': 'key'},
41 | const {'1': 'value', '3': 2, '4': 1, '5': 9, '10': 'value'},
42 | ],
43 | '7': const {'7': true},
44 | };
45 |
46 |
--------------------------------------------------------------------------------
/ios/Runner/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/android/front_imopei_pda_android.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_cli_project
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | $(FLUTTER_BUILD_NAME)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(FLUTTER_BUILD_NUMBER)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UISupportedInterfaceOrientations
30 |
31 | UIInterfaceOrientationPortrait
32 | UIInterfaceOrientationLandscapeLeft
33 | UIInterfaceOrientationLandscapeRight
34 |
35 | UISupportedInterfaceOrientations~ipad
36 |
37 | UIInterfaceOrientationPortrait
38 | UIInterfaceOrientationPortraitUpsideDown
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UIViewControllerBasedStatusBarAppearance
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/lib/personal/index.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/widgets.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:flutter_cli_project/infrastructure/context_util.dart';
5 | import 'package:flutter_cli_project/infrastructure/toast_tool.dart';
6 | import 'package:flutter_cli_project/login/login_page.dart';
7 | import 'package:flutter_cli_project/main_app/authenticate_bloc.dart';
8 | import 'package:flutter_cli_project/personal/dashboard_page.dart';
9 |
10 | class HomePage extends PageStateLess {
11 |
12 | @override
13 | Widget build0(BuildContext context) {
14 | return BlocBuilder(
15 | builder: (context, state) {
16 | return state is AuthenticationAuthenticated ?
17 | _dashboardPage() : LoginPage();
18 | }
19 | );
20 | }
21 |
22 | _dashboardPage() {
23 | return _PopContainer();
24 | }
25 |
26 | }
27 |
28 | class _PopContainer extends PageStateFul {
29 |
30 | @override
31 | State createState0() {
32 | return _PopContainerState();
33 | }
34 |
35 | }
36 |
37 | class _PopContainerState extends State<_PopContainer> {
38 |
39 | DateTime _lastBackDateTime;
40 |
41 | @override
42 | Widget build(BuildContext context) {
43 | return WillPopScope(
44 | onWillPop: () async {
45 | if (_lastBackDateTime == null ||
46 | DateTime.now().difference(_lastBackDateTime) > Duration(seconds: 1)) {
47 | //两次点击间隔超过1秒则重新计时
48 | _lastBackDateTime = DateTime.now();
49 |
50 | ToastTool.shortOfKey('global.press.back.again');
51 | return false;
52 | }
53 | return true;
54 | },
55 | child: DashboardPage()
56 | );
57 | }
58 |
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/lib/infrastructure/dialog_util.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | import 'context_util.dart';
4 |
5 | typedef OkCallBack = void Function();
6 |
7 | /// 弹窗工具类
8 | class DialogUtil {
9 |
10 | /// 一个简单的弹窗,一般用于完成一个命令请求后提示成功的行为.
11 | static simpleDialog(String title, String content, {
12 | BuildContext context
13 | }) {
14 | BuildContext _context = context ?? CurrentPageContext.get();
15 | showDialog(
16 | context: _context,
17 | builder: (context) => AlertDialog(
18 | title: Text(title),
19 | content: Text(content),
20 | actions: [
21 | FlatButton(
22 | child: Text('Ok'),
23 | onPressed: () {
24 | Navigator.of(context).pop();
25 | },
26 | )
27 | ]
28 | )
29 | );
30 | }
31 |
32 | /// 确认弹窗,一般用于点击一个命令按钮之前的提示是否确认执行的行为.
33 | static confirmDialog(
34 | String title,
35 | String content,
36 | OkCallBack okCallBack, {
37 | BuildContext context
38 | }) {
39 | BuildContext _context = context ?? CurrentPageContext.get();
40 | showDialog(
41 | context: _context,
42 | builder: (context) =>
43 | AlertDialog(
44 | title: Text(title),
45 | content: Text(content),
46 | actions: [
47 | FlatButton(
48 | child: Text('Ok'),
49 | onPressed: () {
50 | okCallBack();
51 | },
52 | ),
53 | FlatButton(
54 | child: Text('取消'),
55 | onPressed: () {
56 | Navigator.of(context).pop();
57 | },
58 | )
59 | ]
60 | )
61 | );
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
13 |
20 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/lib/main_app/routes.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_cli_project/personal/index.dart';
3 | import 'package:flutter_cli_project/personal/theme_setting.dart';
4 | import 'package:flutter_cli_project/services/check_bill/check_bill_index.dart';
5 | import 'package:flutter_cli_project/services/check_bill/check_bill_routers.dart';
6 | import 'package:flutter_cli_project/services/deliver_bill_pick/deliver_bill_routers.dart';
7 | import 'package:flutter_cli_project/services/deliver_bill_pick/loading_index.dart';
8 | import 'package:flutter_cli_project/services/deliver_bill_pick/pick_index.dart';
9 |
10 | import 'notfound_page.dart';
11 |
12 | class Routes {
13 |
14 | /// 路由信息
15 | static final Map _routes = {
16 | '/themeSetting': (BuildContext context) => ThemeSetting(),
17 | '/main': (BuildContext context) => HomePage(),
18 | DeliverBillPickIndexConst.pickIndexPath: (BuildContext context) => PickIndex(),
19 | DeliverBillPickIndexConst.loadingIndexPath: (BuildContext context) => LoadingIndex(),
20 | DeliverBillPickIndexConst.auditIndexPath: (BuildContext context) => CheckBillIndex(),
21 | CheckBillIndexConst.checkBillIndexPath: (BuildContext context) => CheckBillIndex(),
22 | };
23 |
24 | /// 路由拦截
25 | static Route routeGenerator(RouteSettings settings, BuildContext buildContext) {
26 | final String name = settings.name;
27 | final Function pageBuilder = _routes[name];
28 | if (pageBuilder != null) {
29 | if (settings.arguments != null) {
30 | // 如果透传了参数
31 | return MaterialPageRoute(
32 | builder: (context) =>
33 | pageBuilder(context, arguments: settings.arguments));
34 | } else {
35 | // 没有透传参数
36 | return MaterialPageRoute(builder: (context) => pageBuilder(context));
37 | }
38 | }
39 | return MaterialPageRoute(builder: (context) => NotFoundPage());
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_bloc/flutter_bloc.dart';
3 | import 'package:flutter_cli_project/infrastructure/i18n_box.dart';
4 | import 'package:flutter_cli_project/infrastructure/profiles_loader.dart';
5 | import 'package:flutter_cli_project/main_app/routes.dart';
6 | import 'package:flutter_cli_project/repository/user_repository.dart';
7 |
8 | import 'infrastructure/context_util.dart';
9 | import 'infrastructure/ioc_container.dart';
10 | import 'main_app/authenticate_bloc.dart';
11 | import 'main_app/system_bloc.dart';
12 | import 'splash_page.dart';
13 |
14 | void main() => runApp(MyApp());
15 |
16 | class MyApp extends PageStateLess {
17 |
18 | Future setupGlobalBloc(BuildContext context) async {
19 | try {
20 | // 初始化i18n
21 | final I18nBox i18nBox = await I18nBox.getInstance();
22 | var systemBloc = context.bloc();
23 | systemBloc.add(SystemEvent(SystemAction.toggle_lang, i18nBox));
24 | // 初始化 profile_loader
25 | ProfilesLoader.initProfile();
26 | } catch (e) {
27 | }
28 | }
29 |
30 | @override
31 | Widget build0(BuildContext context) {
32 | UserRepository userRepository = IocContainer.instance().userRepository;
33 |
34 | return MultiBlocProvider(
35 | providers: [
36 | BlocProvider(
37 | create: (BuildContext context) => SystemBloc(),
38 | ),
39 | BlocProvider(
40 | create: (BuildContext context) => AuthenticationBloc(
41 | userRepository: userRepository
42 | ),
43 | ),
44 | ],
45 | child: BlocBuilder(
46 | builder: (_, state) {
47 | setupGlobalBloc(_);
48 | return MaterialApp(
49 | theme: state.theme,
50 | home: SplashPage(),
51 | onGenerateRoute: (RouteSettings settings) {
52 | return Routes.routeGenerator(settings, _);
53 | },
54 | );
55 | },
56 | )
57 | );
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/lib/personal/theme_setting.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/src/widgets/framework.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:flutter_cli_project/components/common_scaffold.dart';
5 | import 'package:flutter_cli_project/infrastructure/context_util.dart';
6 | import 'package:flutter_cli_project/main_app/system_bloc.dart';
7 | import 'package:flutter_cli_project/personal/themes.dart';
8 |
9 | class ThemeSetting extends PageStateLess {
10 |
11 | @override
12 | Widget build0(BuildContext context) {
13 | return BlocBuilder(
14 | builder: (_, state) {
15 | return CommonScaffold(
16 | body: ListView(
17 | children: [
18 | ListTile(
19 | title: Text(
20 | "暗夜黑(推荐)",
21 | style: TextStyle(
22 | fontWeight: FontWeight.w100, fontSize: 18.0),
23 | ),
24 | leading: Icon(
25 | Icons.bookmark,
26 | color: Colors.blue,
27 | ),
28 | onTap: () {
29 | _switchTheme(context, Themes.blackTheme);
30 | },
31 | ),
32 | ListTile(
33 | title: Text(
34 | "骚气白",
35 | style: TextStyle(
36 | fontWeight: FontWeight.w100, fontSize: 18.0),
37 | ),
38 | leading: Icon(
39 | Icons.collections,
40 | color: Colors.blue,
41 | ),
42 | onTap: () {
43 | _switchTheme(context, Themes.kIOSTheme);
44 | },
45 | ),
46 | ]
47 | ),
48 | );
49 | },
50 | );
51 | }
52 |
53 | void _switchTheme(BuildContext context, ThemeData themeData) {
54 | var systemBloc = context.bloc();
55 | systemBloc.add(SystemEvent(SystemAction.toggle_theme, themeData));
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/.idea/libraries/Dart_SDK.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/android/app/build.gradle:
--------------------------------------------------------------------------------
1 | def localProperties = new Properties()
2 | def localPropertiesFile = rootProject.file('local.properties')
3 | if (localPropertiesFile.exists()) {
4 | localPropertiesFile.withReader('UTF-8') { reader ->
5 | localProperties.load(reader)
6 | }
7 | }
8 |
9 | def flutterRoot = localProperties.getProperty('flutter.sdk')
10 | if (flutterRoot == null) {
11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
12 | }
13 |
14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
15 | if (flutterVersionCode == null) {
16 | flutterVersionCode = '1'
17 | }
18 |
19 | def flutterVersionName = localProperties.getProperty('flutter.versionName')
20 | if (flutterVersionName == null) {
21 | flutterVersionName = '1.0'
22 | }
23 |
24 | apply plugin: 'com.android.application'
25 | apply plugin: 'kotlin-android'
26 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
27 |
28 | android {
29 | compileSdkVersion 28
30 |
31 | sourceSets {
32 | main.java.srcDirs += 'src/main/kotlin'
33 | }
34 |
35 | lintOptions {
36 | disable 'InvalidPackage'
37 | }
38 |
39 | defaultConfig {
40 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
41 | applicationId "com.jingchuan.imopei.flutter_cli_project"
42 | minSdkVersion 16
43 | targetSdkVersion 28
44 | versionCode flutterVersionCode.toInteger()
45 | versionName flutterVersionName
46 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
47 | }
48 |
49 | buildTypes {
50 | release {
51 | // TODO: Add your own signing config for the release build.
52 | // Signing with the debug keys for now, so `flutter run --release` works.
53 | signingConfig signingConfigs.debug
54 | }
55 | }
56 | }
57 |
58 | flutter {
59 | source '../..'
60 | }
61 |
62 | dependencies {
63 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
64 | testImplementation 'junit:junit:4.12'
65 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
66 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
67 | }
68 |
--------------------------------------------------------------------------------
/lib/login/login_bloc.dart:
--------------------------------------------------------------------------------
1 | import 'package:equatable/equatable.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_bloc/flutter_bloc.dart';
4 | import 'package:flutter_cli_project/infrastructure/ioc_container.dart';
5 | import 'package:flutter_cli_project/main_app/authenticate_bloc.dart';
6 | import 'package:flutter_cli_project/repository/user_repository.dart';
7 |
8 | import 'dto/UserAuthenticateDto.pb.dart';
9 |
10 | /// 登录状态
11 | @immutable
12 | abstract class LoginState extends Equatable {
13 |
14 | const LoginState();
15 |
16 | @override
17 | List