Skip to content

Commit

Permalink
Add timestamps to ChatItemWidget and ChatForwardWidget (#399)
Browse files Browse the repository at this point in the history
- add `ApplicationSettings.timelineEnabled` switching timestamps and timeline in `Chat`
- add `ProfileTab.chats` section to `Menu` tab
- add `TimelineSwitchView` switching `ApplicationSettings.timelineEnabled`
- refactor `ChatItemWidget` and `ChatForwardWidget` to display timestamps

Additionally:
- add `RichTextExtension` finding `RichText`s
  • Loading branch information
krida2000 committed Apr 20, 2023
1 parent 198fd33 commit 1a95144
Show file tree
Hide file tree
Showing 25 changed files with 859 additions and 276 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ All user visible changes to this project will be documented in this file. This p
- Chat page:
- Redesigned info and call messages. ([#357])
- Redesigned file attachments. ([#362])
- Message timestamps. ([#399])
- Media panel:
- Position and size persistence. ([#270], [#264])
- Proportionally resizing secondary panel. ([#393], [#356], [#258])
Expand Down Expand Up @@ -64,6 +65,7 @@ All user visible changes to this project will be documented in this file. This p
[#380]: /../../pull/380
[#388]: /../../pull/388
[#393]: /../../pull/393
[#399]: /../../pull/399
[#403]: /../../pull/403


Expand Down
4 changes: 4 additions & 0 deletions assets/l10n/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ label_app_background = Application background
label_application = Application
label_are_you_sure_no = No
label_are_you_sure_yes = Yes
label_as_timeline = As timeline
label_attachments = [{$count} { $count ->
[1] attachment
*[other] attachments
Expand Down Expand Up @@ -476,6 +477,7 @@ label_direct_chat_link_in_chat_description =
- send messages to group chat,
- make calls
label_disabled = Disabled
label_display_timestamps = Display time stamps
label_download = Download
label_download_application = Download application
label_draft = Draft
Expand Down Expand Up @@ -522,6 +524,7 @@ label_hint_drag_n_drop_video =
label_hint_from_gapopa = Hint from Gapopa
label_image_downloaded = Image downloaded.
label_image_saved_to_gallery = Image saved to gallery.
label_in_message = In message
label_incoming_call = Incoming call
label_introduction_description =
Password is not set. Access to an account without a password is retained for one year from the time the account was created or until:
Expand Down Expand Up @@ -672,6 +675,7 @@ label_subtitle_participants = participants
label_tab_chats = Chats
label_tab_contacts = Contacts
label_tab_menu = Menu
label_timeline_style = Timeline style
label_transition_count = Transitions: {$count}
label_typing = Typing
label_unconfirmed = Unconfirmed
Expand Down
4 changes: 4 additions & 0 deletions assets/l10n/ru-RU.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,7 @@ label_app_background = Фон приложения
label_application = Приложение
label_are_you_sure_no = Нет
label_are_you_sure_yes = Да
label_as_timeline = Как таймлайн
label_attachments = [{$count} { $count ->
[1] прикрепление
[few] прикрепления
Expand Down Expand Up @@ -492,6 +493,7 @@ label_direct_chat_link_in_chat_description =
- отправлять сообщения в чат группы,
- совершать звонки
label_disabled = Отключены
label_display_timestamps = Отображать метки времени
label_download = Скачать
label_download_application = Скачать приложение
label_draft = Черновик
Expand Down Expand Up @@ -538,6 +540,7 @@ label_hint_drag_n_drop_video =
label_hint_from_gapopa = Подсказка от Gapopa
label_image_downloaded = Изображение загружено.
label_image_saved_to_gallery = Изображение сохранено в галерею.
label_in_message = В сообщении
label_incoming_call = Входящий звонок
label_introduction_description =
Пароль не задан. Доступ к аккаунту без пароля сохраняется в течении одного года с момента создания аккаунта или пока:
Expand Down Expand Up @@ -692,6 +695,7 @@ label_subtitle_participants = участников
label_tab_chats = Чаты
label_tab_contacts = Контакты
label_tab_menu = Меню
label_timeline_style = Стиль метки времени
label_transition_count = Переходов: {$count}
label_typing = Печатает
label_unconfirmed = Неподтвержденный
Expand Down
6 changes: 6 additions & 0 deletions lib/domain/model/application_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ApplicationSettings extends HiveObject {
this.showDragAndDropButtonsHint = false,
this.sortContactsByName = true,
this.loadImages = true,
this.timelineEnabled = false,
});

/// Indicator whether [OngoingCall]s are preferred to be displayed in the
Expand Down Expand Up @@ -75,4 +76,9 @@ class ApplicationSettings extends HiveObject {
/// Indicator whether [ImageAttachment]s should be loaded automatically.
@HiveField(8)
bool loadImages;

/// Indicator whether [ChatItem.at] labels should be displayed as a timeline
/// in a [Chat].
@HiveField(9)
bool timelineEnabled;
}
3 changes: 3 additions & 0 deletions lib/domain/repository/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,7 @@ abstract class AbstractSettingsRepository {
/// Returns the [Rect] preferences of an [OngoingCall] happening in the
/// specified [Chat].
Rect? getCallRect(ChatId id);

/// Sets the [ApplicationSettings.timelineEnabled] value.
Future<void> setTimelineEnabled(bool enabled);
}
7 changes: 7 additions & 0 deletions lib/provider/hive/application_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,11 @@ class ApplicationSettingsHiveProvider
0,
(box.get(0) ?? ApplicationSettings())..loadImages = enabled,
);

/// Stores a new [enabled] value of [ApplicationSettings.timelineEnabled]
/// to [Hive].
Future<void> setTimelineEnabled(bool enabled) => putSafe(
0,
(box.get(0) ?? ApplicationSettings())..timelineEnabled = enabled,
);
}
1 change: 1 addition & 0 deletions lib/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ enum ProfileTab {
signing,
link,
background,
chats,
calls,
media,
notifications,
Expand Down
2 changes: 2 additions & 0 deletions lib/store/chat_rx.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,8 @@ class AwaitableTimer {
_timer = Timer(d, () async {
try {
_completer.complete(await callback());
} on StateError {
// No-op, as [Future] is allowed to be completed.
} catch (e, stackTrace) {
_completer.completeError(e, stackTrace);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/store/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ class SettingsRepository extends DisposableInterface
@override
Rect? getCallRect(ChatId id) => _callRectLocal.get(id);

@override
Future<void> setTimelineEnabled(bool enabled) =>
_settingsLocal.setTimelineEnabled(enabled);

/// Initializes [MediaSettingsHiveProvider.boxEvents] subscription.
Future<void> _initMediaSubscription() async {
_mediaSubscription = StreamIterator(_mediaLocal.boxEvents);
Expand Down
61 changes: 37 additions & 24 deletions lib/ui/page/home/page/chat/view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -282,24 +282,26 @@ class _ChatViewState extends State<ChatView>
],
),
body: Listener(
onPointerSignal: (s) {
if (s is PointerScrollEvent) {
if ((s.scrollDelta.dy.abs() < 3 &&
s.scrollDelta.dx.abs() > 3) ||
c.isHorizontalScroll.value) {
double value =
_animation.value + s.scrollDelta.dx / 100;
_animation.value = value.clamp(0, 1);

if (_animation.value == 0 ||
_animation.value == 1) {
_resetHorizontalScroll(c, 10.milliseconds);
} else {
_resetHorizontalScroll(c);
onPointerSignal: c.settings.value?.timelineEnabled == true
? (s) {
if (s is PointerScrollEvent) {
if ((s.scrollDelta.dy.abs() < 3 &&
s.scrollDelta.dx.abs() > 3) ||
c.isHorizontalScroll.value) {
double value =
_animation.value + s.scrollDelta.dx / 100;
_animation.value = value.clamp(0, 1);

if (_animation.value == 0 ||
_animation.value == 1) {
_resetHorizontalScroll(c, 10.milliseconds);
} else {
_resetHorizontalScroll(c);
}
}
}
}
}
}
},
: null,
onPointerPanZoomUpdate: (s) {
if (c.scrollOffset.dx.abs() < 7 &&
c.scrollOffset.dy.abs() < 7) {
Expand All @@ -323,7 +325,8 @@ class _ChatViewState extends State<ChatView>
child: RawGestureDetector(
behavior: HitTestBehavior.translucent,
gestures: {
if (c.isSelecting.isFalse)
if (c.settings.value?.timelineEnabled == true &&
c.isSelecting.isFalse)
AllowMultipleHorizontalDragGestureRecognizer:
GestureRecognizerFactoryWithHandlers<
AllowMultipleHorizontalDragGestureRecognizer>(
Expand Down Expand Up @@ -613,6 +616,7 @@ class _ChatViewState extends State<ChatView>
user: u.data,
getUser: c.getUser,
animation: _animation,
timestamp: c.settings.value?.timelineEnabled != true,
onHide: () => c.hideChatItem(e.value),
onDelete: () => c.deleteMessage(e.value),
onReply: () {
Expand All @@ -622,9 +626,13 @@ class _ChatViewState extends State<ChatView>
c.send.replied.insert(0, e.value);
}
},
onCopy: c.selection.value?.plainText.isNotEmpty == true
? (_) => c.copyText(c.selection.value!.plainText)
: c.copyText,
onCopy: (text) {
if (c.selection.value?.plainText.isNotEmpty == true) {
c.copyText(c.selection.value!.plainText);
} else {
c.copyText(text);
}
},
onRepliedTap: (q) async {
if (q.original != null) {
await c.animateTo(q.original!.id);
Expand Down Expand Up @@ -665,6 +673,7 @@ class _ChatViewState extends State<ChatView>
user: u.data,
getUser: c.getUser,
animation: _animation,
timestamp: c.settings.value?.timelineEnabled != true,
onHide: () async {
final List<Future> futures = [];

Expand Down Expand Up @@ -714,9 +723,13 @@ class _ChatViewState extends State<ChatView>
}
}
},
onCopy: c.selection.value?.plainText.isNotEmpty == true
? (_) => c.copyText(c.selection.value!.plainText)
: c.copyText,
onCopy: (text) {
if (c.selection.value?.plainText.isNotEmpty == true) {
c.copyText(c.selection.value!.plainText);
} else {
c.copyText(text);
}
},
onGallery: c.calculateGallery,
onEdit: () => c.editMessage(element.note.value!.value),
onDrag: (d) => c.isItemDragged.value = d,
Expand Down
Loading

0 comments on commit 1a95144

Please sign in to comment.