Skip to content

Add personal user_id & full_name data, updating latter via events & in UI #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions lib/api/model/events.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ abstract class Event {
final type = json['type'] as String;
switch (type) {
case 'alert_words': return AlertWordsEvent.fromJson(json);
case 'realm_user':
switch(json['op'] as String) {
case 'update': return RealmUserUpdateEvent.fromJson(json);
// TODO add realm_user/add and realm_user/remove events
default: return UnexpectedEvent.fromJson(json);
}
case 'message': return MessageEvent.fromJson(json);
case 'heartbeat': return HeartbeatEvent.fromJson(json);
// TODO add many more event types
Expand Down Expand Up @@ -63,6 +69,76 @@ class AlertWordsEvent extends Event {
Map<String, dynamic> toJson() => _$AlertWordsEventToJson(this);
}

/// A Zulip event of type `realm_user` (only for op:update).
@JsonSerializable()
class RealmUserUpdateEvent extends Event {
@override
@JsonKey(includeToJson: true)
String get type => 'realm_user';

@override
@JsonKey(includeToJson: true)
String get op => 'update';

final RealmUserUpdateEventPerson person;

RealmUserUpdateEvent({required super.id, required this.person});

factory RealmUserUpdateEvent.fromJson(Map<String, dynamic> json) =>
_$RealmUserUpdateEventFromJson(json);

@override
Map<String, dynamic> toJson() => _$RealmUserUpdateEventToJson(this);
}

@JsonSerializable()
class RealmUserUpdateEventPerson {
final int user_id;

final String? full_name;

// TODO express that all four avatar-related properties will be present if any of them is
final String? avatar_url;
final String? avatar_url_medium;
final String? avatar_source;
final String? avatar_version;

final String? timezone;
// final String? email; // Deprecated as redundant with user_id

final int? bot_owner_id;

final int? role;

final bool? is_billing_admin;

final String? delivery_email; // TODO Can also be 'None', distinct from null

// final CustomProfileFieldValueUpdate? custom_profile_field; // TODO handle

final String? new_email;

RealmUserUpdateEventPerson({
required this.user_id,
this.full_name,
this.avatar_url,
this.avatar_url_medium,
this.avatar_source,
this.avatar_version,
this.timezone,
this.bot_owner_id,
this.role,
this.is_billing_admin, // Can also be null?
this.delivery_email,
this.new_email,
});

factory RealmUserUpdateEventPerson.fromJson(Map<String, dynamic> json) =>
_$RealmUserUpdateEventPersonFromJson(json);

Map<String, dynamic> toJson() => _$RealmUserUpdateEventPersonToJson(this);
}

/// A Zulip event of type `message`.
// TODO use [JsonSerializable] here too, using its customization features,
// in order to skip the boilerplate in [fromJson] and [toJson].
Expand Down
51 changes: 51 additions & 0 deletions lib/api/model/events.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions lib/api/model/initial_snapshot.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ class InitialSnapshot {

// TODO etc., etc.

final int user_id;
final String full_name;

InitialSnapshot({
this.queue_id,
required this.last_event_id,
Expand All @@ -34,6 +37,8 @@ class InitialSnapshot {
required this.alert_words,
required this.custom_profile_fields,
required this.subscriptions,
required this.user_id,
required this.full_name,
});

factory InitialSnapshot.fromJson(Map<String, dynamic> json) =>
Expand Down
4 changes: 4 additions & 0 deletions lib/api/model/initial_snapshot.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions lib/model/store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ class PerAccountStore extends ChangeNotifier {
required this.last_event_id,
required this.zulip_version,
required this.subscriptions,
required this.user_id,
required this.full_name,
});

/// Load the user's data from the server, and start an event queue going.
Expand Down Expand Up @@ -93,6 +95,9 @@ class PerAccountStore extends ChangeNotifier {
final String zulip_version;
final Map<int, Subscription> subscriptions;

final int user_id;
String full_name;

// TODO lots more data. When adding, be sure to update handleEvent too.

final Set<MessageListView> _messageListViews = {};
Expand Down Expand Up @@ -144,6 +149,15 @@ class PerAccountStore extends ChangeNotifier {
for (final view in _messageListViews) {
view.maybeAddMessage(event.message);
}
} else if (event is RealmUserUpdateEvent) {
debugPrint("server event: realm_user op:update");
if (event.person.user_id == user_id) {
final String? new_full_name = event.person.full_name;
if (new_full_name != null) {
full_name = new_full_name;
notifyListeners();
}
}
} else if (event is UnexpectedEvent) {
debugPrint("server event: ${jsonEncode(event.toJson())}"); // TODO log better
} else {
Expand Down Expand Up @@ -201,5 +215,7 @@ PerAccountStore processInitialSnapshot(Account account,
last_event_id: initialSnapshot.last_event_id,
zulip_version: initialSnapshot.zulip_version,
subscriptions: subscriptions,
user_id: initialSnapshot.user_id,
full_name: initialSnapshot.full_name,
);
}
3 changes: 3 additions & 0 deletions lib/widgets/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class HomePage extends StatelessWidget {
child: Column(children: [
const Text('🚧 Under construction 🚧'),
const SizedBox(height: 12),
Text.rich(TextSpan(
text: 'You are: ',
children: [bold(store.full_name)])),
Text.rich(TextSpan(
text: 'Connected to: ',
children: [bold(store.account.realmUrl)])),
Expand Down
4 changes: 4 additions & 0 deletions test/api/model/events_checks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ extension AlertWordsEventChecks on Subject<AlertWordsEvent> {
Subject<List<String>> get alert_words => has((e) => e.alert_words, 'alert_words');
}

extension RealmUserEventChecks on Subject<RealmUserEvent> {
Subject<RealmUserEventPerson> get person => has((e) => e.person, 'realm_user');
}

extension MessageEventChecks on Subject<MessageEvent> {
Subject<Message> get message => has((e) => e.message, 'message');
}
Expand Down