mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2025-12-22 10:59:30 +00:00
fix: keyboard not showing when adding new user (#79)
* feat: add fadeSlideTransitionBuilder for smoother transitions in user login * fix: reuse onboarding components on server manager page * fix: gaining focus rebuilt the widget using memoized fixes this issue
This commit is contained in:
parent
c8767b4e1e
commit
25be7fda03
10 changed files with 447 additions and 493 deletions
|
|
@ -39,6 +39,22 @@ class OnboardingSinglePage extends HookConsumerWidget {
|
|||
}
|
||||
}
|
||||
|
||||
Widget fadeSlideTransitionBuilder(
|
||||
Widget child,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 0.3),
|
||||
end: const Offset(0, 0),
|
||||
).animate(animation),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class OnboardingBody extends HookConsumerWidget {
|
||||
const OnboardingBody({
|
||||
super.key,
|
||||
|
|
@ -54,22 +70,6 @@ class OnboardingBody extends HookConsumerWidget {
|
|||
|
||||
final canUserLogin = useState(apiSettings.activeServer != null);
|
||||
|
||||
fadeSlideTransitionBuilder(
|
||||
Widget child,
|
||||
Animation<double> animation,
|
||||
) {
|
||||
return FadeTransition(
|
||||
opacity: animation,
|
||||
child: SlideTransition(
|
||||
position: Tween<Offset>(
|
||||
begin: const Offset(0, 0.3),
|
||||
end: const Offset(0, 0),
|
||||
).animate(animation),
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
|
|
|
|||
|
|
@ -1,33 +1,42 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_animate/flutter_animate.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/api/server_provider.dart';
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_open_id.dart';
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_password.dart';
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_token.dart';
|
||||
import 'package:vaani/hacks/fix_autofill_losing_focus.dart';
|
||||
import 'package:vaani/models/error_response.dart';
|
||||
import 'package:vaani/settings/api_settings_provider.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart' show AuthMethod;
|
||||
import 'package:vaani/api/api_provider.dart' show serverStatusProvider;
|
||||
import 'package:vaani/api/server_provider.dart'
|
||||
show ServerAlreadyExistsException, audiobookShelfServerProvider;
|
||||
import 'package:vaani/features/onboarding/view/onboarding_single_page.dart'
|
||||
show fadeSlideTransitionBuilder;
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_open_id.dart'
|
||||
show UserLoginWithOpenID;
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_password.dart'
|
||||
show UserLoginWithPassword;
|
||||
import 'package:vaani/features/onboarding/view/user_login_with_token.dart'
|
||||
show UserLoginWithToken;
|
||||
import 'package:vaani/hacks/fix_autofill_losing_focus.dart'
|
||||
show InactiveFocusScopeObserver;
|
||||
import 'package:vaani/models/error_response.dart' show ErrorResponseHandler;
|
||||
import 'package:vaani/settings/api_settings_provider.dart'
|
||||
show apiSettingsProvider;
|
||||
import 'package:vaani/settings/models/models.dart' as model;
|
||||
|
||||
class UserLoginWidget extends HookConsumerWidget {
|
||||
UserLoginWidget({
|
||||
super.key,
|
||||
required this.server,
|
||||
this.onSuccess,
|
||||
});
|
||||
|
||||
final Uri server;
|
||||
final serverStatusError = ErrorResponseHandler();
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final serverStatusError = useMemoized(() => ErrorResponseHandler(), []);
|
||||
final serverStatus =
|
||||
ref.watch(serverStatusProvider(server, serverStatusError.storeError));
|
||||
|
||||
final api = ref.watch(audiobookshelfApiProvider(server));
|
||||
|
||||
return serverStatus.when(
|
||||
data: (value) {
|
||||
if (value == null) {
|
||||
|
|
@ -42,6 +51,7 @@ class UserLoginWidget extends HookConsumerWidget {
|
|||
openIDAvailable:
|
||||
value.authMethods?.contains(AuthMethod.openid) ?? false,
|
||||
openIDButtonText: value.authFormData?.authOpenIDButtonText,
|
||||
onSuccess: onSuccess,
|
||||
);
|
||||
},
|
||||
loading: () {
|
||||
|
|
@ -88,6 +98,7 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
this.openIDAvailable = false,
|
||||
this.onPressed,
|
||||
this.openIDButtonText,
|
||||
this.onSuccess,
|
||||
});
|
||||
|
||||
final Uri server;
|
||||
|
|
@ -95,6 +106,7 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
final bool openIDAvailable;
|
||||
final void Function()? onPressed;
|
||||
final String? openIDButtonText;
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -104,8 +116,6 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
localAvailable ? AuthMethodChoice.local : AuthMethodChoice.authToken,
|
||||
);
|
||||
|
||||
final apiSettings = ref.watch(apiSettingsProvider);
|
||||
|
||||
model.AudiobookShelfServer addServer() {
|
||||
var newServer = model.AudiobookShelfServer(
|
||||
serverUrl: server,
|
||||
|
|
@ -119,9 +129,9 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
newServer = e.server;
|
||||
} finally {
|
||||
ref.read(apiSettingsProvider.notifier).updateState(
|
||||
apiSettings.copyWith(
|
||||
activeServer: newServer,
|
||||
),
|
||||
ref.read(apiSettingsProvider).copyWith(
|
||||
activeServer: newServer,
|
||||
),
|
||||
);
|
||||
}
|
||||
return newServer;
|
||||
|
|
@ -172,26 +182,36 @@ class UserLoginMultipleAuth extends HookConsumerWidget {
|
|||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
].animate(interval: 100.ms).fadeIn(
|
||||
duration: 150.ms,
|
||||
curve: Curves.easeIn,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: switch (methodChoice.value) {
|
||||
AuthMethodChoice.authToken => UserLoginWithToken(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
),
|
||||
AuthMethodChoice.local => UserLoginWithPassword(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
),
|
||||
AuthMethodChoice.openid => UserLoginWithOpenID(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
openIDButtonText: openIDButtonText,
|
||||
),
|
||||
},
|
||||
child: AnimatedSwitcher(
|
||||
duration: 200.ms,
|
||||
transitionBuilder: fadeSlideTransitionBuilder,
|
||||
child: switch (methodChoice.value) {
|
||||
AuthMethodChoice.authToken => UserLoginWithToken(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
AuthMethodChoice.local => UserLoginWithPassword(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
AuthMethodChoice.openid => UserLoginWithOpenID(
|
||||
server: server,
|
||||
addServer: addServer,
|
||||
openIDButtonText: openIDButtonText,
|
||||
onSuccess: onSuccess,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
|||
|
|
@ -20,12 +20,14 @@ class UserLoginWithOpenID extends HookConsumerWidget {
|
|||
required this.server,
|
||||
required this.addServer,
|
||||
this.openIDButtonText,
|
||||
this.onSuccess,
|
||||
});
|
||||
|
||||
final Uri server;
|
||||
final model.AudiobookShelfServer Function() addServer;
|
||||
final String? openIDButtonText;
|
||||
final responseErrorHandler = ErrorResponseHandler(name: 'OpenID');
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||
import 'package:lottie/lottie.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/api/authenticated_user_provider.dart';
|
||||
import 'package:vaani/api/authenticated_users_provider.dart';
|
||||
import 'package:vaani/hacks/fix_autofill_losing_focus.dart';
|
||||
import 'package:vaani/models/error_response.dart';
|
||||
import 'package:vaani/router/router.dart';
|
||||
|
|
@ -18,11 +18,13 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
super.key,
|
||||
required this.server,
|
||||
required this.addServer,
|
||||
this.onSuccess,
|
||||
});
|
||||
|
||||
final Uri server;
|
||||
final model.AudiobookShelfServer Function() addServer;
|
||||
final serverErrorResponse = ErrorResponseHandler();
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -81,13 +83,16 @@ class UserLoginWithPassword extends HookConsumerWidget {
|
|||
username: username,
|
||||
authToken: api.token!,
|
||||
);
|
||||
// add the user to the list of users
|
||||
ref
|
||||
.read(authenticatedUserProvider.notifier)
|
||||
.addUser(authenticatedUser, setActive: true);
|
||||
|
||||
// redirect to the library page
|
||||
GoRouter.of(context).goNamed(Routes.home.name);
|
||||
if (onSuccess != null) {
|
||||
onSuccess!(authenticatedUser);
|
||||
} else {
|
||||
// add the user to the list of users
|
||||
ref
|
||||
.read(authenticatedUsersProvider.notifier)
|
||||
.addUser(authenticatedUser, setActive: true);
|
||||
context.goNamed(Routes.home.name);
|
||||
}
|
||||
}
|
||||
|
||||
return Center(
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||
import 'package:vaani/api/api_provider.dart';
|
||||
import 'package:vaani/api/authenticated_user_provider.dart';
|
||||
import 'package:vaani/api/authenticated_users_provider.dart';
|
||||
import 'package:vaani/models/error_response.dart';
|
||||
import 'package:vaani/router/router.dart';
|
||||
import 'package:vaani/settings/models/models.dart' as model;
|
||||
|
|
@ -14,11 +14,13 @@ class UserLoginWithToken extends HookConsumerWidget {
|
|||
super.key,
|
||||
required this.server,
|
||||
required this.addServer,
|
||||
this.onSuccess,
|
||||
});
|
||||
|
||||
final Uri server;
|
||||
final model.AudiobookShelfServer Function() addServer;
|
||||
final serverErrorResponse = ErrorResponseHandler();
|
||||
final Function(model.AuthenticatedUser)? onSuccess;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
|
|
@ -65,11 +67,14 @@ class UserLoginWithToken extends HookConsumerWidget {
|
|||
authToken: api.token!,
|
||||
);
|
||||
|
||||
ref
|
||||
.read(authenticatedUserProvider.notifier)
|
||||
.addUser(authenticatedUser, setActive: true);
|
||||
|
||||
context.goNamed(Routes.home.name);
|
||||
if (onSuccess != null) {
|
||||
onSuccess!(authenticatedUser);
|
||||
} else {
|
||||
ref
|
||||
.read(authenticatedUsersProvider.notifier)
|
||||
.addUser(authenticatedUser, setActive: true);
|
||||
context.goNamed(Routes.home.name);
|
||||
}
|
||||
}
|
||||
|
||||
return Form(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue