Skip to content

Commit

Permalink
refactor: api_types/core/model/ui/boxes: Clarify draft types & naming.
Browse files Browse the repository at this point in the history
Previously a draft was a Message, which is a much more complex data
structure received from the server with differently-named fields. The
draft system only requires the data which is subsequently sent via
the send_message API call, so a simpler API-specific set of data
structures are created and used for drafts named ~ Composition.

Other than typing, the new data structures allow space to define where
we wish to move to use newer API forms (ids vs strings) in future. An
extra 'stream_id' field is present in StreamComposition, not present in
the API, until we migrate to use IDs.

To emphasize the message/draft distinction and migration, variable names
are also updated to match.
  • Loading branch information
neiljp committed Feb 15, 2021
1 parent 01fc24a commit 306a394
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 21 deletions.
17 changes: 17 additions & 0 deletions zulipterminal/api_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@
EditPropagateMode = Literal['change_one', 'change_all', 'change_later']


class PrivateComposition(TypedDict):
type: Literal['private']
content: str
to: List[str] # emails # TODO: Migrate to using List[int] (user ids)


class StreamComposition(TypedDict):
type: Literal['stream']
content: str
to: str # stream name # TODO: Migrate to using int (stream id)
subject: str # TODO: Migrate to using topic
stream_id: int # FIXME: Not type of API; use until migrate to stream id


Composition = Union[PrivateComposition, StreamComposition]


class Message(TypedDict, total=False):
id: int
sender_id: int
Expand Down
6 changes: 3 additions & 3 deletions zulipterminal/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import zulip
from typing_extensions import Literal

from zulipterminal.api_types import Message
from zulipterminal.api_types import Composition, Message
from zulipterminal.config.themes import ThemeSpec
from zulipterminal.helper import asynch
from zulipterminal.model import Model
Expand Down Expand Up @@ -262,10 +262,10 @@ def search_messages(self, text: str) -> None:
if 0 <= focus_position < len(w_list):
self.view.message_view.set_focus(focus_position)

def save_draft_confirmation_popup(self, message: Message) -> None:
def save_draft_confirmation_popup(self, draft: Composition) -> None:
question = urwid.Text('Save this message as a draft?'
' (This will overwrite the existing draft.)')
save_draft = partial(self.model.save_draft, message)
save_draft = partial(self.model.save_draft, draft)
self.loop.widget = PopUpConfirmationView(self, question, save_draft)

def stream_muting_confirmation_popup(self, button: Any) -> None:
Expand Down
10 changes: 5 additions & 5 deletions zulipterminal/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from typing_extensions import Literal

from zulipterminal import unicode_emojis
from zulipterminal.api_types import EditPropagateMode, Event
from zulipterminal.api_types import Composition, EditPropagateMode, Event
from zulipterminal.config.keys import primary_key_for_command
from zulipterminal.helper import (
Message,
Expand Down Expand Up @@ -127,7 +127,7 @@ def __init__(self, controller: Any) -> None:

self.unread_counts = classify_unread_counts(self)

self._draft: Optional[Message] = None
self._draft: Optional[Composition] = None
unicode_emoji_data = unicode_emojis.EMOJI_DATA
for name, data in unicode_emoji_data.items():
data['type'] = 'unicode_emoji'
Expand Down Expand Up @@ -333,11 +333,11 @@ def react_to_message(self,
response = self.client.add_reaction(reaction_to_toggle_spec)
display_error_if_present(response, self.controller)

def session_draft_message(self) -> Optional[Message]:
def session_draft_message(self) -> Optional[Composition]:
return deepcopy(self._draft)

def save_draft(self, message: Message) -> None:
self._draft = deepcopy(message)
def save_draft(self, draft: Composition) -> None:
self._draft = deepcopy(draft)
self.controller.view.set_footer_text("Saved message as draft", 3)

@asynch
Expand Down
4 changes: 2 additions & 2 deletions zulipterminal/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ def keypress(self, size: Tuple[int, int], key: str) -> Optional[str]:
if saved_draft:
if saved_draft['type'] == 'stream':
self.write_box.stream_box_view(
caption=saved_draft['display_recipient'],
caption=saved_draft['to'],
title=saved_draft['subject'],
stream_id=saved_draft['stream_id'],
)
elif saved_draft['type'] == 'private':
email_list = saved_draft['display_recipient']
email_list = saved_draft['to']
recipient_user_ids = [
self.model.user_dict[email.strip()]['user_id']
for email in email_list
Expand Down
29 changes: 18 additions & 11 deletions zulipterminal/ui_tools/boxes.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
from tzlocal import get_localzone
from urwid_readline import ReadlineEdit

from zulipterminal.api_types import (
Composition,
PrivateComposition,
StreamComposition,
)
from zulipterminal.config.keys import (
is_command_key,
keys_for_command,
Expand Down Expand Up @@ -543,24 +548,26 @@ def keypress(self, size: urwid_Size, key: str) -> Optional[str]:
if not self.msg_edit_id:
if self.to_write_box:
self.update_recipient_emails(self.to_write_box)
message = Message(
display_recipient=self.recipient_emails,
content=self.msg_write_box.edit_text,
type='private',
this_draft: Composition = PrivateComposition(
type="private",
to=self.recipient_emails,
content=self.msg_write_box.edit_text,
)
elif self.stream_id:
message = Message(
display_recipient=self.stream_write_box.edit_text,
this_draft = StreamComposition(
type="stream",
to=self.stream_write_box.edit_text,
content=self.msg_write_box.edit_text,
subject=self.title_write_box.edit_text,
stream_id=self.stream_id,
type='stream',
stream_id=self.stream_id, # FIXME Migrate to ids
)
saved_draft = self.model.session_draft_message()
if not saved_draft:
self.model.save_draft(message)
elif message != saved_draft:
self.view.controller.save_draft_confirmation_popup(message)
self.model.save_draft(this_draft)
elif this_draft != saved_draft:
self.view.controller.save_draft_confirmation_popup(
this_draft,
)
elif is_command_key('CYCLE_COMPOSE_FOCUS', key):
if len(self.contents) == 0:
return key
Expand Down

0 comments on commit 306a394

Please sign in to comment.