Aaron.kr

Code • Data • Design • Education

Korean By Heart Flashcards React Native App

This is the project README cross posted from the GitHub repository: https://github.com/jekkilekki/reactnd-flashcards

(React Native Mobile App)

Korean By Heart is a React Native mobile app built in Expo. It utilizes:

  1. Redux to manage application state
  2. React Navigation for Switch, Stacked, Tabbed, and Modal Navigation
  3. AsyncStorage for maintaining app changes
  4. Expo Notifications to set reminders to use the app daily
  5. Native Base for styled components

This project was bootstrapped with Create React Native App.
It was built as part of Udacity’s React Nanodegree program.

Table of Contents

Overview

The primary purpose of this app is to provide a well-designed, comprehensive dictionary / flashcard app for learners of Korean. (i.e. I built it for myself) Therefore, some of the important features I needed in this app included:

A comprehensive data set

The data set in use is a list of nearly 6,000 Korean words I have stored in a Google Sheet spreadsheet with multiple pieces of meta-data (including the English translation, part of speech, origin, and so on). The list was exported as .csv and converted to a JSON object. Future iterations of the app will include:

  1. (possibly) Access to a dictionary API to fetch data directly from a “real” dictionary rather than maintaining a hard copy
  2. The ability to add pictures and example sentences – or other hints – to each flashcard

** Note: This was one of the biggest challenges in the app because there was often too much data being loaded at once in the CardList view. Therefore, I had to learn how to implement pagination and reloading of data at the end of my FlatList component.

Pictures

An app without pictures is boring. Therefore, each deck has its own uniquely identifying image. Future iterations of the app will include:

  1. Handling of local storage for pictures
  2. Access to the phone’s camera and gallery for adding pictures
  3. Ability to add pictures (ideally at a reduced resolution) to every card

Personalized data

Currently, whatever changes to Decks and Cards that users make are saved (and retrieved) in AsyncStorage.

However, I intend to make this app publicly available after completion and also wanted a way to allow users to sign up and login to access their data from cloud storage. Therefore, I’ve incorporated the beginnings of Firebase. With the proper _config file (not included in this repo), users would be able to sign up and login to access the Firebase database I’ve set up. Future iterations of the app will include:

  1. Profile information (possibly in a Drawer navigator, accessible by clicking the User icon in the upper-right corner of the app header)
  2. A personalized photo – replacing the User icon in the header
  3. Saving and retrieving data from Firebase (as opposed to – or in addition to? – AsyncStorage)
  4. Ability to login with additional services like Facebook, Twitter, and so on

iOS vs Android

Devices tested

  • iOS emulator (Xcode 9 + iOS 11.1)
  • Android emulator (Android Studio + Nexus 5)
  • LG G6 (real device, network access)
  • (not yet tested, but accessible) iPad 2

Through the development of this app, I noticed slight differences in the way the Xcode iOS emulator and Android Studio’s emulator handle the code. Notably (upcoming fixes):

  1. Swiper Cards (via react-native-deck-swiper) are not rendered on Android (emulator, nor device) – I’m working to solve this issue now, but may need to resort to a different <Component />
  2. Various sizing, placement, and color issues are not consistent across devices. For example, the login User icon in the upper-right of the header looks perfect on iOS, but has the wrong vertical padding on Android

** Note: After completing the basic functionality of the app, I’ll return to fix minor styling details.

Installation

The easiest way to install and run this app is on an actual device (rather than an emulator – which requires more setup).

At its most basic, clone this directory to your computer with:

git clone https://github.com/jekkilekki/reactnd-flashcards

Then, navigate to the newly created directory in your Terminal and run:

npm install
npm start

You may also replace npm with yarn if you have Yarn installed.

Next, install the Expo app on your Android or iOS device.

Finally, open the Expo app and scan the QR code from your Terminal (after running npm start).

More detailed instructions can be found in the official Create React Native App GitHub repository or the Expo Installation documentation.

App Functionality

Deck List

decklist

The DeckList screen is the ❤ of the application. This is the first screen that appears after loading the app. From here, users have access to:

  1. Pre-installed and sorted flashcard Decks
  2. AddDeck functionality (via the Floating Action Button in the bottom-right)
  3. CardsList and About screens from the Tabbed navigation
  4. Login via the User icon in the Header’s right corner
  5. [Upcoming]: Calendar that displays on which days the user studied
  6. [iOS]: A Permissions dialog appears to request permission to set LocalNotifications for the app. Android does not have this popup – permissions seems to be granted inherently

Future Development

  • Add Deck sliding ability (slide left to Delete, etc)
  • Add Deck editing and Deletion Redux functionality
  • Possibly add an additional (earlier) Home view – with access to different Series or Books of Flashcard Decks

Add Deck

adddeck

The AddDeck view sets a default image to be used as the New Deck image. It additionally requests a Deck Name and Deck Description.

Future Development

  • Disallow submission of the Form without at least the Deck Image and Deck Name
  • Set a default Deck Image when rendering Decks on the DeckList view as a missing uri value produces an error
  • Allow access to the device’s Camera or Gallery to select an image
  • Allow images to be stored within the app’s data / folders and accessed from there – rather than just using Internet images (which may use data)
  • Possibly ask for additional Meta info

Single Deck View

decksingle

The Single Deck view includes multiple parts:

  1. Add Cards to Deck with the Floating Action Button in the upper-right corner
  2. The full list of Flashcards is divided into subsets of 30 cards each to make studying and quizzing them much easier
  3. The full list of Flashcards (in this Deck) is available to view (and search) in the second tab
  4. The two tabs, Sets and Quiz have similar functionality – but pass an argument to the Quiz.js component to let it know whether we want the score recorded or not (not yet fully implemented)
  5. The six boxes above the tabs are intended to (one day) be used as different levels of a Spaced Repetition System (some details about this in the About view). Basically:
    • If a user has “Mastered” a card in the Quiz – it advances a box – and after passing through all the boxes, is removed from the Deck
    • If a user “Reviews” the card in the Quiz, it either remains in the current box, or moves back one box
    • If the card is “New” and the user doesn’t know it, it moves all the way back to the first box

Future Development

  • Fully implement the Leitner SRS box model
  • Enable users to “set” a subset number to divide the CardList into groups (currently set to 30)
  • make this also available on individual decks

Add Cards To Deck

addcardstodeck

The AddCardsToDeck view displays like the Single Deck view, but includes ALL Card data (and not just that specific to its own Deck). This allows users to click a flashcard ListItem to “add” it to their Deck. A notification Alert with the card’s Korean word pops up after successfully adding a card to the Deck. Users may also Search for cards to add. Clicking Close returns to the Single Deck view.

Future Development

  • Rather than displaying an arrow on every ListItem, display a circle
  • Empty circle = can be added
  • Green checkmark circle = already in the Deck
  • These should update dynamically as cards are added to the Deck
  • When adding cards to the Deck, allow users to select multiple cards at once (like with an empty circle or radio button as described above) – and add them all at once.
  • This functionality should behave in a similar way as KakaoTalk’s adding multiple friends to a chat

Studying and Quizzing

quiz

The Studying/Quizzing view is passed a prop telling the app which type of “Session” the user has initiated. In the future, this will be used to keep track of Quiz scores and Study sessions in different ways. The view includes:

  • A (flippable) Card at the top
  • Hint currently just jiggles the Card – but in the future, it should reveal the FIRST letter of the English translation
  • Reverse flips the card over to see the translation – and in the future, doing so should disable the “I know it” green button in the footer
  • Three “swipe” options at the bottom – from left to right:
  • I don't know it (also can Swipe Left on the card) – adds 0 points to the score and is considered “New”
  • Mark for review (also Swipe Top) – adds 0.5 points to the score and may be used if a Hint or Reverse button is pressed – this is considered “Learning”
  • I know it (also Swipe Right) – adds 1 point to the score and is considered “Mastered” – this button should be disabled if Hint or Reverse is pressed
  • Swipe Bottom on the card (future implemenation) should be used to remove the card from the Deck

Future Development

  • Disable I know it if Hint or Reverse are pressed
  • Reveal the FIRST letter of the English translation if Hint is pressed – also possibly reveal example sentences one-by-one as Hint is repeatedly pressed
  • Cards that are Marked for Review should be added to a new array that is iterated over after the initial Card array is completed – so they can be “reviewed” one final time before revealing the score (which will be adjusted after this functionality is implemented)
  • Possibly include a line of dots (or small icons) at the top indicating which card the using is viewing and/or reviewing

Quiz Results

quizresults

The Quiz Results page is broken down into multiple “stats” areas:

  1. Total percentage correct (“Learning” cards are currently assigned 1/2 the point value of “Mastered” cards) – also represented by a Circle Graph
  2. A breakdown of the score is indicated under the Total percent, and the point values of each button are shown under their respective graphs
  3. The number of cards swiped Left (I don't know it), Top (Mark for review), and Right (I know it) are indicated in the second stat bar
  4. The Time elapsed for the Study/Quizzing section is indicated in the third line – this currently displays in milliseconds but will be adjusted to display a “human readable” time
  5. The TOTAL Time for Deck quizzing sessions (will be) displayed in the final stat box. Currently, each study session’s elasped time is incremented and saved to AsyncStorage as studyTime in a Deck’s JS object. This value needs to be retrieved from AsyncStorage and converted to a “human readable” String here
  6. The option to “Restart” the session or return “Back to Deck” are presented in buttons at the bottom of the screen

Future Development

  • Make the Time strings into “human readable” times (including “Days”, etc – similar to the Audible app)
  • Retrieve the total studyTime value from AsynStorage and display it here

Card List

cardlist
cardlist-search

The CardList is sorted in Korean alphabetical order. One of the biggest struggles with this view was loading too many ListItems at once. Therefore, I had to develop a system of pagination and reloading as the end of the FlatList is reached. Users also are able to:

  1. Click a ListItem to view the Single Card – and all its meta data (including example sentences using the vocabulary word where available)
  2. Search for a Card [partially broken] – this functionality (due to the pagination feature) also loads the “next” page on each setState() call. This will be fixed in upcoming versions of the app
  3. Add a New Card (Floating Action Button)

Future Development

  • Cause the Search functionality to disallow reloading the paginated card data
  • Add a FILTER system to allow
  • Sorting by alphabetical English order
  • Listing only certain Parts of Speech (Nouns, Verbs, etc)
  • ListItems appearing in a certain Deck

Single Card View

cardsingle

The Single Card View displays a flashcard in the same manner as the Quiz component – but including the English translation as well as any example sentences below the card (this image does not show this). At the bottom of the screen, the Floating Action Button indicates that users should be able to “Edit” the current card – and as expected, pressing this button turns all the <Text /> components into <Input /> components with their respective current values. However, this functionality is not yet fully implemented as it doesn’t “Save” any changes made to the card.

Future Development

  • Create Redux actions for Edit and Delete – both in individual Cards, and individual Decks
  • These Redux Edit and Delete actions should also be present and available from the DeckList and CardList views (via swiping on a ListItem)
  • After Firebase authentication is implemented, the CRUD operations for Cards or Decks should be limited to logged in users

Login and Signup

login
signup

Under the current implementation of the Login and Signup pages, a user IS ABLE to both Signup to Firebase, AND Login (if the utils/_config.js file is present and includes appropriate Firebase keys.

Future Development

  • Possibly integrate the two views in a better (single screen) manner
  • Include the <KeyboardAvoidingView> component to be sure the device keyboard doesn’t cover the Input components – this also needs to be implemented in CardList’s Search field

Architecture

Korean By Heart is a React Native mobile app built in Expo which utilizes Redux to manage application state.

App updates are triggered by dispatching action creators to Redux reducers which return updated state information to the app. Components read the necessary state from the Redux store and there are no direct API calls in the components’ lifecycle methods. State-based props are mapped from the store rather than stored as component state.

Folder Structure

After cloning the GitHub repository, the project directory includes the following folders:

reactnd-flashcards/
  .expo/
  node_modules/
  assets/
  actions/
  components/
    shared/
    views/
  middleware/
  reducers/
  utils/

Future development:

I have plans to add Grammar Lists, Vocabulary from various books, and possibly even Phrase Lists in the future. As this app grows in size and complexity, I may need to break down the components/ folder into more managable pieces:

components/
  auth/
  cards/
  decks/
  quiz/
  appScreens/

/src/actions

From the Redux.js site:

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().

Actions are plain JavaScript objects. Actions must have a type property that indicates the type of action being performed. Types should typically be defined as string constants.

This app’s actions are contained within the following files and are self-explanatory:

  • shared.js (handles loading the initial app data)
  • authedUser.js
  • SET_AUTHED_USER (not yet implemented – to be incorporated with Firebase)
  • cards.js
  • SET_CARDS (from the “fake” database _DATA.js)
  • NEW_CARD
  • EDIT_CARD (work in progress)
  • DELETE_CARD (work in progress)
  • decks.js
  • SET_DECKS (called every time an action occurs in the decks – saves to AsyncStorage)
  • NEW_DECK
  • ADD_CARD_TO_DECK
  • RECORD_SESSION (records all stats from a study or quizzing session)
  • STUDY_TIME (increments total study time for the deck)
  • EDIT_DECK (work in progress)
  • DELETE_DECK (work in progress)

/src/components

All React Native components and component-specific CSS reside within the components folder.

/src/middleware

From the Redux.js site:

Middleware is some code you can put between the framework receiving a request, and the framework generating a response.

The middleware applied in this app includes thunk and a logger which “logs” information on the state of the application to the browser console after Redux actions are dispatched.

thunk

From Redux-thunk on GitHub:

Redux Thunk middleware allows you to write action creators that return a function instead of an action. The thunk can be used to delay the dispatch of an action, or to dispatch only if a certain condition is met. The inner function receives the store methods dispatch and getState as parameters.

Applying thunk as a middleware in this app allows us to call asynchronous actions and await their completion before dispatching additional actions (such as RECORD_SESSION followed by STUDY_TIME and then SET_DECKS to save the newly updated state to AsyncStorage).

/src/reducers

From the Redux.js site:

Reducers specify how the application’s state changes in response to actions sent to the store. Remember that actions only describe what happened, but don’t describe how the application’s state changes.

In Redux, all the application state is stored as a single object.

There are two major “slices” of state that need to be maintained and updated by our reducers. These are the cards and decks slices of state (authedUser (not yet fully implemented) is also maintained here but it has much less “work” to do as it only handles logging in or logging out).

The following files contain the app’s reducers which are combined in index.js with Redux’s combineReducers() function:

  • index.js (combines our reducers)
  • authedUser.js (not yet fully implemented)
  • decks.js
  • cards.js

Each of last two files, decks.js and cards.js contain specific actions from their relevant /actions files (see above).

/src/utils

The following files are contained within the /utils folder:

  • _config.js (excluded from the repo – would contain Firebase authentication data and keys)
  • _DATA.js (our “fake” database and default API calls)
  • api.js (handles AsyncStorage saving and retrieval)
  • colors.js (includes ALL Google Material Design color codes mapped to exported variable names)
  • helpers.js (handles generating UIDs, spliting decks into subsets, parts of speech design, and Local Notifications)

Future Development

Although much of the following list has been mentioned or hinted at above, here it is again in full and brief:

  • Data
  • Utilize dictionary site API
  • Utilize WP REST API for Grammar
  • Connect to the WP REST API to retrieve these lists
  • Personalization
  • Utilize Firebase database for user login and personalized data
  • Apply third-party login options (Facebook, Twitter, etc)
  • Create personalized profile options & settings (Drawer Nav)
  • Device
  • Allow Camera and Gallery access
  • Use local storage (or Firebase DB) for images
  • Upgrade
  • Include Grammar and Phrase Lists
  • Separate decks into Books or Series (separate “Home” view)
  • Restructure Components folders

Contributing

The best way to Contribute to this app is to open an Issue on GitHub.

Pull Requests are welcome especially if they help fix an Issue or solve a Problem listed in the Future Development section. I want to continue development on this project and make it a viable flashcard app for learning Korean. But I may not be very responsive due to other life obligations.

License

The Korean By Heart app is licensed under the MIT open source license and built with React Native, Expo, and Redux and uses the following third-party resources and node modules:

Troubleshooting

See the project README on GitHub.

Changelog

1.0.0 – 2018.10.05

  • Initial release

Comments

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.