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"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="21" />
|
<bytecodeTargetLevel target="17" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -1,9 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="FrameworkDetectionExcludesConfiguration">
|
<component name="FrameworkDetectionExcludesConfiguration">
|
||||||
<file type="web" url="file://$PROJECT_DIR$" />
|
<file type="web" url="file://$PROJECT_DIR$" />
|
||||||
</component>
|
</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" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
|
import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
|
id("org.jetbrains.kotlin.plugin.serialization")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -15,6 +18,8 @@ android {
|
|||||||
versionName = "1.0"
|
versionName = "1.0"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
buildConfigField("String", "API_BASE_URL", project.property("API_BASE_URL").toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@ -36,7 +41,6 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.appcompat)
|
implementation(libs.androidx.appcompat)
|
||||||
implementation(libs.material)
|
implementation(libs.material)
|
||||||
@ -48,7 +52,5 @@ dependencies {
|
|||||||
implementation(libs.navigation.fragment.ktx)
|
implementation(libs.navigation.fragment.ktx)
|
||||||
implementation(libs.navigation.ui.ktx)
|
implementation(libs.navigation.ui.ktx)
|
||||||
implementation(libs.androidx.activity)
|
implementation(libs.androidx.activity)
|
||||||
testImplementation(libs.junit)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
|
||||||
androidTestImplementation(libs.androidx.espresso.core)
|
|
||||||
}
|
}
|
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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
@ -3,10 +3,12 @@ package tech.mercantec.easyeat
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import androidx.activity.enableEdgeToEdge
|
import android.widget.EditText
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import tech.mercantec.easyeat.helpers.login
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity() {
|
class LoginActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -15,11 +17,24 @@ class LoginActivity : AppCompatActivity() {
|
|||||||
setContentView(R.layout.activity_login)
|
setContentView(R.layout.activity_login)
|
||||||
|
|
||||||
findViewById<Button>(R.id.login).setOnClickListener {
|
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)
|
thread {
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK // Prevent going back to login screen
|
try {
|
||||||
startActivity(intent)
|
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 {
|
findViewById<Button>(R.id.back).setOnClickListener {
|
||||||
|
@ -3,10 +3,12 @@ package tech.mercantec.easyeat
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
import androidx.activity.enableEdgeToEdge
|
import android.widget.EditText
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import tech.mercantec.easyeat.helpers.register
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
class RegisterActivity : AppCompatActivity() {
|
class RegisterActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@ -15,10 +17,30 @@ class RegisterActivity : AppCompatActivity() {
|
|||||||
setContentView(R.layout.activity_register)
|
setContentView(R.layout.activity_register)
|
||||||
|
|
||||||
findViewById<Button>(R.id.register).setOnClickListener {
|
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))
|
if (password != confirmPassword) {
|
||||||
finish()
|
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 {
|
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
|
<EditText
|
||||||
|
android:id="@+id/email"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/email_hint"
|
android:hint="@string/email_hint"
|
||||||
@ -39,6 +40,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/password_hint"
|
android:hint="@string/password_hint"
|
||||||
|
@ -24,10 +24,10 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/username"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/username_hint"
|
android:hint="@string/username_hint"
|
||||||
android:autofillHints="emailAddress"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -39,6 +39,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/email"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/email_hint"
|
android:hint="@string/email_hint"
|
||||||
@ -54,6 +55,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/password_hint"
|
android:hint="@string/password_hint"
|
||||||
@ -70,6 +72,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
|
android:id="@+id/confirm_password"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/password_hint"
|
android:hint="@string/password_hint"
|
||||||
|
@ -2,4 +2,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.kotlin.android) 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
|
# 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,
|
# resources declared in the library itself and none from the library's dependencies,
|
||||||
# thereby reducing the size of the R class for that library
|
# 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"
|
junitVersion = "1.1.5"
|
||||||
espressoCore = "3.5.1"
|
espressoCore = "3.5.1"
|
||||||
appcompat = "1.6.1"
|
appcompat = "1.6.1"
|
||||||
|
kotlinxSerializationJson = "1.2.2"
|
||||||
material = "1.10.0"
|
material = "1.10.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
lifecycleLivedataKtx = "2.6.1"
|
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-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
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" }
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||||
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
androidx-lifecycle-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" }
|
||||||
|
Loading…
Reference in New Issue
Block a user