added foreground service

appointment_merge
Faiz Hashmi 3 months ago
parent 0779955ef0
commit 675441894a

@ -7,7 +7,7 @@ plugins {
android {
namespace = "com.example.hmg_qline.hmg_qline"
compileSdk = flutter.compileSdkVersion
compileSdk = 35
ndkVersion = "27.0.12077973"
compileOptions {

@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<queries>

@ -1,19 +1,24 @@
package com.example.hmg_qline.hmg_qline
import android.app.AlarmManager
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.lifecycle.LifecycleService
import android.app.ActivityManager
class BootForegroundService : LifecycleService() {
override fun onCreate() {
super.onCreate()
startForegroundService()
schedulePeriodicCheck()
}
private fun startForegroundService() {
@ -30,18 +35,73 @@ class BootForegroundService : LifecycleService() {
val notification: Notification = NotificationCompat.Builder(this, channelId)
.setContentTitle("QLine App")
.setContentText("Launching application...")
.setContentText("Monitoring QLine activity...")
.setSmallIcon(R.mipmap.ic_launcher)
.build()
startForeground(1, notification)
// Launch MainActivity
Log.d("BootForegroundService", "Starting MainActivity")
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningProcesses = activityManager.runningAppProcesses
stopSelf() // Stop the service after launching the app
var isAppInForeground = false
for (process in runningProcesses) {
if (process.processName == packageName &&
process.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
) {
isAppInForeground = true
break
}
}
if (!isAppInForeground) {
Log.d("BootForegroundService", "App is NOT in foreground — launching MainActivity.")
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
}
startActivity(intent)
} else {
Log.d("BootForegroundService", "App is already in foreground.")
}
stopSelf() // Stop the service after check
}
private fun schedulePeriodicCheck() {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val intent = Intent(this, BootForegroundService::class.java)
val pendingIntent = PendingIntent.getService(
this,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// Repeat every 1 minute
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + 60 * 1000,
60 * 1000,
pendingIntent
)
}
private fun bringAppToFrontIfNotVisible() {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val runningProcesses = activityManager.runningAppProcesses
val isAppInForeground = runningProcesses.any {
it.processName == packageName && it.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
}
if (!isAppInForeground) {
Log.d("BootForegroundService", "App is not in foreground, launching MainActivity")
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
} else {
Log.d("BootForegroundService", "App is already in foreground")
}
}
}

@ -1,5 +1,27 @@
package com.example.hmg_qline.hmg_qline
import android.content.Intent
import android.os.Bundle
import android.util.Log
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity : FlutterActivity() {}
class MainActivity : FlutterActivity() {
private val CHANNEL = "com.example.hmg_qline/foreground"
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, _ ->
Log.d("MainActivity", "MethodChannel call received: ${call.method}")
if (call.method == "reopenApp") {
Log.d("MainActivity", "reopenApp called, launching MainActivity")
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
}
}
}
}

@ -2,6 +2,7 @@
// import 'package:flutter/material.dart';
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/services.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:get_it/get_it.dart';
import 'package:hmg_qline/api/api_client.dart';
@ -12,6 +13,7 @@ import 'package:hmg_qline/services/cache_service.dart';
import 'package:hmg_qline/services/connectivity_service.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/services/text_to_speech_service.dart';
import 'package:hmg_qline/utilities/native_method_handler.dart';
import 'package:hmg_qline/view_models/queuing_view_model.dart';
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
import 'package:just_audio/just_audio.dart';
@ -39,8 +41,10 @@ class AppDependencies {
getIt.registerSingleton<SignalrRepo>(SignalrRepoImp(loggerService: getIt.get<LoggerService>()));
getIt.registerSingleton<ScreenDetailsRepo>(ScreenDetailsRepoImp(apiClientInstance: getIt.get<ApiClient>(), loggerService: getIt.get<LoggerService>()));
//ThirdPartyServices
//repos
getIt.registerSingleton<NativeMethodChannelService>(NativeMethodChannelServiceImp(loggerService: getIt.get<LoggerService>(), platform: const MethodChannel('com.example.hmg_qline/foreground')));
//ThirdPartyServices
getIt.registerSingleton<ConnectivityService>(ConnectivityServiceImp(connectivityInstance: Connectivity()));
getIt.registerSingleton<CacheService>(CacheServiceImp(preferencesInstance: await SharedPreferences.getInstance()));
getIt.registerSingleton<AudioService>(AudioServiceImp(audioPlayerInstance: AudioPlayer()));
@ -54,6 +58,7 @@ class AppDependencies {
cacheService: getIt.get<CacheService>(),
connectivityService: getIt.get<ConnectivityService>(),
loggerService: getIt.get<LoggerService>(),
nativeMethodChannelService: getIt.get<NativeMethodChannelService>(),
),
);

@ -23,6 +23,9 @@ class AppStrings {
static String dataLogsFileName = "data_logs.txt";
static String errorLogsFileName = "error_logs.txt";
static String openAppNativeFunctionName = "reopenApp";
}
class AppColors {
@ -104,7 +107,7 @@ class AppConstants {
static String testIP = '12.4.5.1'; // projectID.QlineType.ScreenType.AnyNumber (1 to 10)
static int thresholdForListUI = 3;
static int currentBuildVersion = 7;
static double currentBuildVersion = 8.1;
}
class ApiConstants {

@ -9,11 +9,58 @@ import 'package:hmg_qline/view_models/queuing_view_model.dart';
import 'package:hmg_qline/views/view_helpers/size_config.dart';
import 'package:wakelock_plus/wakelock_plus.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AppDependencies.addDependencies();
WakelockPlus.enable();
// Keep the screen on
await WakelockPlus.enable();
// The following foreground task logic is now handled natively in Android. Commented out for clarity.
/*
void _initializeForegroundTask() {
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
channelId: 'foreground_service',
channelName: AppStrings.appName,
channelDescription: '',
onlyAlertOnce: true,
),
iosNotificationOptions: const IOSNotificationOptions(
showNotification: false,
playSound: false,
),
foregroundTaskOptions: ForegroundTaskOptions(
eventAction: ForegroundTaskEventAction.repeat(5000),
autoRunOnBoot: true,
autoRunOnMyPackageReplaced: true,
allowWakeLock: true,
allowWifiLock: true,
),
);
}
Future<void> _startForegroundService() async {
await FlutterForegroundTask.startService(
notificationTitle: AppStrings.appName,
notificationText: 'App is running in foreground',
callback: startCallback,
);
}
// Initialize foreground task first
_initializeForegroundTask();
// Register lifecycle callback (e.g., reopen app on detach)
LifecycleHandler(
onDetached: () {
getIt<NativeMethodChannelService>().reopenApp();
},
).register();
// Start foreground service AFTER initialization
await _startForegroundService();
*/
runApp(const MyApp());
}
@ -26,26 +73,26 @@ class MyApp extends StatelessWidget {
builder: (context, constraints) {
return OrientationBuilder(builder: (context, orientation) {
SizeConfig().init(constraints, orientation);
// SystemChrome.setPreferredOrientations([DeviceOrientation.portraitDown]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: []);
return MultiProvider(
providers: [
ChangeNotifierProvider<ScreenConfigViewModel>(create: (context) => getIt.get<ScreenConfigViewModel>()),
ChangeNotifierProvider<QueuingViewModel>(create: (context) => getIt.get<QueuingViewModel>()),
],
child: MaterialApp(
showSemanticsDebugger: false,
title: AppStrings.appName,
theme: ThemeData(
fontFamily: AppStrings.fontNamePoppins,
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.grey).copyWith(
surface: const Color.fromRGBO(255, 255, 255, 1),
),
providers: [
ChangeNotifierProvider<ScreenConfigViewModel>(create: (context) => getIt.get<ScreenConfigViewModel>()),
ChangeNotifierProvider<QueuingViewModel>(create: (context) => getIt.get<QueuingViewModel>()),
],
child: MaterialApp(
showSemanticsDebugger: false,
title: AppStrings.appName,
theme: ThemeData(
fontFamily: AppStrings.fontNamePoppins,
colorScheme: ColorScheme.fromSwatch(primarySwatch: Colors.grey).copyWith(
surface: const Color.fromRGBO(255, 255, 255, 1),
),
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
debugShowCheckedModeBanner: false,
));
),
initialRoute: AppRoutes.initialRoute,
routes: AppRoutes.routes,
debugShowCheckedModeBanner: false,
),
);
});
},
);

@ -48,9 +48,27 @@ class SignalrRepoImp implements SignalrRepo {
.build();
connection!.serverTimeoutInMilliseconds = 120000;
connection!.onclose((exception) {
int reconnectAttempts = 0;
const int maxReconnectAttempts = 10;
const Duration reconnectDelay = Duration(seconds: 5);
connection!.onclose((exception) async {
log(exception.toString());
onHubDisconnected(exception);
// Attempt to reconnect with limit and delay
if (reconnectAttempts < maxReconnectAttempts) {
reconnectAttempts++;
loggerService.logToFile("SignalR reconnect attempt #$reconnectAttempts", type: LogTypeEnum.data);
await Future.delayed(reconnectDelay);
try {
await connection!.start();
loggerService.logToFile("SignalR reconnected after disconnect", type: LogTypeEnum.data);
reconnectAttempts = 0; // Reset on success
} catch (e) {
loggerService.logError("Reconnect failed: $e");
}
} else {
loggerService.logError("Max SignalR reconnect attempts reached.");
}
});
connection!.onreconnecting((exception) => onHubConnecting(exception));

@ -23,7 +23,7 @@ class LoggerServiceImp implements LoggerService {
@override
Future<void> logToFile(String message, {LogTypeEnum type = LogTypeEnum.data}) async {
try {
final timestamp = DateFormat('yyyy-MM-dd HH:mm:ss a').format(DateTime.now());
final timestamp = DateFormat('yyyy-MM-dd hh:mm:ss a').format(DateTime.now());
final formattedMessage = "[$timestamp] ${type.name.toUpperCase()}: $message";
final dir = await getApplicationDocumentsDirectory();

@ -0,0 +1,22 @@
import 'package:flutter_foreground_task/flutter_foreground_task.dart';
void startCallback() {
FlutterForegroundTask.setTaskHandler(MyTaskHandler());
}
class MyTaskHandler extends TaskHandler {
@override
Future<void> onStart(DateTime timestamp, TaskStarter? starter) async {
// Initialization code, e.g. open DB or services
}
@override
Future<void> onDestroy(DateTime timestamp, bool isTimeout) async {
// Clean up if needed
}
@override
void onRepeatEvent(DateTime timestamp) {
// Called based on the eventAction set in ForegroundTaskOptions
}
}

@ -0,0 +1,51 @@
import 'package:flutter/widgets.dart';
import 'package:hmg_qline/config/dependency_injection.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
class LifecycleHandler extends WidgetsBindingObserver {
final void Function()? onResumed;
final void Function()? onPaused;
final void Function()? onDetached;
final void Function()? onInactive;
final void Function()? onHidden;
LifecycleHandler({
this.onResumed,
this.onPaused,
this.onDetached,
this.onInactive,
this.onHidden,
});
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
LoggerService loggerService = getIt.get<LoggerService>();
loggerService.logInfo("[didChangeAppLifecycleState] : ${state.toString()}");
switch (state) {
case AppLifecycleState.resumed:
onResumed?.call();
break;
case AppLifecycleState.paused:
onPaused?.call();
break;
case AppLifecycleState.inactive:
onInactive?.call();
break;
case AppLifecycleState.detached:
onDetached?.call();
break;
case AppLifecycleState.hidden:
onHidden?.call();
break;
}
}
void register() {
WidgetsBinding.instance.addObserver(this);
}
void unregister() {
WidgetsBinding.instance.removeObserver(this);
}
}

@ -0,0 +1,38 @@
import 'package:flutter/services.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:restart_app/restart_app.dart';
abstract class NativeMethodChannelService {
void reopenApp();
void restartApp();
}
class NativeMethodChannelServiceImp implements NativeMethodChannelService {
MethodChannel platform;
LoggerService loggerService;
NativeMethodChannelServiceImp({required this.platform, required this.loggerService});
@override
void reopenApp() async {
try {
await platform.invokeMethod(AppStrings.openAppNativeFunctionName);
} catch (e) {
loggerService.logError("Error launching app: $e");
loggerService.logToFile("Error launching app: $e", type: LogTypeEnum.error);
}
}
@override
void restartApp() async {
try {
await Restart.restartApp();
} catch (e) {
loggerService.logError("Error restarting App : $e");
loggerService.logToFile("Error restarting App : $e", type: LogTypeEnum.error);
}
}
}

@ -89,6 +89,8 @@ class QueuingViewModel extends ChangeNotifier {
Future<void> onHubReconnected(var response) async {
log("onHubConnected: $response");
loggerService.logToFile("onHubConnected", type: LogTypeEnum.data);
ScreenConfigViewModel screenConfigViewModel = getIt.get<ScreenConfigViewModel>();
screenConfigViewModel.updateIsHubConnected(true);
screenConfigViewModel.notifyListeners();
@ -96,6 +98,8 @@ class QueuingViewModel extends ChangeNotifier {
Future<void> onHubDisconnected(var response) async {
log("onHubDisconnected: $response");
loggerService.logToFile("onHubDisconnected", type: LogTypeEnum.data);
ScreenConfigViewModel screenConfigViewModel = getIt.get<ScreenConfigViewModel>();
screenConfigViewModel.updateIsHubConnected(false);
screenConfigViewModel.notifyListeners();

@ -1,8 +1,10 @@
import 'dart:developer';
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hmg_qline/config/dependency_injection.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/main.dart';
import 'package:hmg_qline/models/generic_response_model.dart';
import 'package:hmg_qline/models/global_config_model.dart';
import 'package:hmg_qline/models/kiosk_language_config_model.dart';
@ -17,6 +19,7 @@ import 'package:hmg_qline/services/connectivity_service.dart';
import 'package:hmg_qline/services/logger_service.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
import 'package:hmg_qline/utilities/native_method_handler.dart';
import 'package:hmg_qline/view_models/queuing_view_model.dart';
import 'package:hmg_qline/views/view_helpers/info_components.dart';
import 'package:qr_code_scanner_plus/qr_code_scanner_plus.dart';
@ -27,12 +30,14 @@ class ScreenConfigViewModel extends ChangeNotifier {
final CacheService cacheService;
final ConnectivityService connectivityService;
final LoggerService loggerService;
final NativeMethodChannelService nativeMethodChannelService;
ScreenConfigViewModel({
required this.screenDetailsRepo,
required this.cacheService,
required this.connectivityService,
required this.loggerService,
required this.nativeMethodChannelService,
});
Future<void> initializeScreenConfigVM() async {
@ -42,6 +47,18 @@ class ScreenConfigViewModel extends ChangeNotifier {
getTheWidgetsConfigurationsEveryMidnight();
}
Future<void> onAppResumed() async {
loggerService.logToFile("[didChangeAppLifecycleState] : [onAppResumed]", type: LogTypeEnum.data);
}
Future<void> onAppPaused() async {
loggerService.logToFile("[didChangeAppLifecycleState] : [onAppPaused]", type: LogTypeEnum.data);
// nativeMethodChannelService.reopenApp();
nativeMethodChannelService.restartApp();
runApp(const MyApp());
}
Future<void> waitForIPAndInitializeConfigVM() async {
while (currentScreenIP == "") {
await getCurrentScreenIP();
@ -103,14 +120,17 @@ class ScreenConfigViewModel extends ChangeNotifier {
}
void listenNetworkConnectivity() {
return connectivityService.subscribeToConnectivityChange(onInternetDisConnected: () {
updateIsInternetConnected(false);
updateIsHubConnected(false);
}, onInternetConnected: () {
updateIsInternetConnected(true);
QueuingViewModel queuingViewModel = getIt.get<QueuingViewModel>();
queuingViewModel.startHubConnection();
});
return connectivityService.subscribeToConnectivityChange(
onInternetDisConnected: () {
updateIsInternetConnected(false);
updateIsHubConnected(false);
},
onInternetConnected: () {
updateIsInternetConnected(true);
QueuingViewModel queuingViewModel = getIt.get<QueuingViewModel>();
queuingViewModel.startHubConnection();
},
);
}
GlobalConfigurationsModel globalConfigurationsModel = GlobalConfigurationsModel();
@ -267,48 +287,51 @@ class ScreenConfigViewModel extends ChangeNotifier {
int counter = 0;
Timer? _midnightTimer;
Future<void> getTheWidgetsConfigurationsEveryMidnight() async {
// Cancel any existing timer to avoid multiple timers running
_midnightTimer?.cancel();
if (!(globalConfigurationsModel.isWeatherReq) && !(globalConfigurationsModel.isPrayerTimeReq) && !(globalConfigurationsModel.isRssFeedReq)) {
return;
}
DateTime current = DateTime.now();
Stream timer = Stream.periodic(const Duration(minutes: 1), (i) {
current = current.add(const Duration(minutes: 1));
return current;
});
timer.listen((data) async {
DateTime dateTime = DateTime.parse(data.toString());
int counter = 0;
DateTime lastChecked = DateTime.now();
_midnightTimer = Timer.periodic(const Duration(minutes: 5), (timer) async {
counter++;
DateTime now = DateTime.now();
log("counterValue: $counter");
if (counter == 60 && globalConfigurationsModel.isRssFeedReq) {
// Every hour, update RSS feed if required
if (counter % 12 == 0 && globalConfigurationsModel.isRssFeedReq) {
await getRssFeedDetailsFromServer();
}
if (globalConfigurationsModel.isWeatherReq) {
if (dateTime.day > currentLastTimeUpdated.day) {
log("lastChecked: [${lastChecked.day}]");
log("now: [${now.day}]");
// At midnight, update weather and prayer details if required
if (now.day != lastChecked.day) {
if (globalConfigurationsModel.isWeatherReq) {
await getWeatherDetailsFromServer();
}
}
if (globalConfigurationsModel.isPrayerTimeReq) {
if (dateTime.day > currentLastTimeUpdated.day) {
if (globalConfigurationsModel.isPrayerTimeReq) {
await getPrayerDetailsFromServer();
}
lastChecked = now;
}
});
}
if (globalConfigurationsModel.isRssFeedReq) {
if (dateTime.day > currentLastTimeUpdated.day) {
await getRssFeedDetailsFromServer();
}
}
@override
void dispose() {
_midnightTimer?.cancel();
patientIdController.dispose();
getNextPrayerToShow();
});
super.dispose();
}
DateTime currentLastTimeUpdated = DateTime.now();
@ -432,12 +455,6 @@ class ScreenConfigViewModel extends ChangeNotifier {
final TextEditingController patientIdController = TextEditingController();
@override
void dispose() {
patientIdController.dispose();
super.dispose();
}
Future<void> onPatientIdSubmitted(String text) async {
int? patientId = int.tryParse(text);
if (patientId != null && patientId > 0) {

@ -32,10 +32,10 @@ class AppFooter extends StatelessWidget {
AppStrings.poweredBy,
fontSize: SizeConfig.getWidthMultiplier() * 2.5,
),
Text("v${screenConfigVM.currentScreenIP}_${AppConstants.currentBuildVersion}",
Text("v${screenConfigVM.currentScreenIP}(${AppConstants.currentBuildVersion})",
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: SizeConfig.getWidthMultiplier() * 1.7,
fontSize: SizeConfig.getWidthMultiplier() * 1.5,
)),
Row(
children: [

@ -1,7 +1,12 @@
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:hmg_qline/config/dependency_injection.dart';
import 'package:hmg_qline/constants/app_constants.dart';
import 'package:hmg_qline/utilities/enums.dart';
import 'package:hmg_qline/utilities/extensions.dart';
import 'package:hmg_qline/utilities/lifecycle_handler.dart';
import 'package:hmg_qline/utilities/native_method_handler.dart';
import 'package:hmg_qline/view_models/queuing_view_model.dart';
import 'package:hmg_qline/view_models/screen_config_view_model.dart';
import 'package:hmg_qline/views/common_widgets/app_footer.dart';
@ -12,9 +17,34 @@ import 'package:hmg_qline/views/main_queue_screen/components/priority_tickets.da
import 'package:hmg_qline/views/main_queue_screen/components/priority_tickets_sidelist.dart';
import 'package:provider/provider.dart';
class MainQueueScreen extends StatelessWidget {
class MainQueueScreen extends StatefulWidget {
const MainQueueScreen({super.key});
@override
State<MainQueueScreen> createState() => _MainQueueScreenState();
}
class _MainQueueScreenState extends State<MainQueueScreen> {
late LifecycleHandler lifecycleHandler;
@override
void initState() {
super.initState();
final ScreenConfigViewModel screenConfigViewModel = context.read<ScreenConfigViewModel>();
lifecycleHandler = LifecycleHandler(
onResumed: () => screenConfigViewModel.onAppResumed(),
onPaused: () => screenConfigViewModel.onAppPaused(),
);
lifecycleHandler.register();
}
@override
void dispose() {
lifecycleHandler.unregister();
super.dispose();
}
Widget dataContent({required BuildContext context}) {
return Consumer2(
builder: (BuildContext context, ScreenConfigViewModel screenConfigViewModel, QueuingViewModel queuingViewModel, Widget? child) {
@ -41,7 +71,7 @@ class MainQueueScreen extends StatelessWidget {
fontFamily = AppStrings.fontNameCairo;
}
if (screenConfigViewModel.state == ViewState.error) {
if (screenConfigViewModel.state == ViewState.error && queuingViewModel.currentTickets.isEmpty) {
widget = intimationWidget(
text: AppStrings.configurationIssueContactAdmin,
fontName: AppStrings.fontNamePoppins,

@ -158,6 +158,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_foreground_task:
dependency: "direct main"
description:
name: flutter_foreground_task
sha256: "9f1b25a81db95d7119d2c5cffc654048cbdd49d4056183e1beadc1a6a38f3e29"
url: "https://pub.dev"
source: hosted
version: "9.1.0"
flutter_lints:
dependency: "direct dev"
description:
@ -472,6 +480,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.0.10+1"
restart_app:
dependency: "direct main"
description:
name: restart_app
sha256: "00d5ec3e9de871cedbe552fc41e615b042b5ec654385e090e0983f6d02f655ed"
url: "https://pub.dev"
source: hosted
version: "1.3.2"
rxdart:
dependency: transitive
description:
@ -484,10 +500,10 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
url: "https://pub.dev"
source: hosted
version: "2.3.5"
version: "2.5.3"
shared_preferences_android:
dependency: transitive
description:

@ -53,6 +53,8 @@ dependencies:
fluttertoast: ^8.2.8
qr_code_scanner_plus: ^2.0.10+1
path_provider: ^2.1.5
flutter_foreground_task: ^9.1.0
restart_app: ^1.3.2
# esc_pos_printer: ^4.0.0 # Ensure you are using the latest version
# esc_pos_utils: ^1.0.0

Loading…
Cancel
Save