Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class ConversationsBloc extends Bloc<ConversationsEvent, ConversationsState> {
add(ConversationsRefreshed());

if (state.typingStatuses.containsKey(chat.id)) {
add(TypingStatusStopReceived(chat.id, chat.lastMessage!.from!));
add(TypingStatusStopReceived(chat.id, chat.lastMessage!.from));
}
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@ class _ConversationsListState extends State<ConversationsList> with RouteAware {
routeObserver.subscribe(this, ModalRoute.of(context) as PageRoute);
}

@override
void didPopNext() {
// TODO RP for now not using
// context.read<ConversationsBloc>().add(ConversationsRefreshed());
}

@override
Widget build(BuildContext context) {
return BlocBuilder<ConversationsBloc, ConversationsState>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ import '../../../db/models/avatar_model.dart';
import '../../../shared/ui/colors.dart';

class AvatarGroupIcon extends StatelessWidget {
const AvatarGroupIcon(this.avatar, {super.key});
const AvatarGroupIcon(this.avatar, this.name, {super.key});

final AvatarModel? avatar;
final String name;
final Size size = const Size(55, 60);

@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
color: black,
decoration: BoxDecoration(
color: getAvatarColor(name),
shape: BoxShape.circle,
),
height: size.height,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';

import '../../../db/models/avatar_model.dart';
import '../../../shared/ui/colors.dart';
import '../../../shared/utils/string_utils.dart';

class AvatarLetterIcon extends StatelessWidget {
const AvatarLetterIcon({
Expand All @@ -10,8 +11,8 @@ class AvatarLetterIcon extends StatelessWidget {
super.key,
this.size = const Size(55, 55),
this.padding = EdgeInsets.zero,
this.backgroundColor = black,
this.textColor = dullGray,
this.backgroundColor,
this.textColor = signalBlack,
this.avatar,
this.isDeleted,
});
Expand All @@ -21,7 +22,7 @@ class AvatarLetterIcon extends StatelessWidget {
final String? lastName;
final Size size;
final EdgeInsetsGeometry padding;
final Color backgroundColor;
final Color? backgroundColor;
final Color textColor;
final AvatarModel? avatar;
final bool? isDeleted;
Expand All @@ -38,7 +39,9 @@ class AvatarLetterIcon extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
color: isDeleted ?? false
? black
: backgroundColor ?? getAvatarColor(name + (lastName ?? '')),
shape: BoxShape.circle,
// border: Border.all(color: whiteAluminum, width: 2),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ConversationListItem extends StatelessWidget {
avatar: conversation.avatar,
isDeleted: isDeletedUser(conversation.opponent),
)
: AvatarGroupIcon(conversation.avatar),
: AvatarGroupIcon(conversation.avatar, conversation.name),
title: Text(
conversation.name,
style: const TextStyle(fontWeight: FontWeight.w500, fontSize: 20),
Expand Down Expand Up @@ -128,62 +128,67 @@ class DateUnreadWidget extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(right: 2),
child: Text(
DateFormatter().getVerboseDateTimeRepresentation(
(conversation.lastMessage?.t != null
? DateTime.fromMillisecondsSinceEpoch(
conversation.lastMessage!.t! * 1000)
: conversation.updatedAt!)),
style: const TextStyle(color: whiteAluminum, fontSize: 15),
),
),
if (conversation.unreadMessagesCount != null &&
conversation.unreadMessagesCount != 0)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Container(
padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 6),
decoration: BoxDecoration(
color: slateBlue, borderRadius: BorderRadius.circular(10.0)),
return Padding(
padding: const EdgeInsets.only(top: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Padding(
padding: const EdgeInsets.only(right: 2),
child: Text(
conversation.unreadMessagesCount.toString(),
style: const TextStyle(color: white),
DateFormatter().getVerboseDateTimeRepresentation(
(conversation.lastMessage?.t != null
? DateTime.fromMillisecondsSinceEpoch(
conversation.lastMessage!.t! * 1000)
: conversation.updatedAt)),
style: const TextStyle(color: whiteAluminum, fontSize: 13),
),
),
),
],
);
if (conversation.unreadMessagesCount != null &&
conversation.unreadMessagesCount != 0)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Container(
padding:
const EdgeInsets.symmetric(vertical: 2, horizontal: 6),
decoration: BoxDecoration(
color: slateBlue,
borderRadius: BorderRadius.circular(10.0)),
child: Text(
conversation.unreadMessagesCount.toString(),
style: const TextStyle(color: white),
),
),
),
],
));
}
}

class DateFormatter {
String getVerboseDateTimeRepresentation(DateTime dateTime) {
DateTime now = DateTime.now();
DateTime justNow = DateTime.now().subtract(const Duration(minutes: 1));
String getVerboseDateTimeRepresentation(DateTime date) {
final now = DateTime.now();
final difference = now.difference(date);

DateTime localDateTime = dateTime.toLocal();
if (difference.inMinutes < 1) {
return 'Just now';
}

if (!localDateTime.difference(justNow).isNegative) {
return DateFormat('jm').format(dateTime);
if (now.year == date.year &&
now.month == date.month &&
now.day == date.day) {
return DateFormat('HH:mm').format(date);
}

String roughTimeString = DateFormat('jm').format(dateTime);
if (localDateTime.day == now.day &&
localDateTime.month == now.month &&
localDateTime.year == now.year) {
return roughTimeString;
final startOfWeek = now.subtract(Duration(days: now.weekday - 1));
if (date.isAfter(startOfWeek)) {
return DateFormat('EEE').format(date).toLowerCase();
}

if (now.difference(localDateTime).inDays < 4) {
String weekday = DateFormat('EEEE').format(localDateTime);
return weekday.substring(0, 2);
if (now.year == date.year) {
return DateFormat('dd.MM').format(date);
}

return DateFormat.yMd().format(dateTime);
return DateFormat('dd.MM.yy').format(date);
}
}
21 changes: 10 additions & 11 deletions sama_chat_client/lib/src/features/profile/bloc/profile_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,25 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
on<ProfileResetChanges>(_onResetChanges);
on<ProfileSubmitted>(_onSubmitted);

_userRepository.getCurrentUser().then((user) {
add(ProfileUserReceived(user));
});
add(ProfileUserReceived());
}

final UserRepository _userRepository;

void _onUserReceived(
Future<void> _onUserReceived(
ProfileUserReceived event,
Emitter<ProfileState> emit,
) {
) async {
var user = await _userRepository.getCurrentUser();
emit(
state.copyWith(
status: FormzSubmissionStatus.initial,
userLogin: event.user?.login,
userAvatar: UserAvatar.pure(event.user?.avatar?.imageUrl ?? ''),
userFirstname: UserFirstname.pure(event.user?.firstName ?? ''),
userLastname: UserLastname.pure(event.user?.lastName ?? ''),
userPhone: UserPhone.pure(event.user?.phone ?? ''),
userEmail: UserEmail.pure(event.user?.email ?? '')),
userLogin: user?.login,
userAvatar: UserAvatar.pure(user?.avatar?.imageUrl ?? ''),
userFirstname: UserFirstname.pure(user?.firstName ?? ''),
userLastname: UserLastname.pure(user?.lastName ?? ''),
userPhone: UserPhone.pure(user?.phone ?? ''),
userEmail: UserEmail.pure(user?.email ?? '')),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ sealed class ProfileEvent extends Equatable {
List<Object?> get props => [];
}

final class ProfileUserReceived extends ProfileEvent {
const ProfileUserReceived(this.user);

final UserModel? user;

@override
List<Object?> get props => [user];
}
final class ProfileUserReceived extends ProfileEvent {}

final class ProfileAvatarPicked extends ProfileEvent {}

Expand Down
24 changes: 24 additions & 0 deletions sama_chat_client/lib/src/shared/ui/colors.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:ui';

import 'package:flutter/material.dart';

const Color white = Color(0xFFFFFFFF);
const Color lightWhite = Color(0xFFF9F9F9);
const Color smokyWhite = Color(0xFFF6F6F6);
Expand All @@ -23,3 +25,25 @@ const Color lightPink = Color(0xFFFFB6C1);
const Color orange = Color(0xFFFFA500);
const Color redPurple = Color(0xFF68174D);
const Color red = Color(0xFFDF2E38);

const colors = [
Color(0xFFe17076), // red
Color(0xFFf4a261), // orange
Color(0xFFe9c46a), // yellow
Color(0xFF2a9d8f), // teal
Color(0xFF4d96ff), // blue
Color(0xFF9b5de5), // purple
Color(0xFFf15bb5), // pink
Color(0xFF00bcd4), // cyan
];

Color getAvatarColor(String input) {
final hash = input.runes.fold(0, (prev, el) => prev * 31 + el);
final index = hash.abs() % colors.length;

final saturation = 0.35 + ((hash >> 8) % 40) / 100; // 0.35–0.75
final lightness = 0.55 + ((hash >> 16) % 20) / 100; // 0.55–0.75

final hsl = HSLColor.fromColor(colors[index]);
return hsl.withSaturation(saturation).withLightness(lightness).toColor();
}