mirror of
				https://gitlab.com/famedly/fluffychat.git
				synced 2025-11-04 06:17:26 +01:00 
			
		
		
		
	Merge branch 'krille/read-marker' into 'main'
fix: Set read marker only on user interaction See merge request famedly/fluffychat!747
This commit is contained in:
		
						commit
						6f7ea70a50
					
				@ -147,6 +147,7 @@ class ChatController extends State<Chat> {
 | 
			
		||||
    if (!mounted) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    setReadMarker();
 | 
			
		||||
    if (scrollController.position.pixels ==
 | 
			
		||||
            scrollController.position.maxScrollExtent &&
 | 
			
		||||
        timeline!.events.isNotEmpty &&
 | 
			
		||||
@ -201,8 +202,8 @@ class ChatController extends State<Chat> {
 | 
			
		||||
    if (timeline == null) {
 | 
			
		||||
      timeline = await room!.getTimeline(onUpdate: updateView);
 | 
			
		||||
      if (timeline!.events.isNotEmpty) {
 | 
			
		||||
        // ignore: unawaited_futures
 | 
			
		||||
        if (room!.markedUnread) room!.markUnread(false);
 | 
			
		||||
        setReadMarker();
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      // when the scroll controller is attached we want to scroll to an event id, if specified
 | 
			
		||||
@ -220,15 +221,24 @@ class ChatController extends State<Chat> {
 | 
			
		||||
    }
 | 
			
		||||
    filteredEvents = timeline!.getFilteredEvents(unfolded: unfolded);
 | 
			
		||||
    timeline!.requestKeys();
 | 
			
		||||
    if ((room!.hasNewMessages || room!.notificationCount > 0) &&
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void>? _setReadMarkerFuture;
 | 
			
		||||
 | 
			
		||||
  void setReadMarker([_]) {
 | 
			
		||||
    if (_setReadMarkerFuture == null &&
 | 
			
		||||
        (room!.hasNewMessages || room!.notificationCount > 0) &&
 | 
			
		||||
        timeline != null &&
 | 
			
		||||
        timeline!.events.isNotEmpty &&
 | 
			
		||||
        Matrix.of(context).webHasFocus) {
 | 
			
		||||
      Logs().v('Set read marker...');
 | 
			
		||||
      // ignore: unawaited_futures
 | 
			
		||||
      timeline!.setReadMarker();
 | 
			
		||||
      _setReadMarkerFuture = timeline!.setReadMarker().then((_) {
 | 
			
		||||
        _setReadMarkerFuture = null;
 | 
			
		||||
      });
 | 
			
		||||
      room!.client.updateIosBadge();
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@ -900,6 +910,7 @@ class ChatController extends State<Chat> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void onInputBarChanged(String text) {
 | 
			
		||||
    setReadMarker();
 | 
			
		||||
    if (text.endsWith(' ') && matrix!.hasComplexBundles) {
 | 
			
		||||
      final clients = currentRoomBundle;
 | 
			
		||||
      for (final client in clients) {
 | 
			
		||||
 | 
			
		||||
@ -156,295 +156,297 @@ class ChatView extends StatelessWidget {
 | 
			
		||||
          redirector.stopRedirection();
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      child: StreamBuilder(
 | 
			
		||||
        stream: controller.room!.onUpdate.stream
 | 
			
		||||
            .rateLimit(const Duration(milliseconds: 250)),
 | 
			
		||||
        builder: (context, snapshot) => FutureBuilder<bool>(
 | 
			
		||||
          future: controller.getTimeline(),
 | 
			
		||||
          builder: (BuildContext context, snapshot) {
 | 
			
		||||
            return Scaffold(
 | 
			
		||||
              appBar: AppBar(
 | 
			
		||||
                actionsIconTheme: IconThemeData(
 | 
			
		||||
                  color: controller.selectedEvents.isEmpty
 | 
			
		||||
                      ? null
 | 
			
		||||
                      : Theme.of(context).colorScheme.primary,
 | 
			
		||||
      child: GestureDetector(
 | 
			
		||||
        onTapDown: controller.setReadMarker,
 | 
			
		||||
        child: StreamBuilder(
 | 
			
		||||
          stream: controller.room!.onUpdate.stream
 | 
			
		||||
              .rateLimit(const Duration(milliseconds: 250)),
 | 
			
		||||
          builder: (context, snapshot) => FutureBuilder<bool>(
 | 
			
		||||
            future: controller.getTimeline(),
 | 
			
		||||
            builder: (BuildContext context, snapshot) {
 | 
			
		||||
              return Scaffold(
 | 
			
		||||
                appBar: AppBar(
 | 
			
		||||
                  actionsIconTheme: IconThemeData(
 | 
			
		||||
                    color: controller.selectedEvents.isEmpty
 | 
			
		||||
                        ? null
 | 
			
		||||
                        : Theme.of(context).colorScheme.primary,
 | 
			
		||||
                  ),
 | 
			
		||||
                  leading: controller.selectMode
 | 
			
		||||
                      ? IconButton(
 | 
			
		||||
                          icon: const Icon(Icons.close),
 | 
			
		||||
                          onPressed: controller.clearSelectedEvents,
 | 
			
		||||
                          tooltip: L10n.of(context)!.close,
 | 
			
		||||
                          color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
                        )
 | 
			
		||||
                      : UnreadBadgeBackButton(roomId: controller.roomId!),
 | 
			
		||||
                  titleSpacing: 0,
 | 
			
		||||
                  title: ChatAppBarTitle(controller),
 | 
			
		||||
                  actions: _appBarActions(context),
 | 
			
		||||
                ),
 | 
			
		||||
                leading: controller.selectMode
 | 
			
		||||
                    ? IconButton(
 | 
			
		||||
                        icon: const Icon(Icons.close),
 | 
			
		||||
                        onPressed: controller.clearSelectedEvents,
 | 
			
		||||
                        tooltip: L10n.of(context)!.close,
 | 
			
		||||
                        color: Theme.of(context).colorScheme.primary,
 | 
			
		||||
                floatingActionButton: controller.showScrollDownButton &&
 | 
			
		||||
                        controller.selectedEvents.isEmpty
 | 
			
		||||
                    ? Padding(
 | 
			
		||||
                        padding: const EdgeInsets.only(bottom: 56.0),
 | 
			
		||||
                        child: FloatingActionButton(
 | 
			
		||||
                          onPressed: controller.scrollDown,
 | 
			
		||||
                          foregroundColor:
 | 
			
		||||
                              Theme.of(context).textTheme.bodyText2!.color,
 | 
			
		||||
                          backgroundColor:
 | 
			
		||||
                              Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
                          mini: true,
 | 
			
		||||
                          child: Icon(Icons.arrow_downward_outlined,
 | 
			
		||||
                              color: Theme.of(context).primaryColor),
 | 
			
		||||
                        ),
 | 
			
		||||
                      )
 | 
			
		||||
                    : UnreadBadgeBackButton(roomId: controller.roomId!),
 | 
			
		||||
                titleSpacing: 0,
 | 
			
		||||
                title: ChatAppBarTitle(controller),
 | 
			
		||||
                actions: _appBarActions(context),
 | 
			
		||||
              ),
 | 
			
		||||
              floatingActionButton: controller.showScrollDownButton &&
 | 
			
		||||
                      controller.selectedEvents.isEmpty
 | 
			
		||||
                  ? Padding(
 | 
			
		||||
                      padding: const EdgeInsets.only(bottom: 56.0),
 | 
			
		||||
                      child: FloatingActionButton(
 | 
			
		||||
                        onPressed: controller.scrollDown,
 | 
			
		||||
                        foregroundColor:
 | 
			
		||||
                            Theme.of(context).textTheme.bodyText2!.color,
 | 
			
		||||
                        backgroundColor:
 | 
			
		||||
                            Theme.of(context).scaffoldBackgroundColor,
 | 
			
		||||
                        mini: true,
 | 
			
		||||
                        child: Icon(Icons.arrow_downward_outlined,
 | 
			
		||||
                            color: Theme.of(context).primaryColor),
 | 
			
		||||
                      ),
 | 
			
		||||
                    )
 | 
			
		||||
                  : null,
 | 
			
		||||
              backgroundColor: Theme.of(context).colorScheme.surface,
 | 
			
		||||
              body: DropTarget(
 | 
			
		||||
                onDragDone: controller.onDragDone,
 | 
			
		||||
                onDragEntered: controller.onDragEntered,
 | 
			
		||||
                onDragExited: controller.onDragExited,
 | 
			
		||||
                child: Stack(
 | 
			
		||||
                  children: <Widget>[
 | 
			
		||||
                    if (Matrix.of(context).wallpaper != null)
 | 
			
		||||
                      Image.file(
 | 
			
		||||
                        Matrix.of(context).wallpaper!,
 | 
			
		||||
                        width: double.infinity,
 | 
			
		||||
                        height: double.infinity,
 | 
			
		||||
                        fit: BoxFit.cover,
 | 
			
		||||
                      ),
 | 
			
		||||
                    SafeArea(
 | 
			
		||||
                      child: Column(
 | 
			
		||||
                        children: <Widget>[
 | 
			
		||||
                          TombstoneDisplay(controller),
 | 
			
		||||
                          PinnedEvents(controller),
 | 
			
		||||
                          Expanded(
 | 
			
		||||
                            child: GestureDetector(
 | 
			
		||||
                                onTap: controller.clearSingleSelectedEvent,
 | 
			
		||||
                                child: Builder(
 | 
			
		||||
                                  builder: (context) {
 | 
			
		||||
                                    if (snapshot.hasError) {
 | 
			
		||||
                                      SentryController.captureException(
 | 
			
		||||
                                        snapshot.error,
 | 
			
		||||
                                        StackTrace.current,
 | 
			
		||||
                                      );
 | 
			
		||||
                                    }
 | 
			
		||||
                                    if (controller.timeline == null) {
 | 
			
		||||
                                      return const Center(
 | 
			
		||||
                                        child:
 | 
			
		||||
                                            CircularProgressIndicator.adaptive(
 | 
			
		||||
                                                strokeWidth: 2),
 | 
			
		||||
                                      );
 | 
			
		||||
                                    }
 | 
			
		||||
                    : null,
 | 
			
		||||
                backgroundColor: Theme.of(context).colorScheme.surface,
 | 
			
		||||
                body: DropTarget(
 | 
			
		||||
                  onDragDone: controller.onDragDone,
 | 
			
		||||
                  onDragEntered: controller.onDragEntered,
 | 
			
		||||
                  onDragExited: controller.onDragExited,
 | 
			
		||||
                  child: Stack(
 | 
			
		||||
                    children: <Widget>[
 | 
			
		||||
                      if (Matrix.of(context).wallpaper != null)
 | 
			
		||||
                        Image.file(
 | 
			
		||||
                          Matrix.of(context).wallpaper!,
 | 
			
		||||
                          width: double.infinity,
 | 
			
		||||
                          height: double.infinity,
 | 
			
		||||
                          fit: BoxFit.cover,
 | 
			
		||||
                        ),
 | 
			
		||||
                      SafeArea(
 | 
			
		||||
                        child: Column(
 | 
			
		||||
                          children: <Widget>[
 | 
			
		||||
                            TombstoneDisplay(controller),
 | 
			
		||||
                            PinnedEvents(controller),
 | 
			
		||||
                            Expanded(
 | 
			
		||||
                              child: GestureDetector(
 | 
			
		||||
                                  onTap: controller.clearSingleSelectedEvent,
 | 
			
		||||
                                  child: Builder(
 | 
			
		||||
                                    builder: (context) {
 | 
			
		||||
                                      if (snapshot.hasError) {
 | 
			
		||||
                                        SentryController.captureException(
 | 
			
		||||
                                          snapshot.error,
 | 
			
		||||
                                          StackTrace.current,
 | 
			
		||||
                                        );
 | 
			
		||||
                                      }
 | 
			
		||||
                                      if (controller.timeline == null) {
 | 
			
		||||
                                        return const Center(
 | 
			
		||||
                                          child: CircularProgressIndicator
 | 
			
		||||
                                              .adaptive(strokeWidth: 2),
 | 
			
		||||
                                        );
 | 
			
		||||
                                      }
 | 
			
		||||
 | 
			
		||||
                                    // create a map of eventId --> index to greatly improve performance of
 | 
			
		||||
                                    // ListView's findChildIndexCallback
 | 
			
		||||
                                    final thisEventsKeyMap = <String, int>{};
 | 
			
		||||
                                    for (var i = 0;
 | 
			
		||||
                                        i < controller.filteredEvents.length;
 | 
			
		||||
                                        i++) {
 | 
			
		||||
                                      thisEventsKeyMap[controller
 | 
			
		||||
                                          .filteredEvents[i].eventId] = i;
 | 
			
		||||
                                    }
 | 
			
		||||
                                    return ListView.custom(
 | 
			
		||||
                                      padding: EdgeInsets.only(
 | 
			
		||||
                                        top: 16,
 | 
			
		||||
                                        bottom: 4,
 | 
			
		||||
                                        left: horizontalPadding,
 | 
			
		||||
                                        right: horizontalPadding,
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      reverse: true,
 | 
			
		||||
                                      controller: controller.scrollController,
 | 
			
		||||
                                      keyboardDismissBehavior: PlatformInfos
 | 
			
		||||
                                              .isIOS
 | 
			
		||||
                                          ? ScrollViewKeyboardDismissBehavior
 | 
			
		||||
                                              .onDrag
 | 
			
		||||
                                          : ScrollViewKeyboardDismissBehavior
 | 
			
		||||
                                              .manual,
 | 
			
		||||
                                      childrenDelegate:
 | 
			
		||||
                                          SliverChildBuilderDelegate(
 | 
			
		||||
                                        (BuildContext context, int i) {
 | 
			
		||||
                                          return i ==
 | 
			
		||||
                                                  controller.filteredEvents
 | 
			
		||||
                                                          .length +
 | 
			
		||||
                                                      1
 | 
			
		||||
                                              ? controller.timeline!
 | 
			
		||||
                                                      .isRequestingHistory
 | 
			
		||||
                                                  ? const Center(
 | 
			
		||||
                                                      child:
 | 
			
		||||
                                                          CircularProgressIndicator
 | 
			
		||||
                                                              .adaptive(
 | 
			
		||||
                                                                  strokeWidth:
 | 
			
		||||
                                                                      2),
 | 
			
		||||
                                                    )
 | 
			
		||||
                                                  : controller.canLoadMore
 | 
			
		||||
                                                      ? Center(
 | 
			
		||||
                                                          child: OutlinedButton(
 | 
			
		||||
                                                            style:
 | 
			
		||||
                                                                OutlinedButton
 | 
			
		||||
                                                                    .styleFrom(
 | 
			
		||||
                                                              backgroundColor:
 | 
			
		||||
                                                                  Theme.of(
 | 
			
		||||
                                                                          context)
 | 
			
		||||
                                                                      .scaffoldBackgroundColor,
 | 
			
		||||
                                      // create a map of eventId --> index to greatly improve performance of
 | 
			
		||||
                                      // ListView's findChildIndexCallback
 | 
			
		||||
                                      final thisEventsKeyMap = <String, int>{};
 | 
			
		||||
                                      for (var i = 0;
 | 
			
		||||
                                          i < controller.filteredEvents.length;
 | 
			
		||||
                                          i++) {
 | 
			
		||||
                                        thisEventsKeyMap[controller
 | 
			
		||||
                                            .filteredEvents[i].eventId] = i;
 | 
			
		||||
                                      }
 | 
			
		||||
                                      return ListView.custom(
 | 
			
		||||
                                        padding: EdgeInsets.only(
 | 
			
		||||
                                          top: 16,
 | 
			
		||||
                                          bottom: 4,
 | 
			
		||||
                                          left: horizontalPadding,
 | 
			
		||||
                                          right: horizontalPadding,
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        reverse: true,
 | 
			
		||||
                                        controller: controller.scrollController,
 | 
			
		||||
                                        keyboardDismissBehavior: PlatformInfos
 | 
			
		||||
                                                .isIOS
 | 
			
		||||
                                            ? ScrollViewKeyboardDismissBehavior
 | 
			
		||||
                                                .onDrag
 | 
			
		||||
                                            : ScrollViewKeyboardDismissBehavior
 | 
			
		||||
                                                .manual,
 | 
			
		||||
                                        childrenDelegate:
 | 
			
		||||
                                            SliverChildBuilderDelegate(
 | 
			
		||||
                                          (BuildContext context, int i) {
 | 
			
		||||
                                            return i ==
 | 
			
		||||
                                                    controller.filteredEvents
 | 
			
		||||
                                                            .length +
 | 
			
		||||
                                                        1
 | 
			
		||||
                                                ? controller.timeline!
 | 
			
		||||
                                                        .isRequestingHistory
 | 
			
		||||
                                                    ? const Center(
 | 
			
		||||
                                                        child:
 | 
			
		||||
                                                            CircularProgressIndicator
 | 
			
		||||
                                                                .adaptive(
 | 
			
		||||
                                                                    strokeWidth:
 | 
			
		||||
                                                                        2),
 | 
			
		||||
                                                      )
 | 
			
		||||
                                                    : controller.canLoadMore
 | 
			
		||||
                                                        ? Center(
 | 
			
		||||
                                                            child:
 | 
			
		||||
                                                                OutlinedButton(
 | 
			
		||||
                                                              style:
 | 
			
		||||
                                                                  OutlinedButton
 | 
			
		||||
                                                                      .styleFrom(
 | 
			
		||||
                                                                backgroundColor:
 | 
			
		||||
                                                                    Theme.of(
 | 
			
		||||
                                                                            context)
 | 
			
		||||
                                                                        .scaffoldBackgroundColor,
 | 
			
		||||
                                                              ),
 | 
			
		||||
                                                              onPressed: controller
 | 
			
		||||
                                                                  .requestHistory,
 | 
			
		||||
                                                              child: Text(L10n.of(
 | 
			
		||||
                                                                      context)!
 | 
			
		||||
                                                                  .loadMore),
 | 
			
		||||
                                                            ),
 | 
			
		||||
                                                            onPressed: controller
 | 
			
		||||
                                                                .requestHistory,
 | 
			
		||||
                                                            child: Text(L10n.of(
 | 
			
		||||
                                                                    context)!
 | 
			
		||||
                                                                .loadMore),
 | 
			
		||||
                                                          ),
 | 
			
		||||
                                                        )
 | 
			
		||||
                                                      : Container()
 | 
			
		||||
                                              : i == 0
 | 
			
		||||
                                                  ? Column(
 | 
			
		||||
                                                      mainAxisSize:
 | 
			
		||||
                                                          MainAxisSize.min,
 | 
			
		||||
                                                      children: [
 | 
			
		||||
                                                        SeenByRow(controller),
 | 
			
		||||
                                                        TypingIndicators(
 | 
			
		||||
                                                            controller),
 | 
			
		||||
                                                      ],
 | 
			
		||||
                                                    )
 | 
			
		||||
                                                  : AutoScrollTag(
 | 
			
		||||
                                                      key: ValueKey(controller
 | 
			
		||||
                                                          .filteredEvents[i - 1]
 | 
			
		||||
                                                          .eventId),
 | 
			
		||||
                                                      index: i - 1,
 | 
			
		||||
                                                      controller: controller
 | 
			
		||||
                                                          .scrollController,
 | 
			
		||||
                                                      child: Swipeable(
 | 
			
		||||
                                                          )
 | 
			
		||||
                                                        : Container()
 | 
			
		||||
                                                : i == 0
 | 
			
		||||
                                                    ? Column(
 | 
			
		||||
                                                        mainAxisSize:
 | 
			
		||||
                                                            MainAxisSize.min,
 | 
			
		||||
                                                        children: [
 | 
			
		||||
                                                          SeenByRow(controller),
 | 
			
		||||
                                                          TypingIndicators(
 | 
			
		||||
                                                              controller),
 | 
			
		||||
                                                        ],
 | 
			
		||||
                                                      )
 | 
			
		||||
                                                    : AutoScrollTag(
 | 
			
		||||
                                                        key: ValueKey(controller
 | 
			
		||||
                                                            .filteredEvents[
 | 
			
		||||
                                                                i - 1]
 | 
			
		||||
                                                            .eventId),
 | 
			
		||||
                                                        background:
 | 
			
		||||
                                                            const Padding(
 | 
			
		||||
                                                          padding: EdgeInsets
 | 
			
		||||
                                                              .symmetric(
 | 
			
		||||
                                                                  horizontal:
 | 
			
		||||
                                                                      12.0),
 | 
			
		||||
                                                          child: Center(
 | 
			
		||||
                                                            child: Icon(Icons
 | 
			
		||||
                                                                .reply_outlined),
 | 
			
		||||
                                                        index: i - 1,
 | 
			
		||||
                                                        controller: controller
 | 
			
		||||
                                                            .scrollController,
 | 
			
		||||
                                                        child: Swipeable(
 | 
			
		||||
                                                          key: ValueKey(controller
 | 
			
		||||
                                                              .filteredEvents[
 | 
			
		||||
                                                                  i - 1]
 | 
			
		||||
                                                              .eventId),
 | 
			
		||||
                                                          background:
 | 
			
		||||
                                                              const Padding(
 | 
			
		||||
                                                            padding: EdgeInsets
 | 
			
		||||
                                                                .symmetric(
 | 
			
		||||
                                                                    horizontal:
 | 
			
		||||
                                                                        12.0),
 | 
			
		||||
                                                            child: Center(
 | 
			
		||||
                                                              child: Icon(Icons
 | 
			
		||||
                                                                  .reply_outlined),
 | 
			
		||||
                                                            ),
 | 
			
		||||
                                                          ),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                        direction:
 | 
			
		||||
                                                            SwipeDirection
 | 
			
		||||
                                                                .endToStart,
 | 
			
		||||
                                                        onSwipe: (direction) =>
 | 
			
		||||
                                                            controller.replyAction(
 | 
			
		||||
                                                                replyTo: controller
 | 
			
		||||
                                                                        .filteredEvents[
 | 
			
		||||
                                                                    i - 1]),
 | 
			
		||||
                                                        child: Message(
 | 
			
		||||
                                                            controller.filteredEvents[
 | 
			
		||||
                                                                i - 1],
 | 
			
		||||
                                                            onInfoTab: controller
 | 
			
		||||
                                                                .showEventInfo,
 | 
			
		||||
                                                            onAvatarTab:
 | 
			
		||||
                                                                (Event event) =>
 | 
			
		||||
                                                                    showModalBottomSheet(
 | 
			
		||||
                                                                      context:
 | 
			
		||||
                                                          direction:
 | 
			
		||||
                                                              SwipeDirection
 | 
			
		||||
                                                                  .endToStart,
 | 
			
		||||
                                                          onSwipe: (direction) =>
 | 
			
		||||
                                                              controller.replyAction(
 | 
			
		||||
                                                                  replyTo: controller
 | 
			
		||||
                                                                          .filteredEvents[
 | 
			
		||||
                                                                      i - 1]),
 | 
			
		||||
                                                          child: Message(
 | 
			
		||||
                                                              controller.filteredEvents[
 | 
			
		||||
                                                                  i - 1],
 | 
			
		||||
                                                              onInfoTab: controller
 | 
			
		||||
                                                                  .showEventInfo,
 | 
			
		||||
                                                              onAvatarTab: (Event event) =>
 | 
			
		||||
                                                                  showModalBottomSheet(
 | 
			
		||||
                                                                    context:
 | 
			
		||||
                                                                        context,
 | 
			
		||||
                                                                    builder: (c) =>
 | 
			
		||||
                                                                        UserBottomSheet(
 | 
			
		||||
                                                                      user: event
 | 
			
		||||
                                                                          .sender,
 | 
			
		||||
                                                                      outerContext:
 | 
			
		||||
                                                                          context,
 | 
			
		||||
                                                                      builder:
 | 
			
		||||
                                                                          (c) =>
 | 
			
		||||
                                                                              UserBottomSheet(
 | 
			
		||||
                                                                        user: event
 | 
			
		||||
                                                                            .sender,
 | 
			
		||||
                                                                        outerContext:
 | 
			
		||||
                                                                            context,
 | 
			
		||||
                                                                        onMention: () => controller
 | 
			
		||||
                                                                            .sendController
 | 
			
		||||
                                                                            .text += '${event.sender.mention} ',
 | 
			
		||||
                                                                      ),
 | 
			
		||||
                                                                      onMention: () => controller
 | 
			
		||||
                                                                          .sendController
 | 
			
		||||
                                                                          .text += '${event.sender.mention} ',
 | 
			
		||||
                                                                    ),
 | 
			
		||||
                                                            unfold: controller
 | 
			
		||||
                                                                .unfold,
 | 
			
		||||
                                                            onSelect: controller
 | 
			
		||||
                                                                .onSelectMessage,
 | 
			
		||||
                                                            scrollToEventId:
 | 
			
		||||
                                                                (String eventId) =>
 | 
			
		||||
                                                                    controller.scrollToEventId(
 | 
			
		||||
                                                                        eventId),
 | 
			
		||||
                                                            longPressSelect:
 | 
			
		||||
                                                                controller
 | 
			
		||||
                                                                    .selectedEvents
 | 
			
		||||
                                                                    .isEmpty,
 | 
			
		||||
                                                            selected: controller
 | 
			
		||||
                                                                .selectedEvents
 | 
			
		||||
                                                                .any((e) => e.eventId == controller.filteredEvents[i - 1].eventId),
 | 
			
		||||
                                                            timeline: controller.timeline!,
 | 
			
		||||
                                                            nextEvent: i < controller.filteredEvents.length ? controller.filteredEvents[i] : null),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                    );
 | 
			
		||||
                                        },
 | 
			
		||||
                                        childCount:
 | 
			
		||||
                                            controller.filteredEvents.length +
 | 
			
		||||
                                                2,
 | 
			
		||||
                                        findChildIndexCallback: (key) =>
 | 
			
		||||
                                            controller.findChildIndexCallback(
 | 
			
		||||
                                                key, thisEventsKeyMap),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    );
 | 
			
		||||
                                  },
 | 
			
		||||
                                )),
 | 
			
		||||
                          ),
 | 
			
		||||
                          if (controller.room!.canSendDefaultMessages &&
 | 
			
		||||
                              controller.room!.membership == Membership.join)
 | 
			
		||||
                            Container(
 | 
			
		||||
                              margin: EdgeInsets.only(
 | 
			
		||||
                                bottom: bottomSheetPadding,
 | 
			
		||||
                                left: bottomSheetPadding,
 | 
			
		||||
                                right: bottomSheetPadding,
 | 
			
		||||
                              ),
 | 
			
		||||
                              constraints: const BoxConstraints(
 | 
			
		||||
                                  maxWidth: FluffyThemes.columnWidth * 2.5),
 | 
			
		||||
                              alignment: Alignment.center,
 | 
			
		||||
                              child: Material(
 | 
			
		||||
                                borderRadius: const BorderRadius.only(
 | 
			
		||||
                                  bottomLeft:
 | 
			
		||||
                                      Radius.circular(AppConfig.borderRadius),
 | 
			
		||||
                                  bottomRight:
 | 
			
		||||
                                      Radius.circular(AppConfig.borderRadius),
 | 
			
		||||
                                ),
 | 
			
		||||
                                elevation: 6,
 | 
			
		||||
                                shadowColor: Theme.of(context)
 | 
			
		||||
                                    .secondaryHeaderColor
 | 
			
		||||
                                    .withAlpha(100),
 | 
			
		||||
                                clipBehavior: Clip.hardEdge,
 | 
			
		||||
                                color: Theme.of(context)
 | 
			
		||||
                                    .appBarTheme
 | 
			
		||||
                                    .backgroundColor,
 | 
			
		||||
                                child: Column(
 | 
			
		||||
                                  mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const ConnectionStatusHeader(),
 | 
			
		||||
                                    ReactionsPicker(controller),
 | 
			
		||||
                                    ReplyDisplay(controller),
 | 
			
		||||
                                    ChatInputRow(controller),
 | 
			
		||||
                                    ChatEmojiPicker(controller),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                                                                  ),
 | 
			
		||||
                                                              unfold: controller
 | 
			
		||||
                                                                  .unfold,
 | 
			
		||||
                                                              onSelect: controller
 | 
			
		||||
                                                                  .onSelectMessage,
 | 
			
		||||
                                                              scrollToEventId:
 | 
			
		||||
                                                                  (String eventId) =>
 | 
			
		||||
                                                                      controller.scrollToEventId(
 | 
			
		||||
                                                                          eventId),
 | 
			
		||||
                                                              longPressSelect:
 | 
			
		||||
                                                                  controller
 | 
			
		||||
                                                                      .selectedEvents
 | 
			
		||||
                                                                      .isEmpty,
 | 
			
		||||
                                                              selected: controller
 | 
			
		||||
                                                                  .selectedEvents
 | 
			
		||||
                                                                  .any((e) => e.eventId == controller.filteredEvents[i - 1].eventId),
 | 
			
		||||
                                                              timeline: controller.timeline!,
 | 
			
		||||
                                                              nextEvent: i < controller.filteredEvents.length ? controller.filteredEvents[i] : null),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                      );
 | 
			
		||||
                                          },
 | 
			
		||||
                                          childCount:
 | 
			
		||||
                                              controller.filteredEvents.length +
 | 
			
		||||
                                                  2,
 | 
			
		||||
                                          findChildIndexCallback: (key) =>
 | 
			
		||||
                                              controller.findChildIndexCallback(
 | 
			
		||||
                                                  key, thisEventsKeyMap),
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      );
 | 
			
		||||
                                    },
 | 
			
		||||
                                  )),
 | 
			
		||||
                            ),
 | 
			
		||||
                        ],
 | 
			
		||||
                      ),
 | 
			
		||||
                    ),
 | 
			
		||||
                    if (controller.dragging)
 | 
			
		||||
                      Container(
 | 
			
		||||
                        color: Theme.of(context)
 | 
			
		||||
                            .scaffoldBackgroundColor
 | 
			
		||||
                            .withOpacity(0.9),
 | 
			
		||||
                        alignment: Alignment.center,
 | 
			
		||||
                        child: const Icon(
 | 
			
		||||
                          Icons.upload_outlined,
 | 
			
		||||
                          size: 100,
 | 
			
		||||
                            if (controller.room!.canSendDefaultMessages &&
 | 
			
		||||
                                controller.room!.membership == Membership.join)
 | 
			
		||||
                              Container(
 | 
			
		||||
                                margin: EdgeInsets.only(
 | 
			
		||||
                                  bottom: bottomSheetPadding,
 | 
			
		||||
                                  left: bottomSheetPadding,
 | 
			
		||||
                                  right: bottomSheetPadding,
 | 
			
		||||
                                ),
 | 
			
		||||
                                constraints: const BoxConstraints(
 | 
			
		||||
                                    maxWidth: FluffyThemes.columnWidth * 2.5),
 | 
			
		||||
                                alignment: Alignment.center,
 | 
			
		||||
                                child: Material(
 | 
			
		||||
                                  borderRadius: const BorderRadius.only(
 | 
			
		||||
                                    bottomLeft:
 | 
			
		||||
                                        Radius.circular(AppConfig.borderRadius),
 | 
			
		||||
                                    bottomRight:
 | 
			
		||||
                                        Radius.circular(AppConfig.borderRadius),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                  elevation: 6,
 | 
			
		||||
                                  shadowColor: Theme.of(context)
 | 
			
		||||
                                      .secondaryHeaderColor
 | 
			
		||||
                                      .withAlpha(100),
 | 
			
		||||
                                  clipBehavior: Clip.hardEdge,
 | 
			
		||||
                                  color: Theme.of(context)
 | 
			
		||||
                                      .appBarTheme
 | 
			
		||||
                                      .backgroundColor,
 | 
			
		||||
                                  child: Column(
 | 
			
		||||
                                    mainAxisSize: MainAxisSize.min,
 | 
			
		||||
                                    children: [
 | 
			
		||||
                                      const ConnectionStatusHeader(),
 | 
			
		||||
                                      ReactionsPicker(controller),
 | 
			
		||||
                                      ReplyDisplay(controller),
 | 
			
		||||
                                      ChatInputRow(controller),
 | 
			
		||||
                                      ChatEmojiPicker(controller),
 | 
			
		||||
                                    ],
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                  ],
 | 
			
		||||
                      if (controller.dragging)
 | 
			
		||||
                        Container(
 | 
			
		||||
                          color: Theme.of(context)
 | 
			
		||||
                              .scaffoldBackgroundColor
 | 
			
		||||
                              .withOpacity(0.9),
 | 
			
		||||
                          alignment: Alignment.center,
 | 
			
		||||
                          child: const Icon(
 | 
			
		||||
                            Icons.upload_outlined,
 | 
			
		||||
                            size: 100,
 | 
			
		||||
                          ),
 | 
			
		||||
                        ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
              );
 | 
			
		||||
            },
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user