├── .gitignore
├── README.md
├── app
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── naman14
│ │ └── hacktoberfest
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── ArefRuqaa-Bold.ttf
│ │ └── ArefRuqaa-Regular.ttf
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── com
│ │ │ └── naman14
│ │ │ └── hacktoberfest
│ │ │ ├── MainActivity.java
│ │ │ ├── adapters
│ │ │ ├── PRAdapter.java
│ │ │ └── ProjectsAdapter.java
│ │ │ ├── fragment
│ │ │ ├── AboutFragment.java
│ │ │ ├── ExploreFragment.java
│ │ │ └── StatusFragment.java
│ │ │ ├── network
│ │ │ ├── api
│ │ │ │ ├── ApiEndPoints.java
│ │ │ │ ├── ApiInterceptor.java
│ │ │ │ ├── BaseURL.java
│ │ │ │ ├── GithubApiManager.java
│ │ │ │ └── services
│ │ │ │ │ └── SearchService.java
│ │ │ ├── entity
│ │ │ │ ├── Issue.java
│ │ │ │ ├── Label.java
│ │ │ │ ├── SearchResponse.java
│ │ │ │ └── User.java
│ │ │ └── repository
│ │ │ │ └── GithubRepository.java
│ │ │ ├── utils
│ │ │ ├── AnimUtils.java
│ │ │ ├── FabAnimationUtils.java
│ │ │ └── Utils.java
│ │ │ └── widgets
│ │ │ ├── CircleImageView.java
│ │ │ ├── FlowLayout.java
│ │ │ ├── GridRecyclerView.java
│ │ │ └── TypefaceTextView.java
│ └── res
│ │ ├── anim
│ │ ├── design_fab_out.xml
│ │ ├── grid_layout_animation.xml
│ │ └── slide_in_bottom.xml
│ │ ├── animator
│ │ └── raise.xml
│ │ ├── color
│ │ └── bottom_navigation_colors.xml
│ │ ├── drawable-anydpi
│ │ ├── compass_outline.xml
│ │ ├── ic_arrow_forward.xml
│ │ ├── ic_av_timer.xml
│ │ ├── ic_code.xml
│ │ ├── ic_done.xml
│ │ └── ic_info_outline.xml
│ │ ├── drawable
│ │ ├── edittext_bg.xml
│ │ ├── filter.png
│ │ ├── frame_fab_light.xml
│ │ ├── git_pull_merged.png
│ │ ├── git_pull_open.png
│ │ ├── ic_arrow_drop_down.xml
│ │ ├── ic_arrow_forward_white.xml
│ │ ├── issue_number_bg.xml
│ │ ├── item_label_bg.xml
│ │ └── spinner_bg.xml
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── fragment_about.xml
│ │ ├── fragment_explore.xml
│ │ ├── fragment_status.xml
│ │ ├── item_label.xml
│ │ ├── item_project.xml
│ │ ├── item_status_pr.xml
│ │ └── layout_filter_reveal.xml
│ │ ├── menu
│ │ └── menu_bottom_navigation.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── values-v23
│ │ └── styles.xml
│ │ └── values
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimen.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── naman14
│ └── hacktoberfest
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshots
├── screenshot1.png
├── screenshot2.png
└── screenshot3.png
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 | .idea/
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Hacktoberfest-Android
2 |
3 | This Android app allows you to check your Hacktoberfest status and explore issues
4 | and projects to get started with open source community.
5 |
6 |
7 |
8 | ## Screenshots
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion rootProject.compileSdkVersion
5 | defaultConfig {
6 | applicationId "com.naman14.hacktoberfest"
7 | minSdkVersion rootProject.minSdkVersion
8 | targetSdkVersion rootProject.targetSdkVersion
9 | versionCode 6
10 | versionName "3.1"
11 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 |
23 | implementation 'androidx.appcompat:appcompat:1.0.0'
24 | implementation 'com.google.android.material:material:1.0.0'
25 | implementation 'androidx.legacy:legacy-support-v13:1.0.0'
26 | implementation 'androidx.cardview:cardview:1.0.0'
27 | implementation 'androidx.browser:browser:1.0.0'
28 |
29 | implementation 'com.afollestad.material-dialogs:core:0.9.4.7'
30 |
31 | implementation "com.jakewharton:butterknife:$rootProject.butterKnifeVersion"
32 | annotationProcessor "com.jakewharton:butterknife-compiler:$rootProject.butterKnifeVersion"
33 |
34 | implementation ("com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion") {
35 | // exclude Retrofit’s OkHttp peer-dependency module and define your own module import
36 | exclude module: 'okhttp'
37 | }
38 | implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
39 | implementation "com.squareup.retrofit2:adapter-rxjava:$rootProject.retrofitVersion"
40 | implementation "com.squareup.okhttp3:okhttp:$rootProject.okHttp3Version"
41 | implementation "com.squareup.okhttp3:logging-interceptor:$rootProject.okHttp3Version"
42 | implementation 'com.squareup.picasso:picasso:2.5.2'
43 |
44 | implementation 'io.reactivex:rxandroid:1.2.1'
45 | implementation 'io.reactivex:rxjava:1.3.2'
46 |
47 | testImplementation 'junit:junit:4.12'
48 | }
49 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /home/naman/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/naman14/hacktoberfest/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.naman14.hacktoberfest", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/app/src/main/assets/ArefRuqaa-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/naman14/Hacktoberfest-Android/99b368c7b3cc1d2c896eab423304c1b0a4f0c7f8/app/src/main/assets/ArefRuqaa-Bold.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/ArefRuqaa-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/naman14/Hacktoberfest-Android/99b368c7b3cc1d2c896eab423304c1b0a4f0c7f8/app/src/main/assets/ArefRuqaa-Regular.ttf
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/naman14/Hacktoberfest-Android/99b368c7b3cc1d2c896eab423304c1b0a4f0c7f8/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest;
2 |
3 | import androidx.annotation.NonNull;
4 | import com.google.android.material.bottomnavigation.BottomNavigationView;
5 | import androidx.fragment.app.Fragment;
6 | import androidx.appcompat.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.view.MenuItem;
9 |
10 | import com.naman14.hacktoberfest.fragment.AboutFragment;
11 | import com.naman14.hacktoberfest.fragment.ExploreFragment;
12 | import com.naman14.hacktoberfest.fragment.StatusFragment;
13 |
14 | import butterknife.BindView;
15 | import butterknife.ButterKnife;
16 |
17 | public class MainActivity extends AppCompatActivity {
18 |
19 | @BindView(R.id.bottomBar)
20 | BottomNavigationView bottomBar;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_main);
26 | ButterKnife.bind(this);
27 |
28 | replaceFragment(new StatusFragment());
29 |
30 | bottomBar.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
31 | @Override
32 | public boolean onNavigationItemSelected(@NonNull MenuItem item) {
33 | switch (item.getItemId()) {
34 | case R.id.tab_status:
35 | replaceFragment(new StatusFragment());
36 | break;
37 | case R.id.tab_explore:
38 | replaceFragment(new ExploreFragment());
39 | break;
40 | case R.id.tab_about:
41 | replaceFragment(new AboutFragment());
42 | break;
43 | }
44 | return true;
45 | }
46 | });
47 | }
48 |
49 | private void replaceFragment(Fragment fragment) {
50 | getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).commit();
51 | }
52 |
53 | public BottomNavigationView getBottomBar() {
54 | return bottomBar;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/adapters/PRAdapter.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.Drawable;
6 | import android.graphics.drawable.GradientDrawable;
7 |
8 | import androidx.browser.customtabs.CustomTabsIntent;
9 | import androidx.recyclerview.widget.RecyclerView;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.TextView;
14 |
15 | import com.naman14.hacktoberfest.R;
16 | import com.naman14.hacktoberfest.network.entity.Issue;
17 | import com.naman14.hacktoberfest.utils.Utils;
18 |
19 | import java.util.List;
20 |
21 | import butterknife.BindView;
22 | import butterknife.ButterKnife;
23 |
24 | /**
25 | * Created by naman on 19/9/17.
26 | */
27 |
28 | public class PRAdapter extends RecyclerView.Adapter {
29 |
30 | private List array;
31 | private Context context;
32 |
33 | public PRAdapter(Context context) {
34 | this.context = context;
35 | }
36 |
37 | @Override
38 | public PRAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
39 | View v = LayoutInflater.from(parent.getContext()).inflate(
40 | R.layout.item_status_pr, parent, false);
41 | return new PRAdapter.ViewHolder(v);
42 | }
43 |
44 | @Override
45 | public void onBindViewHolder(PRAdapter.ViewHolder holder, int position) {
46 |
47 | Issue issue = array.get(position);
48 |
49 | holder.tvPrNumber.setText("#" + issue.getNumber());
50 | holder.tvPrTitle.setText(issue.getTitle());
51 | holder.tvPrRepo.setText(getRepoFromUrl(issue.getRepository_url()));
52 |
53 | GradientDrawable drawable = (GradientDrawable) holder.tvPrStatus.getBackground();
54 | Drawable img;
55 | switch (issue.getState()) {
56 | case "open":
57 | holder.tvPrStatus.setText("Open");
58 | img = context.getResources().getDrawable( R.drawable.git_pull_open);
59 | img.setBounds( 0, 0, 50, 50 );
60 | holder.tvPrStatus.setCompoundDrawables(img, null, null, null);
61 | drawable.setColor(Color.parseColor("#2cbe4e"));
62 | break;
63 | // github api doesn't have a way to distinguish between closed and merged state. state is
64 | case "closed":
65 | holder.tvPrStatus.setText("Merged/Closed");
66 | img = context.getResources().getDrawable( R.drawable.git_pull_merged);
67 | img.setBounds( 0, 0, 50, 50 );
68 | holder.tvPrStatus.setCompoundDrawables(img, null, null, null);
69 | drawable.setColor(Color.parseColor("#6f42c1"));
70 | break;
71 | }
72 |
73 | }
74 |
75 | @Override
76 | public int getItemCount() {
77 | if (array != null) {
78 | return array.size();
79 | } else {
80 | return 0;
81 | }
82 | }
83 |
84 | public class ViewHolder extends RecyclerView.ViewHolder {
85 |
86 | @BindView(R.id.tv_pr_number)
87 | TextView tvPrNumber;
88 |
89 | @BindView(R.id.tv_pr_title)
90 | TextView tvPrTitle;
91 |
92 | @BindView(R.id.tv_pr_repo)
93 | TextView tvPrRepo;
94 |
95 | @BindView(R.id.tv_pr_status)
96 | TextView tvPrStatus;
97 |
98 | ViewHolder(View v) {
99 | super(v);
100 | ButterKnife.bind(this, v);
101 |
102 | tvPrNumber.setOnClickListener(new View.OnClickListener() {
103 | @Override
104 | public void onClick(View view) {
105 | Utils.openChromeCustomTab(context, array.get(getAdapterPosition()).getHtml_url());
106 | }
107 | });
108 |
109 | v.setOnClickListener(new View.OnClickListener() {
110 | @Override
111 | public void onClick(View view) {
112 | Utils.openChromeCustomTab(context, array.get(getAdapterPosition()).getHtml_url());
113 | }
114 | });
115 |
116 | }
117 | }
118 |
119 | private String getRepoFromUrl(String url) {
120 | return url.replace("https://api.github.com/repos/", "");
121 | }
122 |
123 | public void setData(List data) {
124 | this.array = data;
125 | notifyDataSetChanged();
126 | }
127 |
128 | public void clearData() {
129 | this.array.clear();
130 | notifyDataSetChanged();
131 | }
132 |
133 | public List getData() {
134 | return array;
135 | }
136 |
137 |
138 | }
139 |
140 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/adapters/ProjectsAdapter.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.adapters;
2 |
3 | import android.content.Context;
4 | import android.graphics.Color;
5 | import android.graphics.drawable.GradientDrawable;
6 |
7 | import androidx.browser.customtabs.CustomTabsIntent;
8 | import androidx.recyclerview.widget.RecyclerView;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.TextView;
13 |
14 | import com.naman14.hacktoberfest.R;
15 | import com.naman14.hacktoberfest.utils.Utils;
16 | import com.naman14.hacktoberfest.network.entity.Issue;
17 | import com.naman14.hacktoberfest.network.entity.Label;
18 | import com.naman14.hacktoberfest.widgets.FlowLayout;
19 |
20 | import java.util.List;
21 |
22 | import butterknife.BindView;
23 | import butterknife.ButterKnife;
24 |
25 | /**
26 | * Created by naman on 19/9/17.
27 | */
28 |
29 | public class ProjectsAdapter extends RecyclerView.Adapter {
30 |
31 | private List array;
32 | private Context context;
33 |
34 | private FlowLayout.LayoutParams params;
35 |
36 | public ProjectsAdapter(Context context) {
37 | this.context = context;
38 | this.params = new FlowLayout.LayoutParams(25, 30);
39 | }
40 |
41 | @Override
42 | public ProjectsAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
43 | View v = LayoutInflater.from(parent.getContext()).inflate(
44 | R.layout.item_project, parent, false);
45 | return new ProjectsAdapter.ViewHolder(v);
46 | }
47 |
48 | @Override
49 | public void onBindViewHolder(ProjectsAdapter.ViewHolder holder, int position) {
50 |
51 | Issue issue = array.get(position);
52 |
53 | holder.tvIssueNumber.setText("#" + issue.getNumber());
54 | holder.tvIssueTitle.setText(issue.getTitle());
55 | holder.tvIssueRepo.setText(getRepoFromUrl(issue.getRepository_url()));
56 |
57 | if (Utils.getLanguagePreference(context).equals("All")) {
58 | holder.tvIssueLanguage.setVisibility(View.GONE);
59 | } else {
60 | holder.tvIssueLanguage.setText(Utils.getLanguagePreference(context));
61 | }
62 |
63 | if (issue.getLabels() != null && issue.getLabels().size() != 0) {
64 | for (Label label : issue.getLabels()) {
65 |
66 | TextView textView = (TextView) LayoutInflater.from(context).inflate(R.layout.item_label, null);
67 |
68 | GradientDrawable drawable = (GradientDrawable) textView.getBackground();
69 | drawable.setColor(Color.parseColor("#" + label.getColor()));
70 |
71 | textView.setText(label.getName());
72 | textView.setTextColor(Utils.getContrastColor(Color.parseColor("#" + label.getColor())));
73 |
74 | holder.llLabels.addView(textView, params);
75 | }
76 | }
77 |
78 | }
79 |
80 | @Override
81 | public int getItemCount() {
82 | if (array != null) {
83 | return array.size();
84 | } else {
85 | return 0;
86 | }
87 | }
88 |
89 | public class ViewHolder extends RecyclerView.ViewHolder {
90 |
91 | @BindView(R.id.tv_issue_number)
92 | TextView tvIssueNumber;
93 |
94 | @BindView(R.id.tv_issue_title)
95 | TextView tvIssueTitle;
96 |
97 | @BindView(R.id.tv_issue_repo)
98 | TextView tvIssueRepo;
99 |
100 | @BindView(R.id.tv_issue_language)
101 | TextView tvIssueLanguage;
102 |
103 | @BindView(R.id.ll_labels)
104 | FlowLayout llLabels;
105 |
106 |
107 | ViewHolder(View v) {
108 | super(v);
109 | ButterKnife.bind(this, v);
110 |
111 |
112 | v.setOnClickListener(new View.OnClickListener() {
113 | @Override
114 | public void onClick(View view) {
115 | Utils.openChromeCustomTab(context, array.get(getAdapterPosition()).getHtml_url());
116 | }
117 | });
118 | }
119 | }
120 |
121 | private String getRepoFromUrl(String url) {
122 | return url.replace("https://api.github.com/repos/", "");
123 | }
124 |
125 | public void setData(List data) {
126 | this.array = data;
127 | notifyDataSetChanged();
128 | }
129 | public void addData(List data) {
130 | int positionStart = array.size() + 1;
131 | this.array.addAll(data);
132 | notifyItemRangeInserted(positionStart,array.size());
133 | }
134 | public void clearData() {
135 | if (array != null) {
136 | this.array.clear();
137 | notifyDataSetChanged();
138 | }
139 | }
140 |
141 | public List getData() {
142 | return array;
143 | }
144 |
145 | }
146 |
147 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/fragment/AboutFragment.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.fragment;
2 |
3 | import android.graphics.Paint;
4 | import android.os.Bundle;
5 | import androidx.annotation.Nullable;
6 | import androidx.fragment.app.Fragment;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | import com.naman14.hacktoberfest.R;
13 | import com.naman14.hacktoberfest.utils.Utils;
14 |
15 | import butterknife.BindView;
16 | import butterknife.ButterKnife;
17 | import butterknife.OnClick;
18 |
19 | /**
20 | * Created by naman on 4/10/17.
21 | */
22 |
23 | public class AboutFragment extends Fragment {
24 |
25 | @BindView(R.id.tv_website)
26 | TextView tvWebsite;
27 |
28 | @Nullable
29 | @Override
30 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
31 | View rootView = inflater.inflate(R.layout.fragment_about, container, false);
32 |
33 | ButterKnife.bind(this, rootView);
34 |
35 | tvWebsite.setPaintFlags(Paint.UNDERLINE_TEXT_FLAG);
36 |
37 | return rootView;
38 | }
39 |
40 | @OnClick(R.id.tv_website)
41 | public void websiteClicked() {
42 | Utils.openChromeCustomTab(getActivity(), "https://hacktoberfest.digitalocean.com");
43 | }
44 |
45 | @OnClick(R.id.tv_view_github)
46 | public void viewGithub() {
47 | Utils.openChromeCustomTab(getActivity(), "https://github.com/naman14/Hacktoberfest-Android");
48 | }
49 |
50 | @OnClick(R.id.tv_sign_up)
51 | public void signUp() {
52 | Utils.openChromeCustomTab(getActivity(), "https://hacktoberfest.digitalocean.com/sign_up/register");
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/fragment/ExploreFragment.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.fragment;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.AnimatorSet;
6 | import android.animation.ObjectAnimator;
7 | import android.graphics.Color;
8 | import android.os.Bundle;
9 | import androidx.annotation.Nullable;
10 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.core.content.ContextCompat;
13 | import androidx.core.widget.NestedScrollView;
14 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
15 | import androidx.recyclerview.widget.LinearLayoutManager;
16 | import androidx.recyclerview.widget.RecyclerView;
17 | import android.view.LayoutInflater;
18 | import android.view.View;
19 | import android.view.ViewAnimationUtils;
20 | import android.view.ViewGroup;
21 | import android.view.ViewTreeObserver;
22 | import android.widget.Button;
23 | import android.widget.ProgressBar;
24 | import android.widget.TextView;
25 | import android.widget.Toast;
26 |
27 | import com.afollestad.materialdialogs.MaterialDialog;
28 | import com.naman14.hacktoberfest.R;
29 | import com.naman14.hacktoberfest.adapters.ProjectsAdapter;
30 | import com.naman14.hacktoberfest.network.entity.Issue;
31 | import com.naman14.hacktoberfest.network.repository.GithubRepository;
32 | import com.naman14.hacktoberfest.utils.AnimUtils;
33 | import com.naman14.hacktoberfest.utils.FabAnimationUtils;
34 | import com.naman14.hacktoberfest.utils.Utils;
35 |
36 | import java.util.Arrays;
37 | import java.util.List;
38 |
39 | import butterknife.BindView;
40 | import butterknife.ButterKnife;
41 | import butterknife.OnClick;
42 | import rx.Subscriber;
43 | import rx.android.schedulers.AndroidSchedulers;
44 | import rx.schedulers.Schedulers;
45 |
46 | /**
47 | * Created by naman on 4/10/17.
48 | */
49 |
50 | public class ExploreFragment extends Fragment {
51 |
52 | @BindView(R.id.recyclerView)
53 | RecyclerView recyclerView;
54 |
55 | @BindView(R.id.progressBar)
56 | ProgressBar progressBar;
57 |
58 | @BindView(R.id.fab)
59 | FloatingActionButton fab;
60 |
61 | @BindView(R.id.confirm_save_container)
62 | ViewGroup confirmSaveContainer;
63 |
64 | @BindView(R.id.results_scrim)
65 | View resultsScrim;
66 |
67 | @BindView(R.id.save_confirmed)
68 | Button saveConfirmed;
69 |
70 | @BindView(R.id.tv_language)
71 | TextView tvLanguage;
72 |
73 | @BindView(R.id.tv_tags)
74 | TextView tvTags;
75 |
76 | @BindView(R.id.scrollView)
77 | NestedScrollView scrollView;
78 |
79 | @BindView(R.id.swipe_refresh_layout)
80 | SwipeRefreshLayout swipeRefreshLayout;
81 |
82 | private ProjectsAdapter adapter;
83 | private int page = 1;
84 | private Boolean loading = false;
85 |
86 | @Nullable
87 | @Override
88 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
89 | View rootView = inflater.inflate(R.layout.fragment_explore, container, false);
90 |
91 | ButterKnife.bind(this, rootView);
92 |
93 | setupFilter();
94 | setupRecyclerview();
95 |
96 | setupSwipeRefreshLayout();
97 |
98 | fetchIssues();
99 | return rootView;
100 | }
101 |
102 | private void setupSwipeRefreshLayout() {
103 |
104 | swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
105 | @Override
106 | public void onRefresh() {
107 | page=1;
108 | fetchIssues();
109 | }
110 | });
111 | }
112 |
113 |
114 | private void setupFilter() {
115 | fab.setOnClickListener(new View.OnClickListener() {
116 | @Override
117 | public void onClick(View v) {
118 | show();
119 | }
120 | });
121 |
122 | resultsScrim.setOnClickListener(new View.OnClickListener() {
123 | @Override
124 | public void onClick(View v) {
125 | hide();
126 | }
127 | });
128 |
129 | saveConfirmed.setOnClickListener(new View.OnClickListener() {
130 | @Override
131 | public void onClick(View v) {
132 | saveAndhide();
133 | }
134 | });
135 |
136 | tvLanguage.setText(Utils.getLanguagePreference(getActivity()));
137 | tvTags.setText(Utils.getTagsPreferenceString(getActivity()));
138 |
139 | scrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
140 | @Override
141 | public void onScrollChange(NestedScrollView view, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
142 | if (scrollY > oldScrollY) {
143 | if (fab.getVisibility() == View.VISIBLE) {
144 | FabAnimationUtils.scaleOut(fab);
145 | }
146 | }
147 | if (scrollY < oldScrollY) {
148 | if (fab.getVisibility() != View.VISIBLE) {
149 | fab.setVisibility(View.VISIBLE);
150 | FabAnimationUtils.scaleIn(fab);
151 | }
152 | }
153 | if(view.getChildAt(view.getChildCount() - 1) != null) {
154 | if ((scrollY >= (view.getChildAt(view.getChildCount() - 1).getMeasuredHeight() - view.getMeasuredHeight())) &&
155 | scrollY > oldScrollY) {
156 | if (!loading) {
157 | page++;
158 | fetchIssues();
159 | }
160 | }
161 | }
162 |
163 | }
164 | });
165 |
166 | }
167 |
168 | @OnClick(R.id.tv_language)
169 | public void showLanguageDialog() {
170 | final String[] array = Utils.getLanguagesArray();
171 | new MaterialDialog.Builder(getActivity())
172 | .title("Select language")
173 | .items(Utils.getLanguagesArray())
174 | .itemsCallbackSingleChoice(Arrays.asList(array).indexOf(Utils.getLanguagePreference(getActivity())), new MaterialDialog.ListCallbackSingleChoice() {
175 | @Override
176 | public boolean onSelection(MaterialDialog dialog, View view, int which, CharSequence text) {
177 | tvLanguage.setText(array[which]);
178 | Utils.setLanguagePreference(getActivity(), array[which]);
179 | return true;
180 | }
181 | })
182 | .show();
183 | }
184 |
185 | @OnClick(R.id.tv_tags)
186 | public void showTagsDialog() {
187 | final List tagsList = Arrays.asList(Utils.getTagsArray());
188 | String[] tagsPreference = Utils.getTagsPreference(getActivity());
189 | Integer[] tagsPreferenceIndex = {};
190 |
191 | if (tagsPreference != null) {
192 | tagsPreferenceIndex = new Integer[tagsPreference.length];
193 |
194 | int index = 0;
195 | for (String tagPreference: tagsPreference) {
196 | tagsPreferenceIndex[index++] = tagsList.indexOf(tagPreference);
197 | }
198 | }
199 |
200 | new MaterialDialog.Builder(getActivity())
201 | .title("Select Tags")
202 | .items(Utils.getTagsArray())
203 | .itemsCallbackMultiChoice(tagsPreferenceIndex, new MaterialDialog.ListCallbackMultiChoice() {
204 | @Override
205 | public boolean onSelection(MaterialDialog dialog, Integer[] which, CharSequence[] text) {
206 | String[] selectedTags = new String[text.length];
207 | int index = 0;
208 |
209 | for (CharSequence charSequence: text) {
210 | selectedTags[index++] = charSequence.toString();
211 | }
212 |
213 | Utils.setTagsPreference(getActivity(), selectedTags);
214 | tvTags.setText(Utils.getTagsPreferenceString(getActivity()));
215 | return true;
216 | };
217 | }
218 | ).positiveText("Select Tags")
219 | .show();
220 | }
221 |
222 | private void setupRecyclerview() {
223 |
224 | final LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
225 | recyclerView.setLayoutManager(layoutManager);
226 |
227 | adapter = new ProjectsAdapter(getActivity());
228 | recyclerView.setAdapter(adapter);
229 |
230 | recyclerView.setNestedScrollingEnabled(false);
231 |
232 | }
233 |
234 | private void fetchIssues() {
235 | loading = true;
236 | swipeRefreshLayout.setEnabled(false);
237 | if(page == 1) {
238 | progressBar.setVisibility(View.VISIBLE);
239 | adapter.clearData();
240 | }
241 | else
242 | swipeRefreshLayout.setRefreshing(true);
243 | String language = Utils.getLanguagePreference(getActivity());
244 |
245 | String[] tags = Utils.getTagsPreference(getActivity());
246 | GithubRepository.getInstance().findIssues(language, tags, page)
247 | .observeOn(AndroidSchedulers.mainThread())
248 | .subscribeOn(Schedulers.io())
249 | .subscribe(new Subscriber>() {
250 | @Override
251 | public void onCompleted() {
252 |
253 | }
254 |
255 | @Override
256 | public void onError(Throwable e) {
257 | progressBar.setVisibility(View.GONE);
258 | swipeRefreshLayout.setRefreshing(false);
259 | swipeRefreshLayout.setEnabled(true);
260 | loading = false;
261 | if (getActivity() != null) {
262 | Toast.makeText(getActivity(), "Error fetching projects", Toast.LENGTH_SHORT).show();
263 | }
264 | }
265 |
266 | @Override
267 | public void onNext(List response) {
268 | progressBar.setVisibility(View.GONE);
269 | swipeRefreshLayout.setRefreshing(false);
270 | swipeRefreshLayout.setEnabled(true);
271 | loading = false;
272 | if(page == 1)
273 | adapter.setData(response);
274 | else
275 | adapter.addData(response);
276 | }
277 | });
278 | }
279 |
280 | private void show() {
281 | FabAnimationUtils.scaleOut(fab);
282 | fab.setVisibility(View.INVISIBLE);
283 | confirmSaveContainer.setVisibility(View.VISIBLE);
284 | resultsScrim.setVisibility(View.VISIBLE);
285 |
286 | confirmSaveContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver
287 | .OnPreDrawListener() {
288 | @Override
289 | public boolean onPreDraw() {
290 | confirmSaveContainer.getViewTreeObserver().removeOnPreDrawListener(this);
291 |
292 | Animator reveal = ViewAnimationUtils.createCircularReveal(confirmSaveContainer,
293 | confirmSaveContainer.getWidth() / 2,
294 | confirmSaveContainer.getHeight() / 2,
295 | fab.getWidth() / 2,
296 | confirmSaveContainer.getWidth() / 2);
297 | reveal.setDuration(250L);
298 | reveal.setInterpolator(AnimUtils.getFastOutSlowInInterpolator(getActivity()));
299 | reveal.start();
300 |
301 | int centerX = (fab.getLeft() + fab.getRight()) / 2;
302 | int centerY = (fab.getTop() + fab.getBottom()) / 2;
303 | Animator revealScrim = ViewAnimationUtils.createCircularReveal(
304 | resultsScrim,
305 | centerX,
306 | centerY,
307 | 0,
308 | (float) Math.hypot(centerX, centerY));
309 | revealScrim.setDuration(400L);
310 | revealScrim.setInterpolator(AnimUtils.getLinearOutSlowInInterpolator(getActivity()
311 | ));
312 | revealScrim.start();
313 | ObjectAnimator fadeInScrim = ObjectAnimator.ofArgb(resultsScrim,
314 | Utils.BACKGROUND_COLOR,
315 | Color.TRANSPARENT,
316 | ContextCompat.getColor(getActivity(), R.color.scrim));
317 | fadeInScrim.setDuration(800L);
318 | fadeInScrim.setInterpolator(AnimUtils.getLinearOutSlowInInterpolator(getActivity()
319 | ));
320 | fadeInScrim.start();
321 |
322 | return false;
323 | }
324 | });
325 | }
326 |
327 | private void hide() {
328 | if (confirmSaveContainer.getVisibility() == View.VISIBLE) {
329 | hideFilterContainer();
330 | }
331 | }
332 |
333 | private void saveAndhide() {
334 | if (confirmSaveContainer.getVisibility() == View.VISIBLE) {
335 | page=1;
336 | fetchIssues();
337 | hideFilterContainer();
338 | }
339 | }
340 |
341 | private void hideFilterContainer() {
342 |
343 | AnimatorSet hideConfirmation = new AnimatorSet();
344 | hideConfirmation.playTogether(
345 | ViewAnimationUtils.createCircularReveal(confirmSaveContainer,
346 | confirmSaveContainer.getWidth() / 2,
347 | confirmSaveContainer.getHeight() / 2,
348 | confirmSaveContainer.getWidth() / 2,
349 | fab.getWidth() / 2),
350 | ObjectAnimator.ofArgb(resultsScrim,
351 | Utils.BACKGROUND_COLOR,
352 | Color.TRANSPARENT));
353 | hideConfirmation.setDuration(150L);
354 | hideConfirmation.setInterpolator(AnimUtils.getFastOutSlowInInterpolator
355 | (getActivity()));
356 | hideConfirmation.addListener(new AnimatorListenerAdapter() {
357 | @Override
358 | public void onAnimationEnd(Animator animation) {
359 | confirmSaveContainer.setVisibility(View.GONE);
360 | resultsScrim.setVisibility(View.GONE);
361 | fab.setVisibility(View.VISIBLE);
362 | FabAnimationUtils.scaleIn(fab);
363 | }
364 | });
365 | hideConfirmation.start();
366 |
367 | }
368 |
369 | }
370 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/fragment/StatusFragment.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.fragment;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.graphics.Point;
6 | import android.os.Bundle;
7 | import android.os.Handler;
8 | import androidx.annotation.Nullable;
9 | import com.google.android.material.snackbar.Snackbar;
10 | import androidx.fragment.app.Fragment;
11 | import androidx.core.widget.NestedScrollView;
12 | import androidx.recyclerview.widget.GridLayoutManager;
13 | import androidx.recyclerview.widget.RecyclerView;
14 | import android.view.KeyEvent;
15 | import android.view.LayoutInflater;
16 | import android.view.View;
17 | import android.view.ViewGroup;
18 | import android.view.ViewParent;
19 | import android.view.inputmethod.EditorInfo;
20 | import android.widget.EditText;
21 | import android.widget.ImageView;
22 | import android.widget.ProgressBar;
23 | import android.widget.TextView;
24 | import android.widget.Toast;
25 |
26 | import com.naman14.hacktoberfest.R;
27 | import com.naman14.hacktoberfest.adapters.PRAdapter;
28 | import com.naman14.hacktoberfest.network.entity.Issue;
29 | import com.naman14.hacktoberfest.network.repository.GithubRepository;
30 | import com.naman14.hacktoberfest.utils.Utils;
31 | import com.naman14.hacktoberfest.widgets.GridRecyclerView;
32 | import com.squareup.picasso.Picasso;
33 |
34 | import java.util.List;
35 |
36 | import butterknife.BindView;
37 | import butterknife.ButterKnife;
38 | import butterknife.OnClick;
39 | import rx.Subscriber;
40 | import rx.android.schedulers.AndroidSchedulers;
41 | import rx.schedulers.Schedulers;
42 |
43 | /**
44 | * Created by naman on 4/10/17.
45 | */
46 |
47 | public class StatusFragment extends Fragment {
48 |
49 | @BindView(R.id.progressBar)
50 | ProgressBar progressBar;
51 |
52 | @BindView(R.id.iv_user_image)
53 | ImageView ivUserImage;
54 |
55 | @BindView(R.id.et_username)
56 | EditText etUsername;
57 |
58 | @BindView(R.id.tv_placeholder)
59 | TextView tvPlaceholder;
60 |
61 | @BindView(R.id.tv_pr_count)
62 | TextView tvPrCount;
63 |
64 | @BindView(R.id.tv_status_message)
65 | TextView tvStatusMessage;
66 |
67 | @BindView(R.id.tv_status_extra_message)
68 | TextView tvStatusExtraMessage;
69 |
70 | @BindView(R.id.iv_check)
71 | ImageView ivCheck;
72 |
73 | @BindView(R.id.scrollView)
74 | NestedScrollView scrollView;
75 |
76 | @BindView(R.id.statusView)
77 | View statusView;
78 |
79 | @BindView(R.id.recyclerView)
80 | GridRecyclerView recyclerView;
81 |
82 | private PRAdapter adapter;
83 | private SharedPreferences prefs;
84 |
85 | private static final String SHARED_PREFS = "hacktoberfest-android";
86 | private static final String USERNAME_KEY = "username";
87 |
88 | @Nullable
89 | @Override
90 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
91 | View rootView = inflater.inflate(R.layout.fragment_status, container, false);
92 |
93 | ButterKnife.bind(this, rootView);
94 |
95 | setupRecyclerview();
96 |
97 | prefs = getActivity()
98 | .getSharedPreferences(SHARED_PREFS, Context.MODE_PRIVATE);
99 |
100 | String storedUsername = prefs.getString(USERNAME_KEY, "");
101 | if(!storedUsername.isEmpty()) {
102 | etUsername.setText(storedUsername);
103 | checkPRStatus();
104 | }
105 |
106 | etUsername.setOnEditorActionListener(new TextView.OnEditorActionListener() {
107 | @Override
108 | public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
109 | if (actionId == EditorInfo.IME_ACTION_DONE) {
110 | Utils.hideKeyboard(getActivity());
111 | checkPRStatus();
112 | return true;
113 | }
114 | return false;
115 | }
116 | });
117 |
118 |
119 | return rootView;
120 | }
121 |
122 |
123 | @OnClick(R.id.iv_check)
124 | public void checkClicked() {
125 | String username = etUsername.getText().toString();
126 |
127 | if(username.isEmpty() || username.trim().length() == 0){
128 | Toast.makeText(getContext(), "Please enter a valid github username", Toast.LENGTH_LONG).show();
129 | }else{
130 | checkPRStatus();
131 | }
132 | }
133 |
134 | private void setupRecyclerview() {
135 | RecyclerView.LayoutManager layoutManager = new GridLayoutManager(getActivity(), 2);
136 | recyclerView.setLayoutManager(layoutManager);
137 |
138 | adapter = new PRAdapter(getActivity());
139 | recyclerView.setAdapter(adapter);
140 |
141 | recyclerView.setNestedScrollingEnabled(false);
142 | }
143 |
144 | private void checkPRStatus() {
145 | tvPlaceholder.setVisibility(View.GONE);
146 | statusView.setVisibility(View.GONE);
147 | progressBar.setVisibility(View.VISIBLE);
148 |
149 | prefs
150 | .edit()
151 | .putString(USERNAME_KEY, etUsername.getText().toString())
152 | .apply();
153 |
154 | GithubRepository.getInstance().findValidPRs(etUsername.getText().toString())
155 | .observeOn(AndroidSchedulers.mainThread())
156 | .subscribeOn(Schedulers.io())
157 | .subscribe(new Subscriber>() {
158 | @Override
159 | public void onCompleted() {
160 |
161 | }
162 |
163 | @Override
164 | public void onError(Throwable e) {
165 | progressBar.setVisibility(View.GONE);
166 | Snackbar.make(scrollView, "Error fetching details", Snackbar.LENGTH_LONG).show();
167 | }
168 |
169 | @Override
170 | public void onNext(List response) {
171 | progressBar.setVisibility(View.GONE);
172 | showStatus(response);
173 |
174 | }
175 | });
176 | }
177 |
178 | private void showStatus(final List response) {
179 | progressBar.setVisibility(View.GONE);
180 | statusView.setVisibility(View.VISIBLE);
181 |
182 | if (response != null && response.size() != 0) {
183 | Picasso.with(getActivity()).load(response.get(0).getUser().getAvatar_url()).into(ivUserImage);
184 | } else {
185 | Picasso.with(getActivity()).load("https://github.com/" +
186 | etUsername.getText().toString() + ".png").into(ivUserImage);
187 | }
188 |
189 | if (response != null) {
190 | tvPrCount.setText(String.valueOf(response.size()));
191 | tvStatusMessage.setText(Utils.getStatusMessage(response.size()));
192 | if (response.size() > 0)
193 | tvStatusExtraMessage.setVisibility(View.VISIBLE);
194 | adapter.setData(response);
195 | } else {
196 | tvPrCount.setText("0");
197 | }
198 |
199 | Handler handler = new Handler();
200 | handler.postDelayed(new Runnable() {
201 | @Override
202 | public void run() {
203 | scrollToView(scrollView, etUsername);
204 |
205 | }
206 | }, 350);
207 |
208 | Handler handler2 = new Handler();
209 | handler2.postDelayed(new Runnable() {
210 | @Override
211 | public void run() {
212 | adapter.setData(response);
213 |
214 | }
215 | }, 450);
216 |
217 | }
218 |
219 |
220 | private void scrollToView(final NestedScrollView scrollViewParent, final View view) {
221 | // Get deepChild Offset
222 | Point childOffset = new Point();
223 | getDeepChildOffset(scrollViewParent, view.getParent(), view, childOffset);
224 | // Scroll to child.
225 | scrollViewParent.smoothScrollTo(0, childOffset.y - 50);
226 | }
227 |
228 | private void getDeepChildOffset(final ViewGroup mainParent, final ViewParent parent, final View child, final Point accumulatedOffset) {
229 | ViewGroup parentGroup = (ViewGroup) parent;
230 | accumulatedOffset.x += child.getLeft();
231 | accumulatedOffset.y += child.getTop();
232 | if (parentGroup.equals(mainParent)) {
233 | return;
234 | }
235 | getDeepChildOffset(mainParent, parentGroup.getParent(), parentGroup, accumulatedOffset);
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/api/ApiEndPoints.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.api;
2 |
3 | /**
4 | * Created by naman on 17/6/17.
5 | */
6 |
7 | public class ApiEndPoints {
8 |
9 | public static final String SEARCH = "search";
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/api/ApiInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.api;
2 |
3 | import android.text.TextUtils;
4 |
5 | import java.io.IOException;
6 |
7 | import okhttp3.Interceptor;
8 | import okhttp3.Request;
9 | import okhttp3.Request.Builder;
10 | import okhttp3.Response;
11 |
12 | /**
13 | * Created by naman on 17/6/17.
14 | */
15 |
16 | public class ApiInterceptor implements Interceptor {
17 |
18 | private static final String HEADER_AUTH = "Authorization";
19 | private static final String HEADER_ACCEPT = "Accept";
20 | private static final String HEADER_USER_AGENT = "User-Agent";
21 | private String authToken;
22 |
23 |
24 | public ApiInterceptor(String authToken) {
25 | this.authToken = authToken;
26 |
27 | }
28 |
29 | @Override
30 | public Response intercept(Chain chain) throws IOException {
31 | Request chainRequest = chain.request();
32 | Builder builder = chainRequest.newBuilder();
33 | builder.header(HEADER_ACCEPT, "application/vnd.github.v3+json");
34 | builder.header(HEADER_USER_AGENT, "Hacktoberfest-Android-App");
35 | if (!TextUtils.isEmpty(authToken)) {
36 | builder.header(HEADER_AUTH, "Bearer " + authToken);
37 | }
38 |
39 | Request request = builder.build();
40 | return chain.proceed(request);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/api/BaseURL.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.api;
2 |
3 | /**
4 | * Created by naman on 17/6/17.
5 | */
6 |
7 | public class BaseURL {
8 |
9 | public static final String PROTOCOL_HTTPS = "https://";
10 |
11 | public static final String API_ENDPOINT = "api.github.com";
12 |
13 |
14 | public String getUrl() {
15 | return PROTOCOL_HTTPS + API_ENDPOINT;
16 |
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/api/GithubApiManager.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.api;
2 |
3 |
4 | import com.naman14.hacktoberfest.network.api.services.SearchService;
5 |
6 | import okhttp3.OkHttpClient;
7 | import okhttp3.logging.HttpLoggingInterceptor;
8 | import retrofit2.Retrofit;
9 | import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
10 | import retrofit2.converter.gson.GsonConverterFactory;
11 |
12 | /**
13 | * Created by naman on 17/6/17.
14 | */
15 |
16 | public class GithubApiManager {
17 |
18 | private static BaseURL baseUrl = new BaseURL();
19 | private static final String BASE_URL = baseUrl.getUrl();
20 |
21 | private static Retrofit retrofit;
22 |
23 | private static SearchService searchApi;
24 |
25 |
26 | public GithubApiManager() {
27 | String authToken = "";
28 | createService(authToken);
29 | }
30 |
31 | private static void init() {
32 | searchApi = createApi(SearchService.class);
33 | }
34 |
35 | private static T createApi(Class clazz) {
36 | return retrofit.create(clazz);
37 | }
38 |
39 | public static void createService(String authToken) {
40 |
41 | HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
42 | interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
43 |
44 | OkHttpClient okHttpClient = new OkHttpClient.Builder()
45 | .addInterceptor(interceptor)
46 | .addInterceptor(new ApiInterceptor(authToken))
47 | .build();
48 |
49 | retrofit = new Retrofit.Builder()
50 | .baseUrl(BASE_URL)
51 | .addConverterFactory(GsonConverterFactory.create())
52 | .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
53 | .client(okHttpClient)
54 | .build();
55 | init();
56 |
57 | }
58 |
59 | public SearchService getSearchApi() {
60 | return searchApi;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/api/services/SearchService.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.api.services;
2 |
3 | import com.naman14.hacktoberfest.network.api.ApiEndPoints;
4 | import com.naman14.hacktoberfest.network.entity.SearchResponse;
5 |
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Query;
8 | import rx.Observable;
9 |
10 | /**
11 | * Created by naman on 4/10/17.
12 | */
13 |
14 | public interface SearchService {
15 |
16 | @GET(ApiEndPoints.SEARCH + "/issues")
17 | Observable findPRs(@Query(encoded = true, value = "q") String searchQuery);
18 |
19 | @GET(ApiEndPoints.SEARCH + "/issues")
20 | Observable findIssues(@Query(encoded = true, value = "q") String searchQuery, @Query(encoded = true, value = "page") int page);
21 |
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/naman14/hacktoberfest/network/entity/Issue.java:
--------------------------------------------------------------------------------
1 | package com.naman14.hacktoberfest.network.entity;
2 |
3 | import java.util.List;
4 |
5 | /**
6 | * Created by naman on 5/10/17.
7 | */
8 |
9 | public class Issue {
10 |
11 | private String html_url, title, body, createdAt, repository_url, state;
12 | private int id, number;
13 |
14 | private String language;
15 |
16 | private User user;
17 |
18 | private List