Save Quoted Messages in Drafts Too
continuous-integration/drone/pr Build is running Details

This commit is contained in:
Sarah Jamie Lewis 2023-03-20 13:13:31 -07:00 committed by Gitea
parent a2d36e62ff
commit ba0a0c2c85
7 changed files with 95 additions and 41 deletions

View File

@ -10,7 +10,8 @@ class EnvironmentConfig {
static void debugLog(String log) {
if (EnvironmentConfig.BUILD_VER == dev_version) {
print(log);
String datetime = DateTime.now().toIso8601String();
print("$datetime $log");
}
}
}

View File

@ -53,12 +53,6 @@ class AppState extends ChangeNotifier {
notifyListeners();
}
int? get selectedIndex => _selectedIndex;
set selectedIndex(int? newVal) {
this._selectedIndex = newVal;
notifyListeners();
}
bool get disableFilePicker => _disableFilePicker;
set disableFilePicker(bool newVal) {
this._disableFilePicker = newVal;

View File

@ -1,4 +1,5 @@
import 'package:cwtch/main.dart';
import 'package:cwtch/models/message_draft.dart';
import 'package:cwtch/models/profile.dart';
import 'package:cwtch/widgets/messagerow.dart';
import 'package:flutter/widgets.dart';
@ -58,10 +59,13 @@ class ContactInfoState extends ChangeNotifier {
int _antispamTickets = 0;
String? _acnCircuit;
String? _messageDraft;
MessageDraft _messageDraft = MessageDraft.empty();
ContactInfoState(this.profileOnion, this.identifier, this.onion,
{nickname = "",
ContactInfoState(
this.profileOnion,
this.identifier,
this.onion, {
nickname = "",
isGroup = false,
accepted = false,
blocked = false,
@ -75,7 +79,8 @@ class ContactInfoState extends ChangeNotifier {
server,
archived = false,
notificationPolicy = "ConversationNotificationPolicy.Default",
pinned = false}) {
pinned = false,
}) {
this._nickname = nickname;
this._isGroup = isGroup;
this._accepted = accepted;
@ -95,13 +100,13 @@ class ContactInfoState extends ChangeNotifier {
keys = Map<String, GlobalKey<MessageRowState>>();
}
String get nickname => this._nickname + (this._messageDraft != null && this._messageDraft != "" ? "*" : "");
String get nickname => this._nickname + (this._messageDraft.isNotEmpty() ? "*" : "");
String get savePeerHistory => this._savePeerHistory;
String? get acnCircuit => this._acnCircuit;
String? get messageDraft => this._messageDraft;
MessageDraft get messageDraft => this._messageDraft;
set antispamTickets(int antispamTickets) {
this._antispamTickets = antispamTickets;
@ -163,11 +168,15 @@ class ContactInfoState extends ChangeNotifier {
notifyListeners();
}
set messageDraft(String? newVal) {
set messageDraft(MessageDraft newVal) {
this._messageDraft = newVal;
notifyListeners();
}
void notifyMessageDraftUpdate() {
notifyListeners();
}
void selected() {
this._newMarkerMsgIndex = this._unreadMessages - 1;
this._unreadMessages = 0;

View File

@ -0,0 +1,44 @@
import 'package:flutter/foundation.dart';
/// A "MessageDraft" structure that stores information about in-progress message drafts.
/// MessageDraft stores text, quoted replies, and attached images.
/// Only one draft is stored per conversation.
class MessageDraft extends ChangeNotifier {
String? _messageText;
QuotedReference? _quotedReference;
static MessageDraft empty() {
return MessageDraft();
}
bool isNotEmpty() {
return this._messageText != null || this._quotedReference != null;
}
String? get messageText => _messageText;
set messageText(String? text) {
this._messageText = text;
notifyListeners();
}
set quotedReference(int index) {
this._quotedReference = QuotedReference(index);
notifyListeners();
}
QuotedReference? getQuotedMessage() {
return this._quotedReference;
}
void clearQuotedReference() {
this._quotedReference = null;
notifyListeners();
}
}
/// A QuotedReference encapsulates the state of replied-to message.
class QuotedReference {
int index;
QuotedReference(this.index);
}

View File

@ -48,7 +48,6 @@ void selectConversation(BuildContext context, int handle) {
// triggers update in Double/TripleColumnView
Provider.of<AppState>(context, listen: false).initialScrollIndex = unread;
Provider.of<AppState>(context, listen: false).selectedConversation = handle;
Provider.of<AppState>(context, listen: false).selectedIndex = null;
Provider.of<AppState>(context, listen: false).hoveredIndex = -1;
// if in singlepane mode, push to the stack
var isLandscape = Provider.of<AppState>(context, listen: false).isLandscape(context);

View File

@ -9,6 +9,7 @@ import 'package:cwtch/models/appstate.dart';
import 'package:cwtch/models/chatmessage.dart';
import 'package:cwtch/models/contact.dart';
import 'package:cwtch/models/message.dart';
import 'package:cwtch/models/message_draft.dart';
import 'package:cwtch/models/messagecache.dart';
import 'package:cwtch/models/messages/quotedmessage.dart';
import 'package:cwtch/models/profile.dart';
@ -66,7 +67,7 @@ class _MessageViewState extends State<MessageView> {
showDown = false;
}
});
ctrlrCompose.text = Provider.of<ContactInfoState>(context, listen: false).messageDraft ?? "";
ctrlrCompose.text = Provider.of<ContactInfoState>(context, listen: false).messageDraft.messageText ?? "";
super.initState();
}
@ -226,7 +227,7 @@ class _MessageViewState extends State<MessageView> {
child: MessageList(
scrollListener,
)),
bottomSheet: showPreview && showMessageFormattingPreview ? _buildPreviewBox() : _buildComposeBox(),
bottomSheet: showPreview && showMessageFormattingPreview ? _buildPreviewBox() : _buildComposeBox(context),
));
}
@ -316,10 +317,10 @@ class _MessageViewState extends State<MessageView> {
var lengthOk = (isGroup && actualMessageLength < GroupMessageLengthMax) || actualMessageLength <= P2PMessageLengthMax;
if (ctrlrCompose.value.text.isNotEmpty && lengthOk) {
if (Provider.of<AppState>(context, listen: false).selectedConversation != null && Provider.of<AppState>(context, listen: false).selectedIndex != null) {
if (Provider.of<AppState>(context, listen: false).selectedConversation != null && Provider.of<ContactInfoState>(context, listen: false).messageDraft.getQuotedMessage() != null) {
var conversationId = Provider.of<AppState>(context, listen: false).selectedConversation!;
MessageCache? cache = Provider.of<ProfileInfoState>(context, listen: false).contactList.getContact(conversationId)?.messageCache;
ById(Provider.of<AppState>(context, listen: false).selectedIndex!)
ById(Provider.of<ContactInfoState>(context, listen: false).messageDraft.getQuotedMessage()!.index)
.get(Provider.of<FlwtchState>(context, listen: false).cwtch, Provider.of<AppState>(context, listen: false).selectedProfile!, conversationId, cache!)
.then((MessageInfo? data) {
try {
@ -335,7 +336,7 @@ class _MessageViewState extends State<MessageView> {
} catch (e) {
EnvironmentConfig.debugLog("Exception: reply to message could not be found: " + e.toString());
}
Provider.of<AppState>(context, listen: false).selectedIndex = null;
Provider.of<ContactInfoState>(context, listen: false).messageDraft.clearQuotedReference();
});
} else {
ChatMessage cm = new ChatMessage(o: TextMessageOverlay, d: ctrlrCompose.value.text);
@ -370,7 +371,7 @@ class _MessageViewState extends State<MessageView> {
// At this point we have decided to send the text to the backend, failure is still possible
// but it will show as an error-ed message, as such the draft can be purged.
Provider.of<ContactInfoState>(context, listen: false).messageDraft = null;
Provider.of<ContactInfoState>(context, listen: false).messageDraft = MessageDraft.empty();
ctrlrCompose.clear();
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
@ -456,7 +457,7 @@ class _MessageViewState extends State<MessageView> {
color: Provider.of<Settings>(context).theme.backgroundMainColor, child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [composeBox]));
}
Widget _buildComposeBox() {
Widget _buildComposeBox(BuildContext context) {
bool isOffline = Provider.of<ContactInfoState>(context).isOnline() == false;
bool isGroup = Provider.of<ContactInfoState>(context).isGroup;
var showToolbar = Provider.of<Settings>(context).isExperimentEnabled(FormattingExperiment);
@ -589,7 +590,7 @@ class _MessageViewState extends State<MessageView> {
enabled: true, // always allow editing...
onChanged: (String x) {
Provider.of<ContactInfoState>(context, listen: false).messageDraft = x;
Provider.of<ContactInfoState>(context, listen: false).messageDraft.messageText = x;
setState(() {
// we need to force a rerender here to update the max length count
});
@ -625,9 +626,10 @@ class _MessageViewState extends State<MessageView> {
Container(color: Provider.of<Settings>(context).theme.backgroundMainColor, padding: EdgeInsets.all(2), margin: EdgeInsets.all(2), height: 164, child: Column(children: textEditChildren));
var children;
if (Provider.of<AppState>(context).selectedConversation != null && Provider.of<AppState>(context).selectedIndex != null) {
if (Provider.of<AppState>(context).selectedConversation != null && Provider.of<ContactInfoState>(context).messageDraft.getQuotedMessage() != null) {
var quoted = FutureBuilder(
future: messageHandler(context, Provider.of<AppState>(context).selectedProfile!, Provider.of<AppState>(context).selectedConversation!, ById(Provider.of<AppState>(context).selectedIndex!)),
future: messageHandler(context, Provider.of<AppState>(context).selectedProfile!, Provider.of<AppState>(context).selectedConversation!,
ById(Provider.of<ContactInfoState>(context).messageDraft.getQuotedMessage()!.index)),
builder: (context, snapshot) {
if (snapshot.hasData) {
var message = snapshot.data! as Message;
@ -669,7 +671,8 @@ class _MessageViewState extends State<MessageView> {
splashRadius: Material.defaultSplashRadius / 2,
tooltip: AppLocalizations.of(context)!.tooltipRemoveThisQuotedMessage,
onPressed: () {
Provider.of<AppState>(context, listen: false).selectedIndex = null;
Provider.of<ContactInfoState>(context, listen: false).messageDraft.clearQuotedReference();
setState(() {});
},
)),
]),

View File

@ -89,7 +89,9 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
tooltip: AppLocalizations.of(context)!.tooltipReplyToThisMessage,
splashRadius: Material.defaultSplashRadius / 2,
onPressed: () {
Provider.of<AppState>(context, listen: false).selectedIndex = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).messageDraft.quotedReference = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).notifyMessageDraftUpdate();
setState(() {});
},
icon: Icon(Icons.reply, color: Provider.of<Settings>(context).theme.dropShadowColor)));
@ -243,7 +245,9 @@ class MessageRowState extends State<MessageRow> with SingleTickerProviderStateMi
},
onPanEnd: (details) {
_runAnimation(details.velocity.pixelsPerSecond, size);
Provider.of<AppState>(context, listen: false).selectedIndex = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).messageDraft.quotedReference = Provider.of<MessageMetadata>(context, listen: false).messageID;
Provider.of<ContactInfoState>(context, listen: false).notifyMessageDraftUpdate();
setState(() {});
},
onLongPress: () async {
modalShowReplies(context, AppLocalizations.of(context)!.headingReplies, AppLocalizations.of(context)!.messageNoReplies, settings, pis, cis, borderColor, cache, messageID);