Skip to content
Open
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
4 changes: 4 additions & 0 deletions Shrine/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,8 @@ dependencies {
implementation(libs.lifecycle.runtime.compose)
implementation(libs.gms.location)
implementation(libs.androidx.core.splashscreen)

testImplementation(libs.androidx.core.testing)
testImplementation(libs.kotlinx.coroutines.test)
testImplementation(libs.truth)
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ class CredentialManagerUtils @Inject constructor(
.setServerClientId(SERVER_CLIENT_ID)
.setFilterByAuthorizedAccounts(false)
.build(),
)
),
)
result = credentialManager.getCredential(context, credentialRequest)
} catch (e: GetCredentialCancellationException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,111 +16,10 @@
package com.authentication.shrine

import android.app.Application
import android.content.Context
import android.os.Build
import androidx.credentials.CredentialManager
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import com.authentication.shrine.api.AddHeaderInterceptor
import com.authentication.shrine.api.AuthApiService
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.HiltAndroidApp
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton

/**
* The main application class for the Shrine app.
*/
@HiltAndroidApp
class ShrineApplication : Application()

/**
* A Dagger Hilt module that provides dependencies for the application.
*/
@Module
@InstallIn(SingletonComponent::class)
object AppModule {

/**
* Creates and provides an OkHttpClient instance with interceptors and timeouts.
*
* @return The OkHttpClient instance.
*/
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient {
val userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} " +
"(Android ${Build.VERSION.RELEASE}; ${Build.MODEL}; ${Build.BRAND})"
return OkHttpClient.Builder()
.addInterceptor(AddHeaderInterceptor(userAgent))
.addInterceptor(
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
},
)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(40, TimeUnit.SECONDS)
.connectTimeout(40, TimeUnit.SECONDS)
.build()
}

/**
* Provides a singleton instance of the CoroutineScope.
*
* @return The CoroutineScope instance.
*/
@Singleton
@Provides
fun provideAppCoroutineScope(): CoroutineScope = CoroutineScope(SupervisorJob())

/**
* Provides a DataStore instance with the file name "auth".
*
* @param application The application context.
* @return The DataStore instance.
*/
@Singleton
@Provides
fun provideDataStore(application: Application): DataStore<Preferences> {
return PreferenceDataStoreFactory.create {
application.preferencesDataStoreFile("auth")
}
}

@Singleton
@Provides
fun providesCredentialManager(@ApplicationContext context: Context): CredentialManager {
return CredentialManager.create(context)
}

@Singleton
@Provides
fun providesCredentialManagerUtils(
credentialManager: CredentialManager,
): CredentialManagerUtils {
return CredentialManagerUtils(credentialManager)
}

@Singleton
@Provides
fun provideAuthApiService(okHttpClient: OkHttpClient): AuthApiService {
return Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(AuthApiService::class.java)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ interface AuthApiService {
*/
@POST("federation/options")
suspend fun getFederationOptions(
@Body urls: FederationOptionsRequest
@Body urls: FederationOptionsRequest,
): Response<GenericAuthResponse>

/**
Expand Down
135 changes: 135 additions & 0 deletions Shrine/app/src/main/java/com/authentication/shrine/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.authentication.shrine.di

import android.app.Application
import android.content.Context
import android.os.Build
import androidx.credentials.CredentialManager
import androidx.datastore.core.DataStore
import androidx.datastore.dataStore

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This import is unused and can be removed.

import androidx.datastore.preferences.core.PreferenceDataStoreFactory
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStoreFile
import com.authentication.shrine.BuildConfig
import com.authentication.shrine.CredentialManagerUtils
import com.authentication.shrine.api.AddHeaderInterceptor
import com.authentication.shrine.api.AuthApiService
import com.authentication.shrine.repository.AuthRepository
import com.authentication.shrine.repository.AuthenticationRepository
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton

/**
* A Dagger Hilt module that provides dependencies for the application.
*/
@Module
@InstallIn(SingletonComponent::class)
object AppModule {

/**
* Creates and provides an OkHttpClient instance with interceptors and timeouts.
*
* @return The OkHttpClient instance.
*/
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient {
val userAgent = "${BuildConfig.APPLICATION_ID}/${BuildConfig.VERSION_NAME} " +
"(Android ${Build.VERSION.RELEASE}; ${Build.MODEL}; ${Build.BRAND})"
return OkHttpClient.Builder()
.addInterceptor(AddHeaderInterceptor(userAgent))
.addInterceptor(
HttpLoggingInterceptor().apply {
level = HttpLoggingInterceptor.Level.BODY
},
)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(40, TimeUnit.SECONDS)
.connectTimeout(40, TimeUnit.SECONDS)
.build()
}

/**
* Provides a singleton instance of the CoroutineScope.
*
* @return The CoroutineScope instance.
*/
@Singleton
@Provides
fun provideAppCoroutineScope(): CoroutineScope = CoroutineScope(SupervisorJob())

/**
* Provides a DataStore instance with the file name "auth".
*
* @param application The application context.
* @return The DataStore instance.
*/
@Singleton
@Provides
fun provideDataStore(application: Application): DataStore<Preferences> {
return PreferenceDataStoreFactory.create {
application.preferencesDataStoreFile("auth")
}
}

@Singleton
@Provides
fun providesCredentialManager(@ApplicationContext context: Context): CredentialManager {
return CredentialManager.create(context)
}

@Singleton
@Provides
fun providesCredentialManagerUtils(
credentialManager: CredentialManager,
): CredentialManagerUtils {
return CredentialManagerUtils(
credentialManager = credentialManager,
)
}

@Singleton
@Provides
fun provideAuthApiService(okHttpClient: OkHttpClient): AuthApiService {
return Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(AuthApiService::class.java)
}

@Singleton
@Provides
fun provideAuthRepository(
dataStore: DataStore<Preferences>,
authApiService: AuthApiService,
): AuthenticationRepository {
return AuthRepository(dataStore, authApiService)
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.authentication.shrine.model

/**
* Represents the request body for getting federation options from the server.
* @param urls a list of urls to send for federated requests.
*/
data class FederationOptionsRequest(
val urls: List<String> = listOf("https://accounts.google.com")
)
val urls: List<String> = listOf("https://accounts.google.com"),
)
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/*
* Copyright 2025 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.authentication.shrine.model

/**
Expand All @@ -7,5 +22,5 @@ package com.authentication.shrine.model
*/
data class SignInWithGoogleRequest(
val token: String,
val url: String = "https://accounts.google.com"
)
val url: String = "https://accounts.google.com",
)
Loading