MVP in Loklak Wok Android using Dagger2

MVP stands for Model-View-Presenter, one of the most popular and commonly used design pattern in android apps. Where “Model” refers to data source, it can be a SharedPreference, Database or data from a Network call. Going by the word, “View” is the user interface and finally “Presenter”, it’s a mediator between model and view. Whatever events occur in a view are passed to presenter and the presenter fetches the data from the model and finally passes it back to the view, where the data is populated in ViewGroups. Now, the main question, why it is so widely used? One of the obvious reason is the simplicity to implement it and it completely separates the business logic, so, easy to write unit-tests. Though it is easy to implement, its implementation requires a lot of boilerplate code, which is one of its downpoints. But, using Dagger2 the boilerplate code can be reduced to a great extent. Let’s see how Dagger2 is used in Loklak Wok Android to implement MVP architecture. Adding Dagger2 to the project In app/build.gradle file dependencies { ... compile 'com.google.dagger:dagger:2.11' annotationProcessor 'com.google.dagger:dagger-compiler:2.11' }   Implementation First a contract is created which defines the behaviour or say the functionality of View and Presenter. Like showing a progress bar when data is being fetched, or the view when the network request is successful or it failed. The contract should be easy to read and going by the names of the method one should be able to know the functionality of methods. For tweet search suggestions, the contract is defined in SuggestContract interface. public interface SuggestContract { interface View { void showProgressBar(boolean show); void onSuggestionFetchSuccessful(List<Query> queries); void onSuggestionFetchError(Throwable throwable); } interface Presenter { void attachView(View view); void createCompositeDisposable(); void loadSuggestionsFromAPI(String query, boolean showProgressBar); void loadSuggestionsFromDatabase(); void saveSuggestions(List<Query> queries); void suggestionQueryChanged(Observable<CharSequence> observable); void detachView(); } }   A SuggestPresenter class is created which implements the SuggestContract.Presenter interface. I will not be explaining how each methods in SuggestPresenter class is implemented as this blog solely deals with implementing MVP. If you are interested you can go through the source code of SuggestPresenter. Similarly, the view i.e. SuggestFragment implements SuggestContract.View interface. So, till this point we have our presenter and view ready. The presenter needs to access the model and the view requires to have an instance of presenter. One way could be instantiating an instance of model inside presenter and an instance of presenter inside view. But, this way model, view and presenter would be coupled and that defeats our purpose. So, we just INJECT model into presenter and presenter into view using Dagger2. Injecting here means Dagger2 instantiates model and presenter and provides wherever they are requested. ApplicationModule provides the required dependencies for accessing the “Model” i.e. a Loklak API client and realm database instance. When we want Dagger2 to provide a dependency we create a method annotated with @Provides as providesLoklakAPI and providesRealm. @Provides LoklakAPI providesLoklakAPI(Retrofit retrofit) { return retrofit.create(LoklakAPI.class); } @Provides Realm providesRealm() { return Realm.getDefaultInstance(); }   If we look…

Continue ReadingMVP in Loklak Wok Android using Dagger2

Animations in Loklak Wok Android

Imagine an Activity popping out of nowhere suddenly in front of the user. And even more irritating, the user doesn’t even know whether a button was clicked. Though these are very small animation implementations but these animations enhance the user experience to a new level. This blog deals with the animations in Loklak Wok Android, a peer message harvester of Loklak Server. Activity transition animation Activity transition is applied when we move from a current activity to a new activity or just go back to an old activity by pressing back button. In Loklak Wok Android, when user navigates for search suggestions from TweetHarvestingActivity to SuggestActivity, the new activity i.e. SuggestActivity comes from right side of the screen and the old one i.e. TweetHarvestingActivity leaves the screen through the left side. This is an example of left-right activity transition. For implementing this, two xml files which define the animations are created, enter.xml and exit.xml are created. <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false"> <translate android:duration="500" android:fromXDelta="100%" android:toXDelta="0%"/> </set>   NOTE: The entering activity comes from right side, that’s why android:fromXDelta parameter is set to 100% and as the activity finally stays at extreme left, android:toXDelta parameter is set to 0%. As the current activity, in this case TweetHarvestingActivity, leaves the screen from left to the negative of left. So, in exit.xml the android:fromXDelta parameter is set to 0% and android:toXDelta parameter is set to -100%. Now, that we are done with defining the animations in xml, it’s time we apply the animations, which is really easy. The animations are applied by invoking Activity.overridePendingTransition(enterAnim, exitAnim) just after the startActivity method. For example, in openSuggestActivity private void openSuggestActivity() { Intent intent = new Intent(getActivity(), SuggestActivity.class); startActivity(intent); getActivity().overridePendingTransition(R.anim.enter, R.anim.exit); }   Touch Selectors Using touch selectors background color of a button or any clickable can be changed, this way a user can see that the clickable responded to the click. The background is usually light accent color or a lighter shade of the icon present in button. There are three states involved while a clickable is touched, pressed, activated and selected. And a default state, i.e. the clickable is not clicked. The background color of each state is defined in a xml file like media_button_selector, which is present in drawable directory. <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/media_button_touch_selector_backgroud" android:state_pressed="true"/> <item android:drawable="@color/media_button_touch_selector_backgroud" android:state_activated="true"/> <item android:drawable="@color/media_button_touch_selector_backgroud" android:state_selected="true"/> <item android:drawable="@android:color/transparent"/> </selector>   The selector is applied by setting it as the background of a clickable, for example, touch selector applied on Location image button present in fragment_tweet_posting.xml . <ImageButton android:layout_width="40dp" android:layout_height="40dp" … android:background="@drawable/media_button_selector" />   Notice the change in the background color of the buttons when clicked. Resources: Some youtube videos for getting started: Newboston: https://www.youtube.com/watch?v=n4IyvL-ACbk Smartherd (from #5.1 to #5.8): https://www.youtube.com/playlist?list=PLlxmoA0rQ-Lzd9-NUrP5Wi18OMi4R-zs_

Continue ReadingAnimations in Loklak Wok Android

Implementing 3 legged Authorization in Loklak Wok Android for Twitter

Loklak Wok Android is a peer harvester that posts collected tweets to the Loklak Server. Not only it is a peer harvester, but also provides users to post their tweets from the app. Posting tweets from the app requires users to authorize the Loklak Wok app, the client app created https://apps.twitter.com/ . This blog explains in detail about the authorization process. Adding Dependencies to the project In app/build.gradle: apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' android { ... packagingOptions { exclude 'META-INF/rxjava.properties' } } dependencies { ... compile 'com.google.code.gson:gson:2.8.1' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' compile 'io.reactivex.rxjava2:rxjava:2.0.5' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' }   In build.gradle project level: dependencies { classpath 'com.android.tools.build:gradle:2.3.3' classpath 'me.tatarka:gradle-retrolambda:3.2.0' }   Steps of Authorization Step 1: Create client app in Twitter Create a twitter client app at https://apps.twitter.com/. Provide the mandatory entries and also Callback url (would be used in next steps). Then go to “Keys and Access Token” and save your consumer key and consumer secret. In case you want to use Twitter API for yourself, click on “Create my access token”, which provides access token and access token secret. Step 2: Obtaining a request token Using the “consumer key” and “consumer secret” request token is obtained by sending a POST request to oauth/request_token. As Twitter API are Oauth1 based the sent request needs to be signed by generating oauth_signature. The oauth_signature is generated by intercepting the network request sent by retrofit rest API client, the oauth interceptor used in Loklak Wok Android is a modified version of this snippet. The retrofit TwitterAPI interface is defined public interface TwitterAPI { String BASE_URL = "https://api.twitter.com/"; @POST("/oauth/request_token") Observable<ResponseBody> getRequestToken(); @FormUrlEncoded @POST("/oauth/access_token") Observable<ResponseBody> getAccessTokenAndSecret(@Field("oauth_verifier") String oauthVerifier); }   And the retrofit REST client is implemented in TwitterRestClient. createTwitterAPIWithoutAccessToken method returns a twitter API client which can be called without providing access keys, this is used as we don’t have access tokens right now. public static TwitterAPI createTwitterAPIWithoutAccessToken() { if (sWithoutAccessTokenRetrofit == null) { sLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); // uncomment to debug network requests // sWithoutAccessTokenClient.addInterceptor(sLoggingInterceptor); sWithoutAccessTokenRetrofit = sRetrofitBuilder .client(sWithoutAccessTokenClient.build()).build(); } return sWithoutAccessTokenRetrofit.create(TwitterAPI.class); }   So, getRequestToken method is used to obtain the request token, if the request is successful oauth_token is returned. @OnClick(R.id.twitter_authorize) public void onClickTwitterAuthorizeButton(View view) { mTwitterApi.getRequestToken() .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::parseRequestTokenResponse, this::onFetchRequestTokenError); }   Step 3: Redirecting the user Using the oauth_token obtained in Step 2, the user is redirected to login page using WebView. private void setAuthorizationView() { ... webView.setVisibility(View.VISIBLE); webView.loadUrl(mAuthorizationUrl); }   A WebView client is created by extending WebViewClient, this is used to keep track of which webpage is opened by overriding shouldOverrideUrlLoading. @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.contains("github")) { String[] tokenAndVerifier = url.split("&"); mOAuthVerifier = tokenAndVerifier[1].substring(tokenAndVerifier[1].indexOf('=') + 1); getAccessTokenAndSecret(); return true; } return false; }   As the link provided in callback url while creating our twitter app is a github page. The WebViewClient checks if it is a github page or not. If yes, then it parses the oauth_verifier from the github url. Step 4: Converting the request token to an access token A…

Continue ReadingImplementing 3 legged Authorization in Loklak Wok Android for Twitter

Implementing Tweet Search feature in Loklak Wok Android

Loklak Wok Android is a peer harvester that posts collected tweets to the Loklak Server. Along with that tweets can be searched using the app. This post describes how search API endpoint and TabLayout is used to implement the tweet searching feature. Adding Dependencies to the project This feature uses Retrofit2, Reactive extensions(RxJava2, RxAndroid and Retrofit RxJava adapter) and RetroLambda (for Java lambda support in Android). In app/build.gradle: apply plugin: 'com.android.application' apply plugin: 'me.tatarka.retrolambda' android { ... packagingOptions { exclude 'META-INF/rxjava.properties' } } dependencies { ... compile 'com.google.code.gson:gson:2.8.1' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0' compile 'io.reactivex.rxjava2:rxjava:2.0.5' compile 'io.reactivex.rxjava2:rxandroid:2.0.1' }   In build.gradle project level: dependencies { classpath 'com.android.tools.build:gradle:2.3.3' classpath 'me.tatarka:gradle-retrolambda:3.2.0' }   Implementation The search API endpoint is defined in LoklakApi interface which would provide the tweet search result. public interface LoklakApi { @GET("api/search.json") Observable<Search> getSearchedTweets( @Query("q") String query, @Query("filter") String filter, @Query("count") int count); }   The POJOs (Plain Old Java Objects) for the result of search API endpoint are obtained using jsonschema2pojo, Gson uses POJOs to convert JSON to Java objects and vice-versa. The REST client is created by Retrofit2 and is implemented in RestClient class. The Gson converter and RxJava adapter for retrofit is added in the retrofit builder. create method is called to generate the API methods(retrofit implements LoklakApi Interface). public class RestClient { private RestClient() { } private static void createRestClient() { sRetrofit = new Retrofit.Builder() .baseUrl(BASE_URL) // gson converter .addConverterFactory(GsonConverterFactory.create(gson)) // retrofit adapter for rxjava .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); } private static Retrofit getRetrofitInstance() { if (sRetrofit == null) { createRestClient(); } return sRetrofit; } public static <T> T createApi(Class<T> apiInterface) { // create method to generate API methods return getRetrofitInstance().create(apiInterface); } }   As search API endpoint provides filter parameter which can be used to filter out tweets containing images and videos. So, the tweets are displayed in three categories i.e. latest, images and videos. The tweets of different category are displayed using a ViewPager. The fragments in ViewPager are inflated by a class that extends FragmentPagerAdapter. SearchFragmentPagerAdapter extends FragmentPagerAdapter, at least two methods getItem and getCount needs to be overridden. Going by the name of methods, getItem provides ith fragment to the  ViewPager and based on the value returned by getCount number of tabs are inflated in TabLayout, a ViewGroup to display fragments in ViewPager in an elegant way. For better UI, the names (here the category of tweets) are displayed, for which we override getPageTitle method. public class SearchFragmentPagerAdapter extends FragmentPagerAdapter { private List<Fragment> mFragmentList = new ArrayList<>(); private List<String> mFragmentNameList = new ArrayList<>(); public SearchFragmentPagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } @Override public CharSequence getPageTitle(int position) { return mFragmentNameList.get(position); } public void addFragment(Fragment fragment, String pageTitle) { mFragmentList.add(fragment); mFragmentNameList.add(pageTitle); } }   For easy understanding an analogy with RecyclerView can be made. The TabLayout here functions as a RecyclerView, ViewPager does the work of LayoutManager and FragmentPagerAdapter is analogous to RecyclerView.Adapter. Now, the fragments which contain the…

Continue ReadingImplementing Tweet Search feature in Loklak Wok Android