Skip to content

Commit 19d3a50

Browse files
committed
setting: Make in-app the default browserPreference on Android
This way, the default behavior when opening links on Android is equivalent as if the browser preference is set to in-app. Signed-off-by: Zixuan James Li <[email protected]>
1 parent d1242a2 commit 19d3a50

File tree

5 files changed

+42
-31
lines changed

5 files changed

+42
-31
lines changed

lib/model/settings.dart

+13-11
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,20 @@ enum BrowserPreference {
4949
}
5050

5151
extension GlobalSettingsHelpers on GlobalSettingsData {
52+
BrowserPreference get effectiveBrowserPreference {
53+
if (browserPreference != null) return browserPreference!;
54+
return switch (defaultTargetPlatform) {
55+
// On iOS we prefer UrlLaunchMode.externalApplication because (for
56+
// HTTP URLs) UrlLaunchMode.platformDefault uses SFSafariViewController,
57+
// which gives an awkward UX as described here:
58+
// https://chat.zulip.org/#narrow/stream/48-mobile/topic/in-app.20browser/near/1169118
59+
TargetPlatform.iOS => BrowserPreference.external,
60+
_ => BrowserPreference.inApp,
61+
};
62+
}
63+
5264
UrlLaunchMode getUrlLaunchMode(Uri url) {
53-
if (browserPreference == null) {
54-
return switch (defaultTargetPlatform) {
55-
// On iOS we prefer UrlLaunchMode.externalApplication because (for
56-
// HTTP URLs) UrlLaunchMode.platformDefault uses SFSafariViewController,
57-
// which gives an awkward UX as described here:
58-
// https://chat.zulip.org/#narrow/stream/48-mobile/topic/in-app.20browser/near/1169118
59-
TargetPlatform.iOS => UrlLaunchMode.externalApplication,
60-
_ => UrlLaunchMode.platformDefault,
61-
};
62-
}
63-
return switch (browserPreference!) {
65+
return switch (effectiveBrowserPreference) {
6466
BrowserPreference.inApp => url.scheme == 'http' || url.scheme == 'https'
6567
? UrlLaunchMode.inAppBrowserView : UrlLaunchMode.platformDefault,
6668
BrowserPreference.external => UrlLaunchMode.externalApplication,

test/model/settings_test.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,20 @@ void main() {
1313
final nonHttpLink = Uri.parse('mailto:[email protected]');
1414

1515
group('getUrlLaunchMode', () {
16-
testAndroidIos('globalSettings.browserPreference is null; use platform-specific defaults', () {
16+
testAndroidIos('globalSettings.browserPreference is null; use platform-specific defaults for http links', () {
1717
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
1818
browserPreference: null));
1919
check(globalStore).globalSettings.getUrlLaunchMode(httpLink).equals(
2020
defaultTargetPlatform == TargetPlatform.iOS
21-
? UrlLaunchMode.externalApplication : UrlLaunchMode.platformDefault);
21+
? UrlLaunchMode.externalApplication : UrlLaunchMode.inAppBrowserView);
22+
});
23+
24+
testAndroidIos('globalSettings.browserPreference is null; use platform-specific defaults for non-http links', () {
25+
final globalStore = eg.globalStore(globalSettings: eg.globalSettings(
26+
browserPreference: null));
27+
check(globalStore).globalSettings.getUrlLaunchMode(nonHttpLink).equals(
28+
defaultTargetPlatform == TargetPlatform.android
29+
? UrlLaunchMode.platformDefault : UrlLaunchMode.externalApplication);
2230
});
2331

2432
testAndroidIos('globalSettings.browserPreference is inApp; follow the preference for http links', () {

test/model/store_checks.dart

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ extension GlobalStoreChecks on Subject<GlobalStore> {
3333
extension GlobalSettingsDataChecks on Subject<GlobalSettingsData> {
3434
Subject<ThemeSetting?> get themeSetting => has((x) => x.themeSetting, 'themeSetting');
3535
Subject<BrowserPreference?> get browserPreference => has((x) => x.browserPreference, 'browserPreference');
36+
Subject<BrowserPreference> get effectiveBrowserPreference => has((x) => x.effectiveBrowserPreference, 'effectiveBrowserPreference');
3637
Subject<UrlLaunchMode> getUrlLaunchMode(Uri url) => has((x) => x.getUrlLaunchMode(url), 'getUrlLaunchMode');
3738
}
3839

test/widgets/content_test.dart

+16-16
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ void main() {
522522
final expectedLaunchUrl = expectedVideo.hrefUrl;
523523
await tester.tap(find.byIcon(Icons.play_arrow_rounded));
524524
check(testBinding.takeLaunchUrlCalls())
525-
.single.equals((url: Uri.parse(expectedLaunchUrl), mode: LaunchMode.platformDefault));
525+
.single.equals((url: Uri.parse(expectedLaunchUrl), mode: LaunchMode.inAppBrowserView));
526526
}
527527

528528
testWidgets('video preview for youtube embed', (tester) async {
@@ -794,7 +794,7 @@ void main() {
794794
await tapText(tester, find.text('hello'));
795795

796796
final expectedLaunchMode = defaultTargetPlatform == TargetPlatform.iOS ?
797-
LaunchMode.externalApplication : LaunchMode.platformDefault;
797+
LaunchMode.externalApplication : LaunchMode.inAppBrowserView;
798798
check(testBinding.takeLaunchUrlCalls())
799799
.single.equals((url: Uri.parse('https://example/'), mode: expectedLaunchMode));
800800
}, variant: const TargetPlatformVariant({TargetPlatform.android, TargetPlatform.iOS}));
@@ -824,19 +824,19 @@ void main() {
824824

825825
await tester.tapAt(base.translate(1*fontSize, 0)); // "fXo bar baz"
826826
check(testBinding.takeLaunchUrlCalls())
827-
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
827+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.inAppBrowserView));
828828

829829
await tester.tapAt(base.translate(9*fontSize, 0)); // "foo bar bXz"
830830
check(testBinding.takeLaunchUrlCalls())
831-
.single.equals((url: Uri.parse('https://b/'), mode: LaunchMode.platformDefault));
831+
.single.equals((url: Uri.parse('https://b/'), mode: LaunchMode.inAppBrowserView));
832832
});
833833

834834
testWidgets('link nested in other spans', (tester) async {
835835
await prepare(tester,
836836
'<p><strong><em><a href="https://a/">word</a></em></strong></p>');
837837
await tapText(tester, find.text('word'));
838838
check(testBinding.takeLaunchUrlCalls())
839-
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
839+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.inAppBrowserView));
840840
});
841841

842842
testWidgets('link containing other spans', (tester) async {
@@ -849,27 +849,27 @@ void main() {
849849

850850
await tester.tapAt(base.translate(1*fontSize, 0)); // "tXo words"
851851
check(testBinding.takeLaunchUrlCalls())
852-
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
852+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.inAppBrowserView));
853853

854854
await tester.tapAt(base.translate(6*fontSize, 0)); // "two woXds"
855855
check(testBinding.takeLaunchUrlCalls())
856-
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
856+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.inAppBrowserView));
857857
});
858858

859859
testWidgets('relative links are resolved', (tester) async {
860860
await prepare(tester,
861861
'<p><a href="/a/b?c#d">word</a></p>');
862862
await tapText(tester, find.text('word'));
863863
check(testBinding.takeLaunchUrlCalls())
864-
.single.equals((url: Uri.parse('${eg.realmUrl}a/b?c#d'), mode: LaunchMode.platformDefault));
864+
.single.equals((url: Uri.parse('${eg.realmUrl}a/b?c#d'), mode: LaunchMode.inAppBrowserView));
865865
});
866866

867867
testWidgets('link inside HeadingNode', (tester) async {
868868
await prepare(tester,
869869
'<h6><a href="https://a/">word</a></h6>');
870870
await tapText(tester, find.text('word'));
871871
check(testBinding.takeLaunchUrlCalls())
872-
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.platformDefault));
872+
.single.equals((url: Uri.parse('https://a/'), mode: LaunchMode.inAppBrowserView));
873873
});
874874

875875
testWidgets('error dialog if invalid link', (tester) async {
@@ -923,7 +923,7 @@ void main() {
923923
await tapText(tester, find.text('invalid'));
924924
final expectedUrl = eg.realmUrl.resolve('/#narrow/stream/1-check/topic');
925925
check(testBinding.takeLaunchUrlCalls())
926-
.single.equals((url: expectedUrl, mode: LaunchMode.platformDefault));
926+
.single.equals((url: expectedUrl, mode: LaunchMode.inAppBrowserView));
927927
check(pushedRoutes).isEmpty();
928928
});
929929
});
@@ -1073,11 +1073,11 @@ void main() {
10731073

10741074
await tester.tap(find.text('Zulip — organized team chat'));
10751075
check(testBinding.takeLaunchUrlCalls())
1076-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1076+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
10771077

10781078
await tester.tap(find.byType(RealmContentNetworkImage));
10791079
check(testBinding.takeLaunchUrlCalls())
1080-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1080+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
10811081
debugNetworkImageHttpClientProvider = null;
10821082
});
10831083

@@ -1091,7 +1091,7 @@ void main() {
10911091

10921092
await tester.tap(find.byType(RealmContentNetworkImage));
10931093
check(testBinding.takeLaunchUrlCalls())
1094-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1094+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
10951095
debugNetworkImageHttpClientProvider = null;
10961096
});
10971097

@@ -1101,11 +1101,11 @@ void main() {
11011101

11021102
await tester.tap(find.text('Zulip — organized team chat'));
11031103
check(testBinding.takeLaunchUrlCalls())
1104-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1104+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
11051105

11061106
await tester.tap(find.byType(RealmContentNetworkImage));
11071107
check(testBinding.takeLaunchUrlCalls())
1108-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1108+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
11091109
debugNetworkImageHttpClientProvider = null;
11101110
});
11111111

@@ -1115,7 +1115,7 @@ void main() {
11151115

11161116
await tester.tap(find.byType(RealmContentNetworkImage));
11171117
check(testBinding.takeLaunchUrlCalls())
1118-
.single.equals((url: url, mode: LaunchMode.platformDefault));
1118+
.single.equals((url: url, mode: LaunchMode.inAppBrowserView));
11191119
debugNetworkImageHttpClientProvider = null;
11201120
});
11211121
});

test/widgets/profile_test.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ void main() {
164164
await tester.tap(find.text(testUrl));
165165
check(testBinding.takeLaunchUrlCalls()).single.equals((
166166
url: Uri.parse(testUrl),
167-
mode: LaunchMode.platformDefault,
167+
mode: LaunchMode.inAppBrowserView,
168168
));
169169
});
170170

@@ -191,7 +191,7 @@ void main() {
191191
await tester.tap(find.text('externalValue'));
192192
check(testBinding.takeLaunchUrlCalls()).single.equals((
193193
url: Uri.parse('http://example/externalValue'),
194-
mode: LaunchMode.platformDefault,
194+
mode: LaunchMode.inAppBrowserView,
195195
));
196196
});
197197

0 commit comments

Comments
 (0)