commit 49eb6d60b9d4ce0e49c2a12f63fa72bd91c7bd25
Author: Burak Fidan <97burakfidan97@gmail.com>
Date: Tue Dec 27 18:38:34 2022 +0300
Git init.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..fb7f4a8
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..a2d7c21
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..bdd9278
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..7aa77db
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,60 @@
+plugins {
+ id 'com.android.application'
+ id 'org.jetbrains.kotlin.android'
+ id 'kotlin-kapt'
+ id 'com.google.dagger.hilt.android'
+}
+
+android {
+ namespace 'com.mrntlu.tokenauthentication'
+ compileSdk 33
+
+ defaultConfig {
+ applicationId "com.mrntlu.tokenauthentication"
+ minSdk 29
+ targetSdk 33
+ versionCode 1
+ versionName "1.0"
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+}
+
+dependencies {
+ implementation 'androidx.core:core-ktx:1.9.0'
+ implementation 'androidx.appcompat:appcompat:1.5.1'
+ implementation 'com.google.android.material:material:1.7.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
+
+ def retrofit_version = "2.9.0"
+ implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
+ implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
+
+ def hilt_version = "2.44"
+ implementation "com.google.dagger:hilt-android:$hilt_version"
+ kapt "com.google.dagger:hilt-compiler:$hilt_version"
+
+ def okhttp_version = "4.10.0"
+ implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
+ implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version"
+
+ def nav_version = "2.5.3"
+ implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
+ implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -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
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..5a4d471
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/HiltApplication.kt b/app/src/main/java/com/mrntlu/tokenauthentication/HiltApplication.kt
new file mode 100644
index 0000000..de90867
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/HiltApplication.kt
@@ -0,0 +1,7 @@
+package com.mrntlu.tokenauthentication
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class HiltApplication: Application() {}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/HiltModule.kt b/app/src/main/java/com/mrntlu/tokenauthentication/HiltModule.kt
new file mode 100644
index 0000000..94044c1
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/HiltModule.kt
@@ -0,0 +1,21 @@
+package com.mrntlu.tokenauthentication
+
+import com.mrntlu.tokenauthentication.repository.AuthRepository
+import com.mrntlu.tokenauthentication.repository.MainRepository
+import com.mrntlu.tokenauthentication.service.auth.AuthApiService
+import com.mrntlu.tokenauthentication.service.main.MainApiService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ViewModelComponent
+
+@Module
+@InstallIn(ViewModelComponent::class)
+class HiltModule {
+
+ @Provides
+ fun provideAuthRepository(authApiService: AuthApiService) = AuthRepository(authApiService)
+
+ @Provides
+ fun provideMainRepository(mainApiService: MainApiService) = MainRepository(mainApiService)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/MainActivity.kt b/app/src/main/java/com/mrntlu/tokenauthentication/MainActivity.kt
new file mode 100644
index 0000000..2dd4735
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/MainActivity.kt
@@ -0,0 +1,19 @@
+package com.mrntlu.tokenauthentication
+
+import androidx.appcompat.app.AppCompatActivity
+import android.os.Bundle
+import androidx.navigation.fragment.NavHostFragment
+import com.mrntlu.tokenauthentication.ui.main.MainFragment
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_main)
+
+ val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
+ val navController = navHostFragment.navController
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/SingletonModule.kt b/app/src/main/java/com/mrntlu/tokenauthentication/SingletonModule.kt
new file mode 100644
index 0000000..d0d4ac8
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/SingletonModule.kt
@@ -0,0 +1,54 @@
+package com.mrntlu.tokenauthentication
+
+import com.mrntlu.tokenauthentication.service.auth.AuthApiService
+import com.mrntlu.tokenauthentication.service.auth.AuthInterceptor
+import com.mrntlu.tokenauthentication.service.main.MainApiService
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+class SingletonModule {
+
+ @Singleton
+ @Provides
+ fun provideOkHttpClient(): OkHttpClient {
+ val loggingInterceptor = HttpLoggingInterceptor()
+ loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
+
+ return OkHttpClient.Builder()
+ .addInterceptor(AuthInterceptor(
+ "Bearer",
+ ""
+ ))
+ .addInterceptor(loggingInterceptor)
+ .build()
+ }
+
+
+ @Singleton
+ @Provides
+ fun provideRetrofitInstance(okHttpClient: OkHttpClient): Retrofit =
+ Retrofit.Builder()
+ .baseUrl("https://jwt-test-api.onrender.com/api/")
+ .addConverterFactory(GsonConverterFactory.create())
+// .client(okHttpClient)
+ .build()
+
+ @Singleton
+ @Provides
+ fun provideAuthAPIService(retrofit: Retrofit): AuthApiService =
+ retrofit.create(AuthApiService::class.java)
+
+ @Singleton
+ @Provides
+ fun provideMainAPIService(retrofit: Retrofit): MainApiService =
+ retrofit.create(MainApiService::class.java)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/models/Auth.kt b/app/src/main/java/com/mrntlu/tokenauthentication/models/Auth.kt
new file mode 100644
index 0000000..6b6af19
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/models/Auth.kt
@@ -0,0 +1,9 @@
+package com.mrntlu.tokenauthentication.models
+
+import com.google.gson.annotations.SerializedName;
+
+data class Auth(
+ @SerializedName("email_address")
+ val email: String,
+ val password: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/models/Data.kt b/app/src/main/java/com/mrntlu/tokenauthentication/models/Data.kt
new file mode 100644
index 0000000..8ef15c5
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/models/Data.kt
@@ -0,0 +1,6 @@
+package com.mrntlu.tokenauthentication.models
+
+data class Data(
+ val _id: String,
+ val email_address: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/models/ErrorResponse.kt b/app/src/main/java/com/mrntlu/tokenauthentication/models/ErrorResponse.kt
new file mode 100644
index 0000000..22368fe
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/models/ErrorResponse.kt
@@ -0,0 +1,6 @@
+package com.mrntlu.tokenauthentication.models
+
+data class ErrorResponse(
+ val code: Int,
+ val message: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/models/LoginResponse.kt b/app/src/main/java/com/mrntlu/tokenauthentication/models/LoginResponse.kt
new file mode 100644
index 0000000..4901716
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/models/LoginResponse.kt
@@ -0,0 +1,8 @@
+package com.mrntlu.tokenauthentication.models
+
+import com.google.gson.annotations.SerializedName
+
+data class LoginResponse(
+ @SerializedName("access_token")
+ val token: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/models/UserInfoResponse.kt b/app/src/main/java/com/mrntlu/tokenauthentication/models/UserInfoResponse.kt
new file mode 100644
index 0000000..e362374
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/models/UserInfoResponse.kt
@@ -0,0 +1,6 @@
+package com.mrntlu.tokenauthentication.models
+
+data class UserInfoResponse(
+ val `data`: Data,
+ val message: String
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/repository/AuthRepository.kt b/app/src/main/java/com/mrntlu/tokenauthentication/repository/AuthRepository.kt
new file mode 100644
index 0000000..4423825
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/repository/AuthRepository.kt
@@ -0,0 +1,14 @@
+package com.mrntlu.tokenauthentication.repository
+
+import com.mrntlu.tokenauthentication.models.Auth
+import com.mrntlu.tokenauthentication.service.auth.AuthApiService
+import com.mrntlu.tokenauthentication.utils.toResultFlow
+import javax.inject.Inject
+
+class AuthRepository @Inject constructor(
+ private val authApiService: AuthApiService,
+) {
+ fun login(auth: Auth) = toResultFlow {
+ authApiService.login(auth)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/repository/MainRepository.kt b/app/src/main/java/com/mrntlu/tokenauthentication/repository/MainRepository.kt
new file mode 100644
index 0000000..3a7e3a0
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/repository/MainRepository.kt
@@ -0,0 +1,13 @@
+package com.mrntlu.tokenauthentication.repository
+
+import com.mrntlu.tokenauthentication.service.main.MainApiService
+import com.mrntlu.tokenauthentication.utils.toResultFlow
+import javax.inject.Inject
+
+class MainRepository @Inject constructor(
+ private val mainApiService: MainApiService,
+) {
+ fun getUserInfo() = toResultFlow {
+ mainApiService.getUserInfo()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthApiService.kt b/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthApiService.kt
new file mode 100644
index 0000000..f3c16d3
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthApiService.kt
@@ -0,0 +1,26 @@
+package com.mrntlu.tokenauthentication.service.auth
+
+import com.mrntlu.tokenauthentication.models.Auth
+import com.mrntlu.tokenauthentication.models.LoginResponse
+import retrofit2.Response
+import retrofit2.http.Body
+import retrofit2.http.FormUrlEncoded
+import retrofit2.http.GET
+import retrofit2.http.Header
+import retrofit2.http.POST
+
+interface AuthApiService {
+
+ @POST("auth/register")
+ suspend fun register(
+ @Body auth: Auth,
+ )
+
+ @POST("auth/login")
+ suspend fun login(
+ @Body auth: Auth,
+ ): Response
+
+ @GET("auth/refresh")
+ suspend fun refreshToken(): Response
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthInterceptor.kt b/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthInterceptor.kt
new file mode 100644
index 0000000..ec9c9b2
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/service/auth/AuthInterceptor.kt
@@ -0,0 +1,16 @@
+package com.mrntlu.tokenauthentication.service.auth
+
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class AuthInterceptor constructor(
+ private val tokenType: String,
+ private val accessToken: String,
+): Interceptor {
+ override fun intercept(chain: Interceptor.Chain): Response {
+ var request = chain.request()
+ request = request.newBuilder().header("Authorization", "$tokenType $accessToken").build()
+
+ return chain.proceed(request)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/service/main/MainApiService.kt b/app/src/main/java/com/mrntlu/tokenauthentication/service/main/MainApiService.kt
new file mode 100644
index 0000000..d922f66
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/service/main/MainApiService.kt
@@ -0,0 +1,11 @@
+package com.mrntlu.tokenauthentication.service.main
+
+import com.mrntlu.tokenauthentication.models.UserInfoResponse
+import retrofit2.Response
+import retrofit2.http.GET
+
+interface MainApiService {
+
+ @GET("user/info")
+ suspend fun getUserInfo(): Response
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/mrntlu/tokenauthentication/ui/auth/LoginFragment.kt b/app/src/main/java/com/mrntlu/tokenauthentication/ui/auth/LoginFragment.kt
new file mode 100644
index 0000000..4ae1dd8
--- /dev/null
+++ b/app/src/main/java/com/mrntlu/tokenauthentication/ui/auth/LoginFragment.kt
@@ -0,0 +1,76 @@
+package com.mrntlu.tokenauthentication.ui.auth
+
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Button
+import android.widget.TextView
+import androidx.core.os.bundleOf
+import androidx.fragment.app.viewModels
+import androidx.navigation.NavController
+import androidx.navigation.Navigation
+import com.mrntlu.tokenauthentication.R
+import com.mrntlu.tokenauthentication.models.Auth
+import com.mrntlu.tokenauthentication.utils.ApiResponse
+import com.mrntlu.tokenauthentication.viewmodels.AuthViewModel
+import com.mrntlu.tokenauthentication.viewmodels.CoroutinesErrorHandler
+import dagger.hilt.android.AndroidEntryPoint
+
+@AndroidEntryPoint
+class LoginFragment : Fragment() {
+
+ private val viewModel: AuthViewModel by viewModels()
+ private lateinit var navController: NavController
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ // Inflate the layout for this fragment
+ return inflater.inflate(R.layout.fragment_login, container, false)
+ }
+
+ /*
+ https://codevoweb.com/golang-postgresql-api-access-and-refresh-tokens/
+ https://github.com/MrNtlu/GraduationProject-Android/blob/master/app/src/main/java/com/mrntlu/localsocialmedia/viewmodel/BaseViewModel.kt
+ https://github.com/MrNtlu/BiSU-Task/blob/main/app/src/main/java/com/mrntlu/bisu/ui/HomeFragment.kt
+ https://www.google.com/search?q=android+interceptor+refresh+token&oq=android+inter&aqs=edge.1.69i57j69i59j0i512l5j69i60l2.2916j0j1&sourceid=chrome&ie=UTF-8
+ */
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ navController = Navigation.findNavController(view)
+
+ val loginTV = view.findViewById(R.id.loginTV)
+
+ viewModel.loginResponse.observe(viewLifecycleOwner) {
+ when(it) {
+ is ApiResponse.Failure -> loginTV.text = it.errorMessage
+ ApiResponse.Idle -> loginTV.text = "Idle"
+ ApiResponse.Loading -> loginTV.text = "Loading"
+ is ApiResponse.Success -> {
+ val bundle = bundleOf(
+ "token" to it.data.token,
+ )
+ navController.navigate(
+ R.id.action_loginFragment_to_main_nav_graph,
+ bundle
+ )
+ }
+ }
+ }
+
+ view.findViewById