├── .gitignore ├── .idea ├── .name ├── codeStyles │ └── Project.xml ├── gradle.xml ├── misc.xml └── runConfigurations.xml ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── habib │ │ └── blogapp │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── habib │ │ │ └── blogapp │ │ │ ├── Adapters │ │ │ ├── AccountPostAdapter.java │ │ │ ├── CommentsAdapter.java │ │ │ ├── PostsAdapter.java │ │ │ └── ViewPagerAdapter.java │ │ │ ├── AddPostActivity.java │ │ │ ├── AuthActivity.java │ │ │ ├── CommentActivity.java │ │ │ ├── Constant.java │ │ │ ├── EditPostActivity.java │ │ │ ├── EditUserInfoActivity.java │ │ │ ├── Fragments │ │ │ ├── AccountFragment.java │ │ │ ├── HomeFragment.java │ │ │ ├── SignInFragment.java │ │ │ └── SignUpFragment.java │ │ │ ├── HomeActivity.java │ │ │ ├── MainActivity.java │ │ │ ├── Models │ │ │ ├── Comment.java │ │ │ ├── Post.java │ │ │ └── User.java │ │ │ ├── OnBoardActivity.java │ │ │ └── UserInfoActivity.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── btn_round.xml │ │ ├── ic_add_black_24dp.xml │ │ ├── ic_arrow_back_black_24dp.xml │ │ ├── ic_comment.xml │ │ ├── ic_delete_forever_black_24dp.xml │ │ ├── ic_exit_to_app_black_24dp.xml │ │ ├── ic_favorite_outline.xml │ │ ├── ic_favorite_red.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_more_vert_black_24dp.xml │ │ ├── ic_person_outline_black_24dp.xml │ │ ├── ic_search_black_24dp.xml │ │ ├── ic_send_black_24dp.xml │ │ ├── p1.jpg │ │ ├── p2.jpg │ │ ├── p3.jpg │ │ └── txt_background.xml │ │ ├── font │ │ └── leckerlione_regular.ttf │ │ ├── layout │ │ ├── activity_add_post.xml │ │ ├── activity_auth.xml │ │ ├── activity_comment.xml │ │ ├── activity_edit_post.xml │ │ ├── activity_edit_user_info.xml │ │ ├── activity_home.xml │ │ ├── activity_main.xml │ │ ├── activity_on_board.xml │ │ ├── activity_user_info.xml │ │ ├── layout_account.xml │ │ ├── layout_account_post.xml │ │ ├── layout_comment.xml │ │ ├── layout_home.xml │ │ ├── layout_post.xml │ │ ├── layout_sign_in.xml │ │ ├── layout_sign_up.xml │ │ └── view_pager.xml │ │ ├── menu │ │ ├── menu_account.xml │ │ ├── menu_main.xml │ │ ├── menu_post_options.xml │ │ └── menu_search.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 │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── habib │ └── blogapp │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── readme.MD └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | BlogApp -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 29 5 | buildToolsVersion "29.0.3" 6 | defaultConfig { 7 | applicationId "com.habib.blogapp" 8 | minSdkVersion 21 9 | targetSdkVersion 29 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | compileOptions { 21 | sourceCompatibility = 1.8 22 | targetCompatibility = 1.8 23 | } 24 | } 25 | 26 | dependencies { 27 | implementation fileTree(dir: 'libs', include: ['*.jar']) 28 | implementation 'androidx.appcompat:appcompat:1.1.0' 29 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 30 | testImplementation 'junit:junit:4.12' 31 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 32 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 33 | implementation 'com.google.android.material:material:1.1.0' 34 | implementation 'de.hdodenhof:circleimageview:3.1.0' 35 | implementation 'com.android.volley:volley:1.1.1' 36 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0' 37 | implementation 'com.squareup.picasso:picasso:2.71828' 38 | implementation 'androidx.recyclerview:recyclerview:1.1.0' 39 | } 40 | -------------------------------------------------------------------------------- /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 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/habib/blogapp/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 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 | 25 | assertEquals("com.habib.blogapp", appContext.getPackageName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Adapters/AccountPostAdapter.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Adapters; 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 | 9 | import androidx.annotation.NonNull; 10 | import androidx.recyclerview.widget.RecyclerView; 11 | 12 | import com.habib.blogapp.Constant; 13 | import com.habib.blogapp.Models.Post; 14 | import com.habib.blogapp.R; 15 | import com.squareup.picasso.Picasso; 16 | 17 | import java.util.ArrayList; 18 | 19 | public class AccountPostAdapter extends RecyclerView.Adapter{ 20 | 21 | private Context context; 22 | private ArrayList arrayList; 23 | 24 | public AccountPostAdapter(Context context, ArrayList arrayList) { 25 | this.context = context; 26 | this.arrayList = arrayList; 27 | } 28 | 29 | @NonNull 30 | @Override 31 | public AccountPostHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 32 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_account_post,parent,false); 33 | return new AccountPostHolder(v); 34 | } 35 | 36 | @Override 37 | public void onBindViewHolder(@NonNull AccountPostHolder holder, int position) { 38 | Picasso.get().load(arrayList.get(position).getPhoto()).into(holder.imageView); 39 | } 40 | 41 | @Override 42 | public int getItemCount() { 43 | return arrayList.size(); 44 | } 45 | 46 | 47 | class AccountPostHolder extends RecyclerView.ViewHolder { 48 | 49 | private ImageView imageView; 50 | 51 | public AccountPostHolder(@NonNull View itemView) { 52 | super(itemView); 53 | imageView = itemView.findViewById(R.id.imgAccountPost); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Adapters/CommentsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Adapters; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.ProgressDialog; 5 | import android.content.Context; 6 | import android.content.DialogInterface; 7 | import android.content.SharedPreferences; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.view.ViewOutlineProvider; 12 | import android.widget.ImageButton; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import androidx.annotation.NonNull; 17 | import androidx.recyclerview.widget.RecyclerView; 18 | 19 | import com.android.volley.AuthFailureError; 20 | import com.android.volley.Request; 21 | import com.android.volley.RequestQueue; 22 | import com.android.volley.toolbox.StringRequest; 23 | import com.android.volley.toolbox.Volley; 24 | import com.habib.blogapp.CommentActivity; 25 | import com.habib.blogapp.Constant; 26 | import com.habib.blogapp.Fragments.HomeFragment; 27 | import com.habib.blogapp.Models.Comment; 28 | import com.habib.blogapp.Models.Post; 29 | import com.habib.blogapp.Models.User; 30 | import com.habib.blogapp.R; 31 | import com.squareup.picasso.Picasso; 32 | 33 | import org.json.JSONException; 34 | import org.json.JSONObject; 35 | 36 | import java.util.ArrayList; 37 | import java.util.HashMap; 38 | import java.util.Map; 39 | 40 | import de.hdodenhof.circleimageview.CircleImageView; 41 | 42 | public class CommentsAdapter extends RecyclerView.Adapter{ 43 | 44 | private Context context; 45 | private ArrayList list; 46 | private SharedPreferences preferences; 47 | private ProgressDialog dialog; 48 | 49 | 50 | public CommentsAdapter(Context context, ArrayList list) { 51 | this.context = context; 52 | this.list = list; 53 | dialog = new ProgressDialog(context); 54 | dialog.setCancelable(false); 55 | preferences = context.getSharedPreferences("user",Context.MODE_PRIVATE); 56 | } 57 | 58 | @NonNull 59 | @Override 60 | public CommentsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 61 | View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_comment,parent,false); 62 | return new CommentsHolder(v); 63 | } 64 | 65 | @Override 66 | public void onBindViewHolder(@NonNull CommentsHolder holder, int position) { 67 | Comment comment = list.get(position); 68 | Picasso.get().load(comment.getUser().getPhoto()).into(holder.imgProfile); 69 | holder.txtName.setText(comment.getUser().getUserName()); 70 | holder.txtDate.setText(comment.getDate()); 71 | holder.txtComment.setText(comment.getComment()); 72 | 73 | if (preferences.getInt("id",0)!=comment.getUser().getId()){ 74 | holder.btnDelete.setVisibility(View.GONE); 75 | } 76 | else { 77 | holder.btnDelete.setVisibility(View.VISIBLE); 78 | holder.btnDelete.setOnClickListener(v->{ 79 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 80 | builder.setMessage("Are you sure?"); 81 | builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() { 82 | @Override 83 | public void onClick(DialogInterface dialog, int which) { 84 | deleteComment(comment.getId(),position); 85 | } 86 | }); 87 | builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 88 | @Override 89 | public void onClick(DialogInterface dialog, int which) { 90 | 91 | } 92 | }); 93 | builder.show(); 94 | }); 95 | } 96 | 97 | } 98 | 99 | private void deleteComment(int commentId,int position){ 100 | dialog.setMessage("Deleting comment"); 101 | dialog.show(); 102 | StringRequest request = new StringRequest(Request.Method.POST,Constant.DELETE_COMMENT,res->{ 103 | 104 | try { 105 | JSONObject object = new JSONObject(res); 106 | if (object.getBoolean("success")){ 107 | list.remove(position); 108 | Post post = HomeFragment.arrayList.get(CommentActivity.postPosition); 109 | post.setComments(post.getComments()-1); 110 | HomeFragment.arrayList.set(CommentActivity.postPosition,post); 111 | HomeFragment.recyclerView.getAdapter().notifyDataSetChanged(); 112 | notifyDataSetChanged(); 113 | } 114 | } catch (JSONException e) { 115 | e.printStackTrace(); 116 | } 117 | dialog.dismiss(); 118 | 119 | },err->{ 120 | err.printStackTrace(); 121 | dialog.dismiss(); 122 | }){ 123 | @Override 124 | public Map getHeaders() throws AuthFailureError { 125 | String token = preferences.getString("token",""); 126 | HashMap map = new HashMap<>(); 127 | map.put("Authorization","Bearer "+token); 128 | return map; 129 | } 130 | 131 | @Override 132 | protected Map getParams() throws AuthFailureError { 133 | HashMap map = new HashMap<>(); 134 | map.put("id",commentId+""); 135 | return map; 136 | } 137 | }; 138 | RequestQueue queue = Volley.newRequestQueue(context); 139 | queue.add(request); 140 | } 141 | 142 | @Override 143 | public int getItemCount() { 144 | return list.size(); 145 | } 146 | 147 | class CommentsHolder extends RecyclerView.ViewHolder{ 148 | 149 | private CircleImageView imgProfile; 150 | private TextView txtName,txtDate,txtComment; 151 | private ImageButton btnDelete; 152 | 153 | public CommentsHolder(@NonNull View itemView) { 154 | super(itemView); 155 | 156 | imgProfile = itemView.findViewById(R.id.imgCommentProfile); 157 | txtName = itemView.findViewById(R.id.txtCommentName); 158 | txtDate = itemView.findViewById(R.id.txtCommentDate); 159 | txtComment = itemView.findViewById(R.id.txtCommentText); 160 | btnDelete = itemView.findViewById(R.id.btnDeleteComment); 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Adapters/PostsAdapter.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Adapters; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.view.LayoutInflater; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Filter; 13 | import android.widget.ImageButton; 14 | import android.widget.ImageView; 15 | import android.widget.PopupMenu; 16 | import android.widget.TextView; 17 | 18 | import androidx.annotation.NonNull; 19 | import androidx.recyclerview.widget.RecyclerView; 20 | 21 | import com.android.volley.AuthFailureError; 22 | import com.android.volley.Request; 23 | import com.android.volley.RequestQueue; 24 | import com.android.volley.toolbox.StringRequest; 25 | import com.android.volley.toolbox.Volley; 26 | import com.habib.blogapp.CommentActivity; 27 | import com.habib.blogapp.Constant; 28 | import com.habib.blogapp.EditPostActivity; 29 | import com.habib.blogapp.HomeActivity; 30 | import com.habib.blogapp.Models.Post; 31 | import com.habib.blogapp.R; 32 | import com.squareup.picasso.Picasso; 33 | 34 | import org.json.JSONException; 35 | import org.json.JSONObject; 36 | 37 | import java.util.ArrayList; 38 | import java.util.Collection; 39 | import java.util.HashMap; 40 | import java.util.Map; 41 | 42 | import de.hdodenhof.circleimageview.CircleImageView; 43 | 44 | public class PostsAdapter extends RecyclerView.Adapter { 45 | 46 | 47 | private Context context; 48 | private ArrayList list; 49 | private ArrayList listAll; 50 | private SharedPreferences preferences; 51 | 52 | public PostsAdapter(Context context, ArrayList list) { 53 | this.context = context; 54 | this.list = list; 55 | this.listAll = new ArrayList<>(list); 56 | preferences = context.getApplicationContext().getSharedPreferences("user",Context.MODE_PRIVATE); 57 | } 58 | 59 | @NonNull 60 | @Override 61 | public PostsHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 62 | View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_post,parent,false); 63 | return new PostsHolder(view); 64 | } 65 | 66 | @Override 67 | public void onBindViewHolder(@NonNull PostsHolder holder, int position) { 68 | Post post = list.get(position); 69 | Picasso.get().load(Constant.URL+"storage/profiles/"+post.getUser().getPhoto()).into(holder.imgProfile); 70 | Picasso.get().load(Constant.URL+"storage/posts/"+post.getPhoto()).into(holder.imgPost); 71 | holder.txtName.setText(post.getUser().getUserName()); 72 | holder.txtComments.setText("View all "+post.getComments()+" comments"); 73 | holder.txtLikes.setText(post.getLikes()+" Likes"); 74 | holder.txtDate.setText(post.getDate()); 75 | holder.txtDesc.setText(post.getDesc()); 76 | 77 | holder.btnLike.setImageResource( 78 | post.isSelfLike()?R.drawable.ic_favorite_red:R.drawable.ic_favorite_outline 79 | ); 80 | // like click 81 | holder.btnLike.setOnClickListener(v->{ 82 | holder.btnLike.setImageResource( 83 | post.isSelfLike()?R.drawable.ic_favorite_outline:R.drawable.ic_favorite_red 84 | ); 85 | 86 | StringRequest request = new StringRequest(Request.Method.POST,Constant.LIKE_POST,response -> { 87 | 88 | Post mPost = list.get(position); 89 | 90 | try { 91 | JSONObject object = new JSONObject(response); 92 | if (object.getBoolean("success")){ 93 | mPost.setSelfLike(!post.isSelfLike()); 94 | mPost.setLikes(mPost.isSelfLike()?post.getLikes()+1:post.getLikes()-1); 95 | list.set(position,mPost); 96 | notifyItemChanged(position); 97 | notifyDataSetChanged(); 98 | } 99 | else { 100 | holder.btnLike.setImageResource( 101 | post.isSelfLike()?R.drawable.ic_favorite_red:R.drawable.ic_favorite_outline 102 | ); 103 | } 104 | 105 | } catch (JSONException e) { 106 | e.printStackTrace(); 107 | } 108 | 109 | },err->{ 110 | err.printStackTrace(); 111 | }){ 112 | // add token 113 | 114 | @Override 115 | public Map getHeaders() throws AuthFailureError { 116 | String token = preferences.getString("token",""); 117 | HashMap map = new HashMap<>(); 118 | map.put("Authorization","Bearer "+token); 119 | return map; 120 | } 121 | 122 | @Override 123 | protected Map getParams() throws AuthFailureError { 124 | HashMap map = new HashMap<>(); 125 | map.put("id",post.getId()+""); 126 | return map; 127 | } 128 | }; 129 | 130 | RequestQueue queue = Volley.newRequestQueue(context); 131 | queue.add(request); 132 | 133 | }); 134 | 135 | if(post.getUser().getId()==preferences.getInt("id",0)){ 136 | holder.btnPostOption.setVisibility(View.VISIBLE); 137 | } else { 138 | holder.btnPostOption.setVisibility(View.GONE); 139 | } 140 | 141 | holder.btnPostOption.setOnClickListener(v->{ 142 | PopupMenu popupMenu = new PopupMenu(context,holder.btnPostOption); 143 | popupMenu.inflate(R.menu.menu_post_options); 144 | popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 145 | @Override 146 | public boolean onMenuItemClick(MenuItem item) { 147 | 148 | switch (item.getItemId()){ 149 | case R.id.item_edit: { 150 | Intent i = new Intent(((HomeActivity)context), EditPostActivity.class); 151 | i.putExtra("postId",post.getId()); 152 | i.putExtra("position",position); 153 | i.putExtra("text",post.getDesc()); 154 | context.startActivity(i); 155 | return true; 156 | } 157 | case R.id.item_delete: { 158 | deletePost(post.getId(),position); 159 | return true; 160 | } 161 | } 162 | 163 | return false; 164 | } 165 | }); 166 | popupMenu.show(); 167 | }); 168 | 169 | holder.txtComments.setOnClickListener(v->{ 170 | Intent i = new Intent(((HomeActivity)context), CommentActivity.class); 171 | i.putExtra("postId",post.getId()); 172 | i.putExtra("postPosition",position); 173 | context.startActivity(i); 174 | }); 175 | 176 | holder.btnComment.setOnClickListener(v->{ 177 | Intent i = new Intent(((HomeActivity)context),CommentActivity.class); 178 | i.putExtra("postId",post.getId()); 179 | i.putExtra("postPosition",position); 180 | context.startActivity(i); 181 | }); 182 | 183 | } 184 | 185 | // delete post 186 | private void deletePost(int postId,int position){ 187 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 188 | builder.setTitle("Confirm"); 189 | builder.setMessage("Delete post?"); 190 | builder.setPositiveButton("Delete", new DialogInterface.OnClickListener() { 191 | @Override 192 | public void onClick(DialogInterface dialog, int which) { 193 | StringRequest request = new StringRequest(Request.Method.POST,Constant.DELETE_POST,response -> { 194 | 195 | try { 196 | JSONObject object = new JSONObject(response); 197 | if (object.getBoolean("success")){ 198 | list.remove(position); 199 | notifyItemRemoved(position); 200 | notifyDataSetChanged(); 201 | listAll.clear(); 202 | listAll.addAll(list); 203 | } 204 | } catch (JSONException e) { 205 | e.printStackTrace(); 206 | } 207 | 208 | },error -> { 209 | 210 | }){ 211 | @Override 212 | public Map getHeaders() throws AuthFailureError { 213 | String token = preferences.getString("token",""); 214 | HashMap map = new HashMap<>(); 215 | map.put("Authorization","Bearer "+token); 216 | return map; 217 | } 218 | 219 | @Override 220 | protected Map getParams() throws AuthFailureError { 221 | HashMap map = new HashMap<>(); 222 | map.put("id",postId+""); 223 | return map; 224 | } 225 | }; 226 | 227 | RequestQueue queue = Volley.newRequestQueue(context); 228 | queue.add(request); 229 | } 230 | }); 231 | builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 232 | @Override 233 | public void onClick(DialogInterface dialog, int which) { 234 | 235 | 236 | } 237 | }); 238 | builder.show(); 239 | } 240 | 241 | @Override 242 | public int getItemCount() { 243 | return list.size(); 244 | } 245 | 246 | 247 | Filter filter = new Filter() { 248 | @Override 249 | protected FilterResults performFiltering(CharSequence constraint) { 250 | 251 | ArrayList filteredList = new ArrayList<>(); 252 | if (constraint.toString().isEmpty()){ 253 | filteredList.addAll(listAll); 254 | } else { 255 | for (Post post : listAll){ 256 | if(post.getDesc().toLowerCase().contains(constraint.toString().toLowerCase()) 257 | || post.getUser().getUserName().toLowerCase().contains(constraint.toString().toLowerCase())){ 258 | filteredList.add(post); 259 | } 260 | } 261 | 262 | } 263 | 264 | FilterResults results = new FilterResults(); 265 | results.values = filteredList; 266 | return results; 267 | } 268 | 269 | @Override 270 | protected void publishResults(CharSequence constraint, FilterResults results) { 271 | list.clear(); 272 | list.addAll((Collection) results.values); 273 | notifyDataSetChanged(); 274 | } 275 | }; 276 | 277 | public Filter getFilter() { 278 | return filter; 279 | } 280 | 281 | class PostsHolder extends RecyclerView.ViewHolder{ 282 | 283 | private TextView txtName,txtDate,txtDesc,txtLikes,txtComments; 284 | private CircleImageView imgProfile; 285 | private ImageView imgPost; 286 | private ImageButton btnPostOption,btnLike,btnComment; 287 | 288 | public PostsHolder(@NonNull View itemView) { 289 | super(itemView); 290 | txtName = itemView.findViewById(R.id.txtPostName); 291 | txtDate = itemView.findViewById(R.id.txtPostDate); 292 | txtDesc = itemView.findViewById(R.id.txtPostDesc); 293 | txtLikes = itemView.findViewById(R.id.txtPostLikes); 294 | txtComments = itemView.findViewById(R.id.txtPostComments); 295 | imgProfile = itemView.findViewById(R.id.imgPostProfile); 296 | imgPost = itemView.findViewById(R.id.imgPostPhoto); 297 | btnPostOption = itemView.findViewById(R.id.btnPostOption); 298 | btnLike = itemView.findViewById(R.id.btnPostLike); 299 | btnComment = itemView.findViewById(R.id.btnPostComment); 300 | btnPostOption.setVisibility(View.GONE); 301 | } 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Adapters/ViewPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Adapters; 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.LinearLayout; 9 | import android.widget.TextView; 10 | 11 | import androidx.annotation.NonNull; 12 | import androidx.viewpager.widget.PagerAdapter; 13 | 14 | import com.habib.blogapp.R; 15 | 16 | public class ViewPagerAdapter extends PagerAdapter { 17 | 18 | private Context context; 19 | private LayoutInflater inflater; 20 | 21 | public ViewPagerAdapter(Context context) { 22 | this.context = context; 23 | } 24 | 25 | private int images[] ={ 26 | R.drawable.p1, 27 | R.drawable.p2, 28 | R.drawable.p3, 29 | }; 30 | 31 | private String titles[] ={ 32 | "Learn", 33 | "Create", 34 | "Enjoy" 35 | }; 36 | 37 | private String descs[] ={ 38 | "lorem ipsum dolor contraint spaces dolor ipsum loremters termainal lorem ispsum contanirnts.", 39 | "lorem ipsum dolor contraint spaces dolor ipsum loremters termainal lorem ispsum contanirnts.", 40 | "lorem ipsum dolor contraint spaces dolor ipsum loremters termainal lorem ispsum contanirnts." 41 | }; 42 | 43 | @Override 44 | public int getCount() { 45 | return titles.length; 46 | } 47 | 48 | @Override 49 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { 50 | return view == (LinearLayout)object; 51 | } 52 | 53 | @NonNull 54 | @Override 55 | public Object instantiateItem(@NonNull ViewGroup container, int position) { 56 | inflater = (LayoutInflater)context.getSystemService(context.LAYOUT_INFLATER_SERVICE); 57 | View v = inflater.inflate(R.layout.view_pager,container,false); 58 | 59 | //init views 60 | ImageView imageView = v.findViewById(R.id.imgViewPager); 61 | TextView txtTitle = v.findViewById(R.id.txtTitleViewPager); 62 | TextView txtDesc = v.findViewById(R.id.txtDescViewPager); 63 | 64 | imageView.setImageResource(images[position]); 65 | txtTitle.setText(titles[position]); 66 | txtDesc.setText(descs[position]); 67 | 68 | container.addView(v); 69 | return v; 70 | } 71 | 72 | @Override 73 | public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { 74 | container.removeView((LinearLayout)object); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/AddPostActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.annotation.Nullable; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import android.app.ProgressDialog; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.graphics.Bitmap; 11 | import android.net.Uri; 12 | import android.os.Bundle; 13 | import android.provider.MediaStore; 14 | import android.util.Base64; 15 | import android.view.View; 16 | import android.widget.Button; 17 | import android.widget.EditText; 18 | import android.widget.ImageView; 19 | import android.widget.Toast; 20 | 21 | import com.android.volley.AuthFailureError; 22 | import com.android.volley.Request; 23 | import com.android.volley.RequestQueue; 24 | import com.android.volley.toolbox.StringRequest; 25 | import com.android.volley.toolbox.Volley; 26 | import com.habib.blogapp.Fragments.HomeFragment; 27 | import com.habib.blogapp.Models.Post; 28 | import com.habib.blogapp.Models.User; 29 | 30 | import org.json.JSONException; 31 | import org.json.JSONObject; 32 | 33 | import java.io.ByteArrayOutputStream; 34 | import java.io.IOException; 35 | import java.util.HashMap; 36 | import java.util.Map; 37 | 38 | public class AddPostActivity extends AppCompatActivity { 39 | private Button btnPost; 40 | private ImageView imgPost; 41 | private EditText txtDesc; 42 | private Bitmap bitmap = null; 43 | private static final int GALLERY_CHANGE_POST = 3; 44 | private ProgressDialog dialog; 45 | private SharedPreferences preferences; 46 | 47 | @Override 48 | protected void onCreate(Bundle savedInstanceState) { 49 | super.onCreate(savedInstanceState); 50 | setContentView(R.layout.activity_add_post); 51 | init(); 52 | } 53 | 54 | private void init() { 55 | preferences = getApplicationContext().getSharedPreferences("user", Context.MODE_PRIVATE); 56 | btnPost = findViewById(R.id.btnAddPost); 57 | imgPost = findViewById(R.id.imgAddPost); 58 | txtDesc = findViewById(R.id.txtDescAddPost); 59 | dialog = new ProgressDialog(this); 60 | dialog.setCancelable(false); 61 | 62 | imgPost.setImageURI(getIntent().getData()); 63 | try { 64 | bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),getIntent().getData()); 65 | } catch (IOException e) { 66 | e.printStackTrace(); 67 | } 68 | 69 | btnPost.setOnClickListener(v->{ 70 | if(!txtDesc.getText().toString().isEmpty()){ 71 | post(); 72 | }else { 73 | Toast.makeText(this, "Post description is required", Toast.LENGTH_SHORT).show(); 74 | } 75 | }); 76 | 77 | } 78 | 79 | private void post(){ 80 | dialog.setMessage("Posting"); 81 | dialog.show(); 82 | 83 | StringRequest request = new StringRequest(Request.Method.POST,Constant.ADD_POST,response -> { 84 | 85 | try { 86 | JSONObject object = new JSONObject(response); 87 | if (object.getBoolean("success")){ 88 | JSONObject postObject = object.getJSONObject("post"); 89 | JSONObject userObject = postObject.getJSONObject("user"); 90 | 91 | User user = new User(); 92 | user.setId(userObject.getInt("id")); 93 | user.setUserName(userObject.getString("name")+" "+userObject.getString("lastname")); 94 | user.setPhoto(userObject.getString("photo")); 95 | 96 | Post post = new Post(); 97 | post.setUser(user); 98 | post.setId(postObject.getInt("id")); 99 | post.setSelfLike(false); 100 | post.setPhoto(postObject.getString("photo")); 101 | post.setDesc(postObject.getString("desc")); 102 | post.setComments(0); 103 | post.setLikes(0); 104 | post.setDate(postObject.getString("created_at")); 105 | 106 | HomeFragment.arrayList.add(0,post); 107 | HomeFragment.recyclerView.getAdapter().notifyItemInserted(0); 108 | HomeFragment.recyclerView.getAdapter().notifyDataSetChanged(); 109 | Toast.makeText(this, "Posted", Toast.LENGTH_SHORT).show(); 110 | finish(); 111 | 112 | 113 | } 114 | } catch (JSONException e) { 115 | e.printStackTrace(); 116 | } 117 | dialog.dismiss(); 118 | 119 | },error -> { 120 | error.printStackTrace(); 121 | dialog.dismiss(); 122 | }){ 123 | 124 | // add token to header 125 | 126 | 127 | @Override 128 | public Map getHeaders() throws AuthFailureError { 129 | String token = preferences.getString("token",""); 130 | HashMap map = new HashMap<>(); 131 | map.put("Authorization","Bearer "+token); 132 | return map; 133 | } 134 | 135 | // add params 136 | 137 | @Override 138 | protected Map getParams() throws AuthFailureError { 139 | HashMap map = new HashMap<>(); 140 | map.put("desc",txtDesc.getText().toString().trim()); 141 | map.put("photo",bitmapToString(bitmap)); 142 | return map; 143 | } 144 | }; 145 | 146 | RequestQueue queue = Volley.newRequestQueue(AddPostActivity.this); 147 | queue.add(request); 148 | 149 | } 150 | 151 | private String bitmapToString(Bitmap bitmap) { 152 | if (bitmap!=null){ 153 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 154 | bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream); 155 | byte [] array = byteArrayOutputStream.toByteArray(); 156 | return Base64.encodeToString(array,Base64.DEFAULT); 157 | } 158 | 159 | return ""; 160 | } 161 | 162 | 163 | public void cancelPost(View view) { 164 | super.onBackPressed(); 165 | } 166 | 167 | public void changePhoto(View view) { 168 | Intent i = new Intent(Intent.ACTION_PICK); 169 | i.setType("image/*"); 170 | startActivityForResult(i,GALLERY_CHANGE_POST); 171 | } 172 | 173 | @Override 174 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 175 | super.onActivityResult(requestCode, resultCode, data); 176 | if(requestCode==GALLERY_CHANGE_POST && resultCode==RESULT_OK){ 177 | Uri imgUri = data.getData(); 178 | imgPost.setImageURI(imgUri); 179 | try { 180 | bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),imgUri); 181 | } catch (IOException e) { 182 | e.printStackTrace(); 183 | } 184 | } 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/AuthActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.os.Bundle; 6 | 7 | import com.habib.blogapp.Fragments.SignInFragment; 8 | 9 | public class AuthActivity extends AppCompatActivity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | setContentView(R.layout.activity_auth); 15 | getSupportFragmentManager().beginTransaction().replace(R.id.frameAuthContainer,new SignInFragment()).commit(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/CommentActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.recyclerview.widget.LinearLayoutManager; 5 | import androidx.recyclerview.widget.RecyclerView; 6 | 7 | import android.app.ProgressDialog; 8 | import android.content.Context; 9 | import android.content.SharedPreferences; 10 | import android.os.Bundle; 11 | import android.view.View; 12 | import android.widget.Button; 13 | import android.widget.EditText; 14 | import android.widget.Toast; 15 | 16 | import com.android.volley.AuthFailureError; 17 | import com.android.volley.Request; 18 | import com.android.volley.RequestQueue; 19 | import com.android.volley.toolbox.StringRequest; 20 | import com.android.volley.toolbox.Volley; 21 | import com.habib.blogapp.Adapters.CommentsAdapter; 22 | import com.habib.blogapp.Fragments.HomeFragment; 23 | import com.habib.blogapp.Models.Comment; 24 | import com.habib.blogapp.Models.Post; 25 | import com.habib.blogapp.Models.User; 26 | 27 | import org.json.JSONArray; 28 | import org.json.JSONException; 29 | import org.json.JSONObject; 30 | 31 | import java.util.ArrayList; 32 | import java.util.HashMap; 33 | import java.util.Map; 34 | 35 | public class CommentActivity extends AppCompatActivity { 36 | 37 | private RecyclerView recyclerView; 38 | private ArrayList list; 39 | private CommentsAdapter adapter; 40 | private int postId = 0; 41 | public static int postPosition = 0; 42 | private SharedPreferences preferences; 43 | private EditText txtAddComment; 44 | private ProgressDialog dialog; 45 | 46 | @Override 47 | protected void onCreate(Bundle savedInstanceState) { 48 | super.onCreate(savedInstanceState); 49 | setContentView(R.layout.activity_comment); 50 | init(); 51 | } 52 | 53 | private void init() { 54 | dialog = new ProgressDialog(this); 55 | dialog.setCancelable(false); 56 | postPosition = getIntent().getIntExtra("postPosition",-1); 57 | preferences = getApplicationContext().getSharedPreferences("user", Context.MODE_PRIVATE); 58 | recyclerView = findViewById(R.id.recyclerComments); 59 | recyclerView.setHasFixedSize(true); 60 | recyclerView.setLayoutManager(new LinearLayoutManager(this)); 61 | txtAddComment = findViewById(R.id.txtAddComment); 62 | postId = getIntent().getIntExtra("postId",0); 63 | getComments(); 64 | } 65 | 66 | private void getComments() { 67 | list = new ArrayList<>(); 68 | StringRequest request = new StringRequest(Request.Method.POST,Constant.COMMENTS,res->{ 69 | 70 | try { 71 | JSONObject object = new JSONObject(res); 72 | if (object.getBoolean("success")){ 73 | JSONArray comments = new JSONArray(object.getString("comments")); 74 | for (int i = 0; i < comments.length(); i++) { 75 | JSONObject comment = comments.getJSONObject(i); 76 | JSONObject user = comment.getJSONObject("user"); 77 | 78 | User mUser = new User(); 79 | mUser.setId(user.getInt("id")); 80 | mUser.setPhoto(Constant.URL+"storage/profiles/"+user.getString("photo")); 81 | mUser.setUserName(user.getString("name")+" "+user.getString("lastname")); 82 | 83 | Comment mComment = new Comment(); 84 | mComment.setId(comment.getInt("id")); 85 | mComment.setUser(mUser); 86 | mComment.setDate(comment.getString("created_at")); 87 | mComment.setComment(comment.getString("comment")); 88 | list.add(mComment); 89 | } 90 | } 91 | 92 | adapter = new CommentsAdapter(this,list); 93 | recyclerView.setAdapter(adapter); 94 | 95 | } catch (JSONException e) { 96 | e.printStackTrace(); 97 | } 98 | 99 | },error -> { 100 | error.printStackTrace(); 101 | }){ 102 | @Override 103 | public Map getHeaders() throws AuthFailureError { 104 | String token = preferences.getString("token",""); 105 | HashMap map = new HashMap<>(); 106 | map.put("Authorization","Bearer "+token); 107 | return map; 108 | } 109 | 110 | @Override 111 | protected Map getParams() throws AuthFailureError { 112 | HashMap map = new HashMap<>(); 113 | map.put("id",postId+""); 114 | return map; 115 | } 116 | }; 117 | 118 | RequestQueue queue = Volley.newRequestQueue(CommentActivity.this); 119 | queue.add(request); 120 | } 121 | 122 | public void goBack(View view) { 123 | super.onBackPressed(); 124 | } 125 | 126 | public void addComment(View view) { 127 | String commentText = txtAddComment.getText().toString(); 128 | dialog.setMessage("Adding comment"); 129 | dialog.show(); 130 | if (commentText.length()>0){ 131 | StringRequest request = new StringRequest(Request.Method.POST,Constant.CREATE_COMMENT,res->{ 132 | 133 | try { 134 | JSONObject object = new JSONObject(res); 135 | if (object.getBoolean("success")){ 136 | JSONObject comment = object.getJSONObject("comment"); 137 | JSONObject user = comment.getJSONObject("user"); 138 | 139 | Comment c = new Comment(); 140 | User u = new User(); 141 | u.setId(user.getInt("id")); 142 | u.setUserName(user.getString("name")+" "+user.getString("lastname")); 143 | u.setPhoto(Constant.URL+"storage/profiles/"+user.getString("photo")); 144 | c.setUser(u); 145 | c.setId(comment.getInt("id")); 146 | c.setDate(comment.getString("created_at")); 147 | c.setComment(comment.getString("comment")); 148 | 149 | Post post = HomeFragment.arrayList.get(postPosition); 150 | post.setComments(post.getComments()+1); 151 | HomeFragment.arrayList.set(postPosition,post); 152 | HomeFragment.recyclerView.getAdapter().notifyDataSetChanged(); 153 | 154 | list.add(c); 155 | recyclerView.getAdapter().notifyDataSetChanged(); 156 | txtAddComment.setText(""); 157 | } 158 | } catch (JSONException e) { 159 | e.printStackTrace(); 160 | } 161 | dialog.dismiss(); 162 | 163 | },err->{ 164 | err.printStackTrace(); 165 | dialog.dismiss(); 166 | }){ 167 | //add token to header 168 | 169 | @Override 170 | public Map getHeaders() throws AuthFailureError { 171 | String token = preferences.getString("token",""); 172 | HashMap map = new HashMap<>(); 173 | map.put("Authorization","Bearer "+token); 174 | return map; 175 | } 176 | 177 | @Override 178 | protected Map getParams() throws AuthFailureError { 179 | HashMap map = new HashMap<>(); 180 | map.put("id",postId+""); 181 | map.put("comment",commentText); 182 | return map; 183 | } 184 | 185 | 186 | }; 187 | RequestQueue queue = Volley.newRequestQueue(CommentActivity.this); 188 | queue.add(request); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Constant.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | public class Constant { 4 | public static final String URL = "http://192.168.43.123/"; 5 | public static final String HOME = URL+"api"; 6 | public static final String LOGIN = HOME+"/login"; 7 | public static final String LOGOUT = HOME+"/logout"; 8 | public static final String REGISTER = HOME+"/register"; 9 | public static final String SAVE_USER_INFO = HOME+"/save_user_info"; 10 | public static final String POSTS = HOME+"/posts"; 11 | public static final String ADD_POST = POSTS+"/create"; 12 | public static final String UPDATE_POST = POSTS+"/update"; 13 | public static final String DELETE_POST = POSTS+"/delete"; 14 | public static final String LIKE_POST = POSTS+"/like"; 15 | public static final String COMMENTS = POSTS+"/comments"; 16 | public static final String CREATE_COMMENT = HOME+"/comments/create"; 17 | public static final String DELETE_COMMENT = HOME+"/comments/delete"; 18 | public static final String MY_POST = POSTS+"/my_posts"; 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/EditPostActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.app.ProgressDialog; 6 | import android.content.Context; 7 | import android.content.SharedPreferences; 8 | import android.os.Bundle; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.EditText; 12 | import android.widget.Toast; 13 | 14 | import com.android.volley.AuthFailureError; 15 | import com.android.volley.Request; 16 | import com.android.volley.RequestQueue; 17 | import com.android.volley.toolbox.StringRequest; 18 | import com.android.volley.toolbox.Volley; 19 | import com.habib.blogapp.Fragments.HomeFragment; 20 | import com.habib.blogapp.Models.Post; 21 | 22 | import org.json.JSONException; 23 | import org.json.JSONObject; 24 | 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | 28 | public class EditPostActivity extends AppCompatActivity { 29 | 30 | private int position =0, id= 0; 31 | private EditText txtDesc; 32 | private Button btnSave; 33 | private ProgressDialog dialog; 34 | private SharedPreferences sharedPreferences; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.activity_edit_post); 40 | init(); 41 | } 42 | 43 | private void init() { 44 | sharedPreferences = getApplication().getSharedPreferences("user", Context.MODE_PRIVATE); 45 | txtDesc = findViewById(R.id.txtDescEditPost); 46 | btnSave = findViewById(R.id.btnEditPost); 47 | dialog = new ProgressDialog(this); 48 | dialog.setCancelable(false); 49 | position = getIntent().getIntExtra("position",0); 50 | id = getIntent().getIntExtra("postId",0); 51 | txtDesc.setText(getIntent().getStringExtra("text")); 52 | 53 | btnSave.setOnClickListener(v->{ 54 | if (!txtDesc.getText().toString().isEmpty()){ 55 | savePost(); 56 | } 57 | }); 58 | } 59 | 60 | private void savePost() { 61 | dialog.setMessage("Saving"); 62 | dialog.show(); 63 | StringRequest request = new StringRequest(Request.Method.POST,Constant.UPDATE_POST,response -> { 64 | 65 | try { 66 | JSONObject object = new JSONObject(response); 67 | if (object.getBoolean("success")){ 68 | // update the post in recycler view 69 | Post post = HomeFragment.arrayList.get(position); 70 | post.setDesc(txtDesc.getText().toString()); 71 | HomeFragment.arrayList.set(position,post); 72 | HomeFragment.recyclerView.getAdapter().notifyItemChanged(position); 73 | HomeFragment.recyclerView.getAdapter().notifyDataSetChanged(); 74 | Toast.makeText(this, "Post Edited", Toast.LENGTH_SHORT).show(); 75 | finish(); 76 | } 77 | } catch (JSONException e) { 78 | e.printStackTrace(); 79 | } 80 | 81 | },error -> { 82 | error.printStackTrace(); 83 | }){ 84 | 85 | //add token to header 86 | 87 | 88 | @Override 89 | public Map getHeaders() throws AuthFailureError { 90 | String token = sharedPreferences.getString("token",""); 91 | HashMap map = new HashMap<>(); 92 | map.put("Authorization","Bearer "+token); 93 | return map; 94 | } 95 | 96 | @Override 97 | protected Map getParams() throws AuthFailureError { 98 | HashMap map = new HashMap<>(); 99 | map.put("id",id+""); 100 | map.put("desc",txtDesc.getText().toString()); 101 | return map; 102 | } 103 | }; 104 | 105 | RequestQueue queue = Volley.newRequestQueue(EditPostActivity.this); 106 | queue.add(request); 107 | } 108 | 109 | public void cancelEdit(View view){ 110 | super.onBackPressed(); 111 | } 112 | } 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/EditUserInfoActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.annotation.Nullable; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import android.app.ProgressDialog; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.graphics.Bitmap; 11 | import android.net.Uri; 12 | import android.os.Bundle; 13 | import android.provider.MediaStore; 14 | import android.util.Base64; 15 | import android.widget.Button; 16 | import android.widget.TextView; 17 | import android.widget.Toast; 18 | 19 | import com.android.volley.AuthFailureError; 20 | import com.android.volley.Request; 21 | import com.android.volley.RequestQueue; 22 | import com.android.volley.toolbox.StringRequest; 23 | import com.android.volley.toolbox.Volley; 24 | import com.google.android.material.textfield.TextInputEditText; 25 | import com.google.android.material.textfield.TextInputLayout; 26 | import com.squareup.picasso.Picasso; 27 | 28 | import org.json.JSONException; 29 | import org.json.JSONObject; 30 | 31 | import java.io.ByteArrayOutputStream; 32 | import java.io.IOException; 33 | import java.util.HashMap; 34 | import java.util.Map; 35 | 36 | import de.hdodenhof.circleimageview.CircleImageView; 37 | 38 | public class EditUserInfoActivity extends AppCompatActivity { 39 | 40 | private TextInputLayout layoutName,layoutLastname; 41 | private TextInputEditText txtName,txtLastname; 42 | private TextView txtSelectPhoto; 43 | private Button btnSave; 44 | private CircleImageView circleImageView; 45 | private static final int GALLERY_CHANGE_PROFILE = 5; 46 | private Bitmap bitmap = null; 47 | private SharedPreferences userPref; 48 | private ProgressDialog dialog; 49 | 50 | @Override 51 | protected void onCreate(Bundle savedInstanceState) { 52 | super.onCreate(savedInstanceState); 53 | setContentView(R.layout.activity_edit_user_info); 54 | init(); 55 | } 56 | 57 | private void init() { 58 | dialog = new ProgressDialog(this); 59 | dialog.setCancelable(false); 60 | userPref = getApplicationContext().getSharedPreferences("user", Context.MODE_PRIVATE); 61 | layoutLastname = findViewById(R.id.txtEditLayoutLastnameameUserInfo); 62 | layoutName = findViewById(R.id.txtEditLayoutNameUserInfo); 63 | txtName = findViewById(R.id.txtEditNameUserInfo); 64 | txtLastname = findViewById(R.id.txtEditLastnameUserInfo); 65 | txtSelectPhoto = findViewById(R.id.txtEditSelectPhoto); 66 | btnSave = findViewById(R.id.btnEditSave); 67 | circleImageView = findViewById(R.id.imgEditUserInfo); 68 | 69 | Picasso.get().load(getIntent().getStringExtra("imgUrl")).into(circleImageView); 70 | txtName.setText(userPref.getString("name","")); 71 | txtLastname.setText(userPref.getString("lastname","")); 72 | 73 | txtSelectPhoto.setOnClickListener(v->{ 74 | Intent i = new Intent(Intent.ACTION_PICK); 75 | i.setType("image/*"); 76 | startActivityForResult(i,GALLERY_CHANGE_PROFILE); 77 | }); 78 | 79 | btnSave.setOnClickListener(v->{ 80 | if (validate()){ 81 | updateProfile(); 82 | } 83 | }); 84 | } 85 | 86 | 87 | private void updateProfile(){ 88 | dialog.setMessage("Updating"); 89 | dialog.show(); 90 | StringRequest request = new StringRequest(Request.Method.POST,Constant.SAVE_USER_INFO,res->{ 91 | 92 | try { 93 | JSONObject object = new JSONObject(res); 94 | if (object.getBoolean("success")){ 95 | SharedPreferences.Editor editor = userPref.edit(); 96 | editor.putString("name",txtName.getText().toString().trim()); 97 | editor.putString("lastname",txtLastname.getText().toString().trim()); 98 | editor.apply(); 99 | Toast.makeText(this, "Profile Updated", Toast.LENGTH_SHORT).show(); 100 | finish(); 101 | } 102 | } catch (JSONException e) { 103 | e.printStackTrace(); 104 | } 105 | dialog.dismiss(); 106 | },err->{ 107 | err.printStackTrace(); 108 | dialog.dismiss(); 109 | }){ 110 | @Override 111 | public Map getHeaders() throws AuthFailureError { 112 | String token = userPref.getString("token",""); 113 | HashMap map = new HashMap<>(); 114 | map.put("Authorization","Bearer "+token); 115 | return map; 116 | } 117 | 118 | @Override 119 | protected Map getParams() throws AuthFailureError { 120 | HashMap map = new HashMap<>(); 121 | map.put("name",txtName.getText().toString().trim()); 122 | map.put("lastname",txtLastname.getText().toString().trim()); 123 | map.put("photo",bitmapToString(bitmap)); 124 | return map; 125 | } 126 | }; 127 | 128 | RequestQueue queue = Volley.newRequestQueue(EditUserInfoActivity.this); 129 | queue.add(request); 130 | } 131 | 132 | @Override 133 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 134 | super.onActivityResult(requestCode, resultCode, data); 135 | if (requestCode==GALLERY_CHANGE_PROFILE && resultCode==RESULT_OK){ 136 | Uri uri = data.getData(); 137 | 138 | circleImageView.setImageURI(uri); 139 | 140 | try { 141 | bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),uri); 142 | } catch (IOException e) { 143 | e.printStackTrace(); 144 | } 145 | } 146 | } 147 | 148 | private boolean validate(){ 149 | if (txtName.getText().toString().isEmpty()){ 150 | layoutName.setErrorEnabled(true); 151 | layoutName.setError("Name is Required"); 152 | return false; 153 | } 154 | if (txtLastname.getText().toString().isEmpty()){ 155 | layoutLastname.setErrorEnabled(true); 156 | layoutLastname.setError("Lastname is required"); 157 | return false; 158 | } 159 | 160 | return true; 161 | } 162 | 163 | private String bitmapToString(Bitmap bitmap) { 164 | if (bitmap!=null){ 165 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 166 | bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream); 167 | byte [] array = byteArrayOutputStream.toByteArray(); 168 | return Base64.encodeToString(array,Base64.DEFAULT); 169 | } 170 | 171 | return ""; 172 | } 173 | } 174 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Fragments/AccountFragment.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Fragments; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.os.Bundle; 9 | import android.view.LayoutInflater; 10 | import android.view.Menu; 11 | import android.view.MenuInflater; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.widget.Button; 16 | import android.widget.TextView; 17 | 18 | import androidx.annotation.NonNull; 19 | import androidx.annotation.Nullable; 20 | import androidx.fragment.app.Fragment; 21 | import androidx.recyclerview.widget.GridLayoutManager; 22 | import androidx.recyclerview.widget.RecyclerView; 23 | 24 | import com.android.volley.AuthFailureError; 25 | import com.android.volley.Request; 26 | import com.android.volley.RequestQueue; 27 | import com.android.volley.toolbox.StringRequest; 28 | import com.android.volley.toolbox.Volley; 29 | import com.google.android.material.appbar.MaterialToolbar; 30 | import com.habib.blogapp.Adapters.AccountPostAdapter; 31 | import com.habib.blogapp.AuthActivity; 32 | import com.habib.blogapp.Constant; 33 | import com.habib.blogapp.EditUserInfoActivity; 34 | import com.habib.blogapp.HomeActivity; 35 | import com.habib.blogapp.Models.Post; 36 | import com.habib.blogapp.R; 37 | import com.squareup.picasso.Picasso; 38 | 39 | import org.json.JSONArray; 40 | import org.json.JSONException; 41 | import org.json.JSONObject; 42 | 43 | import java.util.ArrayList; 44 | import java.util.HashMap; 45 | import java.util.Map; 46 | 47 | import de.hdodenhof.circleimageview.CircleImageView; 48 | 49 | public class AccountFragment extends Fragment { 50 | 51 | private View view; 52 | private MaterialToolbar toolbar; 53 | private CircleImageView imgProfile; 54 | private TextView txtName,txtPostsCount; 55 | private Button btnEditAccount; 56 | private RecyclerView recyclerView; 57 | private ArrayList arrayList; 58 | private SharedPreferences preferences; 59 | private AccountPostAdapter adapter; 60 | private String imgUrl = ""; 61 | 62 | public AccountFragment(){} 63 | 64 | @Nullable 65 | @Override 66 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 67 | view = inflater.inflate(R.layout.layout_account,container,false); 68 | init(); 69 | return view; 70 | } 71 | 72 | private void init() { 73 | preferences = getContext().getSharedPreferences("user",Context.MODE_PRIVATE); 74 | toolbar = view.findViewById(R.id.toolbarAccount); 75 | ((HomeActivity)getContext()).setSupportActionBar(toolbar); 76 | setHasOptionsMenu(true); 77 | imgProfile = view.findViewById(R.id.imgAccountProfile); 78 | txtName = view.findViewById(R.id.txtAccountName); 79 | txtPostsCount = view.findViewById(R.id.txtAccountPostCount); 80 | recyclerView = view.findViewById(R.id.recyclerAccount); 81 | btnEditAccount = view.findViewById(R.id.btnEditAccount); 82 | recyclerView.setHasFixedSize(true); 83 | recyclerView.setLayoutManager(new GridLayoutManager(getContext(),2)); 84 | 85 | 86 | btnEditAccount.setOnClickListener(v->{ 87 | Intent i = new Intent(((HomeActivity)getContext()), EditUserInfoActivity.class); 88 | i.putExtra("imgUrl",imgUrl); 89 | startActivity(i); 90 | }); 91 | } 92 | 93 | private void getData() { 94 | arrayList = new ArrayList<>(); 95 | StringRequest request = new StringRequest(Request.Method.GET,Constant.MY_POST,res->{ 96 | 97 | try { 98 | JSONObject object = new JSONObject(res); 99 | if (object.getBoolean("success")){ 100 | JSONArray posts = object.getJSONArray("posts"); 101 | for (int i = 0; i < posts.length(); i++) { 102 | JSONObject p = posts.getJSONObject(i); 103 | 104 | Post post = new Post(); 105 | post.setPhoto(Constant.URL+"storage/posts/"+p.getString("photo")); 106 | arrayList.add(post); 107 | 108 | } 109 | JSONObject user = object.getJSONObject("user"); 110 | txtName.setText(user.getString("name")+" "+user.getString("lastname")); 111 | txtPostsCount.setText(arrayList.size()+""); 112 | Picasso.get().load(Constant.URL+"storage/profiles/"+user.getString("photo")).into(imgProfile); 113 | adapter = new AccountPostAdapter(getContext(),arrayList); 114 | recyclerView.setAdapter(adapter); 115 | imgUrl = Constant.URL+"storage/profiles/"+user.getString("photo"); 116 | } 117 | 118 | 119 | } catch (JSONException e) { 120 | e.printStackTrace(); 121 | } 122 | 123 | },error -> { 124 | error.printStackTrace(); 125 | }){ 126 | 127 | @Override 128 | public Map getHeaders() throws AuthFailureError { 129 | String token = preferences.getString("token",""); 130 | HashMap map = new HashMap<>(); 131 | map.put("Authorization","Bearer "+token); 132 | return map; 133 | } 134 | }; 135 | 136 | RequestQueue queue = Volley.newRequestQueue(getContext()); 137 | queue.add(request); 138 | } 139 | 140 | 141 | @Override 142 | public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { 143 | inflater.inflate(R.menu.menu_account,menu); 144 | super.onCreateOptionsMenu(menu, inflater); 145 | } 146 | 147 | @Override 148 | public boolean onOptionsItemSelected(@NonNull MenuItem item) { 149 | 150 | switch (item.getItemId()){ 151 | case R.id.item_logout: { 152 | AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 153 | builder.setMessage("Do you want to logout?"); 154 | builder.setPositiveButton("Logout", new DialogInterface.OnClickListener() { 155 | @Override 156 | public void onClick(DialogInterface dialog, int which) { 157 | logout(); 158 | } 159 | }); 160 | builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { 161 | @Override 162 | public void onClick(DialogInterface dialog, int which) { 163 | 164 | } 165 | }); 166 | builder.show(); 167 | } 168 | } 169 | 170 | return super.onOptionsItemSelected(item); 171 | } 172 | 173 | private void logout(){ 174 | StringRequest request = new StringRequest(Request.Method.GET,Constant.LOGOUT,res->{ 175 | 176 | try { 177 | JSONObject object = new JSONObject(res); 178 | if (object.getBoolean("success")){ 179 | SharedPreferences.Editor editor = preferences.edit(); 180 | editor.clear(); 181 | editor.apply(); 182 | startActivity(new Intent(((HomeActivity)getContext()), AuthActivity.class)); 183 | ((HomeActivity)getContext()).finish(); 184 | } 185 | } catch (JSONException e) { 186 | e.printStackTrace(); 187 | } 188 | 189 | 190 | },error -> { 191 | error.printStackTrace(); 192 | }){ 193 | @Override 194 | public Map getHeaders() throws AuthFailureError { 195 | String token = preferences.getString("token",""); 196 | HashMap map = new HashMap<>(); 197 | map.put("Authorization","Bearer "+token); 198 | return map; 199 | } 200 | }; 201 | 202 | RequestQueue queue = Volley.newRequestQueue(getContext()); 203 | queue.add(request); 204 | } 205 | 206 | @Override 207 | public void onHiddenChanged(boolean hidden) { 208 | 209 | if (!hidden){ 210 | getData(); 211 | } 212 | 213 | super.onHiddenChanged(hidden); 214 | } 215 | 216 | @Override 217 | public void onResume() { 218 | super.onResume(); 219 | getData(); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Fragments/HomeFragment.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Fragments; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | import android.os.Bundle; 6 | import android.view.LayoutInflater; 7 | import android.view.Menu; 8 | import android.view.MenuInflater; 9 | import android.view.MenuItem; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.annotation.Nullable; 15 | import androidx.appcompat.widget.SearchView; 16 | import androidx.fragment.app.Fragment; 17 | import androidx.recyclerview.widget.LinearLayoutManager; 18 | import androidx.recyclerview.widget.RecyclerView; 19 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 20 | 21 | import com.android.volley.AuthFailureError; 22 | import com.android.volley.Request; 23 | import com.android.volley.RequestQueue; 24 | import com.android.volley.toolbox.StringRequest; 25 | import com.android.volley.toolbox.Volley; 26 | import com.google.android.material.appbar.MaterialToolbar; 27 | import com.habib.blogapp.Adapters.PostsAdapter; 28 | import com.habib.blogapp.Constant; 29 | import com.habib.blogapp.HomeActivity; 30 | import com.habib.blogapp.Models.Post; 31 | import com.habib.blogapp.Models.User; 32 | import com.habib.blogapp.R; 33 | 34 | import org.json.JSONArray; 35 | import org.json.JSONException; 36 | import org.json.JSONObject; 37 | 38 | import java.util.ArrayList; 39 | import java.util.HashMap; 40 | import java.util.Map; 41 | 42 | public class HomeFragment extends Fragment { 43 | private View view; 44 | public static RecyclerView recyclerView; 45 | public static ArrayList arrayList; 46 | private SwipeRefreshLayout refreshLayout; 47 | private PostsAdapter postsAdapter; 48 | private MaterialToolbar toolbar; 49 | private SharedPreferences sharedPreferences; 50 | 51 | public HomeFragment(){} 52 | 53 | @Nullable 54 | @Override 55 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 56 | view = inflater.inflate(R.layout.layout_home,container,false); 57 | init(); 58 | return view; 59 | } 60 | 61 | private void init(){ 62 | sharedPreferences = getContext().getApplicationContext().getSharedPreferences("user", Context.MODE_PRIVATE); 63 | recyclerView = view.findViewById(R.id.recyclerHome); 64 | recyclerView.setHasFixedSize(true); 65 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 66 | refreshLayout = view.findViewById(R.id.swipeHome); 67 | toolbar = view.findViewById(R.id.toolbarHome); 68 | ((HomeActivity)getContext()).setSupportActionBar(toolbar); 69 | setHasOptionsMenu(true); 70 | 71 | getPosts(); 72 | 73 | refreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { 74 | @Override 75 | public void onRefresh() { 76 | getPosts(); 77 | } 78 | }); 79 | } 80 | 81 | private void getPosts() { 82 | arrayList = new ArrayList<>(); 83 | refreshLayout.setRefreshing(true); 84 | 85 | StringRequest request = new StringRequest(Request.Method.GET, Constant.POSTS,response -> { 86 | 87 | try { 88 | JSONObject object = new JSONObject(response); 89 | if (object.getBoolean("success")){ 90 | JSONArray array = new JSONArray(object.getString("posts")); 91 | for (int i = 0; i < array.length(); i++) { 92 | JSONObject postObject = array.getJSONObject(i); 93 | JSONObject userObject = postObject.getJSONObject("user"); 94 | 95 | User user = new User(); 96 | user.setId(userObject.getInt("id")); 97 | user.setUserName(userObject.getString("name")+" "+userObject.getString("lastname")); 98 | user.setPhoto(userObject.getString("photo")); 99 | 100 | Post post = new Post(); 101 | post.setId(postObject.getInt("id")); 102 | post.setUser(user); 103 | post.setLikes(postObject.getInt("likesCount")); 104 | post.setComments(postObject.getInt("commentsCount")); 105 | post.setDate(postObject.getString("created_at")); 106 | post.setDesc(postObject.getString("desc")); 107 | post.setPhoto(postObject.getString("photo")); 108 | post.setSelfLike(postObject.getBoolean("selfLike")); 109 | 110 | arrayList.add(post); 111 | } 112 | 113 | postsAdapter = new PostsAdapter(getContext(),arrayList); 114 | recyclerView.setAdapter(postsAdapter); 115 | } 116 | } catch (JSONException e) { 117 | e.printStackTrace(); 118 | } 119 | 120 | refreshLayout.setRefreshing(false); 121 | 122 | },error -> { 123 | error.printStackTrace(); 124 | refreshLayout.setRefreshing(false); 125 | }){ 126 | 127 | // provide token in header 128 | 129 | @Override 130 | public Map getHeaders() throws AuthFailureError { 131 | String token = sharedPreferences.getString("token",""); 132 | HashMap map = new HashMap<>(); 133 | map.put("Authorization","Bearer "+token); 134 | return map; 135 | } 136 | }; 137 | 138 | RequestQueue queue = Volley.newRequestQueue(getContext()); 139 | queue.add(request); 140 | } 141 | 142 | @Override 143 | public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { 144 | inflater.inflate(R.menu.menu_search,menu); 145 | MenuItem item = menu.findItem(R.id.search); 146 | SearchView searchView = (SearchView)item.getActionView(); 147 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 148 | @Override 149 | public boolean onQueryTextSubmit(String query) { 150 | 151 | return false; 152 | } 153 | 154 | @Override 155 | public boolean onQueryTextChange(String newText) { 156 | postsAdapter.getFilter().filter(newText); 157 | return false; 158 | } 159 | }); 160 | super.onCreateOptionsMenu(menu, inflater); 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Fragments/SignInFragment.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Fragments; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.Intent; 5 | import android.content.SharedPreferences; 6 | import android.os.Bundle; 7 | import android.text.Editable; 8 | import android.text.TextWatcher; 9 | import android.view.LayoutInflater; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.widget.Button; 13 | import android.widget.TextView; 14 | import android.widget.Toast; 15 | 16 | import androidx.annotation.NonNull; 17 | import androidx.annotation.Nullable; 18 | import androidx.fragment.app.Fragment; 19 | 20 | import com.android.volley.AuthFailureError; 21 | import com.android.volley.Request; 22 | import com.android.volley.RequestQueue; 23 | import com.android.volley.toolbox.StringRequest; 24 | import com.android.volley.toolbox.Volley; 25 | import com.google.android.material.textfield.TextInputEditText; 26 | import com.google.android.material.textfield.TextInputLayout; 27 | import com.habib.blogapp.AuthActivity; 28 | import com.habib.blogapp.Constant; 29 | import com.habib.blogapp.HomeActivity; 30 | import com.habib.blogapp.R; 31 | 32 | import org.json.JSONException; 33 | import org.json.JSONObject; 34 | 35 | import java.util.HashMap; 36 | import java.util.Map; 37 | 38 | public class SignInFragment extends Fragment { 39 | private View view; 40 | private TextInputLayout layoutEmail,layoutPassword; 41 | private TextInputEditText txtEmail,txtPassword; 42 | private TextView txtSignUp; 43 | private Button btnSignIn; 44 | private ProgressDialog dialog; 45 | 46 | public SignInFragment(){} 47 | 48 | @Nullable 49 | @Override 50 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 51 | view = inflater.inflate(R.layout.layout_sign_in,container,false); 52 | init(); 53 | return view; 54 | } 55 | 56 | private void init() { 57 | layoutPassword = view.findViewById(R.id.txtLayoutPasswordSignIn); 58 | layoutEmail = view.findViewById(R.id.txtLayoutEmailSignIn); 59 | txtPassword = view.findViewById(R.id.txtPasswordSignIn); 60 | txtSignUp = view.findViewById(R.id.txtSignUp); 61 | txtEmail = view.findViewById(R.id.txtEmailSignIn); 62 | btnSignIn = view.findViewById(R.id.btnSignIn); 63 | dialog = new ProgressDialog(getContext()); 64 | dialog.setCancelable(false); 65 | 66 | txtSignUp.setOnClickListener(v->{ 67 | //change fragments 68 | getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.frameAuthContainer,new SignUpFragment()).commit(); 69 | }); 70 | 71 | btnSignIn.setOnClickListener(v->{ 72 | //validate fields first 73 | if (validate()){ 74 | login(); 75 | } 76 | }); 77 | 78 | 79 | txtEmail.addTextChangedListener(new TextWatcher() { 80 | @Override 81 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 82 | 83 | } 84 | 85 | @Override 86 | public void onTextChanged(CharSequence s, int start, int before, int count) { 87 | if (!txtEmail.getText().toString().isEmpty()){ 88 | layoutEmail.setErrorEnabled(false); 89 | } 90 | } 91 | 92 | @Override 93 | public void afterTextChanged(Editable s) { 94 | 95 | } 96 | }); 97 | 98 | txtPassword.addTextChangedListener(new TextWatcher() { 99 | @Override 100 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 101 | 102 | } 103 | 104 | @Override 105 | public void onTextChanged(CharSequence s, int start, int before, int count) { 106 | if (txtPassword.getText().toString().length()>7){ 107 | layoutPassword.setErrorEnabled(false); 108 | } 109 | } 110 | 111 | @Override 112 | public void afterTextChanged(Editable s) { 113 | 114 | } 115 | }); 116 | } 117 | 118 | 119 | private boolean validate (){ 120 | if (txtEmail.getText().toString().isEmpty()){ 121 | layoutEmail.setErrorEnabled(true); 122 | layoutEmail.setError("Email is Required"); 123 | return false; 124 | } 125 | if (txtPassword.getText().toString().length()<8){ 126 | layoutPassword.setErrorEnabled(true); 127 | layoutPassword.setError("Required at least 8 characters"); 128 | return false; 129 | } 130 | return true; 131 | } 132 | 133 | 134 | private void login (){ 135 | dialog.setMessage("Logging in"); 136 | dialog.show(); 137 | StringRequest request = new StringRequest(Request.Method.POST, Constant.LOGIN,response -> { 138 | //we get response if connection success 139 | try { 140 | JSONObject object = new JSONObject(response); 141 | if (object.getBoolean("success")){ 142 | JSONObject user = object.getJSONObject("user"); 143 | //make shared preference user 144 | SharedPreferences userPref = getActivity().getApplicationContext().getSharedPreferences("user",getContext().MODE_PRIVATE); 145 | SharedPreferences.Editor editor = userPref.edit(); 146 | editor.putString("token",object.getString("token")); 147 | editor.putString("name",user.getString("name")); 148 | editor.putInt("id",user.getInt("id")); 149 | editor.putString("lastname",user.getString("lastname")); 150 | editor.putString("photo",user.getString("photo")); 151 | editor.putBoolean("isLoggedIn",true); 152 | editor.apply(); 153 | //if success 154 | startActivity(new Intent(((AuthActivity)getContext()), HomeActivity.class)); 155 | ((AuthActivity) getContext()).finish(); 156 | Toast.makeText(getContext(), "Login Success", Toast.LENGTH_SHORT).show(); 157 | } 158 | } catch (JSONException e) { 159 | e.printStackTrace(); 160 | } 161 | dialog.dismiss(); 162 | },error -> { 163 | // error if connection not success 164 | error.printStackTrace(); 165 | dialog.dismiss(); 166 | }){ 167 | 168 | // add parameters 169 | 170 | 171 | @Override 172 | protected Map getParams() throws AuthFailureError { 173 | HashMap map = new HashMap<>(); 174 | map.put("email",txtEmail.getText().toString().trim()); 175 | map.put("password",txtPassword.getText().toString()); 176 | return map; 177 | } 178 | }; 179 | 180 | //add this request to requestqueue 181 | RequestQueue queue = Volley.newRequestQueue(getContext()); 182 | queue.add(request); 183 | } 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | } 199 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Fragments/SignUpFragment.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Fragments; 2 | 3 | 4 | import android.app.ProgressDialog; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.os.Bundle; 8 | import android.text.Editable; 9 | import android.text.TextWatcher; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.widget.Button; 14 | import android.widget.TextView; 15 | import android.widget.Toast; 16 | 17 | import androidx.annotation.NonNull; 18 | import androidx.annotation.Nullable; 19 | import androidx.fragment.app.Fragment; 20 | 21 | import com.android.volley.AuthFailureError; 22 | import com.android.volley.Request; 23 | import com.android.volley.RequestQueue; 24 | import com.android.volley.toolbox.StringRequest; 25 | import com.android.volley.toolbox.Volley; 26 | import com.google.android.material.textfield.TextInputEditText; 27 | import com.google.android.material.textfield.TextInputLayout; 28 | import com.habib.blogapp.AuthActivity; 29 | import com.habib.blogapp.Constant; 30 | import com.habib.blogapp.HomeActivity; 31 | import com.habib.blogapp.R; 32 | import com.habib.blogapp.UserInfoActivity; 33 | 34 | import org.json.JSONException; 35 | import org.json.JSONObject; 36 | 37 | import java.util.HashMap; 38 | import java.util.Map; 39 | 40 | public class SignUpFragment extends Fragment { 41 | private View view; 42 | private TextInputLayout layoutEmail,layoutPassword,layoutConfirm; 43 | private TextInputEditText txtEmail,txtPassword,txtConfirm; 44 | private TextView txtSignIn; 45 | private Button btnSignUp; 46 | private ProgressDialog dialog; 47 | 48 | public SignUpFragment(){} 49 | 50 | @Nullable 51 | @Override 52 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 53 | view = inflater.inflate(R.layout.layout_sign_up,container,false); 54 | init(); 55 | return view; 56 | } 57 | 58 | private void init() { 59 | layoutPassword = view.findViewById(R.id.txtLayoutPasswordSignUp); 60 | layoutEmail = view.findViewById(R.id.txtLayoutEmailSignUp); 61 | layoutConfirm = view.findViewById(R.id.txtLayoutConfrimSignUp); 62 | txtPassword = view.findViewById(R.id.txtPasswordSignUp); 63 | txtConfirm = view.findViewById(R.id.txtConfirmSignUp); 64 | txtSignIn = view.findViewById(R.id.txtSignIn); 65 | txtEmail = view.findViewById(R.id.txtEmailSignUp); 66 | btnSignUp = view.findViewById(R.id.btnSignUp); 67 | dialog = new ProgressDialog(getContext()); 68 | dialog.setCancelable(false); 69 | 70 | txtSignIn.setOnClickListener(v->{ 71 | //change fragments 72 | getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.frameAuthContainer,new SignInFragment()).commit(); 73 | }); 74 | 75 | btnSignUp.setOnClickListener(v->{ 76 | //validate fields first 77 | if (validate()){ 78 | register(); 79 | } 80 | }); 81 | 82 | 83 | txtEmail.addTextChangedListener(new TextWatcher() { 84 | @Override 85 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 86 | 87 | } 88 | 89 | @Override 90 | public void onTextChanged(CharSequence s, int start, int before, int count) { 91 | if (!txtEmail.getText().toString().isEmpty()){ 92 | layoutEmail.setErrorEnabled(false); 93 | } 94 | } 95 | 96 | @Override 97 | public void afterTextChanged(Editable s) { 98 | 99 | } 100 | }); 101 | 102 | txtPassword.addTextChangedListener(new TextWatcher() { 103 | @Override 104 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 105 | 106 | } 107 | 108 | @Override 109 | public void onTextChanged(CharSequence s, int start, int before, int count) { 110 | if (txtPassword.getText().toString().length()>7){ 111 | layoutPassword.setErrorEnabled(false); 112 | } 113 | } 114 | 115 | @Override 116 | public void afterTextChanged(Editable s) { 117 | 118 | } 119 | }); 120 | 121 | txtConfirm.addTextChangedListener(new TextWatcher() { 122 | @Override 123 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 124 | 125 | } 126 | 127 | @Override 128 | public void onTextChanged(CharSequence s, int start, int before, int count) { 129 | if (txtConfirm.getText().toString().equals(txtPassword.getText().toString())){ 130 | layoutConfirm.setErrorEnabled(false); 131 | } 132 | 133 | } 134 | 135 | @Override 136 | public void afterTextChanged(Editable s) { 137 | 138 | } 139 | }); 140 | } 141 | 142 | 143 | private boolean validate (){ 144 | if (txtEmail.getText().toString().isEmpty()){ 145 | layoutEmail.setErrorEnabled(true); 146 | layoutEmail.setError("Email is Required"); 147 | return false; 148 | } 149 | if (txtPassword.getText().toString().length()<8){ 150 | layoutPassword.setErrorEnabled(true); 151 | layoutPassword.setError("Required at least 8 characters"); 152 | return false; 153 | } 154 | if (!txtConfirm.getText().toString().equals(txtPassword.getText().toString())){ 155 | layoutConfirm.setErrorEnabled(true); 156 | layoutConfirm.setError("Password does not match"); 157 | return false; 158 | } 159 | 160 | 161 | return true; 162 | } 163 | 164 | 165 | private void register(){ 166 | dialog.setMessage("Registering"); 167 | dialog.show(); 168 | StringRequest request = new StringRequest(Request.Method.POST, Constant.REGISTER, response -> { 169 | //we get response if connection success 170 | try { 171 | JSONObject object = new JSONObject(response); 172 | if (object.getBoolean("success")){ 173 | JSONObject user = object.getJSONObject("user"); 174 | //make shared preference user 175 | SharedPreferences userPref = getActivity().getApplicationContext().getSharedPreferences("user",getContext().MODE_PRIVATE); 176 | SharedPreferences.Editor editor = userPref.edit(); 177 | editor.putString("token",object.getString("token")); 178 | editor.putString("name",user.getString("name")); 179 | editor.putInt("id",user.getInt("id")); 180 | editor.putString("lastname",user.getString("lastname")); 181 | editor.putString("photo",user.getString("photo")); 182 | editor.putBoolean("isLoggedIn",true); 183 | editor.apply(); 184 | //if success 185 | startActivity(new Intent(((AuthActivity)getContext()), UserInfoActivity.class)); 186 | ((AuthActivity) getContext()).finish(); 187 | Toast.makeText(getContext(), "Register Success", Toast.LENGTH_SHORT).show(); 188 | } 189 | } catch (JSONException e) { 190 | e.printStackTrace(); 191 | } 192 | dialog.dismiss(); 193 | 194 | },error -> { 195 | // error if connection not success 196 | error.printStackTrace(); 197 | dialog.dismiss(); 198 | }){ 199 | 200 | // add parameters 201 | 202 | 203 | @Override 204 | protected Map getParams() throws AuthFailureError { 205 | HashMap map = new HashMap<>(); 206 | map.put("email",txtEmail.getText().toString().trim()); 207 | map.put("password",txtPassword.getText().toString()); 208 | return map; 209 | } 210 | }; 211 | 212 | //add this request to requestqueue 213 | RequestQueue queue = Volley.newRequestQueue(getContext()); 214 | queue.add(request); 215 | } 216 | 217 | 218 | } 219 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/HomeActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.annotation.NonNull; 4 | import androidx.annotation.Nullable; 5 | import androidx.appcompat.app.AppCompatActivity; 6 | import androidx.fragment.app.Fragment; 7 | import androidx.fragment.app.FragmentManager; 8 | 9 | import android.content.Intent; 10 | import android.net.Uri; 11 | import android.os.Bundle; 12 | import android.view.MenuItem; 13 | 14 | import com.google.android.material.bottomnavigation.BottomNavigationView; 15 | import com.google.android.material.floatingactionbutton.FloatingActionButton; 16 | import com.habib.blogapp.Fragments.AccountFragment; 17 | import com.habib.blogapp.Fragments.HomeFragment; 18 | 19 | public class HomeActivity extends AppCompatActivity { 20 | 21 | private FragmentManager fragmentManager; 22 | private FloatingActionButton fab; 23 | private BottomNavigationView navigationView; 24 | private static final int GALLERY_ADD_POST = 2; 25 | 26 | @Override 27 | protected void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_home); 30 | fragmentManager = getSupportFragmentManager(); 31 | fragmentManager.beginTransaction().replace(R.id.frameHomeContainer,new HomeFragment(),HomeFragment.class.getSimpleName()).commit(); 32 | init(); 33 | } 34 | 35 | private void init() { 36 | navigationView = findViewById(R.id.bottom_nav); 37 | fab = findViewById(R.id.fab); 38 | fab.setOnClickListener(v->{ 39 | Intent i = new Intent(Intent.ACTION_PICK); 40 | i.setType("image/*"); 41 | startActivityForResult(i,GALLERY_ADD_POST); 42 | }); 43 | 44 | navigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { 45 | @Override 46 | public boolean onNavigationItemSelected(@NonNull MenuItem item) { 47 | 48 | switch (item.getItemId()){ 49 | case R.id.item_home: { 50 | Fragment account = fragmentManager.findFragmentByTag(AccountFragment.class.getSimpleName()); 51 | if (account!=null){ 52 | fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(AccountFragment.class.getSimpleName())).commit(); 53 | fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName())).commit(); 54 | } 55 | break; 56 | } 57 | 58 | case R.id.item_account: { 59 | Fragment account = fragmentManager.findFragmentByTag(AccountFragment.class.getSimpleName()); 60 | fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag(HomeFragment.class.getSimpleName())).commit(); 61 | if (account!=null){ 62 | fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag(AccountFragment.class.getSimpleName())).commit(); 63 | } 64 | else { 65 | fragmentManager.beginTransaction().add(R.id.frameHomeContainer,new AccountFragment(),AccountFragment.class.getSimpleName()).commit(); 66 | } 67 | break; 68 | } 69 | } 70 | 71 | return true; 72 | } 73 | }); 74 | 75 | } 76 | 77 | 78 | @Override 79 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 80 | super.onActivityResult(requestCode, resultCode, data); 81 | if(requestCode==GALLERY_ADD_POST && resultCode==RESULT_OK){ 82 | Uri imgUri = data.getData(); 83 | Intent i = new Intent(HomeActivity.this,AddPostActivity.class); 84 | i.setData(imgUri); 85 | startActivity(i); 86 | } 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | 11 | public class MainActivity extends AppCompatActivity { 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_main); 17 | 18 | //this code will pause the app for 1.5 secs and then any thing in run method will run. 19 | Handler handler = new Handler(); 20 | handler.postDelayed(new Runnable() { 21 | @Override 22 | public void run() { 23 | 24 | SharedPreferences userPref = getApplicationContext().getSharedPreferences("user",Context.MODE_PRIVATE); 25 | boolean isLoggedIn = userPref.getBoolean("isLoggedIn",false); 26 | 27 | if (isLoggedIn){ 28 | startActivity(new Intent(MainActivity.this,HomeActivity.class)); 29 | finish(); 30 | } 31 | 32 | else { 33 | isFirstTime(); 34 | } 35 | } 36 | },1500); 37 | } 38 | 39 | private void isFirstTime() { 40 | //for checking if the app is running for the very first time 41 | //we need to save a value to shared preferences 42 | SharedPreferences preferences = getApplication().getSharedPreferences("onBoard", Context.MODE_PRIVATE); 43 | boolean isFirstTime = preferences.getBoolean("isFirstTime",true); 44 | //default value true 45 | if (isFirstTime){ 46 | // if its true then its first time and we will change it false 47 | SharedPreferences.Editor editor = preferences.edit(); 48 | editor.putBoolean("isFirstTime",false); 49 | editor.apply(); 50 | 51 | // start Onboard activity 52 | startActivity(new Intent(MainActivity.this,OnBoardActivity.class)); 53 | finish(); 54 | } 55 | else{ 56 | //start Auth Activity 57 | startActivity(new Intent(MainActivity.this,AuthActivity.class)); 58 | finish(); 59 | } 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Models/Comment.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Models; 2 | 3 | public class Comment { 4 | private int id; 5 | private String comment,date; 6 | private User user; 7 | 8 | public Comment() { 9 | } 10 | 11 | public int getId() { 12 | return id; 13 | } 14 | 15 | public void setId(int id) { 16 | this.id = id; 17 | } 18 | 19 | public String getComment() { 20 | return comment; 21 | } 22 | 23 | public void setComment(String comment) { 24 | this.comment = comment; 25 | } 26 | 27 | public String getDate() { 28 | return date; 29 | } 30 | 31 | public void setDate(String date) { 32 | this.date = date; 33 | } 34 | 35 | public User getUser() { 36 | return user; 37 | } 38 | 39 | public void setUser(User user) { 40 | this.user = user; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Models/Post.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Models; 2 | 3 | public class Post { 4 | private int id,likes,comments; 5 | private String date,desc,photo; 6 | private User user; 7 | private boolean selfLike; 8 | 9 | public int getId() { 10 | return id; 11 | } 12 | 13 | public void setId(int id) { 14 | this.id = id; 15 | } 16 | 17 | public int getLikes() { 18 | return likes; 19 | } 20 | 21 | public void setLikes(int likes) { 22 | this.likes = likes; 23 | } 24 | 25 | public int getComments() { 26 | return comments; 27 | } 28 | 29 | public void setComments(int comments) { 30 | this.comments = comments; 31 | } 32 | 33 | public String getDate() { 34 | return date; 35 | } 36 | 37 | public void setDate(String date) { 38 | this.date = date; 39 | } 40 | 41 | public String getDesc() { 42 | return desc; 43 | } 44 | 45 | public void setDesc(String desc) { 46 | this.desc = desc; 47 | } 48 | 49 | public String getPhoto() { 50 | return photo; 51 | } 52 | 53 | public void setPhoto(String photo) { 54 | this.photo = photo; 55 | } 56 | 57 | public User getUser() { 58 | return user; 59 | } 60 | 61 | public void setUser(User user) { 62 | this.user = user; 63 | } 64 | 65 | public boolean isSelfLike() { 66 | return selfLike; 67 | } 68 | 69 | public void setSelfLike(boolean selfLike) { 70 | this.selfLike = selfLike; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/Models/User.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp.Models; 2 | 3 | public class User { 4 | private int id; 5 | private String userName,photo; 6 | 7 | public int getId() { 8 | return id; 9 | } 10 | 11 | public void setId(int id) { 12 | this.id = id; 13 | } 14 | 15 | public String getUserName() { 16 | return userName; 17 | } 18 | 19 | public void setUserName(String userName) { 20 | this.userName = userName; 21 | } 22 | 23 | public String getPhoto() { 24 | return photo; 25 | } 26 | 27 | public void setPhoto(String photo) { 28 | this.photo = photo; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/OnBoardActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.appcompat.app.AppCompatActivity; 4 | import androidx.viewpager.widget.ViewPager; 5 | 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | import android.text.Html; 9 | import android.view.View; 10 | import android.widget.Button; 11 | import android.widget.LinearLayout; 12 | import android.widget.TextView; 13 | 14 | import com.habib.blogapp.Adapters.ViewPagerAdapter; 15 | 16 | public class OnBoardActivity extends AppCompatActivity { 17 | 18 | private ViewPager viewPager; 19 | private Button btnLeft,btnRight; 20 | private ViewPagerAdapter adapter; 21 | private LinearLayout dotsLayout; 22 | private TextView[] dots; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_on_board); 28 | init(); 29 | } 30 | 31 | private void init() { 32 | viewPager = findViewById(R.id.view_pager); 33 | btnLeft = findViewById(R.id.btnLeft); 34 | btnRight = findViewById(R.id.btnRight); 35 | dotsLayout = findViewById(R.id.dotsLayout); 36 | adapter = new ViewPagerAdapter(this); 37 | addDots(0); 38 | viewPager.addOnPageChangeListener(listener); // create this listener 39 | viewPager.setAdapter(adapter); 40 | 41 | btnRight.setOnClickListener(v->{ 42 | //if button text is next we will go to next page of viewpager 43 | if (btnRight.getText().toString().equals("Next")){ 44 | viewPager.setCurrentItem(viewPager.getCurrentItem()+1); 45 | } 46 | else{ 47 | //else its finish we will start Auth activity 48 | startActivity(new Intent(OnBoardActivity.this,AuthActivity.class)); 49 | finish(); 50 | } 51 | }); 52 | 53 | btnLeft.setOnClickListener(v->{ 54 | // if btn skip clicked then we go to page 3 55 | viewPager.setCurrentItem(viewPager.getCurrentItem()+2); 56 | }); 57 | 58 | 59 | } 60 | 61 | //method to create dots from html code 62 | private void addDots(int position){ 63 | dotsLayout.removeAllViews(); 64 | dots = new TextView[3]; 65 | for (int i = 0; i < dots.length; i++) { 66 | dots[i] = new TextView(this); 67 | //this html code creates dot 68 | dots[i].setText(Html.fromHtml("•")); 69 | dots[i].setTextSize(35); 70 | dots[i].setTextColor(getResources().getColor(R.color.colorLightGrey)); 71 | dotsLayout.addView(dots[i]); 72 | } 73 | 74 | // ok now lets change the selected dot color 75 | if(dots.length>0){ 76 | dots[position].setTextColor(getResources().getColor(R.color.colorGrey)); 77 | } 78 | } 79 | 80 | 81 | 82 | private ViewPager.OnPageChangeListener listener = new ViewPager.OnPageChangeListener() { 83 | @Override 84 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 85 | 86 | } 87 | 88 | @Override 89 | public void onPageSelected(int position) { 90 | addDots(position); 91 | //ok now we need to change the text of Next button to Finish if we reached page 3 92 | //and hide Skip button if we are not in page 1 93 | 94 | if(position==0){ 95 | btnLeft.setVisibility(View.VISIBLE); 96 | btnLeft.setEnabled(true); 97 | btnRight.setText("Next"); 98 | } 99 | else if(position==1){ 100 | btnLeft.setVisibility(View.GONE); 101 | btnLeft.setEnabled(false); 102 | btnRight.setText("Next"); 103 | } 104 | else{ 105 | btnLeft.setVisibility(View.GONE); 106 | btnLeft.setEnabled(false); 107 | btnRight.setText("Finish"); 108 | } 109 | } 110 | 111 | @Override 112 | public void onPageScrollStateChanged(int state) { 113 | 114 | } 115 | }; 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | } 128 | -------------------------------------------------------------------------------- /app/src/main/java/com/habib/blogapp/UserInfoActivity.java: -------------------------------------------------------------------------------- 1 | package com.habib.blogapp; 2 | 3 | import androidx.annotation.Nullable; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | 6 | import android.app.ProgressDialog; 7 | import android.content.Context; 8 | import android.content.Intent; 9 | import android.content.SharedPreferences; 10 | import android.graphics.Bitmap; 11 | import android.net.Uri; 12 | import android.os.Bundle; 13 | import android.provider.MediaStore; 14 | import android.util.Base64; 15 | import android.widget.Button; 16 | import android.widget.TextView; 17 | 18 | import com.android.volley.AuthFailureError; 19 | import com.android.volley.Request; 20 | import com.android.volley.RequestQueue; 21 | import com.android.volley.toolbox.StringRequest; 22 | import com.android.volley.toolbox.Volley; 23 | import com.google.android.material.textfield.TextInputEditText; 24 | import com.google.android.material.textfield.TextInputLayout; 25 | 26 | import org.json.JSONException; 27 | import org.json.JSONObject; 28 | 29 | import java.io.ByteArrayOutputStream; 30 | import java.io.IOException; 31 | import java.util.HashMap; 32 | import java.util.Map; 33 | 34 | import de.hdodenhof.circleimageview.CircleImageView; 35 | 36 | public class UserInfoActivity extends AppCompatActivity { 37 | 38 | private TextInputLayout layoutName,layoutLastname; 39 | private TextInputEditText txtName,txtLastname; 40 | private TextView txtSelectPhoto; 41 | private Button btnContinue; 42 | private CircleImageView circleImageView; 43 | private static final int GALLERY_ADD_PROFILE = 1; 44 | private Bitmap bitmap = null; 45 | private SharedPreferences userPref; 46 | private ProgressDialog dialog; 47 | 48 | @Override 49 | protected void onCreate(Bundle savedInstanceState) { 50 | super.onCreate(savedInstanceState); 51 | setContentView(R.layout.activity_user_info); 52 | init(); 53 | } 54 | 55 | private void init() { 56 | dialog = new ProgressDialog(this); 57 | dialog.setCancelable(false); 58 | userPref = getApplicationContext().getSharedPreferences("user", Context.MODE_PRIVATE); 59 | layoutLastname = findViewById(R.id.txtLayoutLastnameameUserInfo); 60 | layoutName = findViewById(R.id.txtLayoutNameUserInfo); 61 | txtName = findViewById(R.id.txtNameUserInfo); 62 | txtLastname = findViewById(R.id.txtLastnameUserInfo); 63 | txtSelectPhoto = findViewById(R.id.txtSelectPhoto); 64 | btnContinue = findViewById(R.id.btnContinue); 65 | circleImageView = findViewById(R.id.imgUserInfo); 66 | 67 | //pick photo from gallery 68 | txtSelectPhoto.setOnClickListener(v->{ 69 | Intent i = new Intent(Intent.ACTION_PICK); 70 | i.setType("image/*"); 71 | startActivityForResult(i,GALLERY_ADD_PROFILE); 72 | }); 73 | 74 | 75 | btnContinue.setOnClickListener(v->{ 76 | // validate fields 77 | if(validate()){ 78 | saveUserInfo(); 79 | } 80 | }); 81 | } 82 | 83 | 84 | @Override 85 | protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { 86 | super.onActivityResult(requestCode, resultCode, data); 87 | if (requestCode==GALLERY_ADD_PROFILE && resultCode==RESULT_OK){ 88 | 89 | Uri imgUri = data.getData(); 90 | circleImageView.setImageURI(imgUri); 91 | 92 | try { 93 | bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(),imgUri); 94 | } catch (IOException e) { 95 | e.printStackTrace(); 96 | } 97 | 98 | } 99 | } 100 | 101 | 102 | private boolean validate(){ 103 | if (txtName.getText().toString().isEmpty()){ 104 | layoutName.setErrorEnabled(true); 105 | layoutName.setError("Name is Required"); 106 | return false; 107 | } 108 | if (txtLastname.getText().toString().isEmpty()){ 109 | layoutLastname.setErrorEnabled(true); 110 | layoutLastname.setError("Lastname is required"); 111 | return false; 112 | } 113 | 114 | return true; 115 | } 116 | 117 | 118 | private void saveUserInfo(){ 119 | dialog.setMessage("Saving"); 120 | dialog.show(); 121 | String name = txtName.getText().toString().trim(); 122 | String lastname = txtLastname.getText().toString().trim(); 123 | 124 | StringRequest request = new StringRequest(Request.Method.POST,Constant.SAVE_USER_INFO,response->{ 125 | 126 | try { 127 | JSONObject object = new JSONObject(response); 128 | if (object.getBoolean("success")){ 129 | SharedPreferences.Editor editor = userPref.edit(); 130 | editor.putString("photo",object.getString("photo")); 131 | editor.apply(); 132 | startActivity(new Intent(UserInfoActivity.this,HomeActivity.class)); 133 | finish(); 134 | } 135 | } catch (JSONException e) { 136 | e.printStackTrace(); 137 | } 138 | 139 | dialog.dismiss(); 140 | 141 | },error ->{ 142 | error.printStackTrace(); 143 | dialog.dismiss(); 144 | } ){ 145 | 146 | //add token to headers 147 | 148 | 149 | @Override 150 | public Map getHeaders() throws AuthFailureError { 151 | String token = userPref.getString("token",""); 152 | HashMap map = new HashMap<>(); 153 | map.put("Authorization","Bearer "+token); 154 | return map; 155 | } 156 | 157 | //add params 158 | 159 | @Override 160 | protected Map getParams() throws AuthFailureError { 161 | HashMap map = new HashMap<>(); 162 | map.put("name",name); 163 | map.put("lastname",lastname); 164 | map.put("photo",bitmapToString(bitmap)); 165 | return map; 166 | } 167 | }; 168 | 169 | RequestQueue queue = Volley.newRequestQueue(UserInfoActivity.this); 170 | queue.add(request); 171 | } 172 | 173 | private String bitmapToString(Bitmap bitmap) { 174 | if (bitmap!=null){ 175 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 176 | bitmap.compress(Bitmap.CompressFormat.JPEG,100,byteArrayOutputStream); 177 | byte [] array = byteArrayOutputStream.toByteArray(); 178 | return Base64.encodeToString(array,Base64.DEFAULT); 179 | } 180 | 181 | return ""; 182 | } 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | } 201 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_comment.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_forever_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_exit_to_app_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_outline.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_favorite_red.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /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_more_vert_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person_outline_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_send_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/p1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibmhamadi/blogapp-android-app/e0827954a329b2dbd487946a78f9ad052b4364e8/app/src/main/res/drawable/p1.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/p2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibmhamadi/blogapp-android-app/e0827954a329b2dbd487946a78f9ad052b4364e8/app/src/main/res/drawable/p2.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/p3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibmhamadi/blogapp-android-app/e0827954a329b2dbd487946a78f9ad052b4364e8/app/src/main/res/drawable/p3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/txt_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/font/leckerlione_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/habibmhamadi/blogapp-android-app/e0827954a329b2dbd487946a78f9ad052b4364e8/app/src/main/res/font/leckerlione_regular.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_add_post.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | 17 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 | 41 | 47 | 48 | 54 | 55 | 63 | 64 | 73 | 74 |