diff --git a/examples/asynchronous_telebot/mini_app.py b/examples/asynchronous_telebot/mini_app.py new file mode 100644 index 000000000..3cdb811cb --- /dev/null +++ b/examples/asynchronous_telebot/mini_app.py @@ -0,0 +1,33 @@ +# The source of the "https://pytelegrambotminiapp.vercel.app" can be found in https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/mini_app_web + +import asyncio +from telebot.async_telebot import AsyncTeleBot +from telebot.types import ( + ReplyKeyboardMarkup, + KeyboardButton, + WebAppInfo, + InlineKeyboardMarkup, + InlineKeyboardButton +) + +BOT_TOKEN = "" +WEB_URL = "https://pytelegrambotminiapp.vercel.app" + +bot = AsyncTeleBot(BOT_TOKEN) + +@bot.message_handler(commands=["start"]) +async def start(message): + reply_keyboard_markup = ReplyKeyboardMarkup(resize_keyboard=True) + reply_keyboard_markup.row(KeyboardButton("Start MiniApp", web_app=WebAppInfo(WEB_URL))) + + inline_keyboard_markup = InlineKeyboardMarkup() + inline_keyboard_markup.row(InlineKeyboardButton('Start MiniApp', web_app=WebAppInfo(WEB_URL))) + + await bot.reply_to(message, "Click the bottom inline button to start MiniApp", reply_markup=inline_keyboard_markup) + await bot.reply_to(message, "Click keyboard button to start MiniApp", reply_markup=reply_keyboard_markup) + +@bot.message_handler(content_types=['web_app_data']) +async def web_app(message): + await bot.reply_to(message, f'Your message is "{message.web_app_data.data}"') + +asyncio.run(bot.polling()) diff --git a/examples/mini_app.py b/examples/mini_app.py new file mode 100644 index 000000000..735acd38c --- /dev/null +++ b/examples/mini_app.py @@ -0,0 +1,32 @@ +# The source of the "https://pytelegrambotminiapp.vercel.app" can be found in https://github.com/eternnoir/pyTelegramBotAPI/tree/master/examples/mini_app_web + +from telebot import TeleBot +from telebot.types import ( + ReplyKeyboardMarkup, + KeyboardButton, + WebAppInfo, + InlineKeyboardMarkup, + InlineKeyboardButton +) + +BOT_TOKEN = "" +WEB_URL = "https://pytelegrambotminiapp.vercel.app" + +bot = TeleBot(BOT_TOKEN) + +@bot.message_handler(commands=["start"]) +def start(message): + reply_keyboard_markup = ReplyKeyboardMarkup(resize_keyboard=True) + reply_keyboard_markup.row(KeyboardButton("Start MiniApp", web_app=WebAppInfo(WEB_URL))) + + inline_keyboard_markup = InlineKeyboardMarkup() + inline_keyboard_markup.row(InlineKeyboardButton('Start MiniApp', web_app=WebAppInfo(WEB_URL))) + + bot.reply_to(message, "Click the bottom inline button to start MiniApp", reply_markup=inline_keyboard_markup) + bot.reply_to(message, "Click keyboard button to start MiniApp", reply_markup=reply_keyboard_markup) + +@bot.message_handler(content_types=['web_app_data']) +def web_app(message): + bot.reply_to(message, f'Your message is "{message.web_app_data.data}"') + +bot.infinity_polling() diff --git a/examples/mini_app_web/index.html b/examples/mini_app_web/index.html new file mode 100644 index 000000000..22bd86ec9 --- /dev/null +++ b/examples/mini_app_web/index.html @@ -0,0 +1,163 @@ + + + + + + + PyTelegramBotApi MiniApp + + + +
+ + +
+ +

client buttons

+
+ + + +
+

hapticFeedback (notification)

+
+ + + +
+ +

tweak color [Bot API 6.1+]

+
+
+

Header color:

+
+
+
+
+
+
+
+
+

Background color:

+
+
+
+
+
+
+
+
+ +

popup and alert [Bot API 6.2+]

+ + +

request [Bot API 6.9+]

+
+ + + +
+ +

story [Bot API 7.8+]

+
+ + + +
+ +

cloud storage [Bot API 6.9+]

+
+
+ + +
+ + + + + + + + + + +
key value
- -
+
+ + +
+
+

data from telegram

+
+
+

initDataUnsafe

+
+
+

ThemeParams

+
+
+

Biometrics Manager

+ + + + + +
supportUnsupported in this platform
+
+
+ +

event from telegram

+
+
+
+
+ +

vertical scroll behaviour [Bot API 7.7+]

+
+

close the miniapp when scroll vertically

+
+ + +
+
+ +

closing confirmation [Bot API 6.2+]

+
+

Confimation dialog when closing miniapp

+
+ + +
+
+ +

links

+ + +

other

+
+ + + +
+ +
+
 version: 
+
 platform: 
+
 color scheme: 
+
+ + + diff --git a/examples/mini_app_web/script.js b/examples/mini_app_web/script.js new file mode 100644 index 000000000..4022ed5f0 --- /dev/null +++ b/examples/mini_app_web/script.js @@ -0,0 +1,318 @@ +const telegram = Telegram.WebApp; +telegram.ready(); + +class ModifyStyle{ + constructor(element) { + this.element = element; + }; + disableButton() { + this.element.style.backgroundColor = 'transparent'; + this.element.style.color = 'var(--tg-theme-button-color)'; + this.element.style.border = "solid 1px var(--tg-theme-button-color)"; + }; + enableButton() { + this.element.style.backgroundColor = "var(--tg-theme-button-color)"; + this.element.style.color = 'var(--tg-theme-text-color)'; + }; +}; + +class TableModify{ + constructor(element) { + this.element = element; + } + addElements(element_1, element_2) { + this.element.innerHTML += ` ${element_1} ${element_2} `; + } + removeElement(id) { + document.getElementById(id).remove(); + } +}; + +const button = { + send_message : document.getElementById('send-message-button'), + back : document.getElementById('back-button'), + main: document.getElementById('main-button'), + settings: document.getElementById('settings-button'), + success: document.getElementById('success-button'), + warning: document.getElementById('warning-button'), + error: document.getElementById('error-button'), + popup: document.getElementById('popup-button'), + alert: document.getElementById('alert-button'), + confirm: document.getElementById('confirm-button'), + contact: document.getElementById('contact-button'), + write_access: document.getElementById('write-access-button'), + biometrics: document.getElementById('biometrics-button'), + cloud_add: document.getElementById('cloud-add-button'), + cloud_remove: document.getElementById('cloud-remove-button'), + vertical_scroll_enable: document.getElementById('enable-scroll-button'), + vertical_scroll_disable: document.getElementById('disable-scroll-button'), + close_confirm_enable: document.getElementById('enable-close-confirm-button'), + close_confirm_disable: document.getElementById('disable-close-confirm-button'), + post_story_photo: document.getElementById('post-story-photo-button'), + post_story_video: document.getElementById('post-story-video-button'), + post_story_with_link: document.getElementById('post-story-with-link-button'), + show_QR: document.getElementById('show-QR-button') , + expand: document.getElementById('expand-button'), + close: document.getElementById('close-button'), +}; + +const input = { + message: document.querySelector('.send-message__input'), + cloud_add_key: document.querySelector('.cloud-storage__input_add-key'), + cloud_add_value: document.querySelector('.cloud-storage__input_add-value'), + cloud_remove_key: document.querySelector('.cloud-storage__input_remove'), +}; + +const text = { + telegram_link: document.getElementById('telegram-link'), + internal_link: document.getElementById('internal-link'), + version: document.getElementById('version-text'), + platform: document.getElementById('platform-text'), + color_scheme: document.getElementById('color-scheme-text') +}; + +const table = { + cloud_table: document.querySelector(".cloud-storage__table"), + biometrics_table: document.getElementById("biometrics-table") +} + +const colors_tweaks = [ + document.getElementById('header-yellow'), + document.getElementById('header-button_color'), + document.getElementById('header-red'), + document.getElementById('header-default'), + document.getElementById('background-yellow'), + document.getElementById('background-button_color'), + document.getElementById('background-red'), + document.getElementById('background-default'), +]; + +telegram.MainButton.setParams({text: 'Close', color: '#ba4d47'}); +telegram.MainButton.onClick(() => {telegram.close()}); +telegram.MainButton.show(); +telegram.enableVerticalSwipes(); + +telegram.CloudStorage.getKeys((error, keys) => { + let table_modify = new TableModify(table.cloud_table); + if (keys.length) {table_modify.removeElement("null-storage-row")}; + keys.forEach((key) => { + telegram.CloudStorage.getItem(key, (error, item) => { + table_modify.addElements(key, item) + }); + }); +}); + +document.getElementById('initDataUnsafe-block').innerHTML += `
 ${JSON.stringify(telegram.initDataUnsafe, null, 2)} 
`; +document.getElementById('themeParams-block').innerHTML += `
 ${JSON.stringify(telegram.themeParams, null, 2)} 
`; + +let biometrics_table_modify = new TableModify(table.biometrics_table); + +telegram.BiometricManager.init(() => {['isInited', 'isBiometricAvailable', 'biometricType', 'isAccessRequested', 'isAccessGranted', 'isBiometricTokenSaved', 'deviceId'].forEach((field) => { + biometrics_table_modify.addElements(field, eval(`telegram.BiometricManager.${field}`)); +}); biometrics_table_modify.removeElement('null-biometrics-row') }); + +['themeChanged', 'viewportChanged', 'mainButtonClicked', 'backButtonClicked', 'settingsButtonClicked', 'invoiceClosed', 'popupClosed', 'qrTextReceived', 'scanQrPopupClosed', +'clipboardTextReceived', 'writeAccessRequested', 'contactRequested', 'biometricManagerUpdated', 'biometricAuthRequested', 'biometricTokenUpdated'].forEach((element) => { + telegram.onEvent(element, () => { + document.getElementById('event-block').innerHTML += `

${element}

`; + }); +}); + +text.color_scheme.innerText += telegram.colorScheme; +text.version.innerText += telegram.version; +text.platform.innerText += telegram.platform; + +button.send_message.addEventListener('click', () => { + telegram.sendData(input.message.value); + if (telegram.initDataUnsafe) telegram.showAlert('SendData only works in miniapp that opened with reply keyboard.') + input.message.value = '' +}); + +button.main.addEventListener('click', (e) => { + const modify_button = new ModifyStyle(e.currentTarget); + if (e.currentTarget.value == 'enable') { + e.currentTarget.value = 'disable'; + modify_button.disableButton(); + telegram.MainButton.hide(); + } else { + e.currentTarget.value = 'enable'; + modify_button.enableButton(); + telegram.MainButton.show(); + } +}); + +button.back.addEventListener('click', (e) => { + const modify_button = new ModifyStyle(e.currentTarget); + if (e.currentTarget.value == 'enable') { + e.currentTarget.value = 'disable'; + modify_button.disableButton(); + telegram.BackButton.hide(); + } else { + e.currentTarget.value = 'enable'; + modify_button.enableButton(); + telegram.BackButton.show(); + } +}); + +button.settings.addEventListener('click', (e) => { + const modify_button = new ModifyStyle(e.currentTarget); + if (e.currentTarget.value == 'enable') { + e.currentTarget.value = 'disable'; + modify_button.disableButton(); + telegram.SettingsButton.hide(); + } else { + e.currentTarget.value = 'enable'; + modify_button.enableButton(); + telegram.SettingsButton.show(); + } +}); + +button.success.addEventListener('click', () => { + telegram.HapticFeedback.notificationOccurred('success'); +}); + +button.warning.addEventListener('click', () => { + telegram.HapticFeedback.notificationOccurred('warning'); +}); + +button.error.addEventListener('click', () => { + telegram.HapticFeedback.notificationOccurred('error'); +}); + +button.popup.addEventListener('click', () => { + telegram.showPopup({title: 'popup', message: 'this is popup message', buttons: [{ text: 'roger'}]}); +}); + +button.alert.addEventListener('click', () => { + telegram.showAlert('This is alert message'); +}); + +button.confirm.addEventListener('click', () => { + telegram.showConfirm('This is confirm message'); +}); + +button.contact.addEventListener('click', () => { + telegram.requestContact(); +}); + +button.write_access.addEventListener('click', () => { + telegram.requestWriteAccess(); +}); + +button.biometrics.addEventListener('click', () => { + telegram.BiometricManager.requestAccess({'reseaon': 'this is biometrics request'}); +}); + +button.vertical_scroll_enable.addEventListener('click', (e) => { + const modify_scroll_enable = new ModifyStyle(e.currentTarget); + const modify_scroll_disable = new ModifyStyle(button.vertical_scroll_disable); + if (e.currentTarget.value == 'disable') { + e.currentTarget.value = 'enable'; + modify_scroll_enable.enableButton(); + modify_scroll_disable.disableButton(); + button.vertical_scroll_disable.value = 'disable'; + telegram.enableVerticalSwipes(); + }; +}); + +button.vertical_scroll_disable.addEventListener('click', (e) => { + const modify_scroll_disable = new ModifyStyle(e.currentTarget); + const modify_scroll_enable = new ModifyStyle(button.vertical_scroll_enable); + if (e.currentTarget.value == 'disable') { + e.currentTarget.value = 'enable'; + modify_scroll_disable.enableButton(); + modify_scroll_enable.disableButton(); + telegram.disableVerticalSwipes(); + button.vertical_scroll_enable.value = 'disable'; + }; +}); + +button.close_confirm_enable.addEventListener('click', (e) => { + const modify_close_confirm_enable = new ModifyStyle(e.currentTarget); + const modify_close_confirm_disable = new ModifyStyle(button.close_confirm_disable); + if (e.currentTarget.value == 'disable') { + e.currentTarget.value = 'enable'; + modify_close_confirm_enable.enableButton(); + modify_close_confirm_disable.disableButton(); + button.close_confirm_disable.value = 'disable'; + telegram.enableClosingConfirmation(); + }; +}); + +button.close_confirm_disable.addEventListener('click', (e) => { + const modify_close_confirm_disable= new ModifyStyle(e.currentTarget); + const modify_close_confirm_enable= new ModifyStyle(button.close_confirm_enable); + if (e.currentTarget.value == 'disable') { + e.currentTarget.id = 'enable'; + modify_close_confirm_enable.disableButton(); + modify_close_confirm_disable.enableButton(); + button.close_confirm_enable.value = 'disable'; + telegram.disableClosingConfirmation(); + }; +}); + +button.show_QR.addEventListener('click', () => { + telegram.showScanQrPopup({text: "this is QR scanner"}); +}); + +button.expand.addEventListener('click', () => { + telegram.expand(); +}); + +button.close.addEventListener('click', () => { + telegram.close(); +}); + +button.cloud_add.addEventListener('click', () => { + let table_modify = new TableModify(table.cloud_table); + telegram.CloudStorage.setItem(input.cloud_add_key.value, input.cloud_add_value.value, (error, is_stored) => { + if (!is_stored) telegram.showAlert(error); + else { + table_modify.addElements(input.cloud_add_key.value, input.cloud_add_value.value); + new TableModify(table.cloud_table).removeElement('null-storage-row'); + }; + input.cloud_add_key.value = ''; + input.cloud_add_value.value = ''; + }); +}); + +button.cloud_remove.addEventListener('click', () => { + let table_modify = new TableModify(table.cloud_table); + telegram.CloudStorage.removeItem(input.cloud_remove_key.value, (error, is_removed) => { + if (!is_removed) telegram.showAlert(error); + else table_modify.removeElement(input.cloud_remove_key.value); + input.cloud_remove_key.value = ''; + }); +}); + +button.post_story_photo.addEventListener('click', () => { + telegram.shareToStory('https://telegra.ph/file/e194a37aed103485469b4.jpg', {text: 'This is photo story'}); +}); + +button.post_story_video.addEventListener('click', () => { + telegram.shareToStory('https://telegra.ph/file/16ffd9385a017b59f458e.mp4', {text: 'This is video story'}); +}); + +button.post_story_with_link.addEventListener('click', () => { + telegram.shareToStory('https://telegra.ph/file/e194a37aed103485469b4.jpg', {text: 'This is story with link', widget_link: {url: 'https://t.me/joinchat/Bn4ixj84FIZVkwhk2jag6A'}}); +}); + +colors_tweaks.forEach((element) => { + element.addEventListener('click', (e) => { + const color = window.getComputedStyle(e.currentTarget).backgroundColor; + if (e.currentTarget.id.includes('header')){ + telegram.setHeaderColor(color); + } else { + telegram.setBackgroundColor(color); + document.querySelector('.body').style.backgroundColor = telegram.backgroundColor; + }; + }); +}); + +text.telegram_link.addEventListener('click', () => { + telegram.openTelegramLink("https://t.me/joinchat/Bn4ixj84FIZVkwhk2jag6A"); +}); + +text.internal_link.addEventListener('click', () => { + telegram.openLink('https://telegram.org', {try_instant_view: false}); +}); diff --git a/examples/mini_app_web/style.css b/examples/mini_app_web/style.css new file mode 100644 index 000000000..30fad466c --- /dev/null +++ b/examples/mini_app_web/style.css @@ -0,0 +1,338 @@ +:root { + --red-color: #ba4d47; + --yellow-color: #bab05b; +} + +.body { + background-color: (--tg-theme-secondary-bg-color); +} + +* { + font-family: Arial, Helvetica, sans-serif; + margin: 0; + padding: 0; +} + +input { + color: var(--tg-theme-text-color); +} + +table { + width: 93vw; + border-collapse: collapse; + border: solid 0px var(--tg-theme-hint-color); + border-radius: 5px; +} + +th { + font-weight: bold; +} + +td { + font-weight: lighter; + max-width: 46.5vw; + overflow-x: hidden; +} + + +th, td { + padding: 3px; + font-size: 14px; + color: var(--tg-theme-text-color); + text-align: center; + border: solid 1px var(--tg-theme-hint-color); +} + +input:focus { + outline: none; +} + +::placeholder { + color: var(--tg-theme-hint-color); +} + +.content-block { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + gap: 9.24px; + background-color: var(--tg-theme-bg-color); + height: 70px; +} + +.content-block_send-message { + flex-direction: column; + height: 160px; +} + +.content-block_tweak-color { + flex-direction: column; + align-items: start; + justify-content: center; + gap: 17px; + height: 96px; +} + +.content-block_cloud-storage { + flex-direction: column; + height: 320px; + gap: 9.6px; +} + +.content-block_link { + height: 104px; + flex-direction: column; +} + +.content-block_event{ + height: 220px; +} + +.content-block_scroll-behaviour, .content-block_close-confirmation { + height: 100px; + align-items: flex-start; + align-self: flex-start; + flex-direction: column; + padding-left: 4.2vw; +} + +.content-block_data { + height: 100%; + flex-direction: column; + align-items: flex-start; + padding:5vh 3vw 5vh 3vw ; + overflow: hidden; +} + +.scroll-behaviour__toggle-box, .content-block__toggle-box { + display: flex; + gap: 9.6px; +} + +.link__content { + display: flex; + flex-direction: row; +} + +.tweak-color__header, .tweak-color__background { + display: flex; + flex-direction: row; + justify-content: flex-end; + gap: 9.6px; + width: 65vw; +} + +.tweak-color__circle-block { + display: flex; + flex-direction: row; + gap: 2vw; +} + +.event__content { + overflow-y: auto; + height: 170px; + width: 88vw; + border: solid 1px var(--tg-theme-hint-color); + border-radius: 5px; + padding: 10px; +} + +.data__content { + padding-top: 10px; + padding-bottom: 10px; +} + +.cloud-storage__input-block { + width: 93vw; + display: flex; + flex-direction: row; + gap: 0px; +} + +.cloud-storage__input-block_remove { + width: 94vw; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +.description-block { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + margin: 10px; + gap: 3px; +} + +.send-message__button{ + border: none; + color: var(--tg-theme-text-color); + background-color: var(--tg-theme-button-color); + border-radius: 5px; + width: 70vw; + height: 40px; +} + +.default-button { + color: var(--tg-theme-text-color); + background-color: var(--tg-theme-button-color); + border: none; + border-radius: 5px; + width: 29vw;; + height: 35px; +} + +.default-button_yellow { + background-color: var(--yellow-color); +} + +.default-button_red { + background-color: var(--red-color); +} + +.default-button_disable { + background: transparent; + color: var(--tg-theme-button-color); + border: solid 1px var(--tg-theme-button-color); +} + +.cloud-storage__button { + border: none; + border-radius: 5px; + color: var(--button_text_color); + width: 93vw; + height: 38px; +} + +.cloud-storage__button_add { + color: var(--tg-theme-text-color); + background-color: var(--tg-theme-button-color); + margin-bottom: 10px; +} + +.cloud-storage__button_remove { + color: var(--tg-theme-text-color); + background-color: var(--red-color); +} + +.header-text { + font-size: 14px; + color: var(--tg-theme-hint-color); + margin-top: 13px; + margin-bottom: 5px; + margin-left: 6px; +} + +.content-block__text { + color: var(--tg-theme-text-color); + font-size: 14px; + padding-bottom: 3px; +} + +.tweak-color__text { + font-size: 13px; + color: var(--tg-theme-text-color); + } + +.data__text { + color: var(--tg-theme-text-color); + font-weight: 300; + font-size: 15px; +} + +.link__text { + font-size: 14px; + color: var(--tg-theme-hint-color); + padding: 2px; +} + +.link__text_blue { + color: var(--tg-theme-link-color); +} + +.event__text { + color: var(--tg-theme-text-color); + font-weight: lighter; + font-size: 13px; +} + + +.description__text { + color: var(--tg-theme-hint-color); + font-size: 13px; + font-weight: 300; +} + +.send-message__input { + border: solid var(--tg-theme-hint-color) 1px; + background-color: transparent; + border-radius: 5px; + width: 67vw; + height: 40px; + padding-left: 10px; +} + +.cloud-storage__input { + border: solid 1px var(--tg-theme-hint-color); + background-color: transparent; + height: 30px; + padding-left: 10px; +} + +.cloud-storage__input_add-key { + border-radius: 5px 0px 0px 5px; + width: 35%; +} + +.cloud-storage__input_add-value { + border-radius: 0px 5px 5px 0px; + width: 65%; +} + +.cloud-storage__input_remove { + width: 90vw; + border: solid 1px var(--tg-theme-hint-color); + border-radius: 5px; + margin-bottom: 10px; +} + +.tweak-color__circle { + border-radius: 100%; + width: 20px; + height: 20px; +} + +.tweak-color__circle_yellow { + background-color: var(--yellow-color); +} + +.tweak-color__circle_red { + background-color: var(--red-color); +} + +.tweak-color__circle_button { + background-color: var(--tg-theme-button-color); +} + +.tweak-color__circle_header { + border: solid 1px var(--tg-theme-hint-color); + background-color: var(--tg-theme-header-bg-color); +} + +.tweak-color__circle_background { + border: solid 1px var(--tg-theme-hint-color); + background-color: var(--tg-theme-secondary-bg-color); +} + +.cloud-storage__table { + margin-bottom: 10px; +} + +.link__list { + color: var(--tg-theme-hint-color); + width: 88vw; +} +