├── .gitignore
├── LICENSE
├── README.md
├── app
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── azhar
│ │ └── githubusers
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── azhar
│ │ │ └── githubusers
│ │ │ ├── adapter
│ │ │ ├── FavoriteAdapter.java
│ │ │ ├── FollowAdapter.java
│ │ │ ├── SearchAdapter.java
│ │ │ └── ViewPagerAdapter.java
│ │ │ ├── database
│ │ │ ├── DatabaseContract.java
│ │ │ ├── DatabaseHelper.java
│ │ │ └── FavoriteHelper.java
│ │ │ ├── model
│ │ │ ├── follow
│ │ │ │ └── ModelFollow.java
│ │ │ ├── search
│ │ │ │ ├── ModelSearch.java
│ │ │ │ └── ModelSearchData.java
│ │ │ └── user
│ │ │ │ └── ModelUser.java
│ │ │ ├── networking
│ │ │ ├── ApiClient.java
│ │ │ └── ApiInterface.java
│ │ │ ├── ui
│ │ │ ├── activities
│ │ │ │ ├── DetailActivity.java
│ │ │ │ ├── FavoriteActivity.java
│ │ │ │ └── MainActivity.java
│ │ │ └── fragment
│ │ │ │ ├── FragmentFollowers.java
│ │ │ │ └── FragmentFollowing.java
│ │ │ └── viewmodel
│ │ │ └── UserViewModel.java
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── bg_search.xml
│ │ ├── ic_arrow_right.xml
│ │ ├── ic_clear.xml
│ │ ├── ic_favorite.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_search.xml
│ │ ├── ic_unfavorite.xml
│ │ ├── ic_user.xml
│ │ ├── tab_background_selected.xml
│ │ └── tab_layout_selector.xml
│ │ ├── layout
│ │ ├── activity_detail.xml
│ │ ├── activity_favorite.xml
│ │ ├── activity_main.xml
│ │ ├── fragment_followers.xml
│ │ ├── fragment_following.xml
│ │ ├── layout_empty.xml
│ │ └── list_item_data.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.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
│ │ ├── raw
│ │ └── lottie_empty.json
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── azhar
│ └── githubusers
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Log file
5 | *.log
6 |
7 | # BlueJ files
8 | *.ctxt
9 |
10 | # Mobile Tools for Java (J2ME)
11 | .mtj.tmp/
12 |
13 | # Package Files #
14 | *.jar
15 | *.war
16 | *.nar
17 | *.ear
18 | *.zip
19 | *.tar.gz
20 | *.rar
21 |
22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
23 | hs_err_pid*
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Github-User-App
2 | Membuat Aplikasi Github User MVVM dengan Android Studio. Ini hanya untuk referensi bagi kalian yang mengikuti Submission Dicoding Github User App.
3 |
4 | # Tutorial Build with Android Studio
5 | https://youtu.be/M1jz8aeo5VM
6 |
7 | # Tutorial Build with Step by Step
8 | https://rivaldi48.blogspot.com/2021/06/tutorial-membuat-aplikasi-github-user-dengan-android-studio.html
9 |
10 |
11 |
12 | *****If you use the Source Code, please make sure to credit and backlink to [Azhar Rivaldi](https://rivaldi48.blogspot.com/)***
13 |
14 | ## 👇 Click For Support Me :
15 |
16 |
17 |
18 | ## 📄 License
19 |
20 | ```
21 | Copyright (C) Azhar Rivaldi
22 |
23 | Licensed under the Apache License, Version 2.0 (the "License");
24 | you may not use this file except in compliance with the License.
25 | You may obtain a copy of the License at
26 |
27 | http://www.apache.org/licenses/LICENSE-2.0
28 |
29 | Unless required by applicable law or agreed to in writing, software
30 | distributed under the License is distributed on an "AS IS" BASIS,
31 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32 | See the License for the specific language governing permissions and
33 | limitations under the License.
34 |
35 | ```
36 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 30
5 | buildToolsVersion "30.0.3"
6 |
7 | defaultConfig {
8 | applicationId "com.azhar.githubusers"
9 | minSdkVersion 21
10 | targetSdkVersion 30
11 | versionCode 1
12 | versionName "1.0"
13 |
14 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
15 | }
16 |
17 | buildTypes {
18 | release {
19 | minifyEnabled false
20 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: "libs", include: ["*.jar"])
27 | implementation 'androidx.appcompat:appcompat:1.3.0'
28 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
29 | implementation 'androidx.cardview:cardview:1.0.0'
30 | implementation 'androidx.recyclerview:recyclerview:1.2.0'
31 | implementation 'androidx.lifecycle:lifecycle-livedata:2.3.1'
32 | implementation 'androidx.lifecycle:lifecycle-viewmodel:2.3.1'
33 |
34 | implementation 'com.google.android.material:material:1.3.0'
35 | implementation 'de.hdodenhof:circleimageview:3.1.0'
36 | implementation 'com.github.ivbaranov:materialfavoritebutton:0.1.5'
37 | implementation 'com.airbnb.android:lottie:3.7.0'
38 |
39 | implementation 'com.squareup.retrofit2:retrofit:2.9.0'
40 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
41 | implementation 'com.squareup.okhttp3:logging-interceptor:4.9.1'
42 |
43 | implementation 'com.github.bumptech.glide:glide:4.12.0'
44 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
45 | annotationProcessor 'com.github.bumptech.glide:compiler:4.12.0'
46 |
47 | testImplementation 'junit:junit:4.13.2'
48 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
49 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
50 |
51 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/azhar/githubusers/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.azhar.githubusers", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
17 |
18 |
21 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/adapter/FavoriteAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.adapter;
2 |
3 | import android.view.LayoutInflater;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.ImageView;
7 | import android.widget.TextView;
8 |
9 | import androidx.recyclerview.widget.RecyclerView;
10 |
11 | import com.azhar.githubusers.R;
12 | import com.azhar.githubusers.model.user.ModelUser;
13 | import com.bumptech.glide.Glide;
14 |
15 | import java.util.ArrayList;
16 |
17 | /**
18 | * Created by Azhar Rivaldi on 23-05-2021
19 | * Youtube Channel : https://bit.ly/2PJMowZ
20 | * Github : https://github.com/AzharRivaldi
21 | * Twitter : https://twitter.com/azharrvldi_
22 | * Instagram : https://www.instagram.com/azhardvls_
23 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
24 | */
25 |
26 | public class FavoriteAdapter extends RecyclerView.Adapter {
27 |
28 | private ArrayList modelUserArrayList = new ArrayList<>();
29 |
30 | public void setFavoriteUserList(ArrayList data) {
31 | this.modelUserArrayList.clear();
32 | this.modelUserArrayList.addAll(data);
33 | notifyDataSetChanged();
34 | }
35 |
36 | @Override
37 | public FavoriteAdapter.FavoriteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
38 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
39 | return new FavoriteAdapter.FavoriteViewHolder(view);
40 | }
41 |
42 | @Override
43 | public void onBindViewHolder(FavoriteViewHolder holder, int position) {
44 | ModelUser item = modelUserArrayList.get(position);
45 |
46 | Glide.with(holder.itemView.getContext())
47 | .load(item.getAvatarUrl())
48 | .into(holder.imageUser);
49 |
50 | holder.tvUsername.setText(item.getLogin());
51 | holder.tvUrl.setText(item.getHtmlUrl());
52 | /*holder.cvListUser.setOnClickListener(new View.OnClickListener() {
53 | @Override
54 | public void onClick(View view) {
55 | Intent intent = new Intent(context, DetailActivity.class);
56 | intent.putExtra(DetailActivity.DETAIL_USER, modelFollowersArrayList.get(position));
57 | context.startActivity(intent);
58 | }
59 | });*/
60 | }
61 |
62 | @Override
63 | public int getItemCount() {
64 | return modelUserArrayList.size();
65 | }
66 |
67 | public class FavoriteViewHolder extends RecyclerView.ViewHolder {
68 | TextView tvUsername, tvUrl;
69 | ImageView imageUser;
70 |
71 | public FavoriteViewHolder(View itemView) {
72 | super(itemView);
73 | tvUsername = itemView.findViewById(R.id.tvUsername);
74 | tvUrl = itemView.findViewById(R.id.tvUrl);
75 | imageUser = itemView.findViewById(R.id.imageUser);
76 | }
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/adapter/FollowAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.adapter;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 |
10 | import androidx.cardview.widget.CardView;
11 | import androidx.recyclerview.widget.RecyclerView;
12 |
13 | import com.azhar.githubusers.R;
14 | import com.azhar.githubusers.model.follow.ModelFollow;
15 | import com.bumptech.glide.Glide;
16 |
17 | import java.util.ArrayList;
18 |
19 | /**
20 | * Created by Azhar Rivaldi on 20-05-2021
21 | * Youtube Channel : https://bit.ly/2PJMowZ
22 | * Github : https://github.com/AzharRivaldi
23 | * Twitter : https://twitter.com/azharrvldi_
24 | * Instagram : https://www.instagram.com/azhardvls_
25 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
26 | */
27 |
28 | public class FollowAdapter extends RecyclerView.Adapter {
29 |
30 | private ArrayList modelFollowArrayList = new ArrayList<>();
31 | private Context context;
32 |
33 | public FollowAdapter(Context context) {
34 | this.context = context;
35 | }
36 |
37 | public void setFollowList(ArrayList items) {
38 | modelFollowArrayList.clear();
39 | modelFollowArrayList.addAll(items);
40 | notifyDataSetChanged();
41 | }
42 |
43 | @Override
44 | public FollowAdapter.FolowersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
45 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
46 | return new FolowersViewHolder(view);
47 | }
48 |
49 | @Override
50 | public void onBindViewHolder(FollowAdapter.FolowersViewHolder holder, int position) {
51 | ModelFollow item = modelFollowArrayList.get(position);
52 |
53 | Glide.with(holder.itemView.getContext())
54 | .load(item.getAvatarUrl())
55 | .into(holder.imageUser);
56 |
57 | holder.tvUsername.setText(item.getLogin());
58 | holder.tvUrl.setText(item.getHtmlUrl());
59 | /*holder.cvListUser.setOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View view) {
62 | Intent intent = new Intent(context, DetailActivity.class);
63 | intent.putExtra(DetailActivity.DETAIL_USER, modelFollowersArrayList.get(position));
64 | context.startActivity(intent);
65 | }
66 | });*/
67 |
68 | }
69 |
70 | @Override
71 | public int getItemCount() {
72 | return modelFollowArrayList.size();
73 | }
74 |
75 | public static class FolowersViewHolder extends RecyclerView.ViewHolder {
76 |
77 | CardView cvListUser;
78 | TextView tvUsername, tvUrl;
79 | ImageView imageUser, imageArrow;
80 |
81 | public FolowersViewHolder(View itemView) {
82 | super(itemView);
83 | cvListUser = itemView.findViewById(R.id.cvListUser);
84 | tvUsername = itemView.findViewById(R.id.tvUsername);
85 | tvUrl = itemView.findViewById(R.id.tvUrl);
86 | imageUser = itemView.findViewById(R.id.imageUser);
87 | imageArrow = itemView.findViewById(R.id.imageArrow);
88 |
89 | imageArrow.setVisibility(View.GONE);
90 | }
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/adapter/SearchAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.adapter;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 | import androidx.cardview.widget.CardView;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.azhar.githubusers.R;
15 | import com.azhar.githubusers.ui.activities.DetailActivity;
16 | import com.azhar.githubusers.model.search.ModelSearchData;
17 | import com.bumptech.glide.Glide;
18 |
19 | import java.util.ArrayList;
20 |
21 | /**
22 | * Created by Azhar Rivaldi on 18-05-2021
23 | * Youtube Channel : https://bit.ly/2PJMowZ
24 | * Github : https://github.com/AzharRivaldi
25 | * Twitter : https://twitter.com/azharrvldi_
26 | * Instagram : https://www.instagram.com/azhardvls_
27 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
28 | */
29 |
30 | public class SearchAdapter extends RecyclerView.Adapter {
31 |
32 | private ArrayList modelSearchDataList= new ArrayList<>();
33 | private Context context;
34 |
35 | public SearchAdapter(Context context) {
36 | this.context = context;
37 | }
38 |
39 | public void setSearchUserList(ArrayList items) {
40 | modelSearchDataList.clear();
41 | modelSearchDataList.addAll(items);
42 | notifyDataSetChanged();
43 | }
44 |
45 | @Override
46 | public SearchViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
47 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_data, parent, false);
48 | return new SearchViewHolder(view);
49 | }
50 |
51 | @Override
52 | public void onBindViewHolder(SearchViewHolder holder, int position) {
53 | ModelSearchData item = modelSearchDataList.get(position);
54 |
55 | Glide.with(holder.itemView.getContext())
56 | .load(item.getAvatarUrl())
57 | .into(holder.imageUser);
58 |
59 | holder.tvUsername.setText(item.getLogin());
60 | holder.tvUrl.setText(item.getHtmlUrl());
61 | holder.cvListUser.setOnClickListener(view -> {
62 | Intent intent = new Intent(context, DetailActivity.class);
63 | intent.putExtra(DetailActivity.DETAIL_USER, modelSearchDataList.get(position));
64 | context.startActivity(intent);
65 | });
66 |
67 | }
68 |
69 | @Override
70 | public int getItemCount() {
71 | return modelSearchDataList.size();
72 | }
73 |
74 | public static class SearchViewHolder extends RecyclerView.ViewHolder {
75 |
76 | CardView cvListUser;
77 | TextView tvUsername, tvUrl;
78 | ImageView imageUser;
79 |
80 | public SearchViewHolder(View itemView) {
81 | super(itemView);
82 | cvListUser = itemView.findViewById(R.id.cvListUser);
83 | tvUsername = itemView.findViewById(R.id.tvUsername);
84 | tvUrl = itemView.findViewById(R.id.tvUrl);
85 | imageUser = itemView.findViewById(R.id.imageUser);
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/adapter/ViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.adapter;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.fragment.app.Fragment;
6 | import androidx.fragment.app.FragmentManager;
7 | import androidx.fragment.app.FragmentStatePagerAdapter;
8 |
9 | import com.azhar.githubusers.model.search.ModelSearchData;
10 | import com.azhar.githubusers.ui.fragment.FragmentFollowers;
11 | import com.azhar.githubusers.ui.fragment.FragmentFollowing;
12 |
13 | /**
14 | * Created by Azhar Rivaldi on 19-05-2021
15 | * Youtube Channel : https://bit.ly/2PJMowZ
16 | * Github : https://github.com/AzharRivaldi
17 | * Twitter : https://twitter.com/azharrvldi_
18 | * Instagram : https://www.instagram.com/azhardvls_
19 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
20 | */
21 |
22 | public class ViewPagerAdapter extends FragmentStatePagerAdapter {
23 |
24 | ModelSearchData modelSearchData;
25 |
26 | public ViewPagerAdapter(FragmentManager fragmentManager, ModelSearchData modelSearchData) {
27 | super(fragmentManager);
28 | this.modelSearchData = modelSearchData;
29 | }
30 |
31 | @Override
32 | public Fragment getItem(int position) {
33 | Bundle bundle = new Bundle();
34 | bundle.putParcelable("modelSearchData", modelSearchData);
35 | Fragment fragment = null;
36 | switch (position) {
37 | case 0:
38 | fragment = new FragmentFollowers();
39 | fragment.setArguments(bundle);
40 | break;
41 | case 1:
42 | fragment = new FragmentFollowing();
43 | fragment.setArguments(bundle);
44 | break;
45 | }
46 | return fragment;
47 | }
48 |
49 | @Override
50 | public int getCount() {
51 | return 2;
52 | }
53 |
54 | @Override
55 | public CharSequence getPageTitle(int position) {
56 | String title = "";
57 | switch (position) {
58 | case 0:
59 | title = "Followers";
60 | break;
61 | case 1:
62 | title = "Following";
63 | break;
64 | }
65 | return title;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/database/DatabaseContract.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.database;
2 |
3 | import android.database.Cursor;
4 | import android.net.Uri;
5 | import android.provider.BaseColumns;
6 |
7 | /**
8 | * Created by Azhar Rivaldi on 23-05-2021
9 | * Youtube Channel : https://bit.ly/2PJMowZ
10 | * Github : https://github.com/AzharRivaldi
11 | * Twitter : https://twitter.com/azharrvldi_
12 | * Instagram : https://www.instagram.com/azhardvls_
13 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
14 | */
15 |
16 | public class DatabaseContract {
17 |
18 | public static final String PACKAGE = "com.azhar.githubusers";
19 | public static final String SCHEME = "content";
20 |
21 | public static final class FavoriteColoumn implements BaseColumns {
22 | public static final String TABLE_NAME = "favorite";
23 | public static final String ID = "id";
24 | public static final String TITLE = "login";
25 | public static final String IMAGE = "avatar_url";
26 | public static final String URL = "html_url";
27 | public static final Uri FAVORITE_URI = new Uri.Builder().scheme(SCHEME).authority(PACKAGE).appendPath(TABLE_NAME).build();
28 | }
29 |
30 | public static String getFavorite(Cursor cursor, String column) {
31 | return cursor.getString(cursor.getColumnIndex(column));
32 | }
33 |
34 | public static int getIntFavorite(Cursor cursor, String column) {
35 | return cursor.getInt(cursor.getColumnIndex(column));
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/database/DatabaseHelper.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.database;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.TABLE_NAME;
8 |
9 | /**
10 | * Created by Azhar Rivaldi on 23-05-2021
11 | * Youtube Channel : https://bit.ly/2PJMowZ
12 | * Github : https://github.com/AzharRivaldi
13 | * Twitter : https://twitter.com/azharrvldi_
14 | * Instagram : https://www.instagram.com/azhardvls_
15 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
16 | */
17 |
18 | public class DatabaseHelper extends SQLiteOpenHelper {
19 |
20 | private static final String DATABASE_NAME = "favoritedb";
21 | private static final int DATABASE_VERSION = 1;
22 |
23 | private static final String CREATE_TABLE_FAVORITE = String.format(
24 | "CREATE TABLE %s" +
25 | " (%s INTEGER PRIMARY KEY," +
26 | " %s TEXT NOT NULL," +
27 | " %s TEXT NOT NULL," +
28 | " %s TEXT NOT NULL)",
29 | TABLE_NAME,
30 | DatabaseContract.FavoriteColoumn.ID,
31 | DatabaseContract.FavoriteColoumn.TITLE,
32 | DatabaseContract.FavoriteColoumn.IMAGE,
33 | DatabaseContract.FavoriteColoumn.URL
34 | );
35 |
36 | @Override
37 | public void onCreate(SQLiteDatabase db) {
38 | db.execSQL(CREATE_TABLE_FAVORITE);
39 | }
40 |
41 | @Override
42 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
43 | db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
44 | onCreate(db);
45 | }
46 |
47 | public DatabaseHelper(Context context) {
48 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/database/FavoriteHelper.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.database;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.SQLException;
7 | import android.database.sqlite.SQLiteDatabase;
8 | import android.database.sqlite.SQLiteOpenHelper;
9 |
10 | import com.azhar.githubusers.model.user.ModelUser;
11 |
12 | import java.util.ArrayList;
13 |
14 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.ID;
15 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.TABLE_NAME;
16 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.IMAGE;
17 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.TITLE;
18 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.URL;
19 |
20 | /**
21 | * Created by Azhar Rivaldi on 23-05-2021
22 | * Youtube Channel : https://bit.ly/2PJMowZ
23 | * Github : https://github.com/AzharRivaldi
24 | * Twitter : https://twitter.com/azharrvldi_
25 | * Instagram : https://www.instagram.com/azhardvls_
26 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
27 | */
28 |
29 | public class FavoriteHelper {
30 |
31 | private static final String DATABASE_TABLE = TABLE_NAME;
32 | private static DatabaseHelper favoriteDbHelper;
33 | private static FavoriteHelper favoriteHelper;
34 | private static SQLiteDatabase db;
35 |
36 | public FavoriteHelper(Context context) {
37 | favoriteDbHelper = new DatabaseHelper(context);
38 | }
39 |
40 | public static FavoriteHelper getFavoriteHelper(Context context) {
41 | if (favoriteHelper == null) {
42 | synchronized (SQLiteOpenHelper.class) {
43 | if (favoriteHelper == null) {
44 | favoriteHelper = new FavoriteHelper(context);
45 | }
46 | }
47 | }
48 | return favoriteHelper;
49 | }
50 |
51 | public void open() throws SQLException {
52 | db = favoriteDbHelper.getWritableDatabase();
53 | }
54 |
55 | public void close() {
56 | favoriteDbHelper.close();
57 | if (db.isOpen())
58 | db.close();
59 | }
60 |
61 | public ArrayList getAllFavorites() {
62 | ArrayList arrayList = new ArrayList<>();
63 | Cursor cursor = db.query(DATABASE_TABLE, null,
64 | null,
65 | null,
66 | null,
67 | null,
68 | ID + " ASC",
69 | null);
70 | cursor.moveToFirst();
71 | ModelUser modelUser;
72 | if (cursor.getCount() > 0) {
73 | do {
74 | modelUser = new ModelUser();
75 | modelUser.setId(cursor.getInt(cursor.getColumnIndexOrThrow(ID)));
76 | modelUser.setLogin(cursor.getString(cursor.getColumnIndexOrThrow(TITLE)));
77 | modelUser.setAvatarUrl(cursor.getString(cursor.getColumnIndexOrThrow(IMAGE)));
78 | modelUser.setHtmlUrl(cursor.getString(cursor.getColumnIndexOrThrow(URL)));
79 | arrayList.add(modelUser);
80 | cursor.moveToNext();
81 | } while (!cursor.isAfterLast());
82 | }
83 | cursor.close();
84 | return arrayList;
85 | }
86 |
87 | public long favoriteInsert(ModelUser userResponse) {
88 | ContentValues contentValues = new ContentValues();
89 | contentValues.put(ID, userResponse.getId());
90 | contentValues.put(TITLE, userResponse.getLogin());
91 | contentValues.put(IMAGE, userResponse.getAvatarUrl());
92 | contentValues.put(URL, userResponse.getHtmlUrl());
93 |
94 | return db.insert(DATABASE_TABLE, null, contentValues);
95 | }
96 |
97 | public int favoriteDelete(String title) {
98 | return db.delete(TABLE_NAME, TITLE + " = '" + title + "'", null);
99 | }
100 |
101 | public Cursor cursorFavoriteGet() {
102 | return db.query(DATABASE_TABLE, null, null,
103 | null, null, null, ID + " ASC");
104 | }
105 |
106 | public Cursor cursorFavoriteGetId(String id) {
107 | return db.query(DATABASE_TABLE, null
108 | , ID + " = ?"
109 | , new String[]{id}
110 | , null
111 | , null
112 | , null
113 | , null);
114 | }
115 |
116 | public int favoriteDeleteProvider(String id) {
117 | return db.delete(TABLE_NAME, ID + "=?", new String[]{id});
118 | }
119 |
120 | public int favoriteUpdateProvider(String id, ContentValues values) {
121 | return db.update(DATABASE_TABLE, values, ID + " =?", new String[]{id});
122 | }
123 |
124 | public long favoriteInsertProvider(ContentValues values) {
125 | return db.insert(DATABASE_TABLE, null, values);
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/model/follow/ModelFollow.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.model.follow;
2 |
3 | import android.os.Parcel;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | /**
8 | * Created by Azhar Rivaldi on 19-05-2021
9 | * Youtube Channel : https://bit.ly/2PJMowZ
10 | * Github : https://github.com/AzharRivaldi
11 | * Twitter : https://twitter.com/azharrvldi_
12 | * Instagram : https://www.instagram.com/azhardvls_
13 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
14 | */
15 |
16 | public class ModelFollow {
17 |
18 | @SerializedName("login")
19 | private String login;
20 |
21 | @SerializedName("avatar_url")
22 | private String avatarUrl;
23 |
24 | @SerializedName("html_url")
25 | private String htmlUrl;
26 |
27 | public String getLogin() {
28 | return login;
29 | }
30 |
31 | public void setLogin(String login) {
32 | this.login = login;
33 | }
34 |
35 | public String getAvatarUrl() {
36 | return avatarUrl;
37 | }
38 |
39 | public void setAvatarUrl(String avatarUrl) {
40 | this.avatarUrl = avatarUrl;
41 | }
42 |
43 | public String getHtmlUrl() {
44 | return htmlUrl;
45 | }
46 |
47 | @Override
48 | public int describeContents() {
49 | return 0;
50 | }
51 |
52 | @Override
53 | public void writeToParcel(Parcel parcel, int flags) {
54 | parcel.writeString(avatarUrl);
55 | parcel.writeString(login);
56 | parcel.writeString(htmlUrl);
57 | }
58 |
59 | protected ModelFollow(Parcel in) {
60 | avatarUrl = in.readString();
61 | login = in.readString();
62 | htmlUrl = in.readString();
63 | }
64 |
65 | public static final Creator CREATOR = new Creator() {
66 | @Override
67 | public ModelFollow createFromParcel(Parcel in) {
68 | return new ModelFollow(in);
69 | }
70 |
71 | @Override
72 | public ModelFollow[] newArray(int size) {
73 | return new ModelFollow[size];
74 | }
75 | };
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/model/search/ModelSearch.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.model.search;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | import java.util.List;
6 |
7 | /**
8 | * Created by Azhar Rivaldi on 18-05-2021
9 | * Youtube Channel : https://bit.ly/2PJMowZ
10 | * Github : https://github.com/AzharRivaldi
11 | * Twitter : https://twitter.com/azharrvldi_
12 | * Instagram : https://www.instagram.com/azhardvls_
13 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
14 | */
15 |
16 | public class ModelSearch {
17 |
18 | @SerializedName("items")
19 | private List modelSearchData;
20 |
21 | public List getModelSearchData() {
22 | return modelSearchData;
23 | }
24 |
25 | public void setModelSearchData(List modelSearchData) {
26 | this.modelSearchData = modelSearchData;
27 | }
28 |
29 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/model/search/ModelSearchData.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.model.search;
2 |
3 | import android.os.Parcel;
4 |
5 | import com.google.gson.annotations.SerializedName;
6 |
7 | /**
8 | * Created by Azhar Rivaldi on 19-05-2021
9 | * Youtube Channel : https://bit.ly/2PJMowZ
10 | * Github : https://github.com/AzharRivaldi
11 | * Twitter : https://twitter.com/azharrvldi_
12 | * Instagram : https://www.instagram.com/azhardvls_
13 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
14 | */
15 |
16 | public class ModelSearchData {
17 |
18 | @SerializedName("login")
19 | private String login;
20 |
21 | @SerializedName("url")
22 | private String url;
23 |
24 | @SerializedName("avatar_url")
25 | private String avatarUrl;
26 |
27 | @SerializedName("html_url")
28 | private String htmlUrl;
29 |
30 | public void setLogin(String login) {
31 | this.login = login;
32 | }
33 |
34 | public String getLogin() {
35 | return login;
36 | }
37 |
38 | public void setAvatarUrl(String avatarUrl) {
39 | this.avatarUrl = avatarUrl;
40 | }
41 |
42 | public String getAvatarUrl() {
43 | return avatarUrl;
44 | }
45 |
46 | public void setHtmlUrl(String htmlUrl) {
47 | this.htmlUrl = htmlUrl;
48 | }
49 |
50 | public String getHtmlUrl() {
51 | return htmlUrl;
52 | }
53 |
54 | public String getUrl() {
55 | return url;
56 | }
57 |
58 | public void setUrl(String url) {
59 | this.url = url;
60 | }
61 |
62 | @Override
63 | public int describeContents() {
64 | return 0;
65 | }
66 |
67 | public ModelSearchData() {
68 | }
69 |
70 | protected ModelSearchData(Parcel in) {
71 | this.avatarUrl = in.readString();
72 | this.login = in.readString();
73 | this.url = in.readString();
74 | }
75 |
76 | @Override
77 | public void writeToParcel(Parcel parcel, int flags) {
78 | parcel.writeString(this.avatarUrl);
79 | parcel.writeString(this.login);
80 | parcel.writeString(this.url);
81 | }
82 |
83 | public static final Creator CREATOR = new Creator() {
84 | @Override
85 | public ModelSearchData createFromParcel(Parcel in) {
86 | return new ModelSearchData(in);
87 | }
88 |
89 | @Override
90 | public ModelSearchData[] newArray(int size) {
91 | return new ModelSearchData[size];
92 | }
93 | };
94 |
95 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/model/user/ModelUser.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.model.user;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 |
5 | public class ModelUser {
6 |
7 | @SerializedName("id")
8 | private int id;
9 |
10 | @SerializedName("login")
11 | private String login;
12 |
13 | @SerializedName("avatar_url")
14 | private String avatarUrl;
15 |
16 | @SerializedName("html_url")
17 | private String htmlUrl;
18 |
19 | @SerializedName("name")
20 | private String name;
21 |
22 | @SerializedName("blog")
23 | private String blog;
24 |
25 | @SerializedName("location")
26 | private String location;
27 |
28 | @SerializedName("email")
29 | private String email;
30 |
31 | @SerializedName("bio")
32 | private String bio;
33 |
34 | @SerializedName("twitter_username")
35 | private String twitterUsername;
36 |
37 | @SerializedName("public_repos")
38 | private String publicRepos;
39 |
40 | @SerializedName("followers")
41 | private String followers;
42 |
43 | @SerializedName("following")
44 | private String following;
45 |
46 | public ModelUser() {
47 |
48 | }
49 |
50 | public int getId() {
51 | return id;
52 | }
53 |
54 | public void setId(int id) {
55 | this.id = id;
56 | }
57 |
58 | public String getLogin() {
59 | return login;
60 | }
61 |
62 | public void setLogin(String login) {
63 | this.login = login;
64 | }
65 |
66 | public String getAvatarUrl() {
67 | return avatarUrl;
68 | }
69 |
70 | public void setAvatarUrl(String avatarUrl) {
71 | this.avatarUrl = avatarUrl;
72 | }
73 |
74 | public String getHtmlUrl() {
75 | return htmlUrl;
76 | }
77 |
78 | public void setHtmlUrl(String htmlUrl) {
79 | this.htmlUrl = htmlUrl;
80 | }
81 |
82 | public String getName() {
83 | return name;
84 | }
85 |
86 | public void setName(String name) {
87 | this.name = name;
88 | }
89 |
90 | public String getBlog() {
91 | return blog;
92 | }
93 |
94 | public void setBlog(String blog) {
95 | this.blog = blog;
96 | }
97 |
98 | public String getLocation() {
99 | return location;
100 | }
101 |
102 | public void setLocation(String location) {
103 | this.location = location;
104 | }
105 |
106 | public String getEmail() {
107 | return email;
108 | }
109 |
110 | public void setEmail(String email) {
111 | this.email = email;
112 | }
113 |
114 | public String getBio() {
115 | return bio;
116 | }
117 |
118 | public void setBio(String bio) {
119 | this.bio = bio;
120 | }
121 |
122 | public String getTwitterUsername() {
123 | return twitterUsername;
124 | }
125 |
126 | public void setTwitterUsername(String twitterUsername) {
127 | this.twitterUsername = twitterUsername;
128 | }
129 |
130 | public String getPublicRepos() {
131 | return publicRepos;
132 | }
133 |
134 | public void setPublicRepos(String publicRepos) {
135 | this.publicRepos = publicRepos;
136 | }
137 |
138 | public String getFollowers() {
139 | return followers;
140 | }
141 |
142 | public void setFollowers(String followers) {
143 | this.followers = followers;
144 | }
145 |
146 | public String getFollowing() {
147 | return following;
148 | }
149 |
150 | public void setFollowing(String following) {
151 | this.following = following;
152 | }
153 |
154 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/networking/ApiClient.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.networking;
2 |
3 | import retrofit2.Retrofit;
4 | import retrofit2.converter.gson.GsonConverterFactory;
5 |
6 | /**
7 | * Created by Azhar Rivaldi on 18-05-2021
8 | * Youtube Channel : https://bit.ly/2PJMowZ
9 | * Github : https://github.com/AzharRivaldi
10 | * Twitter : https://twitter.com/azharrvldi_
11 | * Instagram : https://www.instagram.com/azhardvls_
12 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
13 | */
14 |
15 | public class ApiClient {
16 |
17 | private static Retrofit retrofit;
18 | private static final String BASE_URL = "https://api.github.com";
19 |
20 | public static Retrofit getClient() {
21 | if (retrofit == null) {
22 | retrofit = new Retrofit.Builder()
23 | .baseUrl(BASE_URL)
24 | .addConverterFactory(GsonConverterFactory.create())
25 | .build();
26 | }
27 | return retrofit;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/networking/ApiInterface.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.networking;
2 |
3 | import com.azhar.githubusers.model.follow.ModelFollow;
4 | import com.azhar.githubusers.model.search.ModelSearch;
5 | import com.azhar.githubusers.model.user.ModelUser;
6 |
7 | import java.util.List;
8 |
9 | import retrofit2.Call;
10 | import retrofit2.http.GET;
11 | import retrofit2.http.Header;
12 | import retrofit2.http.Path;
13 | import retrofit2.http.Query;
14 |
15 | /**
16 | * Created by Azhar Rivaldi on 18-05-2021
17 | * Youtube Channel : https://bit.ly/2PJMowZ
18 | * Github : https://github.com/AzharRivaldi
19 | * Twitter : https://twitter.com/azharrvldi_
20 | * Instagram : https://www.instagram.com/azhardvls_
21 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
22 | */
23 |
24 | public interface ApiInterface {
25 |
26 | @GET("users/{username}")
27 | Call detailUser(@Path("username") String username);
28 |
29 | @GET("/search/users")
30 | Call searchUser(@Header("Authorization") String authorization,
31 | @Query("q") String username);
32 |
33 | @GET("users/{username}/followers")
34 | Call> followersUser(@Header("Authorization") String authorization,
35 | @Path("username") String username);
36 |
37 | @GET("users/{username}/following")
38 | Call> followingUser(@Header("Authorization") String authorization,
39 | @Path("username") String username);
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/ui/activities/DetailActivity.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.ui.activities;
2 |
3 | import android.database.Cursor;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.os.Bundle;
6 | import android.view.MenuItem;
7 | import android.widget.ImageView;
8 | import android.widget.TextView;
9 | import android.widget.Toast;
10 |
11 | import androidx.appcompat.app.AppCompatActivity;
12 | import androidx.appcompat.widget.Toolbar;
13 | import androidx.lifecycle.ViewModelProvider;
14 | import androidx.viewpager.widget.ViewPager;
15 |
16 | import com.azhar.githubusers.R;
17 | import com.azhar.githubusers.adapter.ViewPagerAdapter;
18 | import com.azhar.githubusers.database.DatabaseContract;
19 | import com.azhar.githubusers.database.DatabaseHelper;
20 | import com.azhar.githubusers.database.FavoriteHelper;
21 | import com.azhar.githubusers.model.search.ModelSearchData;
22 | import com.azhar.githubusers.model.user.ModelUser;
23 | import com.azhar.githubusers.viewmodel.UserViewModel;
24 | import com.bumptech.glide.Glide;
25 | import com.github.ivbaranov.mfb.MaterialFavoriteButton;
26 | import com.google.android.material.appbar.CollapsingToolbarLayout;
27 | import com.google.android.material.tabs.TabLayout;
28 |
29 | import java.util.ArrayList;
30 |
31 | import static com.azhar.githubusers.database.DatabaseContract.FavoriteColoumn.TABLE_NAME;
32 |
33 | public class DetailActivity extends AppCompatActivity {
34 |
35 | public static final String DETAIL_USER = "DETAIL_USER";
36 | private FavoriteHelper favoriteHelper;
37 | ArrayList modelUserArrayList = new ArrayList<>();
38 | UserViewModel userViewModel;
39 | ModelSearchData modelSearchData;
40 | String strUsername;
41 | ImageView imageUser;
42 | TextView tvUsername, tvBio, tvFollowers, tvFollowing, tvRepository;
43 | TabLayout tabsLayout;
44 | Toolbar toolbar;
45 | ViewPager viewPager;
46 | MaterialFavoriteButton imageFavorite;
47 | CollapsingToolbarLayout collapsingToolbarLayout;
48 |
49 | @Override
50 | protected void onCreate(Bundle savedInstanceState) {
51 | super.onCreate(savedInstanceState);
52 | setContentView(R.layout.activity_detail);
53 |
54 | toolbar = findViewById(R.id.toolbar);
55 | imageUser = findViewById(R.id.imageUser);
56 | tvUsername = findViewById(R.id.tvUsername);
57 | tvBio = findViewById(R.id.tvBio);
58 | tvFollowers = findViewById(R.id.tvFollowers);
59 | tvFollowing = findViewById(R.id.tvFollowing);
60 | tvRepository = findViewById(R.id.tvRepository);
61 | tabsLayout = findViewById(R.id.tabsLayout);
62 | viewPager = findViewById(R.id.viewPager);
63 | imageFavorite = findViewById(R.id.imageFavorite);
64 | collapsingToolbarLayout = findViewById(R.id.collapsingToolbarLayout);
65 |
66 | toolbar.setTitle(null);
67 | setSupportActionBar(toolbar);
68 | assert getSupportActionBar() != null;
69 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
70 | getSupportActionBar().setDisplayShowTitleEnabled(false);
71 |
72 | favoriteHelper = FavoriteHelper.getFavoriteHelper(getApplicationContext());
73 | favoriteHelper.open();
74 |
75 | modelSearchData = getIntent().getBundle(DETAIL_USER);
76 | if (modelSearchData != null) {
77 | strUsername = modelSearchData.getLogin();
78 | }
79 |
80 | viewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), modelSearchData));
81 | viewPager.setOffscreenPageLimit(2);
82 | tabsLayout.setupWithViewPager(viewPager);
83 |
84 | //method set viewmodel
85 | userViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(UserViewModel.class);
86 | userViewModel.setUserDetail(strUsername);
87 | userViewModel.getUserList().observe(this, modelUser -> {
88 | Glide.with(getApplicationContext())
89 | .load(modelUser.getAvatarUrl())
90 | .into(imageUser);
91 |
92 | collapsingToolbarLayout.setTitle(modelUser.getName());
93 | tvUsername.setText(modelUser.getLogin() + " \u2022 " + modelUser.getLocation());
94 | tvBio.setText(modelUser.getBio());
95 | tvFollowers.setText(modelUser.getFollowers());
96 | tvFollowing.setText(modelUser.getFollowing());
97 | tvRepository.setText(modelUser.getPublicRepos());
98 |
99 | //method set favorite or unfavorite
100 | if (FavoriteExist(strUsername)) {
101 | imageFavorite.setFavorite(true);
102 | imageFavorite.setOnFavoriteChangeListener(
103 | (buttonView, favorite) -> {
104 | if (favorite) {
105 | modelUserArrayList = favoriteHelper.getAllFavorites();
106 | favoriteHelper.favoriteInsert(modelUser);
107 | Toast.makeText(getApplicationContext(), "Ditambahkan Favorite", Toast.LENGTH_SHORT).show();
108 | } else {
109 | modelUserArrayList = favoriteHelper.getAllFavorites();
110 | favoriteHelper.favoriteDelete(strUsername);
111 | Toast.makeText(getApplicationContext(), "Dihapus Favorite", Toast.LENGTH_SHORT).show();
112 | }
113 | });
114 | } else {
115 | imageFavorite.setOnFavoriteChangeListener(
116 | (buttonView, favorite) -> {
117 | if (favorite) {
118 | modelUserArrayList = favoriteHelper.getAllFavorites();
119 | favoriteHelper.favoriteInsert(modelUser);
120 | Toast.makeText(getApplicationContext(), "Ditambahkan Favorite", Toast.LENGTH_SHORT).show();
121 | } else {
122 | modelUserArrayList = favoriteHelper.getAllFavorites();
123 | favoriteHelper.favoriteDelete(strUsername);
124 | Toast.makeText(getApplicationContext(), "Dihapus Favorite", Toast.LENGTH_SHORT).show();
125 | }
126 | });
127 | }
128 | });
129 | }
130 |
131 | //method check data if exist
132 | public boolean FavoriteExist(String item) {
133 | String pilih = DatabaseContract.FavoriteColoumn.TITLE + " =?";
134 | String[] pilihArg = {item};
135 | String limit = "1";
136 | favoriteHelper = new FavoriteHelper(this);
137 | favoriteHelper.open();
138 | DatabaseHelper dataBaseHelper = new DatabaseHelper(DetailActivity.this);
139 | SQLiteDatabase database = dataBaseHelper.getWritableDatabase();
140 | Cursor cursor = database.query(TABLE_NAME, null, pilih, pilihArg, null, null, null, limit);
141 | boolean exists;
142 | exists = (cursor.getCount() > 0);
143 | cursor.close();
144 |
145 | return exists;
146 | }
147 |
148 | @Override
149 | public boolean onOptionsItemSelected(MenuItem item) {
150 | if (item.getItemId() == android.R.id.home) {
151 | finish();
152 | return true;
153 | }
154 | return super.onOptionsItemSelected(item);
155 | }
156 |
157 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/ui/activities/FavoriteActivity.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.ui.activities;
2 |
3 | import androidx.appcompat.app.AppCompatActivity;
4 | import androidx.appcompat.widget.Toolbar;
5 | import androidx.constraintlayout.widget.ConstraintLayout;
6 | import androidx.recyclerview.widget.LinearLayoutManager;
7 | import androidx.recyclerview.widget.RecyclerView;
8 |
9 | import android.os.Bundle;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 |
13 | import com.azhar.githubusers.R;
14 | import com.azhar.githubusers.adapter.FavoriteAdapter;
15 | import com.azhar.githubusers.database.FavoriteHelper;
16 | import com.azhar.githubusers.model.user.ModelUser;
17 |
18 | import java.util.ArrayList;
19 |
20 | public class FavoriteActivity extends AppCompatActivity {
21 |
22 | ArrayList modelUserArrayList = new ArrayList<>();
23 | private FavoriteHelper favoriteHelper;
24 | private FavoriteAdapter favoriteAdapter;
25 | Toolbar toolbar;
26 | ConstraintLayout layoutEmpty;
27 | RecyclerView rvListFavoriteUser;
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_favorite);
33 |
34 | toolbar = findViewById(R.id.toolbar);
35 | layoutEmpty = findViewById(R.id.layoutEmpty);
36 | rvListFavoriteUser = findViewById(R.id.rvListFavoriteUser);
37 |
38 | favoriteHelper = FavoriteHelper.getFavoriteHelper(FavoriteActivity.this);
39 | favoriteHelper.open();
40 |
41 | toolbar.setTitle(null);
42 | setSupportActionBar(toolbar);
43 | assert getSupportActionBar() != null;
44 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
45 |
46 | favoriteAdapter = new FavoriteAdapter();
47 | rvListFavoriteUser.setLayoutManager(new LinearLayoutManager(this));
48 | rvListFavoriteUser.setAdapter(favoriteAdapter);
49 | rvListFavoriteUser.setHasFixedSize(true);
50 |
51 | getDataFavorite();
52 | }
53 |
54 | //method show data
55 | private void getDataFavorite() {
56 | if (modelUserArrayList.size() == 0) {
57 | layoutEmpty.setVisibility(View.VISIBLE);
58 | rvListFavoriteUser.setVisibility(View.GONE);
59 | } else {
60 | layoutEmpty.setVisibility(View.GONE);
61 | rvListFavoriteUser.setVisibility(View.VISIBLE);
62 | favoriteAdapter.setFavoriteUserList(modelUserArrayList);
63 | }
64 | }
65 |
66 | @Override
67 | public void onResume(){
68 | super.onResume();
69 | getDataFavorite();
70 | }
71 |
72 | @Override
73 | public boolean onOptionsItemSelected(MenuItem item) {
74 | if (item.getItemId() == android.R.id.home) {
75 | finish();
76 | return true;
77 | }
78 | return super.onOptionsItemSelected(item);
79 | }
80 |
81 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/ui/activities/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.ui.activities;
2 |
3 | import android.app.ProgressDialog;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.view.inputmethod.EditorInfo;
9 | import android.view.inputmethod.InputMethodManager;
10 | import android.widget.EditText;
11 | import android.widget.ImageView;
12 | import android.widget.Toast;
13 |
14 | import androidx.appcompat.app.AppCompatActivity;
15 | import androidx.constraintlayout.widget.ConstraintLayout;
16 | import androidx.lifecycle.ViewModelProvider;
17 | import androidx.recyclerview.widget.LinearLayoutManager;
18 | import androidx.recyclerview.widget.RecyclerView;
19 |
20 | import com.azhar.githubusers.R;
21 | import com.azhar.githubusers.adapter.SearchAdapter;
22 | import com.azhar.githubusers.viewmodel.UserViewModel;
23 |
24 | public class MainActivity extends AppCompatActivity {
25 |
26 | SearchAdapter searchAdapter;
27 | UserViewModel searchViewModel;
28 | ProgressDialog progressDialog;
29 | RecyclerView rvListUser;
30 | EditText searchUser;
31 | ImageView imageClear, imageFavorite;
32 | ConstraintLayout layoutEmpty;
33 |
34 | @Override
35 | protected void onCreate(Bundle savedInstanceState) {
36 | super.onCreate(savedInstanceState);
37 | setContentView(R.layout.activity_main);
38 |
39 | searchUser = findViewById(R.id.searchUser);
40 | imageClear = findViewById(R.id.imageClear);
41 | imageFavorite = findViewById(R.id.imageFavorite);
42 | rvListUser = findViewById(R.id.rvListUser);
43 | layoutEmpty = findViewById(R.id.layoutEmpty);
44 |
45 | progressDialog = new ProgressDialog(this);
46 | progressDialog.setTitle("Mohon Tunggu...");
47 | progressDialog.setCancelable(false);
48 | progressDialog.setMessage("Sedang menampilkan data");
49 |
50 | imageClear.setOnClickListener(view -> {
51 | searchUser.getText().clear();
52 | imageClear.setVisibility(View.GONE);
53 | layoutEmpty.setVisibility(View.VISIBLE);
54 | rvListUser.setVisibility(View.GONE);
55 | });
56 |
57 | imageFavorite.setOnClickListener(view -> {
58 | Intent intent = new Intent(MainActivity.this, FavoriteActivity.class);
59 | startActivity(intent);
60 | });
61 |
62 | //method action search
63 | searchUser.setOnEditorActionListener((v, actionId, event) -> {
64 | String strUsername = searchUser.getText().toString();
65 | if (strUsername.isEmpty()) {
66 | Toast.makeText(MainActivity.this, "Form tidak boleh kosong!", Toast.LENGTH_SHORT).show();
67 | } else {
68 | if (actionId == EditorInfo.IME_ACTION_SEARCH) {
69 | progressDialog.show();
70 | searchViewModel.setSearchUser(strUsername);
71 | InputMethodManager inputMethodManager = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
72 | inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
73 | imageClear.setVisibility(View.VISIBLE);
74 | layoutEmpty.setVisibility(View.GONE);
75 | return true;
76 | }
77 | }
78 | return false;
79 | });
80 |
81 | searchAdapter = new SearchAdapter(this);
82 | rvListUser.setLayoutManager(new LinearLayoutManager(this));
83 | rvListUser.setAdapter(searchAdapter);
84 | rvListUser.setHasFixedSize(true);
85 |
86 | //method set viewmodel
87 | searchViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(UserViewModel.class);
88 | searchViewModel.getResultList().observe(this, modelSearchData -> {
89 | progressDialog.dismiss();
90 | if (modelSearchData.size() != 0) {
91 | searchAdapter.setSearchUserList(modelSearchData);
92 | } else {
93 | Toast.makeText(MainActivity.this, "Pengguna Tidak Ditemukan!", Toast.LENGTH_SHORT).show();
94 | }
95 | });
96 | }
97 |
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/ui/fragment/FragmentFollowers.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.ui.fragment;
2 |
3 | import android.app.ProgressDialog;
4 | import android.os.Bundle;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.Toast;
9 |
10 | import androidx.constraintlayout.widget.ConstraintLayout;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.ViewModelProvider;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.azhar.githubusers.R;
17 | import com.azhar.githubusers.adapter.FollowAdapter;
18 | import com.azhar.githubusers.model.search.ModelSearchData;
19 | import com.azhar.githubusers.viewmodel.UserViewModel;
20 |
21 | public class FragmentFollowers extends Fragment {
22 |
23 | ModelSearchData modelSearchData;
24 | UserViewModel followersViewModel;
25 | FollowAdapter followAdapter;
26 | RecyclerView rvListFollowers;
27 | ConstraintLayout layoutEmpty;
28 | ProgressDialog progressDialog;
29 | String strUsername;
30 |
31 | public FragmentFollowers() {
32 | // Required empty public constructor
33 | }
34 |
35 | @Override
36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
37 | View view = inflater.inflate(R.layout.fragment_followers, container, false);
38 |
39 | progressDialog = new ProgressDialog(getContext());
40 | progressDialog.setTitle("Mohon Tunggu...");
41 | progressDialog.setCancelable(false);
42 | progressDialog.setMessage("Sedang menampilkan data");
43 |
44 | rvListFollowers = view.findViewById(R.id.rvListFollowers);
45 | layoutEmpty = view.findViewById(R.id.layoutEmpty);
46 |
47 | modelSearchData = this.getArguments().getBundle("modelSearchData");
48 | if (modelSearchData != null) {
49 | strUsername = modelSearchData.getLogin();
50 | }
51 |
52 | followAdapter = new FollowAdapter(getContext());
53 | rvListFollowers.setLayoutManager(new LinearLayoutManager(getContext()));
54 | rvListFollowers.setAdapter(followAdapter);
55 | rvListFollowers.setHasFixedSize(true);
56 |
57 | //method set viewmodel
58 | followersViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(UserViewModel.class);
59 | followersViewModel.setFollowersUser(strUsername);
60 | progressDialog.show();
61 | followersViewModel.getFollowersUser().observe(getViewLifecycleOwner(), modelFollowers -> {
62 | if (modelFollowers.size() != 0) {
63 | layoutEmpty.setVisibility(View.GONE);
64 | followAdapter.setFollowList(modelFollowers);
65 | } else {
66 | layoutEmpty.setVisibility(View.VISIBLE);
67 | Toast.makeText(getContext(), "Followers Tidak Ditemukan!", Toast.LENGTH_SHORT).show();
68 | }
69 | progressDialog.dismiss();
70 | });
71 |
72 | return view;
73 | }
74 |
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/ui/fragment/FragmentFollowing.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.ui.fragment;
2 |
3 | import android.app.ProgressDialog;
4 | import android.os.Bundle;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.Toast;
9 |
10 | import androidx.constraintlayout.widget.ConstraintLayout;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.ViewModelProvider;
13 | import androidx.recyclerview.widget.LinearLayoutManager;
14 | import androidx.recyclerview.widget.RecyclerView;
15 |
16 | import com.azhar.githubusers.R;
17 | import com.azhar.githubusers.adapter.FollowAdapter;
18 | import com.azhar.githubusers.model.search.ModelSearchData;
19 | import com.azhar.githubusers.viewmodel.UserViewModel;
20 |
21 | public class FragmentFollowing extends Fragment {
22 |
23 | ModelSearchData modelSearchData;
24 | UserViewModel followingViewModel;
25 | FollowAdapter followingAdapter;
26 | RecyclerView rvListFollowing;
27 | ConstraintLayout layoutEmpty;
28 | ProgressDialog progressDialog;
29 | String strUsername;
30 |
31 | public FragmentFollowing() {
32 | // Required empty public constructor
33 | }
34 |
35 | @Override
36 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
37 | View view = inflater.inflate(R.layout.fragment_following, container, false);
38 |
39 | progressDialog = new ProgressDialog(getContext());
40 | progressDialog.setTitle("Mohon Tunggu...");
41 | progressDialog.setCancelable(false);
42 | progressDialog.setMessage("Sedang menampilkan data");
43 |
44 | rvListFollowing = view.findViewById(R.id.rvListFollowing);
45 | layoutEmpty = view.findViewById(R.id.layoutEmpty);
46 |
47 | modelSearchData = this.getArguments().getBundle("modelSearchData");
48 | if (modelSearchData != null) {
49 | strUsername = modelSearchData.getLogin();
50 | }
51 |
52 | followingAdapter = new FollowAdapter(getContext());
53 | rvListFollowing.setLayoutManager(new LinearLayoutManager(getContext()));
54 | rvListFollowing.setAdapter(followingAdapter);
55 | rvListFollowing.setHasFixedSize(true);
56 |
57 | //method set viewmodel
58 | followingViewModel = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory()).get(UserViewModel.class);
59 | followingViewModel.setFollowingUser(strUsername);
60 | progressDialog.show();
61 | followingViewModel.getFollowingUser().observe(getViewLifecycleOwner(), modelFollowing -> {
62 | if (modelFollowing.size() != 0) {
63 | layoutEmpty.setVisibility(View.GONE);
64 | followingAdapter.setFollowList(modelFollowing);
65 | } else {
66 | layoutEmpty.setVisibility(View.VISIBLE);
67 | Toast.makeText(getContext(), "Following Tidak Ditemukan!", Toast.LENGTH_SHORT).show();
68 | }
69 | progressDialog.dismiss();
70 | });
71 |
72 | return view;
73 | }
74 |
75 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/azhar/githubusers/viewmodel/UserViewModel.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers.viewmodel;
2 |
3 | import android.util.Log;
4 |
5 | import androidx.lifecycle.LiveData;
6 | import androidx.lifecycle.MutableLiveData;
7 | import androidx.lifecycle.ViewModel;
8 |
9 | import com.azhar.githubusers.model.follow.ModelFollow;
10 | import com.azhar.githubusers.model.search.ModelSearch;
11 | import com.azhar.githubusers.model.search.ModelSearchData;
12 | import com.azhar.githubusers.model.user.ModelUser;
13 | import com.azhar.githubusers.networking.ApiClient;
14 | import com.azhar.githubusers.networking.ApiInterface;
15 |
16 | import java.util.ArrayList;
17 |
18 | import retrofit2.Call;
19 | import retrofit2.Callback;
20 | import retrofit2.Response;
21 |
22 | /**
23 | * Created by Azhar Rivaldi on 19-05-2021
24 | * Youtube Channel : https://bit.ly/2PJMowZ
25 | * Github : https://github.com/AzharRivaldi
26 | * Twitter : https://twitter.com/azharrvldi_
27 | * Instagram : https://www.instagram.com/azhardvls_
28 | * Linkedin : https://www.linkedin.com/in/azhar-rivaldi
29 | */
30 |
31 | public class UserViewModel extends ViewModel {
32 |
33 | private MutableLiveData> modelSearchMutableLiveData = new MutableLiveData<>();
34 | private MutableLiveData> modelFollowersMutableLiveData = new MutableLiveData<>();
35 | private MutableLiveData> modelFollowingMutableLiveData = new MutableLiveData<>();
36 | private MutableLiveData modelUserMutableLiveData = new MutableLiveData<>();
37 | public static String strApiKey = "mau API KEY? Tonton video tutorialnya ya^^";
38 |
39 | //method search user
40 | public void setSearchUser(String query) {
41 | ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
42 |
43 | Call call = apiService.searchUser(strApiKey, query);
44 | call.enqueue(new Callback() {
45 | @Override
46 | public void onResponse(Call call, Response response) {
47 | if (!response.isSuccessful()) {
48 | Log.e("response", response.toString());
49 | } else if (response.body() != null) {
50 | ArrayList items = new ArrayList<>(response.body().getModelSearchData());
51 | modelSearchMutableLiveData.setValue(items);
52 | }
53 | }
54 |
55 | @Override
56 | public void onFailure(Call call, Throwable t) {
57 | Log.e("failure", t.toString());
58 | }
59 | });
60 | }
61 |
62 | //method view detail user
63 | public void setUserDetail(String strUsername) {
64 | ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
65 | Call call = apiService.detailUser(strUsername);
66 | call.enqueue(new Callback() {
67 |
68 | @Override
69 | public void onResponse(Call call, Response response) {
70 | if (!response.isSuccessful()) {
71 | Log.e("response", response.toString());
72 | } else if (response.body() != null) {
73 | modelUserMutableLiveData.setValue(response.body());
74 | }
75 | }
76 |
77 | @Override
78 | public void onFailure(Call call, Throwable t) {
79 | Log.e("failure", t.toString());
80 | }
81 | });
82 | }
83 |
84 | //method get followers
85 | public void setFollowersUser(String strUsername) {
86 | ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
87 |
88 | Call> call = apiService.followersUser(strApiKey, strUsername);
89 | call.enqueue(new Callback>() {
90 | @Override
91 | public void onResponse(Call> call, Response> response) {
92 | if (!response.isSuccessful()) {
93 | Log.e("response", response.toString());
94 | } else if (response.body() != null) {
95 | modelFollowersMutableLiveData.setValue(response.body());
96 | }
97 | }
98 |
99 | @Override
100 | public void onFailure(Call> call, Throwable t) {
101 | Log.e("failure", t.toString());
102 | }
103 | });
104 | }
105 |
106 | //method get following
107 | public void setFollowingUser(String strUsername) {
108 | ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
109 |
110 | Call> call = apiService.followingUser(strApiKey, strUsername);
111 | call.enqueue(new Callback>() {
112 | @Override
113 | public void onResponse(Call> call, Response> response) {
114 | if (!response.isSuccessful()) {
115 | Log.e("response", response.toString());
116 | } else if (response.body() != null) {
117 | modelFollowingMutableLiveData.setValue(response.body());
118 | }
119 | }
120 |
121 | @Override
122 | public void onFailure(Call> call, Throwable t) {
123 | Log.e("failure", t.toString());
124 | }
125 | });
126 | }
127 |
128 | public LiveData> getResultList() {
129 | return modelSearchMutableLiveData;
130 | }
131 |
132 | public LiveData getUserList() {
133 | return modelUserMutableLiveData;
134 | }
135 |
136 | public LiveData> getFollowersUser() {
137 | return modelFollowersMutableLiveData;
138 | }
139 |
140 | public LiveData> getFollowingUser() {
141 | return modelFollowingMutableLiveData;
142 | }
143 |
144 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_search.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_right.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_clear.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_favorite.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_unfavorite.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_user.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_background_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/tab_layout_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
23 |
24 |
32 |
33 |
39 |
40 |
49 |
50 |
61 |
62 |
70 |
71 |
77 |
78 |
84 |
85 |
91 |
92 |
100 |
101 |
102 |
103 |
109 |
110 |
116 |
117 |
125 |
126 |
127 |
128 |
134 |
135 |
142 |
143 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
168 |
169 |
170 |
171 |
179 |
180 |
181 |
182 |
187 |
188 |
196 |
197 |
209 |
210 |
211 |
212 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_favorite.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
17 |
18 |
21 |
22 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
42 |
43 |
48 |
49 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
12 |
13 |
17 |
18 |
23 |
24 |
37 |
38 |
39 |
40 |
48 |
49 |
57 |
58 |
59 |
60 |
61 |
62 |
68 |
69 |
74 |
75 |
76 |
77 |
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_followers.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_following.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_empty.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/list_item_data.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
14 |
15 |
23 |
24 |
30 |
31 |
39 |
40 |
49 |
50 |
51 |
52 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/raw/lottie_empty.json:
--------------------------------------------------------------------------------
1 | {
2 | "v": "4.7.0",
3 | "fr": 25,
4 | "ip": 0,
5 | "op": 50,
6 | "w": 120,
7 | "h": 120,
8 | "nm": "Comp 1",
9 | "ddd": 0,
10 | "assets": [],
11 | "layers": [
12 | {
13 | "ddd": 0,
14 | "ind": 1,
15 | "ty": 4,
16 | "nm": "ruoi",
17 | "ks": {
18 | "o": {
19 | "a": 1,
20 | "k": [
21 | {
22 | "i": {
23 | "x": [
24 | 0.833
25 | ],
26 | "y": [
27 | 0.967
28 | ]
29 | },
30 | "o": {
31 | "x": [
32 | 0.167
33 | ],
34 | "y": [
35 | 0.033
36 | ]
37 | },
38 | "n": [
39 | "0p833_0p967_0p167_0p033"
40 | ],
41 | "t": 35,
42 | "s": [
43 | 100
44 | ],
45 | "e": [
46 | 0
47 | ]
48 | },
49 | {
50 | "t": 49
51 | }
52 | ]
53 | },
54 | "r": {
55 | "a": 0,
56 | "k": 0
57 | },
58 | "p": {
59 | "a": 1,
60 | "k": [
61 | {
62 | "i": {
63 | "x": 0.833,
64 | "y": 0.833
65 | },
66 | "o": {
67 | "x": 0,
68 | "y": 0
69 | },
70 | "n": "0p833_0p833_0_0",
71 | "t": 0,
72 | "s": [
73 | 57.361,
74 | 61.016,
75 | 0
76 | ],
77 | "e": [
78 | 57.699,
79 | 41.796,
80 | 0
81 | ],
82 | "to": [
83 | -4.67500305175781,
84 | -4.12800598144531,
85 | 0
86 | ],
87 | "ti": [
88 | -13.9099960327148,
89 | 5.27300262451172,
90 | 0
91 | ]
92 | },
93 | {
94 | "i": {
95 | "x": 0.833,
96 | "y": 0.833
97 | },
98 | "o": {
99 | "x": 0.167,
100 | "y": 0.167
101 | },
102 | "n": "0p833_0p833_0p167_0p167",
103 | "t": 10.219,
104 | "s": [
105 | 57.699,
106 | 41.796,
107 | 0
108 | ],
109 | "e": [
110 | 79.084,
111 | 33.982,
112 | 0
113 | ],
114 | "to": [
115 | 12.8159942626953,
116 | -4.85800170898438,
117 | 0
118 | ],
119 | "ti": [
120 | -4.54498291015625,
121 | 3.73400115966797,
122 | 0
123 | ]
124 | },
125 | {
126 | "i": {
127 | "x": 0.833,
128 | "y": 0.833
129 | },
130 | "o": {
131 | "x": 0.167,
132 | "y": 0.167
133 | },
134 | "n": "0p833_0p833_0p167_0p167",
135 | "t": 19.445,
136 | "s": [
137 | 79.084,
138 | 33.982,
139 | 0
140 | ],
141 | "e": [
142 | 59.691,
143 | 9.121,
144 | 0
145 | ],
146 | "to": [
147 | 6.61601257324219,
148 | -5.43799591064453,
149 | 0
150 | ],
151 | "ti": [
152 | 20.0290069580078,
153 | 1.20700073242188,
154 | 0
155 | ]
156 | },
157 | {
158 | "t": 35
159 | }
160 | ]
161 | },
162 | "a": {
163 | "a": 0,
164 | "k": [
165 | 60.531,
166 | 10.945,
167 | 0
168 | ]
169 | },
170 | "s": {
171 | "a": 0,
172 | "k": [
173 | 100,
174 | 100,
175 | 100
176 | ]
177 | }
178 | },
179 | "ao": 0,
180 | "shapes": [
181 | {
182 | "ty": "gr",
183 | "it": [
184 | {
185 | "ty": "gr",
186 | "it": [
187 | {
188 | "ind": 0,
189 | "ty": "sh",
190 | "ix": 1,
191 | "ks": {
192 | "a": 0,
193 | "k": {
194 | "i": [
195 | [
196 | -0.994,
197 | 0
198 | ],
199 | [
200 | 0,
201 | -0.994
202 | ],
203 | [
204 | 0.995,
205 | 0
206 | ],
207 | [
208 | 0,
209 | 0.994
210 | ]
211 | ],
212 | "o": [
213 | [
214 | 0.995,
215 | 0
216 | ],
217 | [
218 | 0,
219 | 0.994
220 | ],
221 | [
222 | -0.994,
223 | 0
224 | ],
225 | [
226 | 0,
227 | -0.994
228 | ]
229 | ],
230 | "v": [
231 | [
232 | -0.001,
233 | -1.801
234 | ],
235 | [
236 | 1.801,
237 | -0.001
238 | ],
239 | [
240 | -0.001,
241 | 1.801
242 | ],
243 | [
244 | -1.801,
245 | -0.001
246 | ]
247 | ],
248 | "c": true
249 | }
250 | },
251 | "nm": "Path 1",
252 | "mn": "ADBE Vector Shape - Group"
253 | },
254 | {
255 | "ty": "fl",
256 | "c": {
257 | "a": 0,
258 | "k": [
259 | 0.529,
260 | 0.529,
261 | 0.529,
262 | 1
263 | ]
264 | },
265 | "o": {
266 | "a": 0,
267 | "k": 100
268 | },
269 | "r": 1,
270 | "nm": "Fill 1",
271 | "mn": "ADBE Vector Graphic - Fill"
272 | },
273 | {
274 | "ty": "tr",
275 | "p": {
276 | "a": 0,
277 | "k": [
278 | 62.4,
279 | 13.144
280 | ],
281 | "ix": 2
282 | },
283 | "a": {
284 | "a": 0,
285 | "k": [
286 | 0,
287 | 0
288 | ],
289 | "ix": 1
290 | },
291 | "s": {
292 | "a": 0,
293 | "k": [
294 | 100,
295 | 100
296 | ],
297 | "ix": 3
298 | },
299 | "r": {
300 | "a": 0,
301 | "k": 0,
302 | "ix": 6
303 | },
304 | "o": {
305 | "a": 0,
306 | "k": 100,
307 | "ix": 7
308 | },
309 | "sk": {
310 | "a": 0,
311 | "k": 0,
312 | "ix": 4
313 | },
314 | "sa": {
315 | "a": 0,
316 | "k": 0,
317 | "ix": 5
318 | },
319 | "nm": "Transform"
320 | }
321 | ],
322 | "nm": "Group 1",
323 | "np": 2,
324 | "cix": 2,
325 | "ix": 1,
326 | "mn": "ADBE Vector Group"
327 | },
328 | {
329 | "ty": "gr",
330 | "it": [
331 | {
332 | "ind": 0,
333 | "ty": "sh",
334 | "ix": 1,
335 | "ks": {
336 | "a": 0,
337 | "k": {
338 | "i": [
339 | [
340 | -1.422,
341 | 0
342 | ],
343 | [
344 | 0,
345 | -1.422
346 | ],
347 | [
348 | 1.421,
349 | 0
350 | ],
351 | [
352 | 0,
353 | 1.422
354 | ]
355 | ],
356 | "o": [
357 | [
358 | 1.421,
359 | 0
360 | ],
361 | [
362 | 0,
363 | 1.422
364 | ],
365 | [
366 | -1.422,
367 | 0
368 | ],
369 | [
370 | 0,
371 | -1.422
372 | ]
373 | ],
374 | "v": [
375 | [
376 | 0.001,
377 | -2.574
378 | ],
379 | [
380 | 2.574,
381 | 0
382 | ],
383 | [
384 | 0.001,
385 | 2.574
386 | ],
387 | [
388 | -2.574,
389 | 0
390 | ]
391 | ],
392 | "c": true
393 | }
394 | },
395 | "nm": "Path 1",
396 | "mn": "ADBE Vector Shape - Group"
397 | },
398 | {
399 | "ty": "st",
400 | "c": {
401 | "a": 0,
402 | "k": [
403 | 0.529,
404 | 0.529,
405 | 0.529,
406 | 1
407 | ]
408 | },
409 | "o": {
410 | "a": 0,
411 | "k": 100
412 | },
413 | "w": {
414 | "a": 0,
415 | "k": 0.7
416 | },
417 | "lc": 1,
418 | "lj": 1,
419 | "ml": 10,
420 | "nm": "Stroke 1",
421 | "mn": "ADBE Vector Graphic - Stroke"
422 | },
423 | {
424 | "ty": "fl",
425 | "c": {
426 | "a": 0,
427 | "k": [
428 | 1,
429 | 1,
430 | 1,
431 | 1
432 | ]
433 | },
434 | "o": {
435 | "a": 0,
436 | "k": 100
437 | },
438 | "r": 1,
439 | "nm": "Fill 1",
440 | "mn": "ADBE Vector Graphic - Fill"
441 | },
442 | {
443 | "ty": "tr",
444 | "p": {
445 | "a": 0,
446 | "k": [
447 | 64.145,
448 | 9.606
449 | ],
450 | "ix": 2
451 | },
452 | "a": {
453 | "a": 0,
454 | "k": [
455 | 0,
456 | 0
457 | ],
458 | "ix": 1
459 | },
460 | "s": {
461 | "a": 0,
462 | "k": [
463 | 100,
464 | 100
465 | ],
466 | "ix": 3
467 | },
468 | "r": {
469 | "a": 0,
470 | "k": 0,
471 | "ix": 6
472 | },
473 | "o": {
474 | "a": 0,
475 | "k": 100,
476 | "ix": 7
477 | },
478 | "sk": {
479 | "a": 0,
480 | "k": 0,
481 | "ix": 4
482 | },
483 | "sa": {
484 | "a": 0,
485 | "k": 0,
486 | "ix": 5
487 | },
488 | "nm": "Transform"
489 | }
490 | ],
491 | "nm": "Group 2",
492 | "np": 3,
493 | "cix": 2,
494 | "ix": 2,
495 | "mn": "ADBE Vector Group"
496 | },
497 | {
498 | "ty": "gr",
499 | "it": [
500 | {
501 | "ind": 0,
502 | "ty": "sh",
503 | "ix": 1,
504 | "ks": {
505 | "a": 0,
506 | "k": {
507 | "i": [
508 | [
509 | -1.996,
510 | 0
511 | ],
512 | [
513 | 0,
514 | -1.996
515 | ],
516 | [
517 | 1.996,
518 | 0
519 | ],
520 | [
521 | 0,
522 | 1.996
523 | ]
524 | ],
525 | "o": [
526 | [
527 | 1.996,
528 | 0
529 | ],
530 | [
531 | 0,
532 | 1.996
533 | ],
534 | [
535 | -1.996,
536 | 0
537 | ],
538 | [
539 | 0,
540 | -1.996
541 | ]
542 | ],
543 | "v": [
544 | [
545 | 0,
546 | -3.614
547 | ],
548 | [
549 | 3.614,
550 | 0
551 | ],
552 | [
553 | 0,
554 | 3.614
555 | ],
556 | [
557 | -3.614,
558 | 0
559 | ]
560 | ],
561 | "c": true
562 | }
563 | },
564 | "nm": "Path 1",
565 | "mn": "ADBE Vector Shape - Group"
566 | },
567 | {
568 | "ty": "st",
569 | "c": {
570 | "a": 0,
571 | "k": [
572 | 0.529,
573 | 0.529,
574 | 0.529,
575 | 1
576 | ]
577 | },
578 | "o": {
579 | "a": 0,
580 | "k": 100
581 | },
582 | "w": {
583 | "a": 0,
584 | "k": 0.7
585 | },
586 | "lc": 1,
587 | "lj": 1,
588 | "ml": 10,
589 | "nm": "Stroke 1",
590 | "mn": "ADBE Vector Graphic - Stroke"
591 | },
592 | {
593 | "ty": "fl",
594 | "c": {
595 | "a": 0,
596 | "k": [
597 | 1,
598 | 1,
599 | 1,
600 | 1
601 | ]
602 | },
603 | "o": {
604 | "a": 0,
605 | "k": 100
606 | },
607 | "r": 1,
608 | "nm": "Fill 1",
609 | "mn": "ADBE Vector Graphic - Fill"
610 | },
611 | {
612 | "ty": "tr",
613 | "p": {
614 | "a": 0,
615 | "k": [
616 | 57.957,
617 | 10.552
618 | ],
619 | "ix": 2
620 | },
621 | "a": {
622 | "a": 0,
623 | "k": [
624 | 0,
625 | 0
626 | ],
627 | "ix": 1
628 | },
629 | "s": {
630 | "a": 0,
631 | "k": [
632 | 100,
633 | 100
634 | ],
635 | "ix": 3
636 | },
637 | "r": {
638 | "a": 0,
639 | "k": 0,
640 | "ix": 6
641 | },
642 | "o": {
643 | "a": 0,
644 | "k": 100,
645 | "ix": 7
646 | },
647 | "sk": {
648 | "a": 0,
649 | "k": 0,
650 | "ix": 4
651 | },
652 | "sa": {
653 | "a": 0,
654 | "k": 0,
655 | "ix": 5
656 | },
657 | "nm": "Transform"
658 | }
659 | ],
660 | "nm": "Group 3",
661 | "np": 3,
662 | "cix": 2,
663 | "ix": 3,
664 | "mn": "ADBE Vector Group"
665 | },
666 | {
667 | "ty": "tr",
668 | "p": {
669 | "a": 0,
670 | "k": [
671 | 60.531,
672 | 10.941
673 | ],
674 | "ix": 2
675 | },
676 | "a": {
677 | "a": 0,
678 | "k": [
679 | 60.531,
680 | 10.941
681 | ],
682 | "ix": 1
683 | },
684 | "s": {
685 | "a": 0,
686 | "k": [
687 | 100,
688 | 100
689 | ],
690 | "ix": 3
691 | },
692 | "r": {
693 | "a": 0,
694 | "k": 0,
695 | "ix": 6
696 | },
697 | "o": {
698 | "a": 0,
699 | "k": 100,
700 | "ix": 7
701 | },
702 | "sk": {
703 | "a": 0,
704 | "k": 0,
705 | "ix": 4
706 | },
707 | "sa": {
708 | "a": 0,
709 | "k": 0,
710 | "ix": 5
711 | },
712 | "nm": "Transform"
713 | }
714 | ],
715 | "nm": "ruoi",
716 | "np": 3,
717 | "cix": 2,
718 | "ix": 1,
719 | "mn": "ADBE Vector Group"
720 | }
721 | ],
722 | "ip": 0,
723 | "op": 50,
724 | "st": 0,
725 | "bm": 0,
726 | "sr": 1
727 | },
728 | {
729 | "ddd": 0,
730 | "ind": 2,
731 | "ty": 4,
732 | "nm": "Shape Layer 2",
733 | "ks": {
734 | "o": {
735 | "a": 1,
736 | "k": [
737 | {
738 | "i": {
739 | "x": [
740 | 0.833
741 | ],
742 | "y": [
743 | 0.967
744 | ]
745 | },
746 | "o": {
747 | "x": [
748 | 0.167
749 | ],
750 | "y": [
751 | 0.033
752 | ]
753 | },
754 | "n": [
755 | "0p833_0p967_0p167_0p033"
756 | ],
757 | "t": 35,
758 | "s": [
759 | 100
760 | ],
761 | "e": [
762 | 0
763 | ]
764 | },
765 | {
766 | "t": 49
767 | }
768 | ]
769 | },
770 | "r": {
771 | "a": 0,
772 | "k": 0
773 | },
774 | "p": {
775 | "a": 0,
776 | "k": [
777 | -0.75,
778 | -0.75,
779 | 0
780 | ]
781 | },
782 | "a": {
783 | "a": 0,
784 | "k": [
785 | 0,
786 | 0,
787 | 0
788 | ]
789 | },
790 | "s": {
791 | "a": 0,
792 | "k": [
793 | 100,
794 | 100,
795 | 100
796 | ]
797 | }
798 | },
799 | "ao": 0,
800 | "shapes": [
801 | {
802 | "ty": "gr",
803 | "it": [
804 | {
805 | "ind": 0,
806 | "ty": "sh",
807 | "ix": 1,
808 | "ks": {
809 | "a": 0,
810 | "k": {
811 | "i": [
812 | [
813 | 0,
814 | 0
815 | ],
816 | [
817 | -13.91,
818 | 5.273
819 | ],
820 | [
821 | -4.545,
822 | 3.734
823 | ],
824 | [
825 | 20.029,
826 | 1.207
827 | ]
828 | ],
829 | "o": [
830 | [
831 | -4.675,
832 | -4.128
833 | ],
834 | [
835 | 12.816,
836 | -4.858
837 | ],
838 | [
839 | 6.616,
840 | -5.438
841 | ],
842 | [
843 | 0,
844 | 0
845 | ]
846 | ],
847 | "v": [
848 | [
849 | -7.383,
850 | 24.76
851 | ],
852 | [
853 | -7.046,
854 | 5.54
855 | ],
856 | [
857 | 14.34,
858 | -2.273
859 | ],
860 | [
861 | -3.178,
862 | -24.76
863 | ]
864 | ],
865 | "c": false
866 | }
867 | },
868 | "nm": "Path 1",
869 | "mn": "ADBE Vector Shape - Group"
870 | },
871 | {
872 | "ty": "st",
873 | "c": {
874 | "a": 0,
875 | "k": [
876 | 0.627,
877 | 0.627,
878 | 0.627,
879 | 1
880 | ]
881 | },
882 | "o": {
883 | "a": 0,
884 | "k": 100
885 | },
886 | "w": {
887 | "a": 0,
888 | "k": 1
889 | },
890 | "lc": 2,
891 | "lj": 2,
892 | "d": [
893 | {
894 | "n": "d",
895 | "nm": "dash",
896 | "v": {
897 | "a": 0,
898 | "k": 2.028
899 | }
900 | },
901 | {
902 | "n": "g",
903 | "nm": "gap",
904 | "v": {
905 | "a": 0,
906 | "k": 2.028
907 | }
908 | },
909 | {
910 | "n": "o",
911 | "nm": "offset",
912 | "v": {
913 | "a": 0,
914 | "k": 0
915 | }
916 | }
917 | ],
918 | "nm": "Stroke 1",
919 | "mn": "ADBE Vector Graphic - Stroke"
920 | },
921 | {
922 | "ty": "tr",
923 | "p": {
924 | "a": 0,
925 | "k": [
926 | 67.87,
927 | 37.631
928 | ],
929 | "ix": 2
930 | },
931 | "a": {
932 | "a": 0,
933 | "k": [
934 | 0,
935 | 0
936 | ],
937 | "ix": 1
938 | },
939 | "s": {
940 | "a": 0,
941 | "k": [
942 | 100,
943 | 100
944 | ],
945 | "ix": 3
946 | },
947 | "r": {
948 | "a": 0,
949 | "k": 0,
950 | "ix": 6
951 | },
952 | "o": {
953 | "a": 0,
954 | "k": 100,
955 | "ix": 7
956 | },
957 | "sk": {
958 | "a": 0,
959 | "k": 0,
960 | "ix": 4
961 | },
962 | "sa": {
963 | "a": 0,
964 | "k": 0,
965 | "ix": 5
966 | },
967 | "nm": "Transform"
968 | }
969 | ],
970 | "nm": "Group 6",
971 | "np": 2,
972 | "cix": 2,
973 | "ix": 1,
974 | "mn": "ADBE Vector Group"
975 | },
976 | {
977 | "ty": "tm",
978 | "s": {
979 | "a": 0,
980 | "k": 0,
981 | "ix": 1
982 | },
983 | "e": {
984 | "a": 1,
985 | "k": [
986 | {
987 | "i": {
988 | "x": [
989 | 0.833
990 | ],
991 | "y": [
992 | 0.953
993 | ]
994 | },
995 | "o": {
996 | "x": [
997 | 0.167
998 | ],
999 | "y": [
1000 | 0.033
1001 | ]
1002 | },
1003 | "n": [
1004 | "0p833_0p953_0p167_0p033"
1005 | ],
1006 | "t": 0,
1007 | "s": [
1008 | 0
1009 | ],
1010 | "e": [
1011 | 100
1012 | ]
1013 | },
1014 | {
1015 | "t": 35
1016 | }
1017 | ],
1018 | "ix": 2
1019 | },
1020 | "o": {
1021 | "a": 0,
1022 | "k": 0,
1023 | "ix": 3
1024 | },
1025 | "m": 1,
1026 | "ix": 2,
1027 | "nm": "Trim Paths 1",
1028 | "mn": "ADBE Vector Filter - Trim"
1029 | }
1030 | ],
1031 | "ip": 0,
1032 | "op": 50,
1033 | "st": 0,
1034 | "bm": 0,
1035 | "sr": 1
1036 | },
1037 | {
1038 | "ddd": 0,
1039 | "ind": 3,
1040 | "ty": 4,
1041 | "nm": "im_emptyBox Outlines",
1042 | "ks": {
1043 | "o": {
1044 | "a": 0,
1045 | "k": 100
1046 | },
1047 | "r": {
1048 | "a": 0,
1049 | "k": 0
1050 | },
1051 | "p": {
1052 | "a": 0,
1053 | "k": [
1054 | 60,
1055 | 60,
1056 | 0
1057 | ]
1058 | },
1059 | "a": {
1060 | "a": 0,
1061 | "k": [
1062 | 60,
1063 | 60,
1064 | 0
1065 | ]
1066 | },
1067 | "s": {
1068 | "a": 0,
1069 | "k": [
1070 | 100,
1071 | 100,
1072 | 100
1073 | ]
1074 | }
1075 | },
1076 | "ao": 0,
1077 | "shapes": [
1078 | {
1079 | "ty": "gr",
1080 | "it": [
1081 | {
1082 | "ty": "gr",
1083 | "it": [
1084 | {
1085 | "ind": 0,
1086 | "ty": "sh",
1087 | "ix": 1,
1088 | "ks": {
1089 | "a": 0,
1090 | "k": {
1091 | "i": [
1092 | [
1093 | 0,
1094 | 0
1095 | ],
1096 | [
1097 | 0,
1098 | 0
1099 | ],
1100 | [
1101 | 0,
1102 | 0
1103 | ],
1104 | [
1105 | 0,
1106 | 0
1107 | ]
1108 | ],
1109 | "o": [
1110 | [
1111 | 0,
1112 | 0
1113 | ],
1114 | [
1115 | 0,
1116 | 0
1117 | ],
1118 | [
1119 | 0,
1120 | 0
1121 | ],
1122 | [
1123 | 0,
1124 | 0
1125 | ]
1126 | ],
1127 | "v": [
1128 | [
1129 | -0.001,
1130 | -16.607
1131 | ],
1132 | [
1133 | -32.143,
1134 | -0.002
1135 | ],
1136 | [
1137 | -0.001,
1138 | 16.607
1139 | ],
1140 | [
1141 | 32.144,
1142 | -0.002
1143 | ]
1144 | ],
1145 | "c": true
1146 | }
1147 | },
1148 | "nm": "Path 1",
1149 | "mn": "ADBE Vector Shape - Group"
1150 | },
1151 | {
1152 | "ty": "fl",
1153 | "c": {
1154 | "a": 0,
1155 | "k": [
1156 | 0.8,
1157 | 0.82,
1158 | 0.851,
1159 | 1
1160 | ]
1161 | },
1162 | "o": {
1163 | "a": 0,
1164 | "k": 100
1165 | },
1166 | "r": 1,
1167 | "nm": "Fill 1",
1168 | "mn": "ADBE Vector Graphic - Fill"
1169 | },
1170 | {
1171 | "ty": "tr",
1172 | "p": {
1173 | "a": 0,
1174 | "k": [
1175 | 60,
1176 | 55.75
1177 | ],
1178 | "ix": 2
1179 | },
1180 | "a": {
1181 | "a": 0,
1182 | "k": [
1183 | 0,
1184 | 0
1185 | ],
1186 | "ix": 1
1187 | },
1188 | "s": {
1189 | "a": 0,
1190 | "k": [
1191 | 100,
1192 | 100
1193 | ],
1194 | "ix": 3
1195 | },
1196 | "r": {
1197 | "a": 0,
1198 | "k": 0,
1199 | "ix": 6
1200 | },
1201 | "o": {
1202 | "a": 0,
1203 | "k": 100,
1204 | "ix": 7
1205 | },
1206 | "sk": {
1207 | "a": 0,
1208 | "k": 0,
1209 | "ix": 4
1210 | },
1211 | "sa": {
1212 | "a": 0,
1213 | "k": 0,
1214 | "ix": 5
1215 | },
1216 | "nm": "Transform"
1217 | }
1218 | ],
1219 | "nm": "Group 7",
1220 | "np": 2,
1221 | "cix": 2,
1222 | "ix": 1,
1223 | "mn": "ADBE Vector Group"
1224 | },
1225 | {
1226 | "ty": "gr",
1227 | "it": [
1228 | {
1229 | "ind": 0,
1230 | "ty": "sh",
1231 | "ix": 1,
1232 | "ks": {
1233 | "a": 0,
1234 | "k": {
1235 | "i": [
1236 | [
1237 | 0,
1238 | 0
1239 | ],
1240 | [
1241 | 0,
1242 | 0
1243 | ],
1244 | [
1245 | 0,
1246 | 0
1247 | ],
1248 | [
1249 | 0,
1250 | 0
1251 | ],
1252 | [
1253 | 0,
1254 | 0
1255 | ],
1256 | [
1257 | 0,
1258 | 0
1259 | ],
1260 | [
1261 | 0,
1262 | 0
1263 | ],
1264 | [
1265 | 0,
1266 | 0
1267 | ],
1268 | [
1269 | 0,
1270 | 0
1271 | ],
1272 | [
1273 | 0,
1274 | 0
1275 | ],
1276 | [
1277 | 0,
1278 | 0
1279 | ],
1280 | [
1281 | 0,
1282 | 0
1283 | ]
1284 | ],
1285 | "o": [
1286 | [
1287 | 0,
1288 | 0
1289 | ],
1290 | [
1291 | 0,
1292 | 0
1293 | ],
1294 | [
1295 | 0,
1296 | 0
1297 | ],
1298 | [
1299 | 0,
1300 | 0
1301 | ],
1302 | [
1303 | 0,
1304 | 0
1305 | ],
1306 | [
1307 | 0,
1308 | 0
1309 | ],
1310 | [
1311 | 0,
1312 | 0
1313 | ],
1314 | [
1315 | 0,
1316 | 0
1317 | ],
1318 | [
1319 | 0,
1320 | 0
1321 | ],
1322 | [
1323 | 0,
1324 | 0
1325 | ],
1326 | [
1327 | 0,
1328 | 0
1329 | ],
1330 | [
1331 | 0,
1332 | 0
1333 | ]
1334 | ],
1335 | "v": [
1336 | [
1337 | 12.856,
1338 | -23.249
1339 | ],
1340 | [
1341 | 0,
1342 | -16.605
1343 | ],
1344 | [
1345 | -12.857,
1346 | -23.249
1347 | ],
1348 | [
1349 | -45,
1350 | -6.641
1351 | ],
1352 | [
1353 | -32.144,
1354 | 0.001
1355 | ],
1356 | [
1357 | -45,
1358 | 6.645
1359 | ],
1360 | [
1361 | -12.857,
1362 | 23.249
1363 | ],
1364 | [
1365 | 0,
1366 | 16.609
1367 | ],
1368 | [
1369 | 12.856,
1370 | 23.249
1371 | ],
1372 | [
1373 | 45,
1374 | 6.645
1375 | ],
1376 | [
1377 | 32.143,
1378 | 0.001
1379 | ],
1380 | [
1381 | 45,
1382 | -6.641
1383 | ]
1384 | ],
1385 | "c": true
1386 | }
1387 | },
1388 | "nm": "Path 1",
1389 | "mn": "ADBE Vector Shape - Group"
1390 | },
1391 | {
1392 | "ty": "fl",
1393 | "c": {
1394 | "a": 0,
1395 | "k": [
1396 | 0.957,
1397 | 0.957,
1398 | 0.957,
1399 | 1
1400 | ]
1401 | },
1402 | "o": {
1403 | "a": 0,
1404 | "k": 100
1405 | },
1406 | "r": 1,
1407 | "nm": "Fill 1",
1408 | "mn": "ADBE Vector Graphic - Fill"
1409 | },
1410 | {
1411 | "ty": "tr",
1412 | "p": {
1413 | "a": 0,
1414 | "k": [
1415 | 60,
1416 | 55.748
1417 | ],
1418 | "ix": 2
1419 | },
1420 | "a": {
1421 | "a": 0,
1422 | "k": [
1423 | 0,
1424 | 0
1425 | ],
1426 | "ix": 1
1427 | },
1428 | "s": {
1429 | "a": 0,
1430 | "k": [
1431 | 100,
1432 | 100
1433 | ],
1434 | "ix": 3
1435 | },
1436 | "r": {
1437 | "a": 0,
1438 | "k": 0,
1439 | "ix": 6
1440 | },
1441 | "o": {
1442 | "a": 0,
1443 | "k": 100,
1444 | "ix": 7
1445 | },
1446 | "sk": {
1447 | "a": 0,
1448 | "k": 0,
1449 | "ix": 4
1450 | },
1451 | "sa": {
1452 | "a": 0,
1453 | "k": 0,
1454 | "ix": 5
1455 | },
1456 | "nm": "Transform"
1457 | }
1458 | ],
1459 | "nm": "Group 8",
1460 | "np": 2,
1461 | "cix": 2,
1462 | "ix": 2,
1463 | "mn": "ADBE Vector Group"
1464 | },
1465 | {
1466 | "ty": "gr",
1467 | "it": [
1468 | {
1469 | "ind": 0,
1470 | "ty": "sh",
1471 | "ix": 1,
1472 | "ks": {
1473 | "a": 0,
1474 | "k": {
1475 | "i": [
1476 | [
1477 | 0,
1478 | 0
1479 | ],
1480 | [
1481 | 0,
1482 | 0
1483 | ],
1484 | [
1485 | 0,
1486 | 0
1487 | ],
1488 | [
1489 | 0,
1490 | 0
1491 | ]
1492 | ],
1493 | "o": [
1494 | [
1495 | 0,
1496 | 0
1497 | ],
1498 | [
1499 | 0,
1500 | 0
1501 | ],
1502 | [
1503 | 0,
1504 | 0
1505 | ],
1506 | [
1507 | 0,
1508 | 0
1509 | ]
1510 | ],
1511 | "v": [
1512 | [
1513 | -16.072,
1514 | 24.171
1515 | ],
1516 | [
1517 | 16.072,
1518 | 11.312
1519 | ],
1520 | [
1521 | 16.072,
1522 | -24.171
1523 | ],
1524 | [
1525 | -16.072,
1526 | -24.171
1527 | ]
1528 | ],
1529 | "c": true
1530 | }
1531 | },
1532 | "nm": "Path 1",
1533 | "mn": "ADBE Vector Shape - Group"
1534 | },
1535 | {
1536 | "ty": "fl",
1537 | "c": {
1538 | "a": 0,
1539 | "k": [
1540 | 0.902,
1541 | 0.914,
1542 | 0.929,
1543 | 1
1544 | ]
1545 | },
1546 | "o": {
1547 | "a": 0,
1548 | "k": 100
1549 | },
1550 | "r": 1,
1551 | "nm": "Fill 1",
1552 | "mn": "ADBE Vector Graphic - Fill"
1553 | },
1554 | {
1555 | "ty": "tr",
1556 | "p": {
1557 | "a": 0,
1558 | "k": [
1559 | 76.072,
1560 | 83.33
1561 | ],
1562 | "ix": 2
1563 | },
1564 | "a": {
1565 | "a": 0,
1566 | "k": [
1567 | 0,
1568 | 0
1569 | ],
1570 | "ix": 1
1571 | },
1572 | "s": {
1573 | "a": 0,
1574 | "k": [
1575 | 100,
1576 | 100
1577 | ],
1578 | "ix": 3
1579 | },
1580 | "r": {
1581 | "a": 0,
1582 | "k": 0,
1583 | "ix": 6
1584 | },
1585 | "o": {
1586 | "a": 0,
1587 | "k": 100,
1588 | "ix": 7
1589 | },
1590 | "sk": {
1591 | "a": 0,
1592 | "k": 0,
1593 | "ix": 4
1594 | },
1595 | "sa": {
1596 | "a": 0,
1597 | "k": 0,
1598 | "ix": 5
1599 | },
1600 | "nm": "Transform"
1601 | }
1602 | ],
1603 | "nm": "Group 9",
1604 | "np": 2,
1605 | "cix": 2,
1606 | "ix": 3,
1607 | "mn": "ADBE Vector Group"
1608 | },
1609 | {
1610 | "ty": "gr",
1611 | "it": [
1612 | {
1613 | "ind": 0,
1614 | "ty": "sh",
1615 | "ix": 1,
1616 | "ks": {
1617 | "a": 0,
1618 | "k": {
1619 | "i": [
1620 | [
1621 | 0,
1622 | 0
1623 | ],
1624 | [
1625 | 0,
1626 | 0
1627 | ],
1628 | [
1629 | 0,
1630 | 0
1631 | ],
1632 | [
1633 | 0,
1634 | 0
1635 | ],
1636 | [
1637 | 0,
1638 | 0
1639 | ]
1640 | ],
1641 | "o": [
1642 | [
1643 | 0,
1644 | 0
1645 | ],
1646 | [
1647 | 0,
1648 | 0
1649 | ],
1650 | [
1651 | 0,
1652 | 0
1653 | ],
1654 | [
1655 | 0,
1656 | 0
1657 | ],
1658 | [
1659 | 0,
1660 | 0
1661 | ]
1662 | ],
1663 | "v": [
1664 | [
1665 | -32.143,
1666 | -24.171
1667 | ],
1668 | [
1669 | -32.143,
1670 | 11.311
1671 | ],
1672 | [
1673 | -0.001,
1674 | 24.171
1675 | ],
1676 | [
1677 | 32.144,
1678 | 11.311
1679 | ],
1680 | [
1681 | 32.144,
1682 | -24.171
1683 | ]
1684 | ],
1685 | "c": true
1686 | }
1687 | },
1688 | "nm": "Path 1",
1689 | "mn": "ADBE Vector Shape - Group"
1690 | },
1691 | {
1692 | "ty": "fl",
1693 | "c": {
1694 | "a": 0,
1695 | "k": [
1696 | 0.8,
1697 | 0.82,
1698 | 0.851,
1699 | 1
1700 | ]
1701 | },
1702 | "o": {
1703 | "a": 0,
1704 | "k": 100
1705 | },
1706 | "r": 1,
1707 | "nm": "Fill 1",
1708 | "mn": "ADBE Vector Graphic - Fill"
1709 | },
1710 | {
1711 | "ty": "tr",
1712 | "p": {
1713 | "a": 0,
1714 | "k": [
1715 | 60,
1716 | 83.33
1717 | ],
1718 | "ix": 2
1719 | },
1720 | "a": {
1721 | "a": 0,
1722 | "k": [
1723 | 0,
1724 | 0
1725 | ],
1726 | "ix": 1
1727 | },
1728 | "s": {
1729 | "a": 0,
1730 | "k": [
1731 | 100,
1732 | 100
1733 | ],
1734 | "ix": 3
1735 | },
1736 | "r": {
1737 | "a": 0,
1738 | "k": 0,
1739 | "ix": 6
1740 | },
1741 | "o": {
1742 | "a": 0,
1743 | "k": 100,
1744 | "ix": 7
1745 | },
1746 | "sk": {
1747 | "a": 0,
1748 | "k": 0,
1749 | "ix": 4
1750 | },
1751 | "sa": {
1752 | "a": 0,
1753 | "k": 0,
1754 | "ix": 5
1755 | },
1756 | "nm": "Transform"
1757 | }
1758 | ],
1759 | "nm": "Group 10",
1760 | "np": 2,
1761 | "cix": 2,
1762 | "ix": 4,
1763 | "mn": "ADBE Vector Group"
1764 | },
1765 | {
1766 | "ty": "tr",
1767 | "p": {
1768 | "a": 0,
1769 | "k": [
1770 | 60,
1771 | 60.186
1772 | ],
1773 | "ix": 2
1774 | },
1775 | "a": {
1776 | "a": 0,
1777 | "k": [
1778 | 60,
1779 | 60.186
1780 | ],
1781 | "ix": 1
1782 | },
1783 | "s": {
1784 | "a": 0,
1785 | "k": [
1786 | 100,
1787 | 100
1788 | ],
1789 | "ix": 3
1790 | },
1791 | "r": {
1792 | "a": 0,
1793 | "k": 0,
1794 | "ix": 6
1795 | },
1796 | "o": {
1797 | "a": 0,
1798 | "k": 100,
1799 | "ix": 7
1800 | },
1801 | "sk": {
1802 | "a": 0,
1803 | "k": 0,
1804 | "ix": 4
1805 | },
1806 | "sa": {
1807 | "a": 0,
1808 | "k": 0,
1809 | "ix": 5
1810 | },
1811 | "nm": "Transform"
1812 | }
1813 | ],
1814 | "nm": "box",
1815 | "np": 4,
1816 | "cix": 2,
1817 | "ix": 1,
1818 | "mn": "ADBE Vector Group"
1819 | }
1820 | ],
1821 | "ip": 0,
1822 | "op": 50,
1823 | "st": 0,
1824 | "bm": 0,
1825 | "sr": 1
1826 | }
1827 | ]
1828 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #485753
4 | #3A3E3D
5 | #f7890b
6 | #699b2c
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | GithubUsers
3 |
4 | Hello blank fragment
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
15 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/app/src/test/java/com/azhar/githubusers/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.azhar.githubusers;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:4.0.2"
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | maven {
20 | url 'https://jitpack.io'
21 | }
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AzharRivaldi/Github-User-App/bdef804aeac0d57125e97c3a360f01232d48b88d/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue May 18 14:27:42 ICT 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/local.properties:
--------------------------------------------------------------------------------
1 | ## This file is automatically generated by Android Studio.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file should *NOT* be checked into Version Control Systems,
5 | # as it contains information specific to your local configuration.
6 | #
7 | # Location of the SDK. This is only used by Gradle.
8 | # For customization when using a Version Control System, please read the
9 | # header note.
10 | sdk.dir=C\:\\Users\\azhar.rivaldi\\AppData\\Local\\Android\\Sdk
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "GithubUsers"
--------------------------------------------------------------------------------