Skip to content

Commit

Permalink
TW-800 Search add empty view
Browse files Browse the repository at this point in the history
  • Loading branch information
drminh2807 committed Oct 27, 2023
1 parent ac596f6 commit 0fbe294
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 37 deletions.
53 changes: 53 additions & 0 deletions assets/images/ic_no_results_found.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -2904,7 +2904,7 @@
"@copyImageFailed": {},
"fileFormatNotSupported": "File format not supported",
"@fileFormatNotSupported": {},
"copyImageSuccess": "Image copied to clipboard",
"noResultsFound": "No results found",
"encryptionMessage": "This feature protects your messages from being read by others, but also prevents them from being backed up on our servers. You can't disable this later.",
"encryptionWarning": "You might lose your messages if you access Twake app on the another device.",
"selectedUsers": "Selected users",
Expand Down
2 changes: 1 addition & 1 deletion lib/pages/chat/events/message_download_content.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class MessageDownloadContent extends StatelessWidget {
);
return InkWell(
onTap: onFileTapped != null
? () async {
? () {
onFileTapped?.call(event);
}
: null,
Expand Down
6 changes: 5 additions & 1 deletion lib/pages/chat_search/chat_search.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ class ChatSearchController extends State<ChatSearch> {

final inputFocus = FocusNode();

final debouncer = Debouncer(_debouncerDuration, initialValue: '');
final debouncer = Debouncer(
_debouncerDuration,
initialValue: '',
checkEquality: false,
);

SameTypeEventsBuilderController? eventsController;

Expand Down
16 changes: 14 additions & 2 deletions lib/pages/chat_search/chat_search_style.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,20 @@ class ChatSearchStyle {
static const EdgeInsetsGeometry inputPadding =
EdgeInsetsDirectional.only(start: 8, top: 16, bottom: 16, end: 16);

static const EdgeInsetsGeometry itemPadding = EdgeInsetsDirectional.all(8);
static const EdgeInsetsGeometry itemMargin =
EdgeInsetsDirectional.symmetric(horizontal: 16);

static const EdgeInsetsGeometry avatarPadding =
static const EdgeInsetsGeometry itemPadding =
EdgeInsetsDirectional.only(end: 8);

static const EdgeInsetsGeometry avatarPadding =
EdgeInsetsDirectional.symmetric(horizontal: 8, vertical: 16);

static const EdgeInsetsGeometry emptyPadding = EdgeInsetsDirectional.all(16);

static const double emptyGap = 128.0;

static const double itemHeight = 90.0;

static const double itemBorderRadius = 12.0;
}
120 changes: 88 additions & 32 deletions lib/pages/chat_search/chat_search_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import 'package:fluffychat/pages/chat_list/chat_list_header_style.dart';
import 'package:fluffychat/pages/chat_search/chat_search.dart';
import 'package:fluffychat/pages/chat_search/chat_search_style.dart';
import 'package:fluffychat/presentation/same_type_events_builder/same_type_events_builder.dart';
import 'package:fluffychat/resource/image_paths.dart';
import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
import 'package:fluffychat/utils/string_extension.dart';
Expand All @@ -17,6 +18,7 @@ import 'package:fluffychat/widgets/matrix.dart';
import 'package:fluffychat/widgets/twake_components/twake_icon_button.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/l10n.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:linagora_design_flutter/linagora_design_flutter.dart';
import 'package:matrix/matrix.dart';

Expand Down Expand Up @@ -52,7 +54,10 @@ class ChatSearchView extends StatelessWidget {
final success = eventsState
.getSuccessOrNull<TimelineSearchEventSuccess>();
final events = success?.events ?? [];
return SliverList.separated(
if (events.isEmpty && controller.eventsController != null) {
return _EmptyView(controller: controller);
}
return SliverList.builder(
itemCount: events.length,
itemBuilder: (context, index) {
final event = events[index];
Expand All @@ -62,7 +67,6 @@ class ChatSearchView extends StatelessWidget {
onTap: controller.onEventTap,
);
},
separatorBuilder: (context, index) => const Divider(),
);
},
),
Expand All @@ -71,6 +75,40 @@ class ChatSearchView extends StatelessWidget {
}
}

class _EmptyView extends StatelessWidget {
const _EmptyView({
required this.controller,
});

final ChatSearchController controller;

@override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: ValueListenableBuilder(
valueListenable: controller.eventsController!.emptyNotifier,
builder: (context, isEmpty, child) => isEmpty
? Padding(
padding: ChatSearchStyle.emptyPadding,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(L10n.of(context)!.noResultsFound),
const SizedBox(height: ChatSearchStyle.emptyGap),
Center(
child: SvgPicture.asset(
ImagePaths.icNoResultsFound,
),
),
],
),
)
: const SizedBox(),
),
);
}
}

class _SearchItem extends StatelessWidget {
final Event event;
final String searchWord;
Expand All @@ -88,10 +126,13 @@ class _SearchItem extends StatelessWidget {
future: event.fetchSenderUser(),
builder: (context, snapshot) {
final user = snapshot.data ?? event.senderFromMemoryOrFallback;
return InkWell(
onTap: () => onTap(event),
child: Padding(
padding: ChatSearchStyle.itemPadding,
return Padding(
padding: ChatSearchStyle.itemMargin,
child: InkWell(
hoverColor: LinagoraRefColors.material().primary[99],
borderRadius:
BorderRadius.circular(ChatSearchStyle.itemBorderRadius),
onTap: () => onTap(event),
child: Row(
children: [
Padding(
Expand All @@ -102,39 +143,54 @@ class _SearchItem extends StatelessWidget {
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
user.id == Matrix.of(context).client.userID
? L10n.of(context)!.you
: user.calcDisplayname(),
maxLines: 1,
child: Container(
margin: ChatSearchStyle.itemPadding,
height: ChatSearchStyle.itemHeight,
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: LinagoraRefColors.material().tertiary[60] ??
Colors.black,
width: 1,
),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Expanded(
child: Text(
user.id == Matrix.of(context).client.userID
? L10n.of(context)!.you
: user.calcDisplayname(),
maxLines: 1,
style: Theme.of(context)
.textTheme
.bodyLarge
?.copyWith(
color: LinagoraSysColors.material()
.onSurface,
),
),
),
Text(
event.originServerTs.localizedTimeShort(context),
style: Theme.of(context)
.textTheme
.bodyLarge
.labelMedium
?.copyWith(
color:
LinagoraSysColors.material().onSurface,
),
),
),
Text(
event.originServerTs.localizedTimeShort(context),
style: Theme.of(context)
.textTheme
.labelMedium
?.copyWith(
color: LinagoraSysColors.material().onSurface,
),
),
],
),
_MessageContent(event: event, searchWord: searchWord),
],
],
),
_MessageContent(event: event, searchWord: searchWord),
],
),
),
),
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class SameTypeEventsBuilderController {
);
final refreshing = ValueNotifier(false);
final loadingMore = ValueNotifier(false);
final emptyNotifier = ValueNotifier(false);

StreamSubscription? _searchSubscription;

Expand All @@ -36,6 +37,7 @@ class SameTypeEventsBuilderController {

Future refresh({bool force = false}) async {
if (refreshing.value && !force) return;
emptyNotifier.value = false;
refreshing.value = true;
final timeline = await getTimeline();
await _searchSubscription?.cancel();
Expand All @@ -62,6 +64,7 @@ class SameTypeEventsBuilderController {
_isEnd) {
return;
}
emptyNotifier.value = false;
loadingMore.value = true;
final timeline = await getTimeline();
await _searchSubscription?.cancel();
Expand All @@ -81,12 +84,20 @@ class SameTypeEventsBuilderController {
}

void clear() {
_searchSubscription?.cancel();
refreshing.value = false;
emptyNotifier.value = false;
eventsNotifier.value = Right(TimelineSearchEventInitial());
}

void _onRefreshDone() {
Logs().v('SameTypeEventsListController::refresh done');
refreshing.value = false;
emptyNotifier.value = eventsNotifier.value
.getSuccessOrNull<TimelineSearchEventSuccess>()
?.events
.isEmpty ??
false;
}

void _onRefreshSuccess(Either<Failure, Success> event) {
Expand Down
2 changes: 2 additions & 0 deletions lib/resource/image_paths.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class ImagePaths {
static String get icErrorPage => _getImagePath('ic_error_page.svg');
static String get icErrorPageBackground =>
_getImagePath('ic_error_page_background.svg');
static String get icNoResultsFound =>
_getImagePath('ic_no_results_found.svg');

static String _getImagePath(String imageName) {
return AssetsPaths.images + imageName;
Expand Down
1 change: 1 addition & 0 deletions lib/utils/string_extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ extension StringCasingExtension on String {
}

String substringToHighlight(String highlightText, {int prefixLength = 0}) {
if (prefixLength < 0) return this;
final index = toLowerCase().indexOf(highlightText.toLowerCase());
if (index > prefixLength) {
return '...${substring(index - prefixLength)}';
Expand Down

0 comments on commit 0fbe294

Please sign in to comment.