# Unit 4 Project: Twitter Part 2
:::warning
📬 Submit this assignment by November 27th 11:59pm IST by emailing a link to your GitHub repository to submissions@ontraq.org
:::
## Unit 4 Project: Twitter Client - Part 2
### Overview
Build a simple Twitter client that supports viewing a Twitter timeline and composing a new tweet.
- [Video playlist](https://www.youtube.com/playlist?list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf)
- [Assignment intro](https://www.youtube.com/watch?v=-45U2DY7Q_M&list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf)
### Submission Instructions
* Make sure you are adding and committing files in git as you complete features and milestones
* Be sure to **include a README** containing a GIF walkthrough of your app.
* Use [this README template](https://courses.codepath.org/snippets/android_university/readme_templates/project_2_readme_part2.md?raw=true) in order to have a complete README.
**Project setup:** Continue using the same project from last week.
**Mockups**:
With required user stories completed:


With several optionals completed, the app might look like:



GIF walkthrough of a well-polished version of this assignment:

The required and optional user stories are outlined below.
## User Stories
- User can compose a new tweet (_**5 points**_)
- User can click a "Compose" icon in the AppBar on the top right
- [Compose Screen Setup](https://www.youtube.com/watch?v=Tl6_kO6NKDo&list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf)
- User can then enter a new tweet and post this to twitter
- User is taken back to home timeline with **new tweet visible** in timeline
- Newly created tweet **should be manually inserted into the timeline** and not rely on a full refresh
- [Publish Tweet and Insert into List](https://www.youtube.com/watch?v=zgg3uFh0taE&list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf)
- While composing a tweet, user can see a character counter with characters remaining for tweet out of 280
- Check out Tip #3 on the Hints section below on how to implement this feature
**Hints**: Check out the Hints below for troubleshooting or tips.
**Walkthrough:** Here is the entire [video walkthrough](https://www.youtube.com/playlist?list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf) for this project.
## Stretch Stories
- Improve the user interface and theme the app to feel "twitter branded" (_**1 to 5 points**_)
- Links in tweets are clickable and will launch the web browser (see [autolink](http://guides.codepath.org/android/Working-with-the-TextView#autolinking-urls)) (_**1 point**_)
- User can select "reply" from detail view to respond to a tweet (_**1 point**_)
- Move the "Compose" action to a [FloatingActionButton](https://guides.codepath.org/android/Floating-Action-Buttons) instead of on the AppBar. (_**1 point**_)
- Compose activity is replaced with a [modal overlay](http://guides.codepath.org/android/Using-DialogFragment) (_**2 points**_)
- Use Parcelable instead of Serializable using the popular [Parceler library](http://guides.codepath.org/android/Using-Parceler). (_**1 point**_)
- User can open the twitter app offline and see last loaded tweets (_**2 points**_)
- Tweets are [persisted into sqlite](http://guides.codepath.org/android/Twitter-Persistence-With-Room) and can be displayed from the local DB
- [Persistence with Room walkthrough](https://www.youtube.com/watch?v=qzg9tT03ukE&list=PLrT2tZ9JRrf6keV69n7hsy2VCaqQ4LWsf&index=5&t=0s)
- When a user leaves the compose view without publishing and there is existing text, prompt to save or delete the draft. If saved, the draft should then be [persisted to disk](http://guides.codepath.org/android/Persisting-Data-to-the-Device) and can later be resumed from the compose view. (_**2 points**_)
- Enable your app to [receive implicit intents](http://guides.codepath.org/android/Using-Intents-to-Create-Flows#receiving-implicit-intents) from other apps. When a link is shared from a web browser, it should pre-fill the text and title of the web page when composing a tweet. (_**1 point**_)
**Cliffnotes**
- (Cliffnotes)Â [ActionBar Guide](https://guides.codepath.org/android/Defining-The-ActionBar)
- (Cliffnotes) [Working with EditText](https://guides.codepath.org/android/Working-with-the-EditText)
- (Cliffnotes)Â [Using Intents](http://guides.codepath.org/android/Using-Intents-to-Create-Flows)
- (Cliffnotes)Â [Sending Network Requests](http://guides.codepath.org/android/Sending-and-Managing-Network-Requests)
## Hints & Troubleshooting
Getting stuck or not sure how to implement a specific feature?
Take a look at some of these [Android debugging video](https://www.youtube.com/watch?v=UH7bGwf7tM0&list=PLrT2tZ9JRrf7ziWU_Qtec6szeWylUTxp6) and some of these guides referenced in the video:
- [Debugging App Crashes Guide](http://guides.codepath.org/android/Debugging-Exceptions-within-your-App)
- [Guide to When Things Go Wrong in Android Apps](https://hackmd.io/s/rkO_BigjW)
- [Asking Effective Technical Questions](https://hackmd.io/s/BJ7LommsZ)
Here's a list of useful notes you may find helps save you time while developing the TwitterClient or running into problems:
* **Tip #0: Using the Debugger** You may notice issues with the debugger connecting or breakpoints within Android studio, particularly when setting breakpoints in background threads. In order to work around this, you need to **uncheck and recheck** the breakpoint **after** the debugger starts. Refer to [debugger troubleshooting sections](http://guides.codepath.org/android/Troubleshooting-Common-Issues#debugger-isn-t-working-breakpoint-in-thread-is-not-hit) for workarounds.
* **Problem #0: API Rate Limiting** Twitter has an [aggressive rate limit for their API](https://developer.twitter.com/en/docs/basics/rate-limiting) meaning that after a certain number of requests in a window, the API stops working for a small window. Please read through that guide for more details. During initial testing, consider writing the timeline JSON response to a file and then reading from that file to display the list timeline.
* **Problem #1: Call to post tweet API doesn't work**. When you are sending an API call and not getting back a response, check the following:
* In order to post to Twitter, you need to **verify the email you signed up for twitter with** before posting.
* Am I using the correct request method (get, post, delete)? Make sure the API you are calling has the request method you expect. Make sure the code reads `client.post(...)`.
* Am I sending to the correct URL (check for typos)?
* Am I correctly using the `JsonHttpResponseHandler` when constructing the callback for the request?
* Am I passing the parameters into the request? Make sure you are passing the `status` parameter and that the `RequestParams` are being passed into the call i.e `client.post(url, params, handler);`
* Does my onSuccess callback accept the correct JSON response type i.e `public void onSuccess(..., JSONObject response)` rather than `JSONArray`?
* **Getting code 226 `This request looks like it might be automated`?** Make sure not to post the same message status over and over again or your account will become flagged. Instead, post a different status message each time to avoid issue.
* **Getting 401 Authorization Required**. Getting `Read-only application cannot POST`? Uninstall your app from the emulator or log out of the account by clearing the access token. Now, be sure that a [few settings are configured properly](https://apps.twitter.com/) such as such as selecting **Read, Write and Access direct messages** for access permissions, and **specifying a callback URL**. You must **specify a callback URL** and select the correct permissions or this POST API will not work! Be sure to **disable callback locking** as well. Once those settings are changed, you need to **re-install the app** and re-authenticate.
* **Problem #2: Using Room, got an error saying that there is no such table**. This is because Room only generates the schema if there is no existing database file. In order to "regenerate" the schema after creating a new model, the easiest way is to increase the version number in your database class (MyDatabase.java) and instantiate your database with `fallbackToDestructiveMigration()`. You can also [uninstall the app](http://stackoverflow.com/questions/12447839/how-to-uninstall-my-app-from-android-emulator-on-a-mac-10-7-4) from the emulator and allow it to be fully re-installed. This is because this clears the database file and triggers Room to recreate the tables based on the annotated models in the project.
* Once your app has launched, you can view the tables using the [[Stetho|Debugging-with-Stetho]] library. Open Chrome and visit `chrome://inspect` and click on the app. You can then navigate to `Resources` tab and find `Web SQL` to view the tables.
* We can also access the raw SQLite database underlying Room by using the adb shell to [download the file](https://gist.github.com/nesquena/f378fced35a168da3085). See [this guide](http://guides.codepath.org/android/Local-Databases-with-SQLiteOpenHelper#sqlite-database-debugging) for other options.
* **Problem #3: Using Room, the User object does not save**. This is because Room needs you to save all objects separately. Before saving a tweet, be sure to save **the associated user** first. Is is recommended that you denormalize the Tweet using an `@Embedded` on the User object to keep the column entries as part of the same table.
* **Problem #4: java.io.NotSerializableException: org.json.JSONArray**. If you encounter any issues passing an object (such as a tweet or user) into an intent, you may encounter serialization issues. These are caused by having fields that are not serializable defined in a model. For example `JSONObject` and `JSONArray` are **not serializable types** meaning you can't store these by default as member variables in a serializable class. If you need to store JSON data then you can apply [this simple pattern](http://stackoverflow.com/a/2657208/313399) to workaround the issue.
* **Tip #1:** Be sure to read through the API docs for this assignment. Review the available [twitter endpoints](https://developer.twitter.com/en/docs/api-reference-index) in particular the one for getting timelines and posting statuses. Ask yourself which other endpoints are most important (i.e profile timeline for a user, mentions, etc) and review those as well. If you're trying to understand how the Twitter API works, use this [API Explorer](https://apigee.com/console/twitter) tool. If you need to figure out the profile information for the current access token being used, use the [verify credentials](https://developer.twitter.com/en/docs/accounts-and-users/manage-account-settings/api-reference/get-account-verify_credentials) endpoint.
* **Tip #2:** Whenever sending a network request, be sure to **handle the failure case** as outlined in our [networking cliffnotes](http://guides.codepath.org/android/Sending-and-Managing-Network-Requests#sending-an-api-request). Not handling this case means your application is extremely brittle, take the time to properly notify the user and handle the behavior of the internet not being connected.
* **Note #1:** Make sure that after you compose a tweet that the **new tweet shows up in the timeline**. To do this, refreshing the timeline may not be enough because of the lag before the new tweet shows up in the timeline API call. Instead, after the tweet is successfully posted to twitter from within the compose screen, we can pass the Tweet back to the `TimelineActivity` through the intent result system to the parent activity and **inject the created tweet directly into the adapter for the timeline** from within `onActivityResult`. See the [intents cliffnotes](http://guides.codepath.org/android/Using-Intents-to-Create-Flows#returning-data-result-to-parent-activity) for how to return the result back to the timeline activity.
* **Note #2:** By default, your twitter client probably looks boring and uninteresting. Take a little time to spruce up your UI and add visual polish with [this guide](http://guides.codepath.org/android/Polishing-a-UI-Tips-and-Tools) and by reviewing the [styling a screen Q&A](http://guides.codepath.org/android/Styling-UI-Screens-FAQ).
* **Tip #3:** Displaying a character count for the twitter client as the user types their tweet. Each tweet can only be a maximum of 280 characters. To achieve this, you can add a TextView to your ComposeActivity and then attach a listener for when the user types text into the EditText. See the [event handling cliffnotes](http://guides.codepath.org/android/Basic-Event-Listeners#textchangedlistener) to see how to use the `addTextChangedListener` to fire events whenever the user types into the text field. If the total characters exceeds 280, consider disabling the submit button or making the count red to indicate that the tweet isn't valid.
* **Tip #4:** To simulate the loss of internet on your emulator, in Android Studio go to `Tools => Android => Android Device Monitor`. Open the "Android Virtual Device Monitor" perspective and then select the "Emulator Control" tab. Use the "Data" area to simulate losing access to the internet when testing network connection failures in your app.
## Concepts
By the end of this week, you should be able to answer the following questions:
1. What is OAuth and why is it needed?
2. What are fragments? Why were they introduced by Google?
:paperclip: [Slides (Fragments & Parse)](https://courses.codepath.com/course_files/android_university/slides/Slides%20(Fragments%20&%20Parse).pdf?raw=true)
## Topics in Focus
While there are many topics covered each week, the topics in focus are the ones that require deeper experimentation. This week the topics are:
* Advanced Navigation: [Fragments](http://guides.codepath.org/android/Creating-and-Using-Fragments)
* Explore the various stages of the [fragment lifecycle](http://guides.codepath.org/android/Creating-and-Using-Fragments#fragment-lifecycle)
* What are the best [fragment communication](http://guides.codepath.org/android/Creating-and-Using-Fragments#communicating-with-fragments) strategies
* What is the [custom listener pattern](http://guides.codepath.org/android/Creating-Custom-Listeners) and why is this pattern so commonly used?
* Why might we [hide rather than replace](http://guides.codepath.org/android/Creating-and-Using-Fragments#fragment-hiding-vs-replace) fragments in a container?
* Modern Fragment Architecture
* What is an activities core responsibilities when using fragments?
* How do we know when to [put code into an activity vs fragment](http://guides.codepath.org/android/Creating-and-Using-Fragments#organizing-your-code)?
* What is the case [against using fragments](https://medium.com/square-corner-blog/advocating-against-android-fragments-81fd0b462c97) or [using custom views instead](https://eng.lyft.com/building-single-activity-apps-using-scoop-763d4271b41)?
### Guides
- [Using the RecyclerView guide](https://guides.codepath.org/android/Using-the-RecyclerView)
- [Heterogeneous Layouts inside RecyclerView guide](https://guides.codepath.org/android/Heterogeneous-Layouts-inside-RecyclerView)
- [Endless Scrolling with AdapterViews and RecyclerView](https://guides.codepath.org/android/Endless-Scrolling-with-AdapterViews-and-RecyclerView)