Skip to content

Commit 806a81a

Browse files
rajveermalviyagnprice
authored andcommitted
content: Open links in-app on Android
`url_launcher` plugin now supports the desired behavior, which is using Android Custom Tabs, so we don't need the workaround of opening the links in external browser anymore, thus removed them. Fixes: zulip#279
1 parent 362f4d1 commit 806a81a

File tree

3 files changed

+19
-33
lines changed

3 files changed

+19
-33
lines changed

lib/widgets/content.dart

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -680,15 +680,7 @@ void _launchUrl(BuildContext context, String urlString) async {
680680
bool launched = false;
681681
String? errorMessage;
682682
try {
683-
launched = await ZulipBinding.instance.launchUrl(url,
684-
mode: switch (Theme.of(context).platform) {
685-
// TODO(#279): On Android we settle for LaunchMode.externalApplication
686-
// because url_launcher's in-app is a weirdly bare UX.
687-
// Switch once that's fixed upstream (by us or otherwise).
688-
TargetPlatform.android => UrlLaunchMode.externalApplication,
689-
_ => UrlLaunchMode.platformDefault,
690-
},
691-
);
683+
launched = await ZulipBinding.instance.launchUrl(url);
692684
} on PlatformException catch (e) {
693685
errorMessage = e.message;
694686
}

test/widgets/content_test.dart

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import 'dart:io';
22

33
import 'package:checks/checks.dart';
4-
import 'package:flutter/foundation.dart';
54
import 'package:flutter/material.dart';
65
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
76
import 'package:flutter_test/flutter_test.dart';
@@ -64,8 +63,6 @@ void main() {
6463
});
6564

6665
group('LinkNode interactions', () {
67-
const expectedModeAndroid = LaunchMode.externalApplication;
68-
6966
// The Flutter test font uses square glyphs, so width equals height:
7067
// https://github.com/flutter/flutter/wiki/Flutter-Test-Fonts
7168
const fontSize = 48.0;
@@ -89,10 +86,8 @@ void main() {
8986
'<p><a href="https://example/">hello</a></p>');
9087

9188
await tester.tap(find.text('hello'));
92-
final expectedMode = defaultTargetPlatform == TargetPlatform.android ?
93-
LaunchMode.externalApplication : LaunchMode.platformDefault;
9489
check(testBinding.takeLaunchUrlCalls())
95-
.single.equals((url: Uri.parse('https://example/'), mode: expectedMode));
90+
.single.equals((url: Uri.parse('https://example/'), mode: LaunchMode.platformDefault));
9691
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
9792

9893
testWidgets('multiple links in paragraph', (tester) async {
@@ -106,19 +101,19 @@ void main() {
106101

107102
await tester.tapAt(base.translate(1*fontSize, 0)); // "fXo bar baz"
108103
check(testBinding.takeLaunchUrlCalls())
109-
.single.equals((url: Uri.parse('https://a/'), mode: expectedModeAndroid));
104+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
110105

111106
await tester.tapAt(base.translate(9*fontSize, 0)); // "foo bar bXz"
112107
check(testBinding.takeLaunchUrlCalls())
113-
.single.equals((url: Uri.parse('https://b/'), mode: expectedModeAndroid));
108+
.single.equals((url: Uri.parse('https://b/'), mode: LaunchMode.platformDefault));
114109
});
115110

116111
testWidgets('link nested in other spans', (tester) async {
117112
await prepareContent(tester,
118113
'<p><strong><em><a href="https://a/">word</a></em></strong></p>');
119114
await tester.tap(find.text('word'));
120115
check(testBinding.takeLaunchUrlCalls())
121-
.single.equals((url: Uri.parse('https://a/'), mode: expectedModeAndroid));
116+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
122117
});
123118

124119
testWidgets('link containing other spans', (tester) async {
@@ -129,27 +124,27 @@ void main() {
129124

130125
await tester.tapAt(base.translate(1*fontSize, 0)); // "tXo words"
131126
check(testBinding.takeLaunchUrlCalls())
132-
.single.equals((url: Uri.parse('https://a/'), mode: expectedModeAndroid));
127+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
133128

134129
await tester.tapAt(base.translate(6*fontSize, 0)); // "two woXds"
135130
check(testBinding.takeLaunchUrlCalls())
136-
.single.equals((url: Uri.parse('https://a/'), mode: expectedModeAndroid));
131+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
137132
});
138133

139134
testWidgets('relative links are resolved', (tester) async {
140135
await prepareContent(tester,
141136
'<p><a href="/a/b?c#d">word</a></p>');
142137
await tester.tap(find.text('word'));
143138
check(testBinding.takeLaunchUrlCalls())
144-
.single.equals((url: Uri.parse('${eg.realmUrl}a/b?c#d'), mode: expectedModeAndroid));
139+
.single.equals((url: Uri.parse('${eg.realmUrl}a/b?c#d'), mode: LaunchMode.platformDefault));
145140
});
146141

147142
testWidgets('link inside HeadingNode', (tester) async {
148143
await prepareContent(tester,
149144
'<h6><a href="https://a/">word</a></h6>');
150145
await tester.tap(find.text('word'));
151146
check(testBinding.takeLaunchUrlCalls())
152-
.single.equals((url: Uri.parse('https://a/'), mode: expectedModeAndroid));
147+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
153148
});
154149

155150
testWidgets('error dialog if invalid link', (tester) async {
@@ -159,7 +154,7 @@ void main() {
159154
await tester.tap(find.text('word'));
160155
await tester.pump();
161156
check(testBinding.takeLaunchUrlCalls())
162-
.single.equals((url: Uri.parse('file:///etc/bad'), mode: expectedModeAndroid));
157+
.single.equals((url: Uri.parse('file:///etc/bad'), mode: LaunchMode.platformDefault));
163158
checkErrorDialog(tester, expectedTitle: 'Unable to open link');
164159
});
165160
});
@@ -206,7 +201,7 @@ void main() {
206201
await tester.tap(find.text('invalid'));
207202
final expectedUrl = eg.realmUrl.resolve('/#narrow/stream/1-check/topic');
208203
check(testBinding.takeLaunchUrlCalls())
209-
.single.equals((url: expectedUrl, mode: LaunchMode.externalApplication));
204+
.single.equals((url: expectedUrl, mode: LaunchMode.platformDefault));
210205
check(pushedRoutes).isEmpty();
211206
});
212207
});

test/widgets/profile_test.dart

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import 'package:checks/checks.dart';
2-
import 'package:flutter/foundation.dart';
32
import 'package:flutter/material.dart';
43
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
54
import 'package:flutter_test/flutter_test.dart';
@@ -167,10 +166,10 @@ void main() {
167166
);
168167

169168
await tester.tap(find.text(testUrl));
170-
final expectedMode = defaultTargetPlatform == TargetPlatform.android ?
171-
LaunchMode.externalApplication : LaunchMode.platformDefault;
172-
check(testBinding.takeLaunchUrlCalls())
173-
.single.equals((url: Uri.parse(testUrl), mode: expectedMode));
169+
check(testBinding.takeLaunchUrlCalls()).single.equals((
170+
url: Uri.parse(testUrl),
171+
mode: LaunchMode.platformDefault,
172+
));
174173
});
175174

176175
testWidgets('page builds; external link type navigates away', (WidgetTester tester) async {
@@ -194,10 +193,10 @@ void main() {
194193
);
195194

196195
await tester.tap(find.text('externalValue'));
197-
final expectedMode = defaultTargetPlatform == TargetPlatform.android ?
198-
LaunchMode.externalApplication : LaunchMode.platformDefault;
199-
check(testBinding.takeLaunchUrlCalls())
200-
.single.equals((url: Uri.parse('http://example/externalValue'), mode: expectedMode));
196+
check(testBinding.takeLaunchUrlCalls()).single.equals((
197+
url: Uri.parse('http://example/externalValue'),
198+
mode: LaunchMode.platformDefault,
199+
));
201200
});
202201

203202
testWidgets('page builds; user links to profile', (WidgetTester tester) async {

0 commit comments

Comments
 (0)