diff --git a/ui/commands.go b/ui/commands.go index f8b7232..8235c15 100644 --- a/ui/commands.go +++ b/ui/commands.go @@ -454,60 +454,8 @@ func cmdUnknownCommand(cmd *Command) { } func cmdHelp(cmd *Command) { - cmd.Reply(`# General -/help - Show this "temporary" help message. -/quit - Quit gomuks. -/clearcache - Clear cache and quit gomuks. -/logout - Log out of Matrix. -/toggle - Temporary command to toggle various UI features. - -Things: rooms, users, baremessages, images, typingnotif, unverified - -# Sending special messages -/me - Send an emote message. -/notice - Send a notice (generally used for bot messages). -/rainbow - Send rainbow text (markdown not supported). -/rainbowme - Send rainbow text in an emote. -/reply [text] - Reply to the selected message. -/react - React to the selected message. -/redact [reason] - Redact the selected message. -/edit - Edit the selected message. - -# Encryption -/fingerprint - View the fingerprint of your device. - -/devices - View the device list of a user. -/device - Show info about a specific device. -/unverify - Un-verify a device. -/blacklist - Blacklist a device. -/verify [fingerprint] - - Verify a device. If the fingerprint is not provided, - interactive emoji verification will be started. -/reset-session - Reset the outbound Megolm session in the current room. - -/import - Import encryption keys -/export - Export encryption keys -/export-room - Export encryption keys for the current room. - -# Rooms -/pm <...> - Create a private chat with the given user(s). -/create [room name] - Create a room. - -/join [server] - Join a room. -/accept - Accept the invite. -/reject - Reject the invite. - -/invite - Invite the given user to the room. -/roomnick - Change your per-room displayname. -/tag - Add the room to . -/untag - Remove the room from . -/tags - List the tags the room is in. -/alias - Add or remove local addresses. - -/leave - Leave the current room. -/kick [reason] - Kick a user. -/ban [reason] - Ban a user. -/unban - Unban a user.`) + view := cmd.MainView + view.ShowModal(NewHelpModal(view)) } func cmdLeave(cmd *Command) { diff --git a/ui/help-modal.go b/ui/help-modal.go new file mode 100644 index 0000000..6588651 --- /dev/null +++ b/ui/help-modal.go @@ -0,0 +1,205 @@ +package ui + +import ( + "strings" + + "maunium.net/go/mauview" + "maunium.net/go/tcell" +) + +type HelpModal struct { + mauview.Component + + container *mauview.Box + + text *mauview.TextView + scrollX int + scrollY int + maxScrollX int + maxScrollY int + textWidth int + textHeight int + + parent *MainView +} + +// There are only math.Min/math.Max for float64 +func Max(a int, b int) int { + if a > b { + return a + } + + return b +} + +func Min(a int, b int) int { + if a < b { + return a + } + + return b +} + +func NewHelpModal(parent *MainView) *HelpModal { + hm := &HelpModal{ + parent: parent, + + scrollX: 0, + scrollY: 0, + maxScrollX: 0, + maxScrollY: 0, + } + + helpText := `# General +/help - Show this "temporary" help message. +/quit - Quit gomuks. +/clearcache - Clear cache and quit gomuks. +/logout - Log out of Matrix. +/toggle - Temporary command to toggle various UI features. + +Things: rooms, users, baremessages, images, typingnotif, unverified + +# Sending special messages +/me - Send an emote message. +/notice - Send a notice (generally used for bot messages). +/rainbow - Send rainbow text (markdown not supported). +/rainbowme - Send rainbow text in an emote. +/reply [text] - Reply to the selected message. +/react - React to the selected message. +/redact [reason] - Redact the selected message. +/edit - Edit the selected message. + +# Encryption +/fingerprint - View the fingerprint of your device. + +/devices - View the device list of a user. +/device - Show info about a specific device. +/unverify - Un-verify a device. +/blacklist - Blacklist a device. +/verify [fingerprint] + - Verify a device. If the fingerprint is not provided, + interactive emoji verification will be started. +/reset-session - Reset the outbound Megolm session in the current room. + +/import - Import encryption keys +/export - Export encryption keys +/export-room - Export encryption keys for the current room. + +# Rooms +/pm <...> - Create a private chat with the given user(s). +/create [room name] - Create a room. + +/join [server] - Join a room. +/accept - Accept the invite. +/reject - Reject the invite. + +/invite - Invite the given user to the room. +/roomnick - Change your per-room displayname. +/tag - Add the room to . +/untag - Remove the room from . +/tags - List the tags the room is in. +/alias - Add or remove local addresses. + +/leave - Leave the current room. +/kick [reason] - Kick a user. +/ban [reason] - Ban a user. +/unban - Unban a user.` + + split := strings.Split(helpText, "\n") + hm.textHeight = len(split) + hm.textWidth = 0 + + for _, line := range split { + hm.textWidth = Max(hm.textWidth, len(line)) + } + + hm.text = mauview.NewTextView(). + SetText(helpText). + SetScrollable(true). + SetWrap(false) + + flex := mauview.NewFlex(). + SetDirection(mauview.FlexRow). + AddProportionalComponent(hm.text, 1) + + hm.container = mauview.NewBox(flex). + SetBorder(true). + SetTitle("Help"). + SetBlurCaptureFunc(func() bool { + hm.parent.HideModal() + return true + }) + + hm.Component = mauview.Center(hm.container, 0, 0). + SetAlwaysFocusChild(true) + + return hm +} + +func (hm *HelpModal) Focus() { + hm.container.Focus() +} + +func (hm *HelpModal) Blur() { + hm.container.Blur() +} + +func (hm *HelpModal) Draw(screen mauview.Screen) { + width, height := screen.Size() + + width /= 2 + if width < 42 { + width = 42 + } + + if height > 40 { + height -= 20 + } else if height > 30 { + height -= 10 + } else if height > 20 { + height -= 5 + } + + oldMaxScrollY := hm.maxScrollY + hm.maxScrollY = hm.textHeight - height + 2 + hm.maxScrollX = hm.textWidth - width + 2 + + if hm.maxScrollY != oldMaxScrollY { + // Reset the scroll + // NOTE: Workarounds a problem where we can no longer scroll + // due to hm.scrollY being too big. + hm.scrollY = 0 + hm.scrollX = 0 + hm.text.ScrollTo(hm.scrollY, hm.scrollX) + } + + hm.Component = mauview.Center(hm.container, width, height). + SetAlwaysFocusChild(true) + + hm.Component.Draw(screen) +} + +func (hm *HelpModal) OnKeyEvent(event mauview.KeyEvent) bool { + switch event.Key() { + case tcell.KeyUp: + hm.scrollY = Max(0, hm.scrollY-1) + hm.text.ScrollTo(hm.scrollY, hm.scrollX) + return true + case tcell.KeyDown: + hm.scrollY = Min(hm.maxScrollY, hm.scrollY+1) + hm.text.ScrollTo(hm.scrollY, hm.scrollX) + return true + + case tcell.KeyLeft: + hm.scrollX = Max(0, hm.scrollX-1) + hm.text.ScrollTo(hm.scrollY, hm.scrollX) + return true + case tcell.KeyRight: + hm.scrollX = Min(hm.maxScrollX, hm.scrollX+1) + hm.text.ScrollTo(hm.scrollY, hm.scrollX) + return true + } + + hm.parent.HideModal() + return true +}