@@ -38,6 +38,7 @@ class BillingController extends ChangeNotifier {
3838 BillingController () {
3939 _initDatabase ();
4040 _checkPrinterStatus ();
41+ checkForUpdates ();
4142 }
4243
4344 Future <void > _initDatabase () async {
@@ -454,4 +455,96 @@ class BillingController extends ChangeNotifier {
454455 ),
455456 ) ?? false ;
456457 }
458+
459+ // 🚀 Auto-Update Feature Variables
460+ static const String appVersion = "1.2.0" ; // Current App Version
461+
462+ bool _hasUpdate = false ;
463+ bool get hasUpdate => _hasUpdate;
464+
465+ bool _isCheckingUpdate = false ;
466+ bool get isCheckingUpdate => _isCheckingUpdate;
467+
468+ String _latestVersion = "" ;
469+ String get latestVersion => _latestVersion;
470+
471+ String _updateDownloadUrl = "" ;
472+ String get updateDownloadUrl => _updateDownloadUrl;
473+
474+ String _updateReleaseNotes = "" ;
475+ String get updateReleaseNotes => _updateReleaseNotes;
476+
477+ Future <void > checkForUpdates () async {
478+ _isCheckingUpdate = true ;
479+ notifyListeners ();
480+
481+ try {
482+ // First try cartsnap repository URL
483+ var response = await http.get (
484+ Uri .parse ('https://api.github.com/repos/1bitVscoder/cartsnap/releases/latest' ),
485+ ).timeout (const Duration (seconds: 5 ));
486+
487+ // Fallback to old smart_billing_app URL if cartsnap repository doesn't exist yet
488+ if (response.statusCode == 404 ) {
489+ response = await http.get (
490+ Uri .parse ('https://api.github.com/repos/1bitVscoder/smart_billing_app/releases/latest' ),
491+ ).timeout (const Duration (seconds: 5 ));
492+ }
493+
494+ if (response.statusCode == 200 ) {
495+ final data = jsonDecode (response.body);
496+ final String tag = data['tag_name' ] ?? "" ;
497+
498+ if (tag.isNotEmpty && _isNewerVersion (tag, appVersion)) {
499+ _hasUpdate = true ;
500+ _latestVersion = tag;
501+ _updateReleaseNotes = data['body' ] ?? "No release notes provided." ;
502+
503+ // Try to find apk asset in the assets list
504+ final assets = data['assets' ] as List ? ;
505+ if (assets != null && assets.isNotEmpty) {
506+ final apkAsset = assets.firstWhere (
507+ (asset) => asset['name' ].toString ().toLowerCase ().endsWith ('.apk' ),
508+ orElse: () => null ,
509+ );
510+ if (apkAsset != null ) {
511+ _updateDownloadUrl = apkAsset['browser_download_url' ] ?? "" ;
512+ }
513+ }
514+
515+ // If no specific APK found, fall back to the release HTML page
516+ if (_updateDownloadUrl.isEmpty) {
517+ _updateDownloadUrl = data['html_url' ] ?? "" ;
518+ }
519+ }
520+ }
521+ } catch (e) {
522+ debugPrint ("Auto-update check exception: $e " );
523+ } finally {
524+ _isCheckingUpdate = false ;
525+ notifyListeners ();
526+ }
527+ }
528+
529+ bool _isNewerVersion (String latest, String current) {
530+ final cleanLatest = latest.replaceAll (RegExp (r'[a-zA-Z]' ), '' ).trim ();
531+ final cleanCurrent = current.replaceAll (RegExp (r'[a-zA-Z]' ), '' ).trim ();
532+
533+ List <int > latestParts = cleanLatest.split ('.' ).map ((e) => int .tryParse (e) ?? 0 ).toList ();
534+ List <int > currentParts = cleanCurrent.split ('.' ).map ((e) => int .tryParse (e) ?? 0 ).toList ();
535+
536+ int maxLength = latestParts.length > currentParts.length ? latestParts.length : currentParts.length;
537+ for (int i = 0 ; i < maxLength; i++ ) {
538+ int latestVal = i < latestParts.length ? latestParts[i] : 0 ;
539+ int currentVal = i < currentParts.length ? currentParts[i] : 0 ;
540+ if (latestVal > currentVal) return true ;
541+ if (latestVal < currentVal) return false ;
542+ }
543+ return false ;
544+ }
545+
546+ void dismissUpdateNotification () {
547+ _hasUpdate = false ;
548+ notifyListeners ();
549+ }
457550}
0 commit comments