Skip to content

Commit

Permalink
Merge pull request #125 from itszechs/multi-account-support
Browse files Browse the repository at this point in the history
Multiple account support
  • Loading branch information
itszechs authored Dec 26, 2024
2 parents 48c4822 + 176ecfe commit 30a2404
Show file tree
Hide file tree
Showing 61 changed files with 2,404 additions and 627 deletions.
58 changes: 58 additions & 0 deletions app/src/main/java/zechs/drive/stream/data/local/AccountsDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package zechs.drive.stream.data.local


import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import kotlinx.coroutines.flow.Flow
import zechs.drive.stream.data.model.Account
import zechs.drive.stream.data.model.AccountWithClient
import zechs.drive.stream.data.model.Client

@Dao
interface AccountsDao {

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addClient(client: Client)

@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addAccount(account: Account)

@Transaction
@Query("DELETE FROM clients WHERE id = :clientId")
suspend fun deleteClient(clientId: String)

@Query("SELECT * FROM clients")
fun getClients(): Flow<List<Client>>

@Transaction
@Query(
"SELECT accounts.*, clients.secret AS clientSecret, clients.redirectUri " +
"FROM accounts JOIN clients ON accounts.clientId = clients.id"
)
fun getAccounts(): Flow<List<AccountWithClient>>

@Transaction
@Query(
"SELECT accounts.*, clients.secret AS clientSecret, clients.redirectUri " +
"FROM accounts JOIN clients ON accounts.clientId = clients.id " +
"WHERE accounts.name = :accountName"
)
suspend fun getAccount(accountName: String): AccountWithClient?

@Query("UPDATE accounts SET name = :newName WHERE name = :oldName")
suspend fun updateAccountName(oldName: String, newName: String)

@Query("DELETE FROM accounts WHERE name = :accountName")
suspend fun deleteAccount(accountName: String)

@Transaction
@Query("UPDATE clients SET secret = :secret, redirectUri = :redirectUri WHERE id = :clientId")
suspend fun updateClient(clientId: String, secret: String, redirectUri: String)

@Query("UPDATE accounts SET accessToken = :newToken WHERE name = :accountName")
suspend fun updateAccessToken(accountName: String, newToken: String)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package zechs.drive.stream.data.local

import androidx.room.Database
import androidx.room.RoomDatabase
import zechs.drive.stream.data.model.Account
import zechs.drive.stream.data.model.Client


@Database(
entities = [Account::class, Client::class],
version = 1,
exportSchema = false
)
abstract class AccountsDatabase : RoomDatabase() {

abstract fun getAccountsDao(): AccountsDao

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package zechs.drive.stream.data.model

import androidx.annotation.Keep
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

@Entity(tableName = "clients")
data class Client(
@PrimaryKey val id: String,
val secret: String,
val redirectUri: String
) {
fun isEmpty() = id.isEmpty() || secret.isEmpty() || redirectUri.isEmpty()
}

@Entity(
tableName = "accounts",
foreignKeys = [ForeignKey(
entity = Client::class,
parentColumns = ["id"],
childColumns = ["clientId"],
onDelete = ForeignKey.CASCADE
)],
indices = [Index("clientId")]
)
data class Account(
@PrimaryKey val name: String,
val refreshToken: String,
val accessToken: String,
val clientId: String
)

@Keep
data class AccountWithClient(
val name: String,
val clientId: String,
val clientSecret: String,
val redirectUri: String,
val refreshToken: String,
val accessToken: String
) {

@Ignore
var isDefault: Boolean = false

fun getDriveClient() = DriveClient(
clientId = clientId,
clientSecret = clientSecret,
redirectUri = redirectUri,
scopes = listOf("https://www.googleapis.com/auth/drive")
)

fun getAccessTokenResponse(): TokenResponse {
val type = object : TypeToken<TokenResponse>() {}.type
return Gson().fromJson(accessToken, type)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,10 @@ data class DriveClient(
} catch (e: Exception) {
null
}

fun getClient() = Client(
id = clientId,
secret = clientSecret,
redirectUri = redirectUri
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package zechs.drive.stream.data.model

import com.google.errorprone.annotations.Keep

@Keep
data class TokenRequestBody(
val token: String
)
15 changes: 15 additions & 0 deletions app/src/main/java/zechs/drive/stream/data/remote/RevokeTokenApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package zechs.drive.stream.data.remote

import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
import zechs.drive.stream.data.model.TokenRequestBody

interface RevokeTokenApi {

@POST("/revoke")
suspend fun revokeToken(
@Body body: TokenRequestBody
): Response<Unit>

}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,11 @@ class DriveRepository @Inject constructor(
)
)
Log.d(TAG, "Received access token (${token.accessToken})")
sessionManager.saveAccessToken(token)
val currentTimeInSeconds = System.currentTimeMillis() / 1000
val newToken = token.copy(
expiresIn = currentTimeInSeconds + token.expiresIn
)
sessionManager.saveAccessToken(newToken)
Resource.Success(token)
} catch (e: Exception) {
doOnError(e)
Expand Down Expand Up @@ -140,7 +144,11 @@ class DriveRepository @Inject constructor(
// saving in data store
sessionManager.saveClient(client)
sessionManager.saveRefreshToken(token.refreshToken)
sessionManager.saveAccessToken(token.toTokenResponse())
val currentTimeInSeconds = System.currentTimeMillis() / 1000
val newToken = token.toTokenResponse().copy(
expiresIn = currentTimeInSeconds + token.expiresIn
)
sessionManager.saveAccessToken(newToken)

Resource.Success(token)
} catch (e: Exception) {
Expand Down
17 changes: 17 additions & 0 deletions app/src/main/java/zechs/drive/stream/di/ApiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import zechs.drive.stream.BuildConfig
import zechs.drive.stream.data.model.StarredAdapter
import zechs.drive.stream.data.remote.DriveApi
import zechs.drive.stream.data.remote.GithubApi
import zechs.drive.stream.data.remote.RevokeTokenApi
import zechs.drive.stream.data.remote.TokenApi
import zechs.drive.stream.data.repository.DriveRepository
import zechs.drive.stream.data.repository.GithubRepository
Expand All @@ -23,6 +24,7 @@ import zechs.drive.stream.utils.SessionManager
import zechs.drive.stream.utils.util.Constants.Companion.GITHUB_API
import zechs.drive.stream.utils.util.Constants.Companion.GOOGLE_ACCOUNTS_URL
import zechs.drive.stream.utils.util.Constants.Companion.GOOGLE_API
import zechs.drive.stream.utils.util.Constants.Companion.GOOGLE_OAUTH_URL
import javax.inject.Named
import javax.inject.Singleton

Expand Down Expand Up @@ -133,6 +135,21 @@ object ApiModule {
.create(GithubApi::class.java)
}

@Provides
@Singleton
fun provideRevokeTokenApi(
@Named("OkHttpClient")
client: OkHttpClient,
moshi: Moshi
): RevokeTokenApi {
return Retrofit.Builder()
.baseUrl(GOOGLE_OAUTH_URL)
.client(client)
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
.create(RevokeTokenApi::class.java)
}

@Provides
@Singleton
fun provideDriveRepository(
Expand Down
20 changes: 17 additions & 3 deletions app/src/main/java/zechs/drive/stream/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import zechs.drive.stream.utils.SessionManager
import zechs.drive.stream.data.local.AccountsDao
import zechs.drive.stream.utils.AppSettings
import zechs.drive.stream.utils.FirstRunProfileMigrator
import zechs.drive.stream.utils.SessionManager
import javax.inject.Singleton


Expand All @@ -26,13 +28,25 @@ object AppModule {
@Provides
fun provideSessionDataStore(
@ApplicationContext appContext: Context,
gson: Gson
): SessionManager = SessionManager(appContext, gson)
gson: Gson,
accountsManager: AccountsDao
): SessionManager = SessionManager(appContext, gson, accountsManager)

@Singleton
@Provides
fun provideThemeDataStore(
@ApplicationContext appContext: Context
): AppSettings = AppSettings(appContext)

@Provides
@Singleton
fun provideFirstRunProfileMigrator(
@ApplicationContext appContext: Context,
gson: Gson,
sessionManager: SessionManager,
accountsManager: AccountsDao,
): FirstRunProfileMigrator {
return FirstRunProfileMigrator(appContext, gson, sessionManager, accountsManager)
}

}
18 changes: 18 additions & 0 deletions app/src/main/java/zechs/drive/stream/di/DatabaseModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import zechs.drive.stream.data.local.AccountsDatabase
import zechs.drive.stream.data.local.WatchListDao
import zechs.drive.stream.data.local.WatchListDatabase
import zechs.drive.stream.data.repository.WatchListRepository
Expand All @@ -17,6 +18,7 @@ import javax.inject.Singleton
object DatabaseModule {

private const val WATCHLIST_DATABASE_NAME = "watch_list.db"
private const val ACCOUNTS_DATABASE_NAME = "accounts.db"

@Singleton
@Provides
Expand All @@ -42,4 +44,20 @@ object DatabaseModule {
watchListDao: WatchListDao
) = WatchListRepository(watchListDao)

@Singleton
@Provides
fun provideAccountsDatabase(
@ApplicationContext appContext: Context
) = Room.databaseBuilder(
appContext,
AccountsDatabase::class.java,
ACCOUNTS_DATABASE_NAME
).build()

@Singleton
@Provides
fun provideAccountsDao(
db: AccountsDatabase
) = db.getAccountsDao()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package zechs.drive.stream.ui.add_account

import android.app.Dialog
import android.content.Context
import android.os.Bundle
import android.view.Window
import android.widget.Toast
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputLayout
import zechs.drive.stream.R

class DialogAddAccount(
context: Context,
val onNextClickListener: (String) -> Unit
) : Dialog(context, R.style.ThemeOverlay_Fade_MaterialAlertDialog) {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.dialog_new_account)

val etNickname = findViewById<TextInputLayout>(R.id.tf_nickname).editText!!
val nextButton = findViewById<MaterialButton>(R.id.btn_next)

nextButton.setOnClickListener {
if (etNickname.text.toString().isEmpty()) {
Toast.makeText(
context,
context.getString(R.string.please_enter_a_nickname),
Toast.LENGTH_SHORT
).show()
} else {
onNextClickListener.invoke(etNickname.text.toString())
dismiss()
}
}
}

}
Loading

0 comments on commit 30a2404

Please sign in to comment.