├── LICENSE ├── README.md ├── Screenshots ├── 01.png ├── 02.png ├── 03.png ├── 04.png ├── 05.png └── 06.png ├── app ├── build.gradle.kts ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── ahmadrezagh671 │ │ └── pixabay │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── ahmadrezagh671 │ │ │ └── pixabay │ │ │ ├── ActivitySettings.java │ │ │ ├── Adapters │ │ │ ├── AdapterCategories.java │ │ │ ├── AdapterColors.java │ │ │ └── AdapterPosts.java │ │ │ ├── FragmentCategory.java │ │ │ ├── FragmentColor.java │ │ │ ├── FragmentExplore.java │ │ │ ├── MainActivity.java │ │ │ ├── Models │ │ │ ├── Category.java │ │ │ └── Post.java │ │ │ ├── SettingsActivities │ │ │ └── ActivityAboutUs.java │ │ │ └── Utilities │ │ │ ├── AppUtil.java │ │ │ ├── Display.java │ │ │ ├── FragmentUtil.java │ │ │ ├── UrlApiUtil.java │ │ │ └── VolleySingleton.java │ └── res │ │ ├── drawable │ │ ├── example_image.jpg │ │ ├── example_profile.jpg │ │ ├── ic_3dot.xml │ │ ├── ic_about_us.xml │ │ ├── ic_back.xml │ │ ├── ic_category.xml │ │ ├── ic_color.xml │ │ ├── ic_comment.xml │ │ ├── ic_data_usage.xml │ │ ├── ic_download.xml │ │ ├── ic_dropdown.xml │ │ ├── ic_launcher_background.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── ic_like_border.xml │ │ ├── ic_mark.xml │ │ ├── ic_person.xml │ │ ├── ic_photo.xml │ │ ├── ic_settings.xml │ │ ├── ic_sort.xml │ │ ├── ic_video.xml │ │ ├── navigation_color.xml │ │ ├── shape_background_gradient.xml │ │ ├── shape_circular.xml │ │ ├── shape_rounded.xml │ │ └── shape_rounded_gradient.xml │ │ ├── layout │ │ ├── activity_about_us.xml │ │ ├── activity_main.xml │ │ ├── activity_settings.xml │ │ ├── fragment_category.xml │ │ ├── fragment_color.xml │ │ ├── fragment_explore.xml │ │ ├── recycler_category.xml │ │ └── recycler_post.xml │ │ ├── menu │ │ ├── bottom_menu.xml │ │ └── more_popup_menu.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_o.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-night │ │ └── themes.xml │ │ ├── values-notnight │ │ └── colors.xml │ │ ├── values │ │ ├── array.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ │ └── xml │ │ ├── backup_rules.xml │ │ └── data_extraction_rules.xml │ └── test │ └── java │ └── com │ └── ahmadrezagh671 │ └── pixabay │ └── ExampleUnitTest.java ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle.kts /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 ahmadrezagh671 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Pixabay_Android_App 2 | [![Downloads](https://img.shields.io/github/downloads/ahmadrezagh671/Pixabay_Android_App/total?logo=googleplay&logoColor=white&label=Download)](https://github.com/ahmadrezagh671/Pixabay_Android_App/releases) 3 | 4 | An Android application that uses the [Pixabay API](https://pixabay.com/api/docs/) to browse, search, and download images. 5 | 6 | ## ✨ Features 7 | 8 | - 🔍 Search images using keywords 9 | - 🎨 Filter images by category and color 10 | - ⬇️ Download images 11 | - 🔄 Swipe to refresh content 12 | - 🔍 Pinch-to-zoom on image previews 13 | - 💾 Efficient image loading and caching 14 | - 📱 Responsive UI 15 | 16 | ## 📦 Libraries Used 17 | 18 | - [Volley](https://developer.android.com/training/volley) – Networking 19 | - [Gson](https://github.com/google/gson) – JSON parsing 20 | - [Glide](https://github.com/bumptech/glide) – Image loading 21 | - [AndroidX SwipeRefreshLayout](https://developer.android.com/reference/androidx/swiperefreshlayout/widget/SwipeRefreshLayout) – Pull to refresh 22 | - [CircleImageView](https://github.com/hdodenhof/CircleImageView) – Circular images 23 | - [Zoomy](https://github.com/imablanco/Zoomy) – Image zoom gestures 24 | - [Flexbox Layout](https://github.com/google/flexbox-layout) – Flexible UI design 25 | 26 | ## 📸 Screenshots 27 | 28 | | ![Screenshot 1](Screenshots/01.png) | ![Screenshot 2](Screenshots/02.png) | ![Screenshot 3](Screenshots/03.png) | 29 | |-----------------------------------------|-----------------------------------------|-----------------------------------------| 30 | | ![Screenshot 4](Screenshots/04.png) | ![Screenshot 5](Screenshots/05.png) | ![Screenshot 6](Screenshots/06.png) | 31 | 32 | ## 🚀 Getting Started 33 | 34 | ### Prerequisites 35 | 36 | - Android Studio 37 | - Minimum SDK: 28 (Android 9) 38 | 39 | ### How to Run 40 | 41 | 1. Clone the repository: 42 | ```bash 43 | git clone https://github.com/ahmadrezagh671/Pixabay_Android_App.git 44 | ``` 45 | 3. Open the project in Android Studio. 46 | 4. Add your [Pixabay API](https://pixabay.com/api/docs/) key in local.properties: 47 | ```properties 48 | Pixabay_API_KEY=371469............34f606 49 | ``` 50 | 5. Build and run the app on an emulator or device. 51 | 52 | ## 📄 License 53 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/ahmadrezagh671/Pixabay_Android_App/blob/main/LICENSE) file for details. 54 | -------------------------------------------------------------------------------- /Screenshots/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/01.png -------------------------------------------------------------------------------- /Screenshots/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/02.png -------------------------------------------------------------------------------- /Screenshots/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/03.png -------------------------------------------------------------------------------- /Screenshots/04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/04.png -------------------------------------------------------------------------------- /Screenshots/05.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/05.png -------------------------------------------------------------------------------- /Screenshots/06.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/Screenshots/06.png -------------------------------------------------------------------------------- /app/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Properties 2 | 3 | plugins { 4 | alias(libs.plugins.android.application) 5 | } 6 | 7 | android { 8 | namespace = "com.ahmadrezagh671.pixabay" 9 | compileSdk = 35 10 | 11 | buildFeatures { 12 | buildConfig = true 13 | } 14 | 15 | defaultConfig { 16 | applicationId = "com.ahmadrezagh671.pixabay" 17 | minSdk = 28 18 | targetSdk = 35 19 | versionCode = 3 20 | versionName = "1.2" 21 | 22 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" 23 | 24 | val properties = Properties() 25 | properties.load(rootProject.file("local.properties").inputStream()) 26 | 27 | buildConfigField("String", "Pixabay_API_KEY", "\"${properties.getProperty("Pixabay_API_KEY")}\"") 28 | } 29 | 30 | buildTypes { 31 | release { 32 | isMinifyEnabled = false 33 | proguardFiles( 34 | getDefaultProguardFile("proguard-android-optimize.txt"), 35 | "proguard-rules.pro" 36 | ) 37 | } 38 | } 39 | compileOptions { 40 | sourceCompatibility = JavaVersion.VERSION_11 41 | targetCompatibility = JavaVersion.VERSION_11 42 | } 43 | } 44 | 45 | dependencies { 46 | 47 | implementation("com.android.volley:volley:1.2.1") 48 | implementation("com.google.code.gson:gson:2.13.1") 49 | implementation("com.github.bumptech.glide:glide:4.16.0") 50 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") 51 | implementation("de.hdodenhof:circleimageview:3.1.0") 52 | implementation("io.github.imablanco:zoomy:1.0.0") 53 | implementation("com.google.android.flexbox:flexbox:3.0.0") 54 | 55 | implementation(libs.appcompat) 56 | implementation(libs.material) 57 | implementation(libs.activity) 58 | implementation(libs.constraintlayout) 59 | testImplementation(libs.junit) 60 | androidTestImplementation(libs.ext.junit) 61 | androidTestImplementation(libs.espresso.core) 62 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/androidTest/java/com/ahmadrezagh671/pixabay/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import android.content.Context; 4 | 5 | import androidx.test.platform.app.InstrumentationRegistry; 6 | import androidx.test.ext.junit.runners.AndroidJUnit4; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | 11 | import static org.junit.Assert.*; 12 | 13 | /** 14 | * Instrumented test, which will execute on an Android device. 15 | * 16 | * @see Testing documentation 17 | */ 18 | @RunWith(AndroidJUnit4.class) 19 | public class ExampleInstrumentedTest { 20 | @Test 21 | public void useAppContext() { 22 | // Context of the app under test. 23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 24 | assertEquals("com.ahmadrezagh671.pixabay", appContext.getPackageName()); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 17 | 22 | 27 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/ActivitySettings.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.widget.ImageButton; 7 | import android.widget.TextView; 8 | import android.widget.Toast; 9 | 10 | import androidx.activity.EdgeToEdge; 11 | import androidx.appcompat.app.AppCompatActivity; 12 | import androidx.core.graphics.Insets; 13 | import androidx.core.view.ViewCompat; 14 | import androidx.core.view.WindowInsetsCompat; 15 | 16 | import com.ahmadrezagh671.pixabay.SettingsActivities.ActivityAboutUs; 17 | import com.ahmadrezagh671.pixabay.Utilities.AppUtil; 18 | 19 | public class ActivitySettings extends AppCompatActivity { 20 | 21 | ImageButton backButton; 22 | TextView appVersionTV; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | EdgeToEdge.enable(this); 28 | setContentView(R.layout.activity_settings); 29 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { 30 | Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); 31 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); 32 | return insets; 33 | }); 34 | 35 | appVersionTV = findViewById(R.id.appVersionTV); 36 | appVersionTV.setText("Version " + AppUtil.getAppVersionStr(this)); 37 | 38 | backButton = findViewById(R.id.backButton); 39 | backButton.setOnClickListener(new View.OnClickListener() { 40 | @Override 41 | public void onClick(View view) { 42 | finish(); 43 | } 44 | }); 45 | 46 | } 47 | 48 | public void userAccount(View view) { 49 | Toast.makeText(this, "Coming soon", Toast.LENGTH_SHORT).show(); 50 | } 51 | 52 | public void dataUsage(View view) { 53 | Toast.makeText(this, "Coming soon", Toast.LENGTH_SHORT).show(); 54 | } 55 | 56 | public void aboutUs(View view) { 57 | startActivity(new Intent(ActivitySettings.this, ActivityAboutUs.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 58 | } 59 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Adapters/AdapterCategories.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Adapters; 2 | 3 | import static com.ahmadrezagh671.pixabay.Utilities.AppUtil.capitalizeFirstLetter; 4 | 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | import com.ahmadrezagh671.pixabay.FragmentExplore; 17 | import com.ahmadrezagh671.pixabay.MainActivity; 18 | import com.ahmadrezagh671.pixabay.Models.Category; 19 | import com.ahmadrezagh671.pixabay.R; 20 | import com.ahmadrezagh671.pixabay.Utilities.Display; 21 | import com.bumptech.glide.Glide; 22 | 23 | import java.util.List; 24 | 25 | public class AdapterCategories extends RecyclerView.Adapter { 26 | 27 | List categories; 28 | Context context; 29 | Activity activity; 30 | FragmentExplore fragmentExplore; 31 | 32 | public AdapterCategories(List categories, Context context, Activity activity, FragmentExplore fragmentExplore) { 33 | this.categories = categories; 34 | this.context = context; 35 | this.activity = activity; 36 | this.fragmentExplore = fragmentExplore; 37 | } 38 | 39 | @NonNull 40 | @Override 41 | public AdapterCategories.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 42 | View view = LayoutInflater.from(context).inflate(R.layout.recycler_category,parent,false); 43 | ViewHolder viewHolder = new ViewHolder(view); 44 | return viewHolder; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(@NonNull AdapterCategories.ViewHolder holder, int position) { 49 | Category item = categories.get(position); 50 | 51 | holder.setImageViewWidth(); 52 | holder.setImageView(item.getImageURL()); 53 | holder.textView.setText(capitalizeFirstLetter(item.getName())); 54 | 55 | holder.view.setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View v) { 58 | fragmentExplore.setCategory(capitalizeFirstLetter(item.getName())); 59 | ((MainActivity)activity).changeFragment(R.id.menuExplore); 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return categories.size(); 67 | } 68 | 69 | public class ViewHolder extends RecyclerView.ViewHolder { 70 | 71 | ImageView imageView; 72 | TextView textView; 73 | View view; 74 | 75 | public ViewHolder(@NonNull View itemView) { 76 | super(itemView); 77 | 78 | imageView = itemView.findViewById(R.id.imageView); 79 | textView = itemView.findViewById(R.id.textView); 80 | 81 | view = itemView; 82 | } 83 | 84 | public void setImageView(String url){ 85 | Glide.with(context).load(url).fitCenter().into(imageView); 86 | } 87 | 88 | public void setImageViewWidth() { 89 | Display.setImageViewWidthHalfScreen(imageView, activity); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Adapters/AdapterColors.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Adapters; 2 | 3 | import static com.ahmadrezagh671.pixabay.Utilities.AppUtil.capitalizeFirstLetter; 4 | 5 | import android.app.Activity; 6 | import android.content.Context; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | import com.ahmadrezagh671.pixabay.FragmentExplore; 17 | import com.ahmadrezagh671.pixabay.MainActivity; 18 | import com.ahmadrezagh671.pixabay.Models.Category; 19 | import com.ahmadrezagh671.pixabay.R; 20 | import com.ahmadrezagh671.pixabay.Utilities.Display; 21 | import com.bumptech.glide.Glide; 22 | 23 | import java.util.List; 24 | 25 | public class AdapterColors extends RecyclerView.Adapter { 26 | 27 | List categories; 28 | Context context; 29 | Activity activity; 30 | FragmentExplore fragmentExplore; 31 | 32 | public AdapterColors(List categories, Context context, Activity activity, FragmentExplore fragmentExplore) { 33 | this.categories = categories; 34 | this.context = context; 35 | this.activity = activity; 36 | this.fragmentExplore = fragmentExplore; 37 | } 38 | 39 | @NonNull 40 | @Override 41 | public AdapterColors.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 42 | View view = LayoutInflater.from(context).inflate(R.layout.recycler_category,parent,false); 43 | ViewHolder viewHolder = new ViewHolder(view); 44 | return viewHolder; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(@NonNull AdapterColors.ViewHolder holder, int position) { 49 | Category item = categories.get(position); 50 | 51 | holder.setImageViewWidth(); 52 | holder.setImageView(item.getImageURL()); 53 | holder.textView.setText(capitalizeFirstLetter(item.getName())); 54 | 55 | holder.view.setOnClickListener(new View.OnClickListener() { 56 | @Override 57 | public void onClick(View v) { 58 | fragmentExplore.setColor(capitalizeFirstLetter(item.getName())); 59 | ((MainActivity)activity).changeFragment(R.id.menuExplore); 60 | } 61 | }); 62 | } 63 | 64 | @Override 65 | public int getItemCount() { 66 | return categories.size(); 67 | } 68 | 69 | public class ViewHolder extends RecyclerView.ViewHolder { 70 | 71 | ImageView imageView; 72 | TextView textView; 73 | View view; 74 | 75 | public ViewHolder(@NonNull View itemView) { 76 | super(itemView); 77 | 78 | imageView = itemView.findViewById(R.id.imageView); 79 | textView = itemView.findViewById(R.id.textView); 80 | 81 | view = itemView; 82 | } 83 | 84 | public void setImageView(String url){ 85 | Glide.with(context).load(url).fitCenter().into(imageView); 86 | } 87 | 88 | public void setImageViewWidth() { 89 | Display.setImageViewWidthHalfScreen(imageView, activity); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Adapters/AdapterPosts.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Adapters; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.util.Log; 6 | import android.view.LayoutInflater; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageButton; 11 | import android.widget.ImageView; 12 | import android.widget.PopupMenu; 13 | import android.widget.TextView; 14 | 15 | import androidx.annotation.NonNull; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | import com.ablanco.zoomy.Zoomy; 19 | import com.ahmadrezagh671.pixabay.Models.Post; 20 | import com.ahmadrezagh671.pixabay.R; 21 | import com.ahmadrezagh671.pixabay.Utilities.AppUtil; 22 | import com.ahmadrezagh671.pixabay.Utilities.Display; 23 | import com.bumptech.glide.Glide; 24 | 25 | import java.util.List; 26 | 27 | public class AdapterPosts extends RecyclerView.Adapter { 28 | 29 | List posts; 30 | Context context; 31 | Activity activity; 32 | 33 | public AdapterPosts(List posts, Context context, Activity activity) { 34 | this.posts = posts; 35 | this.context = context; 36 | this.activity = activity; 37 | } 38 | 39 | @NonNull 40 | @Override 41 | public AdapterPosts.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 42 | View view = LayoutInflater.from(context).inflate(R.layout.recycler_post,parent,false); 43 | ViewHolder viewHolder = new ViewHolder(view); 44 | return viewHolder; 45 | } 46 | 47 | @Override 48 | public void onBindViewHolder(@NonNull AdapterPosts.ViewHolder holder, int position) { 49 | Post post = posts.get(position); 50 | holder.setImageViewHeightAndWidth(post.getWebformatHeight(), post.getWebformatWidth()); 51 | holder.setImageView(post.getWebformatURL()); 52 | holder.setProfilePic(post.getUserImageURL()); 53 | holder.usernameTV.setText(post.getUser()); 54 | holder.postTypeTV.setText(post.getType()); 55 | holder.tagsTV.setText(post.getTags()); 56 | holder.likeTV.setText(String.valueOf(post.getLikes())); 57 | holder.commentTV.setText(String.valueOf(post.getComments())); 58 | holder.downloadTV.setText(String.valueOf(post.getDownloads())); 59 | 60 | holder.moreIB.setOnClickListener(new View.OnClickListener() { 61 | @Override 62 | public void onClick(View v) { 63 | PopupMenu popup = new PopupMenu(activity, v); 64 | popup.getMenuInflater().inflate(R.menu.more_popup_menu, popup.getMenu()); 65 | popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 66 | public boolean onMenuItemClick(MenuItem item) { 67 | int id = item.getItemId(); 68 | if (id == R.id.menuOpenPage){ 69 | AppUtil.openLink(post.getPageURL(),context); 70 | } else if (id == R.id.menuDownload) { 71 | String[] temp = post.getLargeImageURL().split("\\."); 72 | String fileName = post.getUser() + post.getId() + "." +temp[temp.length-1]; 73 | Log.i("fileName", "onMenuItemClick: " + fileName); 74 | AppUtil.downloadFile(post.getLargeImageURL(),fileName,activity); 75 | } 76 | return true; 77 | } 78 | }); 79 | 80 | popup.show(); 81 | } 82 | }); 83 | } 84 | 85 | @Override 86 | public int getItemCount() { 87 | return posts.size(); 88 | } 89 | 90 | public class ViewHolder extends RecyclerView.ViewHolder { 91 | 92 | ImageView imageView,profilePic; 93 | TextView usernameTV,postTypeTV; 94 | TextView likeTV,commentTV,downloadTV,tagsTV; 95 | ImageButton moreIB; 96 | 97 | View view; 98 | 99 | public ViewHolder(@NonNull View itemView) { 100 | super(itemView); 101 | view = itemView; 102 | imageView = view.findViewById(R.id.imageView); 103 | profilePic = view.findViewById(R.id.profilePic); 104 | usernameTV = view.findViewById(R.id.usernameTV); 105 | postTypeTV = view.findViewById(R.id.postTypeTV); 106 | likeTV = view.findViewById(R.id.likeTV); 107 | commentTV = view.findViewById(R.id.commentTV); 108 | downloadTV = view.findViewById(R.id.downloadTV); 109 | moreIB = view.findViewById(R.id.moreIB); 110 | tagsTV = view.findViewById(R.id.tagsTV); 111 | 112 | } 113 | 114 | public void setImageView(String url){ 115 | Glide.with(context).load(url).fitCenter().into(imageView); 116 | new Zoomy.Builder(activity) 117 | .target(imageView) 118 | .enableImmersiveMode(false) 119 | .animateZooming(false) 120 | .register(); 121 | } 122 | public void setProfilePic(String url){ 123 | if (!url.isEmpty()) 124 | Glide.with(context).load(url).fitCenter().into(profilePic); 125 | else 126 | profilePic.setImageResource(R.drawable.example_profile); 127 | } 128 | public void setImageViewHeightAndWidth(int height, int width) { 129 | Display.setImageViewHeightAndWidth(imageView, height, width, activity); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/FragmentCategory.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | import androidx.fragment.app.Fragment; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.ahmadrezagh671.pixabay.Adapters.AdapterCategories; 15 | import com.ahmadrezagh671.pixabay.Models.Category; 16 | import com.ahmadrezagh671.pixabay.Utilities.UrlApiUtil; 17 | import com.android.volley.RequestQueue; 18 | import com.android.volley.Response; 19 | import com.android.volley.VolleyError; 20 | import com.android.volley.toolbox.JsonObjectRequest; 21 | import com.android.volley.toolbox.Volley; 22 | import com.google.android.flexbox.FlexDirection; 23 | import com.google.android.flexbox.FlexboxLayoutManager; 24 | import com.google.android.flexbox.JustifyContent; 25 | 26 | import org.json.JSONException; 27 | import org.json.JSONObject; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | import java.util.Random; 32 | 33 | 34 | public class FragmentCategory extends Fragment { 35 | 36 | RecyclerView recyclerView; 37 | AdapterCategories adapterCategories; 38 | List categories; 39 | FlexboxLayoutManager layoutManagerFlex; 40 | 41 | RequestQueue requestQueue; 42 | 43 | FragmentExplore fragmentExplore; 44 | 45 | public FragmentCategory() { 46 | 47 | } 48 | 49 | public FragmentCategory(FragmentExplore fragmentExplore) { 50 | this.fragmentExplore = fragmentExplore; 51 | } 52 | 53 | public static FragmentCategory newInstance() { 54 | FragmentCategory fragment = new FragmentCategory(); 55 | return fragment; 56 | } 57 | 58 | @Override 59 | public void onCreate(Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | 62 | categories = new ArrayList<>(); 63 | 64 | requestQueue = Volley.newRequestQueue(getContext()); 65 | 66 | } 67 | 68 | @Override 69 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 70 | Bundle savedInstanceState) { 71 | // Inflate the layout for this fragment 72 | View view = inflater.inflate(R.layout.fragment_category, container, false); 73 | 74 | layoutManagerFlex = new FlexboxLayoutManager(getContext()); 75 | layoutManagerFlex.setFlexDirection(FlexDirection.ROW); 76 | layoutManagerFlex.setJustifyContent(JustifyContent.SPACE_EVENLY); 77 | 78 | recyclerView = view.findViewById(R.id.recyclerView); 79 | recyclerView.setHasFixedSize(true); 80 | recyclerView.setLayoutManager(layoutManagerFlex); 81 | 82 | return view; 83 | } 84 | 85 | @Override 86 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 87 | super.onViewCreated(view, savedInstanceState); 88 | 89 | requestQueue.stop(); 90 | 91 | String[] category_array= getResources().getStringArray(R.array.category_array); 92 | 93 | for (String category:category_array) { 94 | String url = UrlApiUtil.getCategoryUrl(category); 95 | 96 | JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener() { 97 | @Override 98 | public void onResponse(JSONObject response) { 99 | try { 100 | JSONObject jsonObject = response.getJSONArray("hits").getJSONObject(new Random().nextInt(3)); 101 | 102 | Category newCategory = new Category(category,jsonObject.getString("webformatURL")); 103 | categories.add(newCategory); 104 | 105 | if (category.equals(category_array[category_array.length-1])){ 106 | adapterCategories = new AdapterCategories(categories,getContext(),getActivity(),fragmentExplore); 107 | recyclerView.setAdapter(adapterCategories); 108 | } 109 | 110 | } catch (JSONException e) { 111 | throw new RuntimeException(e); 112 | } 113 | } 114 | }, new Response.ErrorListener() { 115 | @Override 116 | public void onErrorResponse(VolleyError error) { 117 | Category newCategory = new Category(category,""); 118 | categories.add(newCategory); 119 | 120 | if (category.equals(category_array[category_array.length-1])){ 121 | adapterCategories = new AdapterCategories(categories,getContext(),getActivity(),fragmentExplore); 122 | recyclerView.setAdapter(adapterCategories); 123 | } 124 | } 125 | }); 126 | 127 | requestQueue.add(jsonObjectRequest); 128 | } 129 | requestQueue.start(); 130 | 131 | } 132 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/FragmentColor.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.annotation.Nullable; 7 | import androidx.fragment.app.Fragment; 8 | import androidx.recyclerview.widget.RecyclerView; 9 | 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | 14 | import com.ahmadrezagh671.pixabay.Adapters.AdapterColors; 15 | import com.ahmadrezagh671.pixabay.Models.Category; 16 | import com.ahmadrezagh671.pixabay.Utilities.UrlApiUtil; 17 | import com.android.volley.RequestQueue; 18 | import com.android.volley.Response; 19 | import com.android.volley.VolleyError; 20 | import com.android.volley.toolbox.JsonObjectRequest; 21 | import com.android.volley.toolbox.Volley; 22 | import com.google.android.flexbox.FlexDirection; 23 | import com.google.android.flexbox.FlexboxLayoutManager; 24 | import com.google.android.flexbox.JustifyContent; 25 | 26 | import org.json.JSONException; 27 | import org.json.JSONObject; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | import java.util.Random; 32 | 33 | 34 | public class FragmentColor extends Fragment { 35 | 36 | RecyclerView recyclerView; 37 | AdapterColors adapterColors; 38 | List colors; 39 | FlexboxLayoutManager layoutManagerFlex; 40 | 41 | RequestQueue requestQueue; 42 | 43 | FragmentExplore fragmentExplore; 44 | 45 | public FragmentColor() { 46 | 47 | } 48 | 49 | public FragmentColor(FragmentExplore fragmentExplore) { 50 | this.fragmentExplore = fragmentExplore; 51 | } 52 | 53 | public static FragmentColor newInstance() { 54 | FragmentColor fragment = new FragmentColor(); 55 | return fragment; 56 | } 57 | 58 | @Override 59 | public void onCreate(Bundle savedInstanceState) { 60 | super.onCreate(savedInstanceState); 61 | 62 | colors = new ArrayList<>(); 63 | 64 | requestQueue = Volley.newRequestQueue(getContext()); 65 | 66 | } 67 | 68 | @Override 69 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 70 | Bundle savedInstanceState) { 71 | // Inflate the layout for this fragment 72 | View view = inflater.inflate(R.layout.fragment_color, container, false); 73 | 74 | layoutManagerFlex = new FlexboxLayoutManager(getContext()); 75 | layoutManagerFlex.setFlexDirection(FlexDirection.ROW); 76 | layoutManagerFlex.setJustifyContent(JustifyContent.SPACE_EVENLY); 77 | 78 | recyclerView = view.findViewById(R.id.recyclerView); 79 | recyclerView.setHasFixedSize(true); 80 | recyclerView.setLayoutManager(layoutManagerFlex); 81 | 82 | return view; 83 | } 84 | 85 | @Override 86 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 87 | super.onViewCreated(view, savedInstanceState); 88 | 89 | requestQueue.stop(); 90 | 91 | String[] color_array= getResources().getStringArray(R.array.color_array); 92 | 93 | for (String color:color_array) { 94 | String url = UrlApiUtil.getColorUrl(color); 95 | 96 | JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener() { 97 | @Override 98 | public void onResponse(JSONObject response) { 99 | try { 100 | JSONObject jsonObject = response.getJSONArray("hits").getJSONObject(new Random().nextInt(3)); 101 | 102 | Category newCategory = new Category(color,jsonObject.getString("webformatURL")); 103 | colors.add(newCategory); 104 | 105 | if (color.equals(color_array[color_array.length-1])){ 106 | adapterColors = new AdapterColors(colors,getContext(),getActivity(),fragmentExplore); 107 | recyclerView.setAdapter(adapterColors); 108 | } 109 | 110 | } catch (JSONException e) { 111 | throw new RuntimeException(e); 112 | } 113 | } 114 | }, new Response.ErrorListener() { 115 | @Override 116 | public void onErrorResponse(VolleyError error) { 117 | Category newCategory = new Category(color,""); 118 | colors.add(newCategory); 119 | 120 | if (color.equals(color_array[color_array.length-1])){ 121 | adapterColors = new AdapterColors(colors,getContext(),getActivity(),fragmentExplore); 122 | recyclerView.setAdapter(adapterColors); 123 | } 124 | } 125 | }); 126 | 127 | requestQueue.add(jsonObjectRequest); 128 | } 129 | requestQueue.start(); 130 | 131 | } 132 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/FragmentExplore.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import static android.view.View.GONE; 4 | import static android.view.View.VISIBLE; 5 | 6 | import android.content.Intent; 7 | import android.os.Bundle; 8 | 9 | import androidx.annotation.NonNull; 10 | import androidx.annotation.Nullable; 11 | import androidx.constraintlayout.widget.ConstraintLayout; 12 | import androidx.fragment.app.Fragment; 13 | import androidx.recyclerview.widget.LinearLayoutManager; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; 16 | 17 | import android.util.Log; 18 | import android.view.LayoutInflater; 19 | import android.view.View; 20 | import android.view.ViewGroup; 21 | 22 | import android.widget.Button; 23 | import android.widget.ImageButton; 24 | import android.widget.LinearLayout; 25 | import android.widget.SearchView; 26 | import android.widget.TextView; 27 | import android.widget.Toast; 28 | 29 | import com.ahmadrezagh671.pixabay.Adapters.AdapterPosts; 30 | import com.ahmadrezagh671.pixabay.Models.Post; 31 | import com.ahmadrezagh671.pixabay.Utilities.UrlApiUtil; 32 | import com.ahmadrezagh671.pixabay.Utilities.VolleySingleton; 33 | import com.android.volley.RequestQueue; 34 | import com.android.volley.Response; 35 | import com.android.volley.VolleyError; 36 | import com.android.volley.toolbox.JsonObjectRequest; 37 | import com.google.gson.Gson; 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.List; 45 | 46 | public class FragmentExplore extends Fragment implements SwipeRefreshLayout.OnRefreshListener, SearchView.OnQueryTextListener { 47 | 48 | private static final String TAG = "FragmentExplore"; 49 | RecyclerView recyclerView; 50 | AdapterPosts adapterPosts; 51 | List posts; 52 | RequestQueue requestQueue; 53 | 54 | SearchView searchView; 55 | String[] lastSearchWords; 56 | 57 | SwipeRefreshLayout swipeRefreshLayout; 58 | Button categorySelectorBTN,colorSelectorBTN,latestBTN; 59 | ImageButton settingsIB; 60 | 61 | ConstraintLayout topDiscoverLayout; 62 | LinearLayout topFilterLayout; 63 | 64 | Button tryAgainButton; 65 | TextView errorTV; 66 | 67 | boolean latestEnable = false; 68 | 69 | public FragmentExplore() { 70 | 71 | } 72 | 73 | 74 | public static FragmentExplore newInstance() { 75 | FragmentExplore fragment = new FragmentExplore(); 76 | return fragment; 77 | } 78 | 79 | @Override 80 | public void onCreate(Bundle savedInstanceState) { 81 | super.onCreate(savedInstanceState); 82 | 83 | posts = new ArrayList<>(); 84 | lastSearchWords = new String[]{}; 85 | 86 | requestQueue = VolleySingleton.getmInstance(getContext()).getRequestQueue(); 87 | } 88 | 89 | @Override 90 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 91 | Bundle savedInstanceState) { 92 | // Inflate the layout for this fragment 93 | View view = inflater.inflate(R.layout.fragment_explore, container, false); 94 | 95 | topDiscoverLayout = view.findViewById(R.id.topDiscoverLayout); 96 | topFilterLayout = view.findViewById(R.id.topFilterLayout); 97 | 98 | recyclerView = view.findViewById(R.id.recyclerView); 99 | recyclerView.setHasFixedSize(true); 100 | recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); 101 | 102 | searchView = view.findViewById(R.id.searchView); 103 | searchView.setOnQueryTextListener(this); 104 | searchView.setOnClickListener(this::onSearchViewClick); 105 | 106 | swipeRefreshLayout = view.findViewById(R.id.SwipeRefreshLayout); 107 | swipeRefreshLayout.setOnRefreshListener(this); 108 | 109 | settingsIB = view.findViewById(R.id.settingsIB); 110 | settingsIB.setOnClickListener(this::onSettingsClick); 111 | 112 | categorySelectorBTN = view.findViewById(R.id.categorySelectorBTN); 113 | categorySelectorBTN.setOnClickListener(this::onClickCategorySelectorBTN); 114 | colorSelectorBTN = view.findViewById(R.id.colorSelectorBTN); 115 | colorSelectorBTN.setOnClickListener(this::onClickColorSelectorBTN); 116 | latestBTN = view.findViewById(R.id.latestBTN); 117 | latestBTN.setOnClickListener(this::onClickLatestBTN); 118 | 119 | tryAgainButton = view.findViewById(R.id.tryAgainButton); 120 | tryAgainButton.setOnClickListener(v -> reload()); 121 | 122 | errorTV = view.findViewById(R.id.errorTV); 123 | 124 | final int[] state = new int[1]; 125 | 126 | recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 127 | @Override 128 | public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 129 | super.onScrollStateChanged(recyclerView, newState); 130 | state[0] = newState; 131 | } 132 | 133 | @Override 134 | public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 135 | super.onScrolled(recyclerView, dx, dy); 136 | 137 | int firstVisibleItem = ((LinearLayoutManager)recyclerView.getLayoutManager()).findFirstVisibleItemPosition(); 138 | 139 | if(firstVisibleItem == 0){ 140 | topItemsVisible(true); 141 | } else if (dy > 50){ 142 | if (state[0] == 0 || state[0] == 2){ 143 | topItemsVisible(false); 144 | } 145 | }else if (dy < -160){ 146 | if (state[0] == 0 || state[0] == 2){ 147 | topItemsVisible(true); 148 | } 149 | } 150 | } 151 | }); 152 | 153 | return view; 154 | } 155 | 156 | 157 | 158 | @Override 159 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { 160 | super.onViewCreated(view, savedInstanceState); 161 | 162 | reload(); 163 | } 164 | 165 | private void requestPostsFromApi(@Nullable String[] words) { 166 | refreshing(true); 167 | 168 | String category = getCategoryF(); 169 | String color = getColorF(); 170 | 171 | requestQueue.cancelAll(true); 172 | 173 | lastSearchWords = words==null ? new String[]{} : words; 174 | 175 | String url = UrlApiUtil.getPhotosUrl(lastSearchWords,category,color,latestEnable); 176 | Log.i(TAG, "requestPostsFromApi: " + url); 177 | 178 | JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener() { 179 | @Override 180 | public void onResponse(JSONObject response) { 181 | try { 182 | JSONArray jsonArray = response.getJSONArray("hits"); 183 | 184 | Gson gson = new Gson(); 185 | 186 | posts.clear(); 187 | 188 | for (int i = 0; i < jsonArray.length(); i++) { 189 | JSONObject jsonObject = jsonArray.getJSONObject(i); 190 | Post item = gson.fromJson(jsonObject.toString(), Post.class); 191 | posts.add(item); 192 | } 193 | 194 | if (posts.isEmpty()) { 195 | errorTV.setText("Nothing Found"); 196 | errorTV.setVisibility(VISIBLE); 197 | } 198 | 199 | if(adapterPosts == null) { 200 | adapterPosts = new AdapterPosts(posts, getContext(), getActivity()); 201 | recyclerView.setAdapter(adapterPosts); 202 | }else { 203 | recyclerView.scrollToPosition(0); 204 | adapterPosts.notifyDataSetChanged(); 205 | } 206 | 207 | } catch (JSONException e) { 208 | //throw new RuntimeException(e); 209 | if (posts.isEmpty()) { 210 | errorTV.setText("Something is wrong"); 211 | errorTV.setVisibility(VISIBLE); 212 | } 213 | } 214 | refreshing(false); 215 | } 216 | }, new Response.ErrorListener() { 217 | @Override 218 | public void onErrorResponse(VolleyError error) { 219 | refreshing(false); 220 | //Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show(); 221 | tryAgainButton.setVisibility(VISIBLE); 222 | } 223 | }); 224 | 225 | requestQueue.add(jsonObjectRequest); 226 | } 227 | 228 | @Override 229 | public void onRefresh() { 230 | reload(); 231 | } 232 | 233 | public String[] getSearchViewQuery(){ 234 | lastSearchWords = searchView.getQuery().toString().split(" "); 235 | if (lastSearchWords.length == 0) 236 | return null; 237 | else 238 | return lastSearchWords; 239 | } 240 | 241 | @Override 242 | public boolean onQueryTextSubmit(String query) { 243 | reload(); 244 | topItemsVisible(true); 245 | return false; 246 | } 247 | 248 | @Override 249 | public boolean onQueryTextChange(String newText) { 250 | if (newText.isEmpty() && lastSearchWords.length >= 1) { 251 | reload(); 252 | } 253 | return false; 254 | } 255 | 256 | private void refreshing(boolean state){ 257 | swipeRefreshLayout.setRefreshing(state); 258 | } 259 | 260 | private String getCategoryF(){ 261 | String category = categorySelectorBTN.getText().toString().split(" ")[0].toLowerCase(); 262 | if (category.equals("category")){ 263 | return "none"; 264 | }else { 265 | return category; 266 | } 267 | } 268 | private String getColorF(){ 269 | String color = colorSelectorBTN.getText().toString().split(" ")[0].toLowerCase(); 270 | if (color.equals("color")){ 271 | return "none"; 272 | }else { 273 | return color; 274 | } 275 | } 276 | 277 | public void onClickLatestBTN(View view) { 278 | if (latestEnable){ 279 | latestEnable = false; 280 | latestBTN.setBackground(getResources().getDrawable(R.drawable.shape_rounded)); 281 | }else { 282 | latestEnable = true; 283 | latestBTN.setBackground(getResources().getDrawable(R.drawable.shape_rounded_gradient)); 284 | } 285 | reload(); 286 | } 287 | 288 | private void onSearchViewClick(View view) { 289 | topItemsVisible(true); 290 | } 291 | 292 | public void onClickColorSelectorBTN(View view) { 293 | ((MainActivity)getActivity()).changeFragment(R.id.menuColor); 294 | } 295 | 296 | public void onClickCategorySelectorBTN(View view) { 297 | ((MainActivity)getActivity()).changeFragment(R.id.menuCategory); 298 | } 299 | 300 | private void onSettingsClick(View view) { 301 | startActivity(new Intent(getContext(),ActivitySettings.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); 302 | } 303 | 304 | private void topItemsVisible(boolean b) { 305 | if (b){ 306 | topDiscoverLayout.setVisibility(View.VISIBLE); 307 | topFilterLayout.setVisibility(View.VISIBLE); 308 | }else { 309 | topFilterLayout.setVisibility(View.GONE); 310 | topDiscoverLayout.setVisibility(View.GONE); 311 | } 312 | } 313 | 314 | private void reload(){ 315 | requestPostsFromApi(getSearchViewQuery()); 316 | tryAgainButton.setVisibility(GONE); 317 | errorTV.setVisibility(GONE); 318 | } 319 | 320 | public void setCategory(String string){ 321 | if (string.equals("None")) string = "Category"; 322 | categorySelectorBTN.setText(string + " ☰"); 323 | reload(); 324 | } 325 | public void setColor(String string){ 326 | if (string.equals("None")) string = "Color"; 327 | colorSelectorBTN.setText(string + " ☰"); 328 | reload(); 329 | } 330 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay; 2 | 3 | import android.os.Bundle; 4 | import android.view.MenuItem; 5 | 6 | import androidx.activity.EdgeToEdge; 7 | import androidx.annotation.NonNull; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import androidx.core.graphics.Insets; 10 | import androidx.core.view.ViewCompat; 11 | import androidx.core.view.WindowInsetsCompat; 12 | import androidx.fragment.app.Fragment; 13 | import androidx.fragment.app.FragmentManager; 14 | 15 | import com.ahmadrezagh671.pixabay.Utilities.FragmentUtil; 16 | import com.google.android.material.bottomnavigation.BottomNavigationView; 17 | import com.google.android.material.navigation.NavigationBarView; 18 | 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | 22 | FragmentExplore fragmentExplore; 23 | FragmentCategory fragmentCategory; 24 | FragmentColor fragmentColor; 25 | 26 | BottomNavigationView buttonNavView; 27 | 28 | FragmentManager fragmentManager; 29 | Fragment lastFragment; 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | EdgeToEdge.enable(this); 35 | setContentView(R.layout.activity_main); 36 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { 37 | Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); 38 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); 39 | return insets; 40 | }); 41 | 42 | buttonNavView = findViewById(R.id.buttonNavView); 43 | 44 | // fix bottom padding bug 45 | buttonNavView.setOnApplyWindowInsetsListener(null); 46 | buttonNavView.setPadding(0,0,0,0); 47 | 48 | fragmentManager = getSupportFragmentManager(); 49 | fragmentExplore = new FragmentExplore(); 50 | fragmentCategory = new FragmentCategory(fragmentExplore); 51 | fragmentColor = new FragmentColor(fragmentExplore); 52 | 53 | buttonNavView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { 54 | @Override 55 | public boolean onNavigationItemSelected(@NonNull MenuItem item) { 56 | int id = item.getItemId(); 57 | 58 | if (id == R.id.menuExplore){ 59 | lastFragment = FragmentUtil.openFragment(fragmentManager,R.id.frame_Layout, fragmentExplore,lastFragment); 60 | } else if (id == R.id.menuCategory) { 61 | lastFragment = FragmentUtil.openFragment(fragmentManager, R.id.frame_Layout, fragmentCategory, lastFragment); 62 | } else if (id == R.id.menuColor) { 63 | lastFragment = FragmentUtil.openFragment(fragmentManager, R.id.frame_Layout, fragmentColor, lastFragment); 64 | } 65 | 66 | return true; 67 | } 68 | }); 69 | 70 | buttonNavView.setSelectedItemId(R.id.menuExplore); 71 | } 72 | 73 | public void changeFragment(int id){ 74 | buttonNavView.setSelectedItemId(id); 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Models/Category.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Models; 2 | 3 | public class Category { 4 | 5 | String name,imageURL; 6 | 7 | public Category(String name, String imageURL) { 8 | this.name = name; 9 | this.imageURL = imageURL; 10 | } 11 | 12 | public String getName() { 13 | return name; 14 | } 15 | 16 | public void setName(String name) { 17 | this.name = name; 18 | } 19 | 20 | public String getImageURL() { 21 | return imageURL; 22 | } 23 | 24 | public void setImageURL(String imageURL) { 25 | this.imageURL = imageURL; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Models/Post.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Models; 2 | 3 | public class Post { 4 | 5 | int id,previewWidth,previewHeight,webformatWidth,webformatHeight,imageWidth,imageHeight,imageSize,views,downloads,collections,likes,comments,user_id; 6 | String pageURL,type,tags,previewURL,webformatURL,largeImageURL,user,userImageURL; 7 | boolean noAiTraining; 8 | 9 | public Post(int id, int previewWidth, int previewHeight, int webformatWidth, int webformatHeight, int imageWidth, int imageHeight, int imageSize, int views, int downloads, int collections, int likes, int comments, int user_id, String pageURL, String type, String tags, String previewURL, String webformatURL, String largeImageURL, String user, String userImageURL, boolean noAiTraining) { 10 | this.id = id; 11 | this.previewWidth = previewWidth; 12 | this.previewHeight = previewHeight; 13 | this.webformatWidth = webformatWidth; 14 | this.webformatHeight = webformatHeight; 15 | this.imageWidth = imageWidth; 16 | this.imageHeight = imageHeight; 17 | this.imageSize = imageSize; 18 | this.views = views; 19 | this.downloads = downloads; 20 | this.collections = collections; 21 | this.likes = likes; 22 | this.comments = comments; 23 | this.user_id = user_id; 24 | this.pageURL = pageURL; 25 | this.type = type; 26 | this.tags = tags; 27 | this.previewURL = previewURL; 28 | this.webformatURL = webformatURL; 29 | this.largeImageURL = largeImageURL; 30 | this.user = user; 31 | this.userImageURL = userImageURL; 32 | this.noAiTraining = noAiTraining; 33 | } 34 | 35 | public int getId() { 36 | return id; 37 | } 38 | 39 | public int getPreviewWidth() { 40 | return previewWidth; 41 | } 42 | 43 | public int getPreviewHeight() { 44 | return previewHeight; 45 | } 46 | 47 | public int getWebformatWidth() { 48 | return webformatWidth; 49 | } 50 | 51 | public int getWebformatHeight() { 52 | return webformatHeight; 53 | } 54 | 55 | public int getImageWidth() { 56 | return imageWidth; 57 | } 58 | 59 | public int getImageHeight() { 60 | return imageHeight; 61 | } 62 | 63 | public int getImageSize() { 64 | return imageSize; 65 | } 66 | 67 | public int getViews() { 68 | return views; 69 | } 70 | 71 | public int getDownloads() { 72 | return downloads; 73 | } 74 | 75 | public int getCollections() { 76 | return collections; 77 | } 78 | 79 | public int getLikes() { 80 | return likes; 81 | } 82 | 83 | public int getComments() { 84 | return comments; 85 | } 86 | 87 | public int getUser_id() { 88 | return user_id; 89 | } 90 | 91 | public String getPageURL() { 92 | return pageURL; 93 | } 94 | 95 | public String getType() { 96 | return type; 97 | } 98 | 99 | public String getTags() { 100 | return tags; 101 | } 102 | 103 | public String getPreviewURL() { 104 | return previewURL; 105 | } 106 | 107 | public String getWebformatURL() { 108 | return webformatURL; 109 | } 110 | 111 | public String getLargeImageURL() { 112 | return largeImageURL; 113 | } 114 | 115 | public String getUser() { 116 | return user; 117 | } 118 | 119 | public String getUserImageURL() { 120 | return userImageURL; 121 | } 122 | 123 | public boolean isNoAiTraining() { 124 | return noAiTraining; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/SettingsActivities/ActivityAboutUs.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.SettingsActivities; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.ImageButton; 8 | import android.widget.TextView; 9 | import android.widget.Toast; 10 | 11 | import androidx.activity.EdgeToEdge; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | import androidx.core.graphics.Insets; 14 | import androidx.core.view.ViewCompat; 15 | import androidx.core.view.WindowInsetsCompat; 16 | 17 | import com.ahmadrezagh671.pixabay.R; 18 | import com.ahmadrezagh671.pixabay.Utilities.AppUtil; 19 | 20 | public class ActivityAboutUs extends AppCompatActivity { 21 | 22 | ImageButton backButton; 23 | TextView appVersionTV; 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | EdgeToEdge.enable(this); 29 | setContentView(R.layout.activity_about_us); 30 | ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> { 31 | Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()); 32 | v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom); 33 | return insets; 34 | }); 35 | 36 | appVersionTV = findViewById(R.id.appVersionTV); 37 | appVersionTV.setText("Version " + AppUtil.getAppVersionStr(this)); 38 | 39 | backButton = findViewById(R.id.backButton); 40 | backButton.setOnClickListener(new View.OnClickListener() { 41 | @Override 42 | public void onClick(View view) { 43 | finish(); 44 | } 45 | }); 46 | } 47 | 48 | public void openGithub(View view) { 49 | AppUtil.openLink(getResources().getString(R.string.githubLink),this); 50 | } 51 | 52 | public void contactUs(View view) { 53 | String email = "ahmadrezagh671@gmail.com"; 54 | String subject = "Pixabay Android App - Support"; 55 | String body = "Hello, I need help with..."; 56 | 57 | String mailto = "mailto:" + email + 58 | "?subject=" + Uri.encode(subject) + 59 | "&body=" + Uri.encode(body); 60 | 61 | Intent emailIntent = new Intent(Intent.ACTION_VIEW); 62 | emailIntent.setData(Uri.parse(mailto)); 63 | 64 | try { 65 | startActivity(Intent.createChooser(emailIntent, "Send Email")); 66 | } catch (Exception e) { 67 | Toast.makeText(this, "No email apps installed.", Toast.LENGTH_SHORT).show(); 68 | } 69 | } 70 | 71 | 72 | 73 | 74 | } -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Utilities/AppUtil.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Utilities; 2 | 3 | import android.app.Activity; 4 | import android.app.DownloadManager; 5 | import android.content.Context; 6 | import android.content.Intent; 7 | import android.content.pm.PackageManager; 8 | import android.net.Uri; 9 | import android.os.Environment; 10 | import android.widget.Toast; 11 | 12 | public class AppUtil { 13 | 14 | public static int getAppVersion(Context context){ 15 | try{ 16 | return (int) (context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES).getLongVersionCode()); 17 | } catch (PackageManager.NameNotFoundException e) { 18 | e.printStackTrace(); 19 | return -1; 20 | } 21 | } 22 | 23 | public static String getAppVersionStr(Context context){ 24 | try{ 25 | return context.getPackageManager().getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES).versionName; 26 | } catch (PackageManager.NameNotFoundException e) { 27 | e.printStackTrace(); 28 | return "error"; 29 | } 30 | } 31 | 32 | public static String capitalizeFirstLetter(String str) { 33 | if (str == null || str.isEmpty()) { 34 | return str; // Handle null or empty strings 35 | } 36 | return str.substring(0, 1).toUpperCase() + str.substring(1); 37 | } 38 | 39 | public static void openLink(String url, Context context) { 40 | try { 41 | Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 42 | intent.addCategory(Intent.CATEGORY_BROWSABLE); 43 | context.startActivity(intent); 44 | } catch (Exception e) { 45 | Toast.makeText(context, "Unable to open link.", Toast.LENGTH_SHORT).show(); 46 | } 47 | } 48 | 49 | public static void downloadFile(String url, String fileName, Activity activity){ 50 | Context context = activity.getApplicationContext(); 51 | DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); 52 | Uri uri = Uri.parse(url); 53 | DownloadManager.Request request = new DownloadManager.Request(uri); 54 | request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE); 55 | 56 | request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,"Pixabay/" + fileName); 57 | long reference = manager.enqueue(request); 58 | 59 | Toast.makeText(context, "Downloading...", Toast.LENGTH_SHORT).show(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Utilities/Display.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Utilities; 2 | 3 | import android.app.Activity; 4 | import android.util.DisplayMetrics; 5 | import android.util.TypedValue; 6 | import android.view.ViewGroup; 7 | import android.widget.ImageView; 8 | 9 | public class Display { 10 | 11 | private static DisplayMetrics getDisplayMetrics(Activity activity){ 12 | DisplayMetrics displayMetrics = new DisplayMetrics(); 13 | activity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); 14 | return displayMetrics; 15 | } 16 | 17 | public static int getDisplayHeight(Activity activity){ 18 | return getDisplayMetrics(activity).heightPixels; 19 | } 20 | public static int getDisplayWidth(Activity activity){ 21 | return getDisplayMetrics(activity).widthPixels; 22 | } 23 | 24 | public static void setImageViewHeightAndWidth(ImageView imageView, int height, int width,Activity activity){ 25 | int displayHeight = getDisplayHeight(activity); 26 | int maxHeight = (int) (displayHeight*0.6); 27 | int displayWidth = getDisplayWidth(activity); 28 | 29 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 30 | 31 | float ratio = (float) width / displayWidth; 32 | int final_height = (int) (height / ratio); 33 | int finalwidth = displayWidth; 34 | 35 | if (final_height > maxHeight){ 36 | float ratio2 = (float) final_height / maxHeight; 37 | finalwidth = (int) (finalwidth / ratio2); 38 | final_height = maxHeight; 39 | } 40 | 41 | params.height = final_height; 42 | params.width = finalwidth; 43 | 44 | imageView.setLayoutParams(params); 45 | } 46 | 47 | public static void setImageViewWidthHalfScreen(ImageView imageView,Activity activity){ 48 | int displayHeight = getDisplayHeight(activity); 49 | int height = (int) (displayHeight*0.3); 50 | 51 | float marginInPx = TypedValue.applyDimension( 52 | TypedValue.COMPLEX_UNIT_DIP, 53 | 14*1.5f, 54 | getDisplayMetrics(activity) 55 | ); 56 | 57 | int displayWidth = getDisplayWidth(activity); 58 | int width = (int) ((displayWidth*0.5) - marginInPx); 59 | 60 | ViewGroup.LayoutParams params = imageView.getLayoutParams(); 61 | 62 | params.height = height; 63 | params.width = width; 64 | 65 | imageView.setLayoutParams(params); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Utilities/FragmentUtil.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Utilities; 2 | 3 | import android.util.Log; 4 | 5 | import androidx.fragment.app.Fragment; 6 | import androidx.fragment.app.FragmentManager; 7 | import androidx.fragment.app.FragmentTransaction; 8 | 9 | public class FragmentUtil { 10 | 11 | public static Fragment openFragment(FragmentManager fragmentManager, int fragmentContainerView_id, Fragment newfragment, Fragment lastFragment){ 12 | Log.i("FragmentUtil", "open fragment: " + newfragment + "\nlast fragment was: " + lastFragment); 13 | FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); 14 | 15 | if (lastFragment != null) 16 | fragmentTransaction.hide(lastFragment); 17 | 18 | if (fragmentManager.getFragments().contains(newfragment)) 19 | fragmentTransaction.show(newfragment); 20 | else 21 | fragmentTransaction.add(fragmentContainerView_id,newfragment); 22 | 23 | lastFragment = newfragment; 24 | fragmentTransaction.commit(); 25 | 26 | return lastFragment; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Utilities/UrlApiUtil.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Utilities; 2 | 3 | import androidx.annotation.Nullable; 4 | 5 | import com.ahmadrezagh671.pixabay.BuildConfig; 6 | 7 | public class UrlApiUtil { 8 | 9 | public static String getPhotosUrl(@Nullable String[] words,String category,String color,boolean latest){ 10 | StringBuilder startUrl = new StringBuilder("https://pixabay.com/api/?key=").append(BuildConfig.Pixabay_API_KEY); 11 | if (words != null) { 12 | startUrl.append("&q="); 13 | for (String word:words) { 14 | startUrl.append(word).append("+"); 15 | } 16 | } 17 | startUrl.append("&image_type=all"); //all, photo, illustration, vector 18 | 19 | if (latest){ 20 | startUrl.append("&order=latest"); //popular, latest 21 | }else { 22 | startUrl.append("&order=popular"); 23 | } 24 | 25 | startUrl.append("&orientation=all"); //all, horizontal, vertical 26 | startUrl.append("&page=1"); //1, 2, 3, ... 27 | startUrl.append("&per_page=20"); //20, 40, 3 - 200 28 | startUrl.append("&safesearch=false"); //true, false 29 | 30 | if (!color.equals("none")){ 31 | startUrl.append("&colors=").append(color); 32 | } 33 | if (!category.equals("none")){ 34 | startUrl.append("&category=").append(category); 35 | } 36 | 37 | return startUrl.toString(); 38 | } 39 | 40 | public static String getCategoryUrl(String category){ 41 | return "https://pixabay.com/api/?key=" + BuildConfig.Pixabay_API_KEY + 42 | "&category=" + category + 43 | "&per_page=5"; 44 | } 45 | 46 | public static String getColorUrl(String color){ 47 | return "https://pixabay.com/api/?key=" + BuildConfig.Pixabay_API_KEY + 48 | "&colors=" + color + 49 | "&per_page=5"; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/ahmadrezagh671/pixabay/Utilities/VolleySingleton.java: -------------------------------------------------------------------------------- 1 | package com.ahmadrezagh671.pixabay.Utilities; 2 | 3 | import android.content.Context; 4 | import com.android.volley.RequestQueue; 5 | import com.android.volley.toolbox.Volley; 6 | 7 | public class VolleySingleton { 8 | 9 | private RequestQueue requestQueue; 10 | private static VolleySingleton mInstance; 11 | 12 | private VolleySingleton(Context context){ 13 | requestQueue = Volley.newRequestQueue(context.getApplicationContext()); 14 | } 15 | 16 | public static synchronized VolleySingleton getmInstance(Context context){ 17 | 18 | if(mInstance == null){ 19 | mInstance = new VolleySingleton(context); 20 | } 21 | return mInstance; 22 | } 23 | 24 | public RequestQueue getRequestQueue(){ 25 | return requestQueue; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/example_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/drawable/example_image.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/example_profile.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/drawable/example_profile.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_3dot.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_about_us.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_back.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_comment.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_data_usage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_download.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_dropdown.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_like_border.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mark.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_person.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_photo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_video.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/navigation_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_background_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_circular.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_rounded.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shape_rounded_gradient.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_about_us.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 19 | 20 | 21 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 51 | 52 | 55 | 56 | 57 | 62 | 63 | 64 | 72 | 73 | 74 | 82 | 83 | 84 | 93 | 94 | 95 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 21 | 22 | 32 | 33 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | 19 | 20 | 21 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 51 | 52 | 53 | 59 | 60 | 61 | 67 | 68 | 81 | 82 | 93 | 94 | 95 | 96 | 102 | 103 | 110 | 111 | 124 | 125 | 136 | 137 | 138 | 139 | 145 | 146 | 153 | 154 | 167 | 168 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 194 | 195 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_color.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_explore.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 15 | 16 | 17 | 25 | 26 | 27 | 39 | 40 | 54 | 55 | 56 | 57 | 58 | 59 | 70 | 71 | 80 | 81 | 89 | 90 | 104 | 105 | 120 | 121 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 153 | 154 | 159 | 160 | 161 | 162 | 163 | 164 | 175 | 176 | 186 | 187 | 201 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycler_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 25 | 26 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycler_post.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | 26 | 27 | 36 | 37 | 44 | 45 | 53 | 54 | 55 | 56 | 57 | 68 | 69 | 84 | 85 | 97 | 98 | 99 | 111 | 112 | 121 | 122 | 131 | 132 | 142 | 143 | 152 | 153 | 163 | 164 | 173 | 174 | 175 | 176 | 177 | 178 | 191 | 192 | 193 | 194 | -------------------------------------------------------------------------------- /app/src/main/res/menu/bottom_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 12 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/more_popup_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-hdpi/ic_launcher_o.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ahmadrezagh671/Pixabay_Android_App/67395764ba88d43d8c7a3f0c2701bb367f1aaadc/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-night/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values-notnight/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF000000 4 | #FFFFFFFF 5 | 6 | #74A4F6 7 | #9ca3af 8 | #6A67C7 9 | #eff5ff 10 | #ffffff 11 | #ffffff 12 | #7CFFFFFF 13 | #E9E9E9 14 | 15 | #60a5fa 16 | #ef4444 17 | #34d399 18 | 19 | #1B1B1B 20 | #616161 21 | #EBEBEB 22 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | none 5 | backgrounds 6 | fashion 7 | nature 8 | science 9 | education 10 | feelings 11 | health 12 | people 13 | religion 14 | places 15 | animals 16 | industry 17 | computer 18 | food 19 | sports 20 | transportation 21 | travel 22 | buildings 23 | business 24 | music 25 | 26 | 27 | 28 | none 29 | grayscale 30 | transparent 31 | red 32 | orange 33 | yellow 34 | green 35 | turquoise 36 | blue 37 | lilac 38 | pink 39 | white 40 | gray 41 | black 42 | brown 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FF000000 4 | #FFFFFFFF 5 | 6 | #60a5fa 7 | #9ca3af 8 | #403dce 9 | #14161B 10 | #0A0E16 11 | #181F28 12 | #BC181F28 13 | #242935 14 | 15 | #60a5fa 16 | #ef4444 17 | #34d399 18 | 19 | #EBEBEB 20 | #A9A9A9 21 | #1B1B1B 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Pixabay 3 | 4 | Pixabay App is a clean and efficient Android application built as a convenient interface for accessing the Pixabay API. It provides a fast, modern, and easy-to-use experience for discovering and browsing free images and videos from Pixabay’s vast library.\n\nThis app is an independent, community-driven project and is not officially affiliated with Pixabay.com. It was created purely for educational and non-commercial purposes.\n\nDeveloped by Ahmadrezagh671@gmail.com 5 | 6 | https://github.com/ahmadrezagh671/Pixabay_Android_App/ 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/themes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 |