Skip to content

Commit

Permalink
TW-692: Add ADR for send/listen event
Browse files Browse the repository at this point in the history
  • Loading branch information
nqhhdev authored and hoangdat committed Oct 4, 2023
1 parent aef271d commit f357c69
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 139 deletions.
73 changes: 73 additions & 0 deletions docs/adr/0009-Instructions-for-naming-twake-events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# 7. Instructions for naming twake events

Date: 2023-10-03

## Status

Accepted

## Docs

- [Spec](https://spec.matrix.org/v1.6/#events)

## Context

- All data exchanged through Matrix is represented as an “event”. In addition, we have local support events.
- We can use local events to handle logic and behavior by injecting events into a defined stream.

## Decision

How to name events
- Below are the naming rules for events.
- App.twake is the name of the application.
- Inapp is event use for local support.
- Profile is the name of the feature.
- Avatar is the name of the event.
ex: 'app.twake.inapp.profile.avatar'

How to use events.
- Send event

```
class TwakeEventDispatcher {
static final TwakeEventDispatcher _twakeEventDispatcher =
TwakeEventDispatcher._instance();
factory TwakeEventDispatcher() {
return _twakeEventDispatcher;
}
TwakeEventDispatcher._instance();
void sendAccountDataEvent({
required Client client,
required BasicEvent basicEvent,
}) {
client.onAccountData.add(basicEvent);
}
}
twakeEventDispatcher.sendAccountDataEvent(
client: client,
basicEvent: BasicEvent(
type: TwakeInappEventTypes.uploadAvatarEvent,
content: profile.toJson(),
),
);
```
- Listen event and handle it

```
client.onAccountData.stream.listen((event) {
Logs().d(
'FetchProfileMixin::onAccountData() - EventType: ${event.type} - EventContent: ${event.content}',
);
if (event.type == TwakeInappEventTypes.uploadAvatarEvent) {
profileNotifier.value = Profile.fromJson(event.content);
}
});
```

## Consequences

- If we do not specifically define the event, it will be duplicated with the homeserver event
54 changes: 43 additions & 11 deletions lib/pages/settings_dashboard/settings/settings.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'dart:async';

import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/data/hive/hive_collection_tom_database.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/event/twake_inapp_event_types.dart';
import 'package:fluffychat/pages/bootstrap/bootstrap_dialog.dart';
import 'package:fluffychat/pages/connect/connect_page_mixin.dart';
import 'package:fluffychat/presentation/enum/settings/settings_enum.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
import 'package:fluffychat/presentation/mixins/fetch_profile_mixin.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/matrix.dart';
import 'package:flutter/material.dart';
Expand All @@ -30,8 +32,13 @@ class Settings extends StatefulWidget {
SettingsController createState() => SettingsController();
}

class SettingsController extends State<Settings>
with ConnectPageMixin, FetchProfileMixin {
class SettingsController extends State<Settings> with ConnectPageMixin {
final ValueNotifier<Profile> profileNotifier = ValueNotifier(
Profile(userId: ''),
);

StreamSubscription? onAccountDataSubscription;

final List<SettingEnum> getListSettingItem = [
SettingEnum.chatSettings,
SettingEnum.privacyAndSecurity,
Expand Down Expand Up @@ -79,14 +86,15 @@ class SettingsController extends State<Settings>

Client get client => Matrix.of(context).client;

@override
void initState() {
getCurrentProfile(client);
handleOnAccountData(client);
WidgetsBinding.instance.addPostFrameCallback((_) {
checkBootstrap();
});
super.initState();
void _getCurrentProfile(Client client) async {
final profile = await client.getProfileFromUserId(
client.userID!,
getFromRooms: false,
);
Logs().d(
'Settings::_getCurrentProfile() - currentProfile: $profile',
);
profileNotifier.value = profile;
}

void checkBootstrap() async {
Expand Down Expand Up @@ -168,6 +176,30 @@ class SettingsController extends State<Settings>
}
}

void _handleOnAccountDataSubscription() {
onAccountDataSubscription = client.onAccountData.stream.listen((event) {
if (event.type == TwakeInappEventTypes.uploadAvatarEvent) {
profileNotifier.value = Profile.fromJson(event.content);
}
});
}

@override
void initState() {
_getCurrentProfile(client);
_handleOnAccountDataSubscription();
WidgetsBinding.instance.addPostFrameCallback((_) {
checkBootstrap();
});
super.initState();
}

@override
void dispose() {
onAccountDataSubscription?.cancel();
super.dispose();
}

@override
Widget build(BuildContext context) {
return SettingsView(
Expand Down
45 changes: 29 additions & 16 deletions lib/pages/settings_dashboard/settings_profile/settings_profile.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:adaptive_dialog/adaptive_dialog.dart';
import 'package:file_picker/file_picker.dart';
import 'package:fluffychat/config/app_config.dart';
Expand All @@ -8,7 +10,6 @@ import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_pr
import 'package:fluffychat/pages/settings_dashboard/settings_profile/settings_profile_view.dart';
import 'package:fluffychat/presentation/enum/settings/settings_profile_enum.dart';
import 'package:fluffychat/presentation/extensions/client_extension.dart';
import 'package:fluffychat/presentation/mixins/fetch_profile_mixin.dart';
import 'package:fluffychat/utils/extension/value_notifier_extension.dart';
import 'package:fluffychat/utils/platform_infos.dart';
import 'package:fluffychat/widgets/matrix.dart';
Expand All @@ -31,8 +32,11 @@ class SettingsProfile extends StatefulWidget {
State<SettingsProfile> createState() => SettingsProfileController();
}

class SettingsProfileController extends State<SettingsProfile>
with FetchProfileMixin {
class SettingsProfileController extends State<SettingsProfile> {
final ValueNotifier<Profile> profileNotifier = ValueNotifier(
Profile(userId: ''),
);

final TwakeEventDispatcher twakeEventDispatcher =
getIt.get<TwakeEventDispatcher>();

Expand Down Expand Up @@ -117,7 +121,7 @@ class SettingsProfileController extends State<SettingsProfile>
future: () => matrix.client.setAvatar(null),
);
if (success.error == null) {
getCurrentProfile(client, isUpdated: true);
_getCurrentProfile(client, isUpdated: true);
}
return;
}
Expand Down Expand Up @@ -165,7 +169,7 @@ class SettingsProfileController extends State<SettingsProfile>
future: () => matrix.client.setAvatar(file),
);
if (success.error == null) {
getCurrentProfile(client, isUpdated: true);
_getCurrentProfile(client, isUpdated: true);
}
}

Expand All @@ -184,6 +188,22 @@ class SettingsProfileController extends State<SettingsProfile>
_handleGetAvatarAction(action);
}

void _handleSyncProfile() async {
Logs().d(
'SettingsProfileController::_handleSyncProfile() - Syncing profile',
);
twakeEventDispatcher.sendAccountDataEvent(
client: client,
basicEvent: BasicEvent(
type: TwakeInappEventTypes.uploadAvatarEvent,
content: profileNotifier.value.toJson(),
),
);
Logs().d(
'SettingsProfileController::_handleSyncProfile() - Syncing success',
);
}

void setDisplayNameAction() async {
if (displayNameFocusNode.hasFocus) {
displayNameFocusNode.unfocus();
Expand All @@ -198,12 +218,11 @@ class SettingsProfileController extends State<SettingsProfile>
);
if (success.error == null) {
isEditedProfileNotifier.toggle();
getCurrentProfile(client, isUpdated: true);
_getCurrentProfile(client, isUpdated: true);
}
}

@override
void getCurrentProfile(
void _getCurrentProfile(
Client client, {
isUpdated = false,
}) async {
Expand All @@ -216,15 +235,9 @@ class SettingsProfileController extends State<SettingsProfile>
'SettingsProfileController::_getCurrentProfile() - currentProfile: $profile',
);
profileNotifier.value = profile;
twakeEventDispatcher.sendAccountDataEvent(
client: client,
basicEvent: BasicEvent(
type: TwakeInappEventTypes.uploadAvatarEvent,
content: profile.toJson(),
),
);
displayNameEditingController.text = displayName;
matrixIdEditingController.text = client.mxid(context);
_handleSyncProfile();
}

void handleTextEditOnChange(SettingsProfileEnum settingsProfileEnum) {
Expand All @@ -247,7 +260,7 @@ class SettingsProfileController extends State<SettingsProfile>

void _initProfile() {
if (widget.profile == null) {
getCurrentProfile(client);
_getCurrentProfile(client);
return;
}
profileNotifier.value = widget.profile!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class SettingsProfileView extends StatelessWidget {
builder: (_) {
return SettingsProfileViewMobile(
profileNotifier: controller.profileNotifier,
displayName: controller.displayName,
onAvatarTap: () => controller.setAvatarAction(),
settingsProfileOptions: ListView.separated(
shrinkWrap: true,
Expand Down Expand Up @@ -134,6 +135,7 @@ class SettingsProfileView extends StatelessWidget {
builder: (_) {
return SettingsProfileViewWeb(
profileNotifier: controller.profileNotifier,
displayName: controller.displayName,
basicInfoWidget: ListView.separated(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@ class SettingsProfileViewMobile extends StatelessWidget {
final ValueNotifier<Profile> profileNotifier;
final Widget settingsProfileOptions;
final VoidCallback onAvatarTap;
final String displayName;

const SettingsProfileViewMobile({
super.key,
required this.profileNotifier,
required this.settingsProfileOptions,
required this.onAvatarTap,
required this.displayName,
});

@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: profileNotifier,
builder: (context, profile, __) {
final displayName = profile.displayName ?? profile.userId;
return Column(
children: [
Divider(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,22 @@ class SettingsProfileViewWeb extends StatelessWidget {
final Widget basicInfoWidget;
final Widget workIdentitiesInfoWidget;
final VoidCallback onAvatarTap;
final String displayName;

const SettingsProfileViewWeb({
super.key,
required this.profileNotifier,
required this.basicInfoWidget,
required this.onAvatarTap,
required this.workIdentitiesInfoWidget,
required this.displayName,
});

@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: profileNotifier,
builder: (context, profile, __) {
final displayName = profile.displayName ?? profile.userId;
return Padding(
padding: SettingsProfileViewWebStyle.paddingBody,
child: Center(
Expand Down
35 changes: 0 additions & 35 deletions lib/presentation/mixins/fetch_profile_mixin.dart

This file was deleted.

Loading

0 comments on commit f357c69

Please sign in to comment.