-
Notifications
You must be signed in to change notification settings - Fork 235
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mark as resolved/unresolved prep 1 #1242
base: main
Are you sure you want to change the base?
Changes from all commits
b75b2c1
a871359
c868f2f
5dfc78b
e58963e
377544a
8ee140d
fe11d69
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
import '../route/messages.dart'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I don't like having lib/api/model/ import from lib/api/route/. If it's needed for the model, that feels like a sign it's part of the model and not part of how particular routes interact with the model. I think these can just stay in this file. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (When this file gets to feel unwieldy, I think the thing to do is to split pieces out by subject area: like a |
||
import 'events.dart'; | ||
import 'initial_snapshot.dart'; | ||
import 'reaction.dart'; | ||
|
@@ -806,30 +807,14 @@ enum MessageEditState { | |
edited, | ||
moved; | ||
|
||
// Adapted from the shared code: | ||
// https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts | ||
// The canonical resolved-topic prefix. | ||
static const String _resolvedTopicPrefix = '✔ '; | ||
|
||
/// Whether the given topic move reflected either a "resolve topic" | ||
/// or "unresolve topic" operation. | ||
/// | ||
/// The Zulip "resolved topics" feature is implemented by renaming the topic; | ||
/// but for purposes of [Message.editState], we want to ignore such renames. | ||
/// This method identifies topic moves that should be ignored in that context. | ||
static bool topicMoveWasResolveOrUnresolve(String topic, String prevTopic) { | ||
if (topic.startsWith(_resolvedTopicPrefix) | ||
&& topic.substring(_resolvedTopicPrefix.length) == prevTopic) { | ||
return true; | ||
} | ||
|
||
if (prevTopic.startsWith(_resolvedTopicPrefix) | ||
&& prevTopic.substring(_resolvedTopicPrefix.length) == topic) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
static bool topicMoveWasResolveOrUnresolve(String topic, String prevTopic) => | ||
topic != prevTopic && topicsMatchModuloResolvePrefix(topic, prevTopic); | ||
|
||
static MessageEditState _readFromMessage(Map<dynamic, dynamic> json, String key) { | ||
// Adapted from `analyze_edit_history` in the web app: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -158,6 +158,19 @@ class GetMessagesResult { | |
// https://zulip.com/api/send-message#parameter-topic | ||
const int kMaxTopicLength = 60; | ||
|
||
/// The canonical resolved-topic prefix. | ||
// Adapted from the shared code: | ||
// https://github.com/zulip/zulip/blob/1fac99733/web/shared/src/resolved_topic.ts | ||
const String kResolvedTopicPrefix = '✔ '; | ||
|
||
String stripResolvePrefixIfPresent(String topic) => | ||
topic.startsWith(kResolvedTopicPrefix) | ||
? topic.substring(kResolvedTopicPrefix.length) | ||
: topic; | ||
Comment on lines
+166
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How does this end up getting used later in your branch? Its behavior differs from which I'm guessing (haven't checked) is what gets applied when the user unresolves a topic in web or the legacy mobile app. |
||
|
||
bool topicsMatchModuloResolvePrefix(String topicA, String topicB) => | ||
stripResolvePrefixIfPresent(topicA) == stripResolvePrefixIfPresent(topicB); | ||
|
||
// https://zulip.com/api/send-message#parameter-content | ||
const int kMaxMessageLengthCodePoints = 10000; | ||
|
||
|
@@ -258,6 +271,49 @@ class SendMessageResult { | |
Map<String, dynamic> toJson() => _$SendMessageResultToJson(this); | ||
} | ||
|
||
/// https://zulip.com/api/update-message | ||
Future<UpdateMessageResult> updateMessage( | ||
ApiConnection connection, { | ||
required int messageId, | ||
String? topic, | ||
PropagateMode? propagateMode, | ||
bool? sendNotificationToOldThread, | ||
bool? sendNotificationToNewThread, | ||
String? content, | ||
int? streamId, | ||
}) { | ||
return connection.patch('updateMessage', UpdateMessageResult.fromJson, 'messages/$messageId', { | ||
if (topic != null) 'topic': RawParameter(topic), | ||
if (propagateMode != null) 'propagate_mode': RawParameter(propagateMode.toJson()), | ||
if (sendNotificationToOldThread != null) 'send_notification_to_old_thread': sendNotificationToOldThread, | ||
if (sendNotificationToNewThread != null) 'send_notification_to_new_thread': sendNotificationToNewThread, | ||
if (content != null) 'content': RawParameter(content), | ||
if (streamId != null) 'stream_id': streamId, | ||
}); | ||
} | ||
|
||
/// As in [updateMessage] or [UpdateMessageEvent.propagateMode]. | ||
@JsonEnum(fieldRename: FieldRename.snake, alwaysCreate: true) | ||
enum PropagateMode { | ||
changeOne, | ||
changeLater, | ||
changeAll; | ||
|
||
String toJson() =>_$PropagateModeEnumMap[this]!; | ||
} | ||
|
||
@JsonSerializable(fieldRename: FieldRename.snake) | ||
class UpdateMessageResult { | ||
// final List<DetachedUpload> detachedUploads; // TODO handle | ||
|
||
UpdateMessageResult(); | ||
|
||
factory UpdateMessageResult.fromJson(Map<String, dynamic> json) => | ||
_$UpdateMessageResultFromJson(json); | ||
|
||
Map<String, dynamic> toJson() => _$UpdateMessageResultToJson(this); | ||
} | ||
|
||
/// https://zulip.com/api/upload-file | ||
Future<UploadFileResult> uploadFile( | ||
ApiConnection connection, { | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -64,6 +64,16 @@ void _showActionSheet( | |
}); | ||
} | ||
|
||
/// A button in an action sheet. | ||
/// | ||
/// When built from server data, the action sheet ignores changes in that data; | ||
/// we intentionally don't live-update the buttons on events. | ||
/// If a button's label, action, or position changes suddenly, | ||
/// it can be confusing and make the on-tap behavior unexpected. | ||
/// Better to let the user decide to tap | ||
Comment on lines
+69
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, yeah. Looking for That one shouldn't cause this problem in practice, though, because it changes by the user's own action. (Or by the message getting deleted, but then it doesn't matter whether the user tries to add a reaction or remove one.) |
||
/// based on information that's comfortably in their working memory, | ||
/// even if we sometimes have to explain (where we handle the tap) | ||
/// that that information has changed and they need to decide again. | ||
Comment on lines
+73
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A key point here is that these races are always possible anyway — the change may have happened on the server but not reached us yet. |
||
abstract class ActionSheetMenuItemButton extends StatelessWidget { | ||
const ActionSheetMenuItemButton({super.key, required this.pageContext}); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And this can move from lib/api/model/events.dart to lib/api/model/model.dart, since it's no longer specific to an event.