Local Ink is an Android app that aims to connect members of the community to independent, local booksellers by recommending books to users based on a profile. The independent booksellers and small bookstores add details for their books that are used to match books with readers' preferences. The books are recommended based on the user's profile and availability at local bookstores. Users can then add these books to a wishlist to buy later or send the list to friends or family as gift ideas.
Here is a quick GIF of a couple featuers, but a watch the video for the full tour!
Here is a link to a video demo of the app with explanations! Click here
[Evaluation of your app across the following attributes]
Required Must-have Stories
Optional Nice-to-have Stories
Tab Navigation (Tab to Screen)
Flow Navigation (Screen to Screen)
https://www.figma.com/file/6TFIQDPIiqvo3lr4rwBAvG/Bookstore-app-wireframe?node-id=0%3A1
Book | Property | Type | Description |
---|---|---|---|
objectId | String | unique id for the book (default field) | |
title | String | Title of the book | |
author | String | Author of the book | |
cover | File (maybe URL?) | Image (or URL to image) of the cover of the book | |
synopsis | String | Summary of book from publisher | |
isbn | Number | Standard number that is used to identify books | |
genre | String | Genre the book falls into | |
age range | String | The book's target age range for readers | |
store | Pointer to Bookstore | The store selling this book | |
price? (optional) | Number | Price of the book | |
createdAt | DateTime | date when book is created (default field) | |
updatedAt | DateTime | date when book is last updated (default field) |
User | Property | Type | Description |
---|---|---|---|
objectId | String | unique id for the usesr (default field) | |
username | String | User's login username | |
name | String | Name of the store | |
isBookstore | Boolean | Whether this user is a bookstore user or not (a reader user) | |
profile | File | Store's profile image | |
geoLocation | Parse GeoPoint | User's current location in latitude/longitude | |
location | String | User's current location string address | |
profile (maybe) | File | User's profile image | |
wishlist | Array of Pointers to books | Array of all the books the user has on their wishlist | |
genrePreference | List |
The user's preference of genres for recommended books | |
agePreference | List |
The user's preference for target age ranges of recommended books | |
website | String | The bookstore's website url (optional) | |
createdAt | DateTime | date when user is created (default field) | |
updatedAt | DateTime | date when user is last updated (default field) |
List of network requests by screen and basic snippets for each Parse network request:
User registration screen
// Create the ParseUser
ParseUser user = new ParseUser();
// Set properties
user.setUsername(username);
user.setPassword(password);
user.setEmail(email);
user.setGenrePreference(genrePreference);
user.setLocation(location);
user.setAgePreference(agePreference);
user.setPricePreference(genrePreference);
// Invoke signUpInBackground
user.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
Intent i = new Intent(SignUpActivity.this, LoginActivity.class);
startActivity(i);
} else {
// Sign up didn't succeed.
Bookseller registration screen
Bookstore bookstore = new Bookstore();
// Set properties
bookstore.setName(name);
bookstore.setPassword(password);
bookstore.setEmail(email);
bookstore.setGenrePreference(genrePreference);
bookstore.setLocation(location);
bookstore.signUpInBackground(new SignUpCallback() {
public void done(ParseException e) {
if (e == null) {
//Successful sign up, now go to home screen
} else {
// Sign up didn't succeed.
Log in screen
ParseUser.logInInBackground(username, password, new LogInCallback() {
@Override
public void done(ParseUser user (or bookstore), ParseException e) {
// If the request is successful, the exception will be null
if (e != null) {
// Issue with log in
return;
} else {
// Log in successful
or
if (ParseUser.getCurrentUser() != null) {
// Someone is already logged in
}
User profile screen
ParseUser.getCurrentUser();
Edit user profile screen
ParseUser.getCurrentUser().setGenrePreference(genrePreference);
Bookstore profile screen
ParseUser.getCurrentUser()
Recommendations/"stream" screen
// I can think of two ways of doing this:
// Get all books and match by location & preferences(probably less efficient, more flexible)
ParseQuery
Or
// Get the nearest x number of bookstores and match the user's preferences in those bookstores to the books in those bookstores //(I think less flexible, more efficient)
// specify what type of data to query - Book.class
ParseQuery
// limit query to nearest x stores (or I might have to get all stores and find the nearest ones manually)
query.setLimit(STORE_LIMIT);
// order bookstores from nearest to farthest
// start an asynchronous call for bookstores
query.findInBackground(new FindCallback<Bookstore>() {
@Override
public void done(List<Bookstore> bookstores, ParseException e) {
// check for errors
if (e != null) {
//issue getting bookstores
return;
}
* Book detail screen
* (Read/GET) Query specific book (Might be done already in recommendations screen--unnecessary to do here?)
* (Update/PUT) Update/add book object to wishlist in User object
* Wishlist screen
* (Read/GET) Query logged in User and get their wishlist
ParseUser.getCurrentUser().getWishlist();
* Add book screen
* (Create/POST) Create a new book object
Book book = new Book(); book.setDescription(description); book.setCover(new ParseFile(image)); book.setAuthor(author); book.setGenre(genre); book.setAgeRabge(ageRange); book.setPrice(price); book.setUser(currentUser); book.saveInBackground(new SaveCallback() { @Override public void done(ParseException e) { if (e != null) { // Something has gone wrong return; }
- [OPTIONAL: List endpoints if using existing API such as Yelp]