+
https://github.com/zevlg/telega.el/issues/105
https://gitlab.com/jessieh/mood-line/issues/6
https://www.youtube.com/watch?v=0m2jR6_eMkU
diff --git a/docs/telega-ellit.org b/docs/telega-ellit.org
index ff7833b..3cdc171 100644
--- a/docs/telega-ellit.org
+++ b/docs/telega-ellit.org
@@ -570,7 +570,6 @@ Use ~telega-story-match-p~ to match a story.
- {{{user-option(telega-filters-custom, 2)}}}
- {{{user-option(telega-use-tracking-for, 2)}}}
- {{{user-option(telega-rainbow-color-custom-for, 2)}}}
-- {{{user-option(telega-chat-prompt-format, 2)}}}
- {{{user-option(telega-chat-group-messages-for, 2)}}}
- {{{user-option(telega-chat-show-deleted-messages-for, 2)}}}
- {{{user-option(telega-root-view-grouping-alist, 2)}}}
diff --git a/docs/telega-manual.org b/docs/telega-manual.org
index 0991ac8..646f5d2 100644
--- a/docs/telega-manual.org
+++ b/docs/telega-manual.org
@@ -1,5 +1,5 @@
#+options: timestamp:nil \n:t num:nil ellit-cid:t
-#+title: Telega Manual (v0.8.290)
+#+title: Telega Manual (v0.8.291)
#+author: Zajcev Evgeny
#+startup: showall
@@ -1589,26 +1589,6 @@ Use ~telega-story-match-p~ to match a story.
Each element is cons cell, where car is Chat Filter, and cdr is color.
Default value: ~((saved-messages))~
-- User Option: ~telega-chat-prompt-format~
-
- Modeline compatible format for the chatbuf input prompt.
- You can use ~telega-chatbuf-editing-msg~ or
- ~telega-chatbuf-replying-msg~ in ~:eval~ section if you want different
- prompt when editing/replying a message.
-
- Default value:
- #+begin_src emacs-lisp
- ((:eval (telega-chatbuf-prompt-default-sender-avatar))
- (:eval (telega-chatbuf-prompt-body))
- (:eval
- (when
- (and telega-use-images
- (telega-chatbuf-match-p 'can-send-or-post))
- (telega-chatbuf-prompt-chat-avatar)))
- (:eval (telega-chatbuf-prompt-topic 25))
- (:eval (telega-auto-translate--chatbuf-prompt-translation)) ">>> ")
- #+end_src
-
- User Option: ~telega-chat-group-messages-for~
Chat Filter for chats where to group messages by sender.
diff --git a/etc/langs/en.plist b/etc/langs/en.plist
index c3ab021..8d1b901 100644
--- a/etc/langs/en.plist
+++ b/etc/langs/en.plist
@@ -37,6 +37,8 @@
("lng_cancel"
:value "Cancel")
+ ("lng_saved_open_chat"
+ :value "Open Chat")
("lng_saved_messages"
:value "Saved Messages")
("lng_replies_messages"
@@ -67,19 +69,35 @@
:value "Phone:")
("lng_profile_bio"
:value "Bio:")
+ ("lng_profile_photos_header"
+ :value "Photos")
("lng_settings_about_bio"
:value "Any details such as age, occupation or city.
Example: 23 y.o. designer from San Francisco")
+ ("lng_settings_empty_bio"
+ :value "None")
+ ("lng_bio_title"
+ :value "Edit Your Bio")
("lng_profile_common_groups"
:zero_value "No groups in common"
:one_value "{count} group in common"
:other_value "{count} groups in common")
("lng_settings_upload"
:value "Set Profile Photo")
+ ("lng_settings_edit"
+ :value "Edit")
+ ("lng_edit_self_title"
+ :value "Edit your name")
+ ("lng_settings_username"
+ :value "Username:")
+ ("lng_settings_choose_username"
+ :value "Choose username")
("lng_profile_restart_bot"
:value "Restart bot")
("lng_profile_set_group_photo"
:value "Set Photo")
+ ("lng_profile_apply_to_join_group"
+ :value "Apply to Join Group")
("lng_scam_badge"
:value "SCAM")
@@ -136,6 +154,12 @@ Example: 23 y.o. designer from San Francisco")
:value "Privacy")
("lng_blocked_list_title"
:value "Blocked Users")
+ ("lng_blocked_list_about"
+ :value "Blocked users can't send you messages or add you to groups. They will not see your profile photos, stories, online and last seen status.")
+ ("lng_blocked_list_add"
+ :value "Block user")
+ ("lng_blocked_list_add_title"
+ :value "Select user to block")
("lng_settings_section_privacy"
:value "Privacy and Security")
("lng_settings_section_notify"
@@ -146,8 +170,15 @@ Example: 23 y.o. designer from San Francisco")
:value "Show message preview")
("lng_edit_privacy_close_friends"
:value "Close friends")
+ ("lng_edit_privacy_about_header"
+ :value "Who can see my bio")
+ ("lng_edit_privacy_about_title"
+ :value "Bio")
;; https://translations.telegram.org/screenshots/11323
+ ("lng_unread_bar"
+ :one_value "{count} Unread Message"
+ :other_value "{count} Unread Messages")
("lng_unread_bar_some"
:value "Unread messages")
@@ -314,6 +345,8 @@ Example: 23 y.o. designer from San Francisco")
("lng_sure_delete_group"
:value "Are you sure you want to delete this group? All members will be removed, and all messages will be lost.")
+ ("lng_profile_add_participant"
+ :value "Add Members")
("lng_profile_hide_participants"
:value "Hide Members")
("lng_profile_hide_participants_about"
@@ -498,6 +531,18 @@ Example: 23 y.o. designer from San Francisco")
:value "Telegram will filter more spam but may occasionally affect ordinary messages. You can report False Positives in Recent Actions.")
("lng_manage_peer_members"
:value "Members")
+ ("lng_manage_peer_send_approve_members"
+ :value "Approve new members")
+ ("lng_manage_peer_send_approve_members_about"
+ :value "Turn this on if you want users to join the group only after they are approved by an admin.")
+ ("lng_manage_peer_no_forwards"
+ :value "Restrict saving content")
+ ("lng_manage_peer_no_forwards_about"
+ :value "Members won't be able to copy, save or forward content from this group.")
+ ("lng_manage_peer_no_forwards_about_channel"
+ :value "Subscribers won't be able to copy, save or forward content from this channel.")
+ ("lng_manage_peer_requests"
+ :value "Join Requests")
("lng_manage_messages_ttl_title"
:value "Auto-delete messages")
("lng_manage_discussion_group"
@@ -595,6 +640,8 @@ Example: 23 y.o. designer from San Francisco")
:value "Telegram FAQ")
("lng_settings_ask_question"
:value "Ask a Question")
+ ("lng_telegram_features_url"
+ :value "https://t.me/TelegramTips")
("telega_settings_telega_manual"
:value "Telega.el Manual")
("telega_settings_donate"
@@ -809,6 +856,8 @@ Example: 23 y.o. designer from San Francisco")
:value "Forward")
("lng_context_delete_msg"
:value "Delete")
+ ("lng_context_select_msg"
+ :value "Select")
("lng_context_disable_spoiler"
:value "Remove Spoiler")
("lng_context_cancel_upload"
@@ -1003,6 +1052,9 @@ to start the topic.")
:value "Request to Join")
("lng_group_request_about_channel"
:value "This channel accepts new subscribers only after they are approved by its admins.")
+ ("lng_group_requests_pending"
+ :one_value "{count} join request"
+ :other_value "{count} join requests")
("lng_payments_invoice_label_test"
:value "Test invoice")
@@ -1196,6 +1248,8 @@ Telegram offers a free and unlimited service to hundreds of millions of users, w
:value "Story")
("lng_in_dlg_story_expired"
:value "Expired story")
+ ("lng_in_dlg_contact"
+ :value "Contact")
;; Edited
("lng_edited"
@@ -1619,6 +1673,8 @@ You can send them an invite link as message instead.")
("lng_link_remove"
:value "Do Not Preview")
+ ("lng_add_tag_button"
+ :value "Add tags")
("lng_context_filter_by_tag"
:value "Filter by Tag")
("lng_context_tag_add_name"
@@ -1667,6 +1723,8 @@ You can send them an invite link as message instead.")
({count} year old)"
:other_value "{date}
({count} years old)")
+ ("lng_settings_birthday_about"
+ :value "Choose who can see your birthday in {link}.")
;; Business
("lng_business_subtitle_sponsored"
@@ -1676,4 +1734,31 @@ You can send them an invite link as message instead.")
("lng_business_about_sponsored"
:value "As a Premium subscriber, you don’t see any ads on Telegram, but you can turn them on, for example, to view your own ads that you launched on the {link}")
+ ;; Proxy
+ ("lng_proxy_settings"
+ :value "Proxy settings")
+ ("lng_proxy_use"
+ :value "Use proxy")
+ ("lng_proxy_checking"
+ :value "checking…")
+ ("lng_proxy_unavailable"
+ :value "not available")
+ ("lng_proxy_available"
+ :value "available (ping: {ping} ms)")
+ ("lng_proxy_connecting"
+ :value "connecting…")
+ ("lng_proxy_online"
+ :value "online")
+ ("lng_proxy_sponsor_warning"
+ :value "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.")
+ ("lng_proxy_add"
+ :value "Add proxy")
+ ("lng_proxy_address_label"
+ :value "Socket address")
+ ("lng_connection_host_ph"
+ :value "Hostname")
+ ("lng_connection_port_ph"
+ :value "Port")
+ ("lng_proxy_menu_delete"
+ :value "Delete")
)
diff --git a/telega-chat.el b/telega-chat.el
index 156d91d..5266a78 100644
--- a/telega-chat.el
+++ b/telega-chat.el
@@ -791,7 +791,7 @@ Specify non-nil BAN to ban this user in this CHAT."
(telega-read-file-name "Profile Photo: " nil nil t)))))
(when (telega-chat-match-p chat '(my-permission :can_invite_users))
(telega-ins " ")
- (telega-ins--box-button "Add Member"
+ (telega-ins--box-button (telega-i18n "lng_profile_add_participant")
'action (lambda (_button)
(call-interactively #'telega-chat-add-member))))
(when (telega-chat-match-p chat '(my-permission :can_change_info))
@@ -1104,8 +1104,7 @@ Specify non-nil BAN to ban this user in this CHAT."
(channel ,(telega-i18n "lng_info_channel_title")
telega-info--insert-supergroup)))))
(cl-assert info-spec)
- (telega-ins--with-face 'telega-describe-section-title
- (telega-ins (upcase (nth 1 info-spec)) "\n"))
+ (telega-ins-describe-section (upcase (nth 1 info-spec)))
(funcall (nth 2 info-spec) (telega-chat--info chat) chat))
(when-let* ((video-chat (plist-get chat :video_chat))
@@ -1120,7 +1119,8 @@ Specify non-nil BAN to ban this user in this CHAT."
(telega-describe-group-call--inserter group-call-id))))))
(when (and (listp telega-debug) (memq 'info telega-debug))
- (telega-ins "\n---DEBUG---\n")
+ (telega-ins "\n")
+ (telega-ins-describe-section "DEBUG")
(telega-ins--with-face 'bold
(telega-ins "Chat: "))
(telega-ins-fmt "%S" chat)
@@ -1129,6 +1129,11 @@ Specify non-nil BAN to ban this user in this CHAT."
(telega-ins--with-face 'bold
(telega-ins "Info: "))
(telega-ins-fmt "%S" (telega-chat--info chat))
+ (telega-ins "\n")
+
+ (telega-ins--with-face 'bold
+ (telega-ins "Full-Info: "))
+ (telega-ins-fmt "%S" (telega--full-info (telega-chat--info chat)))
(telega-ins "\n"))
)
@@ -1228,7 +1233,8 @@ CHAT must be a channel."
(not (telega-user-chat user))))
(hash-table-values (alist-get 'user telega--info)))))
(list (telega-completing-read-msg-sender
- "Chat with: " (nconc chats users)))))
+ (concat (telega-i18n "lng_saved_open_chat") ": ")
+ (nconc chats users)))))
(when (telega-user-p chat-or-user)
(setq chat-or-user (or (telega-chat-get (plist-get chat-or-user :id))
@@ -1377,12 +1383,12 @@ Use `telega-chat-leave' to just leave the CHAT."
CHAT-TYPE is one of \"basicgroup\", \"supergroup\", \"forum\", \"channel\",
\"secret\", \"location-supergroup\", \"location-channel\".
Return newly created chat."
- (interactive (list (funcall telega-completing-read-function
- "Chat Type: "
- (list "basicgroup" "supergroup" "forum"
- "channel" "secret"
- "location-supergroup" "location-channel")
- nil t)))
+ (interactive (list (telega-completing-read
+ "Chat Type: "
+ (list "basicgroup" "supergroup" "forum"
+ "channel" "secret"
+ "location-supergroup" "location-channel")
+ nil t)))
(cond ((string= chat-type "basicgroup")
(let ((title (read-string "Chat Title: "))
@@ -1484,11 +1490,11 @@ Return newly created chat."
"Report a CHAT having inappropriate content."
(interactive
(list (or telega-chatbuf--chat (telega-chat-at (point)))
- (apply telega-completing-read-function
- "Report Reason: "
- '("Spam" "Violence" "Pornography" "ChildAbuse"
- "Copyright" "UnrelatedLocation" "Fake" "Custom")
- nil t)))
+ (telega-completing-read
+ "Report Reason: "
+ '("Spam" "Violence" "Pornography" "ChildAbuse"
+ "Copyright" "UnrelatedLocation" "Fake" "Custom")
+ nil t)))
(let ((text (when (string= "Custom" reason)
(read-string "Custom Report Reason: "))))
(telega--reportChat chat reason text)))
@@ -1521,7 +1527,7 @@ Switch only if CHAT is opened, i.e. has corresponding chatbuf."
(unless telega--chat-buffers-alist
(user-error "No chatbufs to switch"))
(telega-completing-read-msg-sender
- "Telega chat: "
+ "Telega chatbuf: "
;; NOTE: if current buffer is chatbuf, then exclude it
;; from the list, because it is strange if it appers first
;; in the list
@@ -1727,7 +1733,7 @@ new Chat buffers.")
(define-button-type 'telega-prompt
:supertype 'telega
- :inserter 'telega-ins
+ :inserter 'telega-ins--insexp
'face 'telega-chat-prompt
'rear-nonsticky t
@@ -1948,6 +1954,18 @@ Use this to surrond header with some prefix and suffix."
(propertize telega-highlight-text-regexp
'face 'telega-highlight-text-face))))
+(defun telega-chabuf-header-unread-messages ()
+ "Formatter for the number of unread messages."
+ (telega-chatbuf--dirtiness-init
+ "updateChatReadInbox" ;unread_count
+ )
+
+ (let ((unread-count (telega-chatbuf--unread-message-count)))
+ (unless (telega-zerop unread-count)
+ (telega-ins--as-string
+ (telega-ins-i18n "lng_unread_bar"
+ :count unread-count)))))
+
(defun telega-chatbuf-header-thread (&optional max-width)
"Formatter for the chatbuf's thread."
(telega-chatbuf--dirtiness-init "thread")
@@ -1963,7 +1981,8 @@ Use this to surrond header with some prefix and suffix."
(telega-ins (telega-symbol 'right-arrow) (telega-symbol 'topic)))
(telega-ins--topic-title topic 'with-icon))
- (telega-ins "Thread: ")
+ (telega-ins--with-face 'telega-shadow
+ (telega-ins (telega-symbol 'reply)))
(telega-ins--content-one-line (telega-chatbuf--thread-msg)))))))
(defun telega-ins--chat-action-bar-button (chat action-bar)
@@ -1985,10 +2004,11 @@ Use this to surrond header with some prefix and suffix."
(telega--reportChat chat "UnrelatedLocation"))))
(chatActionBarInviteMembers
- (telega-ins--box-button "Invite Users"
+ (telega-ins--box-button (telega-i18n "lng_profile_add_participant")
'action (lambda (_ignored)
- (let ((new-users (telega-completing-read-user-list
- "Invite new users")))
+ (let ((new-users
+ (telega-completing-read-user-list
+ (telega-i18n "lng_profile_add_participant"))))
(dolist (user new-users)
(telega-chat-add-member chat user))))))
@@ -2027,6 +2047,26 @@ Use this to surrond header with some prefix and suffix."
(telega-ins--date (plist-get action-bar :request_date) 'date-long)
)))
+(defun telega-chatbuf-footer-ins-pending-join-requests ()
+ "Inserter for the pending join requests."
+ (telega-chatbuf--dirtiness-init "updateChatPendingJoinRequests")
+
+ (when-let* ((pending-join-requests
+ (plist-get telega-chatbuf--chat :pending_join_requests))
+ (nrequests (plist-get pending-join-requests :total_count)))
+ (unless (or (telega-zerop nrequests)
+ (eq nrequests (plist-get telega-chatbuf--hidden-headers
+ :pending-join-requests)))
+ (telega-ins--text-button (telega-symbol 'button-close)
+ 'face 'telega-link
+ 'action (lambda (_ignored)
+ (plist-put telega-chatbuf--hidden-headers
+ :pending-join-requests nrequests)
+ (telega-chatbuf--chat-update "updateChatPendingJoinRequests")))
+ (telega-ins " " (telega-i18n "lng_manage_peer_requests") ": ")
+ (telega-ins--pending-join-requests pending-join-requests)
+ (telega-ins "\n"))))
+
(defun telega-chatbuf-footer-ins-action-bar ()
"Formatter for the action bar."
(telega-chatbuf--dirtiness-init "updateChatActionBar")
@@ -2403,6 +2443,13 @@ These users can be added to group only via invite link."
(when telega-chatbuf--bot-start-parameter
telega-chatbuf--bot-start-parameter)))
+ ((and (eq (telega-chat--type telega-chatbuf--chat)
+ 'supergroup)
+ (plist-get (telega-chat--supergroup-locally
+ telega-chatbuf--chat)
+ :join_by_request))
+ (upcase (telega-i18n "lng_profile_apply_to_join_group")))
+
((and (not (telega-chat-private-p telega-chatbuf--chat))
(not (telega-chat-secret-p telega-chatbuf--chat)))
(upcase (telega-i18n "lng_group_invite_join"))))))
@@ -2667,7 +2714,7 @@ Global chat bindings:
(goto-char (point-max))
(setq telega-chatbuf--prompt-button
- (telega-button--insert 'telega-prompt ">>> "))
+ (telega-button--insert 'telega-prompt '(telega-ins ">>> ")))
;; user's input starts just after the prompt
(setq telega-chatbuf--input-marker (point-marker))
@@ -2906,17 +2953,19 @@ Recover previous active action after BODY execution."
(menu-button (plist-get bot-info :menu_button)))
(telega-tl-str menu-button :text)))
-(defun telega-chatbuf-prompt-default-sender-avatar ()
- "Return one line avatar for default message sender to the chatbuf."
+(defun telega-chatbuf-prompt-ins-default-sender-avatar ()
+ "Insert one line avatar for default message sender to the chatbuf."
+ (telega-chatbuf--dirtiness-init
+ "updateChatMessageSender")
+
(when (telega-chatbuf-match-p 'has-default-sender)
- (let ((chat telega-chatbuf--chat))
- (telega-ins--as-string
- (telega-ins--image
- (telega-msg-sender-avatar-image-one-line
- (telega-msg-sender (plist-get chat :message_sender_id))))))))
+ (telega-ins--image
+ (telega-msg-sender-avatar-image-one-line
+ (telega-msg-sender
+ (plist-get telega-chatbuf--chat :message_sender_id))))))
-(defun telega-chatbuf-prompt-body ()
- "Return body for the chatbuf input prompt."
+(defun telega-chatbuf-prompt-ins-body ()
+ "Insert body for the chatbuf's input prompt."
(telega-chatbuf--dirtiness-init
"thread" ; telega-chatbuf--thread-msg
@@ -2924,43 +2973,41 @@ Recover previous active action after BODY execution."
;; 'me-is-member and 'me-is-anonymous
)
- (cond ((telega-chatbuf-match-p 'me-is-anonymous)
- (telega-i18n "telega_chat_prompt_anonymous"))
+ (telega-ins
+ (cond ((telega-chatbuf-match-p 'me-is-anonymous)
+ (telega-i18n "telega_chat_prompt_anonymous"))
- ((and (telega-chatbuf--thread-msg)
- (not (telega-chatbuf-match-p 'me-is-member)))
- (telega-i18n "telega_chat_prompt_comment"))
+ ((and (telega-chatbuf--thread-msg)
+ (not (telega-chatbuf-match-p 'me-is-member)))
+ (telega-i18n "telega_chat_prompt_comment"))
- ((telega-chatbuf-match-p '(and (type channel)
- (my-permission :can_post_messages)))
- (telega-i18n "telega_chat_prompt_broadcast"))
+ ((telega-chatbuf-match-p '(and (type channel)
+ (my-permission :can_post_messages)))
+ (telega-i18n "telega_chat_prompt_broadcast"))
- ((telega-chatbuf-match-p 'has-default-sender)
- (telega-symbol 'right-arrow))))
+ ((telega-chatbuf-match-p 'has-default-sender)
+ (telega-symbol 'right-arrow)))))
-(defun telega-chatbuf-prompt-chat-avatar ()
- "Return chatbuf's avatar for the one line usage."
+(defun telega-chatbuf-prompt-ins-chat-avatar ()
+ "Inserter for chatbuf's avatar in the input prompt."
(telega-chatbuf--dirtiness-init
"updateChatPhoto"
"updateChatMessageSender")
- (let ((chat telega-chatbuf--chat))
- (telega-ins--as-string
- (telega-ins--image
- (telega-msg-sender-avatar-image-one-line chat)))))
+ (telega-ins--image
+ (telega-msg-sender-avatar-image-one-line telega-chatbuf--chat)))
-(defun telega-chatbuf-prompt-topic (&optional max-width with-topic-title-p)
- "Return current topic title for the prompt."
+(defun telega-chatbuf-prompt-ins-topic (&optional max-width with-topic-title-p)
+ "Inserter for the current topic in the chatbuf's input prompt."
(telega-chatbuf--dirtiness-init "thread")
(when-let ((topic (telega-chatbuf--thread-topic)))
- (telega-ins--as-string
- (telega-ins--with-attrs (list :max max-width :align 'left :elide t
- :face 'telega-shadow)
- (telega-ins (telega-symbol 'topic))
- (telega-ins--topic-icon topic)
- (when with-topic-title-p
- (telega-ins--topic-title topic))))))
+ (telega-ins--with-attrs (list :max max-width :align 'left :elide t
+ :face 'telega-shadow)
+ (telega-ins (telega-symbol 'topic))
+ (telega-ins--topic-icon topic)
+ (when with-topic-title-p
+ (telega-ins--topic-title topic)))))
(defun telega-chatbuf--prompt-update (&optional reset-aux)
"Update chatbuf's prompt.
@@ -2971,19 +3018,13 @@ If RESET-AUX is specified, then reset aux prompt."
(setq telega-chatbuf--aux-plist nil)
(telega-chatbuf--chat-update "aux-plist"))
- (let ((prompt (format-mode-line telega-chat-prompt-format
- nil nil (current-buffer))))
- (telega-button--update-value
- telega-chatbuf--prompt-button
- (if (telega-chatbuf-match-p 'can-send-or-post)
- prompt
- (propertize prompt 'face 'telega-shadow)))))))
+ (telega-button--update-value
+ telega-chatbuf--prompt-button
+ telega-chat-prompt-insexp))))
(defun telega-chatbuf--prompt-reset ()
"Reset prompt to initial state in chat buffer."
- (let ((inhibit-read-only t)
- (buffer-undo-list t))
- (telega-chatbuf--prompt-update 'reset)))
+ (telega-chatbuf--prompt-update 'reset))
(defun telega-chatbuf--input-draft-update (&optional force)
"Update chatbuf's input to display draft message.
@@ -4919,8 +4960,9 @@ If `\\[universal-argument]' is given, then attach live location."
:with-username-p t)
user))
contacts))
- (name (funcall telega-completing-read-function
- "Contact: " (mapcar 'car names-alist) nil t))
+ (name (telega-completing-read
+ (concat (telega-i18n "lng_in_dlg_contact") ": ")
+ (mapcar 'car names-alist) nil t))
(user (cdr (assoc name names-alist))))
(cl-assert user)
(list (telega-user-as-contact user)))))
@@ -5454,9 +5496,9 @@ Use this attachment to disable/enable notification on the receiver side."
(defun telega-chatbuf-attach-dice (emoji)
"Attach random dice roll message."
- (interactive (list (funcall telega-completing-read-function
- "Dice Emoji: "
- telega--dice-emojis nil t)))
+ (interactive (list (telega-completing-read
+ "Dice Emoji: "
+ telega--dice-emojis nil t)))
(telega-chatbuf-input-insert
(list :@type "inputMessageDice"
:emoji emoji
@@ -5467,10 +5509,10 @@ Use this attachment to disable/enable notification on the receiver side."
Using this type of attachment it is possible to intermix multiple
markups in the chatbuf input.
Markups are defined in the `telega-chat-markup-functions' user option."
- (interactive (list (funcall telega-completing-read-function
- "Markup: "
- (mapcar #'car telega-chat-markup-functions)
- nil t)))
+ (interactive (list (telega-completing-read
+ "Markup: "
+ (mapcar #'car telega-chat-markup-functions)
+ nil t)))
(let ((markup-func (cdr (assoc markup-name telega-chat-markup-functions))))
(telega-chatbuf-input-insert
(telega-string-as-markup (or markup-text "") markup-name markup-func))
@@ -5485,14 +5527,13 @@ Markups are defined in the `telega-chat-markup-functions' user option."
"Attach something to the chatbuf input.
`\\[universal-argument]' is passed directly to the attachment function.
See `telega-chat-attach-commands' for available attachment types."
- (interactive
- (list (funcall telega-completing-read-function
- "Attachment type: "
- (mapcar #'car (seq-filter
- (lambda (cmd-spec)
- (telega-chatbuf-match-p (nth 1 cmd-spec)))
- telega-chat-attach-commands))
- nil t)))
+ (interactive (list (telega-completing-read
+ "Attachment type: "
+ (mapcar #'car (seq-filter
+ (lambda (cmd-spec)
+ (telega-chatbuf-match-p (nth 1 cmd-spec)))
+ telega-chat-attach-commands))
+ nil t)))
(let ((cmd (nth 2 (assoc attach-type telega-chat-attach-commands))))
(cl-assert (commandp cmd))
@@ -6348,13 +6389,13 @@ CALLBACK is called after point is moved to the message with MSG-ID."
(defun telega-chatbuf--read-filter (prompt msg-filter-specs)
"Read a message filter from MSG-FILTER-SPECS."
(let ((msg-filter-spec
- (assoc (funcall telega-completing-read-function
- prompt
- (mapcar #'car (cl-remove-if-not
- (lambda (spec)
- (telega-chatbuf-match-p (nth 1 spec)))
- msg-filter-specs))
- nil t)
+ (assoc (telega-completing-read
+ prompt
+ (mapcar #'car (cl-remove-if-not
+ (lambda (spec)
+ (telega-chatbuf-match-p (nth 1 spec)))
+ msg-filter-specs))
+ nil t)
msg-filter-specs)))
(list :title (nth 0 msg-filter-spec)
:tdlib-msg-filter (nth 2 msg-filter-spec))))
@@ -6481,8 +6522,8 @@ by some chat member, member name is queried."
"Show only messages marked with HASHTAG.
If `\\[universal-argument]' is given, then search for HASHTAG
sent by some chat member, member name is queried."
- (interactive (list (funcall telega-completing-read-function
- "Hashtag: #" (telega--searchHashtags ""))
+ (interactive (list (telega-completing-read
+ "Hashtag: #" (telega--searchHashtags ""))
current-prefix-arg))
(telega-chatbuf-filter-search
(concat (unless (string-prefix-p "#" hashtag) "#") hashtag)
diff --git a/telega-core.el b/telega-core.el
index 3acd656..836e745 100644
--- a/telega-core.el
+++ b/telega-core.el
@@ -893,7 +893,8 @@ Strips `line-prefix' and `wrap-prefix' text properties from copied text."
bstr))
(defmacro with-telega-help-win (buffer-or-name &rest body)
- "Execute BODY in help BUFFER-OR-NAME."
+ "Execute BODY in help BUFFER-OR-NAME.
+Return a buffer."
(declare (indent 1))
`(progn
;; (with-help-window ,buffer-or-name)
@@ -912,7 +913,8 @@ Strips `line-prefix' and `wrap-prefix' text properties from copied text."
;; (setq-local fill-column -1)
;; (visual-fill-column-mode 1)
- ,@body)))
+ ,@body
+ ,buffer-or-name)))
(defun telega-help-win--add-tdlib-callback (extra)
(setq telega--help-win-tdlib-callbacks
@@ -1457,7 +1459,7 @@ Properties specified in PROPS are retained on
"Change BUTTON to NEW-BUTTON."
(declare (indent 1))
(let ((newbutton (gensym "newbutton")))
- `(let ((inhibit-read-only t))
+ `(with-telega-buffer-modify
(goto-char (button-start ,button))
(let ((,newbutton ,new-button))
(delete-region (point) (button-end ,button))
@@ -1877,6 +1879,11 @@ If COLUMN is nil or less then current column, then current column is used."
(telega-ins--with-face '(:height 0.25)
(telega-ins "\n")))
+(defun telega-ins-describe-subsection (title)
+ "Insert a description subsection with TITLE."
+ (telega-ins--with-face 'telega-describe-subsection-title
+ (telega-ins title "\n")))
+
(defmacro telega-ins-describe-item (title &rest body)
"Describe item with TITLE."
(declare (indent 1))
diff --git a/telega-customize.el b/telega-customize.el
index 203c43c..817b8e6 100644
--- a/telega-customize.el
+++ b/telega-customize.el
@@ -215,6 +215,14 @@ Tracking notifications for telega buffers will use the
(or unmuted mention))
:group 'telega)
+(defcustom telega-image-transform-smoothing t
+ "Default value for the `:transform-smoothing' image property.
+If nil, then smoothing is applied only for downscaled images, if image
+is upscaled then nearest neighbor filter is used to show real pixels."
+ :package-version '(telega . "0.8.291")
+ :type 'boolean
+ :group 'telega)
+
(defcustom telega-use-images (or (and (fboundp 'image-transforms-p)
(funcall 'image-transforms-p))
(when (fboundp 'imagemagick-types)
@@ -1351,20 +1359,22 @@ Setting it to non-nil might introduce additional flickering in chatbuf."
:type 'boolean
:group 'telega-chat)
-(defcustom telega-chat-prompt-format
- '((:eval (telega-chatbuf-prompt-default-sender-avatar))
- (:eval (telega-chatbuf-prompt-body))
- (:eval (when (and telega-use-images
- (telega-chatbuf-match-p 'can-send-or-post))
- (telega-chatbuf-prompt-chat-avatar)))
- (:eval (telega-chatbuf-prompt-topic 25))
- (:eval (telega-auto-translate--chatbuf-prompt-translation))
- ">>> ")
- "*Modeline compatible format for the chatbuf input prompt.
+(defcustom telega-chat-prompt-insexp
+ '(telega-ins--with-face (unless (telega-chatbuf-match-p 'can-send-or-post)
+ 'telega-shadow)
+ (telega-chatbuf-prompt-ins-default-sender-avatar)
+ (telega-chatbuf-prompt-ins-body)
+ (when (or (telega-chatbuf-match-p 'has-default-sender)
+ (telega-chatbuf-match-p 'can-send-or-post))
+ (telega-chatbuf-prompt-ins-chat-avatar))
+ (telega-chatbuf-prompt-ins-topic 25)
+ (telega-auto-translate--chatbuf-prompt-ins-translation)
+ (telega-ins ">>> "))
+ "*Inserter sexp for the chatbuf's input prompt.
You can use `telega-chatbuf-editing-msg' or
-`telega-chatbuf-replying-msg' in `:eval' section if you want different
-prompt when editing/replying a message."
- :package-version '(telega . "0.7.101")
+`telega-chatbuf-replying-msg' functions if you want different prompt
+when editing/replying a message."
+ :package-version '(telega . "0.8.291")
:type 'sexp
:group 'telega-chat)
@@ -1642,11 +1652,18 @@ See `mode-line-buffer-identification'."
" " (telega-chatbuf-header-preview-mode)))
(:eval (telega-chatbuf-header-concat
" " (telega-chatbuf-header-highlight-text)))
- (:eval (telega-mode-line-align-right
- (telega-chatbuf-header-thread 30)
+ (:eval (telega-mode-line-align
+ 'center
+ (telega-chatbuf-header-concat
+ " " (telega-chabuf-header-unread-messages))
+ telega-chat-fill-column))
+ (:eval (telega-mode-line-align
+ 'right
+ (telega-chatbuf-header-concat
+ " " (telega-chatbuf-header-thread 30))
telega-chat-fill-column)))
"*Modeline compatible format for the chatbuf's header line."
- :package-version '(telega . "0.8.170")
+ :package-version '(telega . "0.8.291")
:type 'sexp
:group 'telega-chat)
@@ -1656,6 +1673,7 @@ See `mode-line-buffer-identification'."
(telega-ins "\n"))
(telega-chatbuf-footer-ins-sponsored-messages)
(telega-chatbuf-footer-ins-prompt-delim t t)
+ (telega-chatbuf-footer-ins-pending-join-requests)
(telega-chatbuf-footer-ins-action-bar)
(telega-chatbuf-footer-ins-active-vvnote)
(telega-chatbuf-footer-ins-active-video-chat)
@@ -1956,17 +1974,10 @@ Message is ignored if its `:ignore' option is set to non-nil."
:type 'number
:group 'telega-chat)
-(defcustom telega-completing-read-function
- ;; NOTE: `flex' completion style is essential for telega, because it
- ;; might prefix completions with the images and user won't be able
- ;; to complete without `flex' completion style
- (if (or (and (boundp 'ido-mode) (symbol-value 'ido-mode))
- (and (eq completing-read-function #'completing-read-default)
- (not (memq 'flex completion-styles))))
- 'ido-completing-read
- completing-read-function)
+(defcustom telega-completing-read-function completing-read-function
"Completing read function to use."
:type 'function
+ :package-version '(telega . "0.8.291")
:options '(ido-completing-read
ivy-completing-read
helm--completing-read-default)
@@ -2305,6 +2316,16 @@ If nil, then user's online status is not displayed."
:type 'string
:group 'telega-symbol)
+(defcustom telega-symbol-outline-close "▸"
+ "Symbol to be used for closed outlines."
+ :type 'string
+ :group 'telega-symbol)
+
+(defcustom telega-symbol-outline-open "▾"
+ "Symbol to be used for open outlines."
+ :type 'string
+ :group 'telega-symbol)
+
(defcustom telega-symbol-linked "⭾"
"Symbol used for linked chats button in modeline."
:type 'string
@@ -2575,6 +2596,12 @@ Used in one line message inserter."
invoice
leave-comment lightning lock location
member multiple-folders
+ (outline-close
+ (when (and telega-use-images (image-type-available-p 'svg))
+ (telega-etc-file-create-image "outline-close.svg" 1)))
+ (outline-open
+ (when (and telega-use-images (image-type-available-p 'svg))
+ (telega-etc-file-create-image "outline-open.svg" 1)))
pause pending phone photo pin poll play
(premium (when (and telega-use-images (image-type-available-p 'svg))
(telega-etc-file-create-image "symbols/premium.svg" 2)))
diff --git a/telega-filter.el b/telega-filter.el
index 4b7f9d0..7b0c241 100644
--- a/telega-filter.el
+++ b/telega-filter.el
@@ -640,9 +640,9 @@ If CHAT-TEMEX is ommited, then active chat filter from
(substring (symbol-name funsym)
(length "telega-filter-by-")))
(apropos-internal "^telega-filter-by-[a-z-]+" 'functionp))))
- (funcall telega-completing-read-function
- "Chat Filter: "
- (seq-uniq (nconc filter-names i-filter-names)) nil t))))
+ (telega-completing-read
+ "Chat Filter: "
+ (seq-uniq (nconc filter-names i-filter-names)) nil t))))
(let ((i-filter-fun-sym (intern (concat "telega-filter-by-" filter-name))))
(if (fboundp i-filter-fun-sym)
@@ -663,11 +663,10 @@ If `\\[universal-argument]' is specified, then negate whole active filter."
(defun telega-filter-by-type (ctype)
"Filter chats by CHAT-TYPE.
CHAT-TYPE is a symbol, one of `telega-chat-types'."
- (interactive
- (list (intern (funcall telega-completing-read-function
- "Chat type: "
- (mapcar #'symbol-name telega-chat-types)
- nil t))))
+ (interactive (list (intern (telega-completing-read
+ "Chat type: "
+ (mapcar #'symbol-name telega-chat-types)
+ nil t))))
(telega-filter-add (list 'type ctype)))
(defun telega-filter-by-name (regexp)
@@ -693,7 +692,7 @@ Use `telega-filter-by-name' for fuzzy searching."
(defun telega-filter-by-custom (name)
"Filter by custom chat filter."
(interactive (list (let ((completion-ignore-case t))
- (funcall telega-completing-read-function
+ (telega-completing-read
"Custom filter: "
(mapcar #'telega-filter--custom-name
telega-filters-custom)
@@ -730,7 +729,7 @@ Use `telega-filter-by-name' for fuzzy searching."
(defun telega-filter-by-online-status (status)
"Filter private chats by its user online STATUS."
(interactive (let ((completion-ignore-case t))
- (list (funcall telega-completing-read-function
+ (list (telega-completing-read
"User status: "
'("Online" "Recently" "LastWeek" "LastMonth"
"Offline" "Empty")
diff --git a/telega-folders.el b/telega-folders.el
index 322f6bd..16b0c49 100644
--- a/telega-folders.el
+++ b/telega-folders.el
@@ -211,7 +211,7 @@ This won't delete any chat, just a folder."
"Assign new name and icon to the folder with FOLDER-NAME."
(interactive (list (telega-completing-read-folder "Rename Folder: ")
(read-string "New Folder name: ")
- (when (y-or-n-p "Associate icon with the folder? ")
+ (when (y-or-n-p "Associate new icon with the folder? ")
(telega-completing-read-folder-icon-name
"Folder icon name: "))))
(let* ((folder-info (telega-folder--chat-folder-info folder-name))
@@ -342,7 +342,7 @@ migrate your custom labels %S to Telegram Folders." custom-labels))))
:count (length (telega-filter-chats telega--ordered-chats
(list 'folder folder-name))))
(when (plist-get folder-info :is_shareable)
- (telega-ins telega-symbol-nbsp "•" telega-symbol-nbsp)
+ (telega-ins " • ")
(telega-ins-i18n "lng_filters_shareable_status"))
(telega-ins ")"))
(telega-ins--move-to-column 35)
diff --git a/telega-info.el b/telega-info.el
index 6f1342a..fe7d075 100644
--- a/telega-info.el
+++ b/telega-info.el
@@ -96,10 +96,9 @@ If OFFLINE-P is non-nil, then do not send a request to telega-server."
:count nmonth)
(round (* nmonth 30.4))))
'(1 3 6 12)))
- (nmonth (funcall telega-completing-read-function
- (concat (telega-i18n "lng_settings_destroy_if")
- " ")
- (mapcar 'car choices) nil t))
+ (nmonth (telega-completing-read
+ (concat (telega-i18n "lng_settings_destroy_if") " ")
+ (mapcar 'car choices) nil t))
(days (cdr (assoc nmonth choices))))
(telega--setAccountTtl days)
@@ -234,7 +233,8 @@ If OFFLINE-P is non-nil, then do not send a request to telega-server."
(full-info (telega--full-info user))
(user-blocked-p (telega-user-match-p user 'is-blocked)))
(when (plist-get full-info :can_be_called)
- (telega-ins--box-button (concat (telega-symbol 'phone) "Call")
+ (telega-ins--box-button (concat (telega-symbol 'phone)
+ (telega-i18n "lng_call_start"))
:value user
:action #'telega-voip-call)
(telega-ins " "))
@@ -683,7 +683,26 @@ and chat permission restrictions"
chat (telega-user-me) my-status))
(t
(user-error "Not yet implemented"))))))
- (telega-ins " " (telega-i18n (cdr perm-spec))))))))))
+ (telega-ins " " (telega-i18n (cdr perm-spec))))))))
+
+ (when owner-p
+ (telega-ins-describe-item
+ (telega-i18n "lng_manage_peer_no_forwards")
+ (telega-ins--text-button
+ (if (plist-get chat :has_protected_content)
+ (telega-symbol 'checkbox-on)
+ (telega-symbol 'checkbox-off))
+ 'face 'telega-link
+ 'action (lambda (_ignored)
+ (telega--toggleChatHasProtectedContent
+ chat (not (plist-get chat :has_protected_content)))))
+ (telega-ins "\n")
+ (telega-ins--help-message
+ (telega-ins-i18n (if channel-p
+ "lng_manage_peer_no_forwards_about_channel"
+ "lng_manage_peer_no_forwards_about"))
+ nil)))
+ ))
(when (plist-get my-perms :can_change_info)
;; All history setting is available to supergroups only, in
@@ -728,7 +747,7 @@ and chat permission restrictions"
(telega-ins-i18n "lng_manage_history_visibility_hidden_about")
nil)))))
- ;; Sign messages is available in channels only
+ ;; Channel specific settings
(when (telega-chat-channel-p chat)
(telega-ins-describe-item (telega-i18n "lng_edit_sign_messages")
(telega-ins--text-button (if (plist-get supergroup :sign_messages)
@@ -758,8 +777,29 @@ and chat permission restrictions"
;; NOTE: No trailing newline
nil)))
- ;; Slow Mode is available only for supergroups
+ ;; Ordinary supergroup settings
(unless (telega-chat-channel-p chat)
+ (when (plist-get my-perms :can_restrict_members)
+ (telega-ins-describe-item
+ (telega-i18n "lng_manage_peer_send_approve_members")
+ (telega-ins--text-button (if (plist-get supergroup :join_by_request)
+ (telega-symbol 'checkbox-on)
+ (telega-symbol 'checkbox-off))
+ 'face 'telega-link
+ 'action (lambda (_ignored)
+ (telega--toggleSupergroupJoinByRequest
+ supergroup
+ (not (plist-get supergroup :join_by_request)))))
+ (when-let ((join-requests (plist-get chat :pending_join_requests)))
+ (telega-ins " ")
+ (telega-ins--pending-join-requests join-requests))
+ (telega-ins "\n")
+ (telega-ins--help-message
+ (telega-ins-i18n "lng_manage_peer_send_approve_members_about")
+ ;; NOTE: No trailing newline
+ nil))
+ )
+
(let* ((slow-mode-delay (plist-get full-info :slow_mode_delay))
(smd-str (if (zerop slow-mode-delay)
(telega-i18n "lng_rights_slowmode_off")
@@ -869,13 +909,7 @@ and chat permission restrictions"
(telega-ins--box-button (telega-i18n "telega_show")
:value chat
:action #'telega-describe-chat-members)))
-
- (when (and (listp telega-debug) (memq 'info telega-debug))
- (insert "\n---DEBUG---\n")
- (insert (propertize "Info: " 'face 'bold)
- (format "%S" supergroup) "\n")
- (insert (propertize "Full-Info: " 'face 'bold)
- (format "%S" full-info) "\n"))))
+ ))
(defun telega-describe-connected-websites (&optional websites)
"Describe connected WEBSITES."
@@ -1046,15 +1080,6 @@ Call CALLBACK on updates."
;; to track ping timeouts
(run-with-timer 10 nil callback))))
-(defun telega--enableProxy (proxy)
- (telega-server--call
- (list :@type "enableProxy"
- :proxy_id (plist-get proxy :id))))
-
-(defun telega--disableProxy ()
- (telega-server--send
- (list :@type "disableProxy")))
-
(defun telega-proxy-last-used (&optional proxies)
"Return last time used proxy."
(car (cl-sort (or (copy-sequence proxies) (telega--getProxies))
diff --git a/telega-ins.el b/telega-ins.el
index df5f9b1..7bd5b26 100644
--- a/telega-ins.el
+++ b/telega-ins.el
@@ -393,7 +393,7 @@ If WITH-AVATAR-P is 2, then insert 2 lines version of an avatar."
(when with-username-p
(when-let ((username (telega-msg-sender-username msg-sender 'with-@)))
(telega-ins--with-face 'telega-shadow
- (telega-ins telega-symbol-nbsp "•" telega-symbol-nbsp))
+ (telega-ins " • "))
(telega-ins--with-face (if (facep with-username-p)
with-username-p
title-faces)
@@ -480,7 +480,11 @@ If WITH-AVATAR-P is 2, then insert 2 lines version of an avatar."
MEMBER specifies corresponding \"ChatMember\" object.
If SHOW-PHONE-P is non-nil, then show USER's phone number."
(let ((avatar (telega-msg-sender-avatar-image user))
- (off-column (telega-current-column)))
+ ;; NOTE: Do not use `telega-current-column', because
+ ;; `telega-ins--user' might be used under
+ ;; `telega-ins--line-wrap-prefix' and `telega-current-column'
+ ;; accounts line/wrap prefix
+ (off-column (current-column)))
(telega-ins--image avatar 0
:no-display-if (not telega-user-show-avatars))
(telega-ins--msg-sender user
@@ -495,7 +499,7 @@ If SHOW-PHONE-P is non-nil, then show USER's phone number."
(when show-phone-p
(when-let ((phone-number (telega-tl-str user :phone_number)))
(telega-ins--with-face 'telega-shadow
- (telega-ins telega-symbol-nbsp "•" telega-symbol-nbsp))
+ (telega-ins " • "))
(telega-ins "+" phone-number)))
;; Insert (him)in<-->out(me) relationship
@@ -509,7 +513,7 @@ If SHOW-PHONE-P is non-nil, then show USER's phone number."
(telega-ins--image avatar 1
:no-display-if (not telega-user-show-avatars))
;; Setup `off-column' for "invited by" string
- (setq off-column (telega-current-column))
+ (setq off-column (current-column))
(telega-ins--user-status user)
(when-let ((join-date (plist-get member :joined_chat_date)))
@@ -1315,14 +1319,14 @@ Return `non-nil' if WEB-PAGE has been inserted."
(when (and user with-username-p)
(when-let ((username (telega-msg-sender-username user 'with-@)))
(telega-ins--with-face 'telega-shadow
- (telega-ins telega-symbol-nbsp "•" telega-symbol-nbsp))
+ (telega-ins " • "))
(telega-ins--with-face 'telega-username
(telega-ins username))))
(when-let* ((with-phone-p with-phone-p)
(phone-number (telega-tl-str contact :phone_number)))
(telega-ins--with-face 'telega-shadow
- (telega-ins telega-symbol-nbsp "•" telega-symbol-nbsp))
+ (telega-ins " • "))
(telega-ins (unless (string-prefix-p "+" phone-number) "+") phone-number))
t))
@@ -3785,25 +3789,6 @@ Short version."
(cl-assert last-msg)
(telega-ins--message-with-chat-header last-msg)))
-(defun telega-ins--root-msg (msg)
- "Inserter for message MSG shown in `telega-root-messages--ewoc'."
- (let ((chat (telega-msg-chat msg))
- (telega-chat-button-width
- (round (* (telega-canonicalize-number telega-chat-button-width
- telega-root-fill-column)
- (/ 2.0 3)))))
- (telega-ins--chat chat)
- (telega-ins " ")
- (telega-ins--chat-msg-one-line chat msg)))
-
-(defun telega-ins--root-msg-call (msg)
- "Inserter for call message MSG in rootbuf."
- (let ((telega-chat-fill-column telega-root-fill-column)
- (telega-msg-heading-with-date-and-status t))
- (telega-ins--message msg
- :sender (when (telega-msg-match-p msg 'outgoing)
- (telega-chat-user (telega-msg-chat msg))))))
-
(defun telega-ins--chat-my-restrictions (chat)
"Insert my restrictions (if any) in the CHAT.
Return non-nil if restrictions has been inserted."
@@ -3845,64 +3830,55 @@ Return non-nil if restrictions has been inserted."
)
t))))
+(defun telega-ins--pending-join-requests (pending-join-requests)
+ "Inserter for the PENDING-JOIN-REQUESTS."
+ (seq-doseq (user-id (plist-get pending-join-requests :user_ids))
+ (telega-ins--image
+ (telega-msg-sender-avatar-image-one-line (telega-user-get user-id))))
+ (telega-ins " ")
+ (telega-ins--text-button
+ (telega-i18n "lng_group_requests_pending"
+ :count (plist-get pending-join-requests :total_count))
+ 'face 'telega-link
+ 'action (lambda (_button)
+ (message "TODO: describe pending requests")))
+ t)
+
+
+(defun telega-ins--root-msg (msg)
+ "Inserter for message MSG shown in `telega-root-messages--ewoc'."
+ (let ((chat (telega-msg-chat msg))
+ (telega-chat-button-width
+ (round (* (telega-canonicalize-number telega-chat-button-width
+ telega-root-fill-column)
+ (/ 2.0 3)))))
+ (telega-ins--chat chat)
+ (telega-ins " ")
+ (telega-ins--chat-msg-one-line chat msg)))
+
+(defun telega-ins--root-msg-call (msg)
+ "Inserter for call message MSG in rootbuf."
+ (let ((telega-chat-fill-column telega-root-fill-column)
+ (telega-msg-heading-with-date-and-status t))
+ (telega-ins--message msg
+ :sender (when (telega-msg-match-p msg 'outgoing)
+ (telega-chat-user (telega-msg-chat msg))))))
+
(defun telega-ins--sponsored-message (sponsored-msg)
"Inserter for the SPONSORED-MSG."
(let* ((sponsor (plist-get sponsored-msg :sponsor))
- (sponsor-type (plist-get sponsor :type))
(chat-photo-info (plist-get sponsor :photo)))
(when chat-photo-info
(telega-ins--image
(telega-chat-photo-info-image-one-line chat-photo-info)))
- (cl-assert sponsor)
- (cl-ecase (telega--tl-type sponsor-type)
- (messageSponsorTypeBot
- (let ((user (telega-user-get (plist-get sponsor-type :bot_user_id))))
- (telega-ins--msg-sender user
- :with-avatar-p nil
- :with-username-p t
- :with-brackets-p nil)))
-
- (messageSponsorTypeWebApp
- (telega-ins (telega-tl-str sponsor-type :web_app_title)))
-
- (messageSponsorTypePublicChannel
- (let ((chat (telega-chat-get (plist-get sponsor-type :chat_id))))
- (telega-ins--msg-sender chat
- :with-avatar-p nil
- :with-username-p 'telega-username
- :with-brackets-p nil)))
-
- (messageSponsorTypePrivateChannel
- (telega-ins (telega-tl-str sponsor-type :title)))
-
- (messageSponsorTypeWebsite
- (telega-ins--with-face 'telega-webpage-sitename
- (telega-ins (telega-tl-str sponsor-type :name)))))
- (telega-ins "\n")
-
(telega-ins--with-face 'telega-msg-sponsored
(telega-ins--content sponsored-msg))
(telega-ins "\n")
- ;; Link
- (cl-ecase (telega--tl-type sponsor-type)
- (messageSponsorTypeBot
- (telega-ins--box-button (telega-i18n "lng_view_button_bot")
- 'action 'telega-msg-open-sponsored))
-
- (messageSponsorTypeWebApp
- (telega-ins--box-button (telega-i18n "lng_open_link")
- 'action 'telega-msg-open-sponsored))
-
- ((messageSponsorTypePublicChannel
- messageSponsorTypePrivateChannel)
- (telega-ins--box-button (telega-i18n "lng_view_button_channel")
- 'action 'telega-msg-open-sponsored))
+ (telega-ins--box-button (telega-i18n "lng_open_link")
+ 'action #'telega-sponsored-msg--action)
- (messageSponsorTypeWebsite
- (telega-ins--box-button (telega-i18n "lng_view_button_external_link")
- 'action 'telega-msg-open-sponsored)))
(telega-ins "\n")))
(defun telega-ins--msg-reaction-type (reaction-type)
diff --git a/telega-match.el b/telega-match.el
index 6d60ceb..06bfd03 100644
--- a/telega-match.el
+++ b/telega-match.el
@@ -670,14 +670,17 @@ BE AWARE: This filter will do blocking request for every chat."
You don't need te be a chat member to be able to send messages.
Chat might not be known (i.e. in your Main or Archive list) to post
messages into it. Use `is-known' chat temex to check chat is known."
- (or (let ((my-perms (telega-chat-member-my-permissions chat)))
- (or (plist-get my-perms :can_send_basic_messages)
- (plist-get my-perms :can_post_messages)))
-
- ;; Also, it is possible to send message to discussion group
- ;; without joining it
- (and (telega-chat-match-p chat '(type supergroup))
- (not (plist-get (telega-chat--info chat) :join_to_send_messages)))))
+ (and (or (telega-chat-match-p chat '(type private secret))
+ (telega-chat-match-p chat 'me-is-member)
+ ;; Also, it is possible to send message to discussion group
+ ;; without joining it
+ (and (telega-chat-match-p chat '(type supergroup))
+ (not (plist-get (telega-chat--supergroup-locally chat)
+ :join_to_send_messages))))
+
+ (let ((my-perms (telega-chat-member-my-permissions chat)))
+ (or (plist-get my-perms :can_send_basic_messages)
+ (plist-get my-perms :can_post_messages)))))
;;; ellit-org: chat-temex
;; - is-inline-bot ::
diff --git a/telega-modes.el b/telega-modes.el
index 4d5369c..f73c49a 100644
--- a/telega-modes.el
+++ b/telega-modes.el
@@ -1080,9 +1080,17 @@ UFILE specifies Telegram file being uploading."
t)))
(unless edit-file-buffers
(user-error "No files opened from telega"))
- (list (funcall telega-completing-read-function
- "Telega Edit File: " edit-file-buffers
- nil t nil 'buffer-name-history))))
+ ;; TODO: Probably use `read-buffer' with a predicate?
+ ;; Something like:
+ ;; (read-buffer "Telega Edit File: " nil t
+ ;; (lambda (val)
+ ;; (when (consp val)
+ ;; (setq val (car val)))
+ ;; (cl-assert (stringp val))
+ ;; (member val edit-file-buffers)))
+ (list (telega-completing-read
+ "Telega Edit File: " edit-file-buffers
+ nil t nil 'buffer-name-history))))
(switch-to-buffer buffer))
@@ -1861,20 +1869,19 @@ Or nil if translation is not needed."
(plist-put msg :telega-translated nil)
(telega-auto-translate--on-msg-insert msg))
-(defun telega-auto-translate--chatbuf-prompt-translation ()
- "Addon to chatbuf prompt in case `telega-auto-translate-mode' is enabled."
+(defun telega-auto-translate--chatbuf-prompt-ins-translation ()
+ "Inserter to chatbuf prompt in case `telega-auto-translate-mode' is enabled."
(when (and telega-auto-translate-mode
telega-chatbuf-language-code
telega-translate-to-language-by-default
(not (equal telega-chatbuf-language-code
telega-translate-to-language-by-default)))
- (telega-ins--as-string
- (telega-ins--with-face 'telega-shadow
- (telega-ins "["
- telega-translate-to-language-by-default
- (telega-symbol 'right-arrow)
- telega-chatbuf-language-code
- "]")))))
+ (telega-ins--with-face 'telega-shadow
+ (telega-ins "["
+ telega-translate-to-language-by-default
+ (telega-symbol 'right-arrow)
+ telega-chatbuf-language-code
+ "]"))))
(defvar telega-auto-translate-mode-lighter
(concat " " (telega-symbol 'mode) "Translate")
diff --git a/telega-msg.el b/telega-msg.el
index ff9b99a..5a8ac16 100644
--- a/telega-msg.el
+++ b/telega-msg.el
@@ -69,6 +69,11 @@
:help "Unmark the message"
:visible (telega-msg-marked-p (telega-msg-at-down-mouse-3))))
(bindings--define-key menu-map [s0] menu-bar-separator)
+ (bindings--define-key menu-map [add-tags]
+ '(menu-item (telega-i18n "lng_add_tag_button") telega-msg-add-reaction
+ :help "Add tag to the message"
+ :visible (telega-msg-match-p (telega-msg-at-down-mouse-3)
+ '(chat saved-messages))))
(bindings--define-key menu-map [add-favorite]
'(menu-item "Add to Favorites" telega-msg-favorite-toggle
:help "Add message to the list of favorite messages"
@@ -901,37 +906,6 @@ non-nil."
(telega-ins "\n")))))
(telega-ins "\n"))))))))
-(defun telega-msg-open-sponsored (sponsored-msg)
- "Open sponsored message SPONSORED-MSG."
- (telega--clickChatSponsoredMessage telega-chatbuf--chat sponsored-msg)
- (let* ((sponsor (plist-get sponsored-msg :sponsor))
- (sponsor-type (plist-get sponsor :type)))
- (cl-ecase (telega--tl-type sponsor-type)
- (messageSponsorTypeBot
- )
- (messageSponsorTypeWebApp
- )
- (messageSponsorTypePublicChannel
- (let ((chat (telega-chat-get (plist-get sponsor-type :chat_id))))
- (telega-ins--msg-sender chat
- :with-avatar-p nil
- :with-username-p t
- :with-brackets-p t)))
-
- (messageSponsorTypePrivateChannel
- (telega-ins (telega-tl-str sponsor-type :title)))
-
- (messageSponsorTypeWebsite
- (telega-browse-url (plist-get sponsor-type :url)))
- ))
-
- (if-let ((tdlib-link (plist-get sponsored-msg :link)))
- (telega-tme-open-tdlib-link tdlib-link)
-
- (when-let ((schat (telega-chat-get
- (plist-get sponsored-msg :sponsor_chat_id) t)))
- (telega-chat--pop-to-buffer schat))))
-
(defun telega-describe--giveaway-info (msg ga-info)
(with-telega-help-win "*Telegram Giveaway Info*"
(let* ((content (plist-get msg :content))
@@ -1166,16 +1140,14 @@ preview, having media content, can be opened with media timestamp."
(defun telega-msg-sender (tl-obj)
"Convert given TL-OBJ to message sender (a chat or a user).
-TL-OBJ could be a \"message\", \"sponsoredMessage\", \"chatMember\",
-\"messageSender\" or \"chatMessageSender\". Return a user or a chat."
+TL-OBJ could be a \"message\", \"chatMember\", \"messageSender\" or
+\"chatMessageSender\".
+Return a user or a chat."
(let ((sender (cl-ecase (telega--tl-type tl-obj)
(chatMessageSender
(when (or (not (plist-get tl-obj :needs_premium))
(plist-get telega--options :is_premium))
(plist-get tl-obj :sender)))
- (sponsoredMessage
- (list :@type "messageSenderChat"
- :chat_id (plist-get tl-obj :sponsor_chat_id)))
(message (plist-get tl-obj :sender_id))
(chatMember (plist-get tl-obj :member_id))
((messageSenderUser messageSenderChat) tl-obj))))
@@ -1952,10 +1924,15 @@ Requires administrator rights in the chat."
(when (and (listp telega-debug) (memq 'info telega-debug))
(let ((print-length nil))
- (telega-ins "\n---DEBUG---\n")
- (telega-ins-fmt "MsgSexp: (telega-msg-get (telega-chat-get %d) %d)\n"
+ (telega-ins "\n")
+ (telega-ins-describe-section "DEBUG")
+ (telega-ins--with-face 'bold
+ (telega-ins "MsgSexp: "))
+ (telega-ins-fmt "(telega-msg-get (telega-chat-get %d) %d)\n"
chat-id msg-id)
- (telega-ins-fmt "Message: %S\n" msg)))
+ (telega-ins--with-face 'bold
+ (telega-ins "Message: "))
+ (telega-ins-fmt "%S\n" msg)))
)))
(defun telega-ignored-messages ()
@@ -1973,20 +1950,18 @@ Requires administrator rights in the chat."
"Display public forwards for the message MSG."
(interactive (list (telega-msg-at (point))))
(let* ((reply (telega--getMessagePublicForwards msg))
- (public-fwd-messages (append (plist-get reply :messages) nil)))
- (unless public-fwd-messages
- (error "No forwardings to public channels for this message"))
-
- (with-help-window "*Telegram Public Forwards*"
- (set-buffer standard-output)
- (let ((inhibit-read-only t))
- (telega-ins (propertize "Total Messages:" 'face 'bold) " "
- (int-to-string (plist-get reply :total_count)) "\n")
- (dolist (fwd-msg public-fwd-messages)
+ (public-fwd-messages (plist-get reply :messages)))
+ (when (seq-empty-p public-fwd-messages)
+ (error "telega: No forwardings to public channels for this message"))
+
+ (with-telega-help-win "*Telegram Public Forwards*"
+ (telega-ins-describe-item "Total Messages"
+ (telega-ins-fmt "%d" (plist-get reply :total_count))
+ (seq-doseq (fwd-msg public-fwd-messages)
+ (telega-ins "\n")
(telega-button--insert 'telega-msg fwd-msg
:inserter #'telega-ins--message-with-chat-header)
- (telega-ins "\n")))
- (goto-char (point-min)))))
+ )))))
(defun telega-msg-diff-edits (msg)
"Display edits to MSG user did."
@@ -2360,6 +2335,13 @@ use `telega-sponsored-msg-for-interactive' instead."
(telega-sponsored-msg-at (point)))))
msg))
+(defun telega-sponsored-msg--action (button)
+ "Open sponsored message SPONSORED-MSG."
+ (let ((sponsored-msg (telega-sponsored-msg-at button)))
+ (telega--clickChatSponsoredMessage telega-chatbuf--chat sponsored-msg)
+ (let ((sponsor (plist-get sponsored-msg :sponsor)))
+ (telega-browse-url (plist-get sponsor :url)))))
+
(defun telega-sponsored-msg-hide (sponsored-msg)
"Hide SPONSORED-MSG in the chatbuf footer."
(interactive (list (telega-sponsored-msg-for-interactive)))
@@ -2375,47 +2357,13 @@ use `telega-sponsored-msg-for-interactive' instead."
(with-telega-help-win "*Telegram Sponsor Info*"
(telega-ins-describe-item "Id"
(telega-ins-fmt "%d" (plist-get sponsored-msg :message_id)))
- (let* ((sponsor (plist-get sponsored-msg :sponsor))
- (sponsor-type (plist-get sponsor :type)))
- (telega-ins-describe-item "Sponsor"
- (telega-ins (substring (plist-get sponsor-type :@type)
- (length "messageSponsorType"))))
- (telega-ins-describe-item "Info"
- (telega-ins--line-wrap-prefix " "
- (telega-ins (telega-tl-str sponsor :info))))
- (cl-ecase (telega--tl-type sponsor-type)
- (messageSponsorTypeBot
- (let ((bot (telega-user-get (plist-get sponsor-type :bot_user_id))))
- (telega-ins-describe-item "Bot User"
- (telega-ins--raw-button
- (telega-link-props 'sender bot 'type 'telega)
- (telega-ins--msg-sender bot
- :with-avatar-p t
- :with-username-p 'telega-username
- :with-brackets-p t)))))
- (messageSponsorTypeWebApp
- (telega-ins-describe-item "Title"
- (telega-ins (telega-tl-str sponsor-type :web_app_title))))
- (messageSponsorTypePublicChannel
- (let ((channel (telega-chat-get (plist-get sponsor-type :chat_id))))
- (telega-ins-describe-item "Channel"
- (telega-ins--raw-button
- (telega-link-props 'sender channel 'type 'telega)
- (telega-ins--msg-sender channel
- :with-avatar-p t
- :with-username-p 'telega-username
- :with-brackets-p t)))))
- (messageSponsorTypePrivateChannel
- (telega-ins-describe-item "Channel Title"
- (telega-ins (telega-tl-str sponsor-type :title)))
- (telega-ins-describe-item "Invite Link"
- (telega-ins (telega-tl-str sponsor-type :invite_link))))
- (messageSponsorTypeWebsite
- (telega-ins-describe-item "Name"
- (telega-ins (telega-tl-str sponsor-type :name)))
- (telega-ins-describe-item "URL"
- (telega-ins (telega-tl-str sponsor-type :url))))
- ))
+ (let ((sponsor (plist-get sponsored-msg :sponsor)))
+ (when-let ((sponsor-info (telega-tl-str sponsor :info)))
+ (telega-ins-describe-item "Sponsor Info"
+ (telega-ins--line-wrap-prefix " "
+ (telega-ins sponsor-info))))
+ (telega-ins-describe-item "Sponsor URL"
+ (telega-ins (telega-tl-str sponsor :url))))
(when-let ((add-info (telega-tl-str sponsored-msg :additional_info)))
(telega-ins-describe-item "Additional Info"
(telega-ins add-info)))
diff --git a/telega-obsolete.el b/telega-obsolete.el
index 0f45a6f..3ded368 100644
--- a/telega-obsolete.el
+++ b/telega-obsolete.el
@@ -273,6 +273,9 @@
'telega-chat-footer-insexp
"0.8.256")
+(telega-obsolete--variable 'telega-chat-prompt-format
+ 'telega-chat-prompt-insexp
+ "0.8.291")
;; Check some obsolete var/fun is used
(cl-eval-when (eval load)
diff --git a/telega-sort.el b/telega-sort.el
index d1c4cc4..bd790b9 100644
--- a/telega-sort.el
+++ b/telega-sort.el
@@ -120,10 +120,11 @@ CRITERIA could be a lit of sort criterias."
If prefix ARG is used, then add sort criteria, instead of
overwriting currently active one."
(interactive
- (let ((cname (funcall telega-completing-read-function
- "Sort criteria: "
- (mapcar 'symbol-name
- (mapcar 'car telega-sort-criteria-alist)))))
+ (let ((cname (telega-completing-read
+ "Sort criteria: "
+ (mapcar 'symbol-name
+ (mapcar 'car telega-sort-criteria-alist))
+ nil t)))
(list (intern cname) current-prefix-arg)))
(telega-sort-set-active-criteria
diff --git a/telega-sticker.el b/telega-sticker.el
index 51ae160..52de883 100644
--- a/telega-sticker.el
+++ b/telega-sticker.el
@@ -717,8 +717,7 @@ Return sticker set."
(lambda ()
(add-hook 'post-command-hook
'telega-stickerset--minibuf-post-command t t))
- (funcall telega-completing-read-function
- prompt telega-minibuffer--choices nil t))))
+ (telega-completing-read prompt telega-minibuffer--choices nil t))))
(cl-find (cadr (assoc sset-name telega-minibuffer--choices)) ssets
:test #'equal
diff --git a/telega-tdlib-events.el b/telega-tdlib-events.el
index 9636312..4eff1b6 100644
--- a/telega-tdlib-events.el
+++ b/telega-tdlib-events.el
@@ -1610,6 +1610,14 @@ Please downgrade TDLib and recompile `telega-server'"
(defun telega--on-updateChatRemovedFromList (event)
)
+(defun telega--on-updateChatPendingJoinRequests (event)
+ (let ((chat (telega-chat-get (plist-get event :chat_id) 'offline)))
+ (cl-assert chat)
+ (plist-put chat :pending_join_requests
+ (plist-get event :pending_join_requests))
+
+ (telega-chat--mark-dirty chat event)))
+
(provide 'telega-tdlib-events)
;;; telega-tdlib-events.el ends here
diff --git a/telega-tdlib.el b/telega-tdlib.el
index b0dee40..ca0463e 100644
--- a/telega-tdlib.el
+++ b/telega-tdlib.el
@@ -86,10 +86,33 @@ If SYNC-P is specified, then set option is sync manner."
(type-of val))))
:value (or val :false)))))
-(defun telega--addProxy (proxy-spec)
+(defun telega--addProxy (proxy-spec &optional callback)
"Add PROXY-SPEC to the list of proxies."
- (telega-server--send
- `(:@type "addProxy" ,@proxy-spec)))
+ (telega-server--call
+ `(:@type "addProxy" ,@proxy-spec)
+ (or callback #'ignore)))
+
+(defun telega--enableProxy (proxy &optional callback)
+ (declare (indent 1))
+ (telega-server--call
+ (list :@type "enableProxy"
+ :proxy_id (plist-get proxy :id))
+ (or callback #'ignore)))
+
+(defun telega--disableProxy (&optional callback)
+ (declare (indent 1))
+ (telega-server--call
+ (list :@type "disableProxy")
+ (or callback #'ignore)))
+
+(defun telega--pingProxy (proxy &optional callback)
+ "Get time needed to receive a response from a Telegram server through a PROXY.
+If PROXY is nil, then ping a Telegram server without a proxy."
+ (declare (indent 1))
+ (telega-server--call
+ (list :@type "pingProxy"
+ :proxy_id (or (plist-get proxy :id) 0))
+ callback))
(defun telega--searchEmojis (text &optional exact-match-p
language-codes callback)
@@ -230,6 +253,12 @@ Requires owner right."
:supergroup_id (plist-get supergroup :id)
:sign_messages (if sign-messages-p t :false))))
+(defun telega--toggleSupergroupJoinByRequest (supergroup join-by-request-p)
+ (telega-server--send
+ (list :@type "toggleSupergroupJoinByRequest"
+ :supergroup_id (plist-get supergroup :id)
+ :join_by_request (if join-by-request-p t :false))))
+
(defun telega--toggleSupergroupIsAllHistoryAvailable (supergroup all-history-available-p)
(telega-server--send
(list :@type "toggleSupergroupIsAllHistoryAvailable"
@@ -980,11 +1009,9 @@ CHAT must be supergroup or channel."
(defun telega--getProxies (&optional callback)
"Return list of currently registered proxies."
- (with-telega-server-reply (reply)
- (append (plist-get reply :proxies) nil)
-
- (list :@type "getProxies")
- callback))
+ (telega-server--call
+ (list :@type "getProxies")
+ callback))
(defun telega--pinChatMessage (msg &optional disable-notifications only-for-self)
"Pin message MSG.
@@ -1305,11 +1332,12 @@ LIMIT - limit number of photos (default=100)."
:first_name (or first-name "")
:last_name (or last-name ""))))
-(defun telega--setBio (bio)
+(defun telega--setBio (bio &optional callback)
"Set me bio to BIO."
- (telega-server--send
+ (telega-server--call
(list :@type "setBio"
- :bio (or bio ""))))
+ :bio (or bio ""))
+ (or callback #'ignore)))
(defun telega--setUsername (username)
"Set me username to USERNAME.
@@ -2233,13 +2261,12 @@ be marked as read."
(list :@type "readChatList"
:chat_list tdlib-chat-list)))
-(defun telega--toggleChatHasProtectedContent (chat)
+(defun telega--toggleChatHasProtectedContent (chat has-protected-content-p)
"Toogle ability of users to save, forward, or copy CHAT content."
(telega-server--send
(list :@type "toggleChatHasProtectedContent"
:chat_id (plist-get chat :id)
- :has_protected_content
- (if (plist-get chat :has_protected_content) :false t))))
+ :has_protected_content (if has-protected-content-p t :false))))
(defun telega--toggleChatIsMarkedAsUnread (chat)
"Toggle marked as read state of the CHAT."
@@ -2695,6 +2722,13 @@ TO-LANGUAGE-CODE is a two-letter ISO 639-1 language code. "
:type tdlib-network-type)
(or callback 'ignore)))
+(defun telega--getNetworkStatistics (&optional only-current-p callback)
+ (declare (indent 1))
+ (telega-server--call
+ (list :@type "getNetworkStatistics"
+ :only_current (if only-current-p t :false))
+ callback))
+
;; Autodownload
(defun telega--getAutoDownloadSettingsPresets (&optional callback)
"Return auto-download settings presets for me."
@@ -3173,6 +3207,21 @@ Saved Messages topic is specified by SM-TOPIC-ID."
(telega-server--send
(list :@type "hideContactCloseBirthdays")))
+(defun telega--toggleHasSponsoredMessagesEnabled (enable-p &optional callback)
+ (telega-server--call
+ (list :@type "toggleHasSponsoredMessagesEnabled"
+ :has_sponsored_messages_enabled (if enable-p t :false))
+ (or callback #'ignore)))
+
+(defun telega--toggleSupergroupCanHaveSponsoredMessages
+ (supergroup enable-p &optional callback)
+ "Toggles whether sponsored messages are shown in the channel chat."
+ (telega-server--call
+ (list :@type "toggleHasSponsoredMessagesEnabled"
+ :supergroup_id (plist-get supergroup :id)
+ :can_have_sponsored_messages (if enable-p t :false))
+ (or callback #'ignore)))
+
(provide 'telega-tdlib)
;;; telega-tdlib.el ends here
diff --git a/telega-tme.el b/telega-tme.el
index d2ec68b..99f56c3 100644
--- a/telega-tme.el
+++ b/telega-tme.el
@@ -188,11 +188,49 @@ PARAMS are additional params."
(when chat
(telega-chat--pop-to-buffer chat))))
-(defun telega-tme-open-proxy (_type _proxy)
+(defun telega-tme-open-proxy-tdlib-link (tdlib-link)
+ "Add a proxy defined by internal TDLIB-LINK."
+ (let ((help-window-select t))
+ (with-telega-help-win "*Telega Add Proxy*"
+ (telega-ins-describe-section (telega-i18n "lng_proxy_add"))
+ ;; NOTE: Only MTPROTO proxies may add sponsor channel
+ (when (eq 'proxyTypeMtproto
+ (telega--tl-type (plist-get tdlib-link :type)))
+ (telega-ins--help-message
+ (telega-ins-i18n "lng_proxy_sponsor_warning")))
+ (telega-ins-describe-item "Server"
+ (telega-ins (telega-tl-str tdlib-link :server)))
+ (telega-ins-describe-item "Port"
+ (telega-ins-fmt "%d" (plist-get tdlib-link :port)))
+ (telega-ins--box-button (telega-i18n "lng_proxy_add")
+ 'action (lambda-with-current-buffer (_button)
+ (kill-buffer-and-window)
+ (telega--addProxy
+ (list :server (telega-tl-str tdlib-link :server)
+ :port (plist-get tdlib-link :port)
+ :type (plist-get tdlib-link :type))
+ (lambda (_proxy)
+ (telega-describe-network)))))
+ )))
+
+(defun telega-tme-open-proxy (type proxy)
"Open the PROXY."
;; TYPE is "socks" or "proxy"
;; :server, :port, :user, :pass, :secret
- (message "TODO: `telega-tme-open-proxy'")
+ (message "TODO: `telega-tme-open-proxy' %S / %S" type proxy)
+ (telega-tme-open-proxy-tdlib-link
+ (list :@type "internalLinkTypeProxy"
+ :server (plist-get proxy :server)
+ :port (string-to-number (plist-get proxy :port))
+ :type (cond ((string= type "proxy")
+ (list :@type "proxyTypeMtproto"
+ :secret (plist-get proxy :secret)))
+ ((string= type "socks")
+ (list :@type "proxyTypeSocks5"
+ :username (plist-get proxy :user)
+ :password (plist-get proxy :pass)))
+ (t
+ (error "Unknown proxy type: %S" type)))))
)
(defun telega-tme-open-stickerset (setname)
@@ -325,8 +363,6 @@ Return non-nil if url has been handled."
(concat "tg:addtheme?slug=" (match-string 1 path)))
((string-match "^/share/url$" path)
(concat "tg:msg_url?" query))
- ((string-match "^/\\(socks\\|proxy\\)$" path)
- (concat "tg:" (match-string 1 path) "?" query))
((string-match
(eval-when-compile
(rx (and line-start "/c/"
@@ -476,6 +512,9 @@ To convert url to TDLib link, use `telega--getInternalLinkType'."
(message "Webapp info: %S" web-app-info)
(telega-browse-url (plist-get web-app-info :url))))
)))
+
+ (internalLinkTypeProxy
+ (telega-tme-open-proxy-tdlib-link tdlib-link))
))
(provide 'telega-tme)
diff --git a/telega-util.el b/telega-util.el
index 1f2667f..4623437 100644
--- a/telega-util.el
+++ b/telega-util.el
@@ -1614,9 +1614,24 @@ Works only with `fido-mode' completion."
require-match initial-input hist def
inherit-input-method)
"Same as `completing-read', but uses `telega-completing-read-function'."
- (funcall telega-completing-read-function
- prompt collection predicate require-match
- initial-input hist def inherit-input-method))
+ ;; NOTE: Use `unicode-name' completion category (see
+ ;; `completion-category-defaults'), because it contains `substring'
+ ;; completion style and can complete any candidate even if it is
+ ;; prefixed with an image
+ (let ((completion-ignore-case t)
+ (candidates
+ (if (eq telega-completing-read-function #'completing-read-default)
+ (lambda (string pred action)
+ (cond ((eq action 'metadata)
+ `(metadata (category . unicode-name)
+ (display-sort-function . ,#'identity)
+ (cycle-sort-function . ,#'identity)))
+ (t
+ (complete-with-action action collection string pred))))
+ collection)))
+ (funcall telega-completing-read-function
+ prompt candidates predicate require-match
+ initial-input hist def inherit-input-method)))
(defun telega-read-string-with-custom-emojis (prompt &rest args)
"Read string allowing to insert custom emojis with `C-c C-e'."
@@ -1641,17 +1656,15 @@ Return a user."
#'telega-completing--chat-members-collection chat))
;; Static completion, can complete only 50 chat members
- (funcall telega-completing-read-function
- prompt
- (telega-completing--chat-members-collection chat "")
- nil t))))
+ (telega-completing-read
+ prompt
+ (telega-completing--chat-members-collection chat "")
+ nil t))))
(cdr (assoc name telega-completing--chat-member-alist))))
(defun telega-completing-read-folder (prompt &optional folder-names)
"Read TDLib folder name completing."
- (funcall telega-completing-read-function
- prompt (or folder-names (telega-folder-names))
- nil t))
+ (telega-completing-read prompt (or folder-names (telega-folder-names)) nil t))
(defun telega-completing-read-folder-list (prompt &optional folder-names)
"Read list of the Telegram folders prompting with PROMPT."
@@ -1662,14 +1675,15 @@ Return a user."
(defun telega-completing-read-folder-icon-name (prompt &optional initial-input)
"Read folder's icon name."
- (funcall telega-completing-read-function prompt
- (mapcar (lambda (icon-name)
- (propertize icon-name 'display
- (concat (cdr (assoc icon-name
- telega-folder-icons-alist))
- icon-name)))
- telega-folder-icon-names)
- nil t initial-input))
+ (telega-completing-read
+ prompt
+ (mapcar (lambda (icon-name)
+ (propertize icon-name 'display
+ (concat (cdr (assoc icon-name
+ telega-folder-icons-alist))
+ icon-name)))
+ telega-folder-icon-names)
+ nil t initial-input))
(defun telega-location-distance (loc1 loc2 &optional components-p)
"Return distance in meters between locations LOC1 and LOC2.
@@ -1751,8 +1765,7 @@ Return non-nil only if \"i'm sure\" is typed in."
(telega-duration-human-readable delay))
delay))
telega--slow-mode-delays))
- (choice (funcall telega-completing-read-function
- prompt (mapcar #'car choices) nil t)))
+ (choice (telega-completing-read prompt (mapcar #'car choices) nil t)))
(cdr (assoc choice choices))))
(defun telega-completing-read-duration (prompt intervals &optional
@@ -1767,8 +1780,7 @@ Return non-nil only if \"i'm sure\" is typed in."
interval 1 'long))
interval))
intervals))
- (choice (funcall telega-completing-read-function
- prompt (mapcar #'car choices) nil t)))
+ (choice (telega-completing-read prompt (mapcar #'car choices) nil t)))
(cdr (assoc choice choices))))
(defun telega-completing-read-mute-for (prompt)
@@ -1851,8 +1863,8 @@ If PERMISSIONS is ommited, then `telega-chat--chat-permissions' is used."
(cons (telega-i18n (cdr perm-spec))
(car perm-spec))))
raw-perms)))
- (perm-choice (funcall telega-completing-read-function
- prompt (mapcar #'car i18n-choices) nil t)))
+ (perm-choice (telega-completing-read
+ prompt (mapcar #'car i18n-choices) nil t)))
(cdr (assoc perm-choice i18n-choices))))
(defun telega-msg-sender-title-for-completion (msg-sender)
@@ -1886,8 +1898,8 @@ If PERMISSIONS is ommited, then `telega-chat--chat-permissions' is used."
(eval-when-compile
(lambda ()
(setq-local nobreak-char-display nil)))
- (funcall telega-completing-read-function
- prompt (mapcar #'car choices) nil t))))
+ (telega-completing-read prompt (mapcar #'car choices)
+ nil t))))
(cdr (assoc choice choices))))
(defun telega-completing-read-topic (chat prompt)
@@ -1898,8 +1910,8 @@ If PERMISSIONS is ommited, then `telega-chat--chat-permissions' is used."
(telega-ins--topic-title topic 'with-icon))
topic))
(telega-chat-topics chat)))
- (choice (funcall telega-completing-read-function
- prompt (mapcar #'car choices) nil t)))
+ (choice (telega-completing-read
+ prompt (mapcar #'car choices) nil t)))
(cdr (assoc choice choices))))
(defun telega--animate-dots (text)
@@ -2544,14 +2556,15 @@ Used as for SVG's `:base-uri' functionality."
(defun telega-create-image (file-or-data &optional type data-p &rest props)
"Wrapper around `create-image' that takes into account `telega-use-images'.
-Also enforces `:transform-smoothing' property to be non-nil."
+Also, applies `telega-image-transform-smoothing' setting."
(declare (indent 3))
(when telega-use-images
(apply #'create-image
file-or-data
(or type (when (eq telega-use-images 'imagemagick) 'imagemagick))
data-p
- (nconc props (list :transform-smoothing t)))))
+ (nconc (list :transform-smoothing telega-image-transform-smoothing)
+ props))))
(defun telega-etc-file-create-image (filename cwidth &optional no-mask-p)
"Create image from etc's FILENAME.
@@ -2791,8 +2804,7 @@ not signal an error and just return nil."
delay 1 'long)))
delay))
'(3600 7200 28800 172800 0)))
- (choice (funcall telega-completing-read-function
- prompt (mapcar #'car choices) nil t))
+ (choice (telega-completing-read prompt (mapcar #'car choices) nil t))
(duration (cdr (assoc choice choices))))
(if (zerop duration)
(- (telega-read-timestamp "Timestamp: ")
@@ -2806,8 +2818,8 @@ not signal an error and just return nil."
(cons (concat (car spec) " (" (cdr spec) ")")
(cdr spec)))
telega-translate-languages-alist))
- (lang (funcall telega-completing-read-function prompt
- (mapcar #'car candidates-alist) nil t)))
+ (lang (telega-completing-read
+ prompt (mapcar #'car candidates-alist) nil t)))
(cdr (assoc lang candidates-alist))))
(defun telega--gen-ins-continuation-callback (show-loading-p
@@ -2885,19 +2897,24 @@ Also return nil if resulting string is empty."
(unless (string-empty-p ret-string)
ret-string)))
-(defun telega-mode-line-align-right (with-string &optional column right-margin)
- "Align to the right side of the header or mode line."
+(defun telega-mode-line-align (how with-string &optional column)
+ "Align WITH-STRING accornding to HOW.
+HOW is either `center' or `right'.
+COLUMN is the column to aligned to."
(when with-string
(concat
- (propertize " " 'display ; spacer -- align right
- (list 'space :align-to (- (or column (window-width))
- (or right-margin 0)
- (string-width with-string))))
+ (propertize " " 'display
+ (list 'space :align-to (/ (- (or column (window-width))
+ (string-width with-string))
+ (cl-ecase how
+ (center 2)
+ (right 1)))))
with-string)))
(defun telega-completing-read-text-formatting-entity (prompt)
"Interactively read text formatting entity type."
- (let* ((fmt-alist (mapcar (lambda (fname)
+ (let* ((completion-ignore-case t)
+ (fmt-alist (mapcar (lambda (fname)
(cons (telega-i18n fname) fname))
'("lng_menu_formatting_bold"
"lng_menu_formatting_italic"
@@ -2908,8 +2925,8 @@ Also return nil if resulting string is empty."
"lng_menu_formatting_strike_out"
"lng_menu_formatting_link_create"
"lng_menu_formatting_clear")))
- (i18n-fmt-name (funcall telega-completing-read-function prompt
- (mapcar #'car fmt-alist) nil t))
+ (i18n-fmt-name (telega-completing-read
+ prompt (mapcar #'car fmt-alist) nil t))
(fmt-name (cdr (assoc i18n-fmt-name fmt-alist))))
(pcase fmt-name
("lng_menu_formatting_bold"
@@ -2978,9 +2995,9 @@ Return nil if no reaction is available for the MSG."
(mapcar (lambda (rtype)
(cons (telega-msg-reaction-title-for-completion rtype)
rtype))
- ;; NOTE: sort reactions according making
- ;; top-reactions be on top
- ;; See https://t.me/emacs_telega/44605
+ ;; NOTE: sort reactions making top-reactions be on
+ ;; top. See https://t.me/emacs_telega/44605
+ ;; `telega-default-reaction-type' always goes first
(sort
(cl-case (telega--tl-type chat-av-reactions)
(chatAvailableReactionsSome
@@ -2998,8 +3015,8 @@ Return nil if no reaction is available for the MSG."
(when (plist-get msg-av-reactions :allow_custom_emoji)
(list (cons custom-label 'custom)))))
(choice (when all-choices
- (funcall telega-completing-read-function
- prompt (mapcar #'car all-choices) nil t))))
+ (telega-completing-read
+ prompt (mapcar #'car all-choices) nil t))))
(when choice
(cdr (assoc choice all-choices)))))
@@ -3019,8 +3036,7 @@ Return nil if there is no tags for the SM-TOPIC-ID or new tag is choosen."
tags))
(choices (nconc (mapcar #'car tag-choices)
(list new-tag-label)))
- (choice (funcall telega-completing-read-function
- prompt choices nil t)))
+ (choice (telega-completing-read prompt choices nil t)))
(cdr (assoc choice tag-choices))))
(defun telega-float-clamp (number digits)
@@ -3170,7 +3186,7 @@ Return nil if there is no tags for the SM-TOPIC-ID or new tag is choosen."
(msg (cdr cmd-scope)))
(telega--removeMessageReaction msg (plist-get tag :tag)
(when msg
- (lambda (_ignored)
+ (lambda-with-current-buffer (_ignored)
;; NOTE: Removing tag from the message might affect
;; message's visibility if message filter is applied at the
;; moment
diff --git a/telega-webpage.el b/telega-webpage.el
index 3cbeb48..83acf57 100644
--- a/telega-webpage.el
+++ b/telega-webpage.el
@@ -558,7 +558,9 @@ instant view for the URL."
(mapc #'telega-webpage--ins-pb
(plist-get telega-webpage--iv :page_blocks))
(when (and (listp telega-debug) (memq 'iv telega-debug))
- (telega-ins-fmt "\n---DEBUG---\n%S" telega-webpage--iv))
+ (telega-ins "\n")
+ (telega-ins-describe-section "DEBUG")
+ (telega-ins-fmt "%S" telega-webpage--iv))
(goto-char (point-min)))
(unless (derived-mode-p 'telega-webpage-mode)
diff --git a/telega.el b/telega.el
index 6e52987..c684c16 100644
--- a/telega.el
+++ b/telega.el
@@ -8,8 +8,8 @@
;; Keywords: comm
;; Package-Requires: ((emacs "27.1") (visual-fill-column "1.9") (rainbow-identifiers "0.2.2") (transient "0.3.0"))
;; URL: https://github.com/zevlg/telega.el
-;; Version: 0.8.290
-(defconst telega-version "0.8.290")
+;; Version: 0.8.291
+(defconst telega-version "0.8.291")
(defconst telega-server-min-version "0.7.7")
(defconst telega-tdlib-min-version "1.8.29")
(defconst telega-tdlib-max-version nil)
@@ -152,12 +152,11 @@ can't write to `telega-server-logfile'" logfile-dir)))
(interactive
(list (if (not telega-accounts)
(user-error "telega: Single account setup, see `telega-accounts'")
- (funcall telega-completing-read-function
- "Telegram Account: "
- (mapcar #'car
- (cl-remove-if #'telega-account--current-p
- telega-accounts))
- nil 'require-match))))
+ (telega-completing-read
+ "Telegram Account: "
+ (mapcar #'car (cl-remove-if #'telega-account--current-p
+ telega-accounts))
+ nil 'require-match))))
(let ((account (assoc account-name telega-accounts)))
(cl-assert account)
@@ -186,8 +185,7 @@ Modifies `telega-network-type' by side-effect."
(list (substring (plist-get (cdr nt) :@type) 11)
(car nt)))
telega-tdlib-network-type-alist))
- (choice (funcall telega-completing-read-function
- "Set Network Type: " choices nil t))
+ (choice (telega-completing-read "Set Network Type: " choices nil t))
(network-type (car (alist-get choice choices nil nil 'string=))))
(list network-type)))