-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix #39 Add account feature and login
- Loading branch information
1 parent
e604bff
commit 46ddbc8
Showing
40 changed files
with
1,383 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
plugins { | ||
alias(libs.plugins.android.library) | ||
alias(libs.plugins.detekt) | ||
alias(libs.plugins.jetbrains.kotlin.android) | ||
alias(libs.plugins.google.dagger.hilt.android) | ||
alias(libs.plugins.ksp) | ||
alias(libs.plugins.serialization) | ||
id("android-library-convention") | ||
id("data-convention") | ||
} | ||
|
||
apply(from = project.rootProject.file("config/detekt/detekt.gradle")) | ||
|
||
android { | ||
namespace = "com.zsoltbertalan.flickslate.account.data" | ||
|
||
buildTypes { | ||
release { | ||
isMinifyEnabled = false | ||
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") | ||
} | ||
} | ||
@Suppress("UnstableApiUsage") | ||
testFixtures { | ||
enable = true | ||
} | ||
} | ||
|
||
dependencies { | ||
api(project(":account:account-domain")) | ||
implementation(libs.kotlinx.serialization.json) | ||
testImplementation(libs.squareUp.okhttp3.mockWebServer) | ||
|
||
//Remove in AGP 8.9.0 https://issuetracker.google.com/issues/340315591 | ||
testFixturesCompileOnly("org.jetbrains.kotlin:kotlin-stdlib:2.1.0") | ||
} | ||
|
||
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach { | ||
compilerOptions.freeCompilerArgs.add("-opt-in=okhttp3.ExperimentalOkHttpApi") | ||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
</manifest> |
26 changes: 26 additions & 0 deletions
26
...unt-data/src/main/java/com/zsoltbertalan/flickslate/account/data/api/AccountDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.zsoltbertalan.flickslate.account.data.api | ||
|
||
import com.zsoltbertalan.flickslate.shared.model.Account | ||
import com.zsoltbertalan.flickslate.shared.util.Outcome | ||
|
||
interface AccountDataSource { | ||
|
||
interface Local { | ||
|
||
fun saveAccessToken(accessToken: String) | ||
fun getAccessToken(): String? | ||
|
||
fun saveAccount(account: Account) | ||
fun getAccount(): Account? | ||
|
||
} | ||
|
||
interface Remote { | ||
|
||
suspend fun createSessionId(username: String, password: String): Outcome<String> | ||
|
||
suspend fun getAccountDetails(sessionToken: String): Outcome<Account> | ||
|
||
} | ||
|
||
} |
37 changes: 37 additions & 0 deletions
37
...a/src/main/java/com/zsoltbertalan/flickslate/account/data/local/AccountLocalDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package com.zsoltbertalan.flickslate.account.data.local | ||
|
||
import android.content.Context | ||
import com.zsoltbertalan.flickslate.account.data.api.AccountDataSource | ||
import com.zsoltbertalan.flickslate.shared.model.Account | ||
import dagger.hilt.android.qualifiers.ApplicationContext | ||
import dagger.hilt.android.scopes.ActivityRetainedScoped | ||
import se.ansman.dagger.auto.AutoBind | ||
import javax.inject.Inject | ||
|
||
@AutoBind | ||
@ActivityRetainedScoped | ||
class AccountLocalDataSource @Inject constructor( | ||
@ApplicationContext val context: Context | ||
) : AccountDataSource.Local { | ||
|
||
override fun saveAccessToken(accessToken: String) { | ||
val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) | ||
sharedPreferences.edit().putString("access_token", accessToken).apply() | ||
} | ||
|
||
override fun getAccessToken(): String? { | ||
val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) | ||
return sharedPreferences.getString("access_token", null) | ||
} | ||
|
||
override fun saveAccount(account: Account) { | ||
val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) | ||
sharedPreferences.edit().putString("account_name", account.name).apply() | ||
} | ||
|
||
override fun getAccount(): Account? { | ||
val sharedPreferences = context.getSharedPreferences("Account", Context.MODE_PRIVATE) | ||
return sharedPreferences.getString("account_name", null)?.let { Account(it) } | ||
} | ||
|
||
} |
69 changes: 69 additions & 0 deletions
69
...rc/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountRemoteDataSource.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network | ||
|
||
import com.github.michaelbull.result.andThen | ||
import com.github.michaelbull.result.map | ||
import com.zsoltbertalan.flickslate.account.data.api.AccountDataSource | ||
import com.zsoltbertalan.flickslate.shared.data.util.runCatchingApi | ||
import com.zsoltbertalan.flickslate.shared.model.Account | ||
import com.zsoltbertalan.flickslate.shared.util.Outcome | ||
import dagger.hilt.android.scopes.ActivityRetainedScoped | ||
import kotlinx.serialization.json.buildJsonObject | ||
import kotlinx.serialization.json.put | ||
import okhttp3.MediaType.Companion.toMediaType | ||
import okhttp3.RequestBody | ||
import okhttp3.RequestBody.Companion.toRequestBody | ||
import se.ansman.dagger.auto.AutoBind | ||
import javax.inject.Inject | ||
|
||
@AutoBind | ||
@ActivityRetainedScoped | ||
class AccountRemoteDataSource @Inject constructor( | ||
private val accountService: AccountService | ||
) : AccountDataSource.Remote { | ||
|
||
override suspend fun createSessionId(username: String, password: String): Outcome<String> { | ||
return runCatchingApi { | ||
accountService.createRequestToken() | ||
}.andThen { createRequestTokenReplyDto -> | ||
|
||
runCatchingApi { | ||
accountService.validateRequestTokenWithLogin( | ||
createValidateRequestTokenWithLoginRequestBody( | ||
username, | ||
password, | ||
createRequestTokenReplyDto.request_token | ||
) | ||
) | ||
} | ||
}.andThen { createRequestTokenReplyDto -> | ||
runCatchingApi { | ||
accountService.createSession(createRequestTokenReplyDto.request_token).session_id | ||
} | ||
} | ||
} | ||
|
||
override suspend fun getAccountDetails(sessionToken: String): Outcome<Account> { | ||
return runCatchingApi { | ||
accountService.getAccountDetails(sessionToken) | ||
}.map { accountDetailsReplyDto -> | ||
val accountName = | ||
if (accountDetailsReplyDto.name.isNullOrEmpty()) accountDetailsReplyDto.username | ||
else accountDetailsReplyDto.name | ||
Account(accountName) | ||
} | ||
} | ||
|
||
} | ||
|
||
private fun createValidateRequestTokenWithLoginRequestBody( | ||
username: String, | ||
password: String, | ||
requestToken: String, | ||
): RequestBody { | ||
val body = buildJsonObject { | ||
put("username", username) | ||
put("password", password) | ||
put("request_token", requestToken) | ||
} | ||
return body.toString().toRequestBody("application/json; charset=UTF-8".toMediaType()) | ||
} |
47 changes: 47 additions & 0 deletions
47
...nt-data/src/main/java/com/zsoltbertalan/flickslate/account/data/network/AccountService.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network | ||
|
||
import com.zsoltbertalan.flickslate.account.data.network.model.AccountDetailsReplyDto | ||
import com.zsoltbertalan.flickslate.account.data.network.model.CreateRequestTokenReplyDto | ||
import com.zsoltbertalan.flickslate.account.data.network.model.CreateSessionReplyDto | ||
import okhttp3.RequestBody | ||
import retrofit2.http.Body | ||
import retrofit2.http.GET | ||
import retrofit2.http.POST | ||
import retrofit2.http.Query | ||
|
||
const val URL_CREATE_REQUEST_TOKEN = "authentication/token/new" | ||
const val URL_VALIDATE_REQUEST_TOKEN_WITH_LOGIN = "authentication/token/validate_with_login" | ||
const val URL_CREATE_SESSION = "authentication/session/new" | ||
const val URL_GET_ACCOUNT_DETAILS = "account" | ||
|
||
/** | ||
* As of December 2024, the API reference for login with password is wrong here: | ||
* https://developer.themoviedb.org/reference/authentication-how-do-i-generate-a-session-id | ||
* | ||
* But inspecting this example gives you the correct login flow: | ||
* http://dev.travisbell.com/play/v3_auth_password.html | ||
* | ||
* The login replaces not the third, but the second step in the process, and you still have to create the session, | ||
* because the second step is only validation, not the session creation. | ||
*/ | ||
interface AccountService { | ||
|
||
@GET(URL_CREATE_REQUEST_TOKEN) | ||
suspend fun createRequestToken(): CreateRequestTokenReplyDto | ||
|
||
@POST(URL_VALIDATE_REQUEST_TOKEN_WITH_LOGIN) | ||
suspend fun validateRequestTokenWithLogin( | ||
@Body requestBody: RequestBody | ||
): CreateRequestTokenReplyDto | ||
|
||
@GET(URL_CREATE_SESSION) | ||
suspend fun createSession( | ||
@Query("request_token") requestToken: String, | ||
): CreateSessionReplyDto | ||
|
||
@GET(URL_GET_ACCOUNT_DETAILS) | ||
suspend fun getAccountDetails( | ||
@Query("session_id") sessionToken: String, | ||
): AccountDetailsReplyDto | ||
|
||
} |
20 changes: 20 additions & 0 deletions
20
...ta/src/main/java/com/zsoltbertalan/flickslate/account/data/network/MoviesServiceModule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network | ||
|
||
import dagger.Module | ||
import dagger.Provides | ||
import dagger.hilt.InstallIn | ||
import dagger.hilt.android.components.ActivityRetainedComponent | ||
import dagger.hilt.android.scopes.ActivityRetainedScoped | ||
import retrofit2.Retrofit | ||
|
||
@Module | ||
@InstallIn(ActivityRetainedComponent::class) | ||
class MoviesServiceModule { | ||
|
||
@Provides | ||
@ActivityRetainedScoped | ||
internal fun provideMoviesService(retroFit: Retrofit): AccountService { | ||
return retroFit.create(AccountService::class.java) | ||
} | ||
|
||
} |
7 changes: 7 additions & 0 deletions
7
...in/java/com/zsoltbertalan/flickslate/account/data/network/model/AccountDetailsReplyDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network.model | ||
|
||
import kotlinx.serialization.Serializable | ||
|
||
@Suppress("ConstructorParameterNaming") | ||
@Serializable | ||
data class AccountDetailsReplyDto(val name: String?, val username: String) |
7 changes: 7 additions & 0 deletions
7
...ava/com/zsoltbertalan/flickslate/account/data/network/model/CreateRequestTokenReplyDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network.model | ||
|
||
import kotlinx.serialization.Serializable | ||
|
||
@Suppress("ConstructorParameterNaming", "PropertyName") | ||
@Serializable | ||
data class CreateRequestTokenReplyDto(val success: Boolean, val expires_at: String, val request_token: String) |
7 changes: 7 additions & 0 deletions
7
...ain/java/com/zsoltbertalan/flickslate/account/data/network/model/CreateSessionReplyDto.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package com.zsoltbertalan.flickslate.account.data.network.model | ||
|
||
import kotlinx.serialization.Serializable | ||
|
||
@Suppress("ConstructorParameterNaming", "PropertyName") | ||
@Serializable | ||
data class CreateSessionReplyDto(val success: Boolean, val session_id: String) |
35 changes: 35 additions & 0 deletions
35
...ata/src/main/java/com/zsoltbertalan/flickslate/account/data/repository/AccountAccessor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.zsoltbertalan.flickslate.account.data.repository | ||
|
||
import com.github.michaelbull.result.andThen | ||
import com.zsoltbertalan.flickslate.account.data.api.AccountDataSource | ||
import com.zsoltbertalan.flickslate.account.domain.api.AccountRepository | ||
import com.zsoltbertalan.flickslate.shared.model.Account | ||
import com.zsoltbertalan.flickslate.shared.util.Outcome | ||
import dagger.hilt.android.scopes.ActivityRetainedScoped | ||
import se.ansman.dagger.auto.AutoBind | ||
import javax.inject.Inject | ||
|
||
@AutoBind | ||
@ActivityRetainedScoped | ||
class AccountAccessor @Inject constructor( | ||
private val accountRemoteDataSource: AccountDataSource.Remote, | ||
private val accountLocalDataSource: AccountDataSource.Local | ||
) : AccountRepository { | ||
|
||
override suspend fun getAccount(): Account? { | ||
return accountLocalDataSource.getAccount() | ||
} | ||
|
||
override suspend fun login(username: String, password: String): Outcome<Account> { | ||
return accountRemoteDataSource.createSessionId(username, password) | ||
.andThen { | ||
val account = accountRemoteDataSource.getAccountDetails(it) | ||
accountLocalDataSource.saveAccount(account.value) | ||
account | ||
} | ||
} | ||
|
||
override fun logout() { | ||
// Do nothing | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
/build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
plugins { | ||
id("android-library-convention") | ||
alias(libs.plugins.serialization) | ||
} | ||
|
||
android { | ||
namespace = "com.zsoltbertalan.flickslate.account.domain" | ||
buildFeatures { | ||
@Suppress("UnstableApiUsage") | ||
testFixtures { | ||
enable = true | ||
} | ||
} | ||
} | ||
|
||
dependencies { | ||
|
||
api(project(":shared")) | ||
|
||
implementation(libs.kotlinResult.result) | ||
implementation(libs.kotlinx.collections.immutable.jvm) | ||
implementation(libs.kotlinx.coroutines.core) | ||
testFixturesCompileOnly(libs.kotlinx.collections.immutable.jvm) | ||
|
||
} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
# Add project specific ProGuard rules here. | ||
# You can control the set of applied configuration files using the | ||
# proguardFiles setting in build.gradle. | ||
# | ||
# For more details, see | ||
# http://developer.android.com/guide/developing/tools/proguard.html | ||
|
||
# If your project uses WebView with JS, uncomment the following | ||
# and specify the fully qualified class name to the JavaScript interface | ||
# class: | ||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | ||
# public *; | ||
#} | ||
|
||
# Uncomment this to preserve the line number information for | ||
# debugging stack traces. | ||
#-keepattributes SourceFile,LineNumberTable | ||
|
||
# If you keep the line number information, uncomment this to | ||
# hide the original source file name. | ||
#-renamesourcefileattribute SourceFile |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> | ||
|
||
</manifest> |
Oops, something went wrong.