New version up, time to reflect on some of the more interesting aspects of its development.
Changelog is short and sweet:
- Exam mode
- Interface language switch in menu
The Exam Mode doesn’t sound like that much of a deal, but it took quite a bit of development effort. I had to rethink navigation, make the main activity stateful, and add “Exams” section in statistics screen.
In the earlier versions the navigation model was rather simple. There was an “infinite” deck of questions (in my mental model and in code I call them “cards”, and they are implemented as fragments) that one can scroll through. The extra functions were stuffed in options menu. Now, with the exam mode there are a few problems:
- Need to make clear when we’re in “Training” mode and when in the “Exam” mode.
- When in exam mode, need to display exam progress (number of questions answered, elapsed time)
- When user completes exam, need to show exam results and allow to review cards with mistakes
As for the exam progress, I came up with what I thought was great idea: when user swipes through exam cards, show a centered translucent window with progress information. Here’s how it looked:
The spinning strip of numbers was a custom widget that was fun to build. Ultimately I ended up using a different method for showing exam progress, and this one was dropped from codebase.
As for exam results, I had an idea of having a new type of “card” that displays exam results instead of question and answers. So the decks of cards could look like this, training mode:
And exam mode:
When user completes exam, we should allow reviewing questions, for the educational effect. At least this is how I used the official online exam webapp: complete exam, then look at every question again, memorize my reasoning that lead to answer, and memorize whether that reasoning was correct or not.
Instead of looking at all answers, some might want to look just at the wrong answers, so my app should allow for that. So I stretched my “deck of cards” metaphor further:
I actually had this implemented, but as with the exam progress overlay window, this didn’t make it into the app. Although the navigation model was perfectly clear in my head, I was worried it wouldn’t make such perfect sense to others.
The need to clearly indicate training and exam modes was what ultimately lead me to introducing actionbar in the interface. That, and then-recently launched Android Design site, which established actionbar as a standard component of typical Android app.
I had considered adding actionbar before, but was reluctant to do so, because actionbar takes vertical screen space, and I was already struggling to fit some of the more text-heavy questions into available space. Making things vertically scrollable of course is the easy way out. Anyhow, I set out to try add actionbar and still fit everything into the screen.
Once the exam is over, there’s an “lightbulb” action item that cycles through the red cards:
ActionBarSherlock comes with tab support, perfect fit for the statistics screen:
The questions have varying amount of content:
- Some have illustrations, some do not
- Each question has 2-5 answer variants. Each variant could be as short as “Yes” or “No”, or it could take a couple sentences
- Questions and answers in Russian take considerably more screen space. It seems words in Russian are just longer on average
For the cards, I have my “ideal” layout with nice, readable font sizes, margins, and equal amounts of vertical space devoted to each answer. If I cannot fit content in the screen, I’m willing to gradually give these up:
- Allow answers to have different screen heights. This is for situations where one answer could fit in, for example, two lines of text, and another answer needs three lines. Give just enough space for each one. Doesn’t look as neat as equal heights, but oh well
- Question block has defined certain minimum height. If the content still doesn’t fit, remove that minimum height requirement
- Last resort–drop down on font sizes and try everything again
I wrote a crazy-messy-looking “constraints solver” that implements this strategy. And it works, every screen eventually kinda fits, even if the font sizes have to be dropped down significantly:
Another nice tweak I did, is this: if there are 4+ answers, and all are really short, display them in two columns:
Making the main activity stateful
Before there was exam mode, the main activity could get away without keeping any state information–except for statistics kept in sqlite database. If user leaves the app, and Android system kills the app, and user comes back again, it’s OK to start a brand new deck of cards. It isn’t quite so for exam. If I’m midway of an exam, then take and incoming call, and upon returning to app, the exam state is gone–I’d be greatly disappointed. So I made my activity save its state in
onSaveInstanceState(), and then restore it in
onCreate(). To make this process clean and easy, I implemented the Parcelable interface for some of my data objects.
In the closing, I thought it would be interesting to compare LOC of an early version which had just two short .java files, and the current version. Then:
$ find . -name *.java | grep -v R\.java | xargs cat | wc -l 159
$ find . -name *.java | grep -v R\.java | xargs cat | wc -l 2398