Skip to content

Commit

Permalink
Merge pull request #368 from builttoroam/develop
Browse files Browse the repository at this point in the history
v4.0.0 release
  • Loading branch information
thomassth authored Nov 29, 2021
2 parents ad9b31d + b5d5217 commit 74d5061
Show file tree
Hide file tree
Showing 37 changed files with 776 additions and 424 deletions.
24 changes: 18 additions & 6 deletions .github/workflows/dart.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,23 @@ on:
jobs:
test:
name: Build test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v1
with:
channel: "stable"
- run: dart --version
- run: flutter --version
- run: flutter test
- name: publish test
run: flutter pub publish --dry-run
- name: android build
run: |
cd example
flutter build appbundle
test-macos:
name: iOS build test
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -27,12 +44,7 @@ jobs:
channel: "stable"
- run: dart --version
- run: flutter --version
- run: flutter test
- name: iOS build
run: |
cd example
flutter build ios --release --no-codesign
- name: android build
run: |
cd example
flutter build appbundle
flutter build ios --release --no-codesign
156 changes: 82 additions & 74 deletions CHANGELOG.md

Large diffs are not rendered by default.

52 changes: 44 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Device Calendar Plugin
**If you're upgrading to `v4.0.0`, your previous code will need to be modified (slightly) otherwise it will not run after update. See Timezone support for more details.**

[![pub package](https://img.shields.io/pub/v/device_calendar.svg)](https://pub.dartlang.org/packages/device_calendar) [![Build Status](https://dev.azure.com/builttoroam/Flutter%20Plugins/_apis/build/status/Device%20Calendar)](https://dev.azure.com/builttoroam/Flutter%20Plugins/_build/latest?definitionId=111)
[![pub package](https://img.shields.io/pub/v/device_calendar.svg)](https://pub.dartlang.org/packages/device_calendar) ![Pub Version (including pre-releases)](https://img.shields.io/pub/v/device_calendar?include_prereleases&label=Prerelease) [![build](https://github.com/builttoroam/device_calendar/actions/workflows/dart.yml/badge.svg?branch=develop)](https://github.com/builttoroam/device_calendar/actions/workflows/dart.yml)

A cross platform plugin for modifying calendars on the user's device.

Expand All @@ -19,18 +20,53 @@ A cross platform plugin for modifying calendars on the user's device.
* Specify a time zone for event start and end date
* **NOTE**: Due to a limitation of iOS API, single time zone property is used for iOS (`event.startTimeZone`)
* **NOTE**: For the time zone list, please refer to the `TZ database name` column on [Wikipedia](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)
* **NOTE**: If the time zone values are null or invalid, it will be defaulted to the device's current time zone.

## Null migration
## Timezone support with TZDateTime

From v4.0.0, device_calendar fits null safety. However, not all workflow had been checked and bugs from 3.2 still presists.
Due to feedback we received, starting from `v4.0.0` we will be using the `timezone` package to better handle all timezone data.

This is already included in this package. However, you need to add this line whenever the package is needed.

```dart
import 'package:timezone/timezone.dart';
```

If you don't need any timezone specific features in your app, you may use `flutter_native_timezone` to get your devices' current timezone, then convert your previous `DateTime` with it.

```dart
import 'package:flutter_native_timezone/flutter_native_timezone.dart';
// As an example, our default timezone is UTC.
Location _currentLocation = getLocation('Etc/UTC');
Future setCurentLocation() async {
String timezone = 'Etc/UTC';
try {
timezone = await FlutterNativeTimezone.getLocalTimezone();
} catch (e) {
print('Could not get the local timezone');
}
_currentLocation = getLocation(timezone);
setLocalLocation(_currentLocation);
}
...
event.start = TZDateTime.from(oldDateTime, _currentLocation);
```

For other use cases, feedback or future developments on the feature, feel free to open a discussion on GitHub.

## Null-safety migration

From `v3.9.0`, device_calendar is null-safe. However, not all workflows have been checked and bugs from older versions still persist.

You are strongly advised to test your workflow with the new package before shipping.
Better yet, please leave a note for what works and what doesn't, or contribute some bug fixes!

## Android Integration

The following will need to be added to the manifest file for your application to indicate permissions to modify calendars a needed
The following will need to be added to the `AndroidManifest.xml` file for your application to indicate permissions to modify calendars are needed

```xml
<uses-permission android:name="android.permission.READ_CALENDAR" />
Expand All @@ -39,7 +75,7 @@ The following will need to be added to the manifest file for your application to
### Proguard / R8 exceptions
By default, all android apps go through R8 for file shrinking when building a release version. Currently, it interferes with some functions such as `retrieveCalendars()`.

You may add the following setting to the ProGuard rules file (thanks to [Britannio Jarrett](https://github.com/britannio)). Read more about the issue [here](https://github.com/builttoroam/device_calendar/issues/99)
You may add the following setting to the ProGuard rules file `proguard-rules.pro` (thanks to [Britannio Jarrett](https://github.com/britannio)). Read more about the issue [here](https://github.com/builttoroam/device_calendar/issues/99)

```
-keep class com.builttoroam.devicecalendar.** { *; }
Expand All @@ -50,11 +86,11 @@ See [here](https://github.com/builttoroam/device_calendar/issues/99#issuecomment
For more information, refer to the guide at [Android Developer](https://developer.android.com/studio/build/shrink-code#keep-code)

### AndroidX migration
**IMPORTANT**: Since version 0.1.0, this version has migrated to use AndroidX instead of the deprecated Android support libraries. When using version 0.10.0 and onwards for this plugin, please ensure your application has been migrated following the guide [here](https://developer.android.com/jetpack/androidx/migrate)
Since `v0.1.0`, this version has migrated to use AndroidX instead of the deprecated Android support libraries. When using `v0.10.0` and onwards for this plugin, please ensure your application has been migrated following the guide [here](https://developer.android.com/jetpack/androidx/migrate)

## iOS Integration

For iOS 10 support, you'll need to modify the Info.plist to add the following key/value pair
For iOS 10 support, you'll need to modify the `Info.plist` to add the following key/value pair

```xml
<key>NSCalendarsUsageDescription</key>
Expand Down
6 changes: 3 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ group 'com.builttoroam.devicecalendar'
version '1.0-SNAPSHOT'

buildscript {
ext.kotlin_version = '1.3.41'
ext.kotlin_version = '1.3.50'
repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.android.tools.build:gradle:4.1.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Expand All @@ -25,7 +25,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 29
compileSdkVersion 30

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ import com.builttoroam.devicecalendar.models.*
import com.builttoroam.devicecalendar.models.Calendar
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.common.PluginRegistry.Registrar
import kotlinx.coroutines.*
import org.dmfs.rfc5545.DateTime
import org.dmfs.rfc5545.Weekday
Expand All @@ -92,14 +92,14 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {
private val BYSETPOS_PART = "BYSETPOS"

private val _cachedParametersMap: MutableMap<Int, CalendarMethodsParametersCacheModel> = mutableMapOf()
private var _registrar: Registrar? = null
private var _binding: ActivityPluginBinding? = null
private var _context: Context? = null
private var _gson: Gson? = null

private val uiThreadHandler = Handler(Looper.getMainLooper())

constructor(registrar: Registrar?, context: Context) {
_registrar = registrar
constructor(binding: ActivityPluginBinding?, context: Context) {
_binding = binding
_context = context
val gsonBuilder = GsonBuilder()
gsonBuilder.registerTypeAdapter(RecurrenceFrequency::class.java, RecurrenceFrequencySerializer())
Expand Down Expand Up @@ -141,7 +141,7 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {
createOrUpdateEvent(cachedValues.calendarId, cachedValues.event, cachedValues.pendingChannelResult)
}
DELETE_EVENT_REQUEST_CODE -> {
deleteEvent(cachedValues.eventId, cachedValues.calendarId, cachedValues.pendingChannelResult)
deleteEvent(cachedValues.calendarId, cachedValues.eventId, cachedValues.pendingChannelResult)
}
REQUEST_PERMISSIONS_REQUEST_CODE -> {
finishWithSuccess(permissionGranted, cachedValues.pendingChannelResult)
Expand Down Expand Up @@ -477,13 +477,9 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {
calendar.set(java.util.Calendar.SECOND, 0)
calendar.set(java.util.Calendar.MILLISECOND, 0)

// All day events must have UTC timezone
val utcTimeZone = TimeZone.getTimeZone("UTC")
calendar.timeZone = utcTimeZone

values.put(Events.DTSTART, calendar.timeInMillis)
values.put(Events.DTEND, calendar.timeInMillis)
values.put(Events.EVENT_TIMEZONE, utcTimeZone.id)
values.put(Events.EVENT_TIMEZONE, getTimeZone(event.startTimeZone).id)
} else {
values.put(Events.DTSTART, event.start!!)
values.put(Events.EVENT_TIMEZONE, getTimeZone(event.startTimeZone).id)
Expand Down Expand Up @@ -656,8 +652,8 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {

private fun arePermissionsGranted(): Boolean {
if (atLeastAPI(23)) {
val writeCalendarPermissionGranted = _registrar!!.context().checkSelfPermission(Manifest.permission.WRITE_CALENDAR) == PackageManager.PERMISSION_GRANTED
val readCalendarPermissionGranted = _registrar!!.context().checkSelfPermission(Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED
val writeCalendarPermissionGranted = _binding!!.activity.checkSelfPermission(Manifest.permission.WRITE_CALENDAR) == PackageManager.PERMISSION_GRANTED
val readCalendarPermissionGranted = _binding!!.activity.checkSelfPermission(Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_GRANTED
return writeCalendarPermissionGranted && readCalendarPermissionGranted
}

Expand All @@ -671,7 +667,7 @@ class CalendarDelegate : PluginRegistry.RequestPermissionsResultListener {

private fun requestPermissions(requestCode: Int) {
if (atLeastAPI(23)) {
_registrar!!.activity().requestPermissions(arrayOf(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR), requestCode)
_binding!!.activity.requestPermissions(arrayOf(Manifest.permission.WRITE_CALENDAR, Manifest.permission.READ_CALENDAR), requestCode)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
package com.builttoroam.devicecalendar

import android.app.Activity
import android.content.Context
import androidx.annotation.NonNull
import com.builttoroam.devicecalendar.common.Constants
import com.builttoroam.devicecalendar.common.DayOfWeek
import com.builttoroam.devicecalendar.common.RecurrenceFrequency
import com.builttoroam.devicecalendar.models.*
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar

const val CHANNEL_NAME = "plugins.builttoroam.com/device_calendar"

class DeviceCalendarPlugin() : MethodCallHandler {
class DeviceCalendarPlugin() : FlutterPlugin, MethodCallHandler, ActivityAware {

/// The MethodChannel that will the communication between Flutter and native Android
///
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel
private var context: Context? = null
private var activity: Activity? = null

// Methods
private val REQUEST_PERMISSIONS_METHOD = "requestPermissions"
private val HAS_PERMISSIONS_METHOD = "hasPermissions"
Expand Down Expand Up @@ -60,28 +73,36 @@ class DeviceCalendarPlugin() : MethodCallHandler {
private val LOCAL_ACCOUNT_NAME_ARGUMENT = "localAccountName"
private val EVENT_AVAILABILITY_ARGUMENT = "availability"


private lateinit var _registrar: Registrar
private lateinit var _calendarDelegate: CalendarDelegate

private constructor(registrar: Registrar, calendarDelegate: CalendarDelegate) : this() {
_registrar = registrar
_calendarDelegate = calendarDelegate
override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
context = flutterPluginBinding.applicationContext
channel = MethodChannel(flutterPluginBinding.binaryMessenger, CHANNEL_NAME)
channel.setMethodCallHandler(this)
}

companion object {
@JvmStatic
fun registerWith(registrar: Registrar) {
val context: Context = registrar.context()
override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
}

val calendarDelegate = CalendarDelegate(registrar, context)
val instance = DeviceCalendarPlugin(registrar, calendarDelegate)
override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity
_calendarDelegate = CalendarDelegate(binding, context!!)
binding.addRequestPermissionsResultListener(_calendarDelegate)
}

val calendarsChannel = MethodChannel(registrar.messenger(), CHANNEL_NAME)
calendarsChannel.setMethodCallHandler(instance)
override fun onDetachedFromActivityForConfigChanges() {
activity = null
}

registrar.addRequestPermissionsResultListener(calendarDelegate)
}
override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
activity = binding.activity
_calendarDelegate = CalendarDelegate(binding, context!!)
binding.addRequestPermissionsResultListener(_calendarDelegate)
}

override fun onDetachedFromActivity() {
activity = null
}

override fun onMethodCall(call: MethodCall, result: Result) {
Expand Down
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
compileSdkVersion 29
ndkVersion '21.4.7075529'
ndkVersion '22.1.7171670'

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand Down
1 change: 1 addition & 0 deletions example/ios/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ Icon?
/Flutter/Generated.xcconfig
/ServiceDefinitions.json

**/.symlinks/
Pods/
1 change: 0 additions & 1 deletion example/ios/.symlinks/plugins/device_calendar

This file was deleted.

6 changes: 5 additions & 1 deletion example/ios/Podfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '9.0'
platform :ios, '9.0'

# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
Expand Down Expand Up @@ -36,6 +36,10 @@ end

post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
flutter_additional_ios_build_settings(target)
config.build_settings['SWIFT_VERSION'] = '5.0'
# Or whatever Swift version your app is using that works with your plugins
end
end
end
10 changes: 8 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,27 @@ PODS:
- device_calendar (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_native_timezone (0.0.1):
- Flutter

DEPENDENCIES:
- device_calendar (from `.symlinks/plugins/device_calendar/ios`)
- Flutter (from `Flutter`)
- flutter_native_timezone (from `.symlinks/plugins/flutter_native_timezone/ios`)

EXTERNAL SOURCES:
device_calendar:
:path: ".symlinks/plugins/device_calendar/ios"
Flutter:
:path: Flutter
flutter_native_timezone:
:path: ".symlinks/plugins/flutter_native_timezone/ios"

SPEC CHECKSUMS:
device_calendar: 23b28a5f1ab3bf77e34542fb1167e1b8b29a98f5
device_calendar: 9cb33f88a02e19652ec7b8b122ca778f751b1f7b
Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c
flutter_native_timezone: 5f05b2de06c9776b4cc70e1839f03de178394d22

PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
PODFILE CHECKSUM: d3740c426905916d1f2ada0ddfce28cc99f7b7af

COCOAPODS: 1.10.1
Loading

0 comments on commit 74d5061

Please sign in to comment.