├── app
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── 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
│ │ │ ├── strings.xml
│ │ │ ├── colors.xml
│ │ │ └── styles.xml
│ │ ├── menu
│ │ │ └── main_menu.xml
│ │ └── layout
│ │ │ ├── item_photo.xml
│ │ │ └── activity_main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── keenencharles
│ │ └── unsplashdemo
│ │ ├── PhotoAdapter.kt
│ │ └── MainActivity.kt
├── proguard-rules.pro
└── build.gradle
├── androidunsplash
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ ├── strings.xml
│ │ │ └── ic_launcher_background.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
│ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ └── drawable
│ │ │ └── ic_launcher_foreground.xml
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ └── com
│ │ │ └── keenencharles
│ │ │ └── unsplash
│ │ │ ├── models
│ │ │ ├── ContentFilter.kt
│ │ │ ├── Order.kt
│ │ │ ├── Orientation.kt
│ │ │ ├── Download.kt
│ │ │ ├── Value.kt
│ │ │ ├── Position.kt
│ │ │ ├── UserStat.kt
│ │ │ ├── SearchResults.kt
│ │ │ ├── Portfolio.kt
│ │ │ ├── Badge.kt
│ │ │ ├── Location.kt
│ │ │ ├── ProfileImage.kt
│ │ │ ├── UserStats.kt
│ │ │ ├── Urls.kt
│ │ │ ├── Color.kt
│ │ │ ├── Stats.kt
│ │ │ ├── Historical.kt
│ │ │ ├── Category.kt
│ │ │ ├── Token.kt
│ │ │ ├── Exif.kt
│ │ │ ├── Links.kt
│ │ │ ├── CurrentUserCollection.kt
│ │ │ ├── CoverPhoto.kt
│ │ │ ├── Collection.kt
│ │ │ ├── Result.kt
│ │ │ ├── Photo.kt
│ │ │ └── User.kt
│ │ │ ├── api
│ │ │ ├── ErrorResponse.kt
│ │ │ ├── UnsplashResource.kt
│ │ │ ├── Scope.kt
│ │ │ ├── endpoints
│ │ │ │ ├── StatsEndpointInterface.kt
│ │ │ │ ├── AuthEndpointInterface.kt
│ │ │ │ ├── CollectionsEndpointInterface.kt
│ │ │ │ ├── UserEndpointInterface.kt
│ │ │ │ └── PhotosEndpointInterface.kt
│ │ │ ├── HeaderInterceptor.kt
│ │ │ ├── UnsplashCallback.kt
│ │ │ └── UnsplashResponseHandler.kt
│ │ │ ├── StatsAPI.kt
│ │ │ ├── Unsplash.kt
│ │ │ ├── CollectionAPI.kt
│ │ │ ├── UserAPI.kt
│ │ │ └── PhotoAPI.kt
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .gitignore
├── gradle.properties
├── LICENSE
├── gradlew.bat
├── README-JAVA.md
├── README.md
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/androidunsplash/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':androidunsplash'
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Android Unsplash
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KeenenCharles/AndroidUnplash/HEAD/androidunsplash/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #6328AC
4 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/ContentFilter.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | enum class ContentFilter(val type: String) {
4 | LOW("low"),
5 | HIGH("high"),
6 | }
7 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Order.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | enum class Order(val order: String) {
4 | LATEST("latest"),
5 | OLDEST("oldest"),
6 | POPULAR("popular")
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Unsplash Demo
3 | Sign In
4 | Search
5 | Go
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Orientation.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | enum class Orientation(val orientation: String) {
4 | LANDSCAPE("landscape"),
5 | PORTRAIT("portrait"),
6 | SQUARISH("squarish")
7 | }
8 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Nov 15 17:08:50 BOT 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Download.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Download(
8 | var url: String? = null,
9 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/ErrorResponse.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class ErrorResponse(
6 | val error: String,
7 | @SerializedName("error_description") val description: String?
8 | )
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Value.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Value(
8 | var date: String? = null,
9 | var value: Int? = null,
10 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Position.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Position(
8 | var latitude: Double? = null,
9 | var longitude: Double? = null
10 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/UserStat.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class UserStat(
8 | var total: Int? = null,
9 | var historical: Historical? = null
10 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/SearchResults.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import com.google.gson.annotations.SerializedName
4 |
5 | data class SearchResults(
6 | var total: Int? = null,
7 | var results: List = listOf(),
8 | @SerializedName("total_pages") var totalPages: Int? = null
9 | )
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Portfolio.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Portfolio(
9 | @SerializedName("url") val url: String? = null
10 | ): Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Badge.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Badge(
8 | var title: String,
9 | var primary: Boolean,
10 | var slug: String,
11 | var link: String
12 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Location.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Location(
8 | var city: String? = null,
9 | var country: String? = null,
10 | var position: Position? = null
11 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/ProfileImage.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class ProfileImage(
8 | var small: String? = null,
9 | var medium: String? = null,
10 | var large: String? = null
11 | ) : Parcelable
--------------------------------------------------------------------------------
/app/src/main/res/menu/main_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/UserStats.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class UserStats(
8 | var username: String? = null,
9 | var downloads: UserStat? = null,
10 | var views: UserStat? = null,
11 | var likes: UserStat? = null
12 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Urls.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Urls(
8 | var raw: String? = null,
9 | var full: String? = null,
10 | var regular: String? = null,
11 | var small: String? = null,
12 | var thumb: String? = null
13 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/UnsplashResource.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | /**
4 | * Class used for API responses
5 | */
6 |
7 | sealed class UnsplashResource(
8 | val data: T? = null,
9 | val errorMessage: String
10 | ) {
11 | class Success(data: T?) : UnsplashResource(data, "")
12 | class Error(errorMessage: String) : UnsplashResource(null, errorMessage)
13 | }
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Color.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | enum class Color(val color: String) {
4 | BLACK_WHITE("black_and_white"),
5 | BLACK("black"),
6 | WHITE("white"),
7 | ORANGE("orange"),
8 | RED("red"),
9 | PURPLE("purple"),
10 | MAGENTA("magenta"),
11 | GREEN("green"),
12 | TEAL("teal"),
13 | BLUE("blue"),
14 | YELLOW("yellow")
15 | }
16 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Stats.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Stats(
9 | @SerializedName("total_photos") var totalPhotos: Int? = null,
10 | @SerializedName("photo_downloads") var photoDownloads: Int? = null
11 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Historical.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import kotlinx.parcelize.Parcelize
5 |
6 | @Parcelize
7 | data class Historical(
8 | var change: Int? = null,
9 | var average: Int? = null,
10 | var resolution: String? = null,
11 | var quantity: Int? = null,
12 | var values: List? = null
13 | ) : Parcelable
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Category.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Category(
9 | var id: Int? = null,
10 | var title: String? = null,
11 | var links: Links? = null,
12 | @SerializedName("photo_count") var photoCount: Int? = null
13 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/Scope.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | enum class Scope private constructor(val scope: String) {
4 |
5 | PUBLIC("public"),
6 | READ_USER("read_user"),
7 | WRITE_USER("write_user"),
8 | READ_PHOTOS("read_photos"),
9 | WRITE_PHOTOS("write_photos"),
10 | WRITE_LIKES("write_likes"),
11 | WRITE_FOLLOWERS("write_likes"),
12 | WRITE_COLLECTIONS("write_collections"),
13 | READ_COLLECTIONS("read_collections")
14 | }
15 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Token.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Token(
9 | var scope: String,
10 | @SerializedName("access_token") var accessToken: String,
11 | @SerializedName("token_type") var tokenType: String,
12 | @SerializedName("created_at") var createdAt: Int
13 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Exif.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Exif(
9 | var make: String? = null,
10 | var model: String? = null,
11 | var aperture: String? = null,
12 | var iso: Int? = null,
13 | @SerializedName("exposure_time") var exposureTime: String? = null,
14 | @SerializedName("focal_length") var focalLength: String? = null
15 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/endpoints/StatsEndpointInterface.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api.endpoints
2 |
3 | import com.keenencharles.unsplash.models.Stats
4 | import retrofit2.Call
5 | import retrofit2.http.GET
6 |
7 | interface StatsEndpointInterface {
8 |
9 | @GET("stats/total")
10 | fun getTotal(): Call
11 |
12 | @GET("stats/total")
13 | suspend fun getTotalSuspend(): Stats
14 |
15 | @GET("stats/month")
16 | fun getMonth(): Call
17 |
18 | @GET("stats/month")
19 | suspend fun getMonthSuspend(): Stats
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Links.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Links(
9 | var self: String? = null,
10 | var html: String? = null,
11 | var photos: String? = null,
12 | var likes: String? = null,
13 | var portfolio: String? = null,
14 | var download: String? = null,
15 | @SerializedName("download_location") var downloadLocation: String? = null
16 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/CurrentUserCollection.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class CurrentUserCollection(
9 | var id: Int? = null,
10 | var title: String? = null,
11 | var curated: Boolean? = null,
12 | @SerializedName("user") var user: User? = null,
13 | @SerializedName("cover_photo") var coverPhoto: CoverPhoto? = null,
14 | @SerializedName("published_at") var publishedAt: String? = null,
15 | @SerializedName("updated_at") var updatedAt: String? = null,
16 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
11 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/CoverPhoto.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 | import java.util.*
7 |
8 | @Parcelize
9 | data class CoverPhoto(
10 | var id: String? = null,
11 | var width: Int? = null,
12 | var height: Int? = null,
13 | var color: String? = null,
14 | var likes: Int? = null,
15 | var user: User? = null,
16 | var urls: Urls? = null,
17 | var categories: List = ArrayList(),
18 | var links: Links? = null,
19 | @SerializedName("liked_by_user") var likedByUser: Boolean? = null
20 | ) : Parcelable
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # files for the dex VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # generated files
13 | bin/
14 | gen/
15 |
16 | # Local configuration file (sdk path, etc)
17 | local.properties
18 |
19 | # Windows thumbnail db
20 | Thumbs.db
21 |
22 | # OSX files
23 | .DS_Store
24 |
25 | # Android Studio
26 | *.iml
27 | .idea
28 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
29 | .gradle
30 | build/
31 | .navigation
32 | captures/
33 | output.json
34 |
35 | #NDK
36 | obj/
37 | .externalNativeBuild
38 |
39 | *.gpg
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_photo.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/HeaderInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | import java.io.IOException
4 |
5 | import okhttp3.Interceptor
6 | import okhttp3.Request
7 | import okhttp3.Response
8 |
9 | class HeaderInterceptor(private val clientId: String, private val token: String?) : Interceptor {
10 |
11 | @Throws(IOException::class)
12 | override fun intercept(chain: Interceptor.Chain): Response {
13 | var auth = "Client-ID $clientId"
14 | if (token != null) {
15 | auth += ",Bearer $token"
16 | }
17 | var request = chain.request()
18 | request = request.newBuilder()
19 | .addHeader("Authorization", auth)
20 | .build()
21 | return chain.proceed(request)
22 | }
23 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.useAndroidX=true
3 | org.gradle.jvmargs=-Xmx1536m
4 |
5 | GROUP=com.keenencharles
6 | POM_ARTIFACT_ID=androidunsplash
7 | VERSION_NAME=3.1.2
8 |
9 | POM_NAME=androidunsplash
10 | POM_PACKAGING=aar
11 |
12 | POM_DESCRIPTION=An unofficial library to access the Unsplash API.
13 | POM_INCEPTION_YEAR=2017
14 |
15 | POM_URL=https://github.com/KeenenCharles/AndroidUnplash
16 | POM_SCM_URL=https://github.com/KeenenCharles/AndroidUnplash
17 | POM_SCM_CONNECTION=scm:git@github.com:KeenenCharles/AndroidUnplash.git
18 | POM_SCM_DEV_CONNECTION=scm:git@github.com:KeenenCharles/AndroidUnplash.git
19 |
20 | POM_LICENCE_NAME=MIT License
21 | POM_LICENCE_URL=https://github.com/KeenenCharles/AndroidUnplash/blob/master/LICENSE
22 | POM_LICENCE_DIST=repo
23 |
24 | POM_DEVELOPER_ID=KeenenCharles
25 | POM_DEVELOPER_NAME=KeenenCharles
26 | POM_DEVELOPER_URL=https://github.com/KeenenCharles
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Collection.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Collection(
9 | var id: String? = null,
10 | var title: String? = null,
11 | var description: String? = null,
12 | var curated: Boolean? = null,
13 | var private: Boolean? = null,
14 | var user: User? = null,
15 | var links: Links? = null,
16 | @SerializedName("cover_photo") var coverPhoto: CoverPhoto? = null,
17 | @SerializedName("share_key") var shareKey: String? = null,
18 | @SerializedName("total_photos") var totalPhotos: Int? = null,
19 | @SerializedName("published_at") var publishedAt: String? = null,
20 | @SerializedName("updated_at") var updatedAt: String? = null
21 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Result.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class Result(
9 | var id: String? = null,
10 | var width: Int? = null,
11 | var height: Int? = null,
12 | var color: String? = null,
13 | var likes: Int? = null,
14 | var user: User? = null,
15 | var urls: Urls? = null,
16 | var links: Links? = null,
17 | val categories: List? = null,
18 | @SerializedName("current_user_collections") var currentUserCollections: List? = null,
19 | @SerializedName("liked_by_user") var likedByUser: Boolean? = null,
20 | @SerializedName("created_at") var createdAt: String? = null,
21 | @SerializedName("updated_at") var updatedAt: String? = null
22 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/UnsplashCallback.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | import com.google.gson.Gson
4 | import retrofit2.Call
5 | import retrofit2.Callback
6 | import retrofit2.Response
7 |
8 | class UnsplashCallback(private var onComplete: (T) -> Unit, private var onError: (String) -> Unit) : Callback {
9 |
10 | override fun onResponse(call: Call, response: Response) {
11 | when (response.code()) {
12 | in 200..299 -> {
13 | onComplete(response.body()!!)
14 | }
15 | in 400..500 -> {
16 | val res = response.errorBody()?.string()?.trim()
17 | val error = Gson().fromJson(res, ErrorResponse::class.java)
18 | onError(error.description ?: "An error occurred")
19 | }
20 | }
21 | }
22 |
23 | override fun onFailure(call: Call, t: Throwable) {
24 | onError(t.message?: "Error")
25 | }
26 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\kcred\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/endpoints/AuthEndpointInterface.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api.endpoints
2 |
3 | import com.keenencharles.unsplash.models.Token
4 | import retrofit2.Call
5 | import retrofit2.http.POST
6 | import retrofit2.http.Query
7 | import retrofit2.http.Url
8 |
9 | interface AuthEndpointInterface {
10 |
11 | @POST
12 | fun getToken(@Url url: String,
13 | @Query("client_id") clientID: String,
14 | @Query("client_secret") clientSecret: String,
15 | @Query("redirect_uri") redirectURI: String,
16 | @Query("code") code: String,
17 | @Query("grant_type") grantType: String): Call
18 |
19 | @POST
20 | suspend fun getTokenSuspend(@Url url: String,
21 | @Query("client_id") clientID: String,
22 | @Query("client_secret") clientSecret: String,
23 | @Query("redirect_uri") redirectURI: String,
24 | @Query("code") code: String,
25 | @Query("grant_type") grantType: String): Token
26 | }
27 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/Photo.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 | import java.util.*
7 |
8 | @Parcelize
9 | data class Photo(
10 | var id: String? = null,
11 | var width: Int? = null,
12 | var height: Int? = null,
13 | var color: String? = null,
14 | var downloads: Int? = null,
15 | var likes: Int? = null,
16 | var exif: Exif? = null,
17 | var location: Location? = null,
18 | var urls: Urls? = null,
19 | var links: Links? = null,
20 | var user: User? = null,
21 | var categories: List = ArrayList(),
22 | @SerializedName("current_user_collections") var currentUserCollections: List = ArrayList(),
23 | @SerializedName("liked_by_user") var likedByUser: Boolean? = null,
24 | @SerializedName("created_at") var createdAt: String? = null,
25 | @SerializedName("updated_at") var updatedAt: String? = null
26 | ) : Parcelable
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Keenen Charles
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 |
--------------------------------------------------------------------------------
/androidunsplash/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Users\kcred\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
27 | -keep class com.keenencharles.unsplash.models.** { *; }
28 | -keep class kotlin.coroutines.Continuation { *; }
--------------------------------------------------------------------------------
/androidunsplash/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-parcelize'
4 | apply plugin: 'com.vanniktech.maven.publish'
5 |
6 | android {
7 | compileSdkVersion 30
8 | defaultConfig {
9 | minSdkVersion 16
10 | targetSdkVersion 30
11 |
12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
13 | consumerProguardFiles("proguard-rules.pro")
14 | }
15 | compileOptions {
16 | sourceCompatibility JavaVersion.VERSION_1_8
17 | targetCompatibility JavaVersion.VERSION_1_8
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 |
24 | implementation 'androidx.appcompat:appcompat:1.3.1'
25 | implementation 'androidx.browser:browser:1.3.0'
26 | implementation "androidx.core:core-ktx:1.6.0"
27 |
28 | implementation "com.squareup.okhttp3:okhttp:4.9.0"
29 | implementation "com.squareup.okhttp3:logging-interceptor:4.9.0"
30 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
31 | implementation("com.squareup.retrofit2:retrofit:2.9.0") {
32 | exclude module: "okhttp"
33 | }
34 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/UnsplashResponseHandler.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api
2 |
3 | import com.google.gson.Gson
4 | import retrofit2.HttpException
5 | import java.net.ConnectException
6 | import java.net.SocketTimeoutException
7 |
8 | class UnsplashResponseHandler {
9 |
10 | fun handleSuccess(data: T? = null): UnsplashResource.Success {
11 | return UnsplashResource.Success(data)
12 | }
13 |
14 | fun handleException(e: Exception): UnsplashResource.Error {
15 | return when (e) {
16 | is ConnectException -> {
17 | UnsplashResource.Error("Connection Error")
18 | }
19 | is HttpException -> {
20 | val res = e.response()?.errorBody()?.string()?.trim()
21 | val error = Gson().fromJson(res, ErrorResponse::class.java)
22 | val message = error.description ?: "An error occurred"
23 | UnsplashResource.Error(message)
24 | }
25 | is SocketTimeoutException -> {
26 | UnsplashResource.Error("Timeout")
27 | }
28 | else -> {
29 | UnsplashResource.Error("Unknown Error")
30 | }
31 | }
32 | }
33 |
34 | }
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/models/User.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.models
2 |
3 | import android.os.Parcelable
4 | import com.google.gson.annotations.SerializedName
5 | import kotlinx.parcelize.Parcelize
6 |
7 | @Parcelize
8 | data class User(
9 | var id: String? = null,
10 | var username: String? = null,
11 | var name: String? = null,
12 | var bio: String? = null,
13 | var location: String? = null,
14 | var totalLikes: Int? = null,
15 | var downloads: Int? = null,
16 | var badge: Badge? = null,
17 | var links: Links? = null,
18 | @SerializedName("current_user_collections") var currentUserCollections: List? = null,
19 | @SerializedName("profile_image") var profileImage: ProfileImage? = null,
20 | @SerializedName("total_photos") var totalPhotos: Int? = null,
21 | @SerializedName("total_collections") var totalCollections: Int? = null,
22 | @SerializedName("followed_by_user") var followedByUser: Boolean? = null,
23 | @SerializedName("followers_count") var followersCount: Int? = null,
24 | @SerializedName("first_name") var firstName: String? = null,
25 | @SerializedName("last_name") var lastName: String? = null,
26 | @SerializedName("instagram_username") var instagramUsername: String? = null,
27 | @SerializedName("twitter_username") var twitterUsername: String? = null,
28 | @SerializedName("portfolio_url") var portfolioUrl: String? = null,
29 | @SerializedName("updated_at") var updatedAt: String? = null
30 | ) : Parcelable
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/StatsAPI.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash
2 |
3 | import com.keenencharles.unsplash.api.UnsplashCallback
4 | import com.keenencharles.unsplash.api.UnsplashResource
5 | import com.keenencharles.unsplash.api.UnsplashResponseHandler
6 | import com.keenencharles.unsplash.api.endpoints.StatsEndpointInterface
7 | import com.keenencharles.unsplash.models.Stats
8 |
9 | @JvmSuppressWildcards
10 | class StatsAPI(
11 | private var apiService: StatsEndpointInterface,
12 | private var responseHandler: UnsplashResponseHandler
13 | ) {
14 |
15 | fun getTotal(
16 | onComplete: (Stats) -> Unit,
17 | onError: (String) -> Unit
18 | ) {
19 | val call = apiService.getTotal()
20 | call.enqueue(UnsplashCallback(onComplete, onError))
21 | }
22 |
23 | suspend fun getTotal(): UnsplashResource {
24 | return try {
25 | val res = apiService.getTotalSuspend()
26 | responseHandler.handleSuccess(res)
27 |
28 | } catch (e: Exception) {
29 | responseHandler.handleException(e)
30 | }
31 | }
32 |
33 | fun getMonth(
34 | onComplete: (Stats) -> Unit,
35 | onError: (String) -> Unit
36 | ) {
37 | val call = apiService.getMonth()
38 | call.enqueue(UnsplashCallback(onComplete, onError))
39 | }
40 |
41 | suspend fun getMonth(): UnsplashResource {
42 | return try {
43 | val res = apiService.getMonthSuspend()
44 | responseHandler.handleSuccess(res)
45 |
46 | } catch (e: Exception) {
47 | responseHandler.handleException(e)
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/keenencharles/unsplashdemo/PhotoAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplashdemo
2 |
3 | import android.view.LayoutInflater
4 | import android.view.ViewGroup
5 | import androidx.recyclerview.widget.RecyclerView
6 | import com.keenencharles.unsplash.models.Photo
7 | import com.keenencharles.unsplashdemo.databinding.ItemPhotoBinding
8 | import com.squareup.picasso.Picasso
9 | import java.util.Collections.emptyList
10 |
11 | class PhotoAdapter(private var onSelected: (Photo) -> Unit) : RecyclerView.Adapter() {
12 |
13 | private var photos: List = emptyList()
14 |
15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
16 | val layoutInflater = LayoutInflater.from(parent.context)
17 | val itemBinding = ItemPhotoBinding.inflate(layoutInflater, parent, false)
18 | return ViewHolder(itemBinding)
19 | }
20 |
21 | override fun onBindViewHolder(holder: ViewHolder, position: Int) {
22 | val photo = photos[position]
23 | holder.bind(photo)
24 |
25 |
26 | holder.binding.root.setOnClickListener {
27 | run {
28 | onSelected(photo)
29 | }
30 | }
31 | }
32 |
33 | override fun getItemCount(): Int {
34 | return photos.size
35 | }
36 |
37 | fun updateList(items: List) {
38 | this.photos = items
39 | notifyDataSetChanged()
40 | }
41 |
42 | inner class ViewHolder(val binding: ItemPhotoBinding) : RecyclerView.ViewHolder(binding.root) {
43 |
44 | fun bind(photo: Photo) {
45 | Picasso.get().load(photo.urls?.small).into(binding.imageView)
46 | binding.executePendingBindings()
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 | apply plugin: 'kotlin-android'
3 | apply plugin: 'kotlin-kapt'
4 | apply plugin: 'kotlin-parcelize'
5 |
6 | Properties properties = new Properties()
7 | properties.load(project.rootProject.file("local.properties").newDataInputStream())
8 |
9 | android {
10 | compileSdkVersion 30
11 | defaultConfig {
12 | applicationId "com.keenencharles.unsplashdemo"
13 | minSdkVersion 16
14 | targetSdkVersion 30
15 | versionCode 1
16 | versionName "0.1.3"
17 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18 | }
19 | compileOptions {
20 | sourceCompatibility JavaVersion.VERSION_1_8
21 | targetCompatibility JavaVersion.VERSION_1_8
22 | }
23 | buildTypes {
24 | debug {
25 | buildConfigField "String", "UnsplashID", properties.getProperty("unsplash.id", "")
26 | buildConfigField "String", "UnsplashSecret", properties.getProperty("unsplash.secret", "")
27 | }
28 | }
29 | buildFeatures {
30 | dataBinding = true
31 | }
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(dir: 'libs', include: ['*.jar'])
36 | implementation project(':androidunsplash')
37 |
38 | implementation 'androidx.appcompat:appcompat:1.3.1'
39 | implementation 'androidx.recyclerview:recyclerview:1.2.1'
40 | implementation 'androidx.core:core-ktx:1.6.0'
41 | implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
42 |
43 | implementation 'com.google.android.material:material:1.4.0'
44 | implementation 'com.google.code.gson:gson:2.8.6'
45 |
46 | implementation 'com.squareup.picasso:picasso:2.71828'
47 | implementation 'com.squareup.okhttp3:okhttp:4.9.0'
48 | }
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
10 |
11 |
18 |
19 |
33 |
34 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/README-JAVA.md:
--------------------------------------------------------------------------------
1 | # Android Unsplash (Unofficial)
2 | An unofficial Unsplash API library for Android
3 |
4 | ## Gradle
5 | Add the line below to your build.gradle to use:
6 | ~~~
7 | dependencies {
8 | implementation 'com.kc.androidunsplash:androidunsplash:1.0.5'
9 | }
10 | ~~~
11 |
12 | ## Usage
13 |
14 | ### Initialize Unsplash Client
15 | ~~~~~
16 | Unsplash unsplash = new Unsplash(YOUR_CLIENT_ID);
17 | ~~~~~
18 | You can sign up for a Client Id at
19 |
20 | ### Get A List of Photos
21 | ~~~~~
22 | unsplash.getPhotos(1, 10, Order.LATEST, new Unsplash.OnPhotosLoadedListener() {
23 | @Override
24 | public void onComplete(List photos) {
25 | int photoCount = photos.size();
26 | }
27 |
28 | @Override
29 | public void onError(String error) {
30 | Log.v("Error", error);
31 | }
32 | });
33 | ~~~~~
34 |
35 | ### Get A Photo By Id
36 | ~~~~~
37 | unsplash.getPhoto(PHOTO_ID, new Unsplash.OnPhotoLoadedListener() {
38 | @Override
39 | public void onComplete(Photo photo) {
40 | String photoUrl = photo.getUrls().getRegular();
41 | }
42 |
43 | @Override
44 | public void onError(String error) {
45 | Log.v("Error", error);
46 | }
47 | });
48 | ~~~~~
49 |
50 | ### Search
51 | ~~~~~
52 | unsplash.searchPhotos(query, new Unsplash.OnSearchCompleteListener() {
53 | @Override
54 | public void onComplete(SearchResults results) {
55 | Log.d("Photos", "Total Results Found " + results.getTotal());
56 | List photos = results.getResults();
57 | }
58 |
59 | @Override
60 | public void onError(String error) {
61 | Log.d("Unsplash", error);
62 | }
63 | });
64 | ~~~~~
65 |
66 | ## Other Features
67 | ~~~~~
68 | getCuratedPhotos()
69 | getRandomPhoto()
70 | getRandomPhotos()
71 | getPhotoDownloadLink
72 | getCollections()
73 | getFeaturedCollections()
74 | getCuratedCollections()
75 | getRelatedCollections()
76 | getCollection()
77 | getCuratedCollection()
78 | getCollectionPhotos()
79 | getCuratedCollectionPhotos()
80 | getStats()
81 | ~~~~~
82 |
83 | Take a look at the API documentation for what each call does in detail
84 |
85 | ## Built With This Library
86 | + [Walldrobe](https://play.google.com/store/apps/details?id=walldrobe.coffecode.com)
87 | + [Love Diary](https://play.google.com/store/apps/details?id=com.kilic.tweetydiary)
88 | + [Advice](https://play.google.com/store/apps/details?id=my.sustento.apeaceofadvice)
89 |
90 | # License
91 | ~~~
92 | MIT License
93 |
94 | Copyright (c) 2017 Keenen Charles
95 |
96 | Permission is hereby granted, free of charge, to any person obtaining a copy
97 | of this software and associated documentation files (the "Software"), to deal
98 | in the Software without restriction, including without limitation the rights
99 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100 | copies of the Software, and to permit persons to whom the Software is
101 | furnished to do so, subject to the following conditions:
102 |
103 | The above copyright notice and this permission notice shall be included in all
104 | copies or substantial portions of the Software.
105 |
106 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
107 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
108 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
109 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
110 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
111 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
112 | SOFTWARE.
113 |
114 | ~~~
115 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/endpoints/CollectionsEndpointInterface.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api.endpoints
2 |
3 | import com.keenencharles.unsplash.models.Photo
4 | import com.keenencharles.unsplash.models.Collection
5 | import com.keenencharles.unsplash.models.SearchResults
6 | import retrofit2.Call
7 | import retrofit2.http.*
8 |
9 | interface CollectionsEndpointInterface {
10 |
11 | @GET("collections")
12 | fun get(
13 | @Query("page") page: Int?,
14 | @Query("per_page") perPage: Int?
15 | ): Call>
16 |
17 | @GET("collections")
18 | suspend fun getSuspend(
19 | @Query("page") page: Int?,
20 | @Query("per_page") perPage: Int?
21 | ): List
22 |
23 | @GET("collections/{id}")
24 | fun getById(@Path("id") id: String): Call
25 |
26 | @GET("collections/{id}")
27 | suspend fun getByIdSuspend(@Path("id") id: String): Collection
28 |
29 | @GET("collections/{id}/photos")
30 | fun getPhotos(
31 | @Path("id") id: String,
32 | @Query("page") page: Int?,
33 | @Query("per_page") perPage: Int?
34 | ): Call>
35 |
36 | @GET("collections/{id}/photos")
37 | suspend fun getPhotosSuspend(
38 | @Path("id") id: String,
39 | @Query("page") page: Int?,
40 | @Query("per_page") perPage: Int?
41 | ): List
42 |
43 | @GET("collections/{id}/related")
44 | fun getRelated(@Path("id") id: String): Call>
45 |
46 | @GET("collections/{id}/related")
47 | suspend fun getRelatedSuspend(@Path("id") id: String): List
48 |
49 | @GET("search/collections")
50 | fun search(
51 | @Query("query") query: String,
52 | @Query("page") page: Int?,
53 | @Query("per_page") perPage: Int?
54 | ): Call>
55 |
56 | @GET("search/collections")
57 | suspend fun searchSuspend(
58 | @Query("query") query: String,
59 | @Query("page") page: Int?,
60 | @Query("per_page") perPage: Int?
61 | ): SearchResults
62 |
63 | @POST("collections")
64 | fun create(
65 | @Query("title") query: String,
66 | @Query("description") page: String?,
67 | @Query("private") private: Boolean?
68 | ): Call
69 |
70 | @POST("collections")
71 | suspend fun createSuspend(
72 | @Query("title") query: String,
73 | @Query("description") page: String?,
74 | @Query("private") private: Boolean?
75 | ): Collection
76 |
77 | @PUT("collections/{id}")
78 | fun update(
79 | @Path("id") id: String,
80 | @Query("title") query: String?,
81 | @Query("description") page: String?,
82 | @Query("private") private: Boolean?
83 | ): Call
84 |
85 | @PUT("collections/{id}")
86 | suspend fun updateSuspend(
87 | @Path("id") id: String,
88 | @Query("title") query: String?,
89 | @Query("description") page: String?,
90 | @Query("private") private: Boolean?
91 | ): Collection
92 |
93 | @DELETE("collections/{id}")
94 | fun delete(@Path("id") id: String): Call
95 |
96 | @DELETE("collections/{id}")
97 | suspend fun deleteSuspend(@Path("id") id: String): Collection
98 |
99 | @POST("collections/{id}/add")
100 | fun addPhoto(
101 | @Query("collection_id") collectionId: String,
102 | @Query("photo_id") page: String?
103 | ): Call
104 |
105 | @POST("collections/{id}/add")
106 | suspend fun addPhotoSuspend(
107 | @Query("collection_id") collectionId: String,
108 | @Query("photo_id") page: String?
109 | ): Collection
110 |
111 | @DELETE("collections/{id}/add")
112 | fun removePhoto(
113 | @Query("collection_id") collectionId: String,
114 | @Query("photo_id") page: String?
115 | ): Call
116 |
117 | @DELETE("collections/{id}/add")
118 | suspend fun removePhotoSuspend(
119 | @Query("collection_id") collectionId: String,
120 | @Query("photo_id") page: String?
121 | ): Collection
122 | }
123 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/endpoints/UserEndpointInterface.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api.endpoints
2 |
3 | import com.keenencharles.unsplash.models.*
4 | import com.keenencharles.unsplash.models.Collection
5 | import retrofit2.Call
6 | import retrofit2.http.GET
7 | import retrofit2.http.PUT
8 | import retrofit2.http.Path
9 | import retrofit2.http.Query
10 |
11 | interface UserEndpointInterface {
12 |
13 | @GET("me")
14 | fun getCurrent(): Call
15 |
16 | @GET("me")
17 | suspend fun getCurrentSuspend(): User
18 |
19 | @PUT("me")
20 | fun updateCurrent(user: User): Call
21 |
22 | @PUT("me")
23 | suspend fun updateCurrentSuspend(user: User): User
24 |
25 | @GET("users/{username}")
26 | fun getByUsername(@Path("username") username: String): Call
27 |
28 | @GET("users/{username}")
29 | suspend fun getByUsernameSuspend(@Path("username") username: String): User
30 |
31 | @GET("users/{username}/portfolio")
32 | fun getPortfolio(@Path("username") username: String): Call
33 |
34 | @GET("users/{username}/portfolio")
35 | suspend fun getPortfolioSuspend(@Path("username") username: String): Portfolio
36 |
37 | @GET("users/{username}/photos")
38 | fun getPhotos(
39 | @Path("username") username: String,
40 | @Query("page") page: Int?,
41 | @Query("per_page") perPage: Int?,
42 | @Query("order_by") orderBy: String?,
43 | @Query("stats") stats: Boolean?,
44 | @Query("resolution") resolution: String?,
45 | @Query("quantity") quantity: Int?
46 | ): Call>
47 |
48 | @GET("users/{username}/photos")
49 | suspend fun getPhotosSuspend(
50 | @Path("username") username: String,
51 | @Query("page") page: Int?,
52 | @Query("per_page") perPage: Int?,
53 | @Query("order_by") orderBy: String?,
54 | @Query("stats") stats: Boolean?,
55 | @Query("resolution") resolution: String?,
56 | @Query("quantity") quantity: Int?
57 | ): List
58 |
59 | @GET("users/{username}/likes")
60 | fun getLikedPhotos(
61 | @Path("username") username: String,
62 | @Query("page") page: Int?,
63 | @Query("per_page") perPage: Int?,
64 | @Query("order_by") orderBy: String?
65 | ): Call>
66 |
67 | @GET("users/{username}/likes")
68 | suspend fun getLikedPhotosSuspend(
69 | @Path("username") username: String,
70 | @Query("page") page: Int?,
71 | @Query("per_page") perPage: Int?,
72 | @Query("order_by") orderBy: String?
73 | ): List
74 |
75 | @GET("users/{username}/collections")
76 | fun getCollections(
77 | @Path("username") username: String,
78 | @Query("page") page: Int?,
79 | @Query("per_page") perPage: Int?,
80 | @Query("order_by") orderBy: String?,
81 | @Query("stats") stats: Boolean?,
82 | @Query("resolution") resolution: String?,
83 | @Query("quantity") quantity: Int?
84 | ): Call>
85 |
86 | @GET("users/{username}/collections")
87 | suspend fun getCollectionsSuspend(
88 | @Path("username") username: String,
89 | @Query("page") page: Int?,
90 | @Query("per_page") perPage: Int?,
91 | @Query("order_by") orderBy: String?,
92 | @Query("stats") stats: Boolean?,
93 | @Query("resolution") resolution: String?,
94 | @Query("quantity") quantity: Int?
95 | ): List
96 |
97 | @GET("users/{username}/statistics")
98 | fun getStatistics(
99 | @Path("username") username: String,
100 | @Query("resolution") resolution: String?,
101 | @Query("quantity") quantity: Int?
102 | ): Call
103 |
104 | @GET("users/{username}/statistics")
105 | suspend fun getStatisticsSuspend(
106 | @Path("username") username: String,
107 | @Query("resolution") resolution: String?,
108 | @Query("quantity") quantity: Int?
109 | ): Stats
110 |
111 | @GET("search/users")
112 | fun search(
113 | @Query("query") query: String,
114 | @Query("page") page: Int?,
115 | @Query("per_page") perPage: Int?
116 | ): Call>
117 |
118 | @GET("search/users")
119 | suspend fun searchSuspend(
120 | @Query("query") query: String,
121 | @Query("page") page: Int?,
122 | @Query("per_page") perPage: Int?
123 | ): SearchResults
124 | }
125 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/Unsplash.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash
2 |
3 | import android.content.Context
4 | import android.net.Uri
5 | import androidx.browser.customtabs.CustomTabsIntent
6 | import com.keenencharles.unsplash.api.*
7 | import com.keenencharles.unsplash.api.endpoints.*
8 | import com.keenencharles.unsplash.models.Token
9 | import okhttp3.OkHttpClient
10 | import okhttp3.logging.HttpLoggingInterceptor
11 | import retrofit2.Retrofit
12 | import retrofit2.converter.gson.GsonConverterFactory
13 |
14 | @JvmSuppressWildcards
15 | class Unsplash(private var clientID: String, private var token: String? = null) {
16 |
17 | lateinit var photos: PhotoAPI
18 | lateinit var collections: CollectionAPI
19 | lateinit var users: UserAPI
20 | lateinit var stats: StatsAPI
21 |
22 | private lateinit var authApiService: AuthEndpointInterface
23 |
24 | private val TAG = "AndroidUnsplash"
25 |
26 | init {
27 | createServices(clientID, token)
28 | }
29 |
30 | private fun createServices(clientId: String, token: String?) {
31 | val retrofit = createRetrofitClient(clientId, token)
32 |
33 | val handler = UnsplashResponseHandler()
34 | photos = PhotoAPI(retrofit.create(PhotosEndpointInterface::class.java), handler)
35 | collections =
36 | CollectionAPI(retrofit.create(CollectionsEndpointInterface::class.java), handler)
37 | users = UserAPI(retrofit.create(UserEndpointInterface::class.java), handler)
38 | stats = StatsAPI(retrofit.create(StatsEndpointInterface::class.java), handler)
39 |
40 | authApiService = retrofit.create(AuthEndpointInterface::class.java)
41 | }
42 |
43 | fun authorize(
44 | context: Context,
45 | redirectURI: String,
46 | scopeList: List
47 | ) {
48 | var scopes = StringBuilder()
49 | for (scope in scopeList) {
50 | scopes.append(scope.scope).append("+")
51 | }
52 |
53 | scopes = scopes.deleteCharAt(scopes.length - 1)
54 |
55 | val url =
56 | "https://unsplash.com/oauth/authorize?client_id=$clientID&redirect_uri=$redirectURI&response_type=code&scope=$scopes"
57 | val builder = CustomTabsIntent.Builder()
58 | val customTabsIntent = builder.build()
59 | customTabsIntent.launchUrl(context, Uri.parse(url))
60 | }
61 |
62 | fun getToken(
63 | clientSecret: String,
64 | redirectURI: String,
65 | code: String,
66 | onComplete: (Token) -> Unit,
67 | onError: (String) -> Unit
68 | ) {
69 | val call = authApiService.getToken(
70 | "https://unsplash.com/oauth/token",
71 | clientID,
72 | clientSecret,
73 | redirectURI,
74 | code,
75 | "authorization_code"
76 | )
77 | call.enqueue(UnsplashCallback(onComplete, onError))
78 | }
79 |
80 | suspend fun getToken(
81 | clientSecret: String,
82 | redirectURI: String,
83 | code: String
84 | ): UnsplashResource {
85 | val responseHandler = UnsplashResponseHandler()
86 | return try {
87 | val res = authApiService.getTokenSuspend(
88 | "https://unsplash.com/oauth/token",
89 | clientID,
90 | clientSecret,
91 | redirectURI,
92 | code,
93 | "authorization_code"
94 | )
95 | responseHandler.handleSuccess(res)
96 |
97 | } catch (e: Exception) {
98 | responseHandler.handleException(e)
99 | }
100 | }
101 |
102 | fun setToken(token: String) {
103 | this.token = token
104 | createServices(clientID, token)
105 | }
106 |
107 | private fun createRetrofitClient(clientID: String, token: String?): Retrofit {
108 | val builder = Retrofit.Builder()
109 | val headerInterceptor = HeaderInterceptor(clientID, token)
110 |
111 | val client = OkHttpClient.Builder()
112 | .addInterceptor(headerInterceptor)
113 |
114 | if (BuildConfig.DEBUG) {
115 | val logging = HttpLoggingInterceptor()
116 | logging.level = HttpLoggingInterceptor.Level.BODY
117 | client.addInterceptor(logging)
118 | }
119 |
120 | return builder
121 | .baseUrl("https://api.unsplash.com/")
122 | .addConverterFactory(GsonConverterFactory.create())
123 | .client(client.build())
124 | .build()
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Android Unsplash (Unofficial)
2 | An unofficial Unsplash API library for Android
3 |
4 | ## Gradle
5 | Add the line below to your build.gradle to use:
6 | ~~~
7 | repositories {
8 | mavenCentral()
9 | }
10 |
11 | dependencies {
12 | implementation 'com.keenencharles:androidunsplash:3.1.2'
13 | }
14 | ~~~
15 |
16 | ## Usage
17 |
18 | ### Initialize Unsplash Client
19 | ~~~~~
20 | val unsplash = Unsplash(YOUR_CLIENT_ID, YOUR_TOKEN);
21 | ~~~~~
22 | You can create an app for your project at
23 | You'll receive a Client ID and a Client Secret
24 |
25 | ### User Authentication
26 | Unsplash uses OAuth2 for user authentication.
27 |
28 | You can call the `authorize()` method to start the process with the scopes you require access to. Ensure those scopes have been turned on in the Unsplash project dashboard.
29 |
30 | ~~~~~
31 | val scopes = listOf(Scope.PUBLIC, Scope.READ_USER, Scope.WRITE_USER)
32 | unsplash.authorize(this, YOUR_REDIRECT_URI, scopes)
33 | ~~~~~
34 |
35 | If your app is mobile only you can create a `redirectURI` by [defining a URI scheme](https://developer.android.com/training/app-links/deep-linking) in your Manifest
36 |
37 | Once the user has been redirected to your app you can need to retrieve the `code` parameter provided in the Intent and call the `getToken()` method.
38 |
39 | ~~~~~
40 | unsplash.getToken(YOUR_SECRET, YOUR_REDIRECT_URI, code, {
41 | Log.d("Token", it.accessToken)
42 | }, {
43 | Log.d("Token", it)
44 | })
45 | ~~~~~
46 |
47 | Add the token you receive to your unsplash client to authenticate user-related requests.
48 | ~~~~~
49 | unsplash.setToken(token.accessToken);
50 | ~~~~~
51 |
52 | ### Get A List of Photos
53 | ~~~~~
54 | unsplash.photos.get(1, 10, Order.LATEST,
55 | onComplete = {
56 | Log.d("Photos", "Photos Found $it")
57 | },
58 | onError = {
59 | Log.d("Unsplash", it)
60 | }
61 | )
62 | ~~~~~
63 |
64 | ### Get A Photo By Id
65 | ~~~~~
66 | unsplash.photos.getById("ID",
67 | onComplete = {
68 | Log.d("Photos", "Photo Found $it")
69 | },
70 | onError = {
71 | Log.d("Photos", it)
72 | }
73 | )
74 | ~~~~~
75 |
76 | ### Search
77 | ~~~~~
78 | unsplash.photos.search(query,
79 | onComplete = {
80 | Log.d("Photos", "Total Results Found " + it.total!!)
81 | val photos = it.results
82 | },
83 | onError = {
84 | Log.d("Unsplash", it)
85 | }
86 | )
87 | ~~~~~
88 |
89 | ## Coroutines
90 | You can also use the library with coroutines by using the same functions without any callbacks.
91 | ~~~~~
92 | val res = unsplash.photos.search(query)
93 | if (res is UnsplashResource.Success) {
94 | Log.d(TAG, "Photos found")
95 | }
96 | else if (res is UnsplashResource.Error) {
97 | Log.d(TAG, res.errorMessage)
98 | }
99 | ~~~~~
100 |
101 | ## Other Features
102 | You can access other features by using their respective classes.
103 |
104 | Collections with `unsplash.collections`
105 |
106 | Users with `unsplash.users`
107 |
108 | Stats with `unsplash.stats`
109 |
110 | Take a look at the API documentation for what each call does in detail
111 |
112 | ## Java
113 |
114 | For Java support you can use the previous version of this library [here](https://github.com/KeenenCharles/AndroidUnplash/blob/master/README-JAVA.md)
115 |
116 | ## Built With This Library
117 | + [Walldrobe](https://play.google.com/store/apps/details?id=walldrobe.coffecode.com)
118 | + [Love Diary](https://play.google.com/store/apps/details?id=com.kilic.tweetydiary)
119 | + [Advice](https://play.google.com/store/apps/details?id=my.sustento.apeaceofadvice)
120 |
121 | # License
122 | ~~~
123 | MIT License
124 |
125 | Copyright (c) 2017 Keenen Charles
126 |
127 | Permission is hereby granted, free of charge, to any person obtaining a copy
128 | of this software and associated documentation files (the "Software"), to deal
129 | in the Software without restriction, including without limitation the rights
130 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
131 | copies of the Software, and to permit persons to whom the Software is
132 | furnished to do so, subject to the following conditions:
133 |
134 | The above copyright notice and this permission notice shall be included in all
135 | copies or substantial portions of the Software.
136 |
137 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
138 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
139 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
140 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
141 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
142 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
143 | SOFTWARE.
144 |
145 | ~~~
146 |
--------------------------------------------------------------------------------
/app/src/main/java/com/keenencharles/unsplashdemo/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplashdemo
2 |
3 | import android.content.Context
4 | import android.content.SharedPreferences
5 | import android.os.Bundle
6 | import android.util.Log
7 | import android.view.Menu
8 | import android.view.MenuInflater
9 | import android.view.MenuItem
10 | import androidx.appcompat.app.AppCompatActivity
11 | import androidx.databinding.DataBindingUtil
12 | import androidx.recyclerview.widget.GridLayoutManager
13 | import com.keenencharles.unsplash.Unsplash
14 | import com.keenencharles.unsplash.models.Order
15 | import com.keenencharles.unsplash.api.Scope
16 | import com.keenencharles.unsplash.api.UnsplashResource
17 | import com.keenencharles.unsplashdemo.databinding.ActivityMainBinding
18 | import kotlinx.coroutines.Dispatchers
19 | import kotlinx.coroutines.GlobalScope
20 | import kotlinx.coroutines.launch
21 | import kotlinx.coroutines.withContext
22 | import java.util.*
23 |
24 | class MainActivity : AppCompatActivity() {
25 |
26 | private val redirectURI = "example://androidunsplash/callback"
27 |
28 | private lateinit var unsplash: Unsplash
29 |
30 | private lateinit var mBinding: ActivityMainBinding
31 | private lateinit var adapter: PhotoAdapter
32 | private lateinit var sharedPref: SharedPreferences
33 |
34 | private val TAG = "AndroidUnsplash"
35 |
36 | override fun onCreate(savedInstanceState: Bundle?) {
37 | super.onCreate(savedInstanceState)
38 | mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
39 |
40 | mBinding.recyclerView.layoutManager = GridLayoutManager(this@MainActivity, 2)
41 | adapter = PhotoAdapter {}
42 | mBinding.recyclerView.adapter = adapter
43 |
44 | mBinding.searchButton.setOnClickListener {
45 | search()
46 | }
47 |
48 | sharedPref = getPreferences(Context.MODE_PRIVATE)
49 |
50 | val token = sharedPref.getString("TOKEN", null)
51 | unsplash = Unsplash(BuildConfig.UnsplashID, token)
52 |
53 | fetchPhotos()
54 |
55 | handleAuthCallback()
56 | }
57 |
58 | private fun fetchPhotos() {
59 | GlobalScope.launch {
60 | withContext(Dispatchers.IO) {
61 | val res = unsplash.photos.get(1, 10, Order.LATEST)
62 |
63 | if (res is UnsplashResource.Success) {
64 | withContext(Dispatchers.Main) {
65 | adapter.updateList(res.data!!)
66 | }
67 | }
68 | else if (res is UnsplashResource.Error) {
69 | Log.d(TAG, res.errorMessage)
70 | }
71 | }
72 | }
73 | }
74 |
75 | private fun handleAuthCallback() {
76 | val data = intent.data
77 | val code = data?.query?.replace("code=", "")
78 |
79 | code?.let { fetchToken(code) }
80 | }
81 |
82 | private fun fetchToken(code: String) {
83 | GlobalScope.launch {
84 | withContext(Dispatchers.IO) {
85 | val res = unsplash.getToken(BuildConfig.UnsplashSecret, redirectURI, code)
86 |
87 | val token = res.data!!.accessToken
88 |
89 | if (res is UnsplashResource.Success) {
90 | Log.d(TAG, token)
91 | unsplash.setToken(token)
92 | sharedPref.edit().putString("TOKEN", token).apply()
93 | } else if (res is UnsplashResource.Error) {
94 | Log.d(TAG, res.errorMessage)
95 | }
96 | }
97 | }
98 | }
99 |
100 | private fun authorize() {
101 | val scopes = listOf(Scope.PUBLIC, Scope.READ_USER, Scope.WRITE_USER)
102 | unsplash.authorize(this@MainActivity, redirectURI, scopes)
103 | }
104 |
105 | private fun search() {
106 | val query = mBinding.editText.text.toString()
107 |
108 | unsplash.photos.search(query,
109 | onComplete = {
110 | Log.d(TAG, "Total Results Found " + it.total!!)
111 | val photos = it.results
112 | adapter.updateList(photos)
113 | },
114 | onError = {
115 | Log.d(TAG, it)
116 | }
117 | )
118 | }
119 |
120 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
121 | val inflater: MenuInflater = menuInflater
122 | inflater.inflate(R.menu.main_menu, menu)
123 | return true
124 | }
125 |
126 | override fun onOptionsItemSelected(item: MenuItem): Boolean {
127 | return when (item.itemId) {
128 | R.id.sign_in -> {
129 | authorize()
130 | true
131 | }
132 | else -> super.onOptionsItemSelected(item)
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10 | DEFAULT_JVM_OPTS=""
11 |
12 | APP_NAME="Gradle"
13 | APP_BASE_NAME=`basename "$0"`
14 |
15 | # Use the maximum available, or set MAX_FD != -1 to use that value.
16 | MAX_FD="maximum"
17 |
18 | warn ( ) {
19 | echo "$*"
20 | }
21 |
22 | die ( ) {
23 | echo
24 | echo "$*"
25 | echo
26 | exit 1
27 | }
28 |
29 | # OS specific support (must be 'true' or 'false').
30 | cygwin=false
31 | msys=false
32 | darwin=false
33 | case "`uname`" in
34 | CYGWIN* )
35 | cygwin=true
36 | ;;
37 | Darwin* )
38 | darwin=true
39 | ;;
40 | MINGW* )
41 | msys=true
42 | ;;
43 | esac
44 |
45 | # Attempt to set APP_HOME
46 | # Resolve links: $0 may be a link
47 | PRG="$0"
48 | # Need this for relative symlinks.
49 | while [ -h "$PRG" ] ; do
50 | ls=`ls -ld "$PRG"`
51 | link=`expr "$ls" : '.*-> \(.*\)$'`
52 | if expr "$link" : '/.*' > /dev/null; then
53 | PRG="$link"
54 | else
55 | PRG=`dirname "$PRG"`"/$link"
56 | fi
57 | done
58 | SAVED="`pwd`"
59 | cd "`dirname \"$PRG\"`/" >/dev/null
60 | APP_HOME="`pwd -P`"
61 | cd "$SAVED" >/dev/null
62 |
63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
64 |
65 | # Determine the Java command to use to start the JVM.
66 | if [ -n "$JAVA_HOME" ] ; then
67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
68 | # IBM's JDK on AIX uses strange locations for the executables
69 | JAVACMD="$JAVA_HOME/jre/sh/java"
70 | else
71 | JAVACMD="$JAVA_HOME/bin/java"
72 | fi
73 | if [ ! -x "$JAVACMD" ] ; then
74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
75 |
76 | Please set the JAVA_HOME variable in your environment to match the
77 | location of your Java installation."
78 | fi
79 | else
80 | JAVACMD="java"
81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
82 |
83 | Please set the JAVA_HOME variable in your environment to match the
84 | location of your Java installation."
85 | fi
86 |
87 | # Increase the maximum file descriptors if we can.
88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
89 | MAX_FD_LIMIT=`ulimit -H -n`
90 | if [ $? -eq 0 ] ; then
91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
92 | MAX_FD="$MAX_FD_LIMIT"
93 | fi
94 | ulimit -n $MAX_FD
95 | if [ $? -ne 0 ] ; then
96 | warn "Could not set maximum file descriptor limit: $MAX_FD"
97 | fi
98 | else
99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
100 | fi
101 | fi
102 |
103 | # For Darwin, add options to specify how the application appears in the dock
104 | if $darwin; then
105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
106 | fi
107 |
108 | # For Cygwin, switch paths to Windows format before running java
109 | if $cygwin ; then
110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
112 | JAVACMD=`cygpath --unix "$JAVACMD"`
113 |
114 | # We build the pattern for arguments to be converted via cygpath
115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
116 | SEP=""
117 | for dir in $ROOTDIRSRAW ; do
118 | ROOTDIRS="$ROOTDIRS$SEP$dir"
119 | SEP="|"
120 | done
121 | OURCYGPATTERN="(^($ROOTDIRS))"
122 | # Add a user-defined pattern to the cygpath arguments
123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
125 | fi
126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
127 | i=0
128 | for arg in "$@" ; do
129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
131 |
132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
134 | else
135 | eval `echo args$i`="\"$arg\""
136 | fi
137 | i=$((i+1))
138 | done
139 | case $i in
140 | (0) set -- ;;
141 | (1) set -- "$args0" ;;
142 | (2) set -- "$args0" "$args1" ;;
143 | (3) set -- "$args0" "$args1" "$args2" ;;
144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
150 | esac
151 | fi
152 |
153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
154 | function splitJvmOpts() {
155 | JVM_OPTS=("$@")
156 | }
157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
159 |
160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
161 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/api/endpoints/PhotosEndpointInterface.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash.api.endpoints
2 |
3 | import com.keenencharles.unsplash.models.Download
4 | import com.keenencharles.unsplash.models.Photo
5 | import com.keenencharles.unsplash.models.SearchResults
6 | import retrofit2.Call
7 | import retrofit2.http.*
8 |
9 | interface PhotosEndpointInterface {
10 |
11 | @GET("photos/{id}")
12 | fun getById(@Path("id") id: String): Call
13 |
14 | @GET("photos/{id}")
15 | suspend fun getByIdSuspend(@Path("id") id: String): Photo
16 |
17 | @GET("photos")
18 | fun get(
19 | @Query("page") page: Int?,
20 | @Query("per_page") perPage: Int?,
21 | @Query("order_by") orderBy: String?
22 | ): Call>
23 |
24 | @GET("photos")
25 | suspend fun getSuspend(
26 | @Query("page") page: Int?,
27 | @Query("per_page") perPage: Int?,
28 | @Query("order_by") orderBy: String?
29 | ): List
30 |
31 | @GET("photos/random")
32 | fun getRandomPhoto(
33 | @Query("collections") collections: String?,
34 | @Query("featured") featured: Boolean?,
35 | @Query("username") username: String?,
36 | @Query("query") query: String?,
37 | @Query("orientation") orientation: String?,
38 | @Query("content_filter") content: String?
39 | ): Call
40 |
41 | @GET("photos/random")
42 | suspend fun getRandomPhotoSuspend(
43 | @Query("collections") collections: String?,
44 | @Query("featured") featured: Boolean?,
45 | @Query("username") username: String?,
46 | @Query("query") query: String?,
47 | @Query("orientation") orientation: String?,
48 | @Query("content_filter") content: String?
49 | ): Photo
50 |
51 | @GET("photos/random")
52 | fun getRandomPhotos(
53 | @Query("collections") collections: String?,
54 | @Query("featured") featured: Boolean?,
55 | @Query("username") username: String?,
56 | @Query("query") query: String?,
57 | @Query("orientation") orientation: String?,
58 | @Query("count") count: Int?,
59 | @Query("content_filter") content: String?
60 | ): Call>
61 |
62 | @GET("photos/random")
63 | suspend fun getRandomPhotosSuspend(
64 | @Query("collections") collections: String?,
65 | @Query("featured") featured: Boolean?,
66 | @Query("username") username: String?,
67 | @Query("query") query: String?,
68 | @Query("orientation") orientation: String?,
69 | @Query("count") count: Int?,
70 | @Query("content_filter") content: String?
71 | ): List
72 |
73 | @GET("photos/{id}/download")
74 | fun getDownloadLink(@Path("id") id: String): Call
75 |
76 | @GET("photos/{id}/download")
77 | suspend fun getDownloadLinkSuspend(@Path("id") id: String): Download
78 |
79 | @GET("search/photos")
80 | fun search(
81 | @Query("query") query: String,
82 | @Query("page") page: Int?,
83 | @Query("per_page") perPage: Int?,
84 | @Query("collections") collections: String?,
85 | @Query("orientation") orientation: String?,
86 | @Query("content_filter") content: String?,
87 | @Query("color") color: String?
88 | ): Call>
89 |
90 | @GET("search/photos")
91 | suspend fun searchSuspend(
92 | @Query("query") query: String,
93 | @Query("page") page: Int?,
94 | @Query("per_page") perPage: Int?,
95 | @Query("collections") collections: String?,
96 | @Query("orientation") orientation: String?,
97 | @Query("content_filter") content: String?,
98 | @Query("color") color: String?
99 | ): SearchResults
100 |
101 | @PUT("photos/{id}")
102 | fun update(
103 | @Path("id") id: String,
104 | @Query("location[latitude]") latitude: String?,
105 | @Query("location[longitude]") longitude: String?,
106 | @Query("location[name]") name: String?,
107 | @Query("location[city]") city: String?,
108 | @Query("location[country]") country: String?,
109 | @Query("location[confidential]") confidential: String?,
110 | @Query("exif[make]") make: String?,
111 | @Query("exif[model]") model: String?,
112 | @Query("exif[exposure_time]") exposureTime: String?,
113 | @Query("exif[exposure_value]") exposureValue: String?,
114 | @Query("exif[focal_length]") focalLength: String?,
115 | @Query("exif[iso_speed_ratings]") iso: String?
116 | ): Call
117 |
118 | @PUT("photos/{id}")
119 | suspend fun updateSuspend(
120 | @Path("id") id: String,
121 | @Query("location[latitude]") latitude: String?,
122 | @Query("location[longitude]") longitude: String?,
123 | @Query("location[name]") name: String?,
124 | @Query("location[city]") city: String?,
125 | @Query("location[country]") country: String?,
126 | @Query("location[confidential]") confidential: String?,
127 | @Query("exif[make]") make: String?,
128 | @Query("exif[model]") model: String?,
129 | @Query("exif[exposure_time]") exposureTime: String?,
130 | @Query("exif[exposure_value]") exposureValue: String?,
131 | @Query("exif[focal_length]") focalLength: String?,
132 | @Query("exif[iso_speed_ratings]") iso: String?
133 | ): Photo
134 |
135 | @PUT("photos/{id}/like")
136 | fun like(@Path("id") id: String): Call
137 |
138 | @PUT("photos/{id}/like")
139 | suspend fun likeSuspend(@Path("id") id: String): Photo
140 |
141 | @DELETE("photos/{id}/like")
142 | fun unlike(@Path("id") id: String): Call
143 |
144 | @DELETE("photos/{id}/like")
145 | suspend fun unlikeSuspend(@Path("id") id: String): Photo
146 | }
147 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/CollectionAPI.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash
2 |
3 | import com.keenencharles.unsplash.api.UnsplashCallback
4 | import com.keenencharles.unsplash.api.UnsplashResource
5 | import com.keenencharles.unsplash.api.UnsplashResponseHandler
6 | import com.keenencharles.unsplash.api.endpoints.CollectionsEndpointInterface
7 | import com.keenencharles.unsplash.models.Photo
8 | import com.keenencharles.unsplash.models.SearchResults
9 | import com.keenencharles.unsplash.models.Collection
10 |
11 | @JvmSuppressWildcards
12 | class CollectionAPI(
13 | private var apiService: CollectionsEndpointInterface,
14 | private var responseHandler: UnsplashResponseHandler
15 | ) {
16 |
17 | fun get(
18 | page: Int? = null,
19 | perPage: Int? = null,
20 | onComplete: (List) -> Unit,
21 | onError: (String) -> Unit
22 | ) {
23 | val call = apiService.get(page, perPage)
24 | call.enqueue(UnsplashCallback(onComplete, onError))
25 | }
26 |
27 | suspend fun get(
28 | page: Int? = null,
29 | perPage: Int? = null
30 | ): UnsplashResource> {
31 | return try {
32 | val res = apiService.getSuspend(page, perPage)
33 | responseHandler.handleSuccess(res)
34 |
35 | } catch (e: Exception) {
36 | responseHandler.handleException(e)
37 | }
38 | }
39 |
40 | fun search(
41 | query: String,
42 | page: Int? = null,
43 | perPage: Int? = null,
44 | onComplete: (SearchResults) -> Unit,
45 | onError: (String) -> Unit
46 | ) {
47 | val call = apiService.search(query, page, perPage)
48 | call.enqueue(UnsplashCallback(onComplete, onError))
49 | }
50 |
51 | suspend fun search(
52 | query: String,
53 | page: Int? = null,
54 | perPage: Int? = null
55 | ): UnsplashResource> {
56 | return try {
57 | val res = apiService.searchSuspend(query, page, perPage)
58 | responseHandler.handleSuccess(res)
59 |
60 | } catch (e: Exception) {
61 | responseHandler.handleException(e)
62 | }
63 | }
64 |
65 | fun getRelated(
66 | id: String,
67 | onComplete: (List) -> Unit,
68 | onError: (String) -> Unit
69 | ) {
70 | val call = apiService.getRelated(id)
71 | call.enqueue(UnsplashCallback(onComplete, onError))
72 | }
73 |
74 | suspend fun getRelated(
75 | id: String
76 | ): UnsplashResource> {
77 | return try {
78 | val res = apiService.getRelatedSuspend(id)
79 | responseHandler.handleSuccess(res)
80 |
81 | } catch (e: Exception) {
82 | responseHandler.handleException(e)
83 | }
84 | }
85 |
86 | fun getById(
87 | id: String,
88 | onComplete: (Collection) -> Unit,
89 | onError: (String) -> Unit
90 | ) {
91 | val call = apiService.getById(id)
92 | call.enqueue(UnsplashCallback(onComplete, onError))
93 | }
94 |
95 | suspend fun getById(
96 | id: String
97 | ): UnsplashResource {
98 | return try {
99 | val res = apiService.getByIdSuspend(id)
100 | responseHandler.handleSuccess(res)
101 |
102 | } catch (e: Exception) {
103 | responseHandler.handleException(e)
104 | }
105 | }
106 |
107 | fun getPhotos(
108 | id: String,
109 | page: Int? = null,
110 | perPage: Int? = null,
111 | onComplete: (List) -> Unit,
112 | onError: (String) -> Unit
113 | ) {
114 | val call = apiService.getPhotos(id, page, perPage)
115 | call.enqueue(UnsplashCallback(onComplete, onError))
116 | }
117 |
118 | suspend fun getPhotos(
119 | id: String,
120 | page: Int? = null,
121 | perPage: Int? = null
122 | ): UnsplashResource> {
123 | return try {
124 | val res = apiService.getPhotosSuspend(id, page, perPage)
125 | responseHandler.handleSuccess(res)
126 |
127 | } catch (e: Exception) {
128 | responseHandler.handleException(e)
129 | }
130 | }
131 |
132 | fun create(
133 | title: String,
134 | description: String? = null,
135 | private: Boolean? = null,
136 | onComplete: (Collection) -> Unit,
137 | onError: (String) -> Unit
138 | ) {
139 | val call = apiService.create(title, description, private)
140 | call.enqueue(UnsplashCallback(onComplete, onError))
141 | }
142 |
143 | suspend fun create(
144 | title: String,
145 | description: String? = null,
146 | private: Boolean? = null
147 | ): UnsplashResource {
148 | return try {
149 | val res = apiService.createSuspend(title, description, private)
150 | responseHandler.handleSuccess(res)
151 |
152 | } catch (e: Exception) {
153 | responseHandler.handleException(e)
154 | }
155 | }
156 |
157 | fun update(
158 | id: String,
159 | title: String? = null,
160 | description: String? = null,
161 | private: Boolean? = null,
162 | onComplete: (Collection) -> Unit,
163 | onError: (String) -> Unit
164 | ) {
165 | val call = apiService.update(id, title, description, private)
166 | call.enqueue(UnsplashCallback(onComplete, onError))
167 | }
168 |
169 | suspend fun update(
170 | id: String,
171 | title: String? = null,
172 | description: String? = null,
173 | private: Boolean? = null
174 | ): UnsplashResource {
175 | return try {
176 | val res = apiService.updateSuspend(id, title, description, private)
177 | responseHandler.handleSuccess(res)
178 |
179 | } catch (e: Exception) {
180 | responseHandler.handleException(e)
181 | }
182 | }
183 |
184 | fun delete(
185 | id: String,
186 | onComplete: (Collection) -> Unit,
187 | onError: (String) -> Unit
188 | ) {
189 | val call = apiService.delete(id)
190 | call.enqueue(UnsplashCallback(onComplete, onError))
191 | }
192 |
193 | suspend fun delete(
194 | id: String,
195 | ): UnsplashResource {
196 | return try {
197 | val res = apiService.deleteSuspend(id)
198 | responseHandler.handleSuccess(res)
199 |
200 | } catch (e: Exception) {
201 | responseHandler.handleException(e)
202 | }
203 | }
204 |
205 | fun addPhoto(
206 | collectionId: String,
207 | photoId: String,
208 | onComplete: (Collection) -> Unit,
209 | onError: (String) -> Unit
210 | ) {
211 | val call = apiService.addPhoto(collectionId, photoId)
212 | call.enqueue(UnsplashCallback(onComplete, onError))
213 | }
214 |
215 | suspend fun addPhoto(
216 | collectionId: String,
217 | photoId: String
218 | ): UnsplashResource {
219 | return try {
220 | val res = apiService.addPhotoSuspend(collectionId, photoId)
221 | responseHandler.handleSuccess(res)
222 |
223 | } catch (e: Exception) {
224 | responseHandler.handleException(e)
225 | }
226 | }
227 |
228 | fun removePhoto(
229 | collectionId: String,
230 | photoId: String,
231 | onComplete: (Collection) -> Unit,
232 | onError: (String) -> Unit
233 | ) {
234 | val call = apiService.removePhoto(collectionId, photoId)
235 | call.enqueue(UnsplashCallback(onComplete, onError))
236 | }
237 |
238 | suspend fun removePhoto(
239 | collectionId: String,
240 | photoId: String
241 | ): UnsplashResource {
242 | return try {
243 | val res = apiService.removePhotoSuspend(collectionId, photoId)
244 | responseHandler.handleSuccess(res)
245 |
246 | } catch (e: Exception) {
247 | responseHandler.handleException(e)
248 | }
249 | }
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/UserAPI.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash
2 |
3 | import com.keenencharles.unsplash.models.Order
4 | import com.keenencharles.unsplash.api.UnsplashCallback
5 | import com.keenencharles.unsplash.api.UnsplashResource
6 | import com.keenencharles.unsplash.api.UnsplashResponseHandler
7 | import com.keenencharles.unsplash.api.endpoints.UserEndpointInterface
8 | import com.keenencharles.unsplash.models.*
9 | import com.keenencharles.unsplash.models.Collection
10 |
11 | @JvmSuppressWildcards
12 | class UserAPI(
13 | private var apiService: UserEndpointInterface,
14 | private var responseHandler: UnsplashResponseHandler
15 | ) {
16 |
17 | fun getCurrent(
18 | onComplete: (User) -> Unit,
19 | onError: (String) -> Unit
20 | ) {
21 | val call = apiService.getCurrent()
22 | call.enqueue(UnsplashCallback(onComplete, onError))
23 | }
24 |
25 | suspend fun getCurrent(): UnsplashResource {
26 | return try {
27 | val res = apiService.getCurrentSuspend()
28 | responseHandler.handleSuccess(res)
29 |
30 | } catch (e: Exception) {
31 | responseHandler.handleException(e)
32 | }
33 | }
34 |
35 | fun updateCurrent(
36 | user: User,
37 | onComplete: (User) -> Unit,
38 | onError: (String) -> Unit
39 | ) {
40 | val call = apiService.updateCurrent(user)
41 | call.enqueue(UnsplashCallback(onComplete, onError))
42 | }
43 |
44 | suspend fun updateCurrent(
45 | user: User
46 | ): UnsplashResource {
47 | return try {
48 | val res = apiService.updateCurrentSuspend(user)
49 | responseHandler.handleSuccess(res)
50 |
51 | } catch (e: Exception) {
52 | responseHandler.handleException(e)
53 | }
54 | }
55 |
56 | fun getByUsername(
57 | username: String,
58 | onComplete: (User) -> Unit,
59 | onError: (String) -> Unit
60 | ) {
61 | val call = apiService.getByUsername(username)
62 | call.enqueue(UnsplashCallback(onComplete, onError))
63 | }
64 |
65 | suspend fun getByUsername(
66 | username: String
67 | ): UnsplashResource {
68 | return try {
69 | val res = apiService.getByUsernameSuspend(username)
70 | responseHandler.handleSuccess(res)
71 |
72 | } catch (e: Exception) {
73 | responseHandler.handleException(e)
74 | }
75 | }
76 |
77 | fun getPortfolio(
78 | username: String,
79 | onComplete: (Portfolio) -> Unit,
80 | onError: (String) -> Unit
81 | ) {
82 | val call = apiService.getPortfolio(username)
83 | call.enqueue(UnsplashCallback(onComplete, onError))
84 | }
85 |
86 | suspend fun getPortfolio(
87 | username: String
88 | ): UnsplashResource {
89 | return try {
90 | val res = apiService.getPortfolioSuspend(username)
91 | responseHandler.handleSuccess(res)
92 |
93 | } catch (e: Exception) {
94 | responseHandler.handleException(e)
95 | }
96 | }
97 |
98 | fun getPhotos(
99 | username: String,
100 | page: Int? = null,
101 | perPage: Int? = null,
102 | order: Order? = null,
103 | stats: Boolean = false,
104 | resolution: String = "days",
105 | quantity: Int? = null,
106 | onComplete: (List) -> Unit,
107 | onError: (String) -> Unit
108 | ) {
109 | val call = apiService.getPhotos(
110 | username,
111 | page,
112 | perPage,
113 | order?.order,
114 | stats,
115 | resolution,
116 | quantity
117 | )
118 | call.enqueue(UnsplashCallback(onComplete, onError))
119 | }
120 |
121 | suspend fun getPhotos(
122 | username: String,
123 | page: Int? = null,
124 | perPage: Int? = null,
125 | order: Order? = null,
126 | stats: Boolean = false,
127 | resolution: String = "days",
128 | quantity: Int? = null
129 | ): UnsplashResource> {
130 | return try {
131 | val res = apiService.getPhotosSuspend(
132 | username,
133 | page,
134 | perPage,
135 | order?.order,
136 | stats,
137 | resolution,
138 | quantity
139 | )
140 | responseHandler.handleSuccess(res)
141 |
142 | } catch (e: Exception) {
143 | responseHandler.handleException(e)
144 | }
145 | }
146 |
147 | fun getLikedPhotos(
148 | username: String,
149 | page: Int? = null,
150 | perPage: Int? = null,
151 | order: Order? = null,
152 | onComplete: (List) -> Unit,
153 | onError: (String) -> Unit
154 | ) {
155 | val call = apiService.getLikedPhotos(username, page, perPage, order?.order)
156 | call.enqueue(UnsplashCallback(onComplete, onError))
157 | }
158 |
159 | suspend fun getLikedPhotos(
160 | username: String,
161 | page: Int? = null,
162 | perPage: Int? = null,
163 | order: Order? = null
164 | ): UnsplashResource> {
165 | return try {
166 | val res = apiService.getLikedPhotosSuspend(username, page, perPage, order?.order)
167 | responseHandler.handleSuccess(res)
168 |
169 | } catch (e: Exception) {
170 | responseHandler.handleException(e)
171 | }
172 | }
173 |
174 | fun getCollections(
175 | username: String,
176 | page: Int? = null,
177 | perPage: Int? = null,
178 | order: Order? = null,
179 | stats: Boolean = false,
180 | resolution: String = "days",
181 | quantity: Int? = null,
182 | onComplete: (List) -> Unit,
183 | onError: (String) -> Unit
184 | ) {
185 | val call = apiService.getCollections(
186 | username,
187 | page,
188 | perPage,
189 | order?.order,
190 | stats,
191 | resolution,
192 | quantity
193 | )
194 | call.enqueue(UnsplashCallback(onComplete, onError))
195 | }
196 |
197 | suspend fun getCollections(
198 | username: String,
199 | page: Int? = null,
200 | perPage: Int? = null,
201 | order: Order? = null,
202 | stats: Boolean = false,
203 | resolution: String = "days",
204 | quantity: Int? = null
205 | ): UnsplashResource> {
206 | return try {
207 | val res = apiService.getCollectionsSuspend(
208 | username,
209 | page,
210 | perPage,
211 | order?.order,
212 | stats,
213 | resolution,
214 | quantity
215 | )
216 | responseHandler.handleSuccess(res)
217 |
218 | } catch (e: Exception) {
219 | responseHandler.handleException(e)
220 | }
221 | }
222 |
223 | fun getStatistics(
224 | username: String,
225 | resolution: String = "days",
226 | quantity: Int? = null,
227 | onComplete: (Stats) -> Unit,
228 | onError: (String) -> Unit
229 | ) {
230 | val call = apiService.getStatistics(username, resolution, quantity)
231 | call.enqueue(UnsplashCallback(onComplete, onError))
232 | }
233 |
234 | suspend fun getStatistics(
235 | username: String,
236 | resolution: String = "days",
237 | quantity: Int? = null
238 | ): UnsplashResource {
239 | return try {
240 | val res = apiService.getStatisticsSuspend(username, resolution, quantity)
241 | responseHandler.handleSuccess(res)
242 |
243 | } catch (e: Exception) {
244 | responseHandler.handleException(e)
245 | }
246 | }
247 |
248 | fun search(
249 | query: String,
250 | page: Int? = null,
251 | perPage: Int? = null,
252 | onComplete: (SearchResults) -> Unit,
253 | onError: (String) -> Unit
254 | ) {
255 | val call = apiService.search(query, page, perPage)
256 | call.enqueue(UnsplashCallback(onComplete, onError))
257 | }
258 |
259 | suspend fun search(
260 | query: String,
261 | page: Int? = null,
262 | perPage: Int? = null
263 | ): UnsplashResource> {
264 | return try {
265 | val res = apiService.searchSuspend(query, page, perPage)
266 | responseHandler.handleSuccess(res)
267 |
268 | } catch (e: Exception) {
269 | responseHandler.handleException(e)
270 | }
271 | }
272 |
273 | }
274 |
--------------------------------------------------------------------------------
/androidunsplash/src/main/java/com/keenencharles/unsplash/PhotoAPI.kt:
--------------------------------------------------------------------------------
1 | package com.keenencharles.unsplash
2 |
3 | import com.keenencharles.unsplash.api.UnsplashCallback
4 | import com.keenencharles.unsplash.api.UnsplashResource
5 | import com.keenencharles.unsplash.api.UnsplashResponseHandler
6 | import com.keenencharles.unsplash.api.endpoints.PhotosEndpointInterface
7 | import com.keenencharles.unsplash.models.*
8 |
9 | @JvmSuppressWildcards
10 | class PhotoAPI(
11 | private var apiService: PhotosEndpointInterface,
12 | private var responseHandler: UnsplashResponseHandler
13 | ) {
14 |
15 | fun get(
16 | page: Int?,
17 | perPage: Int?,
18 | order: Order?,
19 | onComplete: (List) -> Unit,
20 | onError: (String) -> Unit
21 | ) {
22 | val call = apiService.get(page, perPage, order?.order)
23 | call.enqueue(UnsplashCallback(onComplete, onError))
24 | }
25 |
26 | suspend fun get(
27 | page: Int?,
28 | perPage: Int?,
29 | order: Order?
30 | ): UnsplashResource> {
31 | return try {
32 | val res = apiService.getSuspend(page, perPage, order?.order)
33 | responseHandler.handleSuccess(res)
34 |
35 | } catch (e: Exception) {
36 | responseHandler.handleException(e)
37 | }
38 | }
39 |
40 | fun getById(
41 | id: String,
42 | onComplete: (Photo) -> Unit,
43 | onError: (String) -> Unit
44 | ) {
45 | val call = apiService.getById(id)
46 | call.enqueue(UnsplashCallback(onComplete, onError))
47 | }
48 |
49 | suspend fun getById(
50 | id: String
51 | ): UnsplashResource {
52 | return try {
53 | val res = apiService.getByIdSuspend(id)
54 | responseHandler.handleSuccess(res)
55 |
56 | } catch (e: Exception) {
57 | responseHandler.handleException(e)
58 | }
59 | }
60 |
61 | fun getRandomPhoto(
62 | collections: String? = null,
63 | featured: Boolean? = false,
64 | username: String? = null,
65 | query: String? = null,
66 | orientation: Orientation? = null,
67 | contentFilter: ContentFilter? = null,
68 | onComplete: (Photo) -> Unit,
69 | onError: (String) -> Unit
70 | ) {
71 | val call = apiService.getRandomPhoto(
72 | collections,
73 | featured,
74 | username,
75 | query,
76 | orientation?.orientation,
77 | contentFilter?.type
78 | )
79 | call.enqueue(UnsplashCallback(onComplete, onError))
80 | }
81 |
82 | suspend fun getRandomPhoto(
83 | collections: String? = null,
84 | featured: Boolean? = false,
85 | username: String? = null,
86 | query: String? = null,
87 | orientation: Orientation? = null,
88 | contentFilter: ContentFilter? = null
89 | ): UnsplashResource {
90 | return try {
91 | val res = apiService.getRandomPhotoSuspend(
92 | collections,
93 | featured,
94 | username,
95 | query,
96 | orientation?.orientation,
97 | contentFilter?.type
98 | )
99 | responseHandler.handleSuccess(res)
100 |
101 | } catch (e: Exception) {
102 | responseHandler.handleException(e)
103 | }
104 | }
105 |
106 | fun getRandomPhotos(
107 | collections: String? = null,
108 | featured: Boolean? = false,
109 | username: String? = null,
110 | query: String? = null,
111 | orientation: Orientation? = null,
112 | count: Int = 1,
113 | contentFilter: ContentFilter? = null,
114 | onComplete: (List) -> Unit,
115 | onError: (String) -> Unit
116 | ) {
117 | val call = apiService.getRandomPhotos(
118 | collections,
119 | featured,
120 | username,
121 | query,
122 | orientation?.orientation,
123 | count,
124 | contentFilter?.type
125 | )
126 | call.enqueue(UnsplashCallback(onComplete, onError))
127 | }
128 |
129 | suspend fun getRandomPhotos(
130 | collections: String? = null,
131 | featured: Boolean? = false,
132 | username: String? = null,
133 | query: String? = null,
134 | orientation: Orientation? = null,
135 | count: Int = 1,
136 | contentFilter: ContentFilter? = null
137 | ): UnsplashResource> {
138 | return try {
139 | val res = apiService.getRandomPhotosSuspend(
140 | collections,
141 | featured,
142 | username,
143 | query,
144 | orientation?.orientation,
145 | count,
146 | contentFilter?.type
147 | )
148 | responseHandler.handleSuccess(res)
149 |
150 | } catch (e: Exception) {
151 | responseHandler.handleException(e)
152 | }
153 | }
154 |
155 | fun search(
156 | query: String,
157 | page: Int? = null,
158 | perPage: Int? = null,
159 | collections: String? = null,
160 | orientation: Orientation? = null,
161 | contentFilter: ContentFilter? = null,
162 | color: Color? = null,
163 | onComplete: (SearchResults) -> Unit,
164 | onError: (String) -> Unit
165 | ) {
166 | val call = apiService.search(
167 | query,
168 | page,
169 | perPage,
170 | collections,
171 | orientation?.orientation,
172 | contentFilter?.type,
173 | color?.color
174 | )
175 | call.enqueue(UnsplashCallback(onComplete, onError))
176 | }
177 |
178 | suspend fun search(
179 | query: String,
180 | page: Int? = null,
181 | perPage: Int? = null,
182 | collections: String? = null,
183 | orientation: Orientation? = null,
184 | contentFilter: ContentFilter? = null,
185 | color: Color? = null
186 | ): UnsplashResource> {
187 | return try {
188 | val res = apiService.searchSuspend(
189 | query,
190 | page,
191 | perPage,
192 | collections,
193 | orientation?.orientation,
194 | contentFilter?.type,
195 | color?.color
196 | )
197 | responseHandler.handleSuccess(res)
198 |
199 | } catch (e: Exception) {
200 | responseHandler.handleException(e)
201 | }
202 | }
203 |
204 | fun getDownloadLink(
205 | id: String,
206 | onComplete: (Download) -> Unit,
207 | onError: (String) -> Unit
208 | ) {
209 | val call = apiService.getDownloadLink(id)
210 | call.enqueue(UnsplashCallback(onComplete, onError))
211 | }
212 |
213 | suspend fun getDownloadLink(
214 | id: String
215 | ): UnsplashResource {
216 | return try {
217 | val res = apiService.getDownloadLinkSuspend(id)
218 | responseHandler.handleSuccess(res)
219 |
220 | } catch (e: Exception) {
221 | responseHandler.handleException(e)
222 | }
223 | }
224 |
225 | fun update(
226 | id: String,
227 | latitude: String? = null,
228 | longitude: String? = null,
229 | name: String? = null,
230 | city: String? = null,
231 | country: String? = null,
232 | confidential: String? = null,
233 | make: String? = null,
234 | model: String? = null,
235 | exposure_time: String? = null,
236 | exposure_value: String? = null,
237 | focal_length: String? = null,
238 | iso: String? = null,
239 | onComplete: (Photo) -> Unit,
240 | onError: (String) -> Unit
241 | ) {
242 | val call = apiService.update(
243 | id, latitude, longitude, name, city,
244 | country, confidential, make, model, exposure_time, exposure_value, focal_length, iso
245 | )
246 | call.enqueue(UnsplashCallback(onComplete, onError))
247 | }
248 |
249 | suspend fun update(
250 | id: String,
251 | latitude: String? = null,
252 | longitude: String? = null,
253 | name: String? = null,
254 | city: String? = null,
255 | country: String? = null,
256 | confidential: String? = null,
257 | make: String? = null,
258 | model: String? = null,
259 | exposure_time: String? = null,
260 | exposure_value: String? = null,
261 | focal_length: String? = null,
262 | iso: String? = null
263 | ): UnsplashResource {
264 | return try {
265 | val res = apiService.updateSuspend(
266 | id, latitude, longitude, name, city,
267 | country, confidential, make, model, exposure_time, exposure_value, focal_length, iso
268 | )
269 | responseHandler.handleSuccess(res)
270 |
271 | } catch (e: Exception) {
272 | responseHandler.handleException(e)
273 | }
274 | }
275 |
276 | fun like(
277 | id: String,
278 | onComplete: (Photo) -> Unit,
279 | onError: (String) -> Unit
280 | ) {
281 | val call = apiService.like(id)
282 | call.enqueue(UnsplashCallback(onComplete, onError))
283 | }
284 |
285 | suspend fun like(
286 | id: String,
287 | ): UnsplashResource {
288 | return try {
289 | val res = apiService.likeSuspend(id)
290 | responseHandler.handleSuccess(res)
291 |
292 | } catch (e: Exception) {
293 | responseHandler.handleException(e)
294 | }
295 | }
296 |
297 | fun unlike(
298 | id: String,
299 | onComplete: (Photo) -> Unit,
300 | onError: (String) -> Unit
301 | ) {
302 | val call = apiService.unlike(id)
303 | call.enqueue(UnsplashCallback(onComplete, onError))
304 | }
305 |
306 | suspend fun unlike(
307 | id: String,
308 | ): UnsplashResource {
309 | return try {
310 | val res = apiService.unlikeSuspend(id)
311 | responseHandler.handleSuccess(res)
312 |
313 | } catch (e: Exception) {
314 | responseHandler.handleException(e)
315 | }
316 | }
317 |
318 | }
319 |
--------------------------------------------------------------------------------