Skip to content

Commit

Permalink
change user screen
Browse files Browse the repository at this point in the history
  • Loading branch information
boxdot committed Jan 30, 2025
1 parent 92a071e commit 546236c
Show file tree
Hide file tree
Showing 15 changed files with 334 additions and 133 deletions.
6 changes: 5 additions & 1 deletion app/lib/core/core_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@ class CoreClient {

// used in app initialization
Future<void> loadDefaultUser() async {
user = await User.loadDefault(path: await dbPath());
user = await User.loadDefault(path: await dbPath())
.onError((error, stackTrace) {
_log.severe("Error loading default user $error");
return null;
});
}

// used in registration cubit
Expand Down
135 changes: 135 additions & 0 deletions app/lib/developer/change_user_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// SPDX-FileCopyrightText: 2025 Phoenix R&D GmbH <[email protected]>
//
// SPDX-License-Identifier: AGPL-3.0-or-later

import 'package:flutter/material.dart';
import 'package:prototype/core/core.dart';
import 'package:prototype/theme/theme.dart';
import 'package:prototype/user/user.dart';
import 'package:prototype/widgets/widgets.dart';
import 'package:provider/provider.dart';

class ChangeUserScreen extends StatelessWidget {
const ChangeUserScreen({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Change User'),
toolbarHeight: isPointer() ? 100 : null,
leading: const AppBarBackButton(),
),
body: Center(
child: Container(
padding: const EdgeInsets.all(Spacings.xs),
constraints: isPointer() ? const BoxConstraints(maxWidth: 800) : null,
child: const _ClientRecords(),
),
),
);
}
}

class _ClientRecords extends StatefulWidget {
const _ClientRecords();

@override
State<_ClientRecords> createState() => _ClientRecordsState();
}

class _ClientRecordsState extends State<_ClientRecords> {
Future<List<UiClientRecord>>? _clientRecords;

@override
void initState() {
super.initState();
loadClientRecords();
}

void loadClientRecords() async {
final clientRecords = User.loadClientRecords(dbPath: await dbPath());
setState(() {
_clientRecords = clientRecords;
});
}

@override
Widget build(BuildContext context) {
return FutureBuilder<List<UiClientRecord>>(
future: _clientRecords,
builder: (context, snapshot) {
if (snapshot.hasData) {
return _ClientRecordsList(snapshot.data!);
} else if (snapshot.hasError) {
return Text(
'Error loading contacts',
);
}
return const CircularProgressIndicator();
},
);
}
}

class _ClientRecordsList extends StatelessWidget {
const _ClientRecordsList(this.clientRecords);

final List<UiClientRecord> clientRecords;

@override
Widget build(BuildContext context) {
final user = context.select((LoadableUserCubit cubit) => cubit.state.user);

return Center(
child: ListView(
children: clientRecords.map((record) {
final isCurrentUser = user?.userName ==
"${record.userName.userName}@${record.userName.domain}";
final currentUserSuffix = isCurrentUser ? " (current)" : "";

final textColor = isCurrentUser
? Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.38)
: null;

return ListTile(
titleAlignment: ListTileTitleAlignment.top,
titleTextStyle: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: textColor),
subtitleTextStyle: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(color: textColor),
leading: Transform.translate(
offset: Offset(0, Spacings.xxs),
child: UserAvatar(
username: record.userName.userName,
image: record.userProfile?.profilePicture,
size: Spacings.xl,
),
),
title: Text(
record.userName.displayName(record.userProfile?.displayName) +
currentUserSuffix,
),
subtitle: Text(
"Domain: ${record.userName.domain}\nID: ${record.clientId}\nCreated: ${record.createdAt}",
),
onTap: !isCurrentUser
? () {
final coreClient = context.read<CoreClient>();
coreClient.logout();
coreClient.loadUser(
userName: record.userName,
clientId: record.clientId,
);
}
: null,
);
}).toList(),
),
);
}
}
1 change: 1 addition & 0 deletions app/lib/developer/developer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
library;

export 'developer_settings_screen.dart';
export 'change_user_screen.dart';
28 changes: 21 additions & 7 deletions app/lib/developer/developer_settings_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ class _DeveloperSettingsScreenState extends State<DeveloperSettingsScreen> {
child: Container(
padding: const EdgeInsets.all(Spacings.xs),
constraints:
isPointer() ? const BoxConstraints(maxWidth: 600) : null,
isPointer() ? const BoxConstraints(maxWidth: 800) : null,
child: ListView(
children: [
if (isMobile) _SectionHeader("Mobile Device"),
if (isMobile)
if (isMobile) ...[
_SectionHeader("Mobile Device"),
ListTile(
title: const Text('Push Token'),
subtitle: Text(
Expand All @@ -88,15 +88,29 @@ class _DeveloperSettingsScreenState extends State<DeveloperSettingsScreen> {
onTap: () =>
_reRegisterPushToken(context.read<CoreClient>()),
),
if (user != null) _SectionHeader("User"),
if (user != null)
const Divider(),
],
if (user != null) ...[
_SectionHeader("User"),
ListTile(
title: Text("Change User"),
subtitle: Text(
"Change the currently logged in user.",
),
onTap: () => context
.read<NavigationCubit>()
.openDeveloperSettings(
screen: DeveloperSettingsScreenType.changeUser),
),
ListTile(
title: Text("Logout"),
title: Text("Log Out"),
subtitle: Text(
"Logout the currently logged in user '${user.userName}, id: ${user.clientId}'.",
"Log out of the currently logged in user.",
),
onTap: () => context.read<CoreClient>().logout(),
),
const Divider(),
],
_SectionHeader("App Data"),
if (user != null)
ListTile(
Expand Down
91 changes: 4 additions & 87 deletions app/lib/intro_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class IntroScreen extends StatelessWidget {

@override
Widget build(BuildContext context) {
final isUserLoading =
context.select((LoadableUserCubit cubit) => cubit.state is LoadingUser);
final isUserLoading = context.select((LoadableUserCubit cubit) {
debugPrint("isUserLoading: ${cubit.state}");
return cubit.state is LoadingUser;
});

return Scaffold(
body: Center(
Expand Down Expand Up @@ -50,7 +52,6 @@ class IntroScreen extends StatelessWidget {
letterSpacing: -0.9,
),
),
const _ClientRecords(),
// Text button that opens the developer settings screen
TextButton(
onPressed: () =>
Expand Down Expand Up @@ -80,90 +81,6 @@ class IntroScreen extends StatelessWidget {
}
}

class _ClientRecords extends StatefulWidget {
const _ClientRecords();

@override
State<_ClientRecords> createState() => _ClientRecordsState();
}

class _ClientRecordsState extends State<_ClientRecords> {
Future<List<UiClientRecord>>? _clientRecords;

@override
void initState() {
super.initState();
loadClientRecords();
}

void loadClientRecords() async {
final clientRecords = User.loadClientRecords(dbPath: await dbPath());
setState(() {
_clientRecords = clientRecords;
});
}

@override
Widget build(BuildContext context) {
return FutureBuilder<List<UiClientRecord>>(
future: _clientRecords,
builder: (context, snapshot) {
if (snapshot.hasData) {
return _ClientRecordsList(snapshot.data!);
} else if (snapshot.hasError) {
return Text(
'Error loading contacts',
);
}
return const CircularProgressIndicator();
},
);
}
}

class _ClientRecordsList extends StatelessWidget {
const _ClientRecordsList(this.clientRecords);

final List<UiClientRecord> clientRecords;

@override
Widget build(BuildContext context) {
const itemExtent = 72.0;

return Center(
child: ConstrainedBox(
constraints: BoxConstraints(
maxHeight: 3.5 * itemExtent, // 3 items without scrolling
maxWidth: MediaQuery.of(context).size.width.clamp(0, 400),
),
child: ListView(
itemExtent: itemExtent,
children: clientRecords
.map(
(record) => ListTile(
leading: UserAvatar(
username: record.userName.userName,
image: record.userProfile?.profilePicture,
size: Spacings.xl,
),
title: Text(
record.userName
.displayName(record.userProfile?.displayName),
),
subtitle: Text(
"@${record.userName.domain}",
),
onTap: () => context.read<CoreClient>().loadUser(
userName: record.userName, clientId: record.clientId),
),
)
.toList(),
),
),
);
}
}

class _GradientText extends StatelessWidget {
const _GradientText(
this.text, {
Expand Down
24 changes: 19 additions & 5 deletions app/lib/navigation/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -189,11 +189,25 @@ extension on HomeNavigation {
key: ValueKey("add-members-screen"),
child: AddMembersScreen(),
),
if (developerSettingsOpen)
const MaterialPage(
key: ValueKey("developer-settings-screen"),
child: DeveloperSettingsScreen(),
),
...switch (developerSettingsScreen) {
null => [],
DeveloperSettingsScreenType.root => [
const MaterialPage(
key: ValueKey("developer-settings-screen"),
child: DeveloperSettingsScreen(),
),
],
DeveloperSettingsScreenType.changeUser => [
const MaterialPage(
key: ValueKey("developer-settings-screen-root"),
child: DeveloperSettingsScreen(),
),
const MaterialPage(
key: ValueKey("developer-settings-screen-change-user"),
child: ChangeUserScreen(),
),
]
},
];
}
}
Loading

0 comments on commit 546236c

Please sign in to comment.