Compare commits
1 commit
main
...
krille/mig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57db6c88cd |
4 changed files with 126 additions and 126 deletions
|
|
@ -16,7 +16,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:record/record.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:universal_html/html.dart' as html;
|
||||
|
||||
|
|
@ -29,6 +29,7 @@ import 'package:fluffychat/pages/chat/recording_dialog.dart';
|
|||
import 'package:fluffychat/pages/chat_details/chat_details.dart';
|
||||
import 'package:fluffychat/utils/error_reporter.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/event_extension.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
import 'package:fluffychat/widgets/app_lock.dart';
|
||||
|
|
@ -104,7 +105,13 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
String get roomId => widget.room.id;
|
||||
|
||||
final AutoScrollController scrollController = AutoScrollController();
|
||||
final ItemScrollController itemScrollController = ItemScrollController();
|
||||
final ScrollOffsetController scrollOffsetController =
|
||||
ScrollOffsetController();
|
||||
final ItemPositionsListener itemPositionsListener =
|
||||
ItemPositionsListener.create();
|
||||
final ScrollOffsetListener scrollOffsetListener =
|
||||
ScrollOffsetListener.create();
|
||||
|
||||
FocusNode inputFocus = FocusNode();
|
||||
StreamSubscription<html.Event>? onFocusSub;
|
||||
|
|
@ -230,21 +237,20 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
setReadMarker(eventId: mostRecentEventId);
|
||||
}
|
||||
|
||||
void _updateScrollController() {
|
||||
void _updateScrollController(double offset) {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (!scrollController.hasClients) return;
|
||||
|
||||
if (timeline?.allowNewEvent == false ||
|
||||
scrollController.position.pixels > 0 && _scrolledUp == false) {
|
||||
offset > 2 && _scrolledUp == false) {
|
||||
setState(() => _scrolledUp = true);
|
||||
} else if (scrollController.position.pixels <= 0 && _scrolledUp == true) {
|
||||
} else if (offset <= 2 && _scrolledUp == true) {
|
||||
setState(() => _scrolledUp = false);
|
||||
setReadMarker();
|
||||
}
|
||||
|
||||
if (scrollController.position.pixels == 0 ||
|
||||
scrollController.position.pixels == 64) {
|
||||
if (offset == 0 || offset == 64) {
|
||||
requestFuture();
|
||||
}
|
||||
}
|
||||
|
|
@ -259,7 +265,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
scrollController.addListener(_updateScrollController);
|
||||
scrollOffsetListener.changes.listen(_updateScrollController);
|
||||
inputFocus.addListener(_inputFocusListener);
|
||||
|
||||
_loadDraft();
|
||||
|
|
@ -292,7 +298,7 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
if (timeline?.events.any((event) => event.eventId == fullyRead) ??
|
||||
false) {
|
||||
Logs().v('Scroll up to visible event', fullyRead);
|
||||
setReadMarker();
|
||||
scrollToEventId(fullyRead);
|
||||
return;
|
||||
}
|
||||
if (!mounted) return;
|
||||
|
|
@ -901,7 +907,9 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
}
|
||||
|
||||
void scrollToEventId(String eventId) async {
|
||||
final eventIndex = timeline!.events.indexWhere((e) => e.eventId == eventId);
|
||||
final events =
|
||||
timeline!.events.where((event) => event.isVisibleInGui).toList();
|
||||
final eventIndex = events.indexWhere((e) => e.eventId == eventId);
|
||||
if (eventIndex == -1) {
|
||||
setState(() {
|
||||
timeline = null;
|
||||
|
|
@ -920,11 +928,11 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
setState(() {
|
||||
scrollToEventIdMarker = eventId;
|
||||
});
|
||||
await scrollController.scrollToIndex(
|
||||
eventIndex,
|
||||
preferPosition: AutoScrollPosition.middle,
|
||||
await itemScrollController.scrollTo(
|
||||
index: eventIndex + 1,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
);
|
||||
_updateScrollController();
|
||||
}
|
||||
|
||||
void scrollDown() async {
|
||||
|
|
@ -939,7 +947,11 @@ class ChatController extends State<ChatPageWithRoom>
|
|||
});
|
||||
await loadTimelineFuture;
|
||||
}
|
||||
scrollController.jumpTo(0);
|
||||
itemScrollController.scrollTo(
|
||||
index: 0,
|
||||
duration: FluffyThemes.animationDuration,
|
||||
curve: FluffyThemes.animationCurve,
|
||||
);
|
||||
}
|
||||
|
||||
void onEmojiSelected(_, Emoji? emoji) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:matrix/matrix.dart';
|
||||
import 'package:scroll_to_index/scroll_to_index.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
import 'package:fluffychat/config/themes.dart';
|
||||
import 'package:fluffychat/pages/chat/chat.dart';
|
||||
|
|
@ -12,7 +12,6 @@ import 'package:fluffychat/pages/user_bottom_sheet/user_bottom_sheet.dart';
|
|||
import 'package:fluffychat/utils/account_config.dart';
|
||||
import 'package:fluffychat/utils/adaptive_bottom_sheet.dart';
|
||||
import 'package:fluffychat/utils/matrix_sdk_extensions/filtered_timeline_extension.dart';
|
||||
import 'package:fluffychat/utils/platform_infos.dart';
|
||||
|
||||
class ChatEventList extends StatelessWidget {
|
||||
final ChatController controller;
|
||||
|
|
@ -41,119 +40,108 @@ class ChatEventList extends StatelessWidget {
|
|||
controller.room.client.applicationAccountConfig.wallpaperUrl != null;
|
||||
|
||||
return SelectionArea(
|
||||
child: ListView.custom(
|
||||
child: ScrollablePositionedList.builder(
|
||||
padding: EdgeInsets.only(
|
||||
top: 16,
|
||||
bottom: 8,
|
||||
left: horizontalPadding,
|
||||
right: horizontalPadding,
|
||||
),
|
||||
itemCount: events.length + 2,
|
||||
reverse: true,
|
||||
controller: controller.scrollController,
|
||||
keyboardDismissBehavior: PlatformInfos.isIOS
|
||||
? ScrollViewKeyboardDismissBehavior.onDrag
|
||||
: ScrollViewKeyboardDismissBehavior.manual,
|
||||
childrenDelegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int i) {
|
||||
// Footer to display typing indicator and read receipts:
|
||||
if (i == 0) {
|
||||
if (controller.timeline!.isRequestingFuture) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||
);
|
||||
}
|
||||
if (controller.timeline!.canRequestFuture) {
|
||||
return Center(
|
||||
child: IconButton(
|
||||
onPressed: controller.requestFuture,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SeenByRow(controller),
|
||||
TypingIndicators(controller),
|
||||
],
|
||||
itemScrollController: controller.itemScrollController,
|
||||
scrollOffsetController: controller.scrollOffsetController,
|
||||
itemPositionsListener: controller.itemPositionsListener,
|
||||
scrollOffsetListener: controller.scrollOffsetListener,
|
||||
itemBuilder: (BuildContext context, int i) {
|
||||
// Footer to display typing indicator and read receipts:
|
||||
if (i == 0) {
|
||||
if (controller.timeline!.isRequestingFuture) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||
);
|
||||
}
|
||||
|
||||
// Request history button or progress indicator:
|
||||
if (i == events.length + 1) {
|
||||
if (controller.timeline!.isRequestingHistory) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||
);
|
||||
}
|
||||
if (controller.timeline!.canRequestHistory) {
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback(controller.requestHistory);
|
||||
return Center(
|
||||
child: IconButton(
|
||||
onPressed: controller.requestHistory,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
i--;
|
||||
|
||||
// The message at this index:
|
||||
final event = events[i];
|
||||
final animateIn = animateInEventIndex != null &&
|
||||
controller.timeline!.events.length > animateInEventIndex &&
|
||||
event == controller.timeline!.events[animateInEventIndex];
|
||||
|
||||
return AutoScrollTag(
|
||||
key: ValueKey(event.eventId),
|
||||
index: i,
|
||||
controller: controller.scrollController,
|
||||
child: Message(
|
||||
event,
|
||||
animateIn: animateIn,
|
||||
resetAnimateIn: () {
|
||||
controller.animateInEventIndex = null;
|
||||
},
|
||||
onSwipe: () => controller.replyAction(replyTo: event),
|
||||
onInfoTab: controller.showEventInfo,
|
||||
onAvatarTab: (Event event) => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => UserBottomSheet(
|
||||
user: event.senderFromMemoryOrFallback,
|
||||
outerContext: context,
|
||||
onMention: () => controller.sendController.text +=
|
||||
'${event.senderFromMemoryOrFallback.mention} ',
|
||||
),
|
||||
if (controller.timeline!.canRequestFuture) {
|
||||
return Center(
|
||||
child: IconButton(
|
||||
onPressed: controller.requestFuture,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
),
|
||||
highlightMarker:
|
||||
controller.scrollToEventIdMarker == event.eventId,
|
||||
onSelect: controller.onSelectMessage,
|
||||
scrollToEventId: (String eventId) =>
|
||||
controller.scrollToEventId(eventId),
|
||||
longPressSelect: controller.selectedEvents.isNotEmpty,
|
||||
selected: controller.selectedEvents
|
||||
.any((e) => e.eventId == event.eventId),
|
||||
timeline: controller.timeline!,
|
||||
displayReadMarker:
|
||||
controller.readMarkerEventId == event.eventId &&
|
||||
controller.timeline?.allowNewEvent == false,
|
||||
nextEvent: i + 1 < events.length ? events[i + 1] : null,
|
||||
previousEvent: i > 0 ? events[i - 1] : null,
|
||||
avatarPresenceBackgroundColor:
|
||||
hasWallpaper ? Colors.transparent : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SeenByRow(controller),
|
||||
TypingIndicators(controller),
|
||||
],
|
||||
);
|
||||
},
|
||||
childCount: events.length + 2,
|
||||
findChildIndexCallback: (key) =>
|
||||
controller.findChildIndexCallback(key, thisEventsKeyMap),
|
||||
),
|
||||
}
|
||||
|
||||
// Request history button or progress indicator:
|
||||
if (i == events.length + 1) {
|
||||
if (controller.timeline!.isRequestingHistory) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator.adaptive(strokeWidth: 2),
|
||||
);
|
||||
}
|
||||
if (controller.timeline!.canRequestHistory) {
|
||||
return Builder(
|
||||
builder: (context) {
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback(controller.requestHistory);
|
||||
return Center(
|
||||
child: IconButton(
|
||||
onPressed: controller.requestHistory,
|
||||
icon: const Icon(Icons.refresh_outlined),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
i--;
|
||||
|
||||
// The message at this index:
|
||||
final event = events[i];
|
||||
final animateIn = animateInEventIndex != null &&
|
||||
controller.timeline!.events.length > animateInEventIndex &&
|
||||
event == controller.timeline!.events[animateInEventIndex];
|
||||
|
||||
return Message(
|
||||
event,
|
||||
animateIn: animateIn,
|
||||
resetAnimateIn: () {
|
||||
controller.animateInEventIndex = null;
|
||||
},
|
||||
onSwipe: () => controller.replyAction(replyTo: event),
|
||||
onInfoTab: controller.showEventInfo,
|
||||
onAvatarTab: (Event event) => showAdaptiveBottomSheet(
|
||||
context: context,
|
||||
builder: (c) => UserBottomSheet(
|
||||
user: event.senderFromMemoryOrFallback,
|
||||
outerContext: context,
|
||||
onMention: () => controller.sendController.text +=
|
||||
'${event.senderFromMemoryOrFallback.mention} ',
|
||||
),
|
||||
),
|
||||
highlightMarker: controller.scrollToEventIdMarker == event.eventId,
|
||||
onSelect: controller.onSelectMessage,
|
||||
scrollToEventId: (String eventId) =>
|
||||
controller.scrollToEventId(eventId),
|
||||
longPressSelect: controller.selectedEvents.isNotEmpty,
|
||||
selected: controller.selectedEvents
|
||||
.any((e) => e.eventId == event.eventId),
|
||||
timeline: controller.timeline!,
|
||||
displayReadMarker: controller.readMarkerEventId == event.eventId &&
|
||||
controller.timeline?.allowNewEvent == false,
|
||||
nextEvent: i + 1 < events.length ? events[i + 1] : null,
|
||||
previousEvent: i > 0 ? events[i - 1] : null,
|
||||
avatarPresenceBackgroundColor:
|
||||
hasWallpaper ? Colors.transparent : null,
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1694,14 +1694,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
scroll_to_index:
|
||||
scrollable_positioned_list:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: scroll_to_index
|
||||
sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176
|
||||
name: scrollable_positioned_list
|
||||
sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
version: "0.3.8"
|
||||
sdp_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ dependencies:
|
|||
qr_code_scanner: ^1.0.1
|
||||
receive_sharing_intent: 1.4.5 # Update needs more work
|
||||
record: ^5.1.2
|
||||
scroll_to_index: ^3.0.1
|
||||
scrollable_positioned_list: ^0.3.8
|
||||
share_plus: ^9.0.0
|
||||
shared_preferences: ^2.2.0 # Pinned because https://github.com/flutter/flutter/issues/118401
|
||||
slugify: ^2.0.0
|
||||
|
|
@ -160,4 +160,4 @@ dependency_overrides:
|
|||
git:
|
||||
url: https://github.com/TheOneWithTheBraid/keyboard_shortcuts.git
|
||||
ref: null-safety
|
||||
win32: 5.5.0
|
||||
win32: 5.5.0
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue