Skip to content

Commit 98dfe35

Browse files
committed
added: navigation menu and auth page
1 parent cba54b3 commit 98dfe35

26 files changed

Lines changed: 476 additions & 33 deletions

File tree

.idea/inspectionProfiles/Project_Default.xml

Lines changed: 32 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ dependencies {
4949
def roomVersion = "2.6.1"
5050
def roomCompilerVersion = "1.1.1"
5151
def lifecycleVersion = "2.8.6"
52+
def jwtVersion = "0.12.6"
5253

5354
implementation fileTree(dir: "libs", include: ["*.jar"])
5455
implementation 'com.github.junrar:junrar:7.5.5'
@@ -59,6 +60,9 @@ dependencies {
5960

6061
implementation "org.apache.commons:commons-text:1.12.0"
6162

63+
implementation "io.jsonwebtoken:jjwt-api:$jwtVersion"
64+
implementation "io.jsonwebtoken:jjwt-impl:$jwtVersion"
65+
6266
kapt "androidx.room:room-compiler:$roomVersion"
6367

6468
implementation "android.arch.persistence.room:runtime:$roomCompilerVersion"
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.home.reader.api
2+
3+
import android.content.Context
4+
import android.util.Log
5+
import androidx.compose.runtime.mutableStateOf
6+
import com.home.reader.persistence.entity.User
7+
import com.home.reader.persistence.repository.UserRepository
8+
9+
class ApiHandler(
10+
context: Context,
11+
private val userRepository: UserRepository
12+
) {
13+
14+
private val processor = ApiProcessor("https://paper.webhop.me/api", context)
15+
16+
private val tokenState = mutableStateOf<String?>(null)
17+
18+
suspend fun initToken() {
19+
if (tokenState.value == null) {
20+
val user = userRepository.get()
21+
tokenState.value = user?.token
22+
}
23+
}
24+
25+
suspend fun login(username: String, password: String): Boolean {
26+
val result = processor.login(username, password)
27+
if (!result.isSuccess()) {
28+
Log.i(
29+
"Login request",
30+
"""
31+
Code: ${result.failReason?.code}
32+
Reason: ${result.failReason?.text}
33+
""".trimIndent()
34+
)
35+
36+
return false
37+
}
38+
39+
val existsUser = userRepository.get()
40+
if (existsUser == null) {
41+
val user = User(
42+
username = username,
43+
password = password,
44+
token = result.value?.token
45+
)
46+
userRepository.insert(user)
47+
} else {
48+
val user = existsUser.copy(
49+
username = username,
50+
password = password,
51+
token = result.value?.token
52+
)
53+
userRepository.update(user)
54+
}
55+
56+
tokenState.value = result.value?.token
57+
return true
58+
}
59+
60+
}

app/src/main/java/com/home/reader/api/ApiProcessor.kt

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,24 @@ import android.content.Context
44
import coil.request.ImageRequest
55
import com.google.gson.Gson
66
import com.google.gson.reflect.TypeToken
7+
import com.home.reader.api.dto.Credentials
78
import com.home.reader.api.dto.Issue
89
import com.home.reader.api.dto.Result
910
import com.home.reader.api.dto.Series
11+
import com.home.reader.api.dto.Token
12+
import okhttp3.MediaType.Companion.toMediaType
1013
import okhttp3.OkHttpClient
1114
import okhttp3.Request
15+
import okhttp3.RequestBody.Companion.toRequestBody
1216
import okhttp3.Response
1317
import java.io.InputStreamReader
1418
import java.lang.reflect.Type
1519

16-
class ApiProcessor(host: String, port: Int, private val context: Context) {
17-
18-
private val baseUrl = "http://$host:$port"
20+
class ApiProcessor(private val host: String, private val context: Context) {
1921
private val client = OkHttpClient()
2022

2123
private companion object {
24+
val CONTENT_TYPE = "application/json".toMediaType()
2225

2326
val SERIES_RESULT_TYPE: Type = TypeToken.getParameterized(
2427
List::class.java,
@@ -30,14 +33,27 @@ class ApiProcessor(host: String, port: Int, private val context: Context) {
3033
Issue::class.java
3134
).type
3235

36+
const val AUTH = "/customer/login"
3337
const val ALL_SERIES = "/comics/series"
3438
const val ISSUES_OF_SERIES = "/comics/series/%s/issues"
3539
}
3640

41+
fun login(username: String, password: String): Result<Token> {
42+
val credentials = Credentials(username, password)
43+
val body = Gson().toJson(credentials).toRequestBody(CONTENT_TYPE)
44+
45+
val request = Request.Builder()
46+
.post(body)
47+
.url("$host$AUTH")
48+
.build()
49+
50+
return client.newCall(request).execute().toResult<Token>()
51+
}
52+
3753
fun getSeries(token: String): Result<List<Series>> {
3854
val request = Request.Builder()
3955
.get()
40-
.url("$baseUrl$ALL_SERIES")
56+
.url("$host$ALL_SERIES")
4157
.addAuthorizationHeader(token)
4258
.build()
4359

@@ -51,7 +67,7 @@ class ApiProcessor(host: String, port: Int, private val context: Context) {
5167
size: String = "origin"
5268
): ImageRequest {
5369
return ImageRequest.Builder(context = context)
54-
.data("$baseUrl/file/$issueId/$page?size=$size")
70+
.data("$host/file/$issueId/$page?size=$size")
5571
.addHeader("Authorization", "Bearer $token")
5672
.build()
5773
}
@@ -60,7 +76,7 @@ class ApiProcessor(host: String, port: Int, private val context: Context) {
6076
val path = ISSUES_OF_SERIES.format(seriesId)
6177
val request = Request.Builder()
6278
.get()
63-
.url("$baseUrl$path")
79+
.url("$host$path")
6480
.addAuthorizationHeader(token)
6581
.build()
6682

@@ -80,4 +96,7 @@ class ApiProcessor(host: String, port: Int, private val context: Context) {
8096
return Result(value)
8197
}
8298

99+
private inline fun <reified T> Response.toResult(): Result<T> {
100+
return this.toResult(TypeToken.get(T::class.java).type)
101+
}
83102
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.home.reader.api.dto
22

33
data class Credentials(
4-
val login: String,
4+
val username: String,
55
val password: String
66
)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.home.reader.api.dto
2+
3+
data class Token(val token: String)

app/src/main/java/com/home/reader/component/activity/MainComposeActivity.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.fillMaxSize
88
import androidx.compose.material3.MaterialTheme
99
import androidx.compose.material3.Surface
1010
import androidx.compose.runtime.Composable
11+
import androidx.compose.runtime.mutableStateOf
1112
import androidx.compose.ui.Modifier
1213
import androidx.compose.ui.tooling.preview.Preview
1314
import androidx.navigation.NavHostController
@@ -42,7 +43,7 @@ class MainComposeActivity : ComponentActivity() {
4243
@Composable
4344
fun MainAppNavHost(
4445
modifier: Modifier = Modifier,
45-
navController: NavHostController = rememberNavController(),
46+
navController: NavHostController = rememberNavController()
4647
) {
4748
NavHost(
4849
modifier = modifier,
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
package com.home.reader.persistence
22

33
import android.content.Context
4+
import com.home.reader.api.ApiHandler
45
import com.home.reader.persistence.repository.IssueRepository
56
import com.home.reader.persistence.repository.SeriesRepository
7+
import com.home.reader.persistence.repository.UserRepository
68
import com.home.reader.persistence.repository.impl.DefaultIssueRepository
79
import com.home.reader.persistence.repository.impl.DefaultSeriesRepository
10+
import com.home.reader.persistence.repository.impl.DefaultUserRepository
811

912
interface AppContainer {
1013
val seriesRepository: SeriesRepository
1114
val issueRepository: IssueRepository
15+
val userRepository: UserRepository
16+
val api: ApiHandler
1217
}
1318

14-
class AppDataContainer(private val context: Context) : AppContainer {
19+
class AppDataContainer(context: Context) : AppContainer {
1520

1621
override val seriesRepository = DefaultSeriesRepository(AppDatabase.invoke(context).seriesDao())
1722

1823
override val issueRepository = DefaultIssueRepository(AppDatabase.invoke(context).issueDao())
1924

25+
override val userRepository = DefaultUserRepository(AppDatabase.invoke(context).userDao())
26+
27+
override val api: ApiHandler = ApiHandler(context, userRepository)
28+
2029
}

app/src/main/java/com/home/reader/persistence/AppDatabase.kt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,23 @@ import androidx.room.Room
66
import androidx.room.RoomDatabase
77
import com.home.reader.persistence.dao.IssueDao
88
import com.home.reader.persistence.dao.SeriesDao
9+
import com.home.reader.persistence.dao.UserDao
910
import com.home.reader.persistence.entity.Issue
1011
import com.home.reader.persistence.entity.Series
12+
import com.home.reader.persistence.entity.User
1113

1214
@Database(
13-
entities = [Issue::class, Series::class],
14-
version = 1
15+
entities = [Issue::class, Series::class, User::class],
16+
version = 2
1517
)
1618
abstract class AppDatabase : RoomDatabase() {
1719

1820
abstract fun seriesDao(): SeriesDao
1921

2022
abstract fun issueDao(): IssueDao
2123

24+
abstract fun userDao(): UserDao
25+
2226
companion object {
2327
@Volatile
2428
private var instance: AppDatabase? = null
@@ -32,6 +36,8 @@ abstract class AppDatabase : RoomDatabase() {
3236
context,
3337
AppDatabase::class.java,
3438
"reader-database"
35-
).build()
39+
)
40+
.fallbackToDestructiveMigration()
41+
.build()
3642
}
3743
}

0 commit comments

Comments
 (0)