diff --git a/CHANGELOG.md b/CHANGELOG.md index 9983b993..27bc7184 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Added `WebViewFeature.DOCUMENT_START_SCRIPT` Android feature support - Added `getRequestedWithHeaderMode`, `setRequestedWithHeaderMode` ServiceWorkerController methods - Added `ContentBlockerTrigger.ifFrameUrl` and `ContentBlockerTrigger.loadContext` properties +- Added `PullToRefreshController.isEnabled` method - Updated `getMetaThemeColor` on iOS 15.0+ - Deprecated `onLoadError` for `onReceivedError`. `onReceivedError` will be called also for subframes - Deprecated `onLoadHttpError` for `onReceivedError`. `onReceivedHttpError` will be called also for subframes diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java index 592869ea..ffb5e656 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshChannelDelegate.java @@ -29,12 +29,20 @@ public class PullToRefreshChannelDelegate extends ChannelDelegateImpl { case "setEnabled": if (pullToRefreshView != null) { Boolean enabled = (Boolean) call.argument("enabled"); + pullToRefreshView.settings.enabled = enabled; // used by InAppWebView.onOverScrolled pullToRefreshView.setEnabled(enabled); result.success(true); } else { result.success(false); } break; + case "isEnabled": + if (pullToRefreshView != null) { + result.success(pullToRefreshView.isEnabled()); + } else { + result.success(false); + } + break; case "setRefreshing": if (pullToRefreshView != null) { Boolean refreshing = (Boolean) call.argument("refreshing"); diff --git a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java index 0ddbf175..28e172f6 100644 --- a/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java +++ b/android/src/main/java/com/pichillilorenzo/flutter_inappwebview/pull_to_refresh/PullToRefreshLayout.java @@ -3,6 +3,7 @@ package com.pichillilorenzo.flutter_inappwebview.pull_to_refresh; import android.content.Context; import android.graphics.Color; import android.util.AttributeSet; +import android.util.Log; import android.view.View; import androidx.annotation.NonNull; @@ -13,6 +14,8 @@ import com.pichillilorenzo.flutter_inappwebview.InAppWebViewFlutterPlugin; import com.pichillilorenzo.flutter_inappwebview.types.Disposable; import com.pichillilorenzo.flutter_inappwebview.webview.in_app_webview.InAppWebView; +import java.util.Arrays; + import io.flutter.plugin.common.MethodChannel; public class PullToRefreshLayout extends SwipeRefreshLayout implements Disposable { diff --git a/ios/Classes/InAppWebView/InAppWebView.swift b/ios/Classes/InAppWebView/InAppWebView.swift index ae509cdd..38bea13e 100755 --- a/ios/Classes/InAppWebView/InAppWebView.swift +++ b/ios/Classes/InAppWebView/InAppWebView.swift @@ -2966,6 +2966,14 @@ if(window.\(JAVASCRIPT_BRIDGE_NAME)[\(_callHandlerID)] != null) { } } + public func isPullToRefreshEnabled() -> Bool { + if #available(iOS 10.0, *) { + return scrollView.refreshControl != nil + } else { + return pullToRefreshControl?.superview != nil + } + } + public func createWebMessageChannel(completionHandler: ((WebMessageChannel) -> Void)? = nil) -> WebMessageChannel { let id = NSUUID().uuidString let webMessageChannel = WebMessageChannel(id: id) diff --git a/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift b/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift index af70b451..89bbcba4 100644 --- a/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift +++ b/ios/Classes/PullToRefresh/PullToRefreshChannelDelegate.swift @@ -32,6 +32,13 @@ public class PullToRefreshChannelDelegate : ChannelDelegate { result(false) } break + case "isEnabled": + if let pullToRefreshView = pullToRefreshControl { + result(pullToRefreshView.delegate?.isPullToRefreshEnabled()) + } else { + result(false) + } + break case "setRefreshing": if let pullToRefreshView = pullToRefreshControl { let refreshing = arguments!["refreshing"] as! Bool @@ -45,6 +52,13 @@ public class PullToRefreshChannelDelegate : ChannelDelegate { result(false) } break + case "isRefreshing": + if let pullToRefreshView = pullToRefreshControl { + result(pullToRefreshView.isRefreshing) + } else { + result(false) + } + break case "setColor": if let pullToRefreshView = pullToRefreshControl { let color = arguments!["color"] as! String diff --git a/ios/Classes/PullToRefresh/PullToRefreshDelegate.swift b/ios/Classes/PullToRefresh/PullToRefreshDelegate.swift index bc2606bd..81d97a54 100644 --- a/ios/Classes/PullToRefresh/PullToRefreshDelegate.swift +++ b/ios/Classes/PullToRefresh/PullToRefreshDelegate.swift @@ -10,4 +10,5 @@ import Foundation public protocol PullToRefreshDelegate { func enablePullToRefresh() func disablePullToRefresh() + func isPullToRefreshEnabled() -> Bool } diff --git a/lib/src/pull_to_refresh/pull_to_refresh_controller.dart b/lib/src/pull_to_refresh/pull_to_refresh_controller.dart index bfcb95c9..85b529ca 100644 --- a/lib/src/pull_to_refresh/pull_to_refresh_controller.dart +++ b/lib/src/pull_to_refresh/pull_to_refresh_controller.dart @@ -95,12 +95,26 @@ class PullToRefreshController { } ///Sets whether the pull-to-refresh feature is enabled or not. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setEnabled](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setEnabled(boolean))) + ///- iOS ([Official API - UIScrollView.refreshControl](https://developer.apple.com/documentation/uikit/uiscrollview/2127691-refreshcontrol)) Future setEnabled(bool enabled) async { Map args = {}; args.putIfAbsent('enabled', () => enabled); await _channel?.invokeMethod('setEnabled', args); } + ///Returns `true` is pull-to-refresh feature is enabled, otherwise `false`. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - View.isEnabled](https://developer.android.com/reference/android/view/View#isEnabled())) + ///- iOS ([Official API - UIScrollView.refreshControl](https://developer.apple.com/documentation/uikit/uiscrollview/2127691-refreshcontrol)) + Future isEnabled() async { + Map args = {}; + return await _channel?.invokeMethod('isEnabled', args); + } + Future _setRefreshing(bool refreshing) async { Map args = {}; args.putIfAbsent('refreshing', () => refreshing); @@ -112,6 +126,10 @@ class PullToRefreshController { ///Call this method when an external event source triggers a programmatic refresh of your scrolling view. ///This method updates the state of the refresh control to reflect the in-progress refresh operation. ///When the refresh operation ends, be sure to call the [endRefreshing] method to return the controller to its default state. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future beginRefreshing() async { return await _setRefreshing(true); } @@ -122,17 +140,29 @@ class PullToRefreshController { ///to return the refresh control to its default state. ///If the refresh control is at least partially visible, calling this method also hides it. ///If animations are also enabled, the control is hidden using an animation. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView + ///- iOS Future endRefreshing() async { await _setRefreshing(false); } ///Returns whether a refresh operation has been triggered and is in progress. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.isRefreshing](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#isRefreshing())) + ///- iOS ([Official API - UIRefreshControl.isRefreshing](https://developer.apple.com/documentation/uikit/uirefreshcontrol/1624844-isrefreshing)) Future isRefreshing() async { Map args = {}; return await _channel?.invokeMethod('isRefreshing', args); } ///Sets the color of the refresh control. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setColorSchemeColors](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setColorSchemeColors(int...))) + ///- iOS ([Official API - UIRefreshControl.tintColor](https://developer.apple.com/documentation/uikit/uirefreshcontrol/1624847-tintcolor)) Future setColor(Color color) async { Map args = {}; args.putIfAbsent('color', () => color.toHex()); @@ -140,6 +170,10 @@ class PullToRefreshController { } ///Sets the background color of the refresh control. + /// + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setProgressBackgroundColorSchemeColor](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setProgressBackgroundColorSchemeColor(int))) + ///- iOS ([Official API - UIView.backgroundColor](https://developer.apple.com/documentation/uikit/uiview/1622591-backgroundcolor)) Future setBackgroundColor(Color color) async { Map args = {}; args.putIfAbsent('color', () => color.toHex()); @@ -148,7 +182,8 @@ class PullToRefreshController { ///Set the distance to trigger a sync in dips. /// - ///**NOTE**: Available only on Android. + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setDistanceToTriggerSync](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setDistanceToTriggerSync(int))) Future setDistanceToTriggerSync(int distanceToTriggerSync) async { Map args = {}; args.putIfAbsent('distanceToTriggerSync', () => distanceToTriggerSync); @@ -157,7 +192,8 @@ class PullToRefreshController { ///Sets the distance that the refresh indicator can be pulled beyond its resting position during a swipe gesture. /// - ///**NOTE**: Available only on Android. + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setSlingshotDistance](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setSlingshotDistance(int))) Future setSlingshotDistance(int slingshotDistance) async { Map args = {}; args.putIfAbsent('slingshotDistance', () => slingshotDistance); @@ -166,7 +202,8 @@ class PullToRefreshController { ///Gets the default distance that the refresh indicator can be pulled beyond its resting position during a swipe gesture. /// - ///**NOTE**: Available only on Android. + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.DEFAULT_SLINGSHOT_DISTANCE](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#DEFAULT_SLINGSHOT_DISTANCE())) Future getDefaultSlingshotDistance() async { Map args = {}; return await _channel?.invokeMethod('getDefaultSlingshotDistance', args); @@ -182,7 +219,8 @@ class PullToRefreshController { ///Sets the size of the refresh indicator. One of [PullToRefreshSize.DEFAULT], or [PullToRefreshSize.LARGE]. /// - ///**NOTE**: Available only on Android. + ///**Supported Platforms/Implementations**: + ///- Android native WebView ([Official API - SwipeRefreshLayout.setSize](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout#setSize(int))) Future setIndicatorSize(PullToRefreshSize size) async { Map args = {}; args.putIfAbsent('size', () => size.toNativeValue()); @@ -199,7 +237,8 @@ class PullToRefreshController { ///Sets the styled title text to display in the refresh control. /// - ///**NOTE**: Available only on iOS. + ///**Supported Platforms/Implementations**: + ///- iOS ([Official API - UIRefreshControl.attributedTitle](https://developer.apple.com/documentation/uikit/uirefreshcontrol/1624845-attributedtitle)) Future setStyledTitle(AttributedString attributedTitle) async { Map args = {}; args.putIfAbsent('attributedTitle', () => attributedTitle.toMap());