refactor: Global plausible / signin / log

release/mobdr-v0.0.1
Frédérik Benoist 2023-06-10 18:01:01 +02:00
parent cf394811d2
commit 58b836b90b
19 changed files with 406 additions and 252 deletions

View File

@ -4,19 +4,20 @@ import 'dart:convert';
/// Plausible class. Use the constructor to set the parameters. /// Plausible class. Use the constructor to set the parameters.
class PlausibleTracker { class PlausibleTracker {
/// The url of your plausible server e.g. https://plausible.io
String serverUrl; String serverUrl;
String userAgent; String userAgent;
String domain; String domain;
String screenWidth; String screenWidth;
String xForwardedFor; String xForwardedFor;
bool enabled = true; bool enabled = false;
/// Constructor /// Constructor
PlausibleTracker(this.serverUrl, this.domain, PlausibleTracker(
{this.userAgent = "", {required this.serverUrl,
this.screenWidth = "", required this.domain,
this.xForwardedFor = "127.0.0.1"}); required this.userAgent,
required this.screenWidth,
required this.xForwardedFor});
/// Post event to plausible /// Post event to plausible
Future<int> event( Future<int> event(
@ -75,6 +76,8 @@ class PlausibleTracker {
/// check if plausible is UP /// check if plausible is UP
Future<bool> hello() async { Future<bool> hello() async {
this.enabled = false;
try { try {
final client = HttpClient(); final client = HttpClient();
final request = await client.getUrl(Uri.parse(serverUrl + '/api/health')); final request = await client.getUrl(Uri.parse(serverUrl + '/api/health'));
@ -88,7 +91,7 @@ class PlausibleTracker {
final postgresStatus = json['postgres']; final postgresStatus = json['postgres'];
final sitesCacheStatus = json['sites_cache']; final sitesCacheStatus = json['sites_cache'];
return clickhouseStatus == 'ok' && this.enabled = clickhouseStatus == 'ok' &&
postgresStatus == 'ok' && postgresStatus == 'ok' &&
sitesCacheStatus == 'ok'; sitesCacheStatus == 'ok';
} }
@ -98,6 +101,6 @@ class PlausibleTracker {
} }
} }
return false; return this.enabled;
} }
} }

View File

@ -16,6 +16,7 @@ import 'package:mobdr/cubit/language/initial_language.dart';
import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/service/shared_prefs.dart';
import 'package:mobdr/ui/splash_screen.dart'; import 'package:mobdr/ui/splash_screen.dart';
import 'package:mobdr/service/device_info.dart'; import 'package:mobdr/service/device_info.dart';
import 'package:mobdr/service/package_info.dart';
import 'package:mobdr/service/directories.dart'; import 'package:mobdr/service/directories.dart';
import 'package:mobdr/service/plausible.dart'; import 'package:mobdr/service/plausible.dart';
@ -55,11 +56,18 @@ Future<void> main() async {
// get/set device informations // get/set device informations
await device_info_plus().initPlatformState(); await device_info_plus().initPlatformState();
// get/set device informations
await package_info_plus().initPackageInfo();
// set device screenWidth/height
SharedPrefs().screenWidth = window.physicalSize.width;
SharedPrefs().screenHeight = window.physicalSize.height;
// initialize directories // initialize directories
await directories().initDirectories(); await directories().initDirectories();
/// initialize tracker plausible analytics /// initialize tracker plausible analytics
await PlausibleUtil.initializePlausible(window.physicalSize.width); await PlausibleUtil.initializePlausible();
// initialize time zone current device // initialize time zone current device
SharedPrefs().timeZone = getCurrentTimeZone(DateTime.now()); SharedPrefs().timeZone = getCurrentTimeZone(DateTime.now());
@ -69,14 +77,8 @@ Future<void> main() async {
'https://mp4.ikksgroup.com/MobilePortal4/index.html#ajax/dashboard.html'; 'https://mp4.ikksgroup.com/MobilePortal4/index.html#ajax/dashboard.html';
// track MobBR // track MobBR
LoggerUtil.dblog('LOG', 'MOBDR', 'Ouverture application', 0); LoggerUtil.dblog(
PlausibleUtil.addEvent( 'LOG', 'MOBDR', 'Démarrage MobDR ' + SharedPrefs().appVersion, 0);
name: 'access',
page: 'access',
referrer: 'referrerPage',
props: {
'name': SharedPrefs().login,
});
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) { .then((_) {
@ -112,20 +114,8 @@ class MyApp extends StatelessWidget with WidgetsBindingObserver {
} else if (state == AppLifecycleState.resumed) { } else if (state == AppLifecycleState.resumed) {
LoggerUtil.logNStackInfo("The application is resumed"); LoggerUtil.logNStackInfo("The application is resumed");
if (PlausibleUtil.isPlausibleInitialized()) { // check if plausible is up and running
// check if plausible is UP await PlausibleUtil.checkPlausibleUp();
await PlausibleUtil.hello();
PlausibleUtil.addEvent(
name: 'access',
page: 'access',
referrer: 'referrerPage',
props: {
'name': SharedPrefs().login,
});
} else {
await PlausibleUtil.initializePlausible(window.physicalSize.width);
}
} else if (state == AppLifecycleState.inactive) { } else if (state == AppLifecycleState.inactive) {
LoggerUtil.logNStackInfo("The application is inactive"); LoggerUtil.logNStackInfo("The application is inactive");
} else if (state == AppLifecycleState.detached) { } else if (state == AppLifecycleState.detached) {

View File

@ -1,5 +1,4 @@
import 'dart:io'; import 'dart:io';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
@ -118,25 +117,23 @@ class ApiProvider {
Future<String> login( Future<String> login(
String userName, String pinCode, String securityCode) async { String userName, String pinCode, String securityCode) async {
var body = { var body = {
// TODO A REMPLIR "application": "MobDR " + SharedPrefs().appVersion,
"application": "MobDR ", //+ ExeInfo(exeVersion)
"pin_code": md5.convert(utf8.encode(pinCode)), "pin_code": md5.convert(utf8.encode(pinCode)),
"security_code": securityCode, //sCodeSecurite "security_code": securityCode,
"langage": "fr", "langage": SharedPrefs().langage,
"screenheight": "0", //SysYRes() "screenheight": SharedPrefs().screenHeight.truncate().toString(),
"screenwidth": "0", //SysXRes() "screenwidth": SharedPrefs().screenWidth.truncate().toString(),
"browser_name": "Natif", "browser_name": "Natif",
"browser_version": "Application", "browser_version": "Flutter",
"engine_name": "Android", "engine_name": SharedPrefs().systemName,
"device_model": "", "device_model": SharedPrefs().deviceModel,
"device_type": "mobile", //SysInfoAppareil(sysModele) WDM 23 "device_type": SharedPrefs().deviceName,
"device_vendor": "", //SysInfoAppareil(sysFabricant) WDM 23 "device_vendor": SharedPrefs().systemName,
"ismobile": 1, "ismobile": 1,
"engine_version": "", // SysVersionAndroid(sysVersionApiLevel) "engine_version": SharedPrefs().systemName,
"os_name": "", // SysVersionAndroid(sysVersionPlateForme) "os_name": SharedPrefs().systemName,
"os_version": "", //SysVersionAndroid(sysVersionNumÈro) "os_version": SharedPrefs().systemVersion,
"fingerprint": "fingerprint": SharedPrefs().fingerPrint
"aa" // TODO: on peut mettre un fingerprint sur la version ou sur l'heure
}; };
Response response; Response response;
@ -150,8 +147,6 @@ class ApiProvider {
'/guid', '/guid',
body); body);
print('res : ' + response.toString());
switch (response.data['autorisation']) { switch (response.data['autorisation']) {
case 1: case 1:

View File

@ -1,14 +1,23 @@
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'dart:convert'; import 'dart:convert';
import 'package:mobdr/service/logger_util.dart';
Future<String> getPublicIPAddress() async { Future<String> getPublicIPAddress() async {
try { try {
var response = Stopwatch stopwatch = Stopwatch()..start();
await http.get(Uri.parse('https://api.ipify.org/?format=json'));
var response = await http
.get(Uri.parse('https://api.bigdatacloud.net/data/client-ip'));
stopwatch.stop();
// log tracker
LoggerUtil.dblog(
'LOG', 'MOBDR', 'Get IPAddress', stopwatch.elapsedMilliseconds);
if (response.statusCode == 200) { if (response.statusCode == 200) {
var data = json.decode(response.body); var data = json.decode(response.body);
return data['ip']; return data['ipString'];
} }
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());

View File

@ -1,7 +1,8 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:io'; import 'dart:io';
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:device_info_plus/device_info_plus.dart'; import 'package:device_info_plus/device_info_plus.dart';
import 'package:mobdr/service/logger_util.dart'; import 'package:mobdr/service/logger_util.dart';
import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/service/shared_prefs.dart';
@ -19,8 +20,27 @@ class device_info_plus {
if (Platform.isAndroid) { if (Platform.isAndroid) {
deviceData = deviceData =
_readAndroidBuildData(await deviceInfoPlugin.androidInfo); _readAndroidBuildData(await deviceInfoPlugin.androidInfo);
// device related info
SharedPrefs().systemName = deviceData['brand'];
SharedPrefs().deviceModel = deviceData['model'];
SharedPrefs().deviceName = deviceData['device'];
SharedPrefs().systemVersion = deviceData['version.release'];
SharedPrefs().fingerPrint = md5
.convert(utf8.encode("${deviceData['fingerprint']}"))
.toString();
} else if (Platform.isIOS) { } else if (Platform.isIOS) {
deviceData = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo); deviceData = _readIosDeviceInfo(await deviceInfoPlugin.iosInfo);
// device related info
SharedPrefs().systemName = deviceData['systemName'];
SharedPrefs().deviceModel = deviceData['model'];
SharedPrefs().deviceName = deviceData['name'];
SharedPrefs().systemVersion = deviceData['systemVersion'];
SharedPrefs().fingerPrint = md5
.convert(utf8.encode(
"${deviceData['name']}${deviceData['model']}${deviceData['identifierForVendor']}${deviceData['systemVersion']}${deviceData['systemName']}${deviceData['localizedModel']}"))
.toString();
} else if (Platform.isLinux) { } else if (Platform.isLinux) {
deviceData = _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo); deviceData = _readLinuxDeviceInfo(await deviceInfoPlugin.linuxInfo);
} else if (Platform.isMacOS) { } else if (Platform.isMacOS) {
@ -198,10 +218,11 @@ class device_info_plus {
} }
String buildUserAgent(Map<String, dynamic> deviceData) { String buildUserAgent(Map<String, dynamic> deviceData) {
String systemName = deviceData['systemName']; if (Platform.isAndroid) {
String systemVersion = deviceData['systemVersion']; return "${deviceData['brand']} ${deviceData['version.release']}; ${deviceData['model']}";
String model = deviceData['model']; } else if (Platform.isIOS) {
return "${deviceData['systemName']} ${deviceData['systemVersion']}; ${deviceData['model']}";
return '$systemName $systemVersion; $model'; } else
return "NO_USER_AGENT";
} }
} }

View File

@ -0,0 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:mobdr/service/shared_prefs.dart';
class package_info_plus {
Future<void> initPackageInfo() async {
if (!kIsWeb) {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
SharedPrefs().appVersion = packageInfo.version;
}
}
}

View File

@ -5,39 +5,50 @@ import 'package:mobdr/network/get_ip_address.dart';
class PlausibleUtil { class PlausibleUtil {
static PlausibleTracker? plausible; static PlausibleTracker? plausible;
static bool isPlausibleInitialized() { static Future<void> initializePlausible() async {
return plausible != null; final ipAddress = await getPublicIPAddress();
}
static Future<void> initializePlausible(double screenWidth) async {
plausible = PlausibleTracker( plausible = PlausibleTracker(
"https://plausible.q2ii.fr", serverUrl: "https://plausible.q2ii.fr",
"mobdr.ikksgroup.com", domain: "mobdr.ikksgroup.com",
userAgent: SharedPrefs().mobileUserAgent,
screenWidth: SharedPrefs().screenWidth.toString(),
xForwardedFor: ipAddress,
); );
await plausible!.hello();
plausible!.userAgent = SharedPrefs().mobileUserAgent;
plausible!.xForwardedFor = await getPublicIPAddress();
plausible!.screenWidth = screenWidth.toString();
plausible!.enabled = await plausible!.hello();
} }
static Future<void> hello() async { static bool isPlausibleEnabled() {
plausible!.enabled = await plausible!.hello(); return plausible?.enabled ?? false;
} }
static void addEvent({ static Future<void> checkPlausibleUp() async {
await plausible?.hello();
if (isPlausibleEnabled() && SharedPrefs().login.isNotEmpty) {
// track application access
PlausibleUtil.addEventAsync(
name: 'access',
page: 'access',
referrer: 'referrerPage',
props: {
'name': SharedPrefs().login,
});
}
}
static void addEventAsync({
required String name, required String name,
required String page, required String page,
String? referrer, String? referrer,
Map<String, String>? props, Map<String, String>? props,
}) { }) async {
PlausibleUtil.plausible?.event( if (isPlausibleEnabled()) {
name: name, plausible?.event(
page: page, name: name,
referrer: referrer ?? '', page: page,
props: props ?? {}, referrer: referrer ?? '',
); props: props ?? {},
);
}
} }
} }

View File

@ -177,9 +177,68 @@ class SharedPrefs {
} }
/// get/set user time zone /// get/set user time zone
String get timeZone => _sharedPrefs.getString('key_timeZone') ?? ""; String get timeZone => _sharedPrefs.getString('key_timezone') ?? "";
set timeZone(String value) { set timeZone(String value) {
_sharedPrefs.setString('key_timeZone', value); _sharedPrefs.setString('key_timezone', value);
}
/// get/set screenWidth
double get screenWidth => _sharedPrefs.getDouble('key_screenwidth') ?? 0;
set screenWidth(double value) {
_sharedPrefs.setDouble('key_screenwidth', value);
}
/// get/set screenHeight
double get screenHeight => _sharedPrefs.getDouble('key_screenheight') ?? 0;
set screenHeight(double value) {
_sharedPrefs.setDouble('key_screenheight', value);
}
/// get/set appVersion
String get appVersion => _sharedPrefs.getString('key_appversion') ?? "";
set appVersion(String value) {
_sharedPrefs.setString('key_appversion', value);
}
/// get/set fingerPrint
String get fingerPrint =>
_sharedPrefs.getString('key_fingerprint') ??
"b42c213ee55376e501bbf4a7a8607bdc"; //NOFINGERPRINT"
set fingerPrint(String value) {
_sharedPrefs.setString('key_fingerprint', value);
}
/// get/set systemName
String get systemName => _sharedPrefs.getString('key_systemname') ?? "";
set systemName(String value) {
_sharedPrefs.setString('key_systemname', value);
}
/// get/set device_model
String get deviceModel => _sharedPrefs.getString('key_device_model') ?? "";
set deviceModel(String value) {
_sharedPrefs.setString('key_device_model', value);
}
/// get/set device Name
String get deviceName => _sharedPrefs.getString('key_device_name') ?? "";
set deviceName(String value) {
_sharedPrefs.setString('key_device_name', value);
}
/// get/set systemVersion
String get systemVersion =>
_sharedPrefs.getString('key_system_version') ?? "";
set systemVersion(String value) {
_sharedPrefs.setString('key_system_version', value);
} }
} }

View File

@ -1,9 +1,8 @@
import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/constant.dart';
import 'package:mobdr/config/global_style.dart'; import 'package:mobdr/config/global_style.dart';
import 'package:mobdr/service/shared_prefs.dart';
import 'package:mobdr/ui/reusable/reusable_widget.dart'; import 'package:mobdr/ui/reusable/reusable_widget.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
class AboutPage extends StatefulWidget { class AboutPage extends StatefulWidget {
@override @override
@ -14,20 +13,8 @@ class _AboutPageState extends State<AboutPage> {
// initialize reusable widget // initialize reusable widget
final _reusableWidget = ReusableWidget(); final _reusableWidget = ReusableWidget();
String _version = '1.0.0';
Future<void> _getSystemDevice() async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
setState(() {
_version = packageInfo.version;
});
}
@override @override
void initState() { void initState() {
if (!kIsWeb) {
_getSystemDevice();
}
super.initState(); super.initState();
} }
@ -64,7 +51,7 @@ class _AboutPageState extends State<AboutPage> {
height: 5, height: 5,
), ),
Text( Text(
_version, SharedPrefs().appVersion,
style: TextStyle(fontSize: 14, color: CHARCOAL), style: TextStyle(fontSize: 14, color: CHARCOAL),
), ),
], ],

View File

@ -77,7 +77,7 @@ class _LogPageState extends State<LogPage> {
// track & log page access // track & log page access
final page = 'log'; final page = 'log';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
} }
@override @override
@ -90,7 +90,7 @@ class _LogPageState extends State<LogPage> {
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
title: Text('Confirmation'), title: Text('Confirmation'),
content: Text('Are you sure you want to delete this log?'), content: Text('Are you sure you want to delete these logs ?'),
actions: [ actions: [
TextButton( TextButton(
child: Text('Cancel'), child: Text('Cancel'),

View File

@ -28,7 +28,7 @@ class _SettingsPageState extends State<SettingsPage> {
// track & log page access // track & log page access
final page = 'settings'; final page = 'settings';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
setState(() { setState(() {
_photoQuality = SharedPrefs().photoQuality; _photoQuality = SharedPrefs().photoQuality;
@ -315,6 +315,7 @@ class _SettingsPageState extends State<SettingsPage> {
SharedPrefs().langage = 'fr'; SharedPrefs().langage = 'fr';
break; break;
default: default:
// TODO a vérifier
_language = 'French'; _language = 'French';
break; break;
} }

View File

@ -5,6 +5,7 @@ import 'package:mobdr/network/api_provider.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:mobdr/ui/home.dart'; import 'package:mobdr/ui/home.dart';
import 'package:mobdr/ui/authentication/verification.dart'; import 'package:mobdr/ui/authentication/verification.dart';
import 'package:mobdr/service/shared_prefs.dart';
class SigninPage extends StatefulWidget { class SigninPage extends StatefulWidget {
@override @override
@ -37,8 +38,21 @@ class _SigninPageState extends State<SigninPage> {
@override @override
void initState() { void initState() {
_etUserName = TextEditingController(text: 'fbenoist'); _etUserName = TextEditingController(text: SharedPrefs().login);
_etPinCode = TextEditingController(text: '9295'); _etPinCode = TextEditingController(text: '');
// clear all user information except login
SharedPrefs().id_utilisateur = 0;
SharedPrefs().email = "";
SharedPrefs().expire = 0;
SharedPrefs().guid = "";
SharedPrefs().langage = "";
SharedPrefs().last_traduction = "";
SharedPrefs().nom = "";
SharedPrefs().prenom = "";
SharedPrefs().version = "";
SharedPrefs().photo = "";
super.initState(); super.initState();
} }
@ -106,7 +120,7 @@ class _SigninPageState extends State<SigninPage> {
height: 20, height: 20,
), ),
TextField( TextField(
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.text,
controller: _etUserName, controller: _etUserName,
decoration: InputDecoration( decoration: InputDecoration(
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
@ -116,7 +130,7 @@ class _SigninPageState extends State<SigninPage> {
borderSide: borderSide:
BorderSide(color: _underlineColor), BorderSide(color: _underlineColor),
), ),
labelText: 'Email', labelText: 'User name',
labelStyle: labelStyle:
TextStyle(color: Colors.grey[700])), TextStyle(color: Colors.grey[700])),
), ),
@ -125,6 +139,7 @@ class _SigninPageState extends State<SigninPage> {
), ),
TextField( TextField(
obscureText: _obscureText, obscureText: _obscureText,
keyboardType: TextInputType.number,
controller: _etPinCode, controller: _etPinCode,
decoration: InputDecoration( decoration: InputDecoration(
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
@ -166,6 +181,7 @@ class _SigninPageState extends State<SigninPage> {
//Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) => HomePage()), (Route<dynamic> route) => false); //Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) => HomePage()), (Route<dynamic> route) => false);
var apiResponse = await _apiProvider.login( var apiResponse = await _apiProvider.login(
_etUserName.text, _etPinCode.text, ''); _etUserName.text, _etPinCode.text, '');
if (apiResponse == 'OK') { if (apiResponse == 'OK') {
Navigator.of(context).pushAndRemoveUntil( Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute( MaterialPageRoute(
@ -175,8 +191,10 @@ class _SigninPageState extends State<SigninPage> {
Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (_) => builder: (_) => VerificationPage(
VerificationPage())); pp_userName: _etUserName.text,
pp_pinCode:
_etPinCode.text)));
} else { } else {
Fluttertoast.showToast( Fluttertoast.showToast(
msg: apiResponse, msg: apiResponse,

View File

@ -1,16 +1,27 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
import 'package:pin_code_fields/pin_code_fields.dart'; import 'package:pin_code_fields/pin_code_fields.dart';
import 'package:mobdr/config/global_style.dart';
import 'package:mobdr/ui/reusable/reusable_widget.dart';
import 'package:mobdr/network/api_provider.dart'; import 'package:mobdr/network/api_provider.dart';
import 'package:mobdr/ui/home.dart'; import 'package:mobdr/ui/home.dart';
import 'package:mobdr/ui/authentication/signin.dart'; import 'package:mobdr/ui/authentication/signin.dart';
class VerificationPage extends StatefulWidget { class VerificationPage extends StatefulWidget {
final String pp_userName;
final String pp_pinCode;
VerificationPage({required this.pp_userName, required this.pp_pinCode});
@override @override
_VerificationPageState createState() => _VerificationPageState(); _VerificationPageState createState() => _VerificationPageState();
} }
class _VerificationPageState extends State<VerificationPage> { class _VerificationPageState extends State<VerificationPage> {
// initialize reusable widget
final _reusableWidget = ReusableWidget();
Color _color1 = Color(0xFF07ac12); Color _color1 = Color(0xFF07ac12);
Color _color2 = Color(0xFF515151); Color _color2 = Color(0xFF515151);
Color _color3 = Color(0xff777777); Color _color3 = Color(0xff777777);
@ -33,140 +44,159 @@ class _VerificationPageState extends State<VerificationPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(
color: GlobalStyle.appBarIconThemeColor,
),
elevation: GlobalStyle.appBarElevation,
title: Text(
'Two factor authentification',
style: GlobalStyle.appBarTitle,
),
backgroundColor: GlobalStyle.appBarBackgroundColor,
systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle,
bottom: _reusableWidget.bottomAppBar(),
),
body: ListView( body: ListView(
padding: EdgeInsets.fromLTRB(30, 120, 30, 30), padding: EdgeInsets.fromLTRB(30, 120, 30, 30),
children: <Widget>[ children: <Widget>[
Center(child: Icon(Icons.phone_android, color: _color1, size: 50)), Center(child: Icon(Icons.phone_android, color: _color1, size: 50)),
SizedBox(height: 20), SizedBox(height: 20),
Center( Center(
child: Text(
'Enter the Verification Code',
style: TextStyle(
fontSize: 16, fontWeight: FontWeight.bold, color: _color2),
)),
SizedBox(
height: 20,
),
Container(
width: MediaQuery.of(context).size.width / 1.5,
child: Text(
'The verification code has been sent by mail',
style: TextStyle(fontSize: 13, color: _color3),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 40,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 50),
child: PinCodeTextField(
autoFocus: true,
appContext: context,
keyboardType: TextInputType.number,
length: 4,
showCursor: false,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.underline,
fieldHeight: 50,
fieldWidth: 40,
inactiveColor: _color4,
activeColor: _color1,
selectedColor: _color1),
animationDuration: Duration(milliseconds: 300),
backgroundColor: Colors.transparent,
onChanged: (value) {
setState(() {
if (value.length == 4) {
_buttonDisabled = false;
} else {
_buttonDisabled = true;
}
_securityCode = value;
});
},
beforeTextPaste: (text) {
return false;
},
),
),
SizedBox(
height: 40,
),
Container(
child: SizedBox(
width: double.maxFinite,
child: TextButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) =>
_buttonDisabled ? Colors.grey[300]! : _color1,
),
overlayColor: MaterialStateProperty.all(Colors.transparent),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(3.0),
)),
),
onPressed: () async {
if (!_buttonDisabled) {
FocusScope.of(context).unfocus();
var apiResponse = await _apiProvider.login(
'fbenoist', '9295', _securityCode);
if (apiResponse == 'OK') {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => HomePage()),
(Route<dynamic> route) => false);
} else {
Fluttertoast.showToast(
msg: apiResponse, toastLength: Toast.LENGTH_SHORT);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SigninPage()),
(Route<dynamic> route) => false);
}
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Text(
'Verify',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _buttonDisabled
? Colors.grey[600]
: Colors.white),
textAlign: TextAlign.center,
),
))),
),
SizedBox(
height: 40,
),
Center(
child: Wrap(
children: [
Text(
"Didn't receive the code? ",
style: TextStyle(fontSize: 13, color: _color4),
),
GestureDetector(
onTap: () {
Fluttertoast.showToast(
msg: 'Click resend', toastLength: Toast.LENGTH_SHORT);
},
child: Text( child: Text(
'Resend', 'Enter the Verification Code',
style: TextStyle(fontSize: 13, color: _color1), style: TextStyle(
), fontSize: 16, fontWeight: FontWeight.bold, color: _color2),
) )),
], SizedBox(
), height: 20,
), ),
], Container(
)); width: MediaQuery.of(context).size.width / 1.5,
child: Text(
'The verification code has been sent by mail',
style: TextStyle(fontSize: 13, color: _color3),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 40,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: 50),
child: PinCodeTextField(
autoFocus: true,
appContext: context,
keyboardType: TextInputType.text,
length: 4,
showCursor: false,
obscureText: false,
animationType: AnimationType.fade,
pinTheme: PinTheme(
shape: PinCodeFieldShape.underline,
fieldHeight: 50,
fieldWidth: 40,
inactiveColor: _color4,
activeColor: _color1,
selectedColor: _color1),
animationDuration: Duration(milliseconds: 300),
backgroundColor: Colors.transparent,
onChanged: (value) {
setState(() {
if (value.length == 4) {
_buttonDisabled = false;
} else {
_buttonDisabled = true;
}
_securityCode = value;
});
},
beforeTextPaste: (text) {
return false;
},
),
),
SizedBox(
height: 40,
),
Container(
child: SizedBox(
width: double.maxFinite,
child: TextButton(
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) =>
_buttonDisabled ? Colors.grey[300]! : _color1,
),
overlayColor:
MaterialStateProperty.all(Colors.transparent),
shape: MaterialStateProperty.all(RoundedRectangleBorder(
borderRadius: BorderRadius.circular(3.0),
)),
),
onPressed: () async {
if (!_buttonDisabled) {
FocusScope.of(context).unfocus();
var apiResponse = await _apiProvider.login(
widget.pp_userName,
widget.pp_pinCode,
_securityCode);
if (apiResponse == 'OK') {
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => HomePage()),
(Route<dynamic> route) => false);
} else {
Fluttertoast.showToast(
msg: apiResponse,
toastLength: Toast.LENGTH_SHORT);
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(
builder: (context) => SigninPage()),
(Route<dynamic> route) => false);
}
}
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Text(
'Verify',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: _buttonDisabled
? Colors.grey[600]
: Colors.white),
textAlign: TextAlign.center,
),
))),
),
SizedBox(
height: 40,
),
Center(
child: Wrap(
children: [
Text(
"Didn't receive the code? ",
style: TextStyle(fontSize: 13, color: _color4),
),
GestureDetector(
onTap: () {
Fluttertoast.showToast(
msg: 'Click resend', toastLength: Toast.LENGTH_SHORT);
},
child: Text(
'Resend',
style: TextStyle(fontSize: 13, color: _color1),
),
)
],
),
),
],
));
} }
} }

View File

@ -23,7 +23,7 @@ class _NotificationPageState extends State<NotificationPage> {
// track & log page access // track & log page access
final page = 'notification'; final page = 'notification';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
} }
@override @override

View File

@ -11,6 +11,7 @@ import 'package:mobdr/config/constant.dart';
import 'package:mobdr/events.dart'; import 'package:mobdr/events.dart';
import 'package:mobdr/service/plausible.dart'; import 'package:mobdr/service/plausible.dart';
import 'package:mobdr/service/logger_util.dart'; import 'package:mobdr/service/logger_util.dart';
import 'package:mobdr/service/plausible.dart';
class HomePage extends StatefulWidget { class HomePage extends StatefulWidget {
@override @override
@ -55,9 +56,18 @@ class _HomePageState extends State<HomePage>
_isSyncing = e.isRunning; _isSyncing = e.isRunning;
}); });
// check if plausible is up and running
doAsyncPlausibleCheck().then((_) {
PlausibleUtil.addEventAsync(name: 'pageview', page: 'tab_home');
});
super.initState(); super.initState();
} }
Future<void> doAsyncPlausibleCheck() async {
await PlausibleUtil.checkPlausibleUp();
}
void _handleTabSelection() { void _handleTabSelection() {
/* /*
setState(() { setState(() {
@ -161,6 +171,6 @@ class _HomePageState extends State<HomePage>
} }
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
} }
} }

View File

@ -4,11 +4,10 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:mobdr/service/shared_prefs.dart'; import 'package:mobdr/service/shared_prefs.dart';
import 'package:mobdr/service/plausible.dart';
import 'package:mobdr/config/constant.dart'; import 'package:mobdr/config/constant.dart';
import 'package:mobdr/ui/onboarding.dart'; import 'package:mobdr/ui/onboarding.dart';
import 'package:mobdr/ui/home.dart'; import 'package:mobdr/ui/home.dart';
import 'package:mobdr/ui/authentication/signin.dart';
class SplashScreenPage extends StatefulWidget { class SplashScreenPage extends StatefulWidget {
@override @override
@ -28,13 +27,22 @@ class _SplashScreenPageState extends State<SplashScreenPage> {
if (_second == 0) { if (_second == 0) {
_cancelFlashsaleTimer(); _cancelFlashsaleTimer();
if (SharedPrefs().onboarding == 0) { // if the user has never seen the onboarding page or the user is not logged in
if (SharedPrefs().onboarding == 0 ||
SharedPrefs().id_utilisateur == 0) {
// see !
SharedPrefs().onboarding = 1; SharedPrefs().onboarding = 1;
PlausibleUtil.addEvent(name: 'pageview', page: 'onboarding');
// go to OnBoarding page
Navigator.pushReplacement(context, Navigator.pushReplacement(context,
MaterialPageRoute(builder: (context) => OnBoardingPage())); MaterialPageRoute(builder: (context) => OnBoardingPage()));
// if the user is not logged in
} else if (SharedPrefs().id_utilisateur == 0) {
// go to sign'in page
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => SigninPage()));
} else { } else {
PlausibleUtil.addEvent(name: 'pageview', page: 'tab_home'); // go to home page !
Navigator.pushReplacement( Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage())); context, MaterialPageRoute(builder: (context) => HomePage()));
} }

View File

@ -110,7 +110,7 @@ class _VisitPhotoTypologyPageState extends State<VisitPhotoTypologyPage> {
// track & log page access // track & log page access
final page = 'visit_photo_typology'; final page = 'visit_photo_typology';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
} }
@override @override

View File

@ -65,7 +65,7 @@ class _VisitPhotoTypologyDetailPageState
// track & log page access // track & log page access
final page = 'visit_photo_typology_detail'; final page = 'visit_photo_typology_detail';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
loadData(widget.pp_imageId).then((_) { loadData(widget.pp_imageId).then((_) {
setState(() { setState(() {

View File

@ -72,7 +72,7 @@ class _VisitPhotoTypologyListPageState
// track & log page access // track & log page access
final page = 'visit_photo_typology_list'; final page = 'visit_photo_typology_list';
LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0); LoggerUtil.dblog('LOG', 'MOBDR', 'Page : ${page}', 0);
PlausibleUtil.addEvent(name: 'pageview', page: page); PlausibleUtil.addEventAsync(name: 'pageview', page: page);
loadData(); loadData();
} }