3 Commits

Author SHA1 Message Date
395d45a4e8 Fix redraw after closing GIF preview
All checks were successful
Release App / release-app (push) Successful in 1m0s
2026-04-26 13:00:57 +03:00
c2c9560e07 Fix saved GIF preview rendering
All checks were successful
Release App / release-app (push) Successful in 48s
2026-04-26 12:59:07 +03:00
063e12a996 Bump version to 0.1.2
All checks were successful
Release App / release-app (push) Successful in 48s
2026-04-26 12:56:24 +03:00
6 changed files with 60 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.21)
project(shinoa VERSION 0.1.1 LANGUAGES CXX)
project(shinoa VERSION 0.1.2 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

View File

@@ -1,5 +1,5 @@
pkgname=shinoa-bin
pkgver=0.1.1
pkgver=0.1.2
pkgrel=1
pkgdesc='Minimal Telegram terminal client built with ncurses and bundled TDLib'
arch=('x86_64')

View File

@@ -79,7 +79,7 @@ It also refreshes a `latest/tdlib-latest.json` manifest with the newest publishe
The repository also includes [`.gitea/workflows/release-app.yaml`](.gitea/workflows/release-app.yaml),
which downloads a prebuilt TDLib bundle from the `shinoa-tdlib` repository using a pinned
version tag such as `v1.8.63`, builds a
versioned app release tag such as `v0.1.1`, and publishes an archive containing `usr/bin/shinoa` plus the
versioned app release tag such as `v0.1.2`, and publishes an archive containing `usr/bin/shinoa` plus the
bundled `usr/lib/libtdjson.so*`. The root `PKGBUILD` installs that prebuilt release as
`shinoa-bin`. The package disables debug splitting with `options=(!debug)`. That workflow expects Gitea secrets named `TELEGRAM_API_ID` and
`TELEGRAM_API_HASH`. Release builds are configured to fail if those secrets are missing.

View File

@@ -108,6 +108,8 @@ class App {
[[nodiscard]] bool has_inline_attachment_preview(const AttachmentInfo &attachment,
int width, int height) const;
void clear_attachment_preview_graphics();
void render_attachment_preview_graphics(const AttachmentInfo &attachment, bool animated,
int top, int left, int width, int height);
void render_attachment_preview_graphics(int top, int left, int width, int height);
void reset_attachment_viewer_send_preview();
[[nodiscard]] std::vector<std::int64_t> forward_target_chat_ids() const;

View File

@@ -987,12 +987,19 @@ void App::render_attachment_preview_graphics(int top, int left, int width, int h
return;
}
const AttachmentInfo &attachment = *attachment_viewer_attachment_;
render_attachment_preview_graphics(*attachment_viewer_attachment_,
attachment_viewer_is_animated_, top, left, width,
height);
}
void App::render_attachment_preview_graphics(const AttachmentInfo &attachment, bool animated,
int top, int left, int width, int height) {
const std::string preview_path = attachment_preview_path(attachment);
if (preview_path.empty() || attachment_viewer_is_animated_) {
if (preview_path.empty() || animated) {
clear_attachment_preview_graphics();
return;
}
const std::string forced_protocol = configured_image_protocol();
const bool want_kitty = forced_protocol == "kitty" ||
(forced_protocol.empty() && terminal_supports_kitty_graphics());

View File

@@ -85,6 +85,10 @@ void App::shutdown_curses() {
}
void App::draw() {
if (!attachment_viewer_open_ && !saved_animation_menu_open_) {
clear_attachment_preview_graphics();
}
erase();
int height = 0;
@@ -168,7 +172,6 @@ void App::draw() {
} else if (attachment_action_menu_open_) {
draw_attachment_action_menu(height, width);
} else if (saved_animation_menu_open_) {
clear_attachment_preview_graphics();
draw_saved_animation_menu(height, width);
} else if (attachments_menu_open_) {
draw_attachments_menu(height, width);
@@ -176,8 +179,6 @@ void App::draw() {
draw_forward_target_menu(height, width);
} else if (help_menu_open_) {
draw_help_menu(height, width);
} else {
clear_attachment_preview_graphics();
}
}
@@ -335,6 +336,7 @@ void App::draw_saved_animation_menu(int height, int width) {
mvwvline(window, 3, preview_left - 1, ACS_VLINE, menu_height - 4);
if (saved_animations_.empty()) {
clear_attachment_preview_graphics();
mvwaddnstr(window, 4, preview_left, "No saved GIFs on this account.", preview_width);
} else {
const SavedAnimationInfo &animation = saved_animations_[static_cast<std::size_t>(
@@ -362,20 +364,53 @@ void App::draw_saved_animation_menu(int height, int width) {
preview_attachment.can_be_deleted = animation.can_be_deleted;
preview_attachment.is_downloaded = animation.is_downloaded;
const std::string preview = render_attachment_preview(
preview_attachment, preview_width, std::max(4, list_height - 4));
const std::vector<std::string> preview_lines = split_preview_lines(preview);
for (std::size_t i = 0; i < preview_lines.size() &&
static_cast<int>(i) < list_height - 3;
++i) {
mvwaddnstr(window, 6 + static_cast<int>(i), preview_left,
truncate_to_width(preview_lines[i], preview_width).c_str(), preview_width);
const int preview_top = 6;
const int preview_height = std::max(4, list_height - 4);
if (has_inline_attachment_preview(preview_attachment, preview_width, preview_height)) {
for (int row = 0; row < preview_height; ++row) {
mvwhline(window, preview_top + row, preview_left, ' ', preview_width);
}
} else {
clear_attachment_preview_graphics();
const std::string preview =
render_attachment_preview(preview_attachment, preview_width, preview_height);
const std::vector<std::string> preview_lines = split_preview_lines(preview);
for (std::size_t i = 0; i < preview_lines.size() &&
static_cast<int>(i) < list_height - 3;
++i) {
mvwaddnstr(window, preview_top + static_cast<int>(i), preview_left,
truncate_to_width(preview_lines[i], preview_width).c_str(),
preview_width);
}
}
}
mvwaddnstr(window, menu_height - 2, 2,
"Enter send r refresh Up/Down move Esc close", menu_width - 4);
wrefresh(window);
if (!saved_animations_.empty()) {
const SavedAnimationInfo &animation = saved_animations_[static_cast<std::size_t>(
saved_animation_selection_index_)];
AttachmentInfo preview_attachment;
preview_attachment.type = AttachmentType::Animation;
preview_attachment.name = animation.name;
preview_attachment.size_bytes = animation.size_bytes;
preview_attachment.downloaded_size = animation.downloaded_size;
preview_attachment.file_id = animation.file_id;
preview_attachment.local_path = animation.local_path;
preview_attachment.is_downloading_active = animation.is_downloading_active;
preview_attachment.can_be_downloaded = animation.can_be_downloaded;
preview_attachment.can_be_deleted = animation.can_be_deleted;
preview_attachment.is_downloaded = animation.is_downloaded;
if (has_inline_attachment_preview(preview_attachment, preview_width,
std::max(4, list_height - 4))) {
render_attachment_preview_graphics(preview_attachment, false, top + 6,
left + preview_left, preview_width,
std::max(4, list_height - 4));
} else {
clear_attachment_preview_graphics();
}
}
delwin(window);
}