diff --git a/assets/images/navbar_logo.svg b/assets/images/navbar_logo.svg
new file mode 100644
index 0000000..2aa53ef
--- /dev/null
+++ b/assets/images/navbar_logo.svg
@@ -0,0 +1,103 @@
+
+
+
+
diff --git a/assets/images/not_found.png b/assets/images/not_found.png
new file mode 100644
index 0000000..bbe50f0
Binary files /dev/null and b/assets/images/not_found.png differ
diff --git a/fonts/company.ttf b/fonts/company.ttf
new file mode 100644
index 0000000..bdcafb4
Binary files /dev/null and b/fonts/company.ttf differ
diff --git a/fonts/wisetronic.ttf b/fonts/wisetronic.ttf
new file mode 100644
index 0000000..f6b6f81
Binary files /dev/null and b/fonts/wisetronic.ttf differ
diff --git a/lib/constants.dart b/lib/constants.dart
new file mode 100644
index 0000000..cbb2a96
--- /dev/null
+++ b/lib/constants.dart
@@ -0,0 +1,8 @@
+
+class Constants {
+ static const bool DEBUG = false;
+ static const BASE_API_URL = 'https://api.minipos.us/';
+ static const String API_SECRET = 'pei326sami1223HellowWorldabcdEd';
+ static const KEY_USER_ID = 'user_id';
+ static const KEY_ACCESS_TOKEN = 'access_token';
+}
\ No newline at end of file
diff --git a/lib/events/eventbus.dart b/lib/events/eventbus.dart
new file mode 100644
index 0000000..28ff482
--- /dev/null
+++ b/lib/events/eventbus.dart
@@ -0,0 +1,4 @@
+
+import 'package:event_bus/event_bus.dart';
+
+final eventBus = new EventBus();
\ No newline at end of file
diff --git a/lib/events/events.dart b/lib/events/events.dart
new file mode 100644
index 0000000..1bd8007
--- /dev/null
+++ b/lib/events/events.dart
@@ -0,0 +1,4 @@
+
+class OpenDrawer {
+
+}
\ No newline at end of file
diff --git a/lib/generated/intl/messages_all.dart b/lib/generated/intl/messages_all.dart
index b285749..531e7cd 100644
--- a/lib/generated/intl/messages_all.dart
+++ b/lib/generated/intl/messages_all.dart
@@ -16,16 +16,20 @@ import 'package:intl/message_lookup_by_library.dart';
import 'package:intl/src/intl_helpers.dart';
import 'messages_en.dart' as messages_en;
+import 'messages_zh_CN.dart' as messages_zh_cn;
typedef Future LibraryLoader();
Map _deferredLibraries = {
'en': () => new Future.value(null),
+ 'zh_CN': () => new Future.value(null),
};
MessageLookupByLibrary _findExact(String localeName) {
switch (localeName) {
case 'en':
return messages_en.messages;
+ case 'zh_CN':
+ return messages_zh_cn.messages;
default:
return null;
}
diff --git a/lib/generated/intl/messages_en.dart b/lib/generated/intl/messages_en.dart
index 26a77ab..90384e9 100644
--- a/lib/generated/intl/messages_en.dart
+++ b/lib/generated/intl/messages_en.dart
@@ -21,6 +21,35 @@ class MessageLookup extends MessageLookupByLibrary {
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => {
-
+ "about" : MessageLookupByLibrary.simpleMessage("About"),
+ "about_us" : MessageLookupByLibrary.simpleMessage("About us"),
+ "blog" : MessageLookupByLibrary.simpleMessage("Blog"),
+ "contact_us" : MessageLookupByLibrary.simpleMessage("Contact us"),
+ "developer_of" : MessageLookupByLibrary.simpleMessage("Developers of"),
+ "download" : MessageLookupByLibrary.simpleMessage("Download"),
+ "home" : MessageLookupByLibrary.simpleMessage("Home"),
+ "information" : MessageLookupByLibrary.simpleMessage("Information"),
+ "learn_more" : MessageLookupByLibrary.simpleMessage("Learn more..."),
+ "license_agreement" : MessageLookupByLibrary.simpleMessage("License agreement"),
+ "loading_please_wait" : MessageLookupByLibrary.simpleMessage("Loading, please wait..."),
+ "login" : MessageLookupByLibrary.simpleMessage("Login"),
+ "logout" : MessageLookupByLibrary.simpleMessage("Logout"),
+ "main_content_1" : MessageLookupByLibrary.simpleMessage("Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products."),
+ "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"),
+ "navigation" : MessageLookupByLibrary.simpleMessage("Navigation"),
+ "point_of_sale_system_solution" : MessageLookupByLibrary.simpleMessage("Point of sale system solution"),
+ "privacy_policy" : MessageLookupByLibrary.simpleMessage("Privacy policy"),
+ "recalculating" : MessageLookupByLibrary.simpleMessage("Recalculating..."),
+ "renew_license" : MessageLookupByLibrary.simpleMessage("Renew license"),
+ "return_policy" : MessageLookupByLibrary.simpleMessage("Return policy"),
+ "service_policy" : MessageLookupByLibrary.simpleMessage("Service policy"),
+ "shop" : MessageLookupByLibrary.simpleMessage("Shop"),
+ "submitting" : MessageLookupByLibrary.simpleMessage("Submitting..."),
+ "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("Submitting, please wait..."),
+ "support" : MessageLookupByLibrary.simpleMessage("Support"),
+ "support_ticket" : MessageLookupByLibrary.simpleMessage("Support ticket"),
+ "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("Tap back again to exit"),
+ "tutorials" : MessageLookupByLibrary.simpleMessage("Tutorials"),
+ "wiki" : MessageLookupByLibrary.simpleMessage("Wiki")
};
}
diff --git a/lib/generated/intl/messages_zh_CN.dart b/lib/generated/intl/messages_zh_CN.dart
new file mode 100644
index 0000000..6332746
--- /dev/null
+++ b/lib/generated/intl/messages_zh_CN.dart
@@ -0,0 +1,55 @@
+// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
+// This is a library that provides messages for a zh_CN locale. All the
+// messages from the main program should be duplicated here with the same
+// function name.
+
+// Ignore issues from commonly used lints in this file.
+// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
+// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
+// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
+// ignore_for_file:unused_import, file_names
+
+import 'package:intl/intl.dart';
+import 'package:intl/message_lookup_by_library.dart';
+
+final messages = new MessageLookup();
+
+typedef String MessageIfAbsent(String messageStr, List args);
+
+class MessageLookup extends MessageLookupByLibrary {
+ String get localeName => 'zh_CN';
+
+ final messages = _notInlinedMessages(_notInlinedMessages);
+ static _notInlinedMessages(_) => {
+ "about" : MessageLookupByLibrary.simpleMessage("关于"),
+ "about_us" : MessageLookupByLibrary.simpleMessage("关于我们"),
+ "blog" : MessageLookupByLibrary.simpleMessage("博客"),
+ "contact_us" : MessageLookupByLibrary.simpleMessage("联系我们"),
+ "developer_of" : MessageLookupByLibrary.simpleMessage("开发者"),
+ "download" : MessageLookupByLibrary.simpleMessage("下载"),
+ "home" : MessageLookupByLibrary.simpleMessage("首页"),
+ "information" : MessageLookupByLibrary.simpleMessage("信息"),
+ "learn_more" : MessageLookupByLibrary.simpleMessage("了解更多..."),
+ "license_agreement" : MessageLookupByLibrary.simpleMessage("许可协议"),
+ "loading_please_wait" : MessageLookupByLibrary.simpleMessage("装载中,清稍候..."),
+ "login" : MessageLookupByLibrary.simpleMessage("登入"),
+ "logout" : MessageLookupByLibrary.simpleMessage("登出"),
+ "main_content_1" : MessageLookupByLibrary.simpleMessage("自从1999年来,我们一直致力于开发完整的强大的销售系统,帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。"),
+ "minipos" : MessageLookupByLibrary.simpleMessage("MiniPOS"),
+ "navigation" : MessageLookupByLibrary.simpleMessage("导航"),
+ "point_of_sale_system_solution" : MessageLookupByLibrary.simpleMessage("收款系统方案"),
+ "privacy_policy" : MessageLookupByLibrary.simpleMessage("私隐条款"),
+ "recalculating" : MessageLookupByLibrary.simpleMessage("运算中..."),
+ "renew_license" : MessageLookupByLibrary.simpleMessage("证书续期"),
+ "return_policy" : MessageLookupByLibrary.simpleMessage("退货条款"),
+ "service_policy" : MessageLookupByLibrary.simpleMessage("服务条款"),
+ "shop" : MessageLookupByLibrary.simpleMessage("线上购买"),
+ "submitting" : MessageLookupByLibrary.simpleMessage("提交中..."),
+ "submitting_please_wait" : MessageLookupByLibrary.simpleMessage("提交中,清稍候..."),
+ "support" : MessageLookupByLibrary.simpleMessage("技术支持"),
+ "support_ticket" : MessageLookupByLibrary.simpleMessage("客户提问"),
+ "tap_back_again_to_exit" : MessageLookupByLibrary.simpleMessage("再次点击返回退出"),
+ "tutorials" : MessageLookupByLibrary.simpleMessage("教程"),
+ "wiki" : MessageLookupByLibrary.simpleMessage("维基")
+ };
+}
diff --git a/lib/generated/l10n.dart b/lib/generated/l10n.dart
index eff322c..948a21e 100644
--- a/lib/generated/l10n.dart
+++ b/lib/generated/l10n.dart
@@ -35,7 +35,305 @@ class S {
return Localizations.of(context, S);
}
+ /// `About`
+ String get about {
+ return Intl.message(
+ 'About',
+ name: 'about',
+ desc: '',
+ args: [],
+ );
+ }
+ /// `Navigation`
+ String get navigation {
+ return Intl.message(
+ 'Navigation',
+ name: 'navigation',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Submitting...`
+ String get submitting {
+ return Intl.message(
+ 'Submitting...',
+ name: 'submitting',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Submitting, please wait...`
+ String get submitting_please_wait {
+ return Intl.message(
+ 'Submitting, please wait...',
+ name: 'submitting_please_wait',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Recalculating...`
+ String get recalculating {
+ return Intl.message(
+ 'Recalculating...',
+ name: 'recalculating',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Loading, please wait...`
+ String get loading_please_wait {
+ return Intl.message(
+ 'Loading, please wait...',
+ name: 'loading_please_wait',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Tap back again to exit`
+ String get tap_back_again_to_exit {
+ return Intl.message(
+ 'Tap back again to exit',
+ name: 'tap_back_again_to_exit',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.`
+ String get main_content_1 {
+ return Intl.message(
+ 'Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.',
+ name: 'main_content_1',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `MiniPOS`
+ String get minipos {
+ return Intl.message(
+ 'MiniPOS',
+ name: 'minipos',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Point of sale system solution`
+ String get point_of_sale_system_solution {
+ return Intl.message(
+ 'Point of sale system solution',
+ name: 'point_of_sale_system_solution',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Learn more...`
+ String get learn_more {
+ return Intl.message(
+ 'Learn more...',
+ name: 'learn_more',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Information`
+ String get information {
+ return Intl.message(
+ 'Information',
+ name: 'information',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Service policy`
+ String get service_policy {
+ return Intl.message(
+ 'Service policy',
+ name: 'service_policy',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Return policy`
+ String get return_policy {
+ return Intl.message(
+ 'Return policy',
+ name: 'return_policy',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Privacy policy`
+ String get privacy_policy {
+ return Intl.message(
+ 'Privacy policy',
+ name: 'privacy_policy',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `License agreement`
+ String get license_agreement {
+ return Intl.message(
+ 'License agreement',
+ name: 'license_agreement',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Support`
+ String get support {
+ return Intl.message(
+ 'Support',
+ name: 'support',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Wiki`
+ String get wiki {
+ return Intl.message(
+ 'Wiki',
+ name: 'wiki',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Support ticket`
+ String get support_ticket {
+ return Intl.message(
+ 'Support ticket',
+ name: 'support_ticket',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Contact us`
+ String get contact_us {
+ return Intl.message(
+ 'Contact us',
+ name: 'contact_us',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `About us`
+ String get about_us {
+ return Intl.message(
+ 'About us',
+ name: 'about_us',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Renew license`
+ String get renew_license {
+ return Intl.message(
+ 'Renew license',
+ name: 'renew_license',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Developers of`
+ String get developer_of {
+ return Intl.message(
+ 'Developers of',
+ name: 'developer_of',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Home`
+ String get home {
+ return Intl.message(
+ 'Home',
+ name: 'home',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Download`
+ String get download {
+ return Intl.message(
+ 'Download',
+ name: 'download',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Tutorials`
+ String get tutorials {
+ return Intl.message(
+ 'Tutorials',
+ name: 'tutorials',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Shop`
+ String get shop {
+ return Intl.message(
+ 'Shop',
+ name: 'shop',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Blog`
+ String get blog {
+ return Intl.message(
+ 'Blog',
+ name: 'blog',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Login`
+ String get login {
+ return Intl.message(
+ 'Login',
+ name: 'login',
+ desc: '',
+ args: [],
+ );
+ }
+
+ /// `Logout`
+ String get logout {
+ return Intl.message(
+ 'Logout',
+ name: 'logout',
+ desc: '',
+ args: [],
+ );
+ }
}
class AppLocalizationDelegate extends LocalizationsDelegate {
@@ -44,6 +342,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate {
List get supportedLocales {
return const [
Locale.fromSubtags(languageCode: 'en'),
+ Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),
];
}
diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb
index 9e26dfe..36ada03 100644
--- a/lib/l10n/intl_en.arb
+++ b/lib/l10n/intl_en.arb
@@ -1 +1,32 @@
-{}
\ No newline at end of file
+{
+ "about": "About",
+ "navigation": "Navigation",
+ "submitting": "Submitting...",
+ "submitting_please_wait": "Submitting, please wait...",
+ "recalculating": "Recalculating...",
+ "loading_please_wait": "Loading, please wait...",
+ "tap_back_again_to_exit": "Tap back again to exit",
+ "main_content_1": "Since 1999, we have been committed to developing a complete and powerful sales system, helping thousands of small businesses handle sales smoothly. Currently we have two main products.",
+ "minipos": "MiniPOS",
+ "point_of_sale_system_solution": "Point of sale system solution",
+ "learn_more": "Learn more...",
+ "information": "Information",
+ "service_policy": "Service policy",
+ "return_policy": "Return policy",
+ "privacy_policy": "Privacy policy",
+ "license_agreement": "License agreement",
+ "support": "Support",
+ "wiki": "Wiki",
+ "support_ticket": "Support ticket",
+ "contact_us": "Contact us",
+ "about_us": "About us",
+ "renew_license": "Renew license",
+ "developer_of": "Developers of",
+ "home": "Home",
+ "download": "Download",
+ "tutorials": "Tutorials",
+ "shop": "Shop",
+ "blog": "Blog",
+ "login": "Login",
+ "logout": "Logout"
+}
\ No newline at end of file
diff --git a/lib/l10n/intl_zh_CN.arb b/lib/l10n/intl_zh_CN.arb
new file mode 100644
index 0000000..3a202bf
--- /dev/null
+++ b/lib/l10n/intl_zh_CN.arb
@@ -0,0 +1,32 @@
+{
+ "about": "关于",
+ "navigation": "导航",
+ "submitting": "提交中...",
+ "submitting_please_wait": "提交中,清稍候...",
+ "recalculating": "运算中...",
+ "loading_please_wait": "装载中,清稍候...",
+ "tap_back_again_to_exit": "再次点击返回退出",
+ "main_content_1": "自从1999年来,我们一直致力于开发完整的强大的销售系统,帮助了上千小企业平滑的处理销售业务。当前我们有两个主要的产品。",
+ "minipos": "MiniPOS",
+ "point_of_sale_system_solution": "收款系统方案",
+ "learn_more": "了解更多...",
+ "information": "信息",
+ "service_policy": "服务条款",
+ "return_policy": "退货条款",
+ "privacy_policy": "私隐条款",
+ "license_agreement": "许可协议",
+ "support": "技术支持",
+ "wiki": "维基",
+ "support_ticket": "客户提问",
+ "contact_us": "联系我们",
+ "about_us": "关于我们",
+ "renew_license": "证书续期",
+ "developer_of": "开发者",
+ "home": "首页",
+ "download": "下载",
+ "tutorials": "教程",
+ "shop": "线上购买",
+ "blog": "博客",
+ "login": "登入",
+ "logout": "登出"
+}
\ No newline at end of file
diff --git a/lib/main.dart b/lib/main.dart
index d8a0526..62b5686 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,113 +1,87 @@
+import 'package:catcher/catcher.dart';
+import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
+import 'package:flutter_device_locale/flutter_device_locale.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:flutter_redux/flutter_redux.dart';
+import 'package:flutter_wisetronic/events/events.dart';
+import 'package:flutter_wisetronic/routes.dart';
+import 'package:flutter_wisetronic/store/actions.dart';
+import 'package:flutter_wisetronic/widgets/general/navigationbar.dart';
+import 'package:flutter_wisetronic/widgets/mobile/mobile_navigation_drawer.dart';
+import 'package:pull_to_refresh/pull_to_refresh.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+import 'package:splashscreen/splashscreen.dart';
-void main() {
- runApp(MyApp());
+import 'constants.dart';
+import 'events/eventbus.dart';
+import 'generated/l10n.dart';
+import 'pages/home.dart';
+import 'store/store.dart';
+
+void main() async {
+ WidgetsFlutterBinding.ensureInitialized();
+ Locale locale = await DeviceLocale.getCurrentLocale();
+
+ runApp(MyApp(locale));
}
class MyApp extends StatelessWidget {
+ final Locale localLocate;
+
+ MyApp(this.localLocate) {
+ Routes.configure();
+ store.dispatch(UpdateLocale(localLocate));
+ }
+
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
+ Widget _buildBody() {
+ return SplashScreen(
+ seconds: 5,
+ routeName: '/',
+ navigateAfterSeconds: Home(localLocate, title: 'Welcome',),
+ styleTextUnderTheLoader: new TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 20.0,
+ ),
+ // imageBackground: (Image.network(Constants.BASE_API_URL + 'gallery/get-wisetronic-slpash')).image,
+ imageBackground: (new Image.network(Constants.BASE_API_URL + 'gallery/get-minimanager-splash/')).image,
+ backgroundColor: Colors.white,
+ onClick: () {
+
+ },
+ loaderColor: Colors.blue,
+ );
+ }
+
return MaterialApp(
- title: 'Flutter Demo',
+ debugShowCheckedModeBanner: Constants.DEBUG,
+ navigatorKey: kIsWeb ? null : Catcher.navigatorKey,
+ localizationsDelegates: [
+ GlobalMaterialLocalizations.delegate,
+ GlobalWidgetsLocalizations.delegate,
+ GlobalCupertinoLocalizations.delegate,
+ RefreshLocalizations.delegate,
+ S.delegate,
+ ],
+ supportedLocales: S.delegate.supportedLocales,
+ localeResolutionCallback: (Locale locale, Iterable supportedLocales) {
+ print('Language code: ${localLocate.languageCode}');
+ for (final supportedLocale in supportedLocales) {
+ return supportedLocale;
+ }
+ return supportedLocales.first;
+ },
+ title: 'Wisetronic Inc.',
theme: ThemeData(
- // This is the theme of your application.
- //
- // Try running your application with "flutter run". You'll see the
- // application has a blue toolbar. Then, without quitting the app, try
- // changing the primarySwatch below to Colors.green and then invoke
- // "hot reload" (press "r" in the console where you ran "flutter run",
- // or simply save your changes to "hot reload" in a Flutter IDE).
- // Notice that the counter didn't reset back to zero; the application
- // is not restarted.
primarySwatch: Colors.blue,
),
- home: MyHomePage(title: 'Flutter Demo Home Page'),
- );
- }
-}
-
-class MyHomePage extends StatefulWidget {
- MyHomePage({Key key, this.title}) : super(key: key);
-
- // This widget is the home page of your application. It is stateful, meaning
- // that it has a State object (defined below) that contains fields that affect
- // how it looks.
-
- // This class is the configuration for the state. It holds the values (in this
- // case the title) provided by the parent (in this case the App widget) and
- // used by the build method of the State. Fields in a Widget subclass are
- // always marked "final".
-
- final String title;
-
- @override
- _MyHomePageState createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State {
- int _counter = 0;
-
- void _incrementCounter() {
- setState(() {
- // This call to setState tells the Flutter framework that something has
- // changed in this State, which causes it to rerun the build method below
- // so that the display can reflect the updated values. If we changed
- // _counter without calling setState(), then the build method would not be
- // called again, and so nothing would appear to happen.
- _counter++;
- });
- }
-
- @override
- Widget build(BuildContext context) {
- // This method is rerun every time setState is called, for instance as done
- // by the _incrementCounter method above.
- //
- // The Flutter framework has been optimized to make rerunning build methods
- // fast, so that you can just rebuild anything that needs updating rather
- // than having to individually change instances of widgets.
- return Scaffold(
- appBar: AppBar(
- // Here we take the value from the MyHomePage object that was created by
- // the App.build method, and use it to set our appbar title.
- title: Text(widget.title),
- ),
- body: Center(
- // Center is a layout widget. It takes a single child and positions it
- // in the middle of the parent.
- child: Column(
- // Column is also a layout widget. It takes a list of children and
- // arranges them vertically. By default, it sizes itself to fit its
- // children horizontally, and tries to be as tall as its parent.
- //
- // Invoke "debug painting" (press "p" in the console, choose the
- // "Toggle Debug Paint" action from the Flutter Inspector in Android
- // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
- // to see the wireframe for each widget.
- //
- // Column has various properties to control how it sizes itself and
- // how it positions its children. Here we use mainAxisAlignment to
- // center the children vertically; the main axis here is the vertical
- // axis because Columns are vertical (the cross axis would be
- // horizontal).
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- Text(
- 'You have pushed the button this many times:',
- ),
- Text(
- '$_counter',
- style: Theme.of(context).textTheme.headline4,
- ),
- ],
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: Icon(Icons.add),
- ), // This trailing comma makes auto-formatting nicer for build methods.
+ home: StoreProvider(
+ store: store,
+ child: _buildBody(),
+ ),
);
}
}
diff --git a/lib/models/gallery.dart b/lib/models/gallery.dart
new file mode 100644
index 0000000..47358d1
--- /dev/null
+++ b/lib/models/gallery.dart
@@ -0,0 +1,24 @@
+
+import 'dart:convert';
+
+class Gallery {
+ int id;
+ String image;
+ String linkUrl;
+
+ Gallery.fromJson(Map json)
+ : id = json['id'],
+ image = json['image'],
+ linkUrl = json['link_url'];
+
+ Map toJson() => {
+ 'id': id,
+ 'image': image,
+ 'link_url': linkUrl
+ };
+
+ @override
+ String toString() {
+ return json.encode(this);
+ }
+}
\ No newline at end of file
diff --git a/lib/models/stripe_payment_method.dart b/lib/models/stripe_payment_method.dart
new file mode 100644
index 0000000..1286035
--- /dev/null
+++ b/lib/models/stripe_payment_method.dart
@@ -0,0 +1,46 @@
+
+import 'dart:convert';
+
+class StripePaymentMethod {
+ int id;
+ String customerId;
+ String paymentMethodId;
+ String paymentMethodType;
+ String cardBrand;
+ String cardCountry;
+ int cardExpMonth;
+ int cardExpYear;
+ String cardFunding;
+ String cardLast4;
+
+ StripePaymentMethod.fromJson(Map json) :
+ id = json['id'],
+ customerId = json['customer_id'],
+ paymentMethodId = json['payment_method_id'],
+ paymentMethodType = json['payment_method_type'],
+ cardBrand = json['card_brand'],
+ cardCountry = json['card_country'],
+ cardExpMonth = json['card_exp_month'],
+ cardExpYear = json['card_exp_year'],
+ cardFunding = json['card_funding'],
+ cardLast4 = json['card_last4'];
+
+ Map toJson() => {
+ 'id': id,
+ 'customer_id': customerId,
+ 'payment_method_id': paymentMethodId,
+ 'payment_method_type': paymentMethodType,
+ 'card_brand': cardBrand,
+ 'card_country': cardCountry,
+ 'card_exp_month': cardExpMonth,
+ 'card_exp_year': cardExpYear,
+ 'card_funding': cardFunding,
+ 'card_last4': cardLast4,
+ };
+
+ @override
+ String toString() {
+ return json.encode(this);
+ }
+
+}
\ No newline at end of file
diff --git a/lib/models/user.dart b/lib/models/user.dart
new file mode 100644
index 0000000..e532ade
--- /dev/null
+++ b/lib/models/user.dart
@@ -0,0 +1,68 @@
+
+import 'dart:convert';
+
+import 'stripe_payment_method.dart';
+
+class User {
+ int id;
+ String username;
+ String nickname;
+ String mobile;
+ String email;
+ String avatarUrl;
+ int lastAddressId;
+ String passCode;
+ double credit;
+ double wallet;
+ int coupon;
+ int points;
+ int orderNum;
+ double pointsToCreditsConversionRate;
+ String contactNumber;
+ String flutterMiniStoreToken;
+ List stripePaymentMethods;
+
+ User.fromJson(Map json)
+ : id = json['id'],
+ username = json['username'],
+ nickname = json['nickname'],
+ mobile = json['mobile'],
+ email = json['email'],
+ avatarUrl = json['avatar_url'],
+ lastAddressId = json['last_address_id'],
+ passCode = json['pass_code'],
+ credit = double.parse(json['credit'].toString()),
+ wallet = double.parse((json['wallet'] == null) ? "0": json['wallet'].toString()),
+ coupon = json['coupon'],
+ points = json['points'],
+ orderNum = json['order_num'],
+ pointsToCreditsConversionRate = double.parse(json['points_to_credits_conversion_rate'].toString()),
+ contactNumber = json['contact_number'],
+ flutterMiniStoreToken = json['flutter_ministore_token'],
+ stripePaymentMethods = (json['stripe_payment_methods'] as List).map((e) => StripePaymentMethod.fromJson(e)).toList();
+
+ Map toJson() => {
+ 'id': id,
+ 'username': username,
+ 'nickname': nickname,
+ 'mobile': mobile,
+ 'email': email,
+ 'avatar_url': avatarUrl,
+ 'last_address_id': lastAddressId,
+ 'pass_code': passCode,
+ 'credit': credit,
+ 'wallet': wallet,
+ 'coupon': coupon,
+ 'points': points,
+ 'order_num': orderNum,
+ 'points_to_credits_conversion_rate': pointsToCreditsConversionRate,
+ 'contact_number': contactNumber,
+ 'flutter_ministore_token': flutterMiniStoreToken,
+ 'stripe_payment_methods': stripePaymentMethods,
+ };
+
+ @override
+ String toString() {
+ return json.encode(this);
+ }
+}
\ No newline at end of file
diff --git a/lib/pages/home.dart b/lib/pages/home.dart
new file mode 100644
index 0000000..31bcaee
--- /dev/null
+++ b/lib/pages/home.dart
@@ -0,0 +1,96 @@
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/models/gallery.dart';
+import '../widgets/general/bottom_nav.dart';
+import '../widgets/general/index_carousel.dart';
+import '../widgets/general/index_main_content_1.dart';
+import '../widgets/general/index_main_content_2.dart';
+import '../widgets/general/index_main_content_3.dart';
+import '../events/eventbus.dart';
+import '../events/events.dart';
+import '../generated/l10n.dart';
+import '../store/actions.dart';
+import '../store/store.dart';
+import '../utils/http_util.dart';
+import '../utils/double_back_to_close_app.dart';
+import '../widgets/general/navigationbar.dart';
+import '../widgets/mobile/mobile_navigation_drawer.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class Home extends StatefulWidget {
+ final Locale locale;
+ final String title;
+
+ Home(this.locale, {Key key, this.title}) : super(key: key);
+
+ @override
+ State createState() {
+ return HomeState();
+ }
+
+}
+
+class HomeState extends State {
+ final _scaffoldKey = GlobalKey();
+ List galleries = [];
+ String content1Message = '';
+ Map content2;
+
+ @override
+ Widget build(BuildContext context) {
+ store.dispatch(UpdateContext(context));
+
+ return ResponsiveBuilder(
+ builder: (context, sizingInformation) =>
+ Scaffold(
+ key: _scaffoldKey,
+ appBar: NavigationBar(),
+ drawer: sizingInformation.deviceScreenType == DeviceScreenType.mobile ? MobileNavigationDrawer() : null,
+ body: DoubleBackToCloseApp(
+ snackBar: SnackBar(
+ content: Text(S.of(context).tap_back_again_to_exit),
+ ),
+ child: SingleChildScrollView(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ IndexCarousel(galleries),
+ IndexMainContent1(content1Message),
+ IndexMainContent2(content2),
+ IndexMainContent3(content2),
+ ],
+ ),
+ ),
+ ),
+ bottomNavigationBar: BottomNav(),
+ ),
+ );
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ _loadData();
+ eventBus.on().listen((event) {
+ if (mounted) {
+ _scaffoldKey.currentState.openDrawer();
+ }
+ });
+
+ }
+
+ void _loadData() {
+ HttpUtil.httpGet('v1/get-wisetronic-index-carousel')
+ .then((value) {
+ print('$value');
+ if (mounted) {
+ setState(() {
+ galleries = (value['index_carousel'] as List).map((i) => Gallery.fromJson(i)).toList();
+ content1Message = value['content']['index_content_1'];
+ content2 = value['content']['index_content_2'];
+ });
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/lib/routes.dart b/lib/routes.dart
new file mode 100644
index 0000000..778a059
--- /dev/null
+++ b/lib/routes.dart
@@ -0,0 +1,16 @@
+
+import 'package:fluro/fluro.dart';
+import 'package:flutter/material.dart';
+
+class Routes {
+ static final router = FluroRouter();
+
+ static void configure() {
+ router.define('/', handler: new Handler(
+ handlerFunc: (BuildContext context, Map> params) {
+ return null;
+ }),
+ transitionType: TransitionType.fadeIn
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/store/actions.dart b/lib/store/actions.dart
new file mode 100644
index 0000000..9716b02
--- /dev/null
+++ b/lib/store/actions.dart
@@ -0,0 +1,18 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/models/user.dart';
+
+class UpdateContext {
+ final BuildContext context;
+ UpdateContext(this.context);
+}
+
+class UpdateLocale {
+ final Locale locale;
+ UpdateLocale(this.locale);
+}
+
+class UpdateCurrentUser {
+ final User user;
+ UpdateCurrentUser(this.user);
+}
\ No newline at end of file
diff --git a/lib/store/reducer/app_reducer.dart b/lib/store/reducer/app_reducer.dart
new file mode 100644
index 0000000..deec659
--- /dev/null
+++ b/lib/store/reducer/app_reducer.dart
@@ -0,0 +1,13 @@
+
+import 'package:flutter_wisetronic/store/reducer/context_reducer.dart';
+import 'package:flutter_wisetronic/store/reducer/locale_reducer.dart';
+import 'package:flutter_wisetronic/store/reducer/user_reducer.dart';
+import 'package:flutter_wisetronic/store/state/app_state.dart';
+
+AppState appReducer(AppState state, action) {
+ return AppState(
+ context: contextReducer(state.context, action),
+ locale: localeReducer(state.locale, action),
+ user: userReducer(state.user, action),
+ );
+}
\ No newline at end of file
diff --git a/lib/store/reducer/context_reducer.dart b/lib/store/reducer/context_reducer.dart
new file mode 100644
index 0000000..586d72c
--- /dev/null
+++ b/lib/store/reducer/context_reducer.dart
@@ -0,0 +1,12 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/store/actions.dart';
+import 'package:redux/redux.dart';
+
+final contextReducer = combineReducers([
+ TypedReducer(_updateContext)
+]);
+
+BuildContext _updateContext(BuildContext context, action) {
+ return action.context;
+}
\ No newline at end of file
diff --git a/lib/store/reducer/locale_reducer.dart b/lib/store/reducer/locale_reducer.dart
new file mode 100644
index 0000000..d27f351
--- /dev/null
+++ b/lib/store/reducer/locale_reducer.dart
@@ -0,0 +1,11 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/store/actions.dart';
+import 'package:redux/redux.dart';
+
+final localeReducer = combineReducers([
+ TypedReducer(_updateLocale)
+]);
+
+Locale _updateLocale(Locale locale, action) {
+ return action.locale;
+}
\ No newline at end of file
diff --git a/lib/store/reducer/user_reducer.dart b/lib/store/reducer/user_reducer.dart
new file mode 100644
index 0000000..d15912d
--- /dev/null
+++ b/lib/store/reducer/user_reducer.dart
@@ -0,0 +1,13 @@
+
+import 'package:redux/redux.dart';
+import 'package:flutter_wisetronic/models/user.dart';
+
+import '../actions.dart';
+
+final userReducer = combineReducers([
+ TypedReducer(_updateCurrentUser)
+]);
+
+User _updateCurrentUser(User user, action) {
+ return action.user;
+}
\ No newline at end of file
diff --git a/lib/store/state/app_state.dart b/lib/store/state/app_state.dart
new file mode 100644
index 0000000..f9c1e61
--- /dev/null
+++ b/lib/store/state/app_state.dart
@@ -0,0 +1,42 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/models/user.dart';
+
+@immutable
+class AppState {
+ final BuildContext context;
+ final Locale locale;
+ final User user;
+
+ AppState({this.context, this.locale, this.user});
+
+ factory AppState.init() => AppState();
+
+ AppState copyWith({
+ BuildContext context,
+ Locale locale}) {
+ return AppState(
+ context: context ?? this.context,
+ locale: locale ?? this.locale,
+ user: user ?? this.user,
+ );
+ }
+
+ @override
+ int get hashCode =>
+ context.hashCode ^
+ locale.hashCode ^
+ user.hashCode;
+
+ @override
+ bool operator ==(Object other) =>
+ identical(this, other) ||
+ other is AppState &&
+ context == other.context &&
+ locale == other.locale &&
+ user == other.user;
+
+ @override
+ String toString() =>
+ 'AppState(context: $context, locale: $locale), user: $user';
+}
\ No newline at end of file
diff --git a/lib/store/store.dart b/lib/store/store.dart
new file mode 100644
index 0000000..08da714
--- /dev/null
+++ b/lib/store/store.dart
@@ -0,0 +1,9 @@
+
+import 'package:flutter_wisetronic/store/reducer/app_reducer.dart';
+import 'package:redux/redux.dart';
+import 'state/app_state.dart';
+
+final store = Store(
+ appReducer,
+ initialState: AppState.init(),
+);
\ No newline at end of file
diff --git a/lib/utils/double_back_to_close_app.dart b/lib/utils/double_back_to_close_app.dart
new file mode 100644
index 0000000..b39eee3
--- /dev/null
+++ b/lib/utils/double_back_to_close_app.dart
@@ -0,0 +1,98 @@
+import 'dart:async';
+
+import 'package:flutter/material.dart';
+
+/// Allows the user to close the app by double tapping the back-button.
+///
+/// You must specify a [SnackBar], so it can be shown when the user taps the
+/// back-button. Notice that the value you set for [SnackBar.duration] is going
+/// to be considered to decide whether the snack-bar is currently visible or
+/// not.
+///
+/// Since the back-button is an Android feature, this Widget is going to be
+/// nothing but the own [child] if the current platform is anything but Android.
+class DoubleBackToCloseApp extends StatefulWidget {
+ /// The [SnackBar] shown when the user taps the back-button.
+ final SnackBar snackBar;
+
+ /// The widget below this widget in the tree.
+ final Widget child;
+
+ /// Creates a widget that allows the user to close the app by double tapping
+ /// the back-button.
+ const DoubleBackToCloseApp({
+ Key key,
+ @required this.snackBar,
+ @required this.child,
+ }) : assert(snackBar != null),
+ assert(child != null),
+ super(key: key);
+
+ @override
+ _DoubleBackToCloseAppState createState() => _DoubleBackToCloseAppState();
+}
+
+class _DoubleBackToCloseAppState extends State {
+ /// The last time the user tapped Android's back-button.
+ DateTime _lastTimeBackButtonWasTapped;
+
+ /// Returns whether the current platform is Android.
+ bool get _isAndroid => Theme.of(context).platform == TargetPlatform.android;
+
+ /// Returns whether the [DoubleBackToCloseApp.snackBar] is currently visible.
+ ///
+ /// The snack-bar is going to be considered visible if the duration of the
+ /// snack-bar is greater than the difference from now to the
+ /// [_lastTimeBackButtonWasTapped].
+ ///
+ /// This is not quite accurate since the snack-bar could've been dismissed by
+ /// the user, so this algorithm needs to be improved, as described in #2.
+ bool get _isSnackBarVisible =>
+ (_lastTimeBackButtonWasTapped != null) &&
+ (widget.snackBar.duration >
+ DateTime.now().difference(_lastTimeBackButtonWasTapped));
+
+ /// Returns whether the next back navigation of this route will be handled
+ /// internally.
+ ///
+ /// Returns true when there's a widget that inserted an entry into the
+ /// local-history of the current route, in order to handle pop. This is done
+ /// by [Drawer], for example, so it can close on pop.
+ bool get _willHandlePopInternally =>
+ ModalRoute.of(context).willHandlePopInternally;
+
+ @override
+ Widget build(BuildContext context) {
+ _ensureThatContextContainsScaffold();
+
+ if (_isAndroid) {
+ return WillPopScope(
+ onWillPop: _handleWillPop,
+ child: widget.child,
+ );
+ } else {
+ return widget.child;
+ }
+ }
+
+ /// Handles [WillPopScope.onWillPop].
+ Future _handleWillPop() async {
+ if (_isSnackBarVisible || _willHandlePopInternally) {
+ return true;
+ } else {
+ _lastTimeBackButtonWasTapped = DateTime.now();
+ // Scaffold.of(context).showSnackBar(widget.snackBar);
+ ScaffoldMessenger.of(context).showSnackBar(widget.snackBar);
+ return false;
+ }
+ }
+
+ /// Throws a [FlutterError] if this widget was not wrapped in a [Scaffold].
+ void _ensureThatContextContainsScaffold() {
+ if (Scaffold.maybeOf(context) == null) {
+ throw FlutterError(
+ '`DoubleBackToCloseApp` must be wrapped in a `Scaffold`.',
+ );
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart
new file mode 100644
index 0000000..9e942e9
--- /dev/null
+++ b/lib/utils/http_util.dart
@@ -0,0 +1,370 @@
+
+
+import 'dart:async';
+import 'dart:convert';
+
+import 'package:crypto/crypto.dart';
+import 'package:dio/dio.dart';
+import '../store/store.dart';
+import 'utils.dart';
+import 'package:hive/hive.dart';
+import 'package:universal_io/io.dart';
+
+import '../constants.dart';
+
+typedef void PostCallback(Response response);
+
+String generateSignature(String string, {String key}) {
+ if (key == null) {
+ key = Constants.API_SECRET;
+ }
+ Hmac mac = new Hmac(sha256, utf8.encode(key));
+ Digest digest = mac.convert(utf8.encode(string + key));
+ String base64Mac = base64.encode(utf8.encode("$digest"));
+ return base64Mac;
+}
+
+class HttpUtil {
+ static String platformName = Utils.getPlatformName();
+
+ static final Map headers = {
+ 'Accept': 'application/json',
+// 'Content-Type': 'application/json',
+ 'Http-Signature': '',
+// 'Http-Group-Id': Constants.GROUP_ID,
+ 'Http-Business-Id': '0',
+ 'Http-App-Key': '',
+ 'Http-Contact-Authorization': '',
+ 'Http-Device-Type': Platform.isIOS ? 'ios' : (Platform.isAndroid ? 'android' : 'web'),
+ 'Http-Api-Branch': 'flutter',
+ 'Http-Language-Code': store.state.locale.languageCode,
+ };
+
+ static Future httpGet(String url,
+ {
+ Map queryParameters,
+ int businessId = 0,
+ Function(int, int) receiveProgress,
+ bool returnError = false,
+ Map additionalHeaders,
+ }) async {
+ Map localHeaders = json.decode(json.encode(headers));
+ if (additionalHeaders != null) {
+ localHeaders.addAll(additionalHeaders);
+ }
+
+ if (!url.startsWith('http')) {
+ localHeaders['Http-Signature'] = generateSignature(url);
+ }
+
+ localHeaders['Http-Business-Id'] = businessId.toString();
+ Box box = await Utils.getBox();
+ localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
+ localHeaders['Http-App-Key'] = platformName;
+ localHeaders['Http-Device-Type'] = platformName;
+ String requestUrl = Constants.BASE_API_URL + url;
+
+ if (url.startsWith('http')) {
+ requestUrl = url;
+ }
+
+ Utils.jsonPrettyPrint(queryParameters);
+
+ Dio dio = Dio();
+ try {
+ Response response = await dio.get(requestUrl,
+ queryParameters: queryParameters,
+ options: Options(
+ headers: localHeaders
+ ),
+ onReceiveProgress: receiveProgress,
+ ).timeout(const Duration(seconds: 30));
+
+ print('HttpGet success. Request: $requestUrl, Response: ${response.statusCode}, Headers: ${response.request.headers}');
+// print(response.data);
+// Utils.jsonPrettyPrint(response.data);
+
+ int statusCode = response.statusCode;
+ return response.data;
+ } on DioError catch(e) {
+ print('error $e');
+ if (returnError) {
+ return e;
+ }
+ throw e;
+ }
+ }
+
+ static Future httpPost(String url, PostCallback callback,
+ {
+ Map queryParameters,
+ int businessId = 0,
+ bool isFormData = false,
+ Map additionalHeaders,
+ Map body,
+ Function(int, int) sendProgress,
+ Function(int, int) receiveProgress,
+ bool returnError = false,
+ }) async {
+
+ Map localHeaders = json.decode(json.encode(headers));
+ if (additionalHeaders != null) {
+ localHeaders.addAll(additionalHeaders);
+ }
+ if (!url.startsWith('http')) {
+ localHeaders['Http-Signature'] = generateSignature(url);
+ }
+ localHeaders['Http-Business-Id'] = businessId.toString();
+ Box box = await Utils.getBox();
+ localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
+ localHeaders['Http-App-Key'] = platformName;
+ localHeaders['Http-Device-Type'] = platformName;
+
+ String requestUrl = Constants.BASE_API_URL + url;
+ if (url.startsWith('http')) {
+ requestUrl = url;
+ }
+
+ // Don't print body will cause upload Multipart file failed
+ //Utils.jsonPrettyPrint(body);
+
+ Dio dio = Dio();
+ dio.interceptors.add(LogInterceptor());
+ try {
+ Response response = await dio.post(
+ requestUrl,
+ queryParameters: queryParameters == null ? {} : queryParameters,
+ data: isFormData ? FormData.fromMap(body) : json.encode(body),
+ options: Options(
+ headers: localHeaders,
+// contentType: isFormData ? Headers.formUrlEncodedContentType : Headers.jsonContentType,
+ ),
+ onSendProgress: sendProgress,
+ onReceiveProgress: receiveProgress,
+ ).timeout(Duration(seconds: 30));
+
+ print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}');
+// Utils.jsonPrettyPrint(response.data);
+
+ int statusCode = response.statusCode;
+ if (callback != null) {
+ callback(response);
+ }
+ return response.data;
+ } on DioError catch(e) {
+ if (e.response != null) {
+ print('HttpPost failed. Request: ${e.request.uri}, Headers: ${e.response.request.headers}');
+ try {
+ Utils.jsonPrettyPrint(e.response.data);
+ } catch (err) {
+ print(e.response.data);
+ }
+ }
+ if (returnError) {
+ return e;
+ }
+ throw e;
+ }
+ }
+
+ static Future httpPut(String url, PostCallback callback,
+ {
+ Map queryParameters,
+ int businessId = 0,
+ Map additionalHeaders,
+ Map body,
+ Function(int, int) sendProgress,
+ Function(int, int) receiveProgress,
+ bool returnError = false,
+ }) async {
+
+ Map localHeaders = json.decode(json.encode(headers));
+ if (additionalHeaders != null) {
+ localHeaders.addAll(additionalHeaders);
+ }
+
+ if (!url.startsWith('http')) {
+ localHeaders['Http-Signature'] = generateSignature(url);
+ }
+
+ localHeaders['Http-Business-Id'] = businessId.toString();
+ Box box = await Utils.getBox();
+ localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
+ localHeaders['Http-App-Key'] = platformName;
+ localHeaders['Http-Device-Type'] = platformName;
+
+ localHeaders['Content-Type'] = Headers.jsonContentType;
+
+ String requestUrl = Constants.BASE_API_URL + url;
+
+ if (url.startsWith('http')) {
+ requestUrl = url;
+ }
+
+ Dio dio = Dio();
+ try {
+ Response response = await dio.put(
+ requestUrl,
+ queryParameters: queryParameters == null ? {} : queryParameters,
+ data: json.encode(body),
+ options: Options(
+ headers: localHeaders,
+ ),
+ onSendProgress: sendProgress,
+ onReceiveProgress: receiveProgress,
+ ).timeout(Duration(seconds: 30));
+
+ print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}');
+// Utils.jsonPrettyPrint(response.data);
+
+ int statusCode = response.statusCode;
+ if (callback != null) {
+ callback(response);
+ }
+ return response.data;
+ } on DioError catch(e) {
+ print('HttpPost failed. Request: ${e.request.uri}');
+ if (e.response != null) {
+ Utils.jsonPrettyPrint(e.response.data);
+ }
+ if (returnError) {
+ return e;
+ }
+ throw e;
+ }
+ }
+
+ static Future httpPatch(String url, PostCallback callback,
+ {
+ Map queryParameters,
+ int businessId = 0,
+ Map additionalHeaders,
+ Map body,
+ Function(int, int) sendProgress,
+ Function(int, int) receiveProgress,
+ bool returnError = false,
+ }) async {
+
+ Map localHeaders = json.decode(json.encode(headers));
+ if (additionalHeaders != null) {
+ localHeaders.addAll(additionalHeaders);
+ }
+
+ if (!url.startsWith('http')) {
+ localHeaders['Http-Signature'] = generateSignature(url);
+ }
+
+ localHeaders['Http-Business-Id'] = businessId.toString();
+ Box box = await Utils.getBox();
+ localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
+ localHeaders['Http-App-Key'] = platformName;
+ localHeaders['Http-Device-Type'] = platformName;
+
+ localHeaders['Content-Type'] = Headers.jsonContentType;
+
+ String requestUrl = Constants.BASE_API_URL + url;
+
+ if (url.startsWith('http')) {
+ requestUrl = url;
+ }
+
+ Utils.jsonPrettyPrint(body);
+
+ Dio dio = Dio();
+ try {
+ Response response = await dio.patch(
+ requestUrl,
+ queryParameters: queryParameters == null ? {} : queryParameters,
+ data: json.encode(body),
+ options: Options(
+ headers: localHeaders,
+ ),
+ onSendProgress: sendProgress,
+ onReceiveProgress: receiveProgress,
+ ).timeout(Duration(seconds: 30));
+
+ print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}');
+// Utils.jsonPrettyPrint(response.data);
+
+ int statusCode = response.statusCode;
+ if (callback != null) {
+ callback(response);
+ }
+ return response.data;
+ } on DioError catch(e) {
+ print('HttpPost failed. Request: ${e.request.uri}');
+ if (e.response != null) {
+ Utils.jsonPrettyPrint(e.response.data);
+ }
+ if (returnError) {
+ return e;
+ }
+ throw e;
+ }
+ }
+
+ static Future httpDelete(String url, PostCallback callback,
+ {
+ Map queryParameters,
+ int businessId = 0,
+ Map additionalHeaders,
+ Map body,
+ bool returnError = false,
+ }) async {
+
+ Map localHeaders = json.decode(json.encode(headers));
+ if (additionalHeaders != null) {
+ localHeaders.addAll(additionalHeaders);
+ }
+
+ if (!url.startsWith('http')) {
+ localHeaders['Http-Signature'] = generateSignature(url);
+ }
+
+ localHeaders['Http-Business-Id'] = businessId.toString();
+ Box box = await Utils.getBox();
+ localHeaders['Http-Contact-Authorization'] = box.get(Constants.KEY_ACCESS_TOKEN, defaultValue: '');
+ localHeaders['Http-App-Key'] = platformName;
+ localHeaders['Http-Device-Type'] = platformName;
+
+ localHeaders['Content-Type'] = Headers.jsonContentType;
+
+ String requestUrl = Constants.BASE_API_URL + url;
+
+ if (url.startsWith('http')) {
+ requestUrl = url;
+ }
+
+ Utils.jsonPrettyPrint(body);
+
+ Dio dio = Dio();
+ try {
+ Response response = await dio.delete(
+ requestUrl,
+ queryParameters: queryParameters == null ? {} : queryParameters,
+ data: json.encode(body),
+ options: Options(
+ headers: localHeaders,
+ ),
+ ).timeout(Duration(seconds: 30));
+
+ print('HttpPost Success. Request: ${response.request.uri}, Response: ${response.statusCode}, Headers: ${response.request.headers}');
+// Utils.jsonPrettyPrint(response.data);
+
+ int statusCode = response.statusCode;
+ if (callback != null) {
+ callback(response);
+ }
+ return response.data;
+ } on DioError catch(e) {
+ print('HttpPost failed. Request: ${e.request.uri}');
+ if (e.response != null) {
+ Utils.jsonPrettyPrint(e.response.data);
+ }
+ if(returnError) {
+ return e;
+ }
+ throw e;
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/utils/util_io.dart b/lib/utils/util_io.dart
new file mode 100644
index 0000000..da45a95
--- /dev/null
+++ b/lib/utils/util_io.dart
@@ -0,0 +1,46 @@
+
+import 'package:cached_network_image/cached_network_image.dart';
+import 'package:flutter/material.dart';
+import '../routes.dart';
+import 'utils.dart';
+import 'package:hive/hive.dart';
+import 'package:path_provider/path_provider.dart';
+
+class Util {
+ static Future getBox() async {
+ final dir = await getApplicationDocumentsDirectory();
+ Hive.init(dir.path);
+ Box box = await Hive.openBox('app_data');
+ return box;
+ }
+
+ static Widget showImage(String imageUrl, {double width, double height,
+ BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) {
+ if (imageUrl == null || imageUrl.isEmpty) {
+ return Container(
+ width: width,
+ height: height,
+ child: Text(''),
+ );
+ }
+ return CachedNetworkImage(
+ imageUrl: imageUrl,
+ width: width,
+ height: width,
+ fit: fit,
+ placeholder: (context, url) => Utils.imageLoadingIndicator(),
+ errorWidget: errorWidget != null ? errorWidget : (context, url, error) {
+ return Image.asset(
+ 'assets/images/not_found.png',
+ width: width,
+ height: height,
+ fit: fit,
+ );
+ },
+ );
+ }
+
+ static void openWebUrl(BuildContext context, String link) {
+ Routes.router.navigateTo(context, '/webview/$link');
+ }
+}
\ No newline at end of file
diff --git a/lib/utils/util_web.dart b/lib/utils/util_web.dart
new file mode 100644
index 0000000..a44c5d4
--- /dev/null
+++ b/lib/utils/util_web.dart
@@ -0,0 +1,52 @@
+
+import 'package:flutter/material.dart';
+import 'package:url_launcher/url_launcher.dart';
+import 'utils.dart';
+import 'package:hive/hive.dart';
+import 'package:hive_flutter/hive_flutter.dart';
+
+class Util {
+
+ static Future getBox() async {
+ Hive.initFlutter();
+ Box box = await Hive.openBox('wisetronic_app_data');
+ return box;
+ }
+
+ static Widget showImage(String imageUrl, {double width, double height,
+ BoxFit fit, Widget Function(BuildContext, String, dynamic) errorWidget}) {
+ return Image.network(imageUrl,
+ fit: fit,
+ width: width,
+ height: height,
+ cacheWidth: width != null ? width.round() : null,
+ cacheHeight: height != null ? height.round() : null,
+ loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent loadingProgress) {
+ if (loadingProgress == null) return child;
+ return Center(
+ child: Utils.imageLoadingIndicator(),
+ );
+ },
+ errorBuilder: (BuildContext context, Object object, StackTrace stackTrace) {
+ if (errorWidget != null) {
+ return errorWidget(context, null, null);
+ }
+ return Image.asset(
+ 'assets/images/not_found.png',
+ width: width,
+ height: height,
+ fit: fit,
+ );
+ },
+ );
+ }
+
+ static void openWebUrl(BuildContext context, String link) async {
+ var url = 'https://${link}';
+ if (await canLaunch(url)) {
+ await launch('$url');
+ } else {
+ print('Could not launch $url');
+ }
+ }
+}
\ No newline at end of file
diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart
new file mode 100644
index 0000000..1531594
--- /dev/null
+++ b/lib/utils/utils.dart
@@ -0,0 +1,277 @@
+
+import 'dart:convert';
+
+import 'package:dio/dio.dart';
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_spinkit/flutter_spinkit.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+import 'package:hive/hive.dart';
+import 'package:intl/intl.dart';
+import 'package:url_launcher/url_launcher.dart';
+import 'package:universal_io/io.dart';
+import 'util_web.dart' if (dart.library.io) 'util_io.dart';
+
+import '../routes.dart';
+import 'http_util.dart';
+
+typedef void OnSuccess(Response response);
+typedef void OnError(dynamic error);
+typedef void OnComplete(dynamic data);
+
+typedef void OnOk();
+
+class Utils {
+
+ static bool equalsIgnoreCase(String a, String b) =>
+ (a == null && b == null) ||
+ (a != null && b != null && a.toLowerCase() == b.toLowerCase());
+
+ static int selectionsContains(Map selections, String key, String name) {
+ if (selections.containsKey(key.toUpperCase())) {
+ for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) {
+ Map item = (selections[key.toUpperCase()] as List)[i];
+ if (Utils.equalsIgnoreCase(item['name'], name)) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ static List getSelectedAttributeValue(Map selections, String key) {
+ List valueArr = [];
+ if (selections.containsKey(key.toUpperCase())) {
+ for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) {
+ valueArr.add((selections[key.toUpperCase()][i]['name'] as String).toLowerCase());
+ }
+ }
+ return valueArr;
+ }
+
+ static bool selectionsNotEmptyAt(Map selections, String key) {
+ if (selections.containsKey(key.toUpperCase()) && (selections[key.toUpperCase()] as List).length > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ static Map stringToJson(String string) {
+ if (string == null || string.isEmpty) {
+ return null;
+ }
+ return json.decode(string);
+ }
+
+ static void jsonPrettyPrint(Map map) {
+ JsonEncoder encoder = new JsonEncoder.withIndent(' ');
+ String prettyPrint = encoder.convert(map);
+ debugPrint(prettyPrint);
+ }
+
+ static launchURL(String url) async {
+ if (await canLaunch(url)) {
+ await launch(url);
+ } else {
+ throw 'Could not launch $url';
+ }
+ }
+
+ static String getPlatformName() {
+ String platformName = '';
+ if (kIsWeb) {
+ platformName = 'web';
+ } else if (Platform.isAndroid) {
+ platformName = 'android';
+ } else if (Platform.isIOS) {
+ platformName = 'ios';
+ }
+ return platformName;
+ }
+
+ static Future getBox() async {
+ return Util.getBox();
+ }
+
+ static Widget imageLoadingIndicator() {
+ return SizedBox(
+ width: 30,
+ height: 30,
+ child: Container(
+ child: CupertinoActivityIndicator(),
+ color: Colors.transparent,
+ ),
+ );
+ }
+
+ static String safePhoneNumber(String phone) {
+ if (phone.length < 8) {
+ return phone;
+ }
+ String start = phone.substring(0, 3);
+ String end = phone.substring(phone.length - 3);
+ return '${start}****${end}';
+ }
+
+ static String safeString(String string) {
+ if (string == null || string.length == 0) {
+ return '';
+ }
+ String start = string.substring(0, 1);
+ String end = string.substring(string.length - 1);
+ return '${start}****${end}';
+ }
+
+ static String smartRound(double amount, int decimalPlace) {
+ double a = double.parse(amount.toStringAsFixed(decimalPlace));
+ double b = double.parse(amount.toStringAsFixed(0));
+ if (a - b == 0) {
+ return amount.toStringAsFixed(0);
+ }
+ return amount.toStringAsFixed(decimalPlace);
+ }
+
+ static void createOrUpdateStripePaymentMethod(
+ String paymentMethodId,
+ String cardBrand,
+ String paymentMethodType,
+ String cardCountry,
+ int cardExpMonth,
+ int cardExpYear,
+ String cardFunding,
+ String cardLast4,
+ ) {
+ HttpUtil.httpPost('v1/create-update-stripe-payment-method', (response) {
+ if (response.statusCode == 200) {
+ print('create or update customer stripe payment method success. ${response.data}');
+ }
+ },
+ body: {
+ 'payment_method_id': paymentMethodId,
+ 'card_brand': cardBrand,
+ 'payment_method_type': paymentMethodType,
+ 'card_country': cardCountry,
+ 'card_exp_month': cardExpMonth,
+ 'card_exp_year': cardExpYear,
+ 'card_funding': cardFunding,
+ 'card_last4': cardLast4,
+ },
+ isFormData: true,
+ ).catchError((error) {
+ print('Error: ${error}');
+ });
+ }
+
+ static showSubmitDialog(BuildContext context) {
+ showDialog(
+ context: context,
+ barrierDismissible: false,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ content: WillPopScope(
+ child: Container(
+ width: 300.0,
+ height: 150.0,
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SpinKitThreeBounce(
+ color: Colors.lightBlueAccent,
+ size: 30.0,
+ ),
+ Text(
+ S.of(context).submitting,
+ ),
+ ],
+ ),
+ ),
+ ),
+ onWillPop: () async {
+ Fluttertoast.showToast(
+ msg: S.of(context).submitting_please_wait,
+ toastLength: Toast.LENGTH_SHORT,
+ gravity: ToastGravity.CENTER,
+ backgroundColor: Colors.red,
+ textColor: Colors.white
+ );
+ return false;
+ }
+ ),
+ );
+ },
+ );
+ }
+
+ static showLoadingDialog(BuildContext context, {String message}) {
+ showDialog(
+ context: context,
+ barrierDismissible: false,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ content: WillPopScope(
+ child: Container(
+ width: 80.0,
+ height: 80.0,
+ child: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ SpinKitThreeBounce(
+ color: Colors.lightBlueAccent,
+ size: 30.0,
+ ),
+ Text(
+ message != null ? message : S.of(context).recalculating,
+ ),
+ ],
+ ),
+ ),
+ ),
+ onWillPop: () async {
+ Fluttertoast.showToast(
+ msg: S.of(context).loading_please_wait,
+ toastLength: Toast.LENGTH_SHORT,
+ gravity: ToastGravity.CENTER,
+ backgroundColor: Colors.red,
+ textColor: Colors.white
+ );
+ return false;
+ }
+ ),
+ );
+ },
+ );
+ }
+
+ static getTitleFromBody(String body) {
+ if (body.length <= 30) {
+ return body;
+ }
+ return body.substring(0, 29);
+ }
+
+ static void getMiniLink(String realLink, OnSuccess onSuccess, OnError onError) {
+ HttpUtil.httpPost('get-minilink/', (response) {
+ onSuccess(response);
+ },
+ body: {
+ 'link': realLink
+ },
+ isFormData: true,
+ ).catchError((error) {
+ onError(error);
+ });
+ }
+}
+
+class RuntimeError extends Error{
+ final int code;
+ final String message;
+ RuntimeError(this.message, {this.code});
+ String toString() => "Runtime Error: $message";
+}
\ No newline at end of file
diff --git a/lib/widgets/desktop/desktop_Index_carousel.dart b/lib/widgets/desktop/desktop_Index_carousel.dart
new file mode 100644
index 0000000..b0eaaf1
--- /dev/null
+++ b/lib/widgets/desktop/desktop_Index_carousel.dart
@@ -0,0 +1,113 @@
+
+import 'package:carousel_slider/carousel_slider.dart';
+import 'package:flutter/material.dart';
+import '../../models/gallery.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class DesktopIndexCarousel extends StatefulWidget {
+ final List galleries;
+
+ const DesktopIndexCarousel(this.galleries, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return DesktopIndexCarouselState();
+ }
+}
+
+class DesktopIndexCarouselState extends State {
+ int _current = 0;
+ double sideSpace = 0;
+ double mainSpace = 1200;
+
+ @override
+ Widget build(BuildContext context) {
+ return Stack(
+ children: [
+ Container(
+ padding: EdgeInsets.only(left: 0.0, right: 0.0, top: 0.0, bottom: 0.0),
+ child: CarouselSlider(
+ items: widget.galleries.map((i) {
+ return Builder(
+ builder: (BuildContext context) {
+ if (MediaQuery.of(context).size.width <= 1200) {
+ mainSpace = MediaQuery.of(context).size.width;
+ sideSpace = 0;
+ } else {
+ mainSpace = 1200;
+ sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
+ }
+ return Row(
+ children: [
+ Container(
+ width: sideSpace,
+ ),
+ Container(
+ width: mainSpace,
+ // margin: EdgeInsets.symmetric(horizontal: 5.0),
+ child: GestureDetector(
+ child: Container(
+ child: Util.showImage(
+ 'https:${i.image}',
+ fit: BoxFit.fitWidth,
+ ),
+ ),
+ onTap: () {
+ if (i.linkUrl != null && i.linkUrl.isNotEmpty) {
+ Util.openWebUrl(context, i.linkUrl);
+ }
+ },
+ ),
+ ),
+ Container(
+ width: sideSpace,
+ ),
+ ],
+ );
+ },
+ );
+ }).toList(),
+ options: CarouselOptions(
+ height: mainSpace / 2.0,
+ aspectRatio: 2/1,
+ initialPage: 0,
+ enableInfiniteScroll: true,
+ autoPlay: true,
+ autoPlayInterval: Duration(seconds: 5),
+ autoPlayCurve: Curves.fastOutSlowIn,
+ scrollDirection: Axis.horizontal,
+ viewportFraction: 1.0,
+ onPageChanged: (index, reason) {
+ setState(() {
+ _current = index;
+ });
+ }
+ ),
+ ),
+ ),
+ Positioned(
+ bottom: 5,
+ right: sideSpace + 10,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: widget.galleries.map((i) {
+ int index = widget.galleries.indexOf(i);
+ return Container(
+ width: 8.0,
+ height: 8.0,
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: _current == index
+ ? Color.fromRGBO(0, 0, 0, 0.9)
+ : Color.fromRGBO(0, 0, 0, 0.4),
+ ),
+ );
+ }).toList(),
+ ),
+ ),
+ ],
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/desktop/desktop_index_main_content_1.dart b/lib/widgets/desktop/desktop_index_main_content_1.dart
new file mode 100644
index 0000000..221812f
--- /dev/null
+++ b/lib/widgets/desktop/desktop_index_main_content_1.dart
@@ -0,0 +1,60 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+
+class DesktopIndexMainContent1 extends StatefulWidget {
+ final String message;
+ const DesktopIndexMainContent1(this.message, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return DesktopIndexMainContent1State();
+ }
+}
+
+class DesktopIndexMainContent1State extends State {
+ double sideSpace = 0;
+ double mainSpace = 1200;
+
+ @override
+ Widget build(BuildContext context) {
+ if (MediaQuery.of(context).size.width <= 1200) {
+ mainSpace = MediaQuery.of(context).size.width;
+ sideSpace = 0;
+ } else {
+ mainSpace = 1200;
+ sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
+ }
+
+ return Row(
+ children: [
+ Container(
+ width: sideSpace,
+ ),
+ Container(
+ width: mainSpace,
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ padding: EdgeInsets.symmetric(vertical: 30.0, horizontal: 30.0),
+ child: Container(
+ child: Text(
+ widget.message,
+ style: TextStyle(
+ fontSize: 20,
+ fontWeight: FontWeight.bold,
+ color: Colors.white,
+ ),
+ ),
+ ),
+ decoration: BoxDecoration(
+ color: Colors.lightGreen,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ ),
+ Container(
+ width: sideSpace,
+ ),
+ ],
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/desktop/desktop_index_main_content_2.dart b/lib/widgets/desktop/desktop_index_main_content_2.dart
new file mode 100644
index 0000000..0f34d7b
--- /dev/null
+++ b/lib/widgets/desktop/desktop_index_main_content_2.dart
@@ -0,0 +1,247 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class DesktopIndexMainContent2 extends StatefulWidget {
+ final Map content;
+ const DesktopIndexMainContent2(this.content, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return DesktopIndexMainContent2State();
+ }
+}
+
+class DesktopIndexMainContent2State extends State {
+ double sideSpace = 0;
+ double mainSpace = 1200;
+
+ @override
+ Widget build(BuildContext context) {
+ if (widget.content == null) {
+ return Container();
+ }
+ if (MediaQuery.of(context).size.width <= 1200) {
+ mainSpace = MediaQuery.of(context).size.width;
+ sideSpace = 0;
+ } else {
+ mainSpace = 1200;
+ sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
+ }
+ return Row(
+ children: [
+ Container(
+ width: sideSpace,
+ ),
+ Container(
+ width: mainSpace,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ width: mainSpace / 2,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['minipos']}',
+ style: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.blueGrey,
+ ),
+ ),
+ ),
+ Container(
+ width: mainSpace / 2 - 100.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['point_of_sale_system_solution']}',
+ style: TextStyle(
+ fontSize: 15.0,
+ color: Colors.grey,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ child: Util.showImage(
+ 'http:${widget.content['minipos_image']['image']}',
+ fit: BoxFit.fitWidth
+ ),
+ ),
+ _buildMiniPosFeatures(mainSpace / 2),
+ ],
+ ),
+ ),
+ Container(
+ width: mainSpace / 2,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['igoshow']}',
+ style: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.blueGrey,
+ ),
+ ),
+ ),
+ Container(
+ width: mainSpace / 2 - 100.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['igoshow_solution']}',
+ style: TextStyle(
+ fontSize: 15.0,
+ color: Colors.grey,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ child: Util.showImage(
+ 'http:${widget.content['igoshow_image']['image']}',
+ fit: BoxFit.fitWidth
+ ),
+ ),
+ _buildiGoShowFeatures(mainSpace / 2),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ width: sideSpace,
+ ),
+ ],
+ );
+ }
+
+ Widget _buildMiniPosFeatures(double width) {
+ Column col = Column(
+ children: [],
+ );
+ for (int i = 0; i < (widget.content['minipos_features'] as List).length; i++) {
+ col.children.add(Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0),
+ child: Icon(
+ Icons.circle,
+ size: 10.0,
+ color: Colors.black87,
+ ),
+ ),
+ Container(
+ width: width - 40.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${(widget.content['minipos_features'] as List)[i]}',
+ style: TextStyle(
+ color: Colors.black54,
+ ),
+ ),
+ ),
+ ],
+ ));
+ }
+ col.children.add(
+ GestureDetector(
+ child: Container(
+ padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Text(
+ S.of(context).learn_more,
+ style: TextStyle(
+ color: Colors.blue,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ );
+ return Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
+ child: col,
+ );
+ }
+
+ Widget _buildiGoShowFeatures(double width) {
+ Column col = Column(
+ children: [],
+ );
+ for (int i = 0; i < (widget.content['igoshow_features'] as List).length; i++) {
+ col.children.add(Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0),
+ child: Icon(
+ Icons.circle,
+ size: 10.0,
+ color: Colors.black87,
+ ),
+ ),
+ Container(
+ width: width - 40.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${(widget.content['igoshow_features'] as List)[i]}',
+ style: TextStyle(
+ color: Colors.black54,
+ ),
+ ),
+ ),
+ ],
+ ));
+ }
+ col.children.add(
+ GestureDetector(
+ child: Container(
+ padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Text(
+ S.of(context).learn_more,
+ style: TextStyle(
+ color: Colors.blue,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ );
+ return Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
+ child: col,
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/desktop/desktop_index_main_content_3.dart b/lib/widgets/desktop/desktop_index_main_content_3.dart
new file mode 100644
index 0000000..fd2b869
--- /dev/null
+++ b/lib/widgets/desktop/desktop_index_main_content_3.dart
@@ -0,0 +1,179 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import 'package:flutter_wisetronic/widgets/general/text_link.dart';
+
+class DesktopIndexMainContent3 extends StatefulWidget {
+ final Map content;
+ const DesktopIndexMainContent3(this.content, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return DesktopIndexMainContent3State();
+ }
+}
+
+class DesktopIndexMainContent3State extends State {
+ double sideSpace = 0;
+ double mainSpace = 1200;
+
+ @override
+ Widget build(BuildContext context) {
+ if (widget.content == null) {
+ return Container();
+ }
+ if (MediaQuery.of(context).size.width <= 1200) {
+ mainSpace = MediaQuery.of(context).size.width;
+ sideSpace = 0;
+ } else {
+ mainSpace = 1200;
+ sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
+ }
+ return Container(
+ width: MediaQuery.of(context).size.width,
+ margin: EdgeInsets.only(top: 20.0),
+ padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
+ decoration: BoxDecoration(
+ color: Color(0xff262626),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ child: Text(
+ S.of(context).information,
+ style: TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.white70,
+ ),
+ ),
+ ),
+ Container(
+ child: Row(
+ children: [
+ TextLink(S.of(context).service_policy, '/service_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).return_policy, '/return_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).privacy_policy, '/privacy_policy', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).license_agreement, '/license_agreement', paddingVertical: 5.0, paddingHorizontal: 10.0,)
+ ],
+ ),
+ ),
+ Container(
+ margin: EdgeInsets.only(top: 12.0),
+ child: Text(
+ S.of(context).support,
+ style: TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.white70,
+ ),
+ ),
+ ),
+ Container(
+ child: Row(
+ children: [
+ TextLink(S.of(context).wiki, '/wiki', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).support_ticket, '/support_ticket', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).contact_us, '/contact_us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).about_us, '/about_us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).renew_license, '/renew_license', paddingVertical: 5.0, paddingHorizontal: 10.0,)
+ ],
+ ),
+ ),
+ Container(
+ margin: EdgeInsets.only(top: 12.0),
+ child: Text(
+ S.of(context).developer_of,
+ style: TextStyle(
+ fontSize: 16.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.white70,
+ ),
+ ),
+ ),
+ Container(
+ child: Row(
+ children: [
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe800,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe801,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe802,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe803,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe804,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe805,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.white24,
+ size: 48.0,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/desktop/desktop_navigationbar.dart b/lib/widgets/desktop/desktop_navigationbar.dart
new file mode 100644
index 0000000..68a5191
--- /dev/null
+++ b/lib/widgets/desktop/desktop_navigationbar.dart
@@ -0,0 +1,99 @@
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import 'package:flutter_wisetronic/widgets/general/navigationbar_logo.dart';
+import 'package:flutter_wisetronic/widgets/general/text_link.dart';
+
+class DesktopNavigationBar extends StatefulWidget {
+ const DesktopNavigationBar({Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return DesktopNavigationBarState();
+ }
+
+}
+
+class DesktopNavigationBarState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ String currentRoute = ModalRoute.of(context).settings.name;
+ return Stack(
+ children: [
+ Container(
+ color: Colors.blue,
+ height: 80.0,
+ ),
+ Container(
+ height: 80.0,
+ padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ NavigationBarLogo(),
+ Container(
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ SizedBox(width: 20.0,),
+ TextLink(
+ S.of(context).home,
+ '/',
+ color: Colors.white,
+ selected: currentRoute == '/',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).download,
+ '/download',
+ color: Colors.white,
+ selected: currentRoute == '/download',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).tutorials,
+ '/tutorials',
+ color: Colors.white,
+ selected: currentRoute == '/tutorials',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).support,
+ '/support',
+ color: Colors.white,
+ selected: currentRoute == '/support',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).shop,
+ '/shop',
+ color: Colors.white,
+ selected: currentRoute == '/shop',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).blog,
+ '/blog',
+ color: Colors.white,
+ selected: currentRoute == '/blog',
+ ),
+ SizedBox(width: 15.0,),
+ TextLink(
+ S.of(context).login,
+ '/login',
+ color: Colors.white,
+ selected: currentRoute == '/login',
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/bottom_nav.dart b/lib/widgets/general/bottom_nav.dart
new file mode 100644
index 0000000..e698eb4
--- /dev/null
+++ b/lib/widgets/general/bottom_nav.dart
@@ -0,0 +1,51 @@
+
+import 'package:flutter/material.dart';
+
+class BottomNav extends StatefulWidget {
+ const BottomNav({Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return BottomNavState();
+ }
+
+}
+
+class BottomNavState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ width: MediaQuery.of(context).size.width,
+ height: 50.0,
+ padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
+ decoration: BoxDecoration(
+ color: Color(0xff232323),
+ ),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+ children: [
+ Container(
+ child: Text(
+ '© 2007-${DateTime.now().year} wisetronic.com. All Rights Reserved.',
+ style: TextStyle(
+ fontSize: 10.0,
+ color: Colors.white60,
+ ),
+ ),
+ ),
+ Container(
+ child: Text(
+ 'All logos shown are registered trademark, copyrighted and belong to their respective owners.',
+ style: TextStyle(
+ fontSize: 10.0,
+ color: Colors.white60,
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/download_item.dart b/lib/widgets/general/download_item.dart
new file mode 100644
index 0000000..a232f11
--- /dev/null
+++ b/lib/widgets/general/download_item.dart
@@ -0,0 +1,90 @@
+
+import 'package:flutter/material.dart';
+import 'package:universal_io/io.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class DownloadItem extends StatefulWidget {
+ final dynamic desc;
+ final double width;
+ const DownloadItem(this.desc, {Key key, this.width}) : super(key: key);
+
+ @override
+ State createState() {
+ return DownloadItemState();
+ }
+
+}
+
+class DownloadItemState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+
+ return Container(
+ padding: EdgeInsets.only(top: 10.0, bottom: 10.0, left: 10.0, right: 10.0),
+ child: Column(
+ children: [
+ Container(
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ Container(
+ child: Row(
+ children: [
+ Container(
+ child: Util.showImage(
+ 'https:${widget.desc['app_icon']}',
+ width: 32.0,
+ height: 32.0,
+ fit: BoxFit.fill,
+ ),
+ ),
+ Container(
+ child: Column(
+ children: [
+ Text(
+ '${widget.desc['name']}',
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ fontSize: 15.0,
+ color: Colors.black87,
+ ),
+ ),
+ Text(
+ '${widget.desc['version']}',
+ style: TextStyle(
+ fontSize: 12.0,
+ color: Colors.black38,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ child: getDownloadButton(),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ child: Text(
+ '${widget.desc['description']}',
+ style: TextStyle(
+ color: Colors.black54,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
+ Widget getDownloadButton() {
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/lib/widgets/general/index_carousel.dart b/lib/widgets/general/index_carousel.dart
new file mode 100644
index 0000000..7d40ea8
--- /dev/null
+++ b/lib/widgets/general/index_carousel.dart
@@ -0,0 +1,21 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/models/gallery.dart';
+import '../desktop/desktop_Index_carousel.dart';
+import '../mobile/mobile_index_carousel.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class IndexCarousel extends StatelessWidget {
+ final List galleries;
+ const IndexCarousel(this.galleries, {Key key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ScreenTypeLayout(
+ mobile: MobileIndexCarousel(galleries),
+ tablet: DesktopIndexCarousel(galleries),
+ desktop: DesktopIndexCarousel(galleries),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/index_main_content_1.dart b/lib/widgets/general/index_main_content_1.dart
new file mode 100644
index 0000000..e9d0ff9
--- /dev/null
+++ b/lib/widgets/general/index_main_content_1.dart
@@ -0,0 +1,20 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/widgets/desktop/desktop_index_main_content_1.dart';
+import 'package:flutter_wisetronic/widgets/mobile/mobile_index_main_content_1.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class IndexMainContent1 extends StatelessWidget {
+ final String message;
+ const IndexMainContent1(this.message, {Key key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ScreenTypeLayout(
+ mobile: MobileIndexMainContent1(message),
+ tablet: DesktopIndexMainContent1(message),
+ desktop: DesktopIndexMainContent1(message),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/index_main_content_2.dart b/lib/widgets/general/index_main_content_2.dart
new file mode 100644
index 0000000..842ed4c
--- /dev/null
+++ b/lib/widgets/general/index_main_content_2.dart
@@ -0,0 +1,20 @@
+
+import 'package:flutter/material.dart';
+import '../desktop/desktop_index_main_content_2.dart';
+import '../mobile/mobile_index_main_content_2.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class IndexMainContent2 extends StatelessWidget {
+ final Map content;
+ const IndexMainContent2(this.content, {Key key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ScreenTypeLayout(
+ mobile: MobileIndexMainContent2(content),
+ tablet: DesktopIndexMainContent2(content),
+ desktop: DesktopIndexMainContent2(content),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/index_main_content_3.dart b/lib/widgets/general/index_main_content_3.dart
new file mode 100644
index 0000000..41906ab
--- /dev/null
+++ b/lib/widgets/general/index_main_content_3.dart
@@ -0,0 +1,20 @@
+
+import 'package:flutter/material.dart';
+import '../desktop/desktop_index_main_content_3.dart';
+import '../mobile/mobile_index_main_content_3.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class IndexMainContent3 extends StatelessWidget {
+ final Map content;
+ const IndexMainContent3(this.content, {Key key}) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ScreenTypeLayout(
+ mobile: MobileIndexMainContent3(content),
+ tablet: DesktopIndexMainContent3(content),
+ desktop: DesktopIndexMainContent3(content),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/navigationbar.dart b/lib/widgets/general/navigationbar.dart
new file mode 100644
index 0000000..d1c67cc
--- /dev/null
+++ b/lib/widgets/general/navigationbar.dart
@@ -0,0 +1,37 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/widgets/desktop/desktop_navigationbar.dart';
+import 'package:flutter_wisetronic/widgets/mobile/mobile_navigationbar.dart';
+import 'package:responsive_builder/responsive_builder.dart';
+
+class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
+ final Key key;
+ final PreferredSizeWidget bottom;
+
+ NavigationBar({Key key, PreferredSizeWidget bottom})
+ : key = key,
+ preferredSize = Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
+ bottom = bottom;
+
+ @override
+ final Size preferredSize;
+
+ @override
+ State createState() {
+ return NavigationBarState();
+ }
+
+}
+
+class NavigationBarState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ return ScreenTypeLayout(
+ mobile: MobileNavigationBar(),
+ tablet: DesktopNavigationBar(),
+ desktop: DesktopNavigationBar(),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/general/navigationbar_logo.dart b/lib/widgets/general/navigationbar_logo.dart
new file mode 100644
index 0000000..c76f73b
--- /dev/null
+++ b/lib/widgets/general/navigationbar_logo.dart
@@ -0,0 +1,25 @@
+
+import 'package:flutter/material.dart';
+
+class NavigationBarLogo extends StatelessWidget {
+ const NavigationBarLogo({Key key}) : super(key: key);
+
+ static const IconData logoData = IconData(
+ 0xe800,
+ fontFamily: 'wisetronic',
+ fontPackage: null
+ );
+
+ @override
+ Widget build(BuildContext context) {
+ return SizedBox(
+ height: 48,
+ width: 178,
+ child: Icon(
+ logoData,
+ color: Colors.white,
+ size: 48.0,
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/widgets/general/text_link.dart b/lib/widgets/general/text_link.dart
new file mode 100644
index 0000000..b40971c
--- /dev/null
+++ b/lib/widgets/general/text_link.dart
@@ -0,0 +1,58 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter/rendering.dart';
+import 'package:url_launcher/url_launcher.dart';
+
+class TextLink extends StatelessWidget {
+ final String title;
+ final String url;
+ final Color color;
+ final double paddingHorizontal;
+ final double paddingVertical;
+ final FontWeight fontWeight;
+ final bool selected;
+ TextLink(this.title, this.url, {
+ this.color,
+ this.paddingHorizontal,
+ this.paddingVertical,
+ this.fontWeight,
+ this.selected
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return MouseRegion(
+ cursor: SystemMouseCursors.click,
+ child: GestureDetector(
+ child: Container(
+ padding: EdgeInsets.symmetric(
+ vertical: paddingVertical ?? 0.0,
+ horizontal: paddingHorizontal ?? 0.0
+ ),
+ child: Text(
+ title,
+ style: TextStyle(
+ color: color ?? Colors.blue,
+ fontWeight: fontWeight ?? FontWeight.normal,
+ ),
+ ),
+ decoration: BoxDecoration(
+ border: (selected != null && selected) ? Border(
+ bottom: BorderSide(
+ color: color ?? Colors.blue,
+ width: 3.0,
+ )
+ ) : null,
+ ),
+ ),
+ onTap: () async {
+ if (await canLaunch(url)) {
+ await launch(url);
+ } else {
+ throw 'Could not launch $url';
+ }
+ },
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_index_carousel.dart b/lib/widgets/mobile/mobile_index_carousel.dart
new file mode 100644
index 0000000..c506484
--- /dev/null
+++ b/lib/widgets/mobile/mobile_index_carousel.dart
@@ -0,0 +1,94 @@
+
+import 'package:carousel_slider/carousel_slider.dart';
+import 'package:flutter/material.dart';
+import '../../models/gallery.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class MobileIndexCarousel extends StatefulWidget {
+ final List galleries;
+
+ const MobileIndexCarousel(this.galleries, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileIndexCarouselState();
+ }
+}
+
+class MobileIndexCarouselState extends State {
+ int _current = 0;
+
+ @override
+ Widget build(BuildContext context) {
+ return Stack(
+ children: [
+ Container(
+ padding: EdgeInsets.only(left: 0.0, right: 0.0, top: 0.0, bottom: 0.0),
+ child: CarouselSlider(
+ items: widget.galleries.map((i) {
+ return Builder(
+ builder: (BuildContext context) {
+ return Container(
+ width: MediaQuery.of(context).size.width,
+ // margin: EdgeInsets.symmetric(horizontal: 5.0),
+ child: GestureDetector(
+ child: Container(
+ child: Util.showImage(
+ 'https:${i.image}',
+ fit: BoxFit.fitWidth,
+ ),
+ ),
+ onTap: () {
+ if (i.linkUrl != null && i.linkUrl.isNotEmpty) {
+ Util.openWebUrl(context, i.linkUrl);
+ }
+ },
+ ),
+ );
+ },
+ );
+ }).toList(),
+ options: CarouselOptions(
+ height: MediaQuery.of(context).size.width / 2.0,
+ aspectRatio: 2/1,
+ initialPage: 0,
+ enableInfiniteScroll: true,
+ autoPlay: true,
+ autoPlayInterval: Duration(seconds: 5),
+ autoPlayCurve: Curves.fastOutSlowIn,
+ scrollDirection: Axis.horizontal,
+ viewportFraction: 1.0,
+ onPageChanged: (index, reason) {
+ setState(() {
+ _current = index;
+ });
+ }
+ ),
+ ),
+ ),
+ Positioned(
+ bottom: 5,
+ right: 10,
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: widget.galleries.map((i) {
+ int index = widget.galleries.indexOf(i);
+ return Container(
+ width: 8.0,
+ height: 8.0,
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
+ decoration: BoxDecoration(
+ shape: BoxShape.circle,
+ color: _current == index
+ ? Color.fromRGBO(0, 0, 0, 0.9)
+ : Color.fromRGBO(0, 0, 0, 0.4),
+ ),
+ );
+ }).toList(),
+ ),
+ ),
+ ],
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_index_main_content_1.dart b/lib/widgets/mobile/mobile_index_main_content_1.dart
new file mode 100644
index 0000000..0f11fb7
--- /dev/null
+++ b/lib/widgets/mobile/mobile_index_main_content_1.dart
@@ -0,0 +1,40 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+
+class MobileIndexMainContent1 extends StatefulWidget {
+ final String message;
+
+ const MobileIndexMainContent1(this.message, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileIndexMainContent1State();
+ }
+}
+
+class MobileIndexMainContent1State extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ padding: EdgeInsets.symmetric(vertical: 20.0, horizontal: 20.0),
+ child: Container(
+ child: Text(
+ widget.message,
+ style: TextStyle(
+ fontSize: 15.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.white,
+ ),
+ ),
+ ),
+ decoration: BoxDecoration(
+ color: Colors.lightGreen,
+ borderRadius: BorderRadius.circular(10),
+ ),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_index_main_content_2.dart b/lib/widgets/mobile/mobile_index_main_content_2.dart
new file mode 100644
index 0000000..3f36a20
--- /dev/null
+++ b/lib/widgets/mobile/mobile_index_main_content_2.dart
@@ -0,0 +1,119 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class MobileIndexMainContent2 extends StatefulWidget {
+ final Map content;
+
+ const MobileIndexMainContent2(this.content, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileIndexMainContent2State();
+ }
+}
+
+class MobileIndexMainContent2State extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ if (widget.content == null) {
+ return Container();
+ }
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['minipos']}',
+ style: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.blueGrey,
+ ),
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['point_of_sale_system_solution']}',
+ style: TextStyle(
+ fontSize: 15.0,
+ color: Colors.grey,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ child: Util.showImage(
+ 'http:${widget.content['minipos_image']['image']}',
+ fit: BoxFit.fitWidth
+ ),
+ ),
+ _buildMiniPosFeatures(),
+ ],
+ );
+ }
+
+ Widget _buildMiniPosFeatures() {
+ Column col = Column(
+ children: [],
+ );
+ for (int i = 0; i < (widget.content['minipos_features'] as List).length; i++) {
+ col.children.add(Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0),
+ child: Icon(
+ Icons.circle,
+ size: 10.0,
+ color: Colors.black87,
+ ),
+ ),
+ Container(
+ width: MediaQuery.of(context).size.width - 40.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${(widget.content['minipos_features'] as List)[i]}',
+ style: TextStyle(
+ color: Colors.black54,
+ ),
+ ),
+ ),
+ ],
+ ));
+ }
+ col.children.add(
+ GestureDetector(
+ child: Container(
+ padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Text(
+ S.of(context).learn_more,
+ style: TextStyle(
+ color: Colors.blue,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ );
+ return Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
+ child: col,
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_index_main_content_3.dart b/lib/widgets/mobile/mobile_index_main_content_3.dart
new file mode 100644
index 0000000..25a8695
--- /dev/null
+++ b/lib/widgets/mobile/mobile_index_main_content_3.dart
@@ -0,0 +1,122 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import '../../utils/util_web.dart' if (dart.library.io) '../../utils/util_io.dart';
+
+class MobileIndexMainContent3 extends StatefulWidget {
+ final Map content;
+
+ const MobileIndexMainContent3(this.content, {Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileIndexMainContent3State();
+ }
+}
+
+class MobileIndexMainContent3State extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ if (widget.content == null) {
+ return Container();
+ }
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['igoshow']}',
+ style: TextStyle(
+ fontSize: 20.0,
+ fontWeight: FontWeight.bold,
+ color: Colors.blueGrey,
+ ),
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${widget.content['igoshow_solution']}',
+ style: TextStyle(
+ fontSize: 15.0,
+ color: Colors.grey,
+ ),
+ overflow: TextOverflow.ellipsis,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.symmetric(horizontal: 10.0),
+ child: Util.showImage(
+ 'http:${widget.content['igoshow_image']['image']}',
+ fit: BoxFit.fitWidth
+ ),
+ ),
+ _buildiGoShowFeatures(),
+ Container(
+ height: 20.0,
+ ),
+ ],
+ );
+ }
+
+ Widget _buildiGoShowFeatures() {
+ Column col = Column(
+ children: [],
+ );
+ for (int i = 0; i < (widget.content['igoshow_features'] as List).length; i++) {
+ col.children.add(Row(
+ mainAxisAlignment: MainAxisAlignment.start,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Container(
+ padding: EdgeInsets.symmetric(vertical: 8.0, horizontal: 5.0),
+ child: Icon(
+ Icons.circle,
+ size: 10.0,
+ color: Colors.black87,
+ ),
+ ),
+ Container(
+ width: MediaQuery.of(context).size.width - 40.0,
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 5.0),
+ child: Text(
+ '${(widget.content['igoshow_features'] as List)[i]}',
+ style: TextStyle(
+ color: Colors.black54,
+ ),
+ ),
+ ),
+ ],
+ ));
+ }
+ col.children.add(
+ GestureDetector(
+ child: Container(
+ padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
+ child: Text(
+ S.of(context).learn_more,
+ style: TextStyle(
+ color: Colors.blue,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ );
+ return Container(
+ padding: EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
+ child: col,
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_navigation_drawer.dart b/lib/widgets/mobile/mobile_navigation_drawer.dart
new file mode 100644
index 0000000..4e34596
--- /dev/null
+++ b/lib/widgets/mobile/mobile_navigation_drawer.dart
@@ -0,0 +1,233 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+import 'package:flutter_wisetronic/widgets/general/text_link.dart';
+import 'package:flutter_wisetronic/widgets/mobile/mobile_navigation_drawer_header.dart';
+
+class MobileNavigationDrawer extends StatefulWidget {
+ const MobileNavigationDrawer({Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileNavigationDrawerState();
+ }
+
+}
+
+class MobileNavigationDrawerState extends State {
+ @override
+ Widget build(BuildContext context) {
+ String currentRoute = ModalRoute.of(context).settings.name;
+
+ return Container(
+ width: 300.0,
+ height: MediaQuery.of(context).size.height,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ boxShadow: [
+ BoxShadow(color: Colors.black12, blurRadius: 16.0),
+ ],
+ ),
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ MobileNavigationDrawerHeader(),
+ TextLink(
+ S.of(context).home,
+ '/',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/',
+ ),
+ TextLink(
+ S.of(context).download,
+ '/download',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/download',
+ ),
+ TextLink(
+ S.of(context).tutorials,
+ '/tutorials',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/tutorials',
+ ),
+ TextLink(
+ S.of(context).support,
+ '/support',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/support',
+ ),
+ TextLink(
+ S.of(context).shop,
+ '/shop',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/shop',
+ ),
+ TextLink(
+ S.of(context).blog,
+ '/blog',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/blog',
+ ),
+ TextLink(
+ S.of(context).login,
+ '/login',
+ paddingVertical: 10.0,
+ paddingHorizontal: 15.0,
+ selected: currentRoute == '/login',
+ ),
+ Container(
+ margin: EdgeInsets.only(top: 20.0),
+ height: 0.5,
+ color: Colors.green,
+ ),
+ Container(
+ margin: EdgeInsets.only(top: 20.0, bottom: 10.0),
+ child: Text(
+ S.of(context).information,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: Colors.black54,
+ fontSize: 16.0,
+ ),
+ ),
+ ),
+ TextLink(
+ S.of(context).service_policy,
+ '/service_policy',
+ paddingVertical: 5.0,
+ paddingHorizontal: 10.0,
+ ),
+ TextLink(
+ S.of(context).return_policy,
+ '/return_policy',
+ paddingVertical: 5.0,
+ paddingHorizontal: 10.0,
+ ),
+ TextLink(
+ S.of(context).privacy_policy,
+ '/privacy_policy',
+ paddingVertical: 5.0,
+ paddingHorizontal: 10.0,
+ ),
+ TextLink(
+ S.of(context).license_agreement,
+ '/license_agreement',
+ paddingVertical: 5.0,
+ paddingHorizontal: 10.0,
+ ),
+ Container(
+ margin: EdgeInsets.only(top: 20.0, bottom: 10.0),
+ child: Text(
+ S.of(context).support,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: Colors.black54,
+ fontSize: 16.0,
+ ),
+ ),
+ ),
+ TextLink(S.of(context).wiki, '/wiki', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).support_ticket, '/support_ticket', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).contact_us, '/contact_us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).about_us, '/about_us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ TextLink(S.of(context).renew_license, '/renew_license', paddingVertical: 5.0, paddingHorizontal: 10.0,),
+ Container(
+ margin: EdgeInsets.only(top: 20.0, bottom: 10.0),
+ child: Text(
+ S.of(context).developer_of,
+ style: TextStyle(
+ fontWeight: FontWeight.bold,
+ color: Colors.black54,
+ fontSize: 16.0,
+ ),
+ ),
+ ),
+ Wrap(
+ children: [
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe800,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe801,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe802,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe803,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe804,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ Container(
+ padding: EdgeInsets.all(10.0),
+ child: Icon(
+ IconData(
+ 0xe805,
+ fontFamily: 'company',
+ fontPackage: null
+ ),
+ color: Colors.black26,
+ size: 48.0,
+ ),
+ ),
+ ],
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_navigation_drawer_header.dart b/lib/widgets/mobile/mobile_navigation_drawer_header.dart
new file mode 100644
index 0000000..f59e44e
--- /dev/null
+++ b/lib/widgets/mobile/mobile_navigation_drawer_header.dart
@@ -0,0 +1,30 @@
+
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/generated/l10n.dart';
+
+class MobileNavigationDrawerHeader extends StatelessWidget {
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ height: 40.0,
+ padding: EdgeInsets.only(top: 10.0),
+ color: Colors.green,
+ alignment: Alignment.center,
+ child: Column(
+ children: [
+ Text(
+ S.of(context).navigation,
+ style: TextStyle(
+ fontSize: 18.0,
+ fontWeight: FontWeight.w800,
+ color: Colors.white,
+ ),
+ )
+ ],
+ ),
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/lib/widgets/mobile/mobile_navigationbar.dart b/lib/widgets/mobile/mobile_navigationbar.dart
new file mode 100644
index 0000000..123bb5c
--- /dev/null
+++ b/lib/widgets/mobile/mobile_navigationbar.dart
@@ -0,0 +1,74 @@
+
+import 'package:flutter/material.dart';
+import 'package:flutter_wisetronic/events/eventbus.dart';
+import 'package:flutter_wisetronic/events/events.dart';
+import 'package:flutter_wisetronic/widgets/general/navigationbar_logo.dart';
+
+class MobileNavigationBar extends StatefulWidget {
+ const MobileNavigationBar({Key key}) : super(key: key);
+
+ @override
+ State createState() {
+ return MobileNavigationBarState();
+ }
+
+}
+
+class MobileNavigationBarState extends State {
+
+ @override
+ Widget build(BuildContext context) {
+ return Container(
+ padding: EdgeInsets.only(left: 10.0, right: 10.0),
+ height: 80.0,
+ color: Colors.blue,
+ child: Row(
+ mainAxisSize: MainAxisSize.max,
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ children: [
+ IconButton(
+ icon: Icon(Icons.menu),
+ onPressed: () {
+ eventBus.fire(OpenDrawer());
+ },
+ ),
+ Container(
+ child: NavigationBarLogo(),
+ padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
+ ),
+ Container()
+ ],
+ ),
+ );
+ // return Stack(
+ // children: [
+ // Container(
+ // height: 80.0,
+ // color: Colors.blue,
+ // ),
+ // Container(
+ // padding: EdgeInsets.only(left: 10.0, right: 10.0),
+ // height: 80.0,
+ // child: Row(
+ // mainAxisSize: MainAxisSize.max,
+ // mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ // children: [
+ // IconButton(
+ // icon: Icon(Icons.menu),
+ // onPressed: () {
+ //
+ // },
+ // ),
+ // Container(
+ // child: NavigationBarLogo(),
+ // padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
+ // ),
+ // Container()
+ // ],
+ // ),
+ // ),
+ // ],
+ // );
+ }
+
+}
\ No newline at end of file
diff --git a/pubspec.lock b/pubspec.lock
index 932b246..00c8da5 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -189,7 +189,7 @@ packages:
name: file
url: "https://pub.dartlang.org"
source: hosted
- version: "5.2.1"
+ version: "6.0.0-nullsafety.4"
flappy_search_bar:
dependency: "direct main"
description:
@@ -285,7 +285,7 @@ packages:
source: hosted
version: "0.3.2"
flutter_svg:
- dependency: transitive
+ dependency: "direct main"
description:
name: flutter_svg
url: "https://pub.dartlang.org"
@@ -363,7 +363,7 @@ packages:
name: intl
url: "https://pub.dartlang.org"
source: hosted
- version: "0.16.1"
+ version: "0.17.0-nullsafety.2"
js:
dependency: transitive
description:
@@ -449,7 +449,7 @@ packages:
source: hosted
version: "0.1.4"
path_provider:
- dependency: transitive
+ dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
@@ -503,7 +503,7 @@ packages:
name: platform
url: "https://pub.dartlang.org"
source: hosted
- version: "2.2.1"
+ version: "3.0.0-nullsafety.4"
plugin_platform_interface:
dependency: transitive
description:
@@ -517,7 +517,7 @@ packages:
name: process
url: "https://pub.dartlang.org"
source: hosted
- version: "3.0.13"
+ version: "4.0.0-nullsafety.4"
pull_to_refresh:
dependency: "direct main"
description:
@@ -649,6 +649,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0-nullsafety.5"
+ universal_io:
+ dependency: "direct main"
+ description:
+ name: universal_io
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "1.0.1"
url_launcher:
dependency: "direct main"
description:
@@ -789,6 +796,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.2.1"
+ zone_local:
+ dependency: transitive
+ description:
+ name: zone_local
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.2"
sdks:
dart: ">=2.12.0-29.10.beta <3.0.0"
flutter: ">=1.24.0-6.0.pre <2.0.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 41c7aff..3056d78 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -55,6 +55,9 @@ dependencies:
package_info: ^0.4.3+2
catcher: ^0.3.22
share: ^0.6.5+4
+ flutter_svg: ^0.19.2+1
+ universal_io: ^1.0.1
+ path_provider: ^1.6.24
dev_dependencies:
flutter_test:
@@ -72,7 +75,8 @@ flutter:
uses-material-design: true
# To add assets to your application, add an assets section, like this:
- # assets:
+ assets:
+ - assets/images/
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
@@ -87,6 +91,13 @@ flutter:
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
+ fonts:
+ - family: wisetronic
+ fonts:
+ - asset: fonts/wisetronic.ttf
+ - family: company
+ fonts:
+ - asset: fonts/company.ttf
# fonts:
# - family: Schyler
# fonts: