diff --git a/README.md b/README.md
index f44358f4..9b4eaeba 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@

-**FastHub** is yet another open source GitHub client app but unlike any other app, FastHub built from ground up.
+**FastHub** is yet another **open source** GitHub client app but unlike any other app, FastHub built from ground up.
@@ -26,6 +26,29 @@
- Receive notifications.
- Loads more...
+
+# FastHub made of:
+
+- Min SDK(21) but Appcompat is used all the way.
+- MVP architecture'd using Thirtyinch lib for the edibility of maintaining and following one structure throughout the project.
+- Lambda expressions because __you know why__.
+- RxJava & RxAndroid for Retrofit & Background threads.
+- Retrofit for consuming rest api.
+- SqliteMagic for offline mode.
+- Stream API for dealing with iterations.
+- JobScheduler using Firebase JobDispatcher for notifications service.
+- ButterKnife for views binding.
+- Icepick for saving instance of objects.
+- Lombok for (getters/setters).
+- BottomNavigationView for `Fragments` navigation.
+- UIL for image loading.
+- AndDown for comments markdown highlighting.
+- Alerter for displaying error/success messages.
+- CircleImageView for avatar images.
+- MatrialTagPrompt for displying guides throughout the app.
+- Firebase analytics, crash reporting, ads & messaging. (analytics & messaging not yet implemented.)
+- The mighty Android support libs.
+
# Contribution
You love FastHub? You want new features or bug fixes? Please contribute to the project either by creating PR or submitting an issue ticket.
diff --git a/app/build.gradle b/app/build.gradle
index cd04be17..9ece2d77 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -117,6 +117,7 @@ dependencies {
compile 'com.annimon:stream:1.1.4'
compile 'com.commonsware.cwac:anddown:0.3.0'
compile 'com.tapadoo.android:alerter:1.0.1'
+ compile 'uk.co.samuelwall:material-tap-target-prompt:1.9.2'
apt 'org.projectlombok:lombok:1.12.6'
apt 'frankiesardo:icepick-processor:3.1.0'
apt 'com.jakewharton:butterknife-compiler:8.4.0'
diff --git a/app/src/main/java/com/fastaccess/App.java b/app/src/main/java/com/fastaccess/App.java
index 0af7a6a9..8d1fa535 100644
--- a/app/src/main/java/com/fastaccess/App.java
+++ b/app/src/main/java/com/fastaccess/App.java
@@ -2,6 +2,7 @@ package com.fastaccess;
import android.app.Application;
import android.support.annotation.NonNull;
+import android.util.Log;
import com.commonsware.cwac.anddown.AndDown;
import com.fastaccess.helper.TypeFaceHelper;
@@ -27,6 +28,13 @@ public class App extends Application {
UILProvider.initUIL(this);
TypeFaceHelper.generateTypeface(this);
NotificationJobTask.scheduleJob(this);//schedule the job for the notifications
+ if (BuildConfig.DEBUG) {
+ Thread.setDefaultUncaughtExceptionHandler((paramThread, paramThrowable) -> {
+ Log.e("Crash", paramThrowable.getMessage(), paramThrowable);
+ System.exit(2);
+ });
+ }
+
}
@NonNull public static App getInstance() {
diff --git a/app/src/main/java/com/fastaccess/helper/PrefGetter.java b/app/src/main/java/com/fastaccess/helper/PrefGetter.java
index a05399b4..9a46744d 100644
--- a/app/src/main/java/com/fastaccess/helper/PrefGetter.java
+++ b/app/src/main/java/com/fastaccess/helper/PrefGetter.java
@@ -9,6 +9,11 @@ import android.support.annotation.NonNull;
public class PrefGetter {
private static final String ADS = "enable_ads";
private static final String TOKEN = "token";
+ private static final String USER_ICON_GUIDE = "user_icon_guide";
+ private static final String RELEASE_GUIDE = "release_guide";
+ private static final String FILE_OPTION_GUIDE = "file_option_guide";
+ private static final String COMMENTS_GUIDE = "comments_guide";
+ private static final String REPO_GUIDE = "repo_guide";
public static void setToken(@NonNull String token) {
PrefHelper.set(TOKEN, token);
@@ -29,4 +34,34 @@ public class PrefGetter {
public static void clear() {
PrefHelper.clearPrefs();
}
+
+ public static boolean isUserIconGuideShowed() {
+ boolean isShowed = PrefHelper.getBoolean(USER_ICON_GUIDE);
+ PrefHelper.set(USER_ICON_GUIDE, true);
+ return isShowed;
+ }
+
+ public static boolean isReleaseHintShow() {
+ boolean isShowed = PrefHelper.getBoolean(RELEASE_GUIDE);
+ PrefHelper.set(RELEASE_GUIDE, true);
+ return isShowed;
+ }
+
+ public static boolean isFileOptionHintShow() {
+ boolean isShowed = PrefHelper.getBoolean(FILE_OPTION_GUIDE);
+ PrefHelper.set(FILE_OPTION_GUIDE, true);
+ return isShowed;
+ }
+
+ public static boolean isCommentHintShowed() {
+ boolean isShowed = PrefHelper.getBoolean(COMMENTS_GUIDE);
+ PrefHelper.set(COMMENTS_GUIDE, true);
+ return isShowed;
+ }
+
+ public static boolean isRepoGuideShowed() {
+ boolean isShowed = PrefHelper.getBoolean(REPO_GUIDE);
+ PrefHelper.set(REPO_GUIDE, true);
+ return isShowed;
+ }
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java
index bde47d59..e4915812 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsMvp.java
@@ -8,6 +8,7 @@ import com.fastaccess.data.dao.SimpleUrlsModel;
import com.fastaccess.provider.rest.loadmore.OnLoadMore;
import com.fastaccess.ui.base.mvp.BaseMvp;
import com.fastaccess.ui.widgets.dialog.ListDialogView;
+import com.fastaccess.ui.widgets.recyclerview.BaseRecyclerAdapter;
import com.fastaccess.ui.widgets.recyclerview.BaseViewHolder;
import java.util.ArrayList;
@@ -18,7 +19,8 @@ import java.util.ArrayList;
interface FeedsMvp {
interface View extends BaseMvp.FAView, SwipeRefreshLayout.OnRefreshListener,
- android.view.View.OnClickListener, ListDialogView.onSimpleItemSelection {
+ android.view.View.OnClickListener, ListDialogView.onSimpleItemSelection,
+ BaseRecyclerAdapter.GuideListener {
void onNotifyAdapter();
diff --git a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsView.java b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsView.java
index 75dc383c..394f8fec 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsView.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/feeds/FeedsView.java
@@ -6,11 +6,14 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
import android.support.v4.widget.SwipeRefreshLayout;
+import android.view.MotionEvent;
import android.view.View;
import com.fastaccess.R;
+import com.fastaccess.data.dao.EventsModel;
import com.fastaccess.data.dao.SimpleUrlsModel;
import com.fastaccess.helper.Logger;
+import com.fastaccess.helper.PrefGetter;
import com.fastaccess.provider.rest.loadmore.OnLoadMore;
import com.fastaccess.provider.scheme.SchemeParser;
import com.fastaccess.ui.adapter.FeedsAdapter;
@@ -22,6 +25,7 @@ import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView;
import java.util.ArrayList;
import butterknife.BindView;
+import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
/**
* Created by Kosh on 11 Nov 2016, 12:36 PM
@@ -50,6 +54,7 @@ public class FeedsView extends BaseFragment imple
refresh.setOnRefreshListener(this);
recycler.setEmptyView(stateLayout, refresh);
adapter = new FeedsAdapter(getPresenter().getEvents());
+ adapter.setGuideListener(this);
adapter.setListener(getPresenter());
getLoadMore().setCurrent_page(getPresenter().getCurrentPage(), getPresenter().getPreviousTotal());
recycler.setAdapter(adapter);
@@ -113,4 +118,29 @@ public class FeedsView extends BaseFragment imple
@Override public void onItemSelected(SimpleUrlsModel item) {
SchemeParser.launchUri(getContext(), Uri.parse(item.getItem()));
}
+
+ @Override public void onShowGuide(@NonNull View itemView, @NonNull EventsModel model) {
+ if (!PrefGetter.isUserIconGuideShowed()) {
+ new MaterialTapTargetPrompt.Builder(getActivity())
+ .setTarget(itemView.findViewById(R.id.avatarLayout))
+ .setPrimaryText(R.string.users)
+ .setSecondaryText(R.string.avatar_click_hint)
+ .setOnHidePromptListener(new MaterialTapTargetPrompt.OnHidePromptListener() {
+ @Override public void onHidePrompt(MotionEvent event, boolean tappedTarget) {
+
+ }
+
+ @Override public void onHidePromptComplete() {
+ new MaterialTapTargetPrompt.Builder(getActivity())
+ .setTarget(itemView)
+ .setPrimaryText(R.string.fork)
+ .setSecondaryText(R.string.feeds_fork_hint)
+ .setCaptureTouchEventOutsidePrompt(true)
+ .show();
+ }
+ })
+ .setCaptureTouchEventOutsidePrompt(true)
+ .show();
+ }
+ }
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerView.java b/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerView.java
index 5f2bcd56..2ac9c4d2 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerView.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/RepoPagerView.java
@@ -10,6 +10,7 @@ import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import com.fastaccess.R;
@@ -21,6 +22,7 @@ import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
import com.fastaccess.helper.InputHelper;
import com.fastaccess.helper.ParseDateFormat;
+import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.TypeFaceHelper;
import com.fastaccess.ui.base.BaseActivity;
import com.fastaccess.ui.modules.repos.code.RepoCodePagerView;
@@ -37,6 +39,7 @@ import butterknife.OnClick;
import hugo.weaving.DebugLog;
import icepick.State;
import it.sephiroth.android.library.bottomnavigation.BottomNavigation;
+import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
/**
* Created by Kosh on 09 Dec 2016, 4:17 PM
@@ -176,6 +179,42 @@ public class RepoPagerView extends BaseActivity
+ new MaterialTapTargetPrompt.Builder(getActivity())
+ .setTarget(itemView.findViewById(R.id.menu))
+ .setPrimaryText(R.string.options)
+ .setSecondaryText(R.string.click_file_option_hint)
+ .setCaptureTouchEventOutsidePrompt(true)
+ .show());
+ adapter.notifyDataSetChanged();// call it notify the adapter to show the guide immediately.
+ }
+ }
+ }
+
@Override public void showProgress(@StringRes int resId) {
refresh.setRefreshing(true);
stateLayout.showProgress();
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/paths/RepoFilePathView.java b/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/paths/RepoFilePathView.java
index 29437c8f..b0eeebbd 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/paths/RepoFilePathView.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/code/files/paths/RepoFilePathView.java
@@ -104,6 +104,12 @@ public class RepoFilePathView extends BaseFragment
+ new MaterialTapTargetPrompt.Builder(getActivity())
+ .setTarget(itemView.findViewById(R.id.download))
+ .setPrimaryText(R.string.download)
+ .setSecondaryText(R.string.click_here_to_download_release_hint)
+ .setCaptureTouchEventOutsidePrompt(true)
+ .show());
+ adapter.notifyDataSetChanged();// call it notify the adapter to show the guide immediately.
+ }
+ }
+ }
+
@NonNull @Override public RepoReleasesPresenter providePresenter() {
return new RepoReleasesPresenter();
}
diff --git a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/comments/IssueCommentsView.java b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/comments/IssueCommentsView.java
index 0cd3b926..f2ff9280 100644
--- a/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/comments/IssueCommentsView.java
+++ b/app/src/main/java/com/fastaccess/ui/modules/repos/issues/issue/details/comments/IssueCommentsView.java
@@ -13,6 +13,7 @@ import com.fastaccess.data.dao.CommentsModel;
import com.fastaccess.data.dao.UserModel;
import com.fastaccess.helper.BundleConstant;
import com.fastaccess.helper.Bundler;
+import com.fastaccess.helper.PrefGetter;
import com.fastaccess.provider.rest.loadmore.OnLoadMore;
import com.fastaccess.ui.adapter.CommentsAdapter;
import com.fastaccess.ui.base.BaseFragment;
@@ -23,6 +24,7 @@ import com.fastaccess.ui.widgets.recyclerview.DynamicRecyclerView;
import butterknife.BindView;
import retrofit2.Response;
+import uk.co.samuelwall.materialtaptargetprompt.MaterialTapTargetPrompt;
/**
* Created by Kosh on 11 Nov 2016, 12:36 PM
@@ -175,4 +177,20 @@ public class IssueCommentsView extends BaseFragment
+ new MaterialTapTargetPrompt.Builder(getActivity())
+ .setTarget(itemView.findViewById(R.id.menu))
+ .setPrimaryText(R.string.comment)
+ .setSecondaryText(R.string.comment_hint)
+ .setCaptureTouchEventOutsidePrompt(true)
+ .show());
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/fastaccess/ui/widgets/recyclerview/BaseRecyclerAdapter.java b/app/src/main/java/com/fastaccess/ui/widgets/recyclerview/BaseRecyclerAdapter.java
index 9ba9ef82..06dc8581 100644
--- a/app/src/main/java/com/fastaccess/ui/widgets/recyclerview/BaseRecyclerAdapter.java
+++ b/app/src/main/java/com/fastaccess/ui/widgets/recyclerview/BaseRecyclerAdapter.java
@@ -3,6 +3,7 @@ package com.fastaccess.ui.widgets.recyclerview;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
+import android.view.View;
import android.view.ViewGroup;
import com.fastaccess.helper.AnimHelper;
@@ -16,10 +17,16 @@ import java.util.List;
public abstract class BaseRecyclerAdapter> extends RecyclerView.Adapter {
+ public interface GuideListener {
+ void onShowGuide(@NonNull View itemView, @NonNull M model);
+ }
+
@NonNull private List data;
@Nullable private P listener;
private int lastKnowingPosition = -1;
private boolean enableAnimation = true;
+ private boolean showedGuide;
+ private GuideListener guideListener;
public BaseRecyclerAdapter() {
this(new ArrayList<>());
@@ -57,12 +64,21 @@ public abstract class BaseRecyclerAdapter lastKnowingPosition) {
AnimHelper.startBeatsAnimation(holder.itemView);
@@ -145,4 +161,12 @@ public abstract class BaseRecyclerAdapterError Deleting Comment
Delete
Comments
+ Comment
Issue
Merge
Pull Request
@@ -160,4 +161,15 @@
Password
Login
Gist Description
+ Whenever there is a User avatar, you can click it to open the User\'s Profile
+ Long click on Fork event to choose to open either Original Repo or the Forked Repo.
+ Click here to download releases.
+ Options
+ Click here to download File or share a Directory.
+ Single tap to tag a user or to edit the comment if you are the author.\nLong press if you are the author of the
+ comment to delete it.
+ Click here to star/unstar repo.
+ Watch
+ Click here to watch/unwatch repo.
+ Click here to fork repo.