Skip to content
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

New Room Preview facilities #2373

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open

New Room Preview facilities #2373

wants to merge 31 commits into from

Conversation

gnunicorn
Copy link
Contributor

@gnunicorn gnunicorn commented Nov 15, 2024

You will now get the room preview shown (if the server supports it), with the ability to join the space, if you have the permissions to,

When you click on an Space / Chat Invite

preview-on-invite.mp4

When you try to access an object via Ref you don't have access to yet

unknown-object-via-boost.mp4

When you scan a QR code to an object you aren't in the space of yet

screen-20250119-125254.mp4

For additional convienience, we are also showing exactly what will be seen/shown/shared over the QR code to the other user, too:

image

To the reviewer:
Sorry, for again coming with such a large pull request. But in certain parts of the app (especially with really old code, like this joining rooms one), it's like the famous "pulling one thread and the entire thing unravels" ... and cascading changes are needed.

In particular these are (not the order they were committed):

  • The actual RoomPreview rust, ffi and dart support, obviously ;)
  • linking the room preview to room invites: 0b5f89a
  • a bigger refactor of ref-item to allow for opening the room preview and have people join and be forwarded from there (as shown above) in 753abc4
  • A minor update in the error handler to give us the option to show better, more specific access information if the server provides it for us: which is the case if we aren't allowed to see the room preview. This is all the textBuilder-changes on those ActerError-Widget in db8e099
  • Two big changes were done around joining rooms:
    • the via-servers are now provided as a list on the dart side as well (as it should be) and we provide our main server in the ref-details for external sharing for proper support of that - which also brings some new rust API to generate lists of strings
    • a refactor of the joinRoom-action to remove the forwarding-callback and instead use the future-syntax as we do in other actions as well, in f2036f9
    • which also brings the - hopefully final - fix for showing a 404 after forwarding to a joined space in 26f9214

Copy link

codecov bot commented Nov 15, 2024

Codecov Report

Attention: Patch coverage is 0% with 126 lines in your changes missing coverage. Please review.

Project coverage is 28.84%. Comparing base (8d97615) to head (2d5d2cd).
Report is 14 commits behind head on main.

Files with missing lines Patch % Lines
native/acter/src/api/room/preview.rs 0.00% 95 Missing ⚠️
native/acter/src/api/utils.rs 0.00% 12 Missing ⚠️
native/core/src/events/common/object_reference.rs 0.00% 9 Missing ⚠️
native/acter/src/api/client.rs 0.00% 7 Missing ⚠️
native/acter/src/api/room.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2373      +/-   ##
==========================================
- Coverage   28.88%   28.84%   -0.04%     
==========================================
  Files         680      695      +15     
  Lines       45422    46083     +661     
==========================================
+ Hits        13119    13292     +173     
- Misses      32303    32791     +488     
Flag Coverage Δ
integration-test 39.58% <0.00%> (-0.25%) ⬇️
unittest 20.03% <0.00%> (+0.19%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@gnunicorn gnunicorn mentioned this pull request Nov 22, 2024
19 tasks
enum ErrorCode {
notFound,
forbidden,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extended the Error types to be more specific and more precise and allow us to show a different error depending on the underlying code we were given by the server: most notably if we were forbidden access.

error: error,
stack: stack,
textBuilder: (error, errCode) => switch (errCode) {
ErrorCode.forbidden =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Showing different errors depending on the error indicated by the server.

@@ -113,6 +113,10 @@ List<String> asDartStringList(FfiListFfiString data) {
return data.toList().map((e) => e.toDartString()).toList();
}

extension FfiListFfiStringtoDart on FfiListFfiString {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made this more accessible via helper extension

@@ -167,7 +169,7 @@ class SubChatsPage extends ConsumerWidget {
[];
final remoteSubchats =
ref.watch(remoteChatRelationsProvider(spaceId)).valueOrNull ?? [];
final entries = [];
final List<(SpaceHierarchyRoomInfo?, String)> entries = [];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

being specific in types allows the dart compiler to figure out the type below isn't correct.

import 'package:flutter/material.dart';
import 'package:phosphor_flutter/phosphor_flutter.dart';

class ItemPreviewCard extends StatelessWidget {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic type that can render an item preview, as used internally by the ref-details or the uri-parsing entity

String? server,
Function(String)? forward,
) async {
Future<String?> joinRoom({
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Several fixes and refactors in this one:

  1. replace that bad old pattern of having a forward-function passed with a proper future based returning instead
  2. allow to throw the error or return an null on failure
  3. support for more than one via-server as the API now allows for that, too
  4. fix the check of the room actually being available and accessible

Comment on lines +64 to +67
final isSpace = await _ensureLoadedWithinTime(() async {
final room = await ref.refresh(maybeRoomProvider(roomId).future);
return room?.isJoined() == true ? room!.isSpace() : null;
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this now properly checks for the room being available and accessible to the UI before continuing.

);
}

Widget buildPreview(BuildContext context) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new feature to show the preview in the chat for a room we don't have access to

shareContentBuilder: shareContentBuilder,
);
}

Widget? qrCodeHeader(BuildContext context) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor feature (and useful for debugging): show the to be shared information within the QRcode above the QRcode as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests updated for additional via-support that we always include now

@gnunicorn gnunicorn requested review from bitfriend, gtalha07 and kumarpalsinh25 and removed request for bitfriend and gtalha07 January 19, 2025 12:58
@gnunicorn gnunicorn marked this pull request as ready for review January 19, 2025 12:59
Copy link
Contributor

@kumarpalsinh25 kumarpalsinh25 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice addition!!

Added few comments few none of that blocking for merge. PR changes looks good to me.

Comment on lines +12 to +29
class AllHashed<T> {
final List<T> items;

AllHashed(this.items);

@override
int get hashCode => Object.hashAll(items);

@override
bool operator ==(Object other) {
if (other is AllHashed<T>) {
return items == other.items;
} else if (other is List<T>) {
return items == other;
}
return false;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not understanding this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two list of items, even if they are all the same, will come out as "different" if they are different instances. This is used to ensure that https://github.com/acterglobal/a3/pull/2373/files#diff-b2a403334550e3f97cc376cf1228271526121ca2ecf70cf62e6c50ba41e69289R14 caches the input value and not keeps triggering for every render.

Comment on lines +14 to +17
} else if (errorStr.contains('[400 / UNKNOWN]')) {
return ErrorCode.unknown;
} else if (errorStr.contains('[403 / M_FORBIDDEN]')) {
return ErrorCode.forbidden;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

errorStr will contains exact [400 / UNKNOWN]?

If not then how about making condition like if (errorStr.contains('400') || errorStr.contains('UNKNOWN'))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this is exact on purpose.

Comment on lines +87 to +93
ObjectType? finalType() {
ObjectRef? cur = objectPath;
while (cur?.child != null) {
cur = cur?.child; // find the deepest object
}
return cur?.objectType;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not understanding this code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it traverses the object path of the reference type to give the most internal objects type.

the way this is constructed is that the actor URI allows unlimited deep linking. Think:

/tl/asdf/t/339390/c/2323 -> this is a reference to the comment 2323 of task 33930 of task list asdf. The way this is represented in the parse uri result is that every object with an object path can have an additional child which (going left to right) gives the next inner type. So this would be TaskList[id=asdf, child=Task[id=339390. child=Comment[id=2323]]]. In order to find out what the actual final object is (in this case "comment"), you need to traverse that tree. Which is what this code does: look for the most inner item that doesn't have any child (in the while) and then return its objectType.

Comment on lines +54 to +78
headerInfo: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
L10n.of(context).toAccess,
style: Theme.of(context).textTheme.bodyMedium,
),
),
ItemPreviewCard(
// showing the same item without the tap
title: refDetails.title(),
refType: typeFromRefDetails(refDetails),
),
Padding(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
L10n.of(context).needToBeMemberOf,
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we can design better design for this. (Later part..)

Also can be generalised this code as I see this used couple of times..

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is already generalized some part. But I didn't get this much further without making things a lot more specific again ... Happy to go further though.

final bool tapEnabled;
final EdgeInsets? margin;

const ReferenceDetailsItem({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the need of ReferenceDetailsItem as we have ItemPreviewCard. Can't we combined those in single widget?

Widget roomHeader(RoomPreview preview) => Consumer(
builder: (context, ref, child) => ListTile(
leading: ActerAvatar(
options: AvatarOptions(ref.watch(roomPreviewAvatarInfo(query))),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't understand this query thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

query needs roomId and via-server listing, which is combined as query record.

Comment on lines +24 to +30
try {
final res = await callback();
if (res != null) {
return res;
}
} catch (e) {
if (throwError) rethrow;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't understand need of this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this code was meant to repeatedly try to call the function until a timeout occured. But that wasn't the case if there was an exception raised in the inner code, it would just fail immediately instead of retrying. This fixes the retry behaviour to what we really wanted to have in the first place.

@gnunicorn gnunicorn enabled auto-merge January 21, 2025 16:44
@gnunicorn gnunicorn disabled auto-merge January 22, 2025 11:53
@gnunicorn gnunicorn added the merge post release only Merge this only after the new release has been cut label Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge post release only Merge this only after the new release has been cut
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

2 participants