Repository: Baseflow/flutter-permission-handler

Issue:
[Feature request]: Split calendar permission into read-only and full access (platform interface)
### Is there already an issue requesting this feature?

- [X] I have searched the [existing issues](https://github.com/baseflow/flutter-permission-handler/issues).

### Please select affected platform(s)

- [X] Android
- [X] iOS
- [X] Windows

### Use case

With the introduction of iOS 17, both iOS and Android now support a read-only permission for accessing the calendar. Since these are the two major platforms the plugin is targeting, we want to update the app-facing API and expose both permissions. 

### Proposal

To that end, we would deprecate the `calendar` permission and introduce two new permissions: `calendarReadOnly` and `calendarFullAccess` in the platform interface. We can keep supporting `calendar` for a little while if we want to. It would behave the same as `calendarFullAccess`. This approach will not require any breaking changes.

### Specific requirements or considerations

_No response_

### Additional information or context

_No response_



Fix patch:
diff --git a/permission_handler_platform_interface/CHANGELOG.md b/permission_handler_platform_interface/CHANGELOG.md
index f385c8ece..706bed88b 100644
--- a/permission_handler_platform_interface/CHANGELOG.md
+++ b/permission_handler_platform_interface/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 3.12.0
+
+* Adds `Permission.calendarReadOnly` and `Permission.calendarFullAccess`.
+* Deprecates `Permission.calendar`. Developers should use `Permission.calendarReadOnly` and `Permission.calendarFullAccess` instead.
+
 ## 3.11.5
 
 * Updates the mentions of Android versions throughout the plugin, now following a format of 'Android {name} (API {number})'. For example: 'Android 13 (API 33)'.
diff --git a/permission_handler_platform_interface/lib/src/permissions.dart b/permission_handler_platform_interface/lib/src/permissions.dart
index ab0246d42..a19504e54 100644
--- a/permission_handler_platform_interface/lib/src/permissions.dart
+++ b/permission_handler_platform_interface/lib/src/permissions.dart
@@ -29,6 +29,7 @@ class Permission {
   ///
   /// Android: Calendar
   /// iOS: Calendar (Events)
+  @Deprecated('Use [calendarReadOnly] and [calendarFullAccess].')
   static const calendar = Permission._(0);
 
   /// Permission for accessing the device's camera.
@@ -296,8 +297,17 @@ class Permission {
   /// Android 13+ (API 33+)
   static const sensorsAlways = Permission._(35);
 
+  /// Permission for reading the device's calendar.
+  ///
+  /// On iOS 16 and lower, this permission is identical to [Permission.calendarFullAccess].
+  static const calendarReadOnly = Permission._(36);
+
+  /// Permission for reading from and writing to the device's calendar.
+  static const calendarFullAccess = Permission._(37);
+
   /// Returns a list of all possible [PermissionGroup] values.
   static const List<Permission> values = <Permission>[
+    // ignore: deprecated_member_use_from_same_package
     calendar,
     camera,
     contacts,
@@ -334,6 +344,8 @@ class Permission {
     audio,
     scheduleExactAlarm,
     sensorsAlways,
+    calendarReadOnly,
+    calendarFullAccess,
   ];
 
   static const List<String> _names = <String>[
@@ -373,6 +385,8 @@ class Permission {
     'audio',
     'scheduleExactAlarm',
     'sensorsAlways',
+    'calendarReadOnly',
+    'calendarFullAccess',
   ];
 
   @override
diff --git a/permission_handler_platform_interface/pubspec.yaml b/permission_handler_platform_interface/pubspec.yaml
index 6bd79ae9a..cb12bb980 100644
--- a/permission_handler_platform_interface/pubspec.yaml
+++ b/permission_handler_platform_interface/pubspec.yaml
@@ -3,7 +3,7 @@ description: A common platform interface for the permission_handler plugin.
 homepage: https://github.com/baseflow/flutter-permission-handler/tree/master/permission_handler_platform_interface
 # NOTE: We strongly prefer non-breaking changes, even at the expense of a
 # less-clean API. See https://flutter.dev/go/platform-interface-breaking-changes
-version: 3.11.5
+version: 3.12.0
 
 dependencies:
   flutter:


Test patch:
diff --git a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart
index 1269c3a96..ca8e03884 100644
--- a/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart
+++ b/permission_handler_platform_interface/test/src/method_channel/method_channel_permission_handler_test.dart
@@ -3,8 +3,11 @@ import 'package:permission_handler_platform_interface/permission_handler_platfor
 import 'package:permission_handler_platform_interface/src/method_channel/method_channel_permission_handler.dart';
 import 'method_channel_mock.dart';
 
-List<Permission> get mockPermissions => List.of(
-    <Permission>{Permission.calendar, Permission.camera, Permission.contacts});
+List<Permission> get mockPermissions => List.of(<Permission>{
+      Permission.contacts,
+      Permission.camera,
+      Permission.calendarReadOnly,
+    });
 
 Map<Permission, PermissionStatus> get mockPermissionMap => {};
 
@@ -21,7 +24,7 @@ void main() {
       );
 
       final permissionStatus = await MethodChannelPermissionHandler()
-          .checkPermissionStatus(Permission.calendar);
+          .checkPermissionStatus(Permission.contacts);
 
       expect(permissionStatus, PermissionStatus.denied);
     });
@@ -35,7 +38,7 @@ void main() {
       );
 
       final permissionStatus = await MethodChannelPermissionHandler()
-          .checkPermissionStatus(Permission.calendar);
+          .checkPermissionStatus(Permission.contacts);
 
       expect(permissionStatus, PermissionStatus.denied);
     });
@@ -51,7 +54,7 @@ void main() {
       );
 
       final permissionStatus = await MethodChannelPermissionHandler()
-          .checkPermissionStatus(Permission.calendar);
+          .checkPermissionStatus(Permission.contacts);
 
       expect(permissionStatus, PermissionStatus.restricted);
     });
@@ -67,7 +70,7 @@ void main() {
       );
 
       final permissionStatus = await MethodChannelPermissionHandler()
-          .checkPermissionStatus(Permission.calendar);
+          .checkPermissionStatus(Permission.contacts);
 
       expect(permissionStatus, PermissionStatus.limited);
     });
@@ -83,7 +86,7 @@ void main() {
       );
 
       final permissionStatus = await MethodChannelPermissionHandler()
-          .checkPermissionStatus(Permission.calendar);
+          .checkPermissionStatus(Permission.contacts);
 
       expect(permissionStatus, PermissionStatus.permanentlyDenied);
     });
@@ -101,7 +104,7 @@ void main() {
       );
 
       final serviceStatus = await MethodChannelPermissionHandler()
-          .checkServiceStatus(Permission.calendar);
+          .checkServiceStatus(Permission.contacts);
 
       expect(serviceStatus, ServiceStatus.disabled);
     });
@@ -115,7 +118,7 @@ void main() {
       );
 
       final serviceStatus = await MethodChannelPermissionHandler()
-          .checkServiceStatus(Permission.calendar);
+          .checkServiceStatus(Permission.contacts);
 
       expect(serviceStatus, ServiceStatus.enabled);
     });
@@ -131,7 +134,7 @@ void main() {
       );
 
       final serviceStatus = await MethodChannelPermissionHandler()
-          .checkServiceStatus(Permission.calendar);
+          .checkServiceStatus(Permission.contacts);
 
       expect(serviceStatus, ServiceStatus.notApplicable);
     });
diff --git a/permission_handler_platform_interface/test/src/permissions_test.dart b/permission_handler_platform_interface/test/src/permissions_test.dart
index 6dadd9888..c5c1b4d2d 100644
--- a/permission_handler_platform_interface/test/src/permissions_test.dart
+++ b/permission_handler_platform_interface/test/src/permissions_test.dart
@@ -6,7 +6,7 @@ void main() {
       () {
     const values = Permission.values;
 
-    expect(values.length, 36);
+    expect(values.length, 38);
   });
 
   test('check if byValue returns corresponding PermissionGroup value', () {