design: Floating input bar

This commit is contained in:
Krille Fear 2021-11-06 11:18:32 +01:00
parent 0fe32596de
commit 66cae6cc85
1 changed files with 248 additions and 232 deletions

View File

@ -1,5 +1,6 @@
import 'dart:ui'; import 'dart:ui';
import 'package:fluffychat/config/themes.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@ -505,254 +506,269 @@ class ChatView extends StatelessWidget {
), ),
), ),
), ),
const Divider(height: 1), if (controller.showScrollDownButton)
const Divider(
height: 1,
),
if (controller.room.canSendDefaultMessages && if (controller.room.canSendDefaultMessages &&
controller.room.membership == Membership.join && controller.room.membership == Membership.join &&
!controller.showEmojiPicker) !controller.showEmojiPicker)
Container( Padding(
decoration: BoxDecoration( padding: EdgeInsets.all(
FluffyThemes.isColumnMode(context) ? 16.0 : 8.0),
child: Material(
borderRadius:
BorderRadius.circular(AppConfig.borderRadius),
elevation: 4,
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
), child: Row(
child: Row( crossAxisAlignment: CrossAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: controller.selectMode
children: controller.selectMode ? <Widget>[
? <Widget>[ SizedBox(
SizedBox( height: 56,
height: 56, child: TextButton(
child: TextButton( onPressed:
onPressed: controller.forwardEventsAction, controller.forwardEventsAction,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
const Icon(Icons const Icon(Icons
.keyboard_arrow_left_outlined), .keyboard_arrow_left_outlined),
Text(L10n.of(context).forward), Text(L10n.of(context).forward),
],
),
),
),
controller.selectedEvents.length == 1
? controller.selectedEvents.first
.getDisplayEvent(
controller.timeline)
.status
.isSent
? SizedBox(
height: 56,
child: TextButton(
onPressed:
controller.replyAction,
child: Row(
children: <Widget>[
Text(L10n.of(context)
.reply),
const Icon(Icons
.keyboard_arrow_right),
],
),
),
)
: SizedBox(
height: 56,
child: TextButton(
onPressed: controller
.sendAgainAction,
child: Row(
children: <Widget>[
Text(L10n.of(context)
.tryToSendAgain),
const SizedBox(width: 4),
const Icon(
Icons.send_outlined,
size: 16),
],
),
),
)
: Container(),
]
: <Widget>[
AnimatedContainer(
duration:
const Duration(milliseconds: 200),
height: 56,
width:
controller.inputText.isEmpty ? 56 : 0,
alignment: Alignment.center,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
child: PopupMenuButton<String>(
icon: const Icon(Icons.add_outlined),
onSelected: controller
.onAddPopupMenuButtonSelected,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'file',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
child: Icon(
Icons.attachment_outlined),
),
title: Text(
L10n.of(context).sendFile),
contentPadding:
const EdgeInsets.all(0),
),
),
PopupMenuItem<String>(
value: 'image',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
child:
Icon(Icons.image_outlined),
),
title: Text(
L10n.of(context).sendImage),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'camera',
child: ListTile(
leading: const CircleAvatar(
backgroundColor:
Colors.purple,
foregroundColor: Colors.white,
child: Icon(Icons
.camera_alt_outlined),
),
title: Text(L10n.of(context)
.openCamera),
contentPadding:
const EdgeInsets.all(0),
),
),
if (controller.room
.getImagePacks(
ImagePackUsage.sticker)
.isNotEmpty)
PopupMenuItem<String>(
value: 'sticker',
child: ListTile(
leading: const CircleAvatar(
backgroundColor:
Colors.orange,
foregroundColor: Colors.white,
child: Icon(Icons
.emoji_emotions_outlined),
),
title: Text(L10n.of(context)
.sendSticker),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'voice',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Icon(
Icons.mic_none_outlined),
),
title: Text(L10n.of(context)
.voiceMessage),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'location',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.brown,
foregroundColor: Colors.white,
child: Icon(
Icons.gps_fixed_outlined),
),
title: Text(L10n.of(context)
.shareLocation),
contentPadding:
const EdgeInsets.all(0),
),
),
], ],
), ),
), ),
),
controller.selectedEvents.length == 1
? controller.selectedEvents.first
.getDisplayEvent(
controller.timeline)
.status
.isSent
? SizedBox(
height: 56,
child: TextButton(
onPressed:
controller.replyAction,
child: Row(
children: <Widget>[
Text(
L10n.of(context).reply),
const Icon(Icons
.keyboard_arrow_right),
],
),
),
)
: SizedBox(
height: 56,
child: TextButton(
onPressed:
controller.sendAgainAction,
child: Row(
children: <Widget>[
Text(L10n.of(context)
.tryToSendAgain),
const SizedBox(width: 4),
const Icon(
Icons.send_outlined,
size: 16),
],
),
),
)
: Container(),
]
: <Widget>[
AnimatedContainer(
duration: const Duration(milliseconds: 200),
height: 56,
width:
controller.inputText.isEmpty ? 56 : 0,
alignment: Alignment.center,
clipBehavior: Clip.hardEdge,
decoration: const BoxDecoration(),
child: PopupMenuButton<String>(
icon: const Icon(Icons.add_outlined),
onSelected: controller
.onAddPopupMenuButtonSelected,
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<String>>[
PopupMenuItem<String>(
value: 'file',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.green,
foregroundColor: Colors.white,
child: Icon(
Icons.attachment_outlined),
),
title:
Text(L10n.of(context).sendFile),
contentPadding:
const EdgeInsets.all(0),
),
),
PopupMenuItem<String>(
value: 'image',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
child: Icon(Icons.image_outlined),
),
title: Text(
L10n.of(context).sendImage),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'camera',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.purple,
foregroundColor: Colors.white,
child: Icon(
Icons.camera_alt_outlined),
),
title: Text(
L10n.of(context).openCamera),
contentPadding:
const EdgeInsets.all(0),
),
),
if (controller.room
.getImagePacks(
ImagePackUsage.sticker)
.isNotEmpty)
PopupMenuItem<String>(
value: 'sticker',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.orange,
foregroundColor: Colors.white,
child: Icon(Icons
.emoji_emotions_outlined),
),
title: Text(
L10n.of(context).sendSticker),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'voice',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.red,
foregroundColor: Colors.white,
child: Icon(
Icons.mic_none_outlined),
),
title: Text(L10n.of(context)
.voiceMessage),
contentPadding:
const EdgeInsets.all(0),
),
),
if (PlatformInfos.isMobile)
PopupMenuItem<String>(
value: 'location',
child: ListTile(
leading: const CircleAvatar(
backgroundColor: Colors.brown,
foregroundColor: Colors.white,
child: Icon(
Icons.gps_fixed_outlined),
),
title: Text(L10n.of(context)
.shareLocation),
contentPadding:
const EdgeInsets.all(0),
),
),
],
),
),
Container(
height: 56,
alignment: Alignment.center,
child: EncryptionButton(controller.room),
),
if (controller.matrix.isMultiAccount &&
controller.matrix.hasComplexBundles &&
controller.matrix.currentBundle.length >
1)
Container( Container(
height: 56, height: 56,
alignment: Alignment.center, alignment: Alignment.center,
child: _ChatAccountPicker(controller), child: EncryptionButton(controller.room),
), ),
Expanded( if (controller.matrix.isMultiAccount &&
child: Padding( controller.matrix.hasComplexBundles &&
padding: const EdgeInsets.symmetric( controller.matrix.currentBundle.length >
vertical: 4.0), 1)
child: InputBar( Container(
room: controller.room, height: 56,
minLines: 1, alignment: Alignment.center,
maxLines: 8, child: _ChatAccountPicker(controller),
autofocus: !PlatformInfos.isMobile, ),
keyboardType: TextInputType.multiline, Expanded(
textInputAction: AppConfig.sendOnEnter child: Padding(
? TextInputAction.send padding: const EdgeInsets.symmetric(
: null, vertical: 4.0),
onSubmitted: child: InputBar(
controller.onInputBarSubmitted, room: controller.room,
focusNode: controller.inputFocus, minLines: 1,
controller: controller.sendController, maxLines: 8,
decoration: InputDecoration( autofocus: !PlatformInfos.isMobile,
hintText: keyboardType: TextInputType.multiline,
L10n.of(context).writeAMessage, textInputAction: AppConfig.sendOnEnter
hintMaxLines: 1, ? TextInputAction.send
border: InputBorder.none, : null,
enabledBorder: InputBorder.none, onSubmitted:
filled: false, controller.onInputBarSubmitted,
focusNode: controller.inputFocus,
controller: controller.sendController,
decoration: InputDecoration(
hintText:
L10n.of(context).writeAMessage,
hintMaxLines: 1,
border: InputBorder.none,
enabledBorder: InputBorder.none,
filled: false,
),
onChanged:
controller.onInputBarChanged,
), ),
onChanged: controller.onInputBarChanged,
), ),
), ),
), if (PlatformInfos.isMobile &&
if (PlatformInfos.isMobile && controller.inputText.isEmpty)
controller.inputText.isEmpty) Container(
Container( height: 56,
height: 56, alignment: Alignment.center,
alignment: Alignment.center, child: IconButton(
child: IconButton( tooltip:
tooltip: L10n.of(context).voiceMessage, L10n.of(context).voiceMessage,
icon: icon: const Icon(
const Icon(Icons.mic_none_outlined), Icons.mic_none_outlined),
onPressed: onPressed:
controller.voiceMessageAction, controller.voiceMessageAction,
),
), ),
), if (!PlatformInfos.isMobile ||
if (!PlatformInfos.isMobile || controller.inputText.isNotEmpty)
controller.inputText.isNotEmpty) Container(
Container( height: 56,
height: 56, alignment: Alignment.center,
alignment: Alignment.center, child: IconButton(
child: IconButton( icon: const Icon(Icons.send_outlined),
icon: const Icon(Icons.send_outlined), onPressed: controller.send,
onPressed: controller.send, tooltip: L10n.of(context).send,
tooltip: L10n.of(context).send, ),
), ),
), ],
], ),
), ),
), ),
AnimatedContainer( AnimatedContainer(