2020-09-19 01:34:04 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
2021-04-05 20:14:39 +02:00
|
|
|
import 'package:lemmy_api_client/v3.dart';
|
2021-04-23 19:32:10 +02:00
|
|
|
import 'package:provider/provider.dart';
|
2020-09-19 23:19:49 +02:00
|
|
|
import 'package:url_launcher/url_launcher.dart' as ul;
|
2020-09-19 01:34:04 +02:00
|
|
|
|
2021-09-14 23:45:26 +02:00
|
|
|
import '../../hooks/delayed_loading.dart';
|
|
|
|
import '../../hooks/stores.dart';
|
|
|
|
import '../../l10n/l10n.dart';
|
|
|
|
import '../../stores/config_store.dart';
|
2021-10-21 20:51:35 +02:00
|
|
|
import '../../widgets/cached_network_image.dart';
|
2021-09-14 23:45:26 +02:00
|
|
|
import '../../widgets/fullscreenable_image.dart';
|
|
|
|
import '../../widgets/radio_picker.dart';
|
2020-09-19 23:19:49 +02:00
|
|
|
import 'add_instance.dart';
|
2020-09-19 01:34:04 +02:00
|
|
|
|
2020-09-30 19:05:00 +02:00
|
|
|
/// A modal where an account can be added for a given instance
|
2020-09-19 01:34:04 +02:00
|
|
|
class AddAccountPage extends HookWidget {
|
2020-12-31 14:58:23 +01:00
|
|
|
final String instanceHost;
|
2020-09-19 01:34:04 +02:00
|
|
|
|
2021-04-09 00:11:44 +02:00
|
|
|
const AddAccountPage({required this.instanceHost});
|
2020-09-19 01:34:04 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
final theme = Theme.of(context);
|
|
|
|
|
2021-02-09 15:12:13 +01:00
|
|
|
final usernameController = useListenable(useTextEditingController());
|
|
|
|
final passwordController = useListenable(useTextEditingController());
|
2021-04-11 17:19:44 +02:00
|
|
|
final passwordFocusNode = useFocusNode();
|
2020-09-19 01:34:04 +02:00
|
|
|
final accountsStore = useAccountsStore();
|
|
|
|
|
2020-09-30 19:05:00 +02:00
|
|
|
final loading = useDelayedLoading();
|
2020-12-31 14:58:23 +01:00
|
|
|
final selectedInstance = useState(instanceHost);
|
2021-04-09 00:11:44 +02:00
|
|
|
final icon = useState<String?>(null);
|
2021-02-09 15:12:13 +01:00
|
|
|
|
2020-09-23 23:20:16 +02:00
|
|
|
useEffect(() {
|
2021-04-05 20:14:39 +02:00
|
|
|
LemmyApiV3(selectedInstance.value)
|
2021-02-24 20:52:18 +01:00
|
|
|
.run(const GetSite())
|
2021-04-09 00:11:44 +02:00
|
|
|
.then((site) => icon.value = site.siteView?.site.icon);
|
2020-09-23 23:20:16 +02:00
|
|
|
return null;
|
|
|
|
}, [selectedInstance.value]);
|
2020-09-19 01:34:04 +02:00
|
|
|
|
|
|
|
handleOnAdd() async {
|
|
|
|
try {
|
2021-04-23 19:32:10 +02:00
|
|
|
final isFirstAccount = accountsStore.hasNoAccount;
|
|
|
|
|
2020-09-22 00:58:52 +02:00
|
|
|
loading.start();
|
2020-09-19 01:34:04 +02:00
|
|
|
await accountsStore.addAccount(
|
2020-09-22 00:58:52 +02:00
|
|
|
selectedInstance.value,
|
2020-09-19 01:34:04 +02:00
|
|
|
usernameController.text,
|
|
|
|
passwordController.text,
|
|
|
|
);
|
2021-04-23 19:32:10 +02:00
|
|
|
|
|
|
|
// if first account try to import settings
|
|
|
|
if (isFirstAccount) {
|
|
|
|
try {
|
|
|
|
await context.read<ConfigStore>().importLemmyUserSettings(
|
|
|
|
accountsStore
|
|
|
|
.userDataFor(
|
|
|
|
selectedInstance.value, usernameController.text)!
|
|
|
|
.jwt);
|
2021-09-08 14:38:26 +02:00
|
|
|
// ignore: empty_catches
|
2021-04-23 19:32:10 +02:00
|
|
|
} catch (e) {}
|
|
|
|
}
|
|
|
|
|
2020-09-22 00:58:52 +02:00
|
|
|
Navigator.of(context).pop();
|
2020-09-19 01:34:04 +02:00
|
|
|
} on Exception catch (err) {
|
2021-03-10 08:34:30 +01:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
2020-09-19 01:34:04 +02:00
|
|
|
content: Text(err.toString()),
|
|
|
|
));
|
|
|
|
}
|
2020-09-22 00:58:52 +02:00
|
|
|
loading.cancel();
|
2020-09-19 01:34:04 +02:00
|
|
|
}
|
|
|
|
|
2021-04-11 17:19:44 +02:00
|
|
|
final handleSubmit =
|
|
|
|
usernameController.text.isEmpty || passwordController.text.isEmpty
|
|
|
|
? null
|
|
|
|
: loading.pending
|
|
|
|
? () {}
|
|
|
|
: handleOnAdd;
|
|
|
|
|
2020-09-19 01:34:04 +02:00
|
|
|
return Scaffold(
|
|
|
|
appBar: AppBar(
|
2021-01-03 19:43:39 +01:00
|
|
|
leading: const CloseButton(),
|
2021-03-03 12:31:36 +01:00
|
|
|
title: const Text('Add account'),
|
2020-09-19 01:34:04 +02:00
|
|
|
),
|
2021-04-11 20:52:11 +02:00
|
|
|
body: AutofillGroup(
|
|
|
|
child: ListView(
|
|
|
|
padding: const EdgeInsets.all(15),
|
|
|
|
children: [
|
|
|
|
if (icon.value == null)
|
|
|
|
const SizedBox(height: 150)
|
|
|
|
else
|
|
|
|
SizedBox(
|
|
|
|
height: 150,
|
|
|
|
child: FullscreenableImage(
|
|
|
|
url: icon.value!,
|
|
|
|
child: CachedNetworkImage(
|
|
|
|
imageUrl: icon.value!,
|
2021-10-21 14:40:28 +02:00
|
|
|
errorBuilder: (_, ___) => const SizedBox.shrink(),
|
2021-04-11 20:52:11 +02:00
|
|
|
),
|
2020-09-20 00:15:36 +02:00
|
|
|
),
|
|
|
|
),
|
2021-04-11 20:52:11 +02:00
|
|
|
RadioPicker<String>(
|
|
|
|
title: 'select instance',
|
|
|
|
values: accountsStore.instances.toList(),
|
|
|
|
groupValue: selectedInstance.value,
|
|
|
|
onChanged: (value) => selectedInstance.value = value,
|
|
|
|
buttonBuilder: (context, displayValue, onPressed) => TextButton(
|
|
|
|
onPressed: onPressed,
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
|
|
children: [
|
|
|
|
Text(displayValue),
|
|
|
|
const Icon(Icons.arrow_drop_down),
|
|
|
|
],
|
|
|
|
),
|
2020-09-19 01:34:04 +02:00
|
|
|
),
|
2021-04-11 20:52:11 +02:00
|
|
|
trailing: ListTile(
|
|
|
|
leading: const Padding(
|
|
|
|
padding: EdgeInsets.all(8),
|
|
|
|
child: Icon(Icons.add),
|
|
|
|
),
|
|
|
|
title: const Text('Add instance'),
|
|
|
|
onTap: () async {
|
2021-09-30 12:55:23 +02:00
|
|
|
final value =
|
|
|
|
await Navigator.of(context).push(AddInstancePage.route());
|
2021-04-11 20:52:11 +02:00
|
|
|
Navigator.of(context).pop(value);
|
|
|
|
},
|
2020-09-19 23:19:49 +02:00
|
|
|
),
|
|
|
|
),
|
2021-04-11 20:52:11 +02:00
|
|
|
TextField(
|
|
|
|
autofocus: true,
|
|
|
|
controller: usernameController,
|
|
|
|
autofillHints: const [
|
|
|
|
AutofillHints.email,
|
|
|
|
AutofillHints.username
|
|
|
|
],
|
|
|
|
onSubmitted: (_) => passwordFocusNode.requestFocus(),
|
|
|
|
decoration: InputDecoration(
|
|
|
|
labelText: L10n.of(context)!.email_or_username),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 5),
|
|
|
|
TextField(
|
|
|
|
controller: passwordController,
|
|
|
|
obscureText: true,
|
|
|
|
focusNode: passwordFocusNode,
|
|
|
|
onSubmitted: (_) => handleSubmit?.call(),
|
|
|
|
autofillHints: const [AutofillHints.password],
|
|
|
|
keyboardType: TextInputType.visiblePassword,
|
|
|
|
decoration:
|
|
|
|
InputDecoration(labelText: L10n.of(context)!.password),
|
|
|
|
),
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: handleSubmit,
|
|
|
|
child: !loading.loading
|
|
|
|
? const Text('Sign in')
|
|
|
|
: SizedBox(
|
|
|
|
width: 20,
|
|
|
|
height: 20,
|
2021-10-24 16:28:25 +02:00
|
|
|
child: CircularProgressIndicator.adaptive(
|
2021-04-11 20:52:11 +02:00
|
|
|
valueColor:
|
|
|
|
AlwaysStoppedAnimation<Color>(theme.canvasColor),
|
|
|
|
),
|
2021-02-09 15:12:13 +01:00
|
|
|
),
|
2021-04-11 20:52:11 +02:00
|
|
|
),
|
|
|
|
TextButton(
|
|
|
|
onPressed: () {
|
|
|
|
// TODO: extract to LemmyUrls or something
|
|
|
|
ul.launch('https://${selectedInstance.value}/login');
|
|
|
|
},
|
|
|
|
child: const Text('Register'),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
2020-09-19 01:34:04 +02:00
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
2021-09-30 12:55:23 +02:00
|
|
|
|
|
|
|
static Route<String> route(String instanceHost) => MaterialPageRoute(
|
|
|
|
builder: (context) => AddAccountPage(instanceHost: instanceHost),
|
|
|
|
fullscreenDialog: true,
|
|
|
|
);
|
2020-09-19 01:34:04 +02:00
|
|
|
}
|