Utopian Rocks Mobile - Update 0.1.0
Repository
https://github.com/tensor-programming/utopian-rocks-mobile
New Features
From prerelease version 0.0.1 to prerelease version 0.1.0; the main new features in this application are the Timer, the Vote Power Indicator, the Information drawer, the "check for update" Button, a Filter Menu and a few structural changes. This also includes minor UI improvements to make the application a bit smoother and more intuitive as well as some minor bug fixes.
The Timer and Vote Power Indicators
First let's talk about the Timer and Vote Power Indicators. The utopian.rocks website addresses these two elements by calculating the rough score of each contribution and simulating the voting system. It also uses the Beem library to further correct the vote power calculations to make them more accurate. In the mobile application, rather then manually calculating these two values in the same way that the website does, the application just grabs the html document. The application is then able to use css selectors to grab the values at the time of the document request and use them as initial values for both fields. The getHtml() function is responsible for grabbing the html document string and adding a static singleton version of it to the ParseWebsite
object.
The getVotePower() and getTimer() functions call the getHtml()
function and grab the appropriate values from the html document string. In the case of getTimer()
, the application needs to reformat the Timer string into a number of seconds. The application then counts down from this value by making use of the Observable.periodic()
method from the RxDart library. This code emmits data to the getTimer()
function every second and then passes the return data to the user interface. By doing this, the application is able to decrement the starting amount of seconds in real-time.
On the frontend, the application uses the intl library to format the seconds into something that is more readable. Here the seconds are passed into a DateTime
object and then formatted using the DateFormat.Hms()
function. This Timer is embedded on a BottomAppBar
along with the Vote Power indicator.
![bottomBar.png](https://steemitimages.com/640x0/https://cdn.steemitimages.com/DQmRDUgATKSFueVpWjk6GZnyfn8WPX9hzZC4ezBLXi8vLew/bottomBar.png)
Information Drawer and Package Info
I wanted to add some instructions and application information to the user interface. I decided to add a drawer to the application which would be able to serve this information. This drawer makes use of the Package_Info library. This library makes it easy to gain access to various pieces of information about the application including version, application name, and the application icon. An entirely new BLoC was created to serve this information to the UI widgets.
The BLoC contains an observable which serves the package information. In Flutter, drawers are created and destroyed every time you open and close them. Because of this, I needed to make the observable reusable and I was able to do this using the Observable.defer()
method. This method creates a new Observable from another Observable only once the observer subscribes to it. Since the Package_Info library serves its data through a Future value, I was able to create a one event Observable from the Future and wrap it in the Observable.defer()
call.
This information is then passed up to the InformationDrawer
widget through the InformationBloc
and it is used to programmatically generate the information for the drawer. This same stream is also re-used for the Update Button widget which is on the drawer.
![drawer.png](https://steemitimages.com/640x0/https://cdn.steemitimages.com/DQmddEnUgMJhiSyo8iLJM4K6TTwaEqo9o24hqSqC6utt7fp/drawer.png)
Release Update Button
Originally, I wanted to make it so that the application would automatically check for updates when the user opened it. I was able to achieve this in some of the early versions but I found that an unauthenticated github API request had a request limit. For a period, I then made it so that the Update Check only happened a single time or happened over a larger period of time, but I found both of these solutions to be unintuitive and intrusive. My final solution was to add a Button to the Information Drawer which the user could press to check for updates. What makes this solution more elegant is that the user can initiate the process and if there is no update available, a notification can be deployed.
For this to work properly, I needed access to the github API so that the application could look at the releases on the utopian-rocks-mobile repository. This was done by creating a GithubApi repository object. As with the contributions results, the GithubApi
calls to a REST api endpoint and grabs JSON. The JSON is then serialized through a small model which was added to the model file. This data is then passed to the UI from the InformationBloc
in a way that is similar to the Package Information. Since this event is tied to a button and a DialogWindow
; it needs to use the Observable.defer()
method so that it can be reusable. Every time a user pushes the button, it creates a new observable which then checks the application's version number with the latest version number from the Github API. If there is a new release or the release number does not match the one inside of the application, then a DialogWindow
is deployed telling the user that they can update the application. Otherwise, a second DialogWindow
is deployed telling the user that there is no new release. The first DialogWindow
contains a button which calls to the Url_Launcher library and it sends an intent to the application with the release url attached to it.
![notification-download.png](https://steemitimages.com/640x0/https://cdn.steemitimages.com/DQmRB2o91uQ4N2wCzgyreXrqPSH6PXPhDkrQpbH9cry52sb/notification-download.png)
![notification.png](https://steemitimages.com/640x0/https://cdn.steemitimages.com/DQmdMnABDamxHN5GK7wa54DQXiymrbWTusiFMWUkZ9MJiTt/notification.png)
Building the Filter Menu
The utopian.rocks website recently added the ability to filter through the contributions by category and I wanted to add this feature to my application as well. I did this by adding a popup menu to the bottom application bar next to the Timer and Vote Power Indicators. The PopupMenu
is programmatically generated by mapping over a list of all of the categories as well as an "all" filter. Each Category Icon, Name and Color is bound to a ListTile
inside of a PopupMenuItem
widget. For the "all" filter, the generic Utopian Icon was used along with the Utopian Purple Blue Color. When the user selects a filter from the PopupMenu
the category string is added to a Sink
in the ContributionBloc
object.
Creating this functionality was a little more tricky then I originally had anticipated because applying a filter to the list of contributions does not emit a new event through the results stream. This means that the StreamBuilder
widgets will not rebuild the UI to account for this change. Originally, I was manually invoking an emission event by re-applying the tabName
string to the tabName Sink
. This made the application think that it was changing from one page to the next which would force a rebuild. This way of doing things was flawed however, because it caused the page to build twice when the user changed from one tab to the next. Sometimes, contributions from one page would bleed over to the next page as a result.
To correct this, I used of a new filteredResults
Observable and the Observable.combineLatest2()
method. The Observable.combineLatest2()
method takes two streams and then passes them through a function to create a new stream. In this case, the two streams are the original results
stream and the filter
sink. These two streams are then passed into a applyFilter
utility function which checks to see whether or not the filter equals the "all" string. If it doesn't the application iterates through all of the contributions and checks the filter against the contribution's category field. The function then returns a new list of contributions which are only in that specific category.
![filter-menu.png](https://steemitimages.com/640x0/https://cdn.steemitimages.com/DQmexN2H3XBMWUhE1m6LuBqfvAvGXbVZpsoTLg9aqB3hHzb/filter-menu.png)
More information
If you want to learn more about the changes made between the different releases, make sure to take a look at the changelog document in the repository. If you'd like to get this application, you may do so by accessing the releases inside of the repository; this will change when the application is deployed to the Google Play and iOS App stores. Also, as of right now, there is no iOS build for this application so if you want to use it on iOS you must build it yourself.
If you'd like to contribute to this project, feel free to make you way over to the repository and open a issue or pull request. Bug reports and suggestions are more than welcome.
Hi there,
Great to see the mobile version is having progress.
I personally don't like this idea. If the utopian.rocks API doesn't have it, it's possible to do the same calculations.
https://steemit.com/@emrebeyler.json
last_vote_time
andvoting_power
properties.This would reduce the HTTP requests from two to one.
Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.
To view those questions and the relevant answers related to your post, click here.
Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]
Well normally I would agree with you. Pulling in an entire HTML document and making a bunch of requests is a fairly bad practice for any application and even worse on a mobile application. That being said, the Idea is to eventually make it so that the application pulls in the HTML a single time on starting up and then it makes its own calculations from there. I am going to add caching next and this will be a big part of it. I looked into doing the calculations manually before and doing them from scratch was fairly performance heavy. The other way to do it would be to make an API request to the steem API for the Utopian vote and recharge information which you suggested, but I really would rather avoid using the steem API if possible. (A utopian API on the other hand would be an entirely different matter wink wink).
Thank you for moderating my contribution @emrebeyler
Thank you for your review, @emrebeyler!
So far this week you've reviewed 9 contributions. Keep up the good work!
@tensor, have you solve the problem on how to use SVG in Flutter?
SVG is not currently supported in flutter. There are some libraries but it involves much more pain then its worth. In my case, the utopian Icons were in Font format so it was very easy to use just code points and IconData objects to create Icons which I could scale and color etc.
Hi @tensor!
Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server
Hey, @tensor!
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!
Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).
Want to chat? Join us on Discord https://discord.gg/h52nFrV.
Vote for Utopian Witness!