Improve keyboard experience
This commit is contained in:
parent
9fa198c3bb
commit
59d93fe697
|
@ -24,6 +24,7 @@ class AddAccountPage extends HookWidget {
|
|||
|
||||
final usernameController = useListenable(useTextEditingController());
|
||||
final passwordController = useListenable(useTextEditingController());
|
||||
final passwordFocusNode = useFocusNode();
|
||||
final accountsStore = useAccountsStore();
|
||||
|
||||
final loading = useDelayedLoading();
|
||||
|
@ -54,6 +55,13 @@ class AddAccountPage extends HookWidget {
|
|||
loading.cancel();
|
||||
}
|
||||
|
||||
final handleSubmit =
|
||||
usernameController.text.isEmpty || passwordController.text.isEmpty
|
||||
? null
|
||||
: loading.pending
|
||||
? () {}
|
||||
: handleOnAdd;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const CloseButton(),
|
||||
|
@ -105,10 +113,11 @@ class AddAccountPage extends HookWidget {
|
|||
},
|
||||
),
|
||||
),
|
||||
// TODO: add support for password managers
|
||||
TextField(
|
||||
autofocus: true,
|
||||
controller: usernameController,
|
||||
autofillHints: const [AutofillHints.email, AutofillHints.username],
|
||||
onSubmitted: (_) => passwordFocusNode.requestFocus(),
|
||||
decoration:
|
||||
InputDecoration(labelText: L10n.of(context)!.email_or_username),
|
||||
),
|
||||
|
@ -116,15 +125,14 @@ class AddAccountPage extends HookWidget {
|
|||
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: usernameController.text.isEmpty ||
|
||||
passwordController.text.isEmpty
|
||||
? null
|
||||
: loading.pending
|
||||
? () {}
|
||||
: handleOnAdd,
|
||||
onPressed: handleSubmit,
|
||||
child: !loading.loading
|
||||
? const Text('Sign in')
|
||||
: SizedBox(
|
||||
|
|
|
@ -47,7 +47,9 @@ class AddInstancePage extends HookWidget {
|
|||
instanceController.removeListener(debounce);
|
||||
};
|
||||
}, []);
|
||||
|
||||
final inst = normalizeInstanceHost(instanceController.text);
|
||||
|
||||
handleOnAdd() async {
|
||||
try {
|
||||
await accountsStore.addInstance(inst, assumeValid: true);
|
||||
|
@ -59,6 +61,8 @@ class AddInstancePage extends HookWidget {
|
|||
}
|
||||
}
|
||||
|
||||
final handleAdd = isSite.value == true ? handleOnAdd : null;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const CloseButton(),
|
||||
|
@ -97,6 +101,9 @@ class AddInstancePage extends HookWidget {
|
|||
child: TextField(
|
||||
autofocus: true,
|
||||
controller: instanceController,
|
||||
autofillHints: const [AutofillHints.url],
|
||||
keyboardType: TextInputType.url,
|
||||
onSubmitted: (_) => handleAdd?.call(),
|
||||
autocorrect: false,
|
||||
decoration: const InputDecoration(labelText: 'instance url'),
|
||||
),
|
||||
|
@ -108,7 +115,7 @@ class AddInstancePage extends HookWidget {
|
|||
child: SizedBox(
|
||||
height: 40,
|
||||
child: ElevatedButton(
|
||||
onPressed: isSite.value == true ? handleOnAdd : null,
|
||||
onPressed: handleAdd,
|
||||
child: !debounce.loading
|
||||
? const Text('Add')
|
||||
: SizedBox(
|
||||
|
|
|
@ -66,6 +66,9 @@ class CreatePostPage extends HookWidget {
|
|||
final pictrsDeleteToken = useState<PictrsUploadFile?>(null);
|
||||
final loggedInAction = useLoggedInAction(selectedInstance.value);
|
||||
|
||||
final titleFocusNode = useFocusNode();
|
||||
final bodyFocusNode = useFocusNode();
|
||||
|
||||
final allCommunitiesSnap = useMemoFuture(
|
||||
() => LemmyApiV3(selectedInstance.value)
|
||||
.run(ListCommunities(
|
||||
|
@ -155,77 +158,6 @@ class CreatePostPage extends HookWidget {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: use lazy autocomplete
|
||||
final communitiesDropdown = InputDecorator(
|
||||
decoration: const InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 1, horizontal: 20),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)))),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<int>(
|
||||
value: selectedCommunity.value?.community.id,
|
||||
hint: Text(L10n.of(context)!.community),
|
||||
onChanged: (communityId) => selectedCommunity.value =
|
||||
allCommunitiesSnap.data
|
||||
?.firstWhere((e) => e.community.id == communityId),
|
||||
items: communitiesList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final url = Row(children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
enabled: pictrsDeleteToken.value == null,
|
||||
controller: urlController,
|
||||
decoration: InputDecoration(
|
||||
labelText: L10n.of(context)!.url,
|
||||
suffixIcon: const Icon(Icons.link),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
IconButton(
|
||||
icon: imageUploadLoading.value
|
||||
? const CircularProgressIndicator()
|
||||
: Icon(pictrsDeleteToken.value == null
|
||||
? Icons.add_photo_alternate
|
||||
: Icons.close),
|
||||
onPressed: pictrsDeleteToken.value == null
|
||||
? loggedInAction(uploadPicture)
|
||||
: () => removePicture(pictrsDeleteToken.value!),
|
||||
tooltip:
|
||||
pictrsDeleteToken.value == null ? 'Add picture' : 'Delete picture',
|
||||
)
|
||||
]);
|
||||
|
||||
final title = TextField(
|
||||
controller: titleController,
|
||||
minLines: 1,
|
||||
maxLines: 2,
|
||||
decoration: InputDecoration(labelText: L10n.of(context)!.title),
|
||||
);
|
||||
|
||||
final body = IndexedStack(
|
||||
index: showFancy.value ? 1 : 0,
|
||||
children: [
|
||||
TextField(
|
||||
controller: bodyController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
minLines: 5,
|
||||
decoration: InputDecoration(labelText: L10n.of(context)!.body),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: MarkdownText(
|
||||
bodyController.text,
|
||||
instanceHost: selectedInstance.value,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
handleSubmit(Jwt token) async {
|
||||
if (selectedCommunity.value == null || titleController.text.isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
|
||||
|
@ -256,6 +188,88 @@ class CreatePostPage extends HookWidget {
|
|||
delayed.cancel();
|
||||
}
|
||||
|
||||
// TODO: use lazy autocomplete
|
||||
final communitiesDropdown = InputDecorator(
|
||||
decoration: const InputDecoration(
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 1, horizontal: 20),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)))),
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton<int>(
|
||||
value: selectedCommunity.value?.community.id,
|
||||
hint: Text(L10n.of(context)!.community),
|
||||
onChanged: (communityId) => selectedCommunity.value =
|
||||
allCommunitiesSnap.data
|
||||
?.firstWhere((e) => e.community.id == communityId),
|
||||
items: communitiesList(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final url = Row(children: [
|
||||
Expanded(
|
||||
child: TextField(
|
||||
enabled: pictrsDeleteToken.value == null,
|
||||
controller: urlController,
|
||||
autofillHints: const [AutofillHints.url],
|
||||
keyboardType: TextInputType.url,
|
||||
onSubmitted: (_) => titleFocusNode.requestFocus(),
|
||||
decoration: InputDecoration(
|
||||
labelText: L10n.of(context)!.url,
|
||||
suffixIcon: const Icon(Icons.link),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 5),
|
||||
IconButton(
|
||||
icon: imageUploadLoading.value
|
||||
? const CircularProgressIndicator()
|
||||
: Icon(pictrsDeleteToken.value == null
|
||||
? Icons.add_photo_alternate
|
||||
: Icons.close),
|
||||
onPressed: pictrsDeleteToken.value == null
|
||||
? loggedInAction(uploadPicture)
|
||||
: () => removePicture(pictrsDeleteToken.value!),
|
||||
tooltip:
|
||||
pictrsDeleteToken.value == null ? 'Add picture' : 'Delete picture',
|
||||
)
|
||||
]);
|
||||
|
||||
final title = TextField(
|
||||
controller: titleController,
|
||||
focusNode: titleFocusNode,
|
||||
keyboardType: TextInputType.text,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
onSubmitted: (_) => bodyFocusNode.requestFocus(),
|
||||
minLines: 1,
|
||||
maxLines: 2,
|
||||
decoration: InputDecoration(labelText: L10n.of(context)!.title),
|
||||
);
|
||||
|
||||
final body = IndexedStack(
|
||||
index: showFancy.value ? 1 : 0,
|
||||
children: [
|
||||
TextField(
|
||||
controller: bodyController,
|
||||
focusNode: bodyFocusNode,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
onSubmitted: (_) =>
|
||||
delayed.pending ? () {} : loggedInAction(handleSubmit),
|
||||
maxLines: null,
|
||||
minLines: 5,
|
||||
decoration: InputDecoration(labelText: L10n.of(context)!.body),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: MarkdownText(
|
||||
bodyController.text,
|
||||
instanceHost: selectedInstance.value,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: const CloseButton(),
|
||||
|
|
|
@ -91,6 +91,13 @@ class _ManageAccount extends HookWidget {
|
|||
|
||||
final deleteAccountPasswordController = useTextEditingController();
|
||||
|
||||
final bioFocusNode = useFocusNode();
|
||||
final emailFocusNode = useFocusNode();
|
||||
final matrixUserFocusNode = useFocusNode();
|
||||
final newPasswordFocusNode = useFocusNode();
|
||||
final verifyPasswordFocusNode = useFocusNode();
|
||||
final oldPasswordFocusNode = useFocusNode();
|
||||
|
||||
final token = accountsStore.tokenFor(user.instanceHost, user.person.name)!;
|
||||
|
||||
handleSubmit() async {
|
||||
|
@ -155,6 +162,8 @@ class _ManageAccount extends HookWidget {
|
|||
const SizedBox(height: 10),
|
||||
TextField(
|
||||
controller: deleteAccountPasswordController,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true,
|
||||
decoration:
|
||||
InputDecoration(hintText: L10n.of(context)!.password),
|
||||
|
@ -219,37 +228,64 @@ class _ManageAccount extends HookWidget {
|
|||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.display_name, style: theme.textTheme.headline6),
|
||||
TextField(controller: displayNameController),
|
||||
TextField(
|
||||
controller: displayNameController,
|
||||
onSubmitted: (_) => bioFocusNode.requestFocus(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.bio, style: theme.textTheme.headline6),
|
||||
TextField(
|
||||
controller: bioController,
|
||||
focusNode: bioFocusNode,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
onSubmitted: (_) => emailFocusNode.requestFocus(),
|
||||
minLines: 4,
|
||||
maxLines: 10,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.email, style: theme.textTheme.headline6),
|
||||
TextField(controller: emailController),
|
||||
TextField(
|
||||
focusNode: emailFocusNode,
|
||||
controller: emailController,
|
||||
autofillHints: const [AutofillHints.email],
|
||||
keyboardType: TextInputType.emailAddress,
|
||||
onSubmitted: (_) => matrixUserFocusNode.requestFocus(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.matrix_user, style: theme.textTheme.headline6),
|
||||
TextField(controller: matrixUserController),
|
||||
TextField(
|
||||
focusNode: matrixUserFocusNode,
|
||||
controller: matrixUserController,
|
||||
onSubmitted: (_) => newPasswordFocusNode.requestFocus(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.new_password, style: theme.textTheme.headline6),
|
||||
TextField(
|
||||
focusNode: newPasswordFocusNode,
|
||||
controller: newPasswordController,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true,
|
||||
onSubmitted: (_) => verifyPasswordFocusNode.requestFocus(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.verify_password,
|
||||
style: theme.textTheme.headline6),
|
||||
TextField(
|
||||
focusNode: verifyPasswordFocusNode,
|
||||
controller: newPasswordVerifyController,
|
||||
autofillHints: const [AutofillHints.newPassword],
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true,
|
||||
onSubmitted: (_) => oldPasswordFocusNode.requestFocus(),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(L10n.of(context)!.old_password, style: theme.textTheme.headline6),
|
||||
TextField(
|
||||
focusNode: oldPasswordFocusNode,
|
||||
controller: oldPasswordController,
|
||||
autofillHints: const [AutofillHints.password],
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
|
|
@ -31,6 +31,16 @@ class SearchTab extends HookWidget {
|
|||
);
|
||||
}
|
||||
|
||||
handleSearch() => searchInputController.text.isNotEmpty
|
||||
? goTo(
|
||||
context,
|
||||
(context) => SearchResultsPage(
|
||||
instanceHost: instanceHost.value!,
|
||||
query: searchInputController.text,
|
||||
),
|
||||
)
|
||||
: null;
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(),
|
||||
body: ListView(
|
||||
|
@ -38,7 +48,9 @@ class SearchTab extends HookWidget {
|
|||
children: [
|
||||
TextField(
|
||||
controller: searchInputController,
|
||||
keyboardType: TextInputType.text,
|
||||
textAlign: TextAlign.center,
|
||||
onSubmitted: (_) => handleSearch(),
|
||||
decoration: InputDecoration(hintText: L10n.of(context)!.search),
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
|
@ -60,12 +72,7 @@ class SearchTab extends HookWidget {
|
|||
),
|
||||
if (searchInputController.text.isNotEmpty)
|
||||
ElevatedButton(
|
||||
onPressed: () => goTo(
|
||||
context,
|
||||
(c) => SearchResultsPage(
|
||||
instanceHost: instanceHost.value!,
|
||||
query: searchInputController.text,
|
||||
)),
|
||||
onPressed: handleSearch,
|
||||
child: Text(L10n.of(context)!.search),
|
||||
)
|
||||
],
|
||||
|
|
|
@ -86,6 +86,7 @@ class WriteMessagePage extends HookWidget {
|
|||
TextField(
|
||||
controller: bodyController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
maxLines: null,
|
||||
minLines: 5,
|
||||
autofocus: true,
|
||||
|
|
|
@ -97,6 +97,8 @@ class WriteComment extends HookWidget {
|
|||
children: [
|
||||
TextField(
|
||||
controller: controller,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
autofocus: true,
|
||||
minLines: 5,
|
||||
maxLines: null,
|
||||
|
|
Loading…
Reference in New Issue