A Flutter App to retrieve Visa Dates automatically using telegram bot API.
Introduction
In today’s lesson we are going to create a simple yet sophisticated automated Flutter Application with the use of Telegram Bot Api and Web View. Let’s deep dive into the topics we are going to discuss to today.
Above is app tutorial on how to use it.
APP LINK: https://drive.google.com/drive/folders/1ze50PtMKyaL6Fyjuh5PPeE3vwL89tsYT?usp=sharing
Contents Of The Lesson
- Home Screen
- Flutter Secure Storage
- UI Explanation
- Web View
- Telegram Bot Integration
- Automation Logic
- GITHUB REPO LINK
Home Screen
Let’s begin with designing our home UI, I have simply added three TextFormField Inside Column Widget to get the required information from the user. It consists of three vital info required i.e Telegram Bot API token, Id or Channel ID, and Desired date to be notified. Let me show you the code, You will have a better grasp in that way.
From the above code, you can see I have added the TextFormFields inside the Column widget, just below the elevated button and other widgets, it's a simple design that I believe I don't need to explain. So let's move to the line 47, Here, I have used CheckBoxListTile For the Remember Info function where I have assigned a boolean _saveDetails by default I have set it true which can be changed by user as per their preference so the assigned SetState method with newValue which will be assigned by the user to our boolean _saveDetails.
In line 57, I have added an ElevatedButton to execute the process. In line 61 to 76, I have added the logic for executing to the next process. In line 62, I have added a conditional to check and Make sure none of the TextFormFields are empty or Null. In line 65 to 69, I have assigned the value which was entered by user to the global variables. I had assigned three global variables so that I could use them anywhere in the project. Below is the code which I had already assigned for the global variables in main.dart file.
The three global variables are userDate, userToken, and userId which will be used in the ProcessPage.
In line 70, I have added a method called _onRemember which is used for saving the user's typed information into the Flutter Secure Storage. So, if user closes and opens the app again, He won’t need the type all the information again. Below is the code to understand more clearly.
From the above CodeSnap, lines 24 to 25 are used for performing the write operations to the device's local storage. Also, I have assigned a conditional there that if only the _saveDetails boolean is true then it will save the data else it won’t. _saveDetails is the same boolean that we used in the CheckboxListTile.
Just above the _onRemember() method you can see a Future method called _readSavedData(). Well it is used for reading the data when user closes and opens the app again. For that purpose, I have added it in the init function. Just above the dispose Function. If the user has used the remember info feature, this Method will simply check the previously saved Info and assign it to the textFormFields. So, The user won’t need to type every info again.
After the Remember info function use case, in line 71, I have used an AlertDialog to make sure the user has entered everything currently. Below is the code for the dialog contents.
Well, I think I don't need to explain whole UI design, I will stick to the functions and logic. I know you guys can figure out the UI part yourself.
So In lines 19 to 25, I have just added navigation to the next page and Navigator.pop to close the DialogBox. I have used the GetX Package for navigation & State management and other Utils.
Also, In line 62, I have added the user input data with String Interpolation so that they can review whether their entered data is accurate or inaccurate. So, This is all about the dialogBox. I have added couple of other AlertDialogBox for instructing user how to input the data. You can find the code from my Github Repo.
ProcessPage
Let’s move to the next page, where the whole automation and integration with the telegram bot API is carried out.
In the ProcessPage, I have firstly implemented the WebView through this Package webview_flutter. Well, I have used the WEBVIEW because the website from where I am going to extract the data is HCaptcha Protected. So, I have applied a very simple logic. I.E. Just logging in with a valid account, and keep refreshing the page every 20 seconds and get the new and updated data required by the user. and sending the data to our TelegramBot which will then post it to the channel or group as per the user assigned it to do. We will use the http POST REQUEST to send the data to the TelegramBot. So, Lets deep dive and see the code.
From lines 1 to 7, I have just set up the WebView, JavaUnrestricted means we can do operations with JavaScripts. The initial URL is the URL of our target Website. onWebViewCreated is a function that is invoked once the web view is created
WebViewController
is used to control a WebView and has different methods we can call on its instance to perform different actions on the WebView. onWebViewStarted is invoked when a page starts loading.
onWebviewStarted is invoked when a page starts while onProgress is invoked when a page is loading. similarly, onPageFinished is invoked when the website is fully loaded.
You’ll notice, that I have added the setState function in each step, basically, it is used for the LinearProgressIndicator to show the progress when the website is being loaded. onPageFinished, I have added a Future which simply evaluates the javascript of the site and helps us extract the required Info. I have used the querySelector to extract the data from the site. After getting the data, I mapped the data to the Date variable. After getting the data, It has several unwanted parts in it to remove the unwanted parts from the data I have used Regex and Velocity_x Package string extension Functions to get exactly the data the user wants.
Finally, after getting the required data, It’s time to send the data to the user assigned TelegramBot API.
if (finalDate.isNotEmpty) {if (onlyDate.toString().contains(userDate)) {final feedback = await http.post(Uri.parse("https://api.telegram.org/bot${userToken}/sendMessage?chat_id=${userID}&text=𝐔𝐩𝐝𝐚𝐭𝐞: $onlyDate, ${DateTime.now().year}\n\n<---𝐕𝐢𝐬𝐚 𝐃𝐚𝐭𝐞𝐬 𝐔𝐩𝐝𝐚𝐭𝐞--->\n\n$finalDate\n\n<--------------𝑬𝑵𝑫-------------->")).timeout(10.seconds, onTimeout: () {return http.Response("", 500);});if (feedback.statusCode == 500) {debugPrint("Timed Out"); }}}
else if (finalDate.isEmpty) {final feedback = await http.post(Uri.parse("https://api.telegram.org/bot${userToken}/sendMessage?chat_id=${userID}&text=<-------𝙎𝙚𝙧𝙫𝙚𝙧 𝙄𝙨𝙨𝙪𝙚------->\n\n𝑹𝒆𝒂𝒔𝒐𝒏: 𝑬𝒊𝒕𝒉𝒆𝒓 𝑫𝒖𝒎𝒎𝒚 𝒂𝒄𝒄𝒐𝒖𝒏𝒕 𝒅𝒆𝒂𝒅 𝒐𝒓 𝑺𝒆𝒓𝒗𝒆𝒓 𝑼𝒑𝒅𝒂𝒕𝒊𝒏𝒈 | 𝑷𝒍𝒆𝒂𝒔𝒆 𝒘𝒂𝒊𝒕......\n\n<--------------𝙴𝙽𝙳-------------->")).timeout(const Duration(seconds: 10), onTimeout: () {return http.Response("", 500);});
else if (finalDate.isEmpty) {final feedback = await http.post(Uri.parse("https://api.telegram.org/bot${userToken}/sendMessage?chat_id=${userID}&text=<-------𝙎𝙚𝙧𝙫𝙚𝙧 𝙄𝙨𝙨𝙪𝙚------->\n\n𝑹𝒆𝒂𝒔𝒐𝒏: 𝑬𝒊𝒕𝒉𝒆𝒓 𝑫𝒖𝒎𝒎𝒚 𝒂𝒄𝒄𝒐𝒖𝒏𝒕 𝒅𝒆𝒂𝒅 𝒐𝒓 𝑺𝒆𝒓𝒗𝒆𝒓 𝑼𝒑𝒅𝒂𝒕𝒊𝒏𝒈 | 𝑷𝒍𝒆𝒂𝒔𝒆 𝒘𝒂𝒊𝒕......\n\n<--------------𝙴𝙽𝙳-------------->")).timeout(const Duration(seconds: 10), onTimeout: () {return http.Response("", 500);});if (feedback.statusCode == 500) {debugPrint("Timed Out");}}Future.delayed(const Duration(seconds: 20), () {_controller?.reload();});},
From the above code, you can see that I have used a conditional in the first place to check whether the data we collected is empty or not, and if it is not empty we have again used another Conditional where we verify whether the data contains the date assigned by the user in the first place If it contains then the process continues. So, when the data also matches as per user assigned data, then we call an HTTP POST REQUEST to Telegram using the botToken and ChannelID we asked from the user in the first place. Did you notice something here? , I have used the global variable i.e userToken and channelID that we had assigned a value in our homePage using the setState function when the ElevatedButton(Start-Process) is pressed. It is just a reference so that you know how that function is used on this page. You will also notice I have also added time out so that if the website takes too long to load it will return statusCode 500 for which we simply used debugPrint which is useless though. We also have added another conditional i.e when the data extracted from the website is empty then We have called an HTTP POST REQUEST and sent a SERVER ISSUE OR UPDATING message to the user bot.
After the telegram integration, Here is a simple code for automation, at the end of the onPageFinished. You can see bit’s the code. It keeps refreshing the page every 20 seconds, updating users with data if it is available as they have assigned the date.
Future.delayed(const Duration(seconds: 20), () {_controller?.reload();});
After this, the remaining UI part is simply the Follow me containers and Notes for users.
SO THIS IS IT GUYS, WE HAVE SUCCESSFULLY COMPLETED OUR APPLICATION WHICH WILL PROVIDE US VISA AVAILABLE DATES, AND KEEP updating it EVERY 20 SECONDS. I HOPE YOU LIKED MY EXPLANATION. IF YOU LIKED MY CONTENT SHARE IT WITH YOUR FRIENDS AND FAMILIES.