Skip to content

Commit

Permalink
TW-615 List all link of Chat in Chat details only mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
drminh2807 authored and hoangdat committed Sep 25, 2023
1 parent 4e1db2c commit 01130f2
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/preview_url/get_preview_url_success.dart';
import 'package:fluffychat/pages/chat_details/chat_details_page_view/links/chat_details_links_style.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/string_extension.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/mixins/get_preview_url_mixin.dart';
import 'package:fluffychat/widgets/mxc_image.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';

class ChatDetailsLinkItem extends StatefulWidget {
const ChatDetailsLinkItem({
super.key,
required this.event,
});

final Event event;

@override
State<ChatDetailsLinkItem> createState() => _ChatDetailsLinkItemState();
}

class _ChatDetailsLinkItemState extends State<ChatDetailsLinkItem>
with GetPreviewUrlMixin {
String get _link => widget.event.firstValidUrl ?? '';

Uri get _uri {
return Uri.tryParse(_link) ?? Uri();
}

@override
String debugLabel = 'ChatDetailsLinkItem';

@override
void initState() {
super.initState();
getPreviewUrl(uri: _uri);
}

@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: getPreviewUrlStateNotifier,
builder: (context, previewUrlState, child) {
final urlPreview = previewUrlState
.getSuccessOrNull<GetPreviewUrlSuccess>()
?.urlPreview;
return InkWell(
onTap: () => UrlLauncher(context, _link).launchUrl(),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: ChatDetailsLinksStyle.margin,
),
child: Row(
children: [
Container(
width: ChatDetailsLinksStyle.avatarSize,
height: ChatDetailsLinksStyle.avatarSize,
alignment: Alignment.center,
decoration: ChatDetailsLinksStyle.avatarDecoration(context),
child: urlPreview?.imageUri != null
? MxcImage(
uri: urlPreview!.imageUri,
isThumbnail: false,
fit: BoxFit.cover,
width: ChatDetailsLinksStyle.avatarSize,
height: ChatDetailsLinksStyle.avatarSize,
placeholder: (_) => child!,
)
: child!,
),
const SizedBox(
width: ChatDetailsLinksStyle.margin,
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
urlPreview?.title ?? _link,
maxLines: 2,
style: ChatDetailsLinksStyle.titleTextStyle(context),
),
if (urlPreview?.description != null)
Text(
urlPreview!.description!,
maxLines: 2,
style: ChatDetailsLinksStyle.descriptionTextStyle(
context,
),
),
Text(
_link,
maxLines: 2,
style: ChatDetailsLinksStyle.linkTextStyle(context),
),
],
),
)
],
),
),
);
},
child: _AvatarPlaceholder(uri: _uri),
);
}
}

class _AvatarPlaceholder extends StatelessWidget {
const _AvatarPlaceholder({
required this.uri,
});

final Uri uri;

@override
Widget build(BuildContext context) {
return Text(
uri.host.getShortcutNameForAvatar(),
style: ChatDetailsLinksStyle.avatarTextStyle(context),
);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/domain/app_state/room/timeline_search_event_state.dart';
import 'package:fluffychat/pages/chat_details/chat_details_page_view/links/chat_details_links_style.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
import 'package:fluffychat/utils/string_extension.dart';
import 'package:fluffychat/pages/chat_details/chat_details_page_view/links/chat_details_links_item.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';

Expand Down Expand Up @@ -31,25 +30,7 @@ class ChatDetailsLinksPage extends StatelessWidget {
return SliverList.separated(
itemCount: events.length,
itemBuilder: (context, index) {
final body = events[index].body;
final link = body.getFirstValidUrl() ?? '';
return ListTile(
leading: Container(
width: ChatDetailsLinksStyle.avatarSize,
height: ChatDetailsLinksStyle.avatarSize,
alignment: Alignment.center,
decoration: ChatDetailsLinksStyle.avatarDecoration(context),
child: Text(
link.getShortcutNameForAvatar(),
style: ChatDetailsLinksStyle.avatarTextStyle(context),
),
),
title: Text(link),
subtitle: Text(
link,
style: ChatDetailsLinksStyle.subtitleTextStyle(context),
),
);
return ChatDetailsLinkItem(event: events[index]);
},
separatorBuilder: (context, index) => const Divider(),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
import 'package:flutter/material.dart';
import 'package:linagora_design_flutter/colors/linagora_ref_colors.dart';

class ChatDetailsLinksStyle {
static const double avatarSize = 56;
static BoxDecoration avatarDecoration(BuildContext context) => BoxDecoration(
color: Theme.of(context).colorScheme.secondary,
borderRadius: BorderRadius.circular(16),
);
static const double margin = 16;
static TextStyle? avatarTextStyle(BuildContext context) =>
Theme.of(context).textTheme.headlineLarge?.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
);
static TextStyle? subtitleTextStyle(BuildContext context) =>
static TextStyle? titleTextStyle(BuildContext context) =>
Theme.of(context).textTheme.titleMedium;
static TextStyle? descriptionTextStyle(BuildContext context) =>
Theme.of(context).textTheme.bodyMedium?.copyWith(
color: LinagoraRefColors.material().tertiary[20],
);
static TextStyle? linkTextStyle(BuildContext context) =>
Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.secondary,
);
Expand Down
6 changes: 4 additions & 2 deletions lib/utils/matrix_sdk_extensions/event_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ extension LocalizedBody on Event {
bool get isVideoOrImage =>
[MessageTypes.Image, MessageTypes.Video].contains(messageType);

bool get isContainsLink =>
messageType == MessageTypes.Text && text.getFirstValidUrl() != null;
String? get firstValidUrl =>
messageType == MessageTypes.Text ? text.getFirstValidUrl() : null;

bool get isContainsLink => firstValidUrl != null;

void shareFile(BuildContext context) async {
final matrixFile = await getFile(context);
Expand Down
56 changes: 56 additions & 0 deletions lib/widgets/mixins/get_preview_url_mixin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'package:dartz/dartz.dart';
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/app_state/preview_url/get_preview_url_success.dart';
import 'package:fluffychat/domain/usecase/preview_url/get_preview_url_interactor.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';

mixin GetPreviewUrlMixin {
static const int _defaultPreferredPreviewTimeInMilliseconds = 2000;

final GetPreviewURLInteractor _getPreviewURLInteractor =
getIt.get<GetPreviewURLInteractor>();

final getPreviewUrlStateNotifier =
ValueNotifier<Either<Failure, Success>>(Right(GetPreviewUrlInitial()));

abstract String debugLabel;

void getPreviewUrl({
required Uri uri,
int preferredPreviewTime = _defaultPreferredPreviewTimeInMilliseconds,
}) {
_getPreviewURLInteractor
.execute(
uri: uri,
preferredPreviewTime: preferredPreviewTime,
)
.listen(
_handleGetPreviewUrlOnData,
onError: _handleGetPreviewUrlOnError,
onDone: _handleGetPreviewUrlOnDone,
);
}

void _handleGetPreviewUrlOnData(Either<Failure, Success> event) {
Logs().d('$debugLabel::_handleGetPreviewUrlOnData()');
getPreviewUrlStateNotifier.value = event;
}

void _handleGetPreviewUrlOnDone() {
Logs().d(
'$debugLabel::_handleGetPreviewUrlOnDone() - done',
);
}

void _handleGetPreviewUrlOnError(
dynamic error,
StackTrace? stackTrace,
) {
Logs().e(
'$debugLabel::_handleGetPreviewUrlOnError() - error: $error | stackTrace: $stackTrace',
);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
import 'package:dartz/dartz.dart' hide State;
import 'package:fluffychat/app_state/failure.dart';
import 'package:fluffychat/app_state/success.dart';
import 'package:fluffychat/di/global/get_it_initializer.dart';
import 'package:fluffychat/domain/app_state/preview_url/get_preview_url_success.dart';
import 'package:fluffychat/domain/usecase/preview_url/get_preview_url_interactor.dart';
import 'package:fluffychat/presentation/extensions/media/url_preview_extension.dart';
import 'package:fluffychat/utils/string_extension.dart';
import 'package:fluffychat/utils/url_launcher.dart';
import 'package:fluffychat/widgets/mixins/get_preview_url_mixin.dart';
import 'package:fluffychat/widgets/twake_components/twake_preview_link/twake_link_preview_item.dart';
import 'package:fluffychat/widgets/twake_components/twake_preview_link/twake_link_view.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
import 'package:matrix_link_text/link_text.dart';

class TwakeLinkPreview extends StatefulWidget {
Expand Down Expand Up @@ -47,60 +42,21 @@ class TwakeLinkPreview extends StatefulWidget {
State<TwakeLinkPreview> createState() => TwakeLinkPreviewController();
}

class TwakeLinkPreviewController extends State<TwakeLinkPreview> {
static const int _defaultPreferredPointInTime = 2000;

final GetPreviewURLInteractor _getPreviewURLInteractor =
getIt.get<GetPreviewURLInteractor>();

final getPreviewUrlStateNotifier =
ValueNotifier<Either<Failure, Success>>(Right(GetPreviewUrlInitial()));

class TwakeLinkPreviewController extends State<TwakeLinkPreview>
with GetPreviewUrlMixin {
String? get firstValidUrl => widget.text.getFirstValidUrl();

@override
String debugLabel = 'TwakeLinkPreviewController';

@override
void initState() {
if (firstValidUrl != null) {
_getPreviewUrlAction();
getPreviewUrl(uri: widget.uri);
}

super.initState();
}

void _getPreviewUrlAction() {
_getPreviewURLInteractor
.execute(
uri: widget.uri,
preferredPreviewTime:
widget.preferredPointInTime ?? _defaultPreferredPointInTime,
)
.listen(
(event) => _handleGetPreviewUrlOnData(event),
onError: _handleGetPreviewUrlOnError,
onDone: _handleGetPreviewUrlOnDone,
);
}

void _handleGetPreviewUrlOnData(Either<Failure, Success> event) {
Logs().d('TwakeLinkPreviewController::_handleGetPreviewUrlOnData()');
getPreviewUrlStateNotifier.value = event;
}

void _handleGetPreviewUrlOnDone() {
Logs().d(
'TwakeLinkPreviewController::_handleGetPreviewUrlOnDone() - done',
);
}

void _handleGetPreviewUrlOnError(
dynamic error,
StackTrace? stackTrace,
) {
Logs().e(
'TwakeLinkPreviewController::_handleGetPreviewUrlOnError() - error: $error | stackTrace: $stackTrace',
);
}

@override
Widget build(BuildContext context) {
return TwakeLinkView(
Expand Down

0 comments on commit 01130f2

Please sign in to comment.