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 @@ + + +
+ + + +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
+support | +Unsupported 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
+pyTelegramBotApi - opens telegram link in telegram
+Telegram - opens link inside telegram in browser.
+other
+version:+
platform:+
color scheme:+
${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; +} +