add profile editor

Fixes #12
This commit is contained in:
Henry Hiles 2026-10-22 21:20:13 -04:00
commit 8fbfcde9c5
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
4 changed files with 639 additions and 102 deletions

View file

@ -307,6 +307,15 @@ class ClientController extends AsyncNotifier<int> {
}
}
Future<void> setProfileField(String field, Object? value) => _sendCommand(
"set_profile_field",
{
"field": field,
// gomuks deletes the field when the value is omitted, not when it's null
"value": ?value,
},
);
Future<void> reportEvent(ReportRequest request) =>
_sendCommand("report_event", request.toJson());

View file

@ -10,6 +10,15 @@ class ProfileController(final String userId)
return client.getProfile(userId);
}
Future<void> setField(String field, Object? value) async {
await ref
.read(ClientController.provider.notifier)
.setProfileField(field, value);
if (!ref.mounted) return;
ref.invalidateSelf();
await future;
}
static final provider = AsyncNotifierProvider.family
.autoDispose<ProfileController, ProfileResponse, String>(
ProfileController.new,

View file

@ -18,12 +18,14 @@ import "package:nexus/controllers/unified_push_allowed.dart";
import "package:nexus/controllers/unified_push_distributors.dart";
import "package:nexus/helpers/extensions/distributor_name.dart";
import "package:nexus/models/account_data.dart";
import "package:nexus/models/client_state.dart";
import "package:nexus/models/room_order.dart";
import "package:nexus/models/settings.dart";
import "package:nexus/models/settings_category.dart";
import "package:nexus/models/show_and_send.dart";
import "package:nexus/main.dart";
import "package:nexus/widgets/settings/dialog_list_tile.dart";
import "package:nexus/widgets/user_bottom_sheet.dart";
import "package:nexus/widgets/reset_encryption_sheet.dart";
import "package:nexus/helpers/extensions/show_adaptive_sheet.dart";
@ -240,9 +242,28 @@ class SettingsSectionsController
]),
),
]),
if (ref.watch(ClientStateController.provider)?.isLoggedIn == true)
if (ref.watch(ClientStateController.provider) case ClientState(
isLoggedIn: true,
:final userId?,
))
"Account": .new([
.new(title: "Profile", icon: Icons.person, settings: .new([])),
.new(
title: "Profile",
icon: Icons.person,
settings: .new([
.new(
title: "Profile",
description: "Your avatar, display name, pronouns, and timezone, as others see them.",
icon: Icons.person,
builder: (title, description, icon) => Center(
child: ConstrainedBox(
constraints: .new(maxWidth: 500),
child: UserBottomSheet(userId, editable: true),
),
),
),
]),
),
.new(
title: "Notifications",
icon: Icons.notifications,

View file

@ -0,0 +1,17 @@
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:timezone/data/latest_10y.dart";
import "package:timezone/timezone.dart";
/// The names of all IANA timezones, e.g. `Europe/London`, alphabetically.
class TimezonesController extends Notifier<IList<String>> {
@override
IList<String> build() {
initializeTimeZones();
return timeZoneDatabase.locations.keys.toIList().sort();
}
static final provider = NotifierProvider<TimezonesController, IList<String>>(
TimezonesController.new,
);
}