diff --git a/.idea/misc.xml b/.idea/misc.xml index fbb6828..5d19981 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -37,7 +37,7 @@ - + diff --git a/app/build.gradle b/app/build.gradle index 97f9ac0..1a818a5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,18 +9,12 @@ buildscript { } apply plugin: 'com.android.application' apply plugin: 'io.fabric' +apply plugin: 'realm-android' repositories { maven { url 'https://maven.fabric.io/public' } } - -repositories { - maven { url 'https://maven.fabric.io/public' } -} - -apply plugin: 'io.fabric' - android { compileSdkVersion 26 buildToolsVersion '26.0.1' @@ -40,6 +34,14 @@ android { } productFlavors { } + + configurations.all { + resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9' + } + + realm { + syncEnabled = true; + } } dependencies { @@ -64,7 +66,6 @@ dependencies { compile('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') { transitive = true; } + compile 'de.hdodenhof:circleimageview:2.1.0' + compile "com.squareup.picasso:picasso:2.4.0" } - - - diff --git a/app/src/main/java/io/devsummit/android/Activities/MainActivity.java b/app/src/main/java/io/devsummit/android/Activities/MainActivity.java index 2d0b980..23ae334 100644 --- a/app/src/main/java/io/devsummit/android/Activities/MainActivity.java +++ b/app/src/main/java/io/devsummit/android/Activities/MainActivity.java @@ -7,77 +7,116 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.widget.BottomNavigationView; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import android.view.MenuItem; import android.view.View; -import android.widget.FrameLayout; import android.widget.ProgressBar; - -import io.devsummit.android.Helpers.ExitAppHelper; -import io.devsummit.android.R; +import io.devsummit.android.Controllers.UserFeedController; import io.devsummit.android.Controllers.UserTicketController; import io.devsummit.android.Fragments.FeedFragment; +import io.devsummit.android.Fragments.TicketFragment; +import io.devsummit.android.Helpers.ExitAppHelper; import io.devsummit.android.Helpers.UserAuthenticationHelper; +import io.devsummit.android.R; +import io.devsummit.android.ViewAdapters.MainViewPagerAdapter; +import io.realm.Realm; public class MainActivity extends AppCompatActivity { + public static UserTicketController userTicketController; + public static UserFeedController userFeedController; + public static TicketFragment ticketFragment; + public static FeedFragment feedFragment; private UserAuthenticationHelper authHelper; - private UserTicketController userTicketController; private ProgressBar mProgressView; private BottomNavigationView navigation; + private ViewPager viewPager; + MenuItem prevMenuItem; @Override public void onBackPressed() { ExitAppHelper.exitTheApp(this); } - private FrameLayout mContainer; + public static MainActivity mMainActivity; private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { - mContainer.removeAllViews(); - Fragment frag = null; - String token = authHelper.getAccessToken(); switch (item.getItemId()) { case R.id.navigation_home: - frag = FeedFragment.newInstance(); + viewPager.setCurrentItem(0); break; case R.id.tickets: - userTicketController.getUserTickets(token, MainActivity.this); + viewPager.setCurrentItem(1); break; } - if (frag != null) { - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - ft.add(R.id.container, frag, frag.getTag()); - ft.commit(); - } return true; } }; + private ViewPager.OnPageChangeListener mOnPageChangeListerner + = new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + if (prevMenuItem != null) { + prevMenuItem.setChecked(false); + } + else + { + navigation.getMenu().getItem(0).setChecked(false); + } + Log.d("page", "onPageSelected: "+position); + navigation.getMenu().getItem(position).setChecked(true); + + } + + @Override + public void onPageSelected(int position) { + + } + + @Override + public void onPageScrollStateChanged(int state) { + + } + + }; + + private void setupViewPager(ViewPager viewPager) { + MainViewPagerAdapter adapter = new MainViewPagerAdapter(getSupportFragmentManager()); + feedFragment=new FeedFragment(); + ticketFragment=new TicketFragment(); + adapter.addFragment(feedFragment); + adapter.addFragment(ticketFragment); + viewPager.setAdapter(adapter); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); + //Initializing viewPager + viewPager = (ViewPager) findViewById(R.id.viewpager); + mMainActivity = MainActivity.this; authHelper = new UserAuthenticationHelper(this); mProgressView = (ProgressBar) findViewById(R.id.main_activity_loader); navigation = (BottomNavigationView) findViewById(R.id.navigation); userTicketController = new UserTicketController(MainActivity.this); - mContainer = (FrameLayout) findViewById(R.id.container); - } + userFeedController = new UserFeedController(MainActivity.this); - @Override - protected void onResume() { - super.onResume(); + setupViewPager(viewPager); navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); - userTicketController.getUserTickets(authHelper.getAccessToken(), MainActivity.this); + viewPager.addOnPageChangeListener(mOnPageChangeListerner); + userTicketController.getUserTickets(authHelper.getAccessToken()); + + Realm.init(getApplicationContext()); } /** diff --git a/app/src/main/java/io/devsummit/android/Controllers/UserFeedController.java b/app/src/main/java/io/devsummit/android/Controllers/UserFeedController.java new file mode 100644 index 0000000..6fdf36c --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Controllers/UserFeedController.java @@ -0,0 +1,62 @@ +package io.devsummit.android.Controllers; + +import android.content.Context; + +import io.devsummit.android.Activities.MainActivity; +import io.devsummit.android.Helpers.InetConnectionHelper; +import io.devsummit.android.Helpers.RealmHelper; +import io.devsummit.android.Models.UserFeedModel; +import io.devsummit.android.Remote.APIService; +import io.devsummit.android.Remote.ApiUtils; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Created by wlisrausr on 04/10/17. + */ + +public class UserFeedController { + private APIService mAPIService; + private MainActivity mMainActivity; + private UserFeedModel userFeedResponse; + + public UserFeedController(MainActivity act) { + mMainActivity = act; + userFeedResponse = new UserFeedModel(); + mAPIService = ApiUtils.getAPIService(); + } + + public void getUserFeed(String token, final Context context, final int page) { + if (mMainActivity != null) { + mMainActivity.showProgress(true); + } + + if (InetConnectionHelper.isNetworkAvailable(context)) { + mAPIService.fetchUserFeed(token, page).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + userFeedResponse = response.body(); + + if (userFeedResponse.getMeta().getSuccess().booleanValue()) { + RealmHelper rh = new RealmHelper(); + + for (int i = 0; i < userFeedResponse.getData().size(); i++) { + rh.receiveData(userFeedResponse.getData().get(i)); + } + + if (page == 1) { + mMainActivity.feedFragment.attachAdapter(); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + } + }); + } + + mMainActivity.showProgress(false); + } +} diff --git a/app/src/main/java/io/devsummit/android/Controllers/UserTicketController.java b/app/src/main/java/io/devsummit/android/Controllers/UserTicketController.java index 0c83138..6e965d3 100644 --- a/app/src/main/java/io/devsummit/android/Controllers/UserTicketController.java +++ b/app/src/main/java/io/devsummit/android/Controllers/UserTicketController.java @@ -1,12 +1,6 @@ package io.devsummit.android.Controllers; -import android.content.Context; -import android.support.v4.app.Fragment; -import android.support.v7.app.AppCompatActivity; - -import io.devsummit.android.R; import io.devsummit.android.Activities.MainActivity; -import io.devsummit.android.Fragments.TicketFragment; import io.devsummit.android.Models.UserTicketModel; import io.devsummit.android.Remote.APIService; import io.devsummit.android.Remote.ApiUtils; @@ -30,17 +24,13 @@ public UserTicketController(MainActivity act) { mAPIService = ApiUtils.getAPIService(); } - public void getUserTickets(String token, final Context context) { + public UserTicketModel getUserTickets(String token) { mMainActivity.showProgress(true); mAPIService.fetchUserTicket(token).enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { UserTickets = response.body(); - AppCompatActivity activity = (AppCompatActivity) context; - Fragment frag = TicketFragment.newInstance(response.body()); - android.support.v4.app.FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction(); - ft.add(R.id.container, frag, frag.getTag()); - ft.commit(); + mMainActivity.ticketFragment.attachItemToAdapter(UserTickets.getData()); mMainActivity.showProgress(false); } @@ -50,6 +40,8 @@ public void onFailure(Call call, Throwable t) { mMainActivity.showProgress(false); } }); + + return UserTickets; } } diff --git a/app/src/main/java/io/devsummit/android/Fragments/FeedFragment.java b/app/src/main/java/io/devsummit/android/Fragments/FeedFragment.java index 0585a3a..4b8c319 100644 --- a/app/src/main/java/io/devsummit/android/Fragments/FeedFragment.java +++ b/app/src/main/java/io/devsummit/android/Fragments/FeedFragment.java @@ -3,45 +3,86 @@ import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import java.util.List; + +import io.devsummit.android.Activities.MainActivity; +import io.devsummit.android.Helpers.EndlessRecyclerViewScrollListener; +import io.devsummit.android.Helpers.UserAuthenticationHelper; +import io.devsummit.android.Models.userfeed.FeedData; import io.devsummit.android.R; +import io.devsummit.android.ViewAdapters.FeedListViewAdapter; +import io.realm.Realm; +import io.realm.Sort; /** * Created by ganesh on 27/09/17. */ public class FeedFragment extends Fragment { - private static final String ARG_TEXT = "arg_text"; - private static final String ARG_COLOR = "arg_color"; - - private View mContent; - - public static Fragment newInstance() { - Fragment frag = new FeedFragment(); - Bundle args = new Bundle(); - frag.setArguments(args); - return frag; - } - + private UserAuthenticationHelper authHelper; + private RecyclerView mRecyclerView; + private LinearLayoutManager mLayoutManager; + private RecyclerView.Adapter mAdapter; + private List feedData; + private EndlessRecyclerViewScrollListener scrollListener; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + authHelper = new UserAuthenticationHelper(getActivity()); + String token = authHelper.getAccessToken(); + MainActivity.userFeedController.getUserFeed(token, getContext(), 1); + // Inflate the layout for this fragment - return inflater.inflate(R.layout.feed_fragment, container, false); + View layout = inflater.inflate(R.layout.feed_fragment, container, false); + + mRecyclerView = (RecyclerView) layout.findViewById(R.id.feeds_recycler_view); + + // use a linear layout manager + mLayoutManager = new LinearLayoutManager(getContext()); + mRecyclerView.setLayoutManager(mLayoutManager); + + //attachAdapter(); + + scrollListener = new EndlessRecyclerViewScrollListener(mLayoutManager) { + @Override + public void onLoadMore(int page, int totalItemsCount, RecyclerView view) { + loadNextDataFromApi(page, totalItemsCount); + } + }; + + mRecyclerView.addOnScrollListener(scrollListener); + + return layout; } - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); + public void attachAdapter(){ + Realm realm = Realm.getDefaultInstance(); + feedData = realm.where(FeedData.class).findAllSorted("createdAt", Sort.DESCENDING); + // specify an adapter (see also next example) + mAdapter = new FeedListViewAdapter(feedData, getContext()); + mRecyclerView.setAdapter(mAdapter); + } - // initialize views - mContent = view.findViewById(R.id.feed_content); + public void loadNextDataFromApi(int offset, int totalItems) { + // Send an API request to retrieve appropriate paginated data + String token = authHelper.getAccessToken(); + offset = totalItems / 10; + MainActivity.userFeedController.getUserFeed(token, getContext(), offset + 1); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); } @Override diff --git a/app/src/main/java/io/devsummit/android/Fragments/TicketFragment.java b/app/src/main/java/io/devsummit/android/Fragments/TicketFragment.java index fb79ab1..55115f8 100644 --- a/app/src/main/java/io/devsummit/android/Fragments/TicketFragment.java +++ b/app/src/main/java/io/devsummit/android/Fragments/TicketFragment.java @@ -11,10 +11,12 @@ import android.view.ViewGroup; import android.widget.ImageButton; +import java.util.List; + +import io.devsummit.android.Activities.MainActivity; import io.devsummit.android.Activities.OrderedTicketActivity; -import io.devsummit.android.Controllers.UserTicketController; import io.devsummit.android.Helpers.UserAuthenticationHelper; -import io.devsummit.android.Models.UserTicketModel; +import io.devsummit.android.Models.userticket.Datum; import io.devsummit.android.R; import io.devsummit.android.ViewAdapters.TicketListViewAdapter; @@ -23,85 +25,39 @@ */ public class TicketFragment extends Fragment implements View.OnClickListener { - private static final String USER_TICKETS = "user_ticket_model"; private RecyclerView mRecyclerView; private RecyclerView.Adapter mAdapter; private RecyclerView.LayoutManager mLayoutManager; - private View mContent; - private UserTicketController userTicketController; private UserAuthenticationHelper authHelper; - private UserTicketModel mUserTicketModel; private ImageButton myOrders; - public static Fragment newInstance(UserTicketModel userTicketModel) { - Fragment frag = new TicketFragment(); - - Bundle bundle = new Bundle(); - bundle.putSerializable(USER_TICKETS, userTicketModel); - frag.setArguments(bundle); - return frag; - } - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - mUserTicketModel = (UserTicketModel) getArguments().getSerializable( - USER_TICKETS); + authHelper = new UserAuthenticationHelper(getContext()); + String token = authHelper.getAccessToken(); + MainActivity.userTicketController.getUserTickets(token); // Inflate the layout for this fragment View layout = inflater.inflate(R.layout.ticket_fragment, container, false); - authHelper = new UserAuthenticationHelper(getActivity()); - - if (mUserTicketModel.getData().size() > 0) { - mRecyclerView = (RecyclerView) layout.findViewById(R.id.user_ticket_recycler_view); - - // use this setting to improve performance if you know that changes - // in content do not change the layout size of the RecyclerView - // mRecyclerView.setHasFixedSize(true); + mRecyclerView = layout.findViewById(R.id.user_ticket_recycler_view); - // use a linear layout manager - mLayoutManager = new LinearLayoutManager(getContext()); - mRecyclerView.setLayoutManager(mLayoutManager); - - // get ticket data - // specify an adapter (see also next example) - mAdapter = new TicketListViewAdapter(mUserTicketModel.getData()); - mRecyclerView.setAdapter(mAdapter); - } + // use a linear layout manager + mLayoutManager = new LinearLayoutManager(getContext()); + mRecyclerView.setLayoutManager(mLayoutManager); - myOrders = (ImageButton) layout.findViewById(R.id.button_my_order); + myOrders = layout.findViewById(R.id.button_my_order); myOrders.setOnClickListener(this); - mRecyclerView = (RecyclerView) layout.findViewById(R.id.user_ticket_recycler_view); - - // use this setting to improve performance if you know that changes - // in content do not change the layout size of the RecyclerView - // mRecyclerView.setHasFixedSize(true); - return layout; } - @Override - public void onResume() { - super.onResume(); - - // use a linear layout manager - mLayoutManager = new LinearLayoutManager(getContext()); - mRecyclerView.setLayoutManager(mLayoutManager); - - // specify an adapter (see also next example) - mAdapter = new TicketListViewAdapter(mUserTicketModel.getData()); - mRecyclerView.setAdapter(mAdapter); - } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - // initialize views - mContent = view.findViewById(R.id.ticket_content); } @Override @@ -113,4 +69,10 @@ public void onClick(View view) { Intent intent = new Intent(getActivity(), OrderedTicketActivity.class); startActivity(intent); } + + public void attachItemToAdapter(List userTickets){ + // specify an adapter (see also next example) + mAdapter = new TicketListViewAdapter(userTickets); + mRecyclerView.setAdapter(mAdapter); + } } diff --git a/app/src/main/java/io/devsummit/android/Helpers/EndlessRecyclerViewScrollListener.java b/app/src/main/java/io/devsummit/android/Helpers/EndlessRecyclerViewScrollListener.java new file mode 100644 index 0000000..d67e05f --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Helpers/EndlessRecyclerViewScrollListener.java @@ -0,0 +1,109 @@ +package io.devsummit.android.Helpers; + +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.StaggeredGridLayoutManager; + +/** + * Created by wlisrausr on 09/10/17. + */ + +public abstract class EndlessRecyclerViewScrollListener extends RecyclerView.OnScrollListener { + // The minimum amount of items to have below your current scroll position + // before loading more. + private int visibleThreshold = 5; + // The current offset index of data you have loaded + private int currentPage = 0; + // The total number of items in the dataset after the last load + private int previousTotalItemCount = 0; + // True if we are still waiting for the last set of data to load. + private boolean loading = true; + // Sets the starting page index + private int startingPageIndex = 0; + + RecyclerView.LayoutManager mLayoutManager; + + public EndlessRecyclerViewScrollListener(LinearLayoutManager layoutManager) { + this.mLayoutManager = layoutManager; + } + + public EndlessRecyclerViewScrollListener(GridLayoutManager layoutManager) { + this.mLayoutManager = layoutManager; + visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); + } + + public EndlessRecyclerViewScrollListener(StaggeredGridLayoutManager layoutManager) { + this.mLayoutManager = layoutManager; + visibleThreshold = visibleThreshold * layoutManager.getSpanCount(); + } + + public int getLastVisibleItem(int[] lastVisibleItemPositions) { + int maxSize = 0; + for (int i = 0; i < lastVisibleItemPositions.length; i++) { + if (i == 0) { + maxSize = lastVisibleItemPositions[i]; + } + else if (lastVisibleItemPositions[i] > maxSize) { + maxSize = lastVisibleItemPositions[i]; + } + } + return maxSize; + } + + // This happens many times a second during a scroll, so be wary of the code you place here. + // We are given a few useful parameters to help us work out if we need to load some more data, + // but first we check if we are waiting for the previous load to finish. + @Override + public void onScrolled(RecyclerView view, int dx, int dy) { + int lastVisibleItemPosition = 0; + int totalItemCount = mLayoutManager.getItemCount(); + + if (mLayoutManager instanceof StaggeredGridLayoutManager) { + int[] lastVisibleItemPositions = ((StaggeredGridLayoutManager) mLayoutManager).findLastVisibleItemPositions(null); + // get maximum element within the list + lastVisibleItemPosition = getLastVisibleItem(lastVisibleItemPositions); + } else if (mLayoutManager instanceof GridLayoutManager) { + lastVisibleItemPosition = ((GridLayoutManager) mLayoutManager).findLastVisibleItemPosition(); + } else if (mLayoutManager instanceof LinearLayoutManager) { + lastVisibleItemPosition = ((LinearLayoutManager) mLayoutManager).findLastVisibleItemPosition(); + } + + // If the total item count is zero and the previous isn't, assume the + // list is invalidated and should be reset back to initial state + if (totalItemCount < previousTotalItemCount) { + this.currentPage = this.startingPageIndex; + this.previousTotalItemCount = totalItemCount; + if (totalItemCount == 0) { + this.loading = true; + } + } + // If it’s still loading, we check to see if the dataset count has + // changed, if so we conclude it has finished loading and update the current page + // number and total item count. + if (loading && (totalItemCount > previousTotalItemCount)) { + loading = false; + previousTotalItemCount = totalItemCount; + } + + // If it isn’t currently loading, we check to see if we have breached + // the visibleThreshold and need to reload more data. + // If we do need to reload some more data, we execute onLoadMore to fetch the data. + // threshold should reflect how many total columns there are too + if (!loading && (lastVisibleItemPosition + visibleThreshold) > totalItemCount) { + currentPage++; + onLoadMore(currentPage, totalItemCount, view); + loading = true; + } + } + + // Call this method whenever performing new searches + public void resetState() { + this.currentPage = this.startingPageIndex; + this.previousTotalItemCount = 0; + this.loading = true; + } + + // Defines the process for actually loading more data based on page + public abstract void onLoadMore(int page, int totalItemsCount, RecyclerView view); +} diff --git a/app/src/main/java/io/devsummit/android/Helpers/InetConnectionHelper.java b/app/src/main/java/io/devsummit/android/Helpers/InetConnectionHelper.java new file mode 100644 index 0000000..2b9373a --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Helpers/InetConnectionHelper.java @@ -0,0 +1,19 @@ +package io.devsummit.android.Helpers; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; + +/** + * Created by wlisrausr on 07/10/17. + */ + +public class InetConnectionHelper { + public static boolean isNetworkAvailable(Context context) { + ConnectivityManager connectivityManager + = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo(); + + return activeNetworkInfo != null && activeNetworkInfo.isConnected(); + } +} diff --git a/app/src/main/java/io/devsummit/android/Helpers/RealmHelper.java b/app/src/main/java/io/devsummit/android/Helpers/RealmHelper.java new file mode 100644 index 0000000..0739863 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Helpers/RealmHelper.java @@ -0,0 +1,24 @@ +package io.devsummit.android.Helpers; + +import io.realm.Realm; +import io.realm.RealmModel; + +/** + * Created by ganesh on 06/10/17. + */ + +public class RealmHelper { + public void receiveData(Object responseData) { + Realm realm = Realm.getDefaultInstance(); + + try { + realm.beginTransaction(); + realm.copyToRealmOrUpdate((RealmModel) responseData); + realm.commitTransaction(); + realm.close(); + } catch (Exception e) { + e.printStackTrace(); + realm.cancelTransaction(); + } + } +} diff --git a/app/src/main/java/io/devsummit/android/Helpers/TextHelper.java b/app/src/main/java/io/devsummit/android/Helpers/TextHelper.java new file mode 100644 index 0000000..b0817ae --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Helpers/TextHelper.java @@ -0,0 +1,38 @@ +package io.devsummit.android.Helpers; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Created by wlisrausr on 04/10/17. + */ + +public class TextHelper { + public static String capitalizeFirstLetter(String input) { + return input.substring(0, 1).toUpperCase() + input.substring(1); + } + + public static String toRupiahFormat(Number nominal) { + NumberFormat format = NumberFormat.getInstance(); + + return "Rp " + format.format(nominal); + } + + public static String dateFormat(String inputDate) { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); + Date formattedDate = null; + + try { + formattedDate = format.parse(inputDate); + } catch (ParseException e) { + e.printStackTrace(); + } + + format = new SimpleDateFormat("MMM dd, yyyy (hh:mm)"); + String outputDate = format.format(formattedDate); + + return outputDate; + } +} diff --git a/app/src/main/java/io/devsummit/android/Models/UserFeedModel.java b/app/src/main/java/io/devsummit/android/Models/UserFeedModel.java new file mode 100644 index 0000000..b284721 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Models/UserFeedModel.java @@ -0,0 +1,63 @@ +package io.devsummit.android.Models; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; +import java.util.List; + +import io.devsummit.android.Models.basemodel.Included; +import io.devsummit.android.Models.basemodel.Meta; +import io.devsummit.android.Models.userfeed.FeedData; +import io.devsummit.android.Models.userfeed.Links; + +/** + * Created by wlisrausr on 04/10/17. + */ + +public class UserFeedModel implements Serializable { + @SerializedName("data") + @Expose + private List data = null; + @SerializedName("included") + @Expose + private Included included; + @SerializedName("links") + @Expose + private Links links; + @SerializedName("meta") + @Expose + private Meta meta; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public Included getIncluded() { + return included; + } + + public void setIncluded(Included included) { + this.included = included; + } + + public Links getLinks() { + return links; + } + + public void setLinks(Links links) { + this.links = links; + } + + public Meta getMeta() { + return meta; + } + + public void setMeta(Meta meta) { + this.meta = meta; + } +} diff --git a/app/src/main/java/io/devsummit/android/Models/userfeed/FeedData.java b/app/src/main/java/io/devsummit/android/Models/userfeed/FeedData.java new file mode 100644 index 0000000..83dca5e --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Models/userfeed/FeedData.java @@ -0,0 +1,124 @@ +package io.devsummit.android.Models.userfeed; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +public class FeedData extends RealmObject implements Serializable { + + @SerializedName("attachment") + @Expose + private String attachment; + @SerializedName("created_at") + @Expose + private String createdAt; + @SerializedName("id") + @Expose + @PrimaryKey + private Integer id; + @SerializedName("message") + @Expose + private String message; + @SerializedName("redirect_url") + @Expose + private String redirectUrl; + @SerializedName("sponsor_id") + @Expose + private Integer sponsorId; + @SerializedName("type") + @Expose + private String type; + @SerializedName("updated_at") + @Expose + private String updatedAt; + @SerializedName("user") + @Expose + private User user; + @SerializedName("user_id") + @Expose + private Integer userId; + + public String getAttachment() { + return attachment; + } + + public void setAttachment(String attachment) { + this.attachment = attachment; + } + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getRedirectUrl() { + return redirectUrl; + } + + public void setRedirectUrl(String redirectUrl) { + this.redirectUrl = redirectUrl; + } + + public Integer getSponsorId() { + return sponsorId; + } + + public void setSponsorId(Integer sponsorId) { + this.sponsorId = sponsorId; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } +} \ No newline at end of file diff --git a/app/src/main/java/io/devsummit/android/Models/userfeed/Links.java b/app/src/main/java/io/devsummit/android/Models/userfeed/Links.java new file mode 100644 index 0000000..8e70d42 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Models/userfeed/Links.java @@ -0,0 +1,52 @@ +package io.devsummit.android.Models.userfeed; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Links { + + @SerializedName("curr") + @Expose + private String curr; + @SerializedName("next") + @Expose + private String next; + @SerializedName("prev") + @Expose + private String prev; + @SerializedName("total_items") + @Expose + private Integer totalItems; + + public String getCurr() { + return curr; + } + + public void setCurr(String curr) { + this.curr = curr; + } + + public String getNext() { + return next; + } + + public void setNext(String next) { + this.next = next; + } + + public String getPrev() { + return prev; + } + + public void setPrev(String prev) { + this.prev = prev; + } + + public Integer getTotalItems() { + return totalItems; + } + + public void setTotalItems(Integer totalItems) { + this.totalItems = totalItems; + } +} \ No newline at end of file diff --git a/app/src/main/java/io/devsummit/android/Models/userfeed/Photo.java b/app/src/main/java/io/devsummit/android/Models/userfeed/Photo.java new file mode 100644 index 0000000..76f6717 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Models/userfeed/Photo.java @@ -0,0 +1,69 @@ +package io.devsummit.android.Models.userfeed; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +public class Photo extends RealmObject implements Serializable { + + @SerializedName("created_at") + @Expose + private String createdAt; + @SerializedName("id") + @Expose + @PrimaryKey + private Integer id; + @SerializedName("updated_at") + @Expose + private String updatedAt; + @SerializedName("url") + @Expose + private String url; + @SerializedName("user_id") + @Expose + private Integer userId; + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Integer getUserId() { + return userId; + } + + public void setUserId(Integer userId) { + this.userId = userId; + } +} \ No newline at end of file diff --git a/app/src/main/java/io/devsummit/android/Models/userfeed/User.java b/app/src/main/java/io/devsummit/android/Models/userfeed/User.java new file mode 100644 index 0000000..c15bb89 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/Models/userfeed/User.java @@ -0,0 +1,159 @@ +package io.devsummit.android.Models.userfeed; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.io.Serializable; + +import io.realm.RealmList; +import io.realm.RealmObject; +import io.realm.annotations.PrimaryKey; + +public class User extends RealmObject implements Serializable { + + @SerializedName("created_at") + @Expose + private String createdAt; + @SerializedName("email") + @Expose + private String email; + @SerializedName("fcmtoken") + @Expose + private String fcmtoken; + @SerializedName("first_name") + @Expose + private String firstName; + @SerializedName("id") + @Expose + @PrimaryKey + private Integer id; + @SerializedName("last_name") + @Expose + private String lastName; + @SerializedName("photos") + @Expose + private RealmList photos = null; + @SerializedName("points") + @Expose + private Integer points; + @SerializedName("referer") + @Expose + private String referer; + @SerializedName("role_id") + @Expose + private Integer roleId; + @SerializedName("social_id") + @Expose + private String socialId; + @SerializedName("updated_at") + @Expose + private String updatedAt; + @SerializedName("username") + @Expose + private String username; + + public String getCreatedAt() { + return createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getFcmtoken() { + return fcmtoken; + } + + public void setFcmtoken(String fcmtoken) { + this.fcmtoken = fcmtoken; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public RealmList getPhotos() { + return photos; + } + + public void setPhotos(RealmList photos) { + this.photos = photos; + } + + public Integer getPoints() { + return points; + } + + public void setPoints(Integer points) { + this.points = points; + } + + public String getReferer() { + return referer; + } + + public void setReferer(String referer) { + this.referer = referer; + } + + public Integer getRoleId() { + return roleId; + } + + public void setRoleId(Integer roleId) { + this.roleId = roleId; + } + + public String getSocialId() { + return socialId; + } + + public void setSocialId(String socialId) { + this.socialId = socialId; + } + + public String getUpdatedAt() { + return updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/devsummit/android/Remote/APIService.java b/app/src/main/java/io/devsummit/android/Remote/APIService.java index 2829e1e..3060d93 100644 --- a/app/src/main/java/io/devsummit/android/Remote/APIService.java +++ b/app/src/main/java/io/devsummit/android/Remote/APIService.java @@ -4,6 +4,7 @@ import io.devsummit.android.Models.NotificationModel; import io.devsummit.android.Models.OrderedTicketModel; import io.devsummit.android.Models.RegisterModel; +import io.devsummit.android.Models.UserFeedModel; import io.devsummit.android.Models.UserTicketModel; import io.devsummit.android.Models.authmodel.RefreshTokenModel; import io.devsummit.android.Models.login.Credentials; @@ -16,6 +17,7 @@ import retrofit2.http.Header; import retrofit2.http.Headers; import retrofit2.http.POST; +import retrofit2.http.Query; import retrofit2.http.Url; /** @@ -49,6 +51,9 @@ public interface APIService { @Headers("Content-Type: application/json") Call fetchNotification(@Header("Authorization") String token, @Url String url); + @GET("api/v1/feeds") + Call fetchUserFeed(@Header("Authorization") String token, @Query("page") int page); + @POST("auth/refreshtoken") @Headers("Content-Type:application/json") Call refreshToken(@Body String refresh_token); diff --git a/app/src/main/java/io/devsummit/android/ViewAdapters/FeedListViewAdapter.java b/app/src/main/java/io/devsummit/android/ViewAdapters/FeedListViewAdapter.java new file mode 100644 index 0000000..dcecff8 --- /dev/null +++ b/app/src/main/java/io/devsummit/android/ViewAdapters/FeedListViewAdapter.java @@ -0,0 +1,105 @@ +package io.devsummit.android.ViewAdapters; + +import android.content.Context; +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import com.squareup.picasso.Picasso; + +import java.util.List; + +import de.hdodenhof.circleimageview.CircleImageView; +import io.devsummit.android.Helpers.TextHelper; +import io.devsummit.android.Models.userfeed.FeedData; +import io.devsummit.android.R; + +/** + * Created by wlisrausr on 04/10/17. + */ + +public class FeedListViewAdapter extends RecyclerView.Adapter { + private List mDataset; + private Context context; + + // Provide a suitable constructor (depends on the kind of dataset) + public FeedListViewAdapter(List myDataset, Context context) { + mDataset = myDataset; + this.context = context; + } + + @Override + public FeedListViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + // TODO: inflate your view and create viewholder, most likely looks like this though + View v = LayoutInflater.from(viewGroup.getContext()).inflate( + R.layout.user_feed_row, + viewGroup, + false); + + FeedListViewHolder vh = new FeedListViewHolder(v); + return vh; + } + + @Override + public void onBindViewHolder(final FeedListViewHolder viewHolder, int i) { + // TODO: all your bind operations + viewHolder.firstName.setText(TextHelper.capitalizeFirstLetter( + mDataset.get(i).getUser().getFirstName().toString() + )); + viewHolder.lastName.setText(TextHelper.capitalizeFirstLetter( + mDataset.get(i).getUser().getLastName().toString() + )); + viewHolder.createdAt.setText(TextHelper.dateFormat(mDataset.get(i).getCreatedAt().toString())); + viewHolder.feedMessage.setText(mDataset.get(i).getMessage().toString()); + + Object attachmentUrl = mDataset.get(i).getAttachment(); + List imgProfileUrl = mDataset.get(i).getUser().getPhotos(); + + viewHolder.feedAttachment.setVisibility(View.GONE); + + if (attachmentUrl != null) { + viewHolder.feedAttachment.setVisibility(View.VISIBLE); + + Picasso.with(context) + .load(mDataset.get(i).getAttachment().toString()) + .into(viewHolder.feedAttachment); + } + + if (imgProfileUrl.size() > 0) { + Picasso.with(context) + .load(mDataset.get(i).getUser().getPhotos().get(0).getUrl().toString()) + .placeholder(R.drawable.empty_profile_grey) + .into(viewHolder.imageProfile); + } + } + + @Override + public int getItemCount() { + // TODO: return total item count of your views + return mDataset.size(); + } + + public static class FeedListViewHolder extends RecyclerView.ViewHolder { + // TODO: whatever views you need to bind + public TextView feedMessage; + public TextView firstName; + public TextView lastName; + public TextView createdAt; + public ImageView feedAttachment; + public CircleImageView imageProfile; + + public FeedListViewHolder(View v) { + super(v); // done this way instead of view tagging + + feedMessage = (TextView) v.findViewById(R.id.feedMessage); + firstName = (TextView) v.findViewById(R.id.firstNameText); + lastName = (TextView) v.findViewById(R.id.lastNameText); + createdAt = (TextView) v.findViewById(R.id.createdAtText); + feedAttachment = (ImageView) v.findViewById(R.id.feedAttachment); + imageProfile = (CircleImageView) v.findViewById(R.id.imageProfile); + } + } +} diff --git a/app/src/main/java/io/devsummit/android/ViewAdapters/MainViewPagerAdapter.java b/app/src/main/java/io/devsummit/android/ViewAdapters/MainViewPagerAdapter.java new file mode 100644 index 0000000..91efaad --- /dev/null +++ b/app/src/main/java/io/devsummit/android/ViewAdapters/MainViewPagerAdapter.java @@ -0,0 +1,34 @@ +package io.devsummit.android.ViewAdapters; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by wlisrausr on 09/10/17. + */ + +public class MainViewPagerAdapter extends FragmentPagerAdapter { + private final List mFragmentList = new ArrayList<>(); + + public MainViewPagerAdapter(FragmentManager manager) { + super(manager); + } + @Override + public Fragment getItem(int position) { + return mFragmentList.get(position); + } + + @Override + public int getCount() { + return mFragmentList.size(); + } + + public void addFragment(Fragment fragment) { + mFragmentList.add(fragment); + } + +} \ No newline at end of file diff --git a/app/src/main/java/io/devsummit/android/ViewAdapters/OrderedTicketListViewAdapter.java b/app/src/main/java/io/devsummit/android/ViewAdapters/OrderedTicketListViewAdapter.java index 11dd0b0..262b50d 100644 --- a/app/src/main/java/io/devsummit/android/ViewAdapters/OrderedTicketListViewAdapter.java +++ b/app/src/main/java/io/devsummit/android/ViewAdapters/OrderedTicketListViewAdapter.java @@ -7,13 +7,10 @@ import android.widget.LinearLayout; import android.widget.TextView; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; import java.util.List; import io.devsummit.android.Helpers.OrderStatusHelper; +import io.devsummit.android.Helpers.TextHelper; import io.devsummit.android.Models.orderedtickets.Datum; import io.devsummit.android.R; @@ -30,28 +27,6 @@ public OrderedTicketListViewAdapter(List myDataset) { mDataset = myDataset; } - public String toRupiahFormat(Number nominal) { - NumberFormat format = NumberFormat.getInstance(); - - return "Rp " + format.format(nominal); - } - - public String dateFormat(String inputDate) { - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); - Date formattedDate = null; - - try { - formattedDate = format.parse(inputDate); - } catch (ParseException e) { - e.printStackTrace(); - } - - format = new SimpleDateFormat("MMM dd, yyyy (hh:mm)"); - String outputDate = format.format(formattedDate); - - return outputDate; - } - @Override public OrderedTicketListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // TODO: inflate your view and create viewholder, most likely looks like this though @@ -75,8 +50,8 @@ public void onBindViewHolder(OrderedTicketListViewHolder holder, int position) { // TODO: all your bind operations holder.orderId.setText(mDataset.get(position).getId().toString()); - holder.orderDate.setText(dateFormat(mDataset.get(position).getCreatedAt().toString())); - holder.orderAmount.setText(toRupiahFormat(mDataset.get(position).getAmount())); + holder.orderDate.setText(TextHelper.dateFormat(mDataset.get(position).getCreatedAt().toString())); + holder.orderAmount.setText(TextHelper.toRupiahFormat(mDataset.get(position).getAmount())); holder.orderStatus.setText(orderStatus); } diff --git a/app/src/main/res/drawable/empty_profile_grey.jpg b/app/src/main/res/drawable/empty_profile_grey.jpg new file mode 100644 index 0000000..8830fbc Binary files /dev/null and b/app/src/main/res/drawable/empty_profile_grey.jpg differ diff --git a/app/src/main/res/drawable/feed_attachment.xml b/app/src/main/res/drawable/feed_attachment.xml new file mode 100644 index 0000000..75a1494 --- /dev/null +++ b/app/src/main/res/drawable/feed_attachment.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_border_color_black_24dp.xml b/app/src/main/res/drawable/ic_border_color_black_24dp.xml new file mode 100644 index 0000000..1889bdf --- /dev/null +++ b/app/src/main/res/drawable/ic_border_color_black_24dp.xml @@ -0,0 +1,13 @@ + + + + diff --git a/app/src/main/res/drawable/ic_report_black_16dp.xml b/app/src/main/res/drawable/ic_report_black_16dp.xml new file mode 100644 index 0000000..f6fb68f --- /dev/null +++ b/app/src/main/res/drawable/ic_report_black_16dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/drawable/ic_share_black_16dp.xml b/app/src/main/res/drawable/ic_share_black_16dp.xml new file mode 100644 index 0000000..bcc5725 --- /dev/null +++ b/app/src/main/res/drawable/ic_share_black_16dp.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d906496..7412f87 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -13,13 +13,13 @@ android:layout_height="match_parent" android:background="@drawable/background_3x" android:layout_weight="1"> - - + android:layout_above="@+id/bottom_navigation" + android:layout_alignParentTop="true" + app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + + + android:layout_marginTop="8dp" + android:scrollbars="vertical" /> + + + \ No newline at end of file diff --git a/app/src/main/res/layout/user_feed_row.xml b/app/src/main/res/layout/user_feed_row.xml new file mode 100644 index 0000000..d13d316 --- /dev/null +++ b/app/src/main/res/layout/user_feed_row.xml @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +