mirror of
https://gitlab.com/famedly/fluffychat.git
synced 2025-01-25 19:44:17 +01:00
fix: minor issues in room list
- allow to discard focus of search field - properly circle the search field's progress indicator - always keep search sections visible in order to workaround annoying behavior: When quickly searching for a chat and one is fast at clicking on a room, it often happens that server side results just drop in at this moment and one clicks at the wrong item -> with a static height as now set, this no longer happens. Signed-off-by: TheOneWithTheBraid <the-one@with-the-braid.cf>
This commit is contained in:
parent
f9e4b9356a
commit
0a4f7c9d26
@ -1450,6 +1450,7 @@
|
|||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"noSearchResult": "No matching search results.",
|
||||||
"moderator": "Moderator",
|
"moderator": "Moderator",
|
||||||
"@moderator": {
|
"@moderator": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -55,6 +55,7 @@ enum ActiveFilter {
|
|||||||
|
|
||||||
class ChatList extends StatefulWidget {
|
class ChatList extends StatefulWidget {
|
||||||
static BuildContext? contextForVoip;
|
static BuildContext? contextForVoip;
|
||||||
|
|
||||||
const ChatList({Key? key}) : super(key: key);
|
const ChatList({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -235,12 +236,15 @@ class ChatListController extends State<ChatList>
|
|||||||
_coolDown = Timer(const Duration(milliseconds: 500), _search);
|
_coolDown = Timer(const Duration(milliseconds: 500), _search);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancelSearch() => setState(() {
|
void cancelSearch() {
|
||||||
searchController.clear();
|
setState(() {
|
||||||
isSearchMode = false;
|
searchController.clear();
|
||||||
roomSearchResult = userSearchResult = null;
|
isSearchMode = false;
|
||||||
isSearching = false;
|
roomSearchResult = userSearchResult = null;
|
||||||
});
|
isSearching = false;
|
||||||
|
});
|
||||||
|
FocusManager.instance.primaryFocus?.unfocus();
|
||||||
|
}
|
||||||
|
|
||||||
bool isTorBrowser = false;
|
bool isTorBrowser = false;
|
||||||
|
|
||||||
|
@ -73,75 +73,81 @@ class ChatListViewBody extends StatelessWidget {
|
|||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (roomSearchResult != null) ...[
|
if (controller.isSearchMode) ...[
|
||||||
SearchTitle(
|
SearchTitle(
|
||||||
title: L10n.of(context)!.publicRooms,
|
title: L10n.of(context)!.publicRooms,
|
||||||
icon: const Icon(Icons.explore_outlined),
|
icon: const Icon(Icons.explore_outlined),
|
||||||
),
|
),
|
||||||
AnimatedContainer(
|
SizedBox(
|
||||||
height: roomSearchResult.chunk.isEmpty ? 0 : 106,
|
height: 106,
|
||||||
duration: const Duration(milliseconds: 250),
|
child: roomSearchResult == null ||
|
||||||
clipBehavior: Clip.hardEdge,
|
roomSearchResult.chunk.isEmpty
|
||||||
decoration: const BoxDecoration(),
|
? Center(
|
||||||
child: ListView.builder(
|
child:
|
||||||
scrollDirection: Axis.horizontal,
|
Text(L10n.of(context)!.noSearchResult),
|
||||||
itemCount: roomSearchResult.chunk.length,
|
)
|
||||||
itemBuilder: (context, i) => _SearchItem(
|
: ListView.builder(
|
||||||
title: roomSearchResult.chunk[i].name ??
|
scrollDirection: Axis.horizontal,
|
||||||
roomSearchResult
|
itemCount: roomSearchResult.chunk.length,
|
||||||
.chunk[i].canonicalAlias?.localpart ??
|
itemBuilder: (context, i) => _SearchItem(
|
||||||
L10n.of(context)!.group,
|
title: roomSearchResult.chunk[i].name ??
|
||||||
avatar: roomSearchResult.chunk[i].avatarUrl,
|
roomSearchResult.chunk[i]
|
||||||
onPressed: () => showModalBottomSheet(
|
.canonicalAlias?.localpart ??
|
||||||
context: context,
|
L10n.of(context)!.group,
|
||||||
builder: (c) => PublicRoomBottomSheet(
|
avatar:
|
||||||
roomAlias: roomSearchResult
|
roomSearchResult.chunk[i].avatarUrl,
|
||||||
.chunk[i].canonicalAlias ??
|
onPressed: () => showModalBottomSheet(
|
||||||
roomSearchResult.chunk[i].roomId,
|
context: context,
|
||||||
outerContext: context,
|
builder: (c) => PublicRoomBottomSheet(
|
||||||
chunk: roomSearchResult.chunk[i],
|
roomAlias: roomSearchResult
|
||||||
|
.chunk[i].canonicalAlias ??
|
||||||
|
roomSearchResult.chunk[i].roomId,
|
||||||
|
outerContext: context,
|
||||||
|
chunk: roomSearchResult.chunk[i],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
if (userSearchResult != null) ...[
|
|
||||||
SearchTitle(
|
SearchTitle(
|
||||||
title: L10n.of(context)!.users,
|
title: L10n.of(context)!.users,
|
||||||
icon: const Icon(Icons.group_outlined),
|
icon: const Icon(Icons.group_outlined),
|
||||||
),
|
),
|
||||||
AnimatedContainer(
|
SizedBox(
|
||||||
height: userSearchResult.results.isEmpty ? 0 : 106,
|
height: 106,
|
||||||
duration: const Duration(milliseconds: 250),
|
child: userSearchResult == null ||
|
||||||
clipBehavior: Clip.hardEdge,
|
userSearchResult.results.isEmpty
|
||||||
decoration: const BoxDecoration(),
|
? Center(
|
||||||
child: ListView.builder(
|
child:
|
||||||
scrollDirection: Axis.horizontal,
|
Text(L10n.of(context)!.noSearchResult),
|
||||||
itemCount: userSearchResult.results.length,
|
)
|
||||||
itemBuilder: (context, i) => _SearchItem(
|
: ListView.builder(
|
||||||
title:
|
scrollDirection: Axis.horizontal,
|
||||||
userSearchResult.results[i].displayName ??
|
itemCount: userSearchResult.results.length,
|
||||||
userSearchResult
|
itemBuilder: (context, i) => _SearchItem(
|
||||||
.results[i].userId.localpart ??
|
title: userSearchResult
|
||||||
L10n.of(context)!.unknownDevice,
|
.results[i].displayName ??
|
||||||
avatar: userSearchResult.results[i].avatarUrl,
|
userSearchResult
|
||||||
onPressed: () => showModalBottomSheet(
|
.results[i].userId.localpart ??
|
||||||
context: context,
|
L10n.of(context)!.unknownDevice,
|
||||||
builder: (c) => ProfileBottomSheet(
|
avatar:
|
||||||
userId: userSearchResult.results[i].userId,
|
userSearchResult.results[i].avatarUrl,
|
||||||
outerContext: context,
|
onPressed: () => showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (c) => ProfileBottomSheet(
|
||||||
|
userId: userSearchResult
|
||||||
|
.results[i].userId,
|
||||||
|
outerContext: context,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
if (controller.isSearchMode)
|
|
||||||
SearchTitle(
|
SearchTitle(
|
||||||
title: L10n.of(context)!.stories,
|
title: L10n.of(context)!.stories,
|
||||||
icon: const Icon(Icons.camera_alt_outlined),
|
icon: const Icon(Icons.camera_alt_outlined),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
if (displayStoriesHeader)
|
if (displayStoriesHeader)
|
||||||
StoriesHeader(
|
StoriesHeader(
|
||||||
key: const Key('stories_header'),
|
key: const Key('stories_header'),
|
||||||
@ -319,6 +325,7 @@ class _SearchItem extends StatelessWidget {
|
|||||||
title,
|
title,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
|
@ -67,8 +67,18 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
),
|
),
|
||||||
suffixIcon: controller.isSearchMode
|
suffixIcon: controller.isSearchMode
|
||||||
? controller.isSearching
|
? controller.isSearching
|
||||||
? const CircularProgressIndicator.adaptive(
|
? const Align(
|
||||||
strokeWidth: 2,
|
alignment: Alignment.centerRight,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.symmetric(
|
||||||
|
vertical: 8.0, horizontal: 12),
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: 24,
|
||||||
|
child: CircularProgressIndicator.adaptive(
|
||||||
|
strokeWidth: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: TextButton(
|
: TextButton(
|
||||||
onPressed: controller.setServer,
|
onPressed: controller.setServer,
|
||||||
|
@ -222,32 +222,37 @@ class ChatListView extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Scaffold(
|
child: GestureDetector(
|
||||||
appBar: ChatListHeader(controller: controller),
|
onTap: FocusManager.instance.primaryFocus?.unfocus,
|
||||||
body: ChatListViewBody(controller),
|
excludeFromSemantics: true,
|
||||||
bottomNavigationBar: controller.displayNavigationBar
|
behavior: HitTestBehavior.translucent,
|
||||||
? NavigationBar(
|
child: Scaffold(
|
||||||
height: 64,
|
appBar: ChatListHeader(controller: controller),
|
||||||
selectedIndex: controller.selectedIndex,
|
body: ChatListViewBody(controller),
|
||||||
onDestinationSelected:
|
bottomNavigationBar: controller.displayNavigationBar
|
||||||
controller.onDestinationSelected,
|
? NavigationBar(
|
||||||
destinations: getNavigationDestinations(context),
|
height: 64,
|
||||||
)
|
selectedIndex: controller.selectedIndex,
|
||||||
: null,
|
onDestinationSelected:
|
||||||
floatingActionButton: controller.filteredRooms.isNotEmpty &&
|
controller.onDestinationSelected,
|
||||||
selectMode == SelectMode.normal
|
destinations: getNavigationDestinations(context),
|
||||||
? KeyBoardShortcuts(
|
)
|
||||||
keysToPress: {
|
: null,
|
||||||
LogicalKeyboardKey.controlLeft,
|
floatingActionButton: controller.filteredRooms.isNotEmpty &&
|
||||||
LogicalKeyboardKey.keyN
|
selectMode == SelectMode.normal
|
||||||
},
|
? KeyBoardShortcuts(
|
||||||
onKeysPressed: () =>
|
keysToPress: {
|
||||||
VRouter.of(context).to('/newprivatechat'),
|
LogicalKeyboardKey.controlLeft,
|
||||||
helpLabel: L10n.of(context)!.newChat,
|
LogicalKeyboardKey.keyN
|
||||||
child: StartChatFloatingActionButton(
|
},
|
||||||
controller: controller),
|
onKeysPressed: () =>
|
||||||
)
|
VRouter.of(context).to('/newprivatechat'),
|
||||||
: null,
|
helpLabel: L10n.of(context)!.newChat,
|
||||||
|
child: StartChatFloatingActionButton(
|
||||||
|
controller: controller),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -19,6 +19,7 @@ enum ContextualRoomAction {
|
|||||||
|
|
||||||
class StoriesHeader extends StatelessWidget {
|
class StoriesHeader extends StatelessWidget {
|
||||||
final String filter;
|
final String filter;
|
||||||
|
|
||||||
const StoriesHeader({required this.filter, Key? key}) : super(key: key);
|
const StoriesHeader({required this.filter, Key? key}) : super(key: key);
|
||||||
|
|
||||||
void _addToStoryAction(BuildContext context) =>
|
void _addToStoryAction(BuildContext context) =>
|
||||||
@ -100,11 +101,6 @@ class StoriesHeader extends StatelessWidget {
|
|||||||
onTap: () => _addToStoryAction(context),
|
onTap: () => _addToStoryAction(context),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (client.storiesRooms.isEmpty ||
|
|
||||||
!client.storiesRooms.any((room) =>
|
|
||||||
room.displayname.toLowerCase().contains(filter.toLowerCase()))) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
final ownStoryRoom = client.storiesRooms
|
final ownStoryRoom = client.storiesRooms
|
||||||
.firstWhereOrNull((r) => r.creatorId == client.userID);
|
.firstWhereOrNull((r) => r.creatorId == client.userID);
|
||||||
final stories = [
|
final stories = [
|
||||||
|
Loading…
Reference in New Issue
Block a user