From 51ff25e239158f9accb9315b63a7b83ca8170e24 Mon Sep 17 00:00:00 2001 From: rohansen856 Date: Mon, 13 Jan 2025 00:18:39 +0530 Subject: [PATCH] feat: added permission request screen --- .../views/onboarding_page_start_button.dart | 2 +- .../bindings/permission_binding.dart | 12 ++ .../controllers/permission_controller.dart | 57 +++++ .../permission/views/permission_view.dart | 197 ++++++++++++++++++ lib/app/routes/app_pages.dart | 7 + lib/app/routes/app_routes.dart | 2 + lib/main.dart | 4 - 7 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 lib/app/modules/permission/bindings/permission_binding.dart create mode 100644 lib/app/modules/permission/controllers/permission_controller.dart create mode 100644 lib/app/modules/permission/views/permission_view.dart diff --git a/lib/app/modules/onboarding/views/onboarding_page_start_button.dart b/lib/app/modules/onboarding/views/onboarding_page_start_button.dart index b7b2cbd..5933e3b 100644 --- a/lib/app/modules/onboarding/views/onboarding_page_start_button.dart +++ b/lib/app/modules/onboarding/views/onboarding_page_start_button.dart @@ -16,7 +16,7 @@ class OnboardingPageStartButton extends StatelessWidget { child: ElevatedButton( onPressed: () { controller.markOnboardingAsCompleted(); - Get.offNamed(Routes.HOME); + Get.offNamed(Routes.PERMISSION); }, style: ElevatedButton.styleFrom( backgroundColor: TaskWarriorColors.black, diff --git a/lib/app/modules/permission/bindings/permission_binding.dart b/lib/app/modules/permission/bindings/permission_binding.dart new file mode 100644 index 0000000..f1aaa7d --- /dev/null +++ b/lib/app/modules/permission/bindings/permission_binding.dart @@ -0,0 +1,12 @@ +import 'package:get/get.dart'; + +import '../controllers/permission_controller.dart'; + +class PermissionBinding extends Bindings { + @override + void dependencies() { + Get.lazyPut( + () => PermissionController(), + ); + } +} diff --git a/lib/app/modules/permission/controllers/permission_controller.dart b/lib/app/modules/permission/controllers/permission_controller.dart new file mode 100644 index 0000000..d23838e --- /dev/null +++ b/lib/app/modules/permission/controllers/permission_controller.dart @@ -0,0 +1,57 @@ +import 'package:get/get.dart'; +import 'package:permission_handler/permission_handler.dart'; + +class PermissionController extends GetxController { + final RxBool isStorageGranted = false.obs; + final RxBool isNotificationGranted = false.obs; + final RxBool isLoading = false.obs; + + @override + void onInit() { + super.onInit(); + checkPermissions(); + } + + Future checkPermissions() async { + try { + isStorageGranted.value = await Permission.storage.status.isGranted; + isNotificationGranted.value = + await Permission.notification.status.isGranted; + } catch (e) { + print('Error checking permissions: $e'); + } + } + + Future requestPermissions() async { + try { + isLoading.value = true; + + PermissionStatus storageStatus; + if (GetPlatform.isAndroid) { + storageStatus = await Permission.storage.request(); + } else { + storageStatus = await Permission.photos.request(); + } + isStorageGranted.value = storageStatus.isGranted; + + final notificationStatus = await Permission.notification.request(); + isNotificationGranted.value = notificationStatus.isGranted; + + if (isStorageGranted.value && isNotificationGranted.value) { + Get.offNamed('/home'); + } + } catch (e) { + print('Error requesting permissions: $e'); + } finally { + isLoading.value = false; + } + } + + void openSettings() async { + try { + await Get.offNamed('/home'); + } catch (e) { + print('Error opening settings: $e'); + } + } +} diff --git a/lib/app/modules/permission/views/permission_view.dart b/lib/app/modules/permission/views/permission_view.dart new file mode 100644 index 0000000..25df6e4 --- /dev/null +++ b/lib/app/modules/permission/views/permission_view.dart @@ -0,0 +1,197 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; +import 'package:taskwarrior/app/utils/constants/taskwarrior_colors.dart'; +import '../controllers/permission_controller.dart'; + +class PermissionView extends GetView { + const PermissionView({super.key}); + + @override + Widget build(BuildContext context) { + final isDarkMode = Theme.of(context).brightness == Brightness.dark; + + if (Platform.isLinux || Platform.isMacOS || Platform.isWindows) { + WidgetsBinding.instance.addPostFrameCallback((_) { + Get.offAllNamed('/home'); + }); + return const SizedBox.shrink(); + } + + return Scaffold( + backgroundColor: isDarkMode + ? TaskWarriorColors.kprimaryBackgroundColor + : TaskWarriorColors.kLightPrimaryBackgroundColor, + body: SafeArea( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + const SizedBox(height: 24), + Text( + 'Why We Need Your Permission', + style: Theme.of(context).textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + color: isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 32), + Icon( + Icons.security, + size: 64, + color: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.white, + ), + const SizedBox(height: 32), + _buildPermissionSection( + context, + icon: Icons.folder_outlined, + title: 'Storage Permission', + description: + 'We use storage access to save your tasks, preferences, ' + 'and app data securely on your device. This ensures that you can ' + 'pick up where you left off seamlessly, even offline.', + isDarkMode: isDarkMode, + ), + const SizedBox(height: 24), + _buildPermissionSection( + context, + icon: Icons.notifications_outlined, + title: 'Notification Permission', + description: + 'Notifications keep you updated with important reminders ' + 'and updates, ensuring you stay on top of your tasks effortlessly.', + isDarkMode: isDarkMode, + ), + const SizedBox(height: 24), + Text( + 'Your privacy is our top priority. We never access or share your ' + 'personal files or data without your consent.', + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.white, + ), + textAlign: TextAlign.center, + ), + const SizedBox(height: 48), + Obx(() => ElevatedButton( + onPressed: controller.isLoading.value + ? null + : controller.requestPermissions, + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.all(16), + backgroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.white, + foregroundColor: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + child: controller.isLoading.value + ? CircularProgressIndicator( + color: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.white, + ) + : Text( + 'Grant Permissions', + style: TextStyle( + color: AppSettings.isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + fontSize: 16, + ), + ), + )), + const SizedBox(height: 16), + TextButton( + onPressed: () => controller.openSettings(), + style: ButtonStyle( + backgroundColor: + WidgetStateProperty.all(TaskWarriorColors.grey), + ), + child: Text( + 'You can manage your permissions anytime later in Settings', + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: AppSettings.isDarkMode + ? TaskWarriorColors.black + : TaskWarriorColors.white, + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 24), + ], + ), + ), + ), + ), + ); + } + + Widget _buildPermissionSection( + BuildContext context, { + required IconData icon, + required String title, + required String description, + required bool isDarkMode, + }) { + return Container( + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + border: Border.all( + color: isDarkMode + ? TaskWarriorColors.ksecondaryBackgroundColor + : TaskWarriorColors.borderColor, + ), + borderRadius: BorderRadius.circular(12), + color: isDarkMode + ? TaskWarriorColors.kdialogBackGroundColor + : TaskWarriorColors.kLightDialogBackGroundColor, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Icon(icon, color: TaskWarriorColors.black), + const SizedBox(width: 12), + Expanded( + child: Text( + title, + style: Theme.of(context).textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.bold, + color: isDarkMode + ? TaskWarriorColors.kprimaryTextColor + : TaskWarriorColors.kLightPrimaryTextColor, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text( + description, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: isDarkMode + ? TaskWarriorColors.ksecondaryTextColor + : TaskWarriorColors.kLightSecondaryTextColor, + ), + ), + ], + ), + ); + } +} diff --git a/lib/app/routes/app_pages.dart b/lib/app/routes/app_pages.dart index f692560..0cc14c1 100644 --- a/lib/app/routes/app_pages.dart +++ b/lib/app/routes/app_pages.dart @@ -13,6 +13,8 @@ import '../modules/manageTaskServer/bindings/manage_task_server_binding.dart'; import '../modules/manageTaskServer/views/manage_task_server_view.dart'; import '../modules/onboarding/bindings/onboarding_binding.dart'; import '../modules/onboarding/views/onboarding_view.dart'; +import '../modules/permission/bindings/permission_binding.dart'; +import '../modules/permission/views/permission_view.dart'; import '../modules/profile/bindings/profile_binding.dart'; import '../modules/profile/views/profile_view.dart'; import '../modules/reports/bindings/reports_binding.dart'; @@ -75,5 +77,10 @@ class AppPages { page: () => const SettingsView(), binding: SettingsBinding(), ), + GetPage( + name: _Paths.PERMISSION, + page: () => const PermissionView(), + binding: PermissionBinding(), + ), ]; } diff --git a/lib/app/routes/app_routes.dart b/lib/app/routes/app_routes.dart index 5cf53cc..b04f381 100644 --- a/lib/app/routes/app_routes.dart +++ b/lib/app/routes/app_routes.dart @@ -14,6 +14,7 @@ abstract class Routes { static const ABOUT = _Paths.ABOUT; static const REPORTS = _Paths.REPORTS; static const SETTINGS = _Paths.SETTINGS; + static const PERMISSION = _Paths.PERMISSION; } abstract class _Paths { @@ -27,4 +28,5 @@ abstract class _Paths { static const ABOUT = '/about'; static const REPORTS = '/reports'; static const SETTINGS = '/settings'; + static const PERMISSION = '/permission'; } diff --git a/lib/main.dart b/lib/main.dart index a88ff58..b9faee9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,16 +1,12 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:taskwarrior/app/utils/app_settings/app_settings.dart'; -import 'package:taskwarrior/app/utils/permissions/permissions_manager.dart'; import 'app/routes/app_pages.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); await AppSettings.init(); - await PermissionsManager.requestAllPermissions(); - - runApp( GetMaterialApp( title: "Application",