Skip to content

Commit e003a66

Browse files
login: Link to doc for what "server URL" is and how to find it
Fixes: #109
1 parent 870b438 commit e003a66

File tree

3 files changed

+61
-3
lines changed

3 files changed

+61
-3
lines changed

assets/l10n/app_en.arb

+4
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,10 @@
308308
"@loginServerUrlInputLabel": {
309309
"description": "Input label in login page for Zulip server URL entry."
310310
},
311+
"serverUrlDocLinkLabel": "What's this?",
312+
"@serverUrlDocLinkLabel": {
313+
"description": "Link to doc to help users understand what a server URL is and how to find theirs."
314+
},
311315
"errorUnableToOpenLinkTitle": "Unable to open link",
312316
"@errorUnableToOpenLinkTitle": {
313317
"description": "Error title when a link fails to open."

lib/widgets/login.dart

+12-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import '../model/store.dart';
1515
import 'app.dart';
1616
import 'dialog.dart';
1717
import 'input.dart';
18+
import 'launch_url.dart';
1819
import 'page.dart';
1920
import 'store.dart';
2021
import 'text.dart';
@@ -108,6 +109,9 @@ class ServerUrlTextEditingController extends TextEditingController {
108109
class AddAccountPage extends StatefulWidget {
109110
const AddAccountPage({super.key});
110111

112+
static final Uri serverUrlHelpUrl =
113+
Uri.parse('https://zulip.com/help/logging-in#find-the-zulip-log-in-url');
114+
111115
static Route<void> buildRoute() {
112116
return _LoginSequenceRoute(page: const AddAccountPage());
113117
}
@@ -213,7 +217,6 @@ class _AddAccountPageState extends State<AddAccountPage> {
213217
child: ConstrainedBox(
214218
constraints: const BoxConstraints(maxWidth: 400),
215219
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
216-
// TODO(#109) Link to doc about what a "server URL" is and how to find it
217220
// TODO(#111) Perhaps give tappable realm URL suggestions based on text typed so far
218221
TextField(
219222
controller: _controller,
@@ -229,7 +232,14 @@ class _AddAccountPageState extends State<AddAccountPage> {
229232
decoration: InputDecoration(
230233
labelText: zulipLocalizations.loginServerUrlInputLabel,
231234
errorText: errorText,
232-
helperText: kLayoutPinningHelperText,
235+
helper: GestureDetector(
236+
onTap: () {
237+
launchUrlWithoutRealm(context, AddAccountPage.serverUrlHelpUrl);
238+
},
239+
child: Text(
240+
style: Theme.of(context).textTheme.bodySmall!
241+
.apply(color: const HSLColor.fromAHSL(1, 200, 1, 0.4).toColor()),
242+
zulipLocalizations.serverUrlDocLinkLabel)),
233243
hintText: 'your-org.zulipchat.com')),
234244
const SizedBox(height: 8),
235245
ElevatedButton(

test/widgets/login_test.dart

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import 'package:checks/checks.dart';
22
import 'package:flutter/material.dart';
33
import 'package:flutter/services.dart';
4+
import 'package:flutter_gen/gen_l10n/zulip_localizations.dart';
45
import 'package:flutter_test/flutter_test.dart';
56
import 'package:http/http.dart' as http;
7+
import 'package:url_launcher/url_launcher.dart';
8+
69
import 'package:zulip/api/model/web_auth.dart';
710
import 'package:zulip/api/route/account.dart';
811
import 'package:zulip/api/route/realm.dart';
@@ -61,7 +64,48 @@ void main() {
6164
expectErrorFromText('[email protected]', ServerUrlValidationError.noUseEmail);
6265
});
6366

64-
// TODO test AddAccountPage
67+
group('AddAccountPage Server URL Helper Text', () {
68+
Future<void> prepareAddAccountPage(WidgetTester tester) async {
69+
await tester.pumpWidget(const MaterialApp(
70+
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
71+
supportedLocales: ZulipLocalizations.supportedLocales,
72+
home: AddAccountPage(),
73+
));
74+
}
75+
76+
final zulipLocalizations = GlobalLocalizations.zulipLocalizations;
77+
78+
Future<Finder> findHelperText(WidgetTester tester) async {
79+
return find.text(zulipLocalizations.serverUrlDocLinkLabel);
80+
}
81+
82+
testWidgets('launches URL when helper text is tapped', (tester) async {
83+
await prepareAddAccountPage(tester);
84+
final helper = await findHelperText(tester);
85+
await tester.tap(helper);
86+
87+
check(testBinding.takeLaunchUrlCalls()).single.equals((
88+
url: AddAccountPage.serverUrlHelpUrl,
89+
mode: LaunchMode.platformDefault,
90+
));
91+
});
92+
93+
testWidgets('shows error dialog when URL fails to open', (tester) async {
94+
await prepareAddAccountPage(tester);
95+
testBinding.launchUrlResult = false;
96+
final helper = await findHelperText(tester);
97+
await tester.tap(helper);
98+
await tester.pump();
99+
100+
await tester.tap(find.byWidget(checkErrorDialog(
101+
tester,
102+
expectedTitle: zulipLocalizations.errorUnableToOpenLinkTitle,
103+
expectedMessage: zulipLocalizations.errorUnableToOpenLinkMessage(
104+
AddAccountPage.serverUrlHelpUrl.toString(),
105+
),
106+
)));
107+
});
108+
});
65109

66110
group('LoginPage', () {
67111
late FakeApiConnection connection;

0 commit comments

Comments
 (0)