This repository was archived by the owner on Feb 22, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Prepare url_launcher for the Link widget #3154
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
540362a
Prepare url_launcher for the Link widget
mdebbar 5875f78
changes
mdebbar 74ed33d
tests
mdebbar 5e1cc98
formatting and analysis
mdebbar ad4c1b1
handle Router correctly
mdebbar b26f8e6
bump min version of flutter sdk
mdebbar 7cea39f
formatting
mdebbar 247991c
version
mdebbar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
packages/url_launcher/url_launcher_platform_interface/CHANGELOG.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| ## 1.0.9 | ||
|
|
||
| * Laid the groundwork for introducing a Link widget. | ||
|
|
||
| ## 1.0.8 | ||
|
|
||
| * Added webOnlyWindowName parameter | ||
|
|
||
113 changes: 113 additions & 0 deletions
113
packages/url_launcher/url_launcher_platform_interface/lib/link.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| // Copyright 2017 The Chromium Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'dart:async'; | ||
| import 'dart:ui'; | ||
|
|
||
| import 'package:flutter/material.dart'; | ||
| import 'package:flutter/services.dart'; | ||
|
|
||
| /// Signature for a function provided by the [Link] widget that instructs it to | ||
| /// follow the link. | ||
| typedef FollowLink = Future<void> Function(); | ||
|
|
||
| /// Signature for a builder function passed to the [Link] widget to construct | ||
| /// the widget tree under it. | ||
| typedef LinkWidgetBuilder = Widget Function( | ||
| BuildContext context, | ||
| FollowLink followLink, | ||
| ); | ||
|
|
||
| /// Signature for a delegate function to build the [Link] widget. | ||
| typedef LinkDelegate = Widget Function(LinkInfo linkWidget); | ||
|
|
||
| final MethodCodec _codec = const JSONMethodCodec(); | ||
|
|
||
| /// Defines where a Link URL should be open. | ||
| /// | ||
| /// This is a class instead of an enum to allow future customizability e.g. | ||
| /// opening a link in a specific iframe. | ||
| class LinkTarget { | ||
| /// Const private constructor with a [debugLabel] to allow the creation of | ||
| /// multiple distinct const instances. | ||
| const LinkTarget._({this.debugLabel}); | ||
|
|
||
| /// Used to distinguish multiple const instances of [LinkTarget]. | ||
| final String debugLabel; | ||
|
|
||
| /// Use the default target for each platform. | ||
| /// | ||
| /// On Android, the default is [blank]. On the web, the default is [self]. | ||
| /// | ||
| /// iOS, on the other hand, defaults to [self] for web URLs, and [blank] for | ||
| /// non-web URLs. | ||
| static const defaultTarget = LinkTarget._(debugLabel: 'defaultTarget'); | ||
|
|
||
| /// On the web, this opens the link in the same tab where the flutter app is | ||
| /// running. | ||
| /// | ||
| /// On Android and iOS, this opens the link in a webview within the app. | ||
| static const self = LinkTarget._(debugLabel: 'self'); | ||
|
|
||
| /// On the web, this opens the link in a new tab or window (depending on the | ||
| /// browser and user configuration). | ||
| /// | ||
| /// On Android and iOS, this opens the link in the browser or the relevant | ||
| /// app. | ||
| static const blank = LinkTarget._(debugLabel: 'blank'); | ||
| } | ||
|
|
||
| /// Encapsulates all the information necessary to build a Link widget. | ||
| abstract class LinkInfo { | ||
ditman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// Called at build time to construct the widget tree under the link. | ||
| LinkWidgetBuilder get builder; | ||
|
|
||
| /// The destination that this link leads to. | ||
| Uri get uri; | ||
|
|
||
| /// The target indicating where to open the link. | ||
| LinkTarget get target; | ||
|
|
||
| /// Whether the link is disabled or not. | ||
| bool get isDisabled; | ||
| } | ||
|
|
||
| /// Pushes the [routeName] into Flutter's navigation system via a platform | ||
| /// message. | ||
| Future<ByteData> pushRouteNameToFramework( | ||
| BuildContext context, | ||
| String routeName, { | ||
| @visibleForTesting bool debugForceRouter = false, | ||
| }) { | ||
| final Completer<ByteData> completer = Completer<ByteData>(); | ||
| if (debugForceRouter || _hasRouter(context)) { | ||
| SystemNavigator.routeInformationUpdated(location: routeName); | ||
| window.onPlatformMessage( | ||
| 'flutter/navigation', | ||
| _codec.encodeMethodCall( | ||
| MethodCall('pushRouteInformation', <dynamic, dynamic>{ | ||
| 'location': routeName, | ||
| 'state': null, | ||
| }), | ||
| ), | ||
| completer.complete, | ||
| ); | ||
| } else { | ||
| window.onPlatformMessage( | ||
| 'flutter/navigation', | ||
| _codec.encodeMethodCall(MethodCall('pushRoute', routeName)), | ||
| completer.complete, | ||
| ); | ||
| } | ||
| return completer.future; | ||
| } | ||
|
|
||
| bool _hasRouter(BuildContext context) { | ||
| try { | ||
| return Router.of(context) != null; | ||
| } on AssertionError { | ||
| // When a `Router` can't be found, an assertion error is thrown. | ||
| return false; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,7 @@ import 'dart:async'; | |
|
|
||
| import 'package:meta/meta.dart' show required; | ||
| import 'package:plugin_platform_interface/plugin_platform_interface.dart'; | ||
| import 'package:url_launcher_platform_interface/link.dart'; | ||
|
|
||
| import 'method_channel_url_launcher.dart'; | ||
|
|
||
|
|
@@ -38,6 +39,9 @@ abstract class UrlLauncherPlatform extends PlatformInterface { | |
| _instance = instance; | ||
| } | ||
|
|
||
| /// The delegate used by the Link widget to build itself. | ||
| LinkDelegate get linkDelegate; | ||
|
Comment on lines
+42
to
+43
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is defined as: @override
LinkDelegate linkDelegate = (LinkInfo linkInfo) => WebLinkDelegate(linkInfo);In the web implementation, how can you override a getter with the function above? Should the signature here be more explicit? |
||
|
|
||
| /// Returns `true` if this platform is able to launch [url]. | ||
| Future<bool> canLaunch(String url) { | ||
| throw UnimplementedError('canLaunch() has not been implemented.'); | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
71 changes: 71 additions & 0 deletions
71
packages/url_launcher/url_launcher_platform_interface/test/link_test.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| // Copyright 2017 The Chromium Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'dart:ui'; | ||
|
|
||
| import 'package:mockito/mockito.dart'; | ||
| import 'package:flutter/services.dart'; | ||
| import 'package:flutter/widgets.dart'; | ||
| import 'package:flutter_test/flutter_test.dart'; | ||
|
|
||
| import 'package:url_launcher_platform_interface/link.dart'; | ||
|
|
||
| final MethodCodec _codec = const JSONMethodCodec(); | ||
|
|
||
| void main() { | ||
| TestWidgetsFlutterBinding.ensureInitialized(); | ||
|
|
||
| PlatformMessageCallback oldHandler; | ||
| MethodCall lastCall; | ||
|
|
||
| setUp(() { | ||
| oldHandler = window.onPlatformMessage; | ||
| window.onPlatformMessage = ( | ||
| String name, | ||
| ByteData data, | ||
| PlatformMessageResponseCallback callback, | ||
| ) { | ||
| lastCall = _codec.decodeMethodCall(data); | ||
| callback(_codec.encodeSuccessEnvelope(true)); | ||
| }; | ||
| }); | ||
|
|
||
| tearDown(() { | ||
| window.onPlatformMessage = oldHandler; | ||
| }); | ||
|
|
||
| test('pushRouteNameToFramework() calls pushRoute when no Router', () async { | ||
| await pushRouteNameToFramework(CustomBuildContext(), '/foo/bar'); | ||
| expect( | ||
| lastCall, | ||
| isMethodCall( | ||
| 'pushRoute', | ||
| arguments: '/foo/bar', | ||
| ), | ||
| ); | ||
| }); | ||
|
|
||
| test( | ||
| 'pushRouteNameToFramework() calls pushRouteInformation when Router exists', | ||
| () async { | ||
| await pushRouteNameToFramework( | ||
| CustomBuildContext(), | ||
| '/foo/bar', | ||
| debugForceRouter: true, | ||
| ); | ||
| expect( | ||
| lastCall, | ||
| isMethodCall( | ||
| 'pushRouteInformation', | ||
| arguments: <dynamic, dynamic>{ | ||
| 'location': '/foo/bar', | ||
| 'state': null, | ||
| }, | ||
| ), | ||
| ); | ||
| }, | ||
| ); | ||
| } | ||
|
|
||
| class CustomBuildContext<T> extends Mock implements BuildContext {} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good change, I had a comment about target being any String in the previous PR