This commit is contained in:
2020-12-23 00:43:59 -05:00
parent 0fd880f57b
commit 86c845b49b
54 changed files with 3638 additions and 107 deletions

8
lib/constants.dart Normal file
View File

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

4
lib/events/eventbus.dart Normal file
View File

@@ -0,0 +1,4 @@
import 'package:event_bus/event_bus.dart';
final eventBus = new EventBus();

4
lib/events/events.dart Normal file
View File

@@ -0,0 +1,4 @@
class OpenDrawer {
}

View File

@@ -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<dynamic> LibraryLoader();
Map<String, LibraryLoader> _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;
}

View File

@@ -21,6 +21,35 @@ class MessageLookup extends MessageLookupByLibrary {
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"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")
};
}

View File

@@ -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<dynamic> args);
class MessageLookup extends MessageLookupByLibrary {
String get localeName => 'zh_CN';
final messages = _notInlinedMessages(_notInlinedMessages);
static _notInlinedMessages(_) => <String, Function> {
"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("维基")
};
}

View File

@@ -35,7 +35,305 @@ class S {
return Localizations.of<S>(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<S> {
@@ -44,6 +342,7 @@ class AppLocalizationDelegate extends LocalizationsDelegate<S> {
List<Locale> get supportedLocales {
return const <Locale>[
Locale.fromSubtags(languageCode: 'en'),
Locale.fromSubtags(languageCode: 'zh', countryCode: 'CN'),
];
}

View File

@@ -1 +1,32 @@
{}
{
"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"
}

32
lib/l10n/intl_zh_CN.arb Normal file
View File

@@ -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": "登出"
}

View File

@@ -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<Locale> 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<MyHomePage> {
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: <Widget>[
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(),
),
);
}
}

24
lib/models/gallery.dart Normal file
View File

@@ -0,0 +1,24 @@
import 'dart:convert';
class Gallery {
int id;
String image;
String linkUrl;
Gallery.fromJson(Map<String, dynamic> json)
: id = json['id'],
image = json['image'],
linkUrl = json['link_url'];
Map<String, dynamic> toJson() => {
'id': id,
'image': image,
'link_url': linkUrl
};
@override
String toString() {
return json.encode(this);
}
}

View File

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

68
lib/models/user.dart Normal file
View File

@@ -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<StripePaymentMethod> stripePaymentMethods;
User.fromJson(Map<String, dynamic> 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<String, dynamic> 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);
}
}

96
lib/pages/home.dart Normal file
View File

@@ -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<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
final _scaffoldKey = GlobalKey<ScaffoldState>();
List<Gallery> galleries = [];
String content1Message = '';
Map<String, dynamic> 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<OpenDrawer>().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'];
});
}
});
}
}

16
lib/routes.dart Normal file
View File

@@ -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<String, List<String>> params) {
return null;
}),
transitionType: TransitionType.fadeIn
);
}
}

18
lib/store/actions.dart Normal file
View File

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

View File

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

View File

@@ -0,0 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/store/actions.dart';
import 'package:redux/redux.dart';
final contextReducer = combineReducers<BuildContext>([
TypedReducer<BuildContext, UpdateContext>(_updateContext)
]);
BuildContext _updateContext(BuildContext context, action) {
return action.context;
}

View File

@@ -0,0 +1,11 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/store/actions.dart';
import 'package:redux/redux.dart';
final localeReducer = combineReducers<Locale>([
TypedReducer<Locale, UpdateLocale>(_updateLocale)
]);
Locale _updateLocale(Locale locale, action) {
return action.locale;
}

View File

@@ -0,0 +1,13 @@
import 'package:redux/redux.dart';
import 'package:flutter_wisetronic/models/user.dart';
import '../actions.dart';
final userReducer = combineReducers<User>([
TypedReducer<User, UpdateCurrentUser>(_updateCurrentUser)
]);
User _updateCurrentUser(User user, action) {
return action.user;
}

View File

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

9
lib/store/store.dart Normal file
View File

@@ -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<AppState>(
appReducer,
initialState: AppState.init(),
);

View File

@@ -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<DoubleBackToCloseApp> {
/// 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<bool> _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`.',
);
}
}
}

370
lib/utils/http_util.dart Normal file
View File

@@ -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<String, String> 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<dynamic> httpGet(String url,
{
Map<String, dynamic> queryParameters,
int businessId = 0,
Function(int, int) receiveProgress,
bool returnError = false,
Map<String, String> additionalHeaders,
}) async {
Map<String, dynamic> 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<dynamic> httpPost(String url, PostCallback callback,
{
Map<String, dynamic> queryParameters,
int businessId = 0,
bool isFormData = false,
Map<String, String> additionalHeaders,
Map<String, dynamic> body,
Function(int, int) sendProgress,
Function(int, int) receiveProgress,
bool returnError = false,
}) async {
Map<String, dynamic> 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<dynamic> httpPut(String url, PostCallback callback,
{
Map<String, dynamic> queryParameters,
int businessId = 0,
Map<String, String> additionalHeaders,
Map<String, dynamic> body,
Function(int, int) sendProgress,
Function(int, int) receiveProgress,
bool returnError = false,
}) async {
Map<String, dynamic> 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<dynamic> httpPatch(String url, PostCallback callback,
{
Map<String, dynamic> queryParameters,
int businessId = 0,
Map<String, String> additionalHeaders,
Map<String, dynamic> body,
Function(int, int) sendProgress,
Function(int, int) receiveProgress,
bool returnError = false,
}) async {
Map<String, dynamic> 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<dynamic> httpDelete(String url, PostCallback callback,
{
Map<String, dynamic> queryParameters,
int businessId = 0,
Map<String, String> additionalHeaders,
Map<String, dynamic> body,
bool returnError = false,
}) async {
Map<String, dynamic> 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;
}
}
}

46
lib/utils/util_io.dart Normal file
View File

@@ -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<Box> 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');
}
}

52
lib/utils/util_web.dart Normal file
View File

@@ -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<Box> 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');
}
}
}

277
lib/utils/utils.dart Normal file
View File

@@ -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<String, dynamic> selections, String key, String name) {
if (selections.containsKey(key.toUpperCase())) {
for (var i = 0; i < (selections[key.toUpperCase()] as List).length; i++) {
Map<String, dynamic> item = (selections[key.toUpperCase()] as List)[i];
if (Utils.equalsIgnoreCase(item['name'], name)) {
return i;
}
}
}
return -1;
}
static List<String> getSelectedAttributeValue(Map<String, dynamic> selections, String key) {
List<String> 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<String, dynamic> selections, String key) {
if (selections.containsKey(key.toUpperCase()) && (selections[key.toUpperCase()] as List).length > 0) {
return true;
}
return false;
}
static Map<String, dynamic> stringToJson(String string) {
if (string == null || string.isEmpty) {
return null;
}
return json.decode(string);
}
static void jsonPrettyPrint(Map<String, dynamic> 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<Box> 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: <Widget>[
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: <Widget>[
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";
}

View File

@@ -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<Gallery> galleries;
const DesktopIndexCarousel(this.galleries, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return DesktopIndexCarouselState();
}
}
class DesktopIndexCarouselState extends State<DesktopIndexCarousel> {
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(),
),
),
],
);
}
}

View File

@@ -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<StatefulWidget> createState() {
return DesktopIndexMainContent1State();
}
}
class DesktopIndexMainContent1State extends State<DesktopIndexMainContent1> {
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,
),
],
);
}
}

View File

@@ -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<String, dynamic> content;
const DesktopIndexMainContent2(this.content, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return DesktopIndexMainContent2State();
}
}
class DesktopIndexMainContent2State extends State<DesktopIndexMainContent2> {
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,
);
}
}

View File

@@ -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<String, dynamic> content;
const DesktopIndexMainContent3(this.content, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return DesktopIndexMainContent3State();
}
}
class DesktopIndexMainContent3State extends State<DesktopIndexMainContent3> {
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,
),
),
],
),
),
],
),
);
}
}

View File

@@ -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<StatefulWidget> createState() {
return DesktopNavigationBarState();
}
}
class DesktopNavigationBarState extends State<DesktopNavigationBar> {
@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',
),
],
),
),
],
),
),
],
);
}
}

View File

@@ -0,0 +1,51 @@
import 'package:flutter/material.dart';
class BottomNav extends StatefulWidget {
const BottomNav({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return BottomNavState();
}
}
class BottomNavState extends State<BottomNav> {
@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,
),
),
),
],
),
);
}
}

View File

@@ -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<StatefulWidget> createState() {
return DownloadItemState();
}
}
class DownloadItemState extends State<DownloadItem> {
@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;
}
}

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<StatefulWidget> createState() {
return NavigationBarState();
}
}
class NavigationBarState extends State<NavigationBar> {
@override
Widget build(BuildContext context) {
return ScreenTypeLayout(
mobile: MobileNavigationBar(),
tablet: DesktopNavigationBar(),
desktop: DesktopNavigationBar(),
);
}
}

View File

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

View File

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

View File

@@ -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<Gallery> galleries;
const MobileIndexCarousel(this.galleries, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MobileIndexCarouselState();
}
}
class MobileIndexCarouselState extends State<MobileIndexCarousel> {
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(),
),
),
],
);
}
}

View File

@@ -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<StatefulWidget> createState() {
return MobileIndexMainContent1State();
}
}
class MobileIndexMainContent1State extends State<MobileIndexMainContent1> {
@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),
),
);
}
}

View File

@@ -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<String, dynamic> content;
const MobileIndexMainContent2(this.content, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MobileIndexMainContent2State();
}
}
class MobileIndexMainContent2State extends State<MobileIndexMainContent2> {
@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,
);
}
}

View File

@@ -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<String, dynamic> content;
const MobileIndexMainContent3(this.content, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MobileIndexMainContent3State();
}
}
class MobileIndexMainContent3State extends State<MobileIndexMainContent3> {
@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,
);
}
}

View File

@@ -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<StatefulWidget> createState() {
return MobileNavigationDrawerState();
}
}
class MobileNavigationDrawerState extends State<MobileNavigationDrawer> {
@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,
),
),
],
),
],
),
),
);
}
}

View File

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

View File

@@ -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<StatefulWidget> createState() {
return MobileNavigationBarState();
}
}
class MobileNavigationBarState extends State<MobileNavigationBar> {
@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()
// ],
// ),
// ),
// ],
// );
}
}