Merge branch 'master' of git.reim.ar:ReiMerc/easyeat
This commit is contained in:
commit
f5d580afe7
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="21" />
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
@ -1,9 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="FrameworkDetectionExcludesConfiguration">
|
||||
<file type="web" url="file://$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -1,6 +1,9 @@
|
||||
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application)
|
||||
alias(libs.plugins.kotlin.android)
|
||||
id("org.jetbrains.kotlin.plugin.serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
@ -15,6 +18,8 @@ android {
|
||||
versionName = "1.0"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
buildConfigField("String", "API_BASE_URL", project.property("API_BASE_URL").toString())
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@ -36,7 +41,6 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
implementation(libs.androidx.core.ktx)
|
||||
implementation(libs.androidx.appcompat)
|
||||
implementation(libs.material)
|
||||
@ -48,7 +52,5 @@ dependencies {
|
||||
implementation(libs.navigation.fragment.ktx)
|
||||
implementation(libs.navigation.ui.ktx)
|
||||
implementation(libs.androidx.activity)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
}
|
1
app/app/gradle.properties
Normal file
1
app/app/gradle.properties
Normal file
@ -0,0 +1 @@
|
||||
API_BASE_URL="https://easyeat.mercantec.tech"
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -3,10 +3,12 @@ package tech.mercantec.easyeat
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||
import tech.mercantec.easyeat.helpers.login
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -15,11 +17,24 @@ class LoginActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_login)
|
||||
|
||||
findViewById<Button>(R.id.login).setOnClickListener {
|
||||
// TODO authenticate
|
||||
val email = findViewById<EditText>(R.id.email).text.toString()
|
||||
val password = findViewById<EditText>(R.id.password).text.toString()
|
||||
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK // Prevent going back to login screen
|
||||
startActivity(intent)
|
||||
thread {
|
||||
try {
|
||||
login(email, password)
|
||||
} catch (e: ApiRequestException) {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
return@thread
|
||||
}
|
||||
|
||||
val intent = Intent(this, MainActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK // Prevent going back to login screen
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.back).setOnClickListener {
|
||||
|
@ -3,10 +3,12 @@ package tech.mercantec.easyeat
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.widget.Button
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import android.widget.EditText
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||
import tech.mercantec.easyeat.helpers.register
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class RegisterActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -15,10 +17,30 @@ class RegisterActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_register)
|
||||
|
||||
findViewById<Button>(R.id.register).setOnClickListener {
|
||||
// TODO create account
|
||||
val username = findViewById<EditText>(R.id.username).text.toString()
|
||||
val email = findViewById<EditText>(R.id.email).text.toString()
|
||||
val password = findViewById<EditText>(R.id.password).text.toString()
|
||||
val confirmPassword = findViewById<EditText>(R.id.confirm_password).text.toString()
|
||||
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
finish()
|
||||
if (password != confirmPassword) {
|
||||
Toast.makeText(this, "Passwords do not match", Toast.LENGTH_LONG).show()
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
thread {
|
||||
try {
|
||||
register(email, username, password)
|
||||
} catch (e: ApiRequestException) {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
return@thread
|
||||
}
|
||||
|
||||
startActivity(Intent(this, LoginActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
findViewById<Button>(R.id.back).setOnClickListener {
|
||||
|
79
app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt
Normal file
79
app/app/src/main/java/tech/mercantec/easyeat/helpers/api.kt
Normal file
@ -0,0 +1,79 @@
|
||||
package tech.mercantec.easyeat.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.SerializationException
|
||||
import tech.mercantec.easyeat.BuildConfig
|
||||
import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.serializer
|
||||
import java.io.IOException
|
||||
|
||||
class ApiRequestException(message: String, cause: Throwable?) : Exception(message, cause)
|
||||
|
||||
class HttpResponse(val body: String, val code: Int)
|
||||
|
||||
fun request(method: String, path: String, data: String?): HttpResponse {
|
||||
val url = URL(BuildConfig.API_BASE_URL + path)
|
||||
|
||||
try {
|
||||
with(url.openConnection() as HttpURLConnection) {
|
||||
requestMethod = method
|
||||
|
||||
if (data != null) {
|
||||
setRequestProperty("Content-Type", "application/json")
|
||||
|
||||
outputStream.write(data.toByteArray())
|
||||
outputStream.flush()
|
||||
}
|
||||
|
||||
if (responseCode >= 400)
|
||||
return HttpResponse(errorStream.readBytes().decodeToString(), responseCode)
|
||||
|
||||
return HttpResponse(inputStream.readBytes().decodeToString(), responseCode)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.e("EasyEat", e.toString())
|
||||
|
||||
throw ApiRequestException("Failed to connect to server: " + e.message, e)
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class HttpErrorResponse(val message: String)
|
||||
|
||||
inline fun <reified Req, reified Res> requestJson(method: String, path: String, data: Req?): Res {
|
||||
val requestJson =
|
||||
if (data != null)
|
||||
Json.encodeToString(serializer<Req>(), data)
|
||||
else null
|
||||
|
||||
val response = request(method, path, requestJson)
|
||||
|
||||
if (response.code >= 400) {
|
||||
try {
|
||||
val error = Json.decodeFromString<HttpErrorResponse>(response.body)
|
||||
|
||||
throw ApiRequestException(error.message, null)
|
||||
} catch (e: SerializationException) {
|
||||
if (e.message != null)
|
||||
Log.e("EasyEat", e.message!!)
|
||||
Log.e("EasyEat", response.body)
|
||||
|
||||
throw ApiRequestException("Request failed with HTTP status code ${response.code}", e)
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return Json.decodeFromString<Res>(response.body)
|
||||
} catch (e: SerializationException) {
|
||||
if (e.message != null)
|
||||
Log.e("EasyEat", e.message!!)
|
||||
Log.e("EasyEat", response.body)
|
||||
|
||||
throw ApiRequestException("Failed to parse response: $response", e)
|
||||
}
|
||||
}
|
28
app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
Normal file
28
app/app/src/main/java/tech/mercantec/easyeat/helpers/auth.kt
Normal file
@ -0,0 +1,28 @@
|
||||
package tech.mercantec.easyeat.helpers
|
||||
|
||||
import android.content.Context
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LoginRequest(val emailUsr: String, val password: String)
|
||||
|
||||
@Serializable
|
||||
data class LoginResponse(val token: String, val userName: String, val id: Int, val refreshToken: String)
|
||||
|
||||
fun login(email: String, password: String) {
|
||||
val request = LoginRequest(email, password)
|
||||
|
||||
val response = requestJson<LoginRequest, LoginResponse>("POST", "/api/User/login", request)
|
||||
|
||||
// TODO save tokens
|
||||
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class CreateUserRequest(val email: String, val userName: String, val password: String)
|
||||
|
||||
fun register(email: String, username: String, password: String) {
|
||||
val request = CreateUserRequest(email, username, password)
|
||||
|
||||
requestJson<CreateUserRequest, Boolean>("POST", "/api/User/create", request)
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/email_hint"
|
||||
@ -39,6 +40,7 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
|
@ -24,10 +24,10 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/username"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username_hint"
|
||||
android:autofillHints="emailAddress"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
@ -39,6 +39,7 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/email_hint"
|
||||
@ -54,6 +55,7 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
@ -70,6 +72,7 @@
|
||||
/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/confirm_password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/password_hint"
|
||||
|
@ -2,4 +2,5 @@
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
id("org.jetbrains.kotlin.plugin.serialization") version "1.7.10" apply false
|
||||
}
|
@ -20,4 +20,6 @@ kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
|
@ -6,6 +6,7 @@ junit = "4.13.2"
|
||||
junitVersion = "1.1.5"
|
||||
espressoCore = "3.5.1"
|
||||
appcompat = "1.6.1"
|
||||
kotlinxSerializationJson = "1.2.2"
|
||||
material = "1.10.0"
|
||||
constraintlayout = "2.1.4"
|
||||
lifecycleLivedataKtx = "2.6.1"
|
||||
@ -22,6 +23,7 @@ junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
||||
|
Loading…
Reference in New Issue
Block a user