Android Final Project: Book Exchange

I am now working on a final group project for the Android class. Since the final project for iOS was optional, I opted out so I could focus on the Android project with my team!

Our app is a bit like GoodReads in that it enables you to search for books. However, the added feature is that users can post books they’d like to sell, buy, or trade! Hence the name “Book Exchange”.

We are working in 4 weekly sprints in order to meet our December 3rd deadline.

So far we have completed 2/4 sprints!

During Sprint 1, we addressed the following user stories:

  • User should be able to register an account
  • User should be able to login
  • Login should be persistent
  • User should be able to logout

During this sprint, I was responsible for user registration. I used the Parse library to accomplish this. We also had to set up the backend in order to store our users and our book posts.

Here’s what our app looked like at the end of Sprint 1:

Sprint 2 was a bit more involved and I was assigned both user stories for this one:

  • User should see top sellers on search screen by default before query is sent via the search bar
  • Allow user to search by ISBN

To display best sellers on the search screen, I used the NYT Book API and displayed the information in a TableView within our default fragment. Within that fragment’s onActivity method, I put an event handler for a search field. This way, I was able to avoid using Android’s default search view and just use an EditText and Button for our search.

Once the user submits a query, the query String is put into a Bundle and passed to the SearchResults fragment where our Back4App backend is queried for results. I used the Parse library to get the results back as Post objects that can be added to a TableView within that fragment.

Parstagram Version 2

This is the final week of the CodePath classes before we begin final projects to showcase what we have learned! I worked on Parstagram version 2 in both Android and iOS.

For the Android version, I used Fragments for the first time. Instead of cramming a bunch of code into the MainActivity, I was able to separate the code into three fragments–one to display a user’s timeline of posts, one to show the user’s profile, and another to compose a new post. The corresponding views for each of these fragments are displayed depending on which menu item in a Bottom Navigation View is clicked on:

In the iOS version, implemented persistent login, the ability to logout, and the ever-so important ability to add and view comments on a post:

Back4App and Parstagram

This week was exciting because, instead of using an external API, we were able to create our own backend for an Instagram-like app in both Android and iOS. We used Back4App to get and post user and post data. This required use of the Parse library in both projects.

In the Android version of the application, I used Parse to enable a user to sign up for an account and to login. I also implemented persistent login and the ability for the user’s to pull up the system’s camera to take a picture, add a caption, and post it to the backend.

In the iOS version, I did the same thing, but also implemented the ability to view the last 20 posts (something that I will get to in the Android version next week).

Twitter Client Version 2

I improved both the Android and iOS versions of my simple Twitter client this week.

In the Android version, users can now compose and post a new Tweet through a compose button added to the ActionBar. After a user posts a tweet, the timeline is automatically refreshed! I used a library called Parcelable in order to pass information from one Android activity to another. Using Parcelable is more time/memory efficient than the Serializable interface.

On the iOS side, I also implemented the ability for a user to compose and post a Tweet. However, what differed from the Android implementation this week was that I also added the ability to favorite and retweet tweets!

Twitter Client Version 1

In both the Android and iOS classes, we created a simple Twitter client using Twitter’s API to authenticate a user to log them in and to fetch tweets from a user’s timeline to display them on the screen.

In the Android app, I also displayed the relative timestamp (e.g. how long ago a tweet was posted) next to each Tweet and implemented pull to refresh. I also tried to be a bit more creative with theming the app:

I also implemented pull to refresh in the iOS version of the Twitter client. In addition, I was able to implement persistent login and the ability to logout:

Flixter Part 2

This week, I worked on improving both the Android and the iOS versions of the Flixter.

In the Android app, I added a RatingBar that converted a movie’s score out of 10 to stars on a view for a particular movie. Using YouTubePlayerView, I also added the ability to play a movie’s trailer video in full screen:

In the iOS app, I added the ability to view a grid layout of movie posters matching a certain genre using a CollectionView and I also added the ability to tap on a TableView cell in order to view a detailed screen about a particular movie:

Web and Mobile Certificate

I’ve resumed teaching high school CS full-time, but I am also now working towards an advanced certificate in web and mobile applications development.

I was perhaps a little overzealous and enrolled in too many interesting classes initially:

  • Linear Algebra (this wasn’t required for my CS degree, but a lot of grad CS courses require it, if I choose to go on to a Masters/PhD)
  • Advanced Web Frameworks (part of the web and mobile applications program)
  • Android Development (a free course through CodePath)
  • iOS Development (another free course through CodePath)

I have decided to drop the linear algebra course since it is the only one that requires specific meet times, which made things a bit challenging since the course meets right after I finish teaching, when my brain was ready for a nap.

Here’s the first Android assignment I’ve completed, Flixter. It uses NYT’s Movie API to populate a TableView with information fetched from a query.

Animated gif of the Flixter app in use.

You can find more details about the app and its source code on Github!

We also did the Flixter assignment in the iOS class using Swift:

Here is my project on GitHub

MinStack

Problem:

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time. These are the operations you should implement for this data structure.

push(x) -- Push element x onto stack.
pop() -- Removes the element on top of the stack.
top() -- Get the top element.
get_min() -- Retrieve the minimum element in the stack.

Example:

min_stack = new MinStack()
min_stack.push(-2)
min_stack.push(0)
min_stack.push(-3)
min_stack.get_min()   # Returns -3.
min_stack.pop()
min_stack.top()       # Returns 0.
min_stack.get_min()   # Returns -2.

1. Understand

# Design a minstack class with the following functionality:
# push(x) -- pushes element x onto stack
# pop() -- removes the element on top of stack
# top() -- returns the top element
# get_min() -- returns the min element in stack

## Example:
# min_stack = new MinStack()
# min_stack.push(-2)
# min_stack.push(0)
# min_stack.push(-3)
# min_stack.get_min()   # Returns -3.
# min_stack.pop()
# min_stack.top()       # Returns 0.
# min_stack.get_min()   # Returns -2.

2. Match

# Can use a list to implement the stack
# Since we're interested in also returning
# the minimum element, we can sacrifice space
# for time by storing tuples containing a pair:
# the element added to the stack and the current min

3. Plan / Pseudocode

# MinStack objects have a single class variable:
# a list of tuples
# Functions:
## push(x)
# If the list is empty, just append (x, x)
# since x will also be the current minimum
# Otherwise, check if x is less than the current min
# (will be located at [-1,1] or the second value
# in the last tuple in the list)
## pop()
# If the list isn't empty,
# remove the last item in list
## top()
# If the list isn't empty,
# Return element at [-1.0] or the first
# value in the last tuple in the list
## get_min()
# Return the element at [-1,1] or the second
# value in the last tuple in the list

4. Implement

5. Review

For the given example:

min_stack = new MinStack()
min_stack.push(-2)
min_stack.push(0)
min_stack.push(-3)
min_stack.get_min()   # Returns -3.
min_stack.pop()
min_stack.top()       # Returns 0.
min_stack.get_min()   # Returns -2.

We get the expected results:

6. Evaluate:

If I had just pushed the elements to the stack instead of a collection of the element and the current min, I would have had to have implemented the get_min function differently.

The get_min function would have had a time complexity of O(N) because I would have had to have traversed the entire list to compute the minimum value. However, by using additional space O(2N), still technically O(N), to store the current minimum every time a new element was pushed to the stack, the time complexity of the get_min function is constant time O(1) since it will always be in the last tuple in the list.

Multimap

Problem:

One common pattern when using hash tables requires building a Map whose values are Collection instances. In this challenge, we’ll take the output of the previous challenge and invert it.

Write a program that takes as its input a HashMap<String,Integer> and returns a HashMap<Integer,HashSet<String>> containing the same data as the input map, only inverted, such that the input map’s values are the output map’s keys and the input map’s keys are the output map’s values.

Example:

Consider the example output for Hash Table Word Count. Using that map as the input, the output for this challenge would be:

2 → ["to", "be"]
1 → ["or", "not", "that", "is", "the", "question"]

1. Understand

# Write a function that takes the output from getFreqDict
# (a dictionary with String:Int key:value pairs)
# and returns a dictionary with Int:HashSet<String> key:value
# pairs where the int is the unique counts and the
# Set is the set of unique words that have that count
# For example, for the string input 
# "To be or not to be, that is the question."
# The output of this function would be the dictionary:
# 2 → ["to", "be"]
# 1 → ["or", "not", "that", "is", "the", "question"]

2. Match

# This is a HashMap / dictionary problem
# We already created a dictionary of all the unique words
# and their counts. We need to iterate on each of these entries
# to create a new dictionary with unique counts as keys
# and a set of words that have these counts as the value

3. Plan/Pseudocode

# Need a new empty dictionary to store results
# Take the dictionary we get from getFreqDict() as input
# Iterate on each entry and check if the value (count) already
# exists as a key in our new dictionary.
# If it doesn't, add the count as the key in this new dictionary
# and a Set containing the word as the value
# If it does exist, add the newly encountered word to the 
# set existing at this key
# return the new dictionary after iteration halts

4. Implement

5. Review

Output for the sentence “To be or not to be, that is the question.”:

6. Evaluate

The solution is a complexity of:

O(N) space and O(N) time

Hash Table Word Count

Problem:

Write a program which takes as its input a String of natural language text and outputs a HashMap<String,Integer> whose keys are the unique words in the input and whose values are the number of times those words occur. The algorithm should be case-insensitive (e.g. “Program” and “program” would count as the same word) and ignore punctuation and whitespace.

Example:

Given the input "To be or not to be, that is the question", the outputted HashMap would contain 8 entries, with two words having a count of 2 and six words having a count of 1:

"to"        → 2
"be"        → 2
"or"        → 1
"not"       → 1
"that"      → 1
"is"        → 1
"the"       → 1
"question"  → 1

1. Understand

# Write a program that takes a String as input
# And outputs a dictionary with String:Int key:value pairs
# The keys are unique words (case insensitive 
# and ignoring whitespace and punctuation)
# Values are frequency counts of that word in the string

## Example input: "To be or not to be, that is the question"
## Should output:
# "to"        → 2
# "be"        → 2
# "or"        → 1
# "not"       → 1
# "that"      → 1
# "is"        → 1
# "the"       → 1
# "question"  → 1

2. Match

# This is a string processing problem
# Can use Python's split() function to get individual words
# in a list and use .lower() to convert each word to lowercase
# and strip() to strip whitespace and punctuation

3. Plan / Pseudocode

# Start with empty dictionary and input string
# First, convert string to a list with split()
# Second, iterate through each word in the list and:
# * convert to lowercase lower()
# * strip whitespace and punct strip()
# * check if its in the dictionary
#   * if it's not, add it with a value of 1
#   * if it is, increment the value associated with the key
# return the dictionary

4. Implement

5. Review

6. Evaluate

Currently all non-alphabetical characters are stripped from the string by using regex.

The algorithm runs at:

O(N) Time and Space