Implementing Timeline for Attendees Activity in Organizer App

Open Event Organizer App offers the functionality to Checkin/checkout attendees but the Organizer was unable to view when a particular attendee was checkin or checkout. We decided to implement a feature to view the timeline of checkin/checkout for each attendee. Let’s begin by adding the dependency in build.gradle. implementation "com.github.vipulasri:timelineview:"1.0.6" In the recyclerview item layout add the TimeLineView layout. Following are some of the useful attributes. app:markerInCenter - This defines the position of the round marker within the layout. Setting it to true, position it in center. app:marker - Custom drawables can be set as marker. <com.github.vipulasri.timelineview.TimelineView android:id="@+id/time_marker" android:layout_width="wrap_content" android:layout_height="match_parent" app:marker="@drawable/ic_marker_active" app:line="#aaa4a4" app:lineSize="2dp" app:linePadding="3dp" app:markerInCenter="true" app:markerSize="20dp" /> The ViewHolder class will extend the RecyclerView,ViewHolder class. In the constructor, we will add a parameter viewType and then set it to TimeLine Marker layout using method initLine. public CheckInHistoryViewHolder(CheckInHistoryLayoutBinding binding, int viewType) { super(binding.getRoot()); this.binding = binding; binding.timeMarker.initLine(viewType); } In RecyclerViewAdapter, we will override the getItemViewType() method. Here we will use the getTimeLineViewType method which takes in position and total size of the recycler view list and returns a TimeLineView type object. @Override public int getItemViewType(int position) { return TimelineView.getTimeLineViewType(position, getItemCount()); } References TimeLineView library by VipulAsri https://github.com/vipulasri/Timeline-View Android Documentation for RecyclerViewAdapter https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter Android Documentation for RecyclerViewView https://developer.android.com/reference/android/support/v7/widget/RecyclerView

Continue ReadingImplementing Timeline for Attendees Activity in Organizer App

Swipe to Check In/Out in Open Event Organizer App

Open Event Organizer App didn’t provide any option for the Event Organizer to view the list of Attendees present under an Order and check them in/out the event. Therefore, we designed a system such that the Organizer can just swipe the attendee present under an order to check them in or out. In this blog post, I will discuss how we implemented this functionality in Open Event Organizer App without using any third party libraries. Specifications We will create a separate class SwipeController.java which extends ItemTouchHelper.SimpleCallback and provide the swiping functionalities to our plain old recyclerview. We will call the super constructor with ItemTouchHelper.LEFT and ItemTouchHelper.RIGHT as arguments to provide left as well as right movements in each recyclerview list item. The bitmaps and paint object initialized here will be used later in onDraw. public SwipeController(OrderDetailViewModel orderDetailViewModel, OrderAttendeesAdapter orderAttendeesAdapter, Context context) { super(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); this.orderDetailViewModel = orderDetailViewModel; this.orderAttendeesAdapter = orderAttendeesAdapter; closeIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.close); doneIcon = BitmapFactory.decodeResource(context.getResources(), R.drawable.done); paintGreen.setColor(context.getResources().getColor(R.color.light_green_500)); paintRed.setColor(context.getResources().getColor(R.color.red_500)); } Next, we will override getMovementFlags method. This method decides the allowed movement directions for each recyclerview item. The deciding logic is that, if an attendee is checked in then the allowed movement is left to check out and if an attendee is checked out then the allowed movement is right to check in. If neither of the above case, then both movements are allowed. @Override public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { int dragFlags = 0; If (orderDetailViewModel.getCheckedInStatus( viewHolder.getAdapterPosition()) == null) makeMovementFlags(dragFlags, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); if (orderDetailViewModel.getCheckedInStatus( viewHolder.getAdapterPosition())) { return makeMovementFlags(dragFlags, ItemTouchHelper.LEFT); } else { return makeMovementFlags(dragFlags, ItemTouchHelper.RIGHT); } } The onChildDraw method involves the code doing actual drawing. The variables used in code are discussed below. ActionState - Checks the state of the recycler view item. We proceed with the below logic if the item is being swiped. dX - The distance by which the item is swiped. Positive for left and negative for right. Background - Background of the viewholder. Rectangular in shape and dimensions changed with change in dX. IconDest - Calculates the position where the icons (close icon or done icon) is placed in canvas Canvas - Java Canvas on which the drawing is done. We set the background and draw the bitmaps on their location in canvas. @Override public void onChildDraw(Canvas canvas, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { View itemView = viewHolder.itemView; float height = (float) itemView.getBottom() - (float) itemView.getTop(); float width = height / 3; RectF background; Paint paint; Bitmap icon; RectF iconDest; if (dX > 0) { background = new RectF((float) itemView.getLeft(), (float) itemView.getTop(), dX, (float) itemView.getBottom()); paint = paintGreen; icon = doneIcon; iconDest = new RectF((float) itemView.getLeft() + width, (float) itemView.getTop() + width, (float) itemView.getLeft() + 2 * width, (float) itemView.getBottom() - width); } else { background = new RectF((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom()); paint = paintRed; icon = closeIcon; iconDest = new RectF((float) itemView.getRight() - 2 * width, (float) itemView.getTop() +…

Continue ReadingSwipe to Check In/Out in Open Event Organizer App

Using RealmRecyclerView Adapter to show list of recorded sensor data from Realm Database

In previous blog Storing Recorded Sensor Data in Realm Database we have stored the data fetched from sensors into the Realm Database by defining model classes. In this blog, we will use the data stored in the Realm to display a list of recorded experiments in the form of well defining card view items so that it is easier for the user to understand. For showing the list we will make use of RecyclerView  widget provided by Android which is a more advanced version of the List view and is used to display large data sets in a vertical list, horizontal list, grid, staggered grid etc. RecyclerView  works in accordance with RecyclerView Adapter which is core engine that is responsible of inflating the layout of list items, populating the items with data, recycling of list item views when they go out of viewing screen and much more. For this blog, we are going to use a special RecyclerView Adapter provided by Realm itself because it integrates properly with the Realm Database and handles modifying, addition, deletion or updating of Realm data automatically and efficiently.    Step 1 Adding the dependencies As always first we need to add the following code in our build.gradle file to add the dependency of Realm database and RealmRecyclerViewAdapter. dependencies { implementation"com.android.support:recyclerview-v7:27.1.1 " implementation 'io.realm:android-adapters:2.1.1' } Step 2 Adding RecyclerView widget in our Activity layout file First, we need to create an activity and name it as “DataLoggerActivity”, inside the layout of the Activity add the <RecyclerView> widget. This RecyclerView will act as a container of our list item. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".activity.DataLoggerActivity"> <android.support.v7.widget.RecyclerView android:layout_below="@id/top_app_bar_layout" android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> Step 3 Creating the layout and View holder for the list item We have to create the layout of the list item which will be inflated by the Adapter. So for this create an XML file in res folder and name it “data_list_item.xml”. For the list of the experiments, we want to show Name of the experiment, recording time, recording date for every list item. For this we will make use of <CardView> and <TextView>. This gist shows the code of xml file. The layout of the list item created is shown in Figure 2 Now we need to create a view holder for this layout which we need to pass to the Adapter, the following code shows the implementation of View Holder for above list item layout. public class ViewHolder extends RecyclerView.ViewHolder { private TextView sensor, dateTime; ImageView deleteIcon; private CardView cardView; public ViewHolder(View itemView) { super(itemView); dateTime = itemView.findViewById(R.id.date_time); sensor = itemView.findViewById(R.id.sensor_name); deleteIcon = itemView.findViewById(R.id.delete_item); cardView = itemView.findViewById(R.id.data_item_card); } } Step 4 Creating the adapter for RecyclerView   In this step, we will start by creating a class called “SensorLoggedListAdpater” and for using use the RecyclerView adapter provided by Realm we need to make this class extend the RealmRecyclerViewAdpater class. But for that we need to pass two generic parameter: Model Class : This is class which define a…

Continue ReadingUsing RealmRecyclerView Adapter to show list of recorded sensor data from Realm Database

Displaying Events In Open Event Android

The user can browse through different events happening nearby or all over the world quickly from the events fragment, the latter is accessible from the bottom navigation bar and provides the user with some details about the event. The user if interested can select the event by clicking on it and will be taken to event details fragment where all the necessary information about the event is given. This blog post will help in understanding how events are fetched and shown in Open Event Android. The implementation of displaying events can be divided into two parts Fetching and storing events Displaying events on UI using recycler view Fetching and Storing Events To fetch an event we need to make get the request to the Open Event Server’s list events endpoint.    @GET("events?include=event-topic")    fun getEvents(): Single<List<Event>> We are using retrofit to make the network calls @GET specifies that it a get request and the URL inside the parentheses is the endpoint we are hitting. This method returns a Single<List<Event>>. Given below is the service layer method which uses DAO method and the API call and returns a Flowable<List<Event>>. fun getEvents(): Flowable<List<Event>> {        val eventsFlowable = eventDao.getAllEvents()        return eventsFlowable.switchMap {            if (it.isNotEmpty())                eventsFlowable            else                eventApi.getEvents()                        .map {                            eventDao.insertEvents(it)                            }                        .toFlowable()                        .flatMap {                            eventsFlowable                        }        }    } Firstly all the events from the database are fetched using the DAO method getAllEvents. If the list returned from the DAO method is not empty this function simply returns the events otherwise it will make the get request to server endpoint using Event API’s getEvents method and the response of this is mapped and stored into the database using the DAO method insertEvents this enables local caching of events and the same list of events are converted into flowable and returned by the function. The events fragment calls the view model function which specifies where to observe (we are observing on main thread because it is involved with UI related changes) and what to subscribe on also handles the displaying of progress bar. Given following is the implementation of the same. fun loadEvents() {        compositeDisposable.add(eventService.getEvents()                .subscribeOn(Schedulers.io())                .observeOn(AndroidSchedulers.mainThread())                .doOnSubscribe({                    progress.value = true                }).doFinally({                    progress.value = false                }).subscribe({                    events.value = it                }, {                    Timber.e(it, "Error fetching events")                    error.value = "Error fetching events"                }))    } You would notice the following parts in the above snippet doOnSubscribe - This part of code is executed whenever the source is subscribed Subscribe - This part of the code will have the end result when subscribed and success doFinally - This part of the code will be executed at the end   Creating Recycler View Recycler view is similar to ListView with some enhancements. When we are dealing with larger datasets our typical choice for displaying lists type UI is Recycler view because its views can be recycled and scrolled very efficiently. Every custom RecyclerView consists of three parts Layout for individual list items Recycler View adapter View Holder that holds views for individual list items The item UI for events in Open Event Android…

Continue ReadingDisplaying Events In Open Event Android

Link Preview Holder on SUSI.AI Android Chat

SUSI Android contains several view holders which binds a view based on its type, and one of them is LinkPreviewHolder. As the name suggests it is used for previewing links in the chat window. As soon as it receives an input as of link it inflates a link preview layout. The problem which exists was that whenever a user inputs a link as an input to app, it crashed. It crashed because it tries to inflate component that doesn’t exists in the view that is given to ViewHolder. So it gave a Null pointer Exception, due to which the app crashed. The work around for fixing this bug was that based on the type of user it will inflate the layout and its components. Let’s see how all functionalities were implemented in the LinkPreviewHolder class. Components of LinkPreviewHolder @BindView(R.id.text) public TextView text; @BindView(R.id.background_layout) public LinearLayout backgroundLayout; @BindView(R.id.link_preview_image) public ImageView previewImageView; @BindView(R.id.link_preview_title) public TextView titleTextView; @BindView(R.id.link_preview_description) public TextView descriptionTextView; @BindView(R.id.timestamp) public TextView timestampTextView; @BindView(R.id.preview_layout) public LinearLayout previewLayout; @Nullable @BindView(R.id.received_tick) public ImageView receivedTick; @Nullable @BindView(R.id.thumbs_up) protected ImageView thumbsUp; @Nullable @BindView(R.id.thumbs_down) protected ImageView thumbsDown; Currently in this it binds the view components with the associated id using declarator @BindView(id) Instantiates the class with a constructor public LinkPreviewViewHolder(View itemView , ClickListener listener) { super(itemView, listener); realm = Realm.getDefaultInstance(); ButterKnife.bind(this,itemView); } Here it binds the current class with the view passed in the constructor using ButterKnife and initiates the ClickListener. Now it is to set the components described above in the setView function: Spanned answerText; text.setLinksClickable(true); text.setMovementMethod(LinkMovementMethod.getInstance()); if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { answerText = Html.fromHtml(model.getContent(), Html.FROM_HTML_MODE_COMPACT); } else { answerText = Html.fromHtml(model.getContent()); } Sets the textView inside the view with a clickable link. Version checking also has been put for checking the version of Android (Above Nougat or not) and implement the function accordingly. This ViewHolder will inflate different components based on the thing that who has requested the output. If the query wants to inflate the LinkPreviewHolder them some extra set of components will get inflated which need not be inflated for the response apart from the basic layout. if (viewType == USER_WITHLINK) { if (model.getIsDelivered()) receivedTick.setImageResource(R.drawable.ic_check); else receivedTick.setImageResource(R.drawable.ic_clock); } In the above code  received tick image resource is set according to the attribute of message is delivered or not for the Query sent by the user. These components will only get initialised when the user has sent some links. Now comes the configuration for the result obtained from the query.  Every skill has some rating associated to it. To mark the ratings there needs to be a counter set for rating the skills, positive or negative. This code should only execute for the response and not for the query part. This is the reason for crashing of the app because the logic tries to inflate the contents of the part of response but the view that is passed belongs to query. So it gives NullPointerException there, so there is a need to separate the logic of Response from the Query. if (viewType !=…

Continue ReadingLink Preview Holder on SUSI.AI Android Chat

Implementing Skill Detail Section in SUSI Android App

SUSI Skills are rules that are defined in SUSI Skill Data repo which are basically the responses SUSI gives to the user queries. When a user queries something from the SUSI Android app, a query to SUSI Server is made which further fetches response from SUSI Skill Data and gives the response to the app. Similarly, when we need to list all skills, an API call is made to server to list all skills. The server then checks the SUSI Skill Data repo for the skills and then return all the required information to the app. Then the app displays all the information about the skill to user. User then can view details of each skill and then interact on the chat interface to use that skill. This process is similar to what SUSI Skill CMS does. The CMS is a skill wiki like interface to view all skills and then edit them. Though the app can not be currently used to edit the skills but it can be used to view them and try them on the chat interface. API Information For listing SUSI Skill groups, we have to call on /cms/getGroups.json This will give you all groups in SUSI model in which skills are present. Current response: { "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }}, "accepted": true, "groups": [ "Small Talk", "Entertainment", "Problem Solving", "Knowledge", "Assistants", "Shopping" ], "message": "Success: Fetched group list" } So, the groups object gives all the groups in which SUSI Skills are located. Next comes, fetching of skills. For that the endpoint is /cms/getGroups.json?group=GROUP_NAME Since we want all skills to be fetched, we call this api for every group. So, for example we will be calling http://api.susi.ai/cms/getSkillList.json?group=Entertainment for getting all skills in group “Entertainment”. Similarly for other groups as well. Sample response of skill: { "accepted": true, "model": "general", "group": "Shopping", "language": "en", "skills": {"amazon_shopping": { "image": "images/amazon_shopping.png", "author_url": "https://github.com/meriki", "examples": ["Buy a dress"], "developer_privacy_policy": null, "author": "Y S Ramya", "skill_name": "Shop At Amazon", "dynamic_content": true, "terms_of_use": null, "descriptions": "Searches items on Amazon.com for shopping", "skill_rating": null }}, "message": "Success: Fetched skill list", "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }} } It gives all details about skills: image author_url examples developer_privacy_policy author skill_name dynamic_content terms_of_use descriptions skill_rating Implementation in SUSI Android App Skill Detail Section UI of Google Assistant Skill Detail Section UI of SUSI SKill CMS Skill Detail Section UI of SUSI Android App The UI of skill detail section in SUSI Android App is the mixture of UI of Skill detail section in Google Assistant ap and SUSI Skill CMS. It displays details of skills in a beautiful manner with horizontal recyclerview used to display the examples. So, we have to display following details about the skill in Skill Detail Section: Skill Name Author Name Skill Image Try it Button Description Examples Rating Content type (Dynamic/Static) Terms of Use Developer’s Privacy policy Let’s see the implementation. 1. Whenever a skill Card View is clicked, showSkillDetailFragment()…

Continue ReadingImplementing Skill Detail Section in SUSI Android App

Using RecyclerView Instead Of ViewPager For Gallery

Phimpme is an Image app that provide camera, editing ,sharing options and a gallery section. The Gallery section allows us to view large number of images that are locally available in the users device. Generally developers used viewpager to swipe the horizontal images although we are also using viewPager but the problem is it is taking more time to load large size images and that disturb the user smooth experience. After so much research I came to new solution. So in this post, I will be explaining how to use recyclerview to view gallery images instead of viewPager. Let’s get started Make sure you have Recyclerview support in your dependencies in build.gradle. As recyclerView required an adapter and viewHolder to set data in recyclerView. So I will be explaining about adapter. ViewHolder for RecyclerView public static class ViewHolder extends RecyclerView.ViewHolder {   ImageView imageView;   LinearLayout linearLayout;   public ViewHolder(View itemView) {       super(itemView);       imageView = new ImageView(context);       linearLayout = (LinearLayout) itemView.findViewById(R.id.layout);       WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);       Display display = wm.getDefaultDisplay();       Point size = new Point();       display.getSize(size);       int width = size.x;       int height = size.y;       LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(               width, height);       imageView.setLayoutParams(params);       imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);       linearLayout.addView(imageView);   } } Right now the imageView is adjusting according to device screen size so that it will be compatible with all devices. I am passing the width and height in LayoutParams to parent of imageview i.e in our case linearlayout is parentView. Adapter for RecyclerView public ImageAdapter(ArrayList<Media> media) {   this.media = media; } @Override public ImageAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {   View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.unit_image_pager, null, false);   return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) {   Glide.with(getContext())           .load(media.get(position).getUri())           .diskCacheStrategy(DiskCacheStrategy.SOURCE)           .thumbnail(0.5f)           .into(holder.imageView);   holder.imageView.setOnClickListener(new View.OnClickListener() {       @Override       public void onClick(View v) {           basicCallBack.callBack(0,null);       }   }); } MediaList is an arrray of media that contains the list of images with URI that will help to load images. I am using Glide to load images you can use any library to load images. Adapter helps to load data in recyclerView. Now set viewPager where you require to scroll images horizontally @Nullable @BindView(R.id.photos_pager) RecyclerView mRecylerPager; mRecylerPager.setLayoutManager(linearLayoutManager); mRecylerPager.setHasFixedSize(true); mRecylerPager.setLongClickable(true); Our recycler view is ready now the most important part is to set things onPageChangeListner. For example : In Phimpme we are getting path of current position image to show in image description so to update the value we are writing that codde in onPageChangeListner and to update the toolbar. mViewPager.setOnPageChangeListener(new PagerRecyclerView.OnPageChangeListener() {   @Override   public void onPageChanged(int oldPosition, int position) {       getAlbum().setCurrentPhotoIndex(position);       toolbar.setTitle((position + 1) + " " + getString(R.string.of) + " " + size_all);       invalidateOptionsMenu();       pathForDescription = getAlbum().getMedia().get(position).getPath();   } }); To scroll to the given position we require to set the position to recyclerView and it can be done by the following code mViewPager.scrollToPosition(getCurrentPsotion()); This is how I implemented the recyclerView instead of ViewPager to load gallery images faster as compare to ViewPager. RecyclerView in Phimpme to load gallery Images Resources:      RecylerView official documentation: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.html ViewPager official documentation: https://developer.android.com/reference/android/support/v4/view/ViewPager.html Basic RecyclerView Tutorial: https://www.raywenderlich.com/126528/android-recyclerview-tutoria  

Continue ReadingUsing RecyclerView Instead Of ViewPager For Gallery

Implementing Skill Listing in SUSI Android App using Nested RecyclerViews

SUSI Skills are rules that are defined in SUSI Skill Data repo which are basically the responses SUSI gives to the user queries. When a user queries something from the SUSI Android app, a query to SUSI Server is made which further fetches response from SUSI Skill Data and gives the response to the app. Similarly, when we need to list all skills, an API call is made to server to list all skills. The server then checks the SUSI Skill Data repo for the skills and then return all the required information to the app. Then the app displays all the information about the skill to user. User then can view details of each skill and then interact on the chat interface to use that skill. This process is similar to what SUSI Skill CMS does. The CMS is a skill wiki like interface to view all skills and then edit them. Though the app can not be currently used to edit the skills but it can be used to view them and try them on the chat interface. API Information For listing SUSI Skill groups, we have to call on  /cms/getGroups.json This will give you all groups in SUSI model in which skills are present. Current response: { "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }}, "accepted": true, "groups": [ "Small Talk", "Entertainment", "Problem Solving", "Knowledge", "Assistants", "Shopping" ], "message": "Success: Fetched group list" } So, the groups object gives all the groups in which SUSI Skills are located. Next comes, fetching of skills. For that the endpoint is /cms/getGroups.json?group=GROUP_NAME Since we want all skills to be fetched, we call this api for every group. So, for example we will be calling http://api.susi.ai/cms/getSkillList.json?group=Entertainment for getting all skills in group “Entertainment”. Similarly for other groups as well. Sample response of skill: { "accepted": true, "model": "general", "group": "Shopping", "language": "en", "skills": {"amazon_shopping": { "image": "images/amazon_shopping.png", "author_url": "https://github.com/meriki", "examples": ["Buy a dress"], "developer_privacy_policy": null, "author": "Y S Ramya", "skill_name": "Shop At Amazon", "dynamic_content": true, "terms_of_use": null, "descriptions": "Searches items on Amazon.com for shopping", "skill_rating": null }}, "message": "Success: Fetched skill list", "session": {"identity": { "type": "host", "name": "14.139.194.24", "anonymous": true }} } It gives all details about skills: image author_url examples developer_privacy_policy author skill_name dynamic_content terms_of_use descriptions skill_rating Implementation in SUSI Android App Skill Listing UI of Google Assistant Skill Listing UI of SUSI SKill CMS Skill Listing UI of SUSI Android App The UI of skill listing in SUSI Android App is the mixture of UI of Skill listing in Google Assistant ap and SUSI Skill CMS. It displays skills in a beautiful manner with horizontal recyclerview nested in vertical recyclerview. So, for implementing horizontal recyclerview inside vertical recyclerview, you need two viewholders and two adapters (one each for a recyclerview). Let’s see the implementation. 1. First task is to fetch the information of groups in which skills are located. This line calls method in SkillListModel which then makes an API call to fetch groups. skillListingModel.fetchGroups(this) 2.…

Continue ReadingImplementing Skill Listing in SUSI Android App using Nested RecyclerViews

Adding Sticky Headers for Grouping Sponsors List in Open Event Android App

The Open Event Android project has a fragment for showing sponsors of the event. Each Sponsor model has a name, url, type and level. The SponsorsFragment shows list according to type and level. Each sponsor list item has sponsor type TextView. There can be more than one sponsors with the same type. So instead of showing type in the Sponsor item we can add Sticky header showing type at the top which will group the sponsors with the same type and also gives the great UI. In this post I explain how to add the Sticky headers in the RecyclerView using StickyHeadersRecyclerView library. 1. Add dependency In order to use Sticky Headers in your app add following dependencies in your app module’s build.gradle file. dependencies { compile 'com.timehop.stickyheadersrecyclerview:library:0.4.3' } 2. Create layout for header Create recycler_view_header.xml file for the header. It will contain LinearLayout and simple TextView which will show Sponsor type. <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/recyclerview_view_header" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="@dimen/padding_medium" /> </LinearLayout> Here you can modify layout according to your need. 3.  Implement StickyRecyclerHeadersAdapter Now implement StickyRecyclerHeadersAdapter in the List Adapter. Override getHeaderId(), onCreateHeaderViewHolder(), onBindHeaderViewHolder () methods of the StickyRecyclerHeadersAdapter. public class SponsorsListAdapter extends BaseRVAdapter<Sponsor, SponsorViewHolder> implements StickyRecyclerHeadersAdapter { ... @Override public long getHeaderId(int position) {...} @Override public RecyclerView.ViewHolder onCreateHeaderViewHolder(ViewGroup parent) {...} @Override public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder, int position) {...} }   The getHeaderId() method is used to give an id to the header. It is the main part of the implementation here all the sponsors with the same type should return the same id. In our case we are returning sponsor level because all the sponsor types have corresponding levels. String level = getItem(position).getLevel(); return Long.valueOf(level);   The onCreateHeaderViewHolder() returns Recycler ViewHolder for the header. Here we will use in the inflate() method of  LayoutInflater to get View object of recycler_view_header.xml file. Then return new RecyclerView.ViewHolder object using View object. View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.recycler_view_header, parent, false); return new RecyclerView.ViewHolder(view) {};   The onBindHeaderViewHolder() binds the sponsor to HeaderViewHolder. In this method we sets the sponsor type string to the TextView we have created in the recycler_view_header.xml file. TextView textView = (TextView) holder.itemView.findViewById(R.id.recyclerview_view_header); textView.setGravity(Gravity.CENTER_HORIZONTAL); String sponsorType = getItem(position).getType(); if (!Utils.isEmpty(sponsorType)) textView.setText(sponsorType.toUpperCase()); Here you can also modify TextView according to your need. We are centering text using setGravity() method. 4.  Setup RecyclerView Now create RecyclerView and set adapter using setAdapter() method. Also as we want the linear list of sponsors so set the LinearLayoutManager using setLayoutManager() method. SponsorsListAdapter sponsorsListAdapter = new SponsorsListAdapter(getContext(), sponsors); sponsorsRecyclerView.setAdapter(sponsorsListAdapter); sponsorsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));   Create StickyRecyclerHeadersDecoration object and add it in the RecyclerView using addItemDecoration() method. final StickyRecyclerHeadersDecoration headersDecoration = new StickyRecyclerHeadersDecoration(sponsorsListAdapter); sponsorsRecyclerView.addItemDecoration(headersDecoration); sponsorsListAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver(){ @Override public void onChanged { headersDecoration.invalidateHeaders(); } }); Now add AdapterDataObserver using registerAdapterDataObserver() method. The onChanged() method in this observer is called whenever dataset changes. So in this method invalidate headers using invalidateHeaders() method of HeaderDecoration. Now we are all set. Run the app it will look like this. Conclusion Sticky headers in the App gives great…

Continue ReadingAdding Sticky Headers for Grouping Sponsors List in Open Event Android App

Generic Social Links Implementation in Open Event Android App

The Open Event Android App has an About Fragment which displays all the info about the event like name, time, location etc. It also shows social media buttons for the event. The problem was that the implementation of showing the social media buttons was not generic. The implementation was working fine for current FOSSASIA sample. If we generate the app for other events it creates a problem. It shows static buttons without proper mapping from social media button to social media link which creates a problem like on clicking GitHub button it opens Facebook link (issue #1792). One solution to this problem is to implement recyclerview with social media buttons. In this post I explain how I have made social links implementation generic using RecyclerView. Add RecyclerView in layout The first step to do is to add recyclerview in the layout xml file and to create a list item for recyclerview which holds the image for the social link button. Then in the About Fragment find recyclerview element added in the xml file using findFragmentById() method. 1. Add recyclerview in xml file In the layout xml file of About Fragment add recyclerview element. Define id, width, height, and gravity of recyclerview. Then specify list item for recyclerview using listitem attribute. <android.support.v7.widget.RecyclerView android:id="@+id/list_social_links" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:overScrollMode="never" android:clipToPadding="false" tools:listitem="@layout/item_social_link" /> 2. Create item_social_link.xml Now create a item_social_link.xml file and add a FrameLayout element. Inside the FrameLayout add an ImageView with appropriate id, width, height and padding. <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout_social_link_parent" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/img_social_link" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="?attr/selectableItemBackgroundBorderless" android:contentDescription="@string/social_link" android:padding="@dimen/padding_large" android:tint="@color/white" /> </FrameLayout> Add and initialize RecyclerView After adding recyclerview in xml file we need to add RecyclerView field in the About Fragment java file. Now add and initialize SocialLinksListAdapter which extends RecyclerView.Adapter and will be used for populating the recyclerview with the social links. @BindView(R.id.list_social_links) protected RecyclerView socialLinksRecyclerView; private SocialLinksListAdapter socialLinksListAdapter; private List<SocialLink> mSocialLinks = new ArrayList<>(); Here mSocialLinks is the list of social links which is fetched from the Event object. Create ViewHolder for social link button Now create SocialLinkViewHolder which extends RecyclerView.ViewHolder and holds one social link item defined in item_social_link.xml file. This file is where the magic happens. Add ImageView, FrameLayout, SocialLink and context fields in it. public class SocialLinkViewHolder extends RecyclerView.ViewHolder { @BindView(R.id.img_social_link) protected ImageView imageView; @BindView(R.id.layout_social_link_parent) protected FrameLayout layout; private SocialLink socialLink; private Context context; public SocialLinkViewHolder(View itemView, Context context) { super(itemView); ButterKnife.bind(this, itemView); this.context = context; } public void bindSocialLink(@NonNull SocialLink socialLink) {...} private void setImageDrawable(@NonNull String name,@NonNull String link) {...} private Drawable getDrawable(@DrawableRes int id) {...} private void showView(boolean show) {...} } The bindSocialLink(SocialLink socialLink) method is called in the onBindViewHolder() method of the SocialLinksListAdapter. In this method initialize socialLink field and set drawable for ImageView according to SocialLink name using setImageDrawable() method. public void bindSocialLink(@NonNull SocialLink socialLink) { this.socialLink = socialLink; setImageDrawable(socialLink.getName(), socialLink.getLink()); } The setImageDrawable() method finds and sets appropriate image for social link button using the name of the social link. If the image for the social link is…

Continue ReadingGeneric Social Links Implementation in Open Event Android App