GraphInstagramService
:
interface GraphInstagramService {
@GET("access_token")
suspend fun getLongAccessTokenInfo(
@Query("grant_type") grantType: String,
@Query("client_secret") clientSecret: String,
@Query("access_token") accessToken: String
): LongAccessTokenInfo
@GET("me")
suspend fun getUserInfo(
@Query("fields") fields: String,
@Query("access_token") accessToken: String
): UserInfoResponse
@GET("me/media")
suspend fun getMedias(
@Query("fields") fields: String,
@Query("access_token") accessToken: String
): MediasResponse
@GET("{albumId}/children")
suspend fun getAlbumDetail(
@Path("albumId") albumId: String,
@Query("fields") fields: String,
@Query("access_token") accessToken: String
): AlbumDetailResponse
@GET("{mediaId}")
suspend fun getMediaItem(
@Path("mediaId") mediaId: String,
@Query("fields") fields: String,
@Query("access_token") accessToken: String
): Response<Map<String, Any>>
}
DataRepository
:
class DataRepository(
context: Context,
private val apiInstagramService: ApiInstagramService,
private val graphInstagramService: GraphInstagramService
) {
private val preference = SharedPreferencesManagerImpl(context)
private val TAG = javaClass.name
private val _accessTokenResult = MutableLiveData<Boolean?>(null)
val accessTokenResult: LiveData<Boolean?> = _accessTokenResult
suspend fun getUserInfo(): UserInfoResponse {
if (preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "").isNullOrEmpty()) {
throw Exception("TOKEN_EMPTY")
}
if (!isTokenValid()) {
throw Exception("TOKEN_EXPIRED")
}
return withContext(Dispatchers.IO) {
return@withContext graphInstagramService.getUserInfo(
fields = "id,username,account_type",
accessToken = preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "")!!
)
}
}
suspend fun getMedias(): List<Map<String,Any>> {
if (preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "").isNullOrEmpty()) {
throw Exception("TOKEN_EMPTY")
}
if (!isTokenValid()) {
throw Exception("TOKEN_EXPIRED")
}
return withContext(Dispatchers.IO) {
return@withContext graphInstagramService.getMedias(
fields = "id,caption,media_type,timestamp,permalink,media_url,thumbnail_url",
accessToken = preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "")!!
).data
}
}
suspend fun getAlbumDetail(albumId: String): List<Map<String, Any>> {
if (preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "").isNullOrEmpty()) {
throw Exception("TOKEN_EMPTY")
}
if (!isTokenValid()) {
throw Exception("TOKEN_EXPIRED")
}
return withContext(Dispatchers.IO) {
return@withContext graphInstagramService.getAlbumDetail(
albumId = albumId,
fields = "id,media_type,media_url,timestamp,thumbnail_url",
accessToken = preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "")!!
).data
}
}
suspend fun getMediaItem(mediaId: String): Map<String, Any> {
if (preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "").isNullOrEmpty()) {
throw Exception("TOKEN_EMPTY")
}
if (!isTokenValid()) {
throw Exception("TOKEN_EXPIRED")
}
return withContext(Dispatchers.IO) {
return@withContext graphInstagramService.getMediaItem(
mediaId = mediaId,
fields = "id,caption,media_type,timestamp,permalink,media_url,thumbnail_url",
accessToken = preference.getString(Constants.PREF_KEY_ACCESS_TOKEN, "")!!
).body() ?: throw Exception("UNKNOWN_EXCEPTION")
}
}
suspend fun logout(): UserInfoResponse {
return withContext(Dispatchers.IO) {
preference.clear()
return@withContext UserInfoResponse("","","")
}
}
suspend fun getAccessToken(
clientId: String,
clientSecret: String,
code: String,
redirectUri: String
) {
withContext(Dispatchers.IO) {
getShortAccessToken(
clientId,
clientSecret,
code,
redirectUri
)
}
}
private suspend fun getShortAccessToken(
clientId: String,
clientSecret: String,
code: String,
redirectUri: String
) {
try {
val shortAccessTokenInfo = apiInstagramService.getShortAccessTokenInfo(
clientId = clientId,
clientSecret = clientSecret,
code = code,
grantType = "authorization_code",
redirectUri = redirectUri
)
Log.d(TAG, "shortAccessTokenInfo = $shortAccessTokenInfo")
preference.set(Constants.PREF_KEY_INSTAGRAM_USER_ID, shortAccessTokenInfo.userId)
val currentTimeMillis: Long = System.currentTimeMillis()
getLongAccessToken(shortAccessTokenInfo.accessToken, clientSecret, currentTimeMillis)
} catch (exception: UnknownHostException) { // Request Api when no internet
exception.printStackTrace()
Log.e(TAG, "shortAccessTokenInfo exception = $exception")
_accessTokenResult.postValue(false)
} catch (exception: Exception) {
exception.printStackTrace()
Log.e(TAG, "shortAccessTokenInfo exception = $exception")
_accessTokenResult.postValue(false)
}
}
private suspend fun getLongAccessToken(
shortAccessToken: String,
clientSecret: String,
currentTimeMillis: Long
) {
try {
val longAccessTokenInfo = graphInstagramService.getLongAccessTokenInfo(
grantType = "ig_exchange_token",
clientSecret = clientSecret,
accessToken = shortAccessToken
)
Log.d(TAG, "longAccessTokenInfo = $longAccessTokenInfo")
val expiredTimeMillis = currentTimeMillis + longAccessTokenInfo.expiresIn
Log.d(
TAG,
"currentTimeMillis = $currentTimeMillis, expiredTimeMillis = $expiredTimeMillis"
)
preference.set(Constants.PREF_KEY_EXPIRED_MILLISECONDS, expiredTimeMillis)
preference.set(Constants.PREF_KEY_ACCESS_TOKEN, longAccessTokenInfo.accessToken)
_accessTokenResult.postValue(true)
} catch (exception: UnknownHostException) { // Request Api when no internet
exception.printStackTrace()
Log.e(TAG, "getLongAccessToken exception = $exception")
_accessTokenResult.postValue(false)
} catch (exception: Exception) {
exception.printStackTrace()
Log.e(TAG, "getLongAccessToken exception = $exception")
_accessTokenResult.postValue(false)
}
}
fun clear() {
_accessTokenResult.value = null
}
private fun isTokenValid(): Boolean {
val expiredMilliseconds = preference.getLong(Constants.PREF_KEY_EXPIRED_MILLISECONDS, 0)
val currentTimeMillis: Long = System.currentTimeMillis()
return currentTimeMillis < expiredMilliseconds
}
}