qr.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. import 'dart:io';
  2. import 'package:auto_route/auto_route.dart';
  3. import 'package:easy_localization/easy_localization.dart';
  4. import 'package:flutter/foundation.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:image_picker/image_picker.dart';
  8. import 'package:mobile_scanner/mobile_scanner.dart';
  9. import 'package:telnow_mobile_new/src/api/api_auth_provider.dart';
  10. import 'package:telnow_mobile_new/src/api/api_auth_repository.dart';
  11. import 'package:telnow_mobile_new/src/injector/injector.dart';
  12. import 'package:telnow_mobile_new/src/layouts/components/template.dart';
  13. import 'package:telnow_mobile_new/src/layouts/auth/login.dart';
  14. import 'package:telnow_mobile_new/src/storage/sharedpreferences/shared_preferences_manager.dart';
  15. import 'package:telnow_mobile_new/src/utils/U.dart';
  16. import 'package:toggle_switch/toggle_switch.dart';
  17. import 'package:url_launcher/url_launcher.dart';
  18. import 'package:http/http.dart' as http;
  19. @RoutePage()
  20. class NewQrPage extends StatefulWidget {
  21. const NewQrPage({Key? key}) : super(key: key);
  22. @override
  23. State<NewQrPage> createState() => _NewQrPageState();
  24. }
  25. class _NewQrPageState extends State<NewQrPage> {
  26. final SharedPreferencesManager _sharedPreferencesManager = locator<SharedPreferencesManager>();
  27. final ApiAuthRepository apiAuthRepository = ApiAuthRepository();
  28. final ApiAuthProvider apiAuthProvider = ApiAuthProvider();
  29. String? accCode = "";
  30. bool? _isAccCodeExist = false;
  31. String companyName = '';
  32. String serialNumber = '';
  33. String imageUrl = '';
  34. List lang = [];
  35. bool useAsset = false;
  36. int sv = 0;
  37. @override
  38. void initState() {
  39. try {
  40. imageUrl = apiAuthProvider.baseUrl + U.decodeBase64Url(Uri.decodeComponent(U.getAccessCode()!))+'/assets/background/tn';
  41. http.head(Uri.parse(imageUrl));
  42. }catch(e){
  43. useAsset = true;
  44. }
  45. getCompanyName();
  46. // TODO: implement initState
  47. super.initState();
  48. }
  49. getCompanyName() async {
  50. if (_sharedPreferencesManager.isKeyExists(SharedPreferencesManager.keyAccessCode)!) {
  51. var lics = await U.reloadLicense();
  52. if (lics != null && mounted) {
  53. setState(() {
  54. companyName = lics['companyName']??'';
  55. serialNumber = lics['serialNumber']??'';
  56. sv = lics['serverVersion'];
  57. if(1754624839 <= sv){
  58. lang = lics['_validlang'] ?? [];
  59. } else if(1698720817 <= lics['serverVersion']){
  60. lang = lics['languages'] != null ? lics['languages'].split(',') : [];
  61. }
  62. });
  63. }
  64. }
  65. }
  66. @override
  67. Widget build(BuildContext context) {
  68. // accCode = _sharedPreferencesManager.getString(SharedPreferencesManager.keyAccessCode);
  69. // _isAccCodeExist = accCode != "" && accCode != null ? true : false;
  70. // var qp = context.router.current.queryParams;
  71. // bool _scanNew = false;
  72. //
  73. // if (qp.isNotEmpty) {
  74. // _scanNew = qp.getString('new') == "true" ? true : false;
  75. // }
  76. // if (_isAccCodeExist! && !kIsWeb && !_scanNew){
  77. // context.router.removeLast();
  78. // context.navigateToPath("/app/${Uri.encodeComponent(accCode!)}/login");
  79. // }
  80. return Scaffold(
  81. resizeToAvoidBottomInset: false,
  82. body: Stack(
  83. children: [
  84. SizedBox(
  85. width: double.infinity, height: double.infinity,
  86. child: !useAsset ? Image.network(imageUrl, fit: BoxFit.cover, width: double.infinity, height: double.infinity,) :
  87. Image.asset('assets/image/background/background.jpg', fit: BoxFit.cover, width: double.infinity, height: double.infinity),
  88. ),
  89. SingleChildScrollView(
  90. child: Container(
  91. padding: EdgeInsets.fromLTRB(16, kIsWeb?105:200, 16, 16),
  92. width: MediaQuery.of(context).size.width,
  93. height: kIsWeb && MediaQuery.of(context).size.height<700 ? 700 : MediaQuery.of(context).size.height,
  94. decoration: BoxDecoration(
  95. gradient: LinearGradient(
  96. begin: Alignment.topCenter, end: Alignment.bottomCenter,
  97. colors: [
  98. primaryColor.withValues(alpha: 0.50), Colors.black.withValues(alpha: 0.91)
  99. ]
  100. )
  101. ),
  102. child: SafeArea(
  103. child: Column(
  104. crossAxisAlignment: CrossAxisAlignment.center,
  105. children: [
  106. Image.asset('assets/image/logo/logo.png', width: 160),
  107. Expanded(
  108. child: Column(
  109. mainAxisAlignment: MainAxisAlignment.start,
  110. children: [
  111. Container(
  112. margin: EdgeInsets.only(top: 100, left: 16, right: 16, bottom: 48),
  113. child: kIsWeb?Column(
  114. children: [
  115. Text('noPIDText'.tr(), style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500), textAlign: TextAlign.center),
  116. SizedBox(height: 16),
  117. Text('noPIDText2'.tr(), style: TextStyle(color: Colors.white, fontSize: 16), textAlign: TextAlign.center),
  118. ],
  119. ):Text('scanQr'.tr(), style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400), textAlign: TextAlign.center),
  120. ),
  121. !kIsWeb?GestureDetector(
  122. onTap: scanDialog,
  123. child: Container(
  124. padding: EdgeInsets.symmetric(vertical: 32, horizontal: 64),
  125. decoration: BoxDecoration(
  126. color: primaryColor.withValues(alpha: 0.50),
  127. border: Border.all(color: Colors.white),
  128. borderRadius: BorderRadius.all(Radius.circular(12))
  129. ),
  130. child: Row(
  131. mainAxisSize: MainAxisSize.min,
  132. children: [
  133. Text('buttonScan'.tr(), style: TextStyle(color: Colors.white, fontSize: 16)),
  134. SizedBox(width: 10),
  135. U.iconsax('scan', color: Colors.white)
  136. ],
  137. ),
  138. ),
  139. ):Container(),
  140. !kIsWeb && U.getAccessCode() != null ? Padding(
  141. padding: EdgeInsets.only(top: 16),
  142. child: GestureDetector(
  143. child: Text('backToLogin'.tr(), style: TextStyle(color: Colors.white, fontSize: 14, decoration: TextDecoration.underline)),
  144. onTap: (){
  145. context.router.removeLast();
  146. context.navigateToPath("/app/${U.getAccessCode()}/login");
  147. },
  148. )
  149. ) : Container(),
  150. ],
  151. ),
  152. ),
  153. companyName.isNotEmpty?Text(companyName, style: TextStyle(fontSize: 16, color: Colors.white), textAlign: TextAlign.center):Container(),
  154. SizedBox(height: 5),
  155. serialNumber.isNotEmpty?Text('${'serialNumber'.tr()} $serialNumber', style: TextStyle(color: Colors.white, fontSize: 14)):Container(),
  156. SizedBox(height: 5),
  157. GestureDetector(
  158. child: Text('policy'.tr(), style: TextStyle(color: Colors.white, fontSize: 14, decoration: TextDecoration.underline)),
  159. onTap: () async {
  160. Uri _url = Uri.parse('https://telmessenger.com/privacy-police/telnow.html');
  161. await canLaunchUrl(_url) ? await launchUrl(_url) : print('Could not launch $_url');
  162. },
  163. ),
  164. SizedBox(height: 5),
  165. Text('${'version'.tr()} ${ApiAuthProvider().displayVersion}', style: TextStyle(color: Colors.white, fontSize: 14)),
  166. SizedBox(height: 5),
  167. Text('Build ${ApiAuthProvider().buildNumber}', style: TextStyle(color: Colors.white, fontSize: 13)),
  168. ],
  169. ),
  170. ),
  171. ),
  172. ),
  173. Container(
  174. margin: EdgeInsets.only(top: kIsWeb?16:50, right: 16),
  175. child: Align(
  176. alignment: Alignment.topRight,
  177. child: lang.isNotEmpty ? GestureDetector(
  178. child: Container(
  179. width: 65, height: 30, padding: EdgeInsets.symmetric(horizontal: 10),
  180. decoration: BoxDecoration(
  181. color: Colors.deepOrange,
  182. borderRadius: BorderRadius.all(Radius.circular(50))
  183. ),
  184. child: Row(
  185. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  186. children: [
  187. U.iconsax('bold/global', color: Colors.white),
  188. Text(context.locale.toString().toUpperCase(), style: TextStyle(color: Colors.white, fontSize: 15, fontWeight: FontWeight.bold))
  189. ],
  190. ),
  191. ),
  192. onTap: () => changeLangLogin(context, lang),
  193. ) : ToggleSwitch(
  194. minWidth: 40,
  195. minHeight: 30,
  196. cornerRadius: 20,
  197. initialLabelIndex: context.locale.toString() == 'en' ? 0 : 1,
  198. activeBgColor: [Colors.deepOrange],
  199. activeFgColor: Colors.white,
  200. inactiveBgColor: Colors.white54,
  201. inactiveFgColor: Colors.white,
  202. labels: ['EN', 'ID'],
  203. onToggle: (index) {
  204. if (index == 0) {
  205. context.setLocale(Locale('en'));
  206. } else {
  207. context.setLocale(Locale('id'));
  208. }
  209. },
  210. ),
  211. ),
  212. )
  213. ],
  214. ),
  215. );
  216. }
  217. Future scanDialog() async {
  218. try {
  219. final result = await InternetAddress.lookup('google.com');
  220. if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
  221. // String barcode = await FlutterBarcodeScanner.scanBarcode('#ff6666', 'Cancel', true, ScanMode.QR);
  222. showModalBottomSheet<void>(
  223. context: context,
  224. backgroundColor: Colors.white,
  225. builder: (BuildContext contextt) {
  226. return SafeArea(
  227. child: Column(
  228. mainAxisSize: MainAxisSize.min,
  229. children: <Widget>[
  230. Padding(
  231. padding: const EdgeInsets.only(top: 15, bottom: 15),
  232. child: Center(
  233. child: Text('buttonScan'.tr(), style: TextStyle(color: textColor, fontWeight: FontWeight.w600)),
  234. ),
  235. ),
  236. divider(),
  237. ListTile(
  238. leading: Icon(Icons.image),
  239. title: Text('fromGallery'.tr(), style: TextStyle(color: textColor)),
  240. onTap: () async{
  241. Navigator.of(contextt).pop();
  242. XFile? file = await ImagePicker().pickImage(source: ImageSource.gallery);
  243. if(file != null){
  244. final BarcodeCapture? barcodeCapture = await MobileScannerController().analyzeImage(file.path);
  245. String? str = barcodeCapture?.barcodes.singleOrNull?.displayValue;
  246. if (str != null) {
  247. scan(str);
  248. }
  249. else{
  250. showError(context, 'messageInvalidCode'.tr());
  251. }
  252. }
  253. },
  254. ),
  255. ListTile(
  256. leading: Icon(Icons.camera),
  257. title: Text('fromCamera'.tr(), style: TextStyle(color: textColor)),
  258. onTap: () async{
  259. Navigator.of(contextt).pop();
  260. Navigator.push(context, MaterialPageRoute(builder: (context) => const ScanBarcodePage())).then((barcode){
  261. if(barcode != null){
  262. scan(barcode);
  263. }
  264. });
  265. },
  266. )
  267. ],
  268. ),
  269. );
  270. }
  271. );
  272. }
  273. } on SocketException catch (_) {
  274. handlingError(context, 0); //no internet
  275. } on PlatformException catch (e) {
  276. if (e.code != '') {
  277. showError(context, 'messageCamPermission'.tr());
  278. } else {
  279. showError(context, 'messageInvalidCode'.tr());
  280. }
  281. } catch (e) {
  282. showError(context, 'messageInvalidCode'.tr());
  283. }
  284. }
  285. Future scan(String barcode) async {
  286. // print("called scan()");
  287. try {
  288. var pidString = barcode.split("app/").last;
  289. var pid = Uri.decodeComponent(pidString.split('/').first);
  290. var splitPID = pid.split('#');
  291. // print(splitPID);
  292. // print(U.decodeBase64Url(splitPID[1]));
  293. await _sharedPreferencesManager.clearKey(SharedPreferencesManager.version);
  294. await _sharedPreferencesManager.putString(SharedPreferencesManager.keyBaseUrl, U.rewriteUrl(splitPID[1]));
  295. await _sharedPreferencesManager.putString(SharedPreferencesManager.keyAccessCode, splitPID[0]);
  296. await _sharedPreferencesManager.putString(SharedPreferencesManager.keySerialCode, 'P-${splitPID[0]}');
  297. apiAuthRepository.init();
  298. if (!pidString.contains('loginme')) {
  299. context.router.removeLast();
  300. context.navigateToPath("/app/${Uri.encodeComponent(splitPID[0])}/login");
  301. } else {
  302. context.router.removeLast();
  303. context.navigateToPath("/app/${Uri.encodeComponent(splitPID[0])}/loginme"+pidString.split("/loginme").last);
  304. }
  305. } catch (e) {
  306. print(e);
  307. if(mounted) showError(context, 'messageInvalidCode'.tr());
  308. }
  309. }
  310. }
  311. class ScanBarcodePage extends StatefulWidget {
  312. const ScanBarcodePage({super.key});
  313. @override
  314. State<ScanBarcodePage> createState() => _ScanBarcodePageState();
  315. }
  316. class _ScanBarcodePageState extends State<ScanBarcodePage> {
  317. @override
  318. Widget build(BuildContext context) {
  319. return Scaffold(
  320. body: MobileScanner(
  321. onDetect: (barcodes) {
  322. // print('sini');
  323. // print(barcodes.barcodes.singleOrNull?.displayValue);
  324. Navigator.of(context).pop(barcodes.barcodes.firstOrNull?.displayValue);
  325. },
  326. ),
  327. );
  328. }
  329. }