Skip to content

Instantly share code, notes, and snippets.

@edujtm
Created July 12, 2020 02:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edujtm/80e9e492c3f0046f2400be01b39a565d to your computer and use it in GitHub Desktop.
Save edujtm/80e9e492c3f0046f2400be01b39a565d to your computer and use it in GitHub Desktop.
val androidModule = module {
single<Auth> {
AuthManager(context = androidContext())
}
single<PlaylistHttpApi> {
// Needs the YouTube wrapper class
YoutubePlaylistApi()
}
factory {
// AccountManager saves a GoogleSignInAccount using the application context
val accountManager = get<Auth>()
GoogleAccountCredential.usingOAuth2(androidContext(), SCOPES)
.apply {
backOff = ExponentialBackOff()
// This is null when the user is not logged in
// but needs to be the email after he logs in
selectedAccountName = accountManager.getUserAccount()?.email
}
}
factory {
// I need the google credentials before instantiating
// the YouTube wrapper class
val credentials = get<GoogleAccountCredential>()
val transport = AndroidHttp.newCompatibleTransport()
val jsonFactory = JacksonFactory.getDefaultInstance()
YouTube.Builder(transport, jsonFactory, credentials)
.build()
}
}
class AuthManager(context: Context) : Auth {
private val appContext = context.applicationContext
private val googleSignInClient: GoogleSignInClient by lazy {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build()
GoogleSignIn.getClient(context, gso)
}
override fun getUserAccount(): GoogleAccount? {
val account = getAccount()
// id and email will not be null due to GoogleSignInOptions.DEFAULT_SIGN_IN
// and requestEmail() being setup
return account?.let {
GoogleAccount(it.id!!, it.email!!, it.displayName!!, it.photoUrl?.toString())
}
}
override fun getSignInIntent(): Intent = googleSignInClient.signInIntent
override fun signOut(callback: () -> Unit) {
googleSignInClient.signOut()?.addOnCompleteListener {
callback()
}
}
fun getAccount() = GoogleSignIn.getLastSignedInAccount(appContext)
}
class YoutubePlaylistApi : PlaylistHttpApi, KoinComponent {
// I solved it by doing this, but I believe this will make it harder
// to test and will lead to more headaches is the future
private val youtube: YouTube
get() = getKoin().get()
override suspend fun getLikedVideos(): RequestState<List<PlaylistItem>> = withContext(Dispatchers.IO) {
return@withContext try {
val likedVideosId = retrieveLikedVideosId()
val result = youtube.playlistItems()
.list("snippet,contentDetails")
.apply {
maxResults = 25
playlistId = likedVideosId
}.execute()
val playlistItems = result.items.map { PlaylistItem.fromJson(it) }
RequestState.Success(playlistItems)
} catch (e: Exception) {
RequestState.Failure(e)
}
}
private suspend fun retrieveLikedVideosId(): String = withContext(Dispatchers.IO) {
val result = youtube.channels()
.list("snippet,contentDetails,statistics")
.apply {
mine = true
}.execute()
val channel = result.items.firstOrNull()
return@withContext channel?.let {
it.contentDetails.relatedPlaylists.likes
} ?: throw Exception("Couldn't retrieve channel information")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment