mirror of
https://git.selfprivacy.org/kherel/selfprivacy.org.app.git
synced 2025-03-31 18:56:21 +00:00
feat: Show skeleton animations during users load
This commit is contained in:
parent
e40cc1da90
commit
9b5fe26251
4 changed files with 51 additions and 29 deletions
lib
logic
ui
|
@ -77,11 +77,11 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||
case ConnectionStatus.nonexistent:
|
||||
emit(UsersInitial());
|
||||
break;
|
||||
case ConnectionStatus.reconnecting:
|
||||
case ConnectionStatus.connected:
|
||||
if (state is! UsersLoaded) {
|
||||
emit(UsersRefreshing(users: state.users));
|
||||
}
|
||||
case ConnectionStatus.reconnecting:
|
||||
case ConnectionStatus.offline:
|
||||
case ConnectionStatus.unauthorized:
|
||||
break;
|
||||
|
|
|
@ -27,6 +27,15 @@ class User extends Equatable {
|
|||
isFoundOnServer: true,
|
||||
);
|
||||
|
||||
const User.fake({
|
||||
this.login = 'fake_username',
|
||||
this.type = UserType.normal,
|
||||
this.password = 'fake',
|
||||
this.sshKeys = const [],
|
||||
this.isFoundOnServer = true,
|
||||
this.note,
|
||||
});
|
||||
|
||||
@HiveField(0)
|
||||
final String login;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:auto_route/auto_route.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:selfprivacy/logic/models/hive/user.dart';
|
||||
import 'package:selfprivacy/ui/router/router.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
|
||||
class UserListItem extends StatelessWidget {
|
||||
const UserListItem({
|
||||
|
@ -19,9 +20,11 @@ class UserListItem extends StatelessWidget {
|
|||
onTap: () {
|
||||
context.pushRoute(UserDetailsRoute(login: user.login));
|
||||
},
|
||||
leading: CircleAvatar(
|
||||
child: Text(
|
||||
user.login[0].toUpperCase(),
|
||||
leading: Skeleton.leaf(
|
||||
child: CircleAvatar(
|
||||
child: Text(
|
||||
user.login[0].toUpperCase(),
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: isPrimaryUser
|
||||
|
|
|
@ -14,6 +14,7 @@ import 'package:selfprivacy/ui/molecules/placeholders/empty_page_placeholder.dar
|
|||
import 'package:selfprivacy/ui/organisms/headers/brand_header.dart';
|
||||
import 'package:selfprivacy/ui/router/router.dart';
|
||||
import 'package:selfprivacy/utils/breakpoints.dart';
|
||||
import 'package:skeletonizer/skeletonizer.dart';
|
||||
|
||||
@RoutePage()
|
||||
class UsersPage extends StatelessWidget {
|
||||
|
@ -39,12 +40,11 @@ class UsersPage extends StatelessWidget {
|
|||
context.watch<OutdatedServerCheckerBloc>().state;
|
||||
|
||||
final users = state.orderedUsers;
|
||||
if (users.isEmpty) {
|
||||
if (state is UsersRefreshing) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(),
|
||||
);
|
||||
}
|
||||
final isLoading = users.isEmpty &&
|
||||
(state is UsersRefreshing || state is UsersInitial);
|
||||
final fakeUsers =
|
||||
List.generate(7, (final int index) => const User.fake());
|
||||
if (users.isEmpty && !isLoading) {
|
||||
return const _UsersNotLoaded();
|
||||
}
|
||||
return RefreshIndicator(
|
||||
|
@ -70,33 +70,43 @@ class UsersPage extends StatelessWidget {
|
|||
horizontal: 16.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: FilledButton.tonal(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.person_add_outlined,
|
||||
size: 18.0,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text('users.new_user'.tr()),
|
||||
],
|
||||
child: Skeletonizer(
|
||||
enabled: isLoading,
|
||||
enableSwitchAnimation: true,
|
||||
child: FilledButton.tonal(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.person_add_outlined,
|
||||
size: 18.0,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text('users.new_user'.tr()),
|
||||
],
|
||||
),
|
||||
onPressed: () {
|
||||
context.pushRoute(const NewUserRoute());
|
||||
},
|
||||
),
|
||||
onPressed: () {
|
||||
context.pushRoute(const NewUserRoute());
|
||||
},
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: users.length,
|
||||
itemCount: isLoading ? fakeUsers.length : users.length,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||
itemBuilder:
|
||||
(final BuildContext context, final int index) =>
|
||||
UserListItem(
|
||||
user: users[index],
|
||||
isPrimaryUser: users[index].type == UserType.primary,
|
||||
Skeletonizer(
|
||||
enabled: isLoading,
|
||||
enableSwitchAnimation: true,
|
||||
child: UserListItem(
|
||||
user: isLoading ? fakeUsers[index] : users[index],
|
||||
isPrimaryUser: isLoading
|
||||
? index == 0
|
||||
: users[index].type == UserType.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
Loading…
Add table
Reference in a new issue