Add settings for swipe actions
This commit is contained in:
parent
23936fa7f1
commit
c97cb326f8
|
@ -71,6 +71,9 @@ class MatrixState extends State<Matrix> {
|
||||||
File wallpaper;
|
File wallpaper;
|
||||||
bool renderHtml = false;
|
bool renderHtml = false;
|
||||||
|
|
||||||
|
String swipeToEndAction;
|
||||||
|
String swipeToStartAction = 'reply';
|
||||||
|
|
||||||
String jitsiInstance = 'https://meet.jit.si/';
|
String jitsiInstance = 'https://meet.jit.si/';
|
||||||
|
|
||||||
void clean() async {
|
void clean() async {
|
||||||
|
@ -283,6 +286,16 @@ class MatrixState extends State<Matrix> {
|
||||||
store.getItem('chat.fluffy.renderHtml').then((final render) async {
|
store.getItem('chat.fluffy.renderHtml').then((final render) async {
|
||||||
renderHtml = render == '1';
|
renderHtml = render == '1';
|
||||||
});
|
});
|
||||||
|
store
|
||||||
|
.getItem('dev.inex.furrychat.swipeToEndAction')
|
||||||
|
.then((final action) async {
|
||||||
|
swipeToEndAction = action ?? swipeToEndAction;
|
||||||
|
});
|
||||||
|
store
|
||||||
|
.getItem('dev.inex.furrychat.swipeToStartAction')
|
||||||
|
.then((final action) async {
|
||||||
|
swipeToStartAction = action ?? swipeToStartAction;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true);
|
onFocusSub = html.window.onFocus.listen((_) => webHasFocus = true);
|
||||||
|
|
|
@ -514,6 +514,11 @@
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"edit": "Edit",
|
||||||
|
"@edit": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"editDisplayname": "Edit displayname",
|
"editDisplayname": "Edit displayname",
|
||||||
"@editDisplayname": {
|
"@editDisplayname": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
@ -1439,6 +1444,16 @@
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"placeholders": {}
|
"placeholders": {}
|
||||||
},
|
},
|
||||||
|
"swipeToEndAction": "Swipe to right action",
|
||||||
|
"@swipeToEndAction": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
|
"swipeToStartAction": "Swipe to left action",
|
||||||
|
"@swipeToStartAction": {
|
||||||
|
"type": "text",
|
||||||
|
"placeholders": {}
|
||||||
|
},
|
||||||
"donate": "Donate",
|
"donate": "Donate",
|
||||||
"@donate": {
|
"@donate": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|
|
@ -317,8 +317,10 @@ class _ChatState extends State<_Chat> {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void forwardEventsAction(BuildContext context) async {
|
void forwardEventsAction(BuildContext context, {Event event}) async {
|
||||||
if (selectedEvents.length == 1) {
|
if (event != null) {
|
||||||
|
Matrix.of(context).shareContent = event.content;
|
||||||
|
} else if (selectedEvents.length == 1) {
|
||||||
Matrix.of(context).shareContent = selectedEvents.first.content;
|
Matrix.of(context).shareContent = selectedEvents.first.content;
|
||||||
} else {
|
} else {
|
||||||
Matrix.of(context).shareContent = {
|
Matrix.of(context).shareContent = {
|
||||||
|
@ -412,6 +414,128 @@ class _ChatState extends State<_Chat> {
|
||||||
e.type != 'm.reaction')
|
e.type != 'm.reaction')
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
|
SwipeDirection _getSwipeDirection(Event event) {
|
||||||
|
var swipeToEndAction = Matrix.of(context).swipeToEndAction;
|
||||||
|
var swipeToStartAction = Matrix.of(context).swipeToStartAction;
|
||||||
|
var client = Matrix.of(context).client;
|
||||||
|
if (event.senderId != client.userID && swipeToEndAction == 'edit') {
|
||||||
|
swipeToEndAction = null;
|
||||||
|
}
|
||||||
|
if (event.senderId != client.userID && swipeToStartAction == 'edit') {
|
||||||
|
swipeToStartAction = null;
|
||||||
|
}
|
||||||
|
if (swipeToEndAction != null && swipeToStartAction != null) {
|
||||||
|
return SwipeDirection.horizontal;
|
||||||
|
}
|
||||||
|
if (swipeToEndAction != null) {
|
||||||
|
return SwipeDirection.startToEnd;
|
||||||
|
}
|
||||||
|
if (swipeToStartAction != null) {
|
||||||
|
return SwipeDirection.endToStart;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _getSwipeBackground(Event event, {bool isSecondary = false}) {
|
||||||
|
var alignToRight, action;
|
||||||
|
if (_getSwipeDirection(event) == SwipeDirection.horizontal) {
|
||||||
|
if (isSecondary) {
|
||||||
|
alignToRight = true;
|
||||||
|
action = Matrix.of(context).swipeToStartAction;
|
||||||
|
} else {
|
||||||
|
alignToRight = false;
|
||||||
|
action = Matrix.of(context).swipeToEndAction;
|
||||||
|
}
|
||||||
|
} else if (isSecondary) {
|
||||||
|
return null;
|
||||||
|
} else if (_getSwipeDirection(event) == SwipeDirection.endToStart) {
|
||||||
|
alignToRight = true;
|
||||||
|
action = Matrix.of(context).swipeToStartAction;
|
||||||
|
} else {
|
||||||
|
alignToRight = false;
|
||||||
|
action = Matrix.of(context).swipeToStartAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'reply':
|
||||||
|
return Container(
|
||||||
|
color: Theme.of(context).primaryColor.withAlpha(100),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
alignToRight ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.reply_outlined),
|
||||||
|
SizedBox(width: 2.0),
|
||||||
|
Text(L10n.of(context).reply)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case 'forward':
|
||||||
|
return Container(
|
||||||
|
color: Theme.of(context).primaryColor.withAlpha(100),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
alignToRight ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.forward_outlined),
|
||||||
|
SizedBox(width: 2.0),
|
||||||
|
Text(L10n.of(context).forward)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
case 'edit':
|
||||||
|
return Container(
|
||||||
|
color: Theme.of(context).primaryColor.withAlpha(100),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment:
|
||||||
|
alignToRight ? MainAxisAlignment.end : MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.edit_outlined),
|
||||||
|
SizedBox(width: 2.0),
|
||||||
|
Text(L10n.of(context).edit)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return Container(
|
||||||
|
color: Theme.of(context).primaryColor.withAlpha(100),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleSwipe(SwipeDirection direction, Event event) {
|
||||||
|
var action;
|
||||||
|
if (direction == SwipeDirection.endToStart) {
|
||||||
|
action = Matrix.of(context).swipeToStartAction;
|
||||||
|
} else {
|
||||||
|
action = Matrix.of(context).swipeToEndAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case 'reply':
|
||||||
|
replyAction(replyTo: event);
|
||||||
|
break;
|
||||||
|
case 'forward':
|
||||||
|
forwardEventsAction(context, event: event);
|
||||||
|
break;
|
||||||
|
case 'edit':
|
||||||
|
setState(() {
|
||||||
|
editEvent = event;
|
||||||
|
sendController.text = editEvent
|
||||||
|
.getDisplayEvent(timeline)
|
||||||
|
.getLocalizedBody(MatrixLocals(L10n.of(context)),
|
||||||
|
withSenderNamePrefix: false, hideReply: true);
|
||||||
|
selectedEvents.clear();
|
||||||
|
});
|
||||||
|
inputFocus.requestFocus();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
matrix = Matrix.of(context);
|
matrix = Matrix.of(context);
|
||||||
|
@ -672,26 +796,16 @@ class _ChatState extends State<_Chat> {
|
||||||
child: Swipeable(
|
child: Swipeable(
|
||||||
key: ValueKey(
|
key: ValueKey(
|
||||||
filteredEvents[i - 1].eventId),
|
filteredEvents[i - 1].eventId),
|
||||||
background: Container(
|
background: _getSwipeBackground(
|
||||||
color: Theme.of(context)
|
filteredEvents[i - 1]),
|
||||||
.primaryColor
|
secondaryBackground:
|
||||||
.withAlpha(100),
|
_getSwipeBackground(
|
||||||
padding: EdgeInsets.symmetric(
|
filteredEvents[i - 1],
|
||||||
horizontal: 12.0),
|
isSecondary: true),
|
||||||
alignment: Alignment.centerLeft,
|
direction: _getSwipeDirection(
|
||||||
child: Row(
|
filteredEvents[i - 1]),
|
||||||
children: [
|
onSwipe: (direction) => _handleSwipe(
|
||||||
Icon(Icons.reply),
|
direction, filteredEvents[i - 1]),
|
||||||
SizedBox(width: 2.0),
|
|
||||||
Text(L10n.of(context).reply)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
direction: SwipeDirection.startToEnd,
|
|
||||||
onSwipe: (direction) {
|
|
||||||
replyAction(
|
|
||||||
replyTo: filteredEvents[i - 1]);
|
|
||||||
},
|
|
||||||
child: Message(filteredEvents[i - 1],
|
child: Message(filteredEvents[i - 1],
|
||||||
onAvatarTab: (Event event) {
|
onAvatarTab: (Event event) {
|
||||||
sendController.text +=
|
sendController.text +=
|
||||||
|
|
|
@ -22,6 +22,74 @@ class ChatSettings extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChatSettingsState extends State<ChatSettings> {
|
class _ChatSettingsState extends State<ChatSettings> {
|
||||||
|
String _getActionDescription(String action) {
|
||||||
|
switch (action) {
|
||||||
|
case 'reply':
|
||||||
|
return L10n.of(context).reply;
|
||||||
|
case 'forward':
|
||||||
|
return L10n.of(context).forward;
|
||||||
|
case 'edit':
|
||||||
|
return L10n.of(context).edit;
|
||||||
|
default:
|
||||||
|
return L10n.of(context).none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _changeSwipeAction(bool isToEnd, String action) async {
|
||||||
|
if (isToEnd) {
|
||||||
|
Matrix.of(context).swipeToEndAction = action;
|
||||||
|
await Matrix.of(context)
|
||||||
|
.store
|
||||||
|
.setItem('chat.fluffy.swipeToEndAction', action);
|
||||||
|
setState(() => null);
|
||||||
|
} else {
|
||||||
|
Matrix.of(context).swipeToStartAction = action;
|
||||||
|
await Matrix.of(context)
|
||||||
|
.store
|
||||||
|
.setItem('chat.fluffy.swipeToStartAction', action);
|
||||||
|
setState(() => null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _swipeActionChooser(BuildContext context, bool isToEnd) {
|
||||||
|
return ListView(
|
||||||
|
children: [
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).none),
|
||||||
|
leading: Icon(Icons.clear_outlined),
|
||||||
|
onTap: () {
|
||||||
|
_changeSwipeAction(isToEnd, null);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).reply),
|
||||||
|
leading: Icon(Icons.reply_outlined),
|
||||||
|
onTap: () {
|
||||||
|
_changeSwipeAction(isToEnd, 'reply');
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).forward),
|
||||||
|
leading: Icon(Icons.forward_outlined),
|
||||||
|
onTap: () {
|
||||||
|
_changeSwipeAction(isToEnd, 'forward');
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).edit),
|
||||||
|
leading: Icon(Icons.edit_outlined),
|
||||||
|
onTap: () {
|
||||||
|
_changeSwipeAction(isToEnd, 'edit');
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -42,6 +110,27 @@ class _ChatSettingsState extends State<ChatSettings> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
Divider(thickness: 1),
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).swipeToEndAction),
|
||||||
|
onTap: () => showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) =>
|
||||||
|
_swipeActionChooser(context, true),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
_getActionDescription(Matrix.of(context).swipeToEndAction)),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: Text(L10n.of(context).swipeToStartAction),
|
||||||
|
onTap: () => showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) =>
|
||||||
|
_swipeActionChooser(context, false),
|
||||||
|
),
|
||||||
|
subtitle: Text(
|
||||||
|
_getActionDescription(Matrix.of(context).swipeToStartAction)),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue