diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index db3ff6b..6d51c54 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -6,5 +6,6 @@
+
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 531d4a4..8ae7375 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
diff --git a/lib/main.dart b/lib/main.dart
index 6529d15..e624408 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,9 +1,12 @@
import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+import 'package:connectivity_plus/connectivity_plus.dart';
+
import 'package:marco/helpers/services/app_initializer.dart';
import 'package:marco/view/my_app.dart';
-import 'package:provider/provider.dart';
import 'package:marco/helpers/theme/app_notifier.dart';
import 'package:marco/helpers/services/app_logger.dart';
+import 'package:marco/view/layouts/offline_screen.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
@@ -18,11 +21,12 @@ Future main() async {
runApp(
ChangeNotifierProvider(
create: (_) => AppNotifier(),
- child: const MyApp(),
+ child: const MainWrapper(),
),
);
} catch (e, stacktrace) {
- logSafe('App failed to initialize.',
+ logSafe(
+ 'App failed to initialize.',
level: LogLevel.error,
error: e,
stackTrace: stacktrace,
@@ -42,3 +46,55 @@ Future main() async {
);
}
}
+
+/// This widget listens to connectivity changes and switches between
+/// `MyApp` and `OfflineScreen` automatically.
+class MainWrapper extends StatefulWidget {
+ const MainWrapper({super.key});
+
+ @override
+ State createState() => _MainWrapperState();
+}
+
+class _MainWrapperState extends State {
+ // Use a List to store connectivity status as the API now returns a list
+ List _connectivityStatus = [ConnectivityResult.none];
+ final Connectivity _connectivity = Connectivity();
+
+ @override
+ void initState() {
+ super.initState();
+ _initializeConnectivity();
+ // Listen for changes, the callback now provides a List
+ _connectivity.onConnectivityChanged.listen((List results) {
+ setState(() {
+ _connectivityStatus = results;
+ });
+ });
+ }
+
+ Future _initializeConnectivity() async {
+ // checkConnectivity() now returns a List
+ final result = await _connectivity.checkConnectivity();
+ setState(() {
+ _connectivityStatus = result;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ // Check if any of the connectivity results indicate no internet
+ final bool isOffline = _connectivityStatus.contains(ConnectivityResult.none);
+
+ // Show OfflineScreen if no internet
+ if (isOffline) {
+ return const MaterialApp(
+ debugShowCheckedModeBanner: false,
+ home: OfflineScreen(),
+ );
+ }
+
+ // Show main app if online
+ return const MyApp();
+ }
+}
\ No newline at end of file
diff --git a/lib/view/auth/mpin_auth_screen.dart b/lib/view/auth/mpin_auth_screen.dart
index d1d332c..32343f7 100644
--- a/lib/view/auth/mpin_auth_screen.dart
+++ b/lib/view/auth/mpin_auth_screen.dart
@@ -168,10 +168,10 @@ class _MPINAuthScreenState extends State
const SizedBox(height: 10),
MyText(
isChangeMpin
- ? 'Set a new 6-digit MPIN for your account.'
+ ? 'Set a new 4-digit MPIN for your account.'
: (isNewUser
- ? 'Set your 6-digit MPIN for quick login.'
- : 'Enter your 6-digit MPIN to continue.'),
+ ? 'Set your 4-digit MPIN for quick login.'
+ : 'Enter your 4-digit MPIN to continue.'),
fontSize: 14,
color: Colors.black54,
textAlign: TextAlign.center,
diff --git a/lib/view/dashboard/dashboard_screen.dart b/lib/view/dashboard/dashboard_screen.dart
index ef0b8d6..99274eb 100644
--- a/lib/view/dashboard/dashboard_screen.dart
+++ b/lib/view/dashboard/dashboard_screen.dart
@@ -6,7 +6,6 @@ import 'package:marco/controller/project_controller.dart';
import 'package:marco/helpers/services/storage/local_storage.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
import 'package:marco/helpers/utils/my_shadow.dart';
-// import 'package:marco/helpers/widgets/my_button.dart';
import 'package:marco/helpers/widgets/my_card.dart';
import 'package:marco/helpers/widgets/my_container.dart';
import 'package:marco/helpers/widgets/my_spacing.dart';
@@ -53,11 +52,10 @@ class _DashboardScreenState extends State with UIMixin {
Widget build(BuildContext context) {
return Layout(
child: SingleChildScrollView(
- padding: const EdgeInsets.all(12),
+ padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- MySpacing.height(12),
_buildDashboardStats(),
MySpacing.height(24),
GetBuilder(
@@ -80,64 +78,6 @@ class _DashboardScreenState extends State with UIMixin {
);
},
),
- // if (!hasMpin) ...[
- // MyCard(
- // borderRadiusAll: 12,
- // paddingAll: 16,
- // shadow: MyShadow(elevation: 2),
- // color: Colors.red.withOpacity(0.05),
- // child: Row(
- // crossAxisAlignment: CrossAxisAlignment.start,
- // children: [
- // const Icon(Icons.warning_amber_rounded,
- // color: Colors.redAccent, size: 28),
- // MySpacing.width(12),
- // Expanded(
- // child: Column(
- // crossAxisAlignment: CrossAxisAlignment.start,
- // children: [
- // MyText.bodyMedium(
- // "MPIN Not Generated",
- // color: Colors.redAccent,
- // fontWeight: 700,
- // ),
- // MySpacing.height(4),
- // MyText.bodySmall(
- // "To secure your account, please generate your MPIN now.",
- // color: contentTheme.onBackground.withOpacity(0.8),
- // ),
- // MySpacing.height(10),
- // Align(
- // alignment: Alignment.center,
- // child: MyButton.rounded(
- // onPressed: () {
- // Get.toNamed("/auth/mpin-auth");
- // },
- // backgroundColor: contentTheme.brandRed,
- // padding: const EdgeInsets.symmetric(
- // horizontal: 20, vertical: 10),
- // child: Row(
- // mainAxisSize: MainAxisSize.min,
- // children: [
- // const Icon(Icons.lock_outline,
- // size: 18, color: Colors.white),
- // MySpacing.width(8),
- // MyText.bodyMedium(
- // "Generate MPIN",
- // color: Colors.white,
- // fontWeight: 600,
- // ),
- // ],
- // ),
- // ),
- // ),
- // ],
- // ),
- // ),
- // ],
- // ),
- // ),
- // ],
],
),
),
diff --git a/lib/view/layouts/offline_screen.dart b/lib/view/layouts/offline_screen.dart
new file mode 100644
index 0000000..c5d4a77
--- /dev/null
+++ b/lib/view/layouts/offline_screen.dart
@@ -0,0 +1,156 @@
+import 'package:flutter/material.dart';
+import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
+import 'package:marco/images.dart';
+
+class OfflineScreen extends StatefulWidget {
+ const OfflineScreen({super.key});
+
+ @override
+ State createState() => _OfflineScreenState();
+}
+
+class _OfflineScreenState extends State
+ with SingleTickerProviderStateMixin, UIMixin {
+ late AnimationController _controller;
+ late Animation _logoAnimation;
+
+ @override
+ void initState() {
+ super.initState();
+ _controller = AnimationController(
+ vsync: this,
+ duration: const Duration(milliseconds: 800),
+ );
+ _logoAnimation = CurvedAnimation(
+ parent: _controller,
+ curve: Curves.easeOutBack,
+ );
+ _controller.forward();
+ }
+
+ @override
+ void dispose() {
+ _controller.dispose();
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Stack(
+ children: [
+ _RedWaveBackground(brandRed: contentTheme.brandRed),
+ SafeArea(
+ child: Center(
+ child: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 12.0),
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ ScaleTransition(
+ scale: _logoAnimation,
+ child: Container(
+ width: 100,
+ height: 100,
+ decoration: BoxDecoration(
+ color: Colors.white,
+ shape: BoxShape.circle,
+ boxShadow: const [
+ BoxShadow(
+ color: Colors.black12,
+ blurRadius: 10,
+ offset: Offset(0, 10),
+ ),
+ ],
+ ),
+ padding: const EdgeInsets.all(20),
+ child: Image.asset(Images.logoDark),
+ ),
+ ),
+ // Increased spacing here
+ const SizedBox(height: 120),
+ const Icon(Icons.wifi_off,
+ size: 100, color: Colors.redAccent),
+ const SizedBox(height: 20),
+ const Text(
+ "No Internet Connection",
+ style: TextStyle(
+ fontSize: 26,
+ fontWeight: FontWeight.bold,
+ color: Colors.black87,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(height: 15),
+ const Text(
+ "It seems you're currently offline. Please check your network settings or Wi-Fi connection.",
+ textAlign: TextAlign.center,
+ style: TextStyle(fontSize: 16, color: Colors.grey),
+ ),
+
+ ],
+ ),
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
+
+class _RedWaveBackground extends StatelessWidget {
+ final Color brandRed;
+ const _RedWaveBackground({required this.brandRed});
+
+ @override
+ Widget build(BuildContext context) {
+ return CustomPaint(
+ painter: _WavePainter(brandRed),
+ size: Size.infinite,
+ );
+ }
+}
+
+class _WavePainter extends CustomPainter {
+ final Color brandRed;
+
+ _WavePainter(this.brandRed);
+
+ @override
+ void paint(Canvas canvas, Size size) {
+ final paint1 = Paint()
+ ..shader = LinearGradient(
+ colors: [brandRed, const Color.fromARGB(255, 97, 22, 22)],
+ begin: Alignment.topLeft,
+ end: Alignment.bottomRight,
+ ).createShader(Rect.fromLTWH(0, 0, size.width, size.height));
+
+ final path1 = Path()
+ ..moveTo(0, size.height * 0.2)
+ ..quadraticBezierTo(size.width * 0.25, size.height * 0.05,
+ size.width * 0.5, size.height * 0.15)
+ ..quadraticBezierTo(
+ size.width * 0.75, size.height * 0.25, size.width, size.height * 0.1)
+ ..lineTo(size.width, 0)
+ ..lineTo(0, 0)
+ ..close();
+
+ canvas.drawPath(path1, paint1);
+
+ final paint2 = Paint()..color = Colors.redAccent.withOpacity(0.15);
+ final path2 = Path()
+ ..moveTo(0, size.height * 0.25)
+ ..quadraticBezierTo(
+ size.width * 0.4, size.height * 0.1, size.width, size.height * 0.2)
+ ..lineTo(size.width, 0)
+ ..lineTo(0, 0)
+ ..close();
+
+ canvas.drawPath(path2, paint2);
+ }
+
+ @override
+ bool shouldRepaint(CustomPainter oldDelegate) => false;
+}
\ No newline at end of file
diff --git a/pubspec.yaml b/pubspec.yaml
index fef9493..fd193f6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -77,6 +77,7 @@ dependencies:
html_editor_enhanced: ^2.7.0
flutter_quill_delta_from_html: ^1.5.2
quill_delta: ^3.0.0-nullsafety.2
+ connectivity_plus: ^6.1.4
dev_dependencies:
flutter_test:
sdk: flutter