ptgb
A complete Telegram Bot API client for Dart

Callback Queries & Editing

Part of the Examples. A live-editing counter built on editMessageText, driven by callback queries.

Source: example/06_callback_queries_and_editing.dart

// ignore_for_file: file_names
// (numbered intentionally for reading/run order -- see README.md)

// ============================================================================
// 06 — CALLBACK QUERIES AND LIVE-EDITING MESSAGES
// ============================================================================
//
// This example builds a tiny interactive counter: a message with +/- inline
// buttons that edits itself in place every time a button is tapped, instead
// of sending a new message each time.
//
// HOW TO RUN:
//   dart run example/06_callback_queries_and_editing.dart   (with a `.env` file)
// ============================================================================

import 'package:ptgb/ptgb.dart';

// A tiny in-memory store mapping "chatId:messageId" -> current count.
// In a real bot you'd likely persist this in a database instead.
final Map<String, int> _counters = {};

InlineKeyboardMarkup _counterKeyboard() => InlineKeyboardMarkup.single([
      InlineKeyboardButton.callback('➖', 'counter:dec'),
      InlineKeyboardButton.callback('🔄', 'counter:reset'),
      InlineKeyboardButton.callback('➕', 'counter:inc'),
    ]);

Future<void> main() async {
  final bot = Bot();

  await for (final update in bot.poll()) {
    final callback = update.callbackQuery;

    if (callback != null) {
      final data = update.callbackData;
      final messageId = (callback['message'] as Map)['message_id'] as int;
      final chatId = update.chatId!;
      final key = '$chatId:$messageId';

      // Update our local counter based on which button was tapped.
      final current = _counters[key] ?? 0;
      final next = switch (data) {
        'counter:inc' => current + 1,
        'counter:dec' => current - 1,
        'counter:reset' => 0,
        _ => current,
      };
      _counters[key] = next;

      // Acknowledge the tap immediately so Telegram stops the loading spinner.
      await bot.answerCallbackQuery(callback['id'] as String);

      // Edit the ORIGINAL message in place instead of sending a new one —
      // this is what makes counters, paginated menus, and live dashboards
      // feel responsive rather than spammy.
      await bot.editMessageText(
        'Count: $next',
        chatId: chatId,
        messageId: messageId,
        replyMarkup: _counterKeyboard(),
      );
      continue;
    }

    final text = update.text;
    final chatId = update.chatId;
    if (text == '/counter' && chatId != null) {
      final sent = await bot.sendMessage(chatId, 'Count: 0', replyMarkup: _counterKeyboard());
      _counters['$chatId:${sent['message_id']}'] = 0;
    } else if (text != null && chatId != null) {
      await bot.sendMessage(chatId, 'Send /counter to try a live-editing message.');
    }
  }
}

Run it from the package root:

dart run example/06_callback_queries_and_editing.dart