Задать вопрос
  • Почему добавляются лишние записи на диаграмму?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Я поместил массив записей в класс и сделал очистку массива в функции setChart, так как записи в нем копились раз за разом. Также переделал структуру добавления новых записей в функции

    class HomeViewController: UIViewController {
    
        var pieChart = PieChartView()
        var entries: [ChartDataEntry] = []
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
    
            self.setChart()
        }
    
        func setChart() {
            entries.removeAll()
            let entries = self.cellArr.map { PieChartDataEntry(value: Double($0.amount), label: String($0.type))) }
            updateSorting(values: entries)
        }
    }
    Ответ написан
    Комментировать
  • Как отредактировать ячейку в TableView по ID?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Переделал функцию sendNewOperation, теперь она выглядит таким образом:

    func sendNewOperation(id: Int?, amount: Float, description: String, category: String,
                              image: String, date: Date, switcher: String) {
            if let oldCellId = id {
                if let ix = self.cellArr.firstIndex(where: { searchedRecord in
                    searchedRecord.id == oldCellId
                }) { 
                    self.cellArr[ix] = Record(amount: amount, descriptionText: description, categoryText: category, categoryImage: image, date: date, id: oldCellId)
                    self.tableView.reloadRows(at: [IndexPath(row: ix, section: 0)], with: .automatic)
                } else {
                    fatalError("couldn't edit old cell #\(oldCellId)")
                } // Создается новая ячейка
            } else {
                let operationID = Int.random(in: 0...10000)
                print("id: \(operationID)")
                self.cellArr.append(Record(amount: amount, descriptionText: description, categoryText: category, categoryImage: image, date: date, id: operationID)) // Добавление в массив нового элемента
                self.tableView.insertRows(at: [IndexPath(row: self.cellArr.count - 1, section: 0)], with: .automatic)
            }
        }


    Так у меня происходит передача данных со второго контроллера при нажатии на кнопку "Сохранить":
    var operationID: Int?
        let homeViewController: HomeViewController
        init(homeViewController: HomeViewController, operationID: Int?) {
            self.homeViewController = homeViewController
            self.operationID = operationID
            super.init(nibName: nil, bundle: nil)
        }         
                
        @objc func saveButtonAction(sender: AnyObject) {
    
            addNewOpDelegate?.sendNewOperation(id: operationID, amount: abs(amount), description: descriptionTextField.text!, category: categoryButton.titleLabel!.text!, image: categoryImage, date: datePicker.date, switcher: segment)
                
            self.navigationController?.popToRootViewController(animated: true) // Закрыть AddNewOperationVC
        }
    
        // Протокол отправки всех введенных значений операции
        protocol AddNewOpSendData: AnyObject {
        func sendNewOperation(id: Int?, amount: Float, description: String, category: String, image: String, date: Date, switcher: String)
    }


    Первый контроллер:

    @objc func AddNewOperation() {
            let vc = AddNewOperationVC(homeViewController: self, operationID: nil)
            vc.addNewOpDelegate = self
            navigationController?.pushViewController(vc, animated: true)
        }
    Ответ написан
    Комментировать
  • Как сделать возврат нескольких значений в функции в одном return?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Теперь все работает как я и хотел, достаточно было отредактировать строку c guard:

    guard allowedCharactersSet.isSuperset(of: typedCharacterSet), let textFieldString = textField.text, let range = Range(range, in: textFieldString) else {
                return false
            }
    Ответ написан
    Комментировать
  • Как получать ошибки при отправке запросов Telegram?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Добавил в функцию sendRequest проверку на ошибки в http-запросах:

    if (!curl_errno($ch)) {
            global $http_code;
            $http_code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
        }


    А в цикле доставал эти ошибки, когда бот натыкался на пользователя, заблокировавшего бота:

    switch ($http_code) {
                case 200: // OK
                    break;
                case 403: // Forbidden
                    $blocked_users = $blocked_users + 1;
                    break;
            }
    Ответ написан
    Комментировать
  • Как вывести инлайн клавиатуру в столбик?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Разобрался, все оказалось куда проще:

    $rows = $array_count;
            $columns = 1;
            $keyboard = [];
            for ($i = 0; $i <= $array_count; $i++) {
                $rowKeys = [];
                for ($j = 1; $j <= $columns; $j++) {
                        $token_get = secret_token_get($user_id)[$i];
                        $token_symbols = substr($token_get['token'], -5);
                        $rowKeys[] = ['text' => $token_symbols, 'callback_data' => $token_symbols];
                }
                $keyboard[] = $rowKeys;
            }
    Ответ написан
    Комментировать
  • Как достать одинаковые ключи из разных массивов?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Это можно сделать через array_merge()
    https://www.php.net/manual/ru/function.array-merge.php
    Ответ написан
    Комментировать
  • Как сделать кнопки под чатом в телеграм боте?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Для начала я сделал функцию, которая возвращает json

    function reply_keyboard($array) {
        return json_encode(['keyboard' => $array]);
    }


    Затем сделал отдельную команду (в моем случае это команда /start), которая отправляет текст и данную кнопку под чатом:

    if (strpos($message, "/start") === 0) { // Команда /start, вызов кнопки под чатом
        $post = [
            'chat_id' => $chat_id,
            'text' => 'Напиши любое сообщение или нажми на кнопку ниже, чтобы начать!',
            $cocktails_button = [[['text' => 'Открыть список коктейлей ']]],
            'reply_markup' => reply_keyboard($cocktails_button),
            'resize_keyboard' => true,
            'one_time_keyboard' => true
        ];
        sendRequest('sendMessage', $post);
    }
    Ответ написан
    Комментировать
  • Как вывести ответ после нажатия на кнопку?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Сначала я разобрался с ошибкой в вебхуке - причину ее возникновения я не нашел, так как в файле поле description отсутствовало, следовательно из-за чего конкретно вылезала ошибка было трудно понять. Я заменил функцию отправки сообщений на другую:

    function sendRequest($method, $post = '') {
    $ch = curl_init('https://api.telegram.org/bot' . BOT_TOKEN . '/' . $method);
    
    if ($post) {
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
    }
    
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
    }


    Она работает так же и ошибок не вызывает.

    Затем я разобрался с обработкой кнопок, точнее их обратных запросах (callback_query/callback_data). Я создал два файла - data, где я получаю chat_id, message, message_id, это мне нужно для отправки первичных сообщений (по типу приветствия, команд). Затем создал файл callback_query, куда поместил следующие строки -

    <?php
    
    $data = json_decode(file_get_contents('php://input'));
    
    
        $callback_query = $data->callback_query;
        $callback_query_id = $callback_query->id;
        $callback_data = $callback_query->data;
    
        $from = $callback_query->from;
    
        $user_id = $from->id;
        $username = $from->username;
    
        $message = $callback_query->message;
        $message_id = $message->message_id;
        $callback_message_text = $message->text;
    
        $chat = $message->chat;
        $chat_id = $chat->id;
    
        $inline_message_id = $callback_query->inline_message_id;


    С помощью них можно получать обратный запрос от нажатия на кнопки. Мой основной код стал выглядеть следующим образом:

    <?php
    
    include 'config.php'; // Токен бота
    include 'functions.php'; // Основные функции
    include 'data.php'; // Получение данных
    
    // Делается запрос
    $method = 'setWebhook';
    $url = 'https://api.telegram.org/bot' . BOT_TOKEN . '/' . $method;
    $options = [
        'url' => 'https://example.ru/bot.php'
    ];
    
    // То, что возвращается из запроса
    $response = file_get_contents($url . '?' . http_build_query($options));
    var_dump($response);
    
    if (strpos($message, "/help") === 0) { // Команда /help
        $post = [
          'chat_id' => $chat_id,
          'text' => 'Эта памятка создана для объяснения различных барменских
    терминов, посуды',
            $help_buttons = [
                [['text' => 'Термины ', 'callback_data' => 'terms']],
                [['text' => 'Посуда / Штучки ', 'callback_data' => 'dishes']]
            ],
            'reply_markup' => inline_keyboard($help_buttons)
        ];
        sendRequest('sendMessage', $post);
    } else {
    // Начальное сообщение
        $post = [
            'chat_id' => $chat_id,
            'text' => 'Давай определимся с категорией коктейлей:',
            $main_menu = [
                [['text' => 'Незабываемые ♾', 'callback_data' => 'the_unforgettables']],
                [['text' => 'Современная Классика ', 'callback_data' => 'contemporary_classic']],
                [['text' => 'Напитки Новой Эры ', 'callback_data' => 'new_era_drinks']]
            ],
            'reply_markup' => inline_keyboard($main_menu)
        ];
        sendRequest('sendMessage', $post);
    }
    
    include 'callback_query.php'; // Получение обратных запросов
    
    switch ($callback_data) {
        case 'the_unforgettables':
            $post = [
                'chat_id' => $chat_id,
                'message_id' => $message_id,
                'text' => 'Отлично, теперь выбери любой коктейль из списка:',
                $InlineTheUnforgettables = [
                    [['text' => 'Negroni', 'callback_data' => 'negroni']],
                    [['text' => 'Manhattan', 'callback_data' => 'manhattan']],
                    [['text' => 'Americano', 'callback_data' => 'americano']],
                    [['text' => 'Daikiri', 'callback_data' => 'daiqiri']],
                    [['text' => 'Old Fashioned', 'callback_data' => 'old_fashioned']],
                    [['text' => 'Ramos Fizz', 'callback_data' => 'ramos_fizz']],
                    [['text' => 'Clover Club', 'callback_data' => 'clover_club']],
                    [['text' => 'Gin Fizz', 'callback_data' => 'gin_fizz']],
                    [['text' => 'Vieux Carre', 'callback_data' => 'vieux_carre']],
                    [['text' => 'Sazerac', 'callback_data' => 'sazerac']]
                ],
                'reply_markup' => inline_keyboard($InlineTheUnforgettables),
            ];
            sendRequest('editMessageText', $post);
            break;
    }
    Ответ написан
    Комментировать
  • Как побороть ошибку "Wrong response from the webhook: 404 Not Found"?

    @fakin_kiska Автор вопроса
    Telegram Bots and iOS
    Решил проблему: оказывается нужно было поместить файл с кодом для бота на сервер, ибо только туда будет идти запрос и там он будет обрабатываться

    Убедитесь, что в доменном имени вы указываете название файла с исполняемым кодом, а не какое либо другое название (Например: исполняемый код называется bot.php, следовательно доменное имя будет выглядеть так - example.com/bot.php)

    Вроде бы банально, но нигде об этом не написано, когда начинаешь создавать бота с нуля
    Надеюсь все более менее понятно объяснил
    Ответ написан