Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Google signin and sync bookmarks #111

Merged
merged 3 commits into from
Apr 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 187 additions & 59 deletions app/src/main/java/fr/paug/androidmakers/ui/activity/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,86 +5,214 @@ import android.net.Uri
import android.os.Bundle
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.runtime.*
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.auth.GoogleAuthProvider
import fr.paug.androidmakers.AndroidMakersApplication
import fr.paug.androidmakers.R
import fr.paug.androidmakers.ui.components.AboutActions
import fr.paug.androidmakers.ui.components.MainLayout
import fr.paug.androidmakers.ui.theme.AndroidMakersTheme
import fr.paug.androidmakers.util.BookmarksStore
import fr.paug.androidmakers.util.CustomTabUtil
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch


val LocalActivity = staticCompositionLocalOf<MainActivity> { throw NotImplementedError() }

data class AMUser(
val uid: String,
val photoUrl: String?,
)

private fun FirebaseUser.toAMUser(): AMUser {
return AMUser(this.uid, this.photoUrl?.toString())
}

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContent {
AndroidMakersTheme {
MainLayout(aboutActions = AboutActions(
onFaqClick = ::onFaqClick,
onCodeOfConductClick = ::onCodeOfConductClick,
onTwitterHashtagClick = ::onTwitterHashtagClick,
onTwitterLogoClick = ::onTwitterLogoClick,
onYouTubeLogoClick = ::onYouTubeLogoClick,
onSponsorClick = ::onSponsorClick
))
}
}
private val _user = MutableStateFlow(FirebaseAuth.getInstance().currentUser?.toAMUser())

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val currentUser = _user.value
if (currentUser != null) {
lifecycleScope.launch {
// fire & forget
// This is racy but oh well...
mergeBookmarks(currentUser.uid)
}
}

private fun onFaqClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://androidmakers.fr/faq")))
setContent {
val rememberedActivity = remember { this }

val userState = _user.collectAsState()

CompositionLocalProvider(
LocalActivity provides rememberedActivity,
) {
AndroidMakersTheme {
MainLayout(
aboutActions = AboutActions(
onFaqClick = ::onFaqClick,
onCodeOfConductClick = ::onCodeOfConductClick,
onTwitterHashtagClick = ::onTwitterHashtagClick,
onTwitterLogoClick = ::onTwitterLogoClick,
onYouTubeLogoClick = ::onYouTubeLogoClick,
onSponsorClick = ::onSponsorClick,
),
user = userState.value,
)
}
}
}
}

private fun onFaqClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://androidmakers.fr/faq")))
}

private fun onCodeOfConductClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://androidmakers.fr/coc")))
private fun onCodeOfConductClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://androidmakers.fr/coc")))
}

private fun onTwitterHashtagClick() {
var twitterIntent: Intent
try {
// get the Twitter app if possible
packageManager?.getPackageInfo("com.twitter.android", 0)
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("twitter://search?query=%23" + getString(R.string.twitter_hashtag_for_query))
)
twitterIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} catch (e: Exception) {
// no Twitter app, revert to browser
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://twitter.com/search?q=%23" + getString(R.string.twitter_hashtag_for_query))
)
}

private fun onTwitterHashtagClick() {
var twitterIntent: Intent
try {
// get the Twitter app if possible
packageManager?.getPackageInfo("com.twitter.android", 0)
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("twitter://search?query=%23" + getString(R.string.twitter_hashtag_for_query))
)
twitterIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} catch (e: Exception) {
// no Twitter app, revert to browser
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://twitter.com/search?q=%23" + getString(R.string.twitter_hashtag_for_query))
)
}
startActivity(twitterIntent)
}

startActivity(twitterIntent)
private fun onTwitterLogoClick() {
var twitterIntent: Intent
try {
// get the Twitter app if possible
packageManager?.getPackageInfo("com.twitter.android", 0)
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("twitter://user?screen_name=" + getString(R.string.twitter_user_name))
)
twitterIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} catch (e: Exception) {
// no Twitter app, revert to browser
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://twitter.com/" + getString(R.string.twitter_user_name))
)
}

private fun onTwitterLogoClick() {
var twitterIntent: Intent
startActivity(twitterIntent)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)

when (requestCode) {
REQ_SIGNIN -> {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
try {
// get the Twitter app if possible
packageManager?.getPackageInfo("com.twitter.android", 0)
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("twitter://user?screen_name=" + getString(R.string.twitter_user_name))
)
twitterIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} catch (e: Exception) {
// no Twitter app, revert to browser
twitterIntent = Intent(
Intent.ACTION_VIEW,
Uri.parse("https://twitter.com/" + getString(R.string.twitter_user_name))
)
}
val account: GoogleSignInAccount = task.getResult(ApiException::class.java)
val idToken = account.idToken
when {
idToken != null -> {
// Got an ID token from Google. Use it to authenticate
// with Firebase.
println("Got ID token")
// Got an ID token from Google. Use it to authenticate
// with Firebase.
val firebaseCredential = GoogleAuthProvider.getCredential(idToken, null)
val auth = FirebaseAuth.getInstance()

startActivity(twitterIntent)
auth.signInWithCredential(firebaseCredential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
println("signInWithCredential:success")
lifecycleScope.launch {
mergeBookmarks(auth.currentUser!!.uid)
_user.value = auth.currentUser?.toAMUser()
}
} else {
// If sign in fails, display a message to the user.
task.exception?.printStackTrace()
_user.value = null
}
}
}
else -> {
_user.value = null
// Shouldn't happen.
println("No ID token :(")
}
}
} catch (e: ApiException) {
e.printStackTrace()
}
}
}
}

private fun onYouTubeLogoClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.youtube_channel))))
suspend fun mergeBookmarks(userId: String) {
val bookmarks = AndroidMakersApplication.instance().store.getBookmarks(userId).first().getOrNull()
if (bookmarks != null) {
BookmarksStore.merge(bookmarks)
}
}
private fun onYouTubeLogoClick() {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.youtube_channel))))
}

private fun onSponsorClick(url: String) {
CustomTabUtil.openChromeTab(this, url)
}
private fun onSponsorClick(url: String) {
CustomTabUtil.openChromeTab(this, url)
}

fun signout() {
val activity = this
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(activity.getString(R.string.default_web_client_id))
.build()
val googleSignInClient = GoogleSignIn.getClient(activity, gso);

FirebaseAuth.getInstance().signOut()
googleSignInClient.signOut()
googleSignInClient.revokeAccess()
_user.value = null
}

fun signin() {
val activity = this
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(activity.getString(R.string.default_web_client_id))
.build()
val googleSignInClient = GoogleSignIn.getClient(activity, gso);

activity.startActivityForResult(googleSignInClient.signInIntent, REQ_SIGNIN)
}
companion object {
const val REQ_SIGNIN = 33
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import fr.androidmakers.store.model.Partner
import fr.androidmakers.store.model.WifiInfo
import fr.paug.androidmakers.AndroidMakersApplication
import fr.paug.androidmakers.R
import fr.paug.androidmakers.ui.activity.AMUser
import fr.paug.androidmakers.ui.navigation.AVANavigationRoute
import fr.paug.androidmakers.ui.theme.AndroidMakersTheme
import fr.paug.androidmakers.ui.viewmodel.Lce
Expand All @@ -41,6 +42,7 @@ import kotlinx.coroutines.launch
fun AVALayout(
onSessionClick: (sessionId: String, roomId: String, startTimestamp: Long, endTimestamp: Long) -> Unit,
aboutActions: AboutActions,
user: AMUser?,
) {
val avaNavController = rememberNavController()
val navBackStackEntry by avaNavController.currentBackStackEntryAsState()
Expand All @@ -65,6 +67,7 @@ fun AVALayout(
Icon(painter = painterResource(R.drawable.ic_filter_list_white_24dp), contentDescription = stringResource(R.string.filter))
}
}
SigninButton(user)
},
elevation = if (currentRoute == AVANavigationRoute.ABOUT.name) AppBarDefaults.TopAppBarElevation else 0.dp
)
Expand Down Expand Up @@ -172,5 +175,5 @@ class PartnersViewModel : LceViewModel<List<Partner>>() {
@Preview
@Composable
private fun AVALayoutPreview() {
AVALayout(onSessionClick = { _, _, _, _ -> }, aboutActions = AboutActions())
AVALayout(onSessionClick = { _, _, _, _ -> }, aboutActions = AboutActions(), user = null)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package fr.paug.androidmakers.ui.components

import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
Expand Down Expand Up @@ -36,10 +35,8 @@ import fr.androidmakers.store.model.Partner
import fr.androidmakers.store.model.WifiInfo
import fr.paug.androidmakers.BuildConfig
import fr.paug.androidmakers.R
import fr.paug.androidmakers.ui.theme.AndroidMakersTheme
import fr.paug.androidmakers.ui.util.imageUrl
import fr.paug.androidmakers.util.imageUrl
import fr.paug.androidmakers.ui.viewmodel.Lce
import surfaceColor2


class AboutActions(
Expand Down
Loading