Merge branch 'master' of git.reim.ar:ReiMerc/easyeat
This commit is contained in:
commit
67e6442255
@ -25,8 +25,7 @@
|
||||
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_main" />
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".WelcomeActivity"
|
||||
|
@ -1,11 +1,15 @@
|
||||
package tech.mercantec.easyeat
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Spinner
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import tech.mercantec.easyeat.models.Ingredient
|
||||
|
||||
class CreateDishActivity : AppCompatActivity() {
|
||||
|
||||
@ -25,6 +29,19 @@ class CreateDishActivity : AppCompatActivity() {
|
||||
addButton.setOnClickListener {
|
||||
addIngredientRow()
|
||||
}
|
||||
|
||||
val saveButton: Button = findViewById(R.id.saveDishButton)
|
||||
saveButton.setOnClickListener {
|
||||
val ingredientList = collectIngredients()
|
||||
|
||||
// Debug/log example
|
||||
for (ingredient in ingredientList) {
|
||||
Log.d("INGREDIENT", "Name: ${ingredient.Element}, Amount: ${ingredient.Amount}, Unit: ${ingredient.Unit}")
|
||||
}
|
||||
|
||||
// You can now save to DB, send to backend, etc.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun addIngredientRow() {
|
||||
@ -39,4 +56,29 @@ class CreateDishActivity : AppCompatActivity() {
|
||||
|
||||
ingredientContainer.addView(ingredientRow)
|
||||
}
|
||||
|
||||
private fun collectIngredients(): List<Ingredient> {
|
||||
val ingredients = mutableListOf<Ingredient>()
|
||||
|
||||
for (i in 0 until ingredientContainer.childCount) {
|
||||
val ingredientView = ingredientContainer.getChildAt(i)
|
||||
|
||||
// Find views inside this ingredient row
|
||||
val nameEditText = ingredientView.findViewById<EditText>(R.id.ingredientNameEditText)
|
||||
val amountEditText = ingredientView.findViewById<EditText>(R.id.ingredientAmountEditText)
|
||||
val spinner = ingredientView.findViewById<Spinner>(R.id.spinner)
|
||||
|
||||
val element = nameEditText.text.toString().trim()
|
||||
val amount = amountEditText.text.toString().trim()
|
||||
val unit = spinner.selectedItem.toString()
|
||||
|
||||
// Optional: Only add non-empty rows
|
||||
if (element.isNotEmpty() && amount.isNotEmpty()) {
|
||||
ingredients.add(Ingredient(Element = element, Amount = amount.toInt(), Unit = unit))
|
||||
}
|
||||
}
|
||||
|
||||
return ingredients
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class LoginActivity : AppCompatActivity() {
|
||||
|
||||
thread {
|
||||
try {
|
||||
login(email, password)
|
||||
login(this, email, password)
|
||||
} catch (e: ApiRequestException) {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||
|
@ -12,8 +12,10 @@ import androidx.navigation.ui.setupActionBarWithNavController
|
||||
import androidx.navigation.ui.setupWithNavController
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
import tech.mercantec.easyeat.databinding.ActivityMainBinding
|
||||
import tech.mercantec.easyeat.helpers.getUserInfo
|
||||
import tech.mercantec.easyeat.models.Dish
|
||||
import tech.mercantec.easyeat.ui.dishes.DishAdapter
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
|
||||
@ -30,17 +32,15 @@ class MainActivity : AppCompatActivity() {
|
||||
val navController = findNavController(R.id.nav_host_fragment_activity_main)
|
||||
val appBarConfiguration = AppBarConfiguration(
|
||||
setOf(
|
||||
R.id.navigation_dishes, R.id.navigation_shopping_list, R.id.navigation_notifications
|
||||
R.id.navigation_dishes, R.id.navigation_shopping_list, R.id.navigation_profile
|
||||
)
|
||||
)
|
||||
setupActionBarWithNavController(navController, appBarConfiguration)
|
||||
navView.setupWithNavController(navController)
|
||||
|
||||
|
||||
findViewById<FloatingActionButton>(R.id.add_dish).setOnClickListener {
|
||||
val intent = Intent(this, CreateDishActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class RegisterActivity : AppCompatActivity() {
|
||||
|
||||
thread {
|
||||
try {
|
||||
register(email, username, password)
|
||||
register(this, email, username, password)
|
||||
} catch (e: ApiRequestException) {
|
||||
runOnUiThread {
|
||||
Toast.makeText(this, e.message, Toast.LENGTH_LONG).show()
|
||||
|
@ -3,15 +3,13 @@ package tech.mercantec.easyeat
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import tech.mercantec.easyeat.helpers.isLoggedIn
|
||||
|
||||
class SplashActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
// TODO do auth check
|
||||
val loggedIn = false
|
||||
|
||||
if (!loggedIn) {
|
||||
if (!isLoggedIn(this)) {
|
||||
startActivity(Intent(this, WelcomeActivity::class.java))
|
||||
|
||||
return
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.mercantec.easyeat.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import kotlinx.serialization.Serializable
|
||||
@ -10,19 +11,27 @@ import java.net.HttpURLConnection
|
||||
import java.net.URL
|
||||
import kotlinx.serialization.json.*
|
||||
import kotlinx.serialization.serializer
|
||||
import tech.mercantec.easyeat.LoginActivity
|
||||
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 {
|
||||
fun request(ctx: Context, method: String, path: String, data: String?, autoRefresh: Boolean = true): HttpResponse {
|
||||
val url = URL(BuildConfig.API_BASE_URL + path)
|
||||
|
||||
val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE)
|
||||
val authToken = prefs.getString("auth-token", null)
|
||||
val refreshToken = prefs.getString("auth-token", null)
|
||||
|
||||
try {
|
||||
with(url.openConnection() as HttpURLConnection) {
|
||||
requestMethod = method
|
||||
|
||||
if (authToken != null)
|
||||
setRequestProperty("Authorization", "Bearer $authToken")
|
||||
|
||||
if (data != null) {
|
||||
setRequestProperty("Content-Type", "application/json")
|
||||
|
||||
@ -30,6 +39,18 @@ fun request(method: String, path: String, data: String?): HttpResponse {
|
||||
outputStream.flush()
|
||||
}
|
||||
|
||||
if (responseCode == 401 && refreshToken != null) {
|
||||
if (!autoRefresh || !refreshAuthToken(ctx, refreshToken)) {
|
||||
val intent = Intent(ctx, LoginActivity::class.java)
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
ctx.startActivity(intent)
|
||||
|
||||
throw ApiRequestException("Please sign in again", null)
|
||||
}
|
||||
|
||||
return request(ctx, method, path, data, false)
|
||||
}
|
||||
|
||||
if (responseCode >= 400)
|
||||
return HttpResponse(errorStream.readBytes().decodeToString(), responseCode)
|
||||
|
||||
@ -45,13 +66,13 @@ fun request(method: String, path: String, data: String?): HttpResponse {
|
||||
@Serializable
|
||||
class HttpErrorResponse(val message: String)
|
||||
|
||||
inline fun <reified Req, reified Res> requestJson(method: String, path: String, data: Req?): Res {
|
||||
inline fun <reified Req, reified Res> requestJson(ctx: Context, 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)
|
||||
val response = request(ctx, method, path, requestJson)
|
||||
|
||||
if (response.code >= 400) {
|
||||
try {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package tech.mercantec.easyeat.helpers
|
||||
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@ -9,20 +10,76 @@ 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) {
|
||||
fun login(ctx: Context, email: String, password: String) {
|
||||
val request = LoginRequest(email, password)
|
||||
|
||||
val response = requestJson<LoginRequest, LoginResponse>("POST", "/api/User/login", request)
|
||||
|
||||
// TODO save tokens
|
||||
val response = requestJson<LoginRequest, LoginResponse>(ctx, "POST", "/api/User/login", request)
|
||||
|
||||
with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
|
||||
putInt("user-id", response.id)
|
||||
putString("username", response.userName)
|
||||
putString("auth-token", response.token)
|
||||
putString("refresh-token", response.refreshToken)
|
||||
apply()
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class CreateUserRequest(val email: String, val userName: String, val password: String)
|
||||
|
||||
fun register(email: String, username: String, password: String) {
|
||||
fun register(ctx: Context, email: String, username: String, password: String) {
|
||||
val request = CreateUserRequest(email, username, password)
|
||||
|
||||
requestJson<CreateUserRequest, Boolean>("POST", "/api/User/create", request)
|
||||
requestJson<CreateUserRequest, Boolean>(ctx, "POST", "/api/User/create", request)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class RefreshTokenRequest(val refreshToken: String)
|
||||
|
||||
@Serializable
|
||||
data class RefreshTokenResponse(val token: String, val refreshToken: String)
|
||||
|
||||
fun refreshAuthToken(ctx: Context, refreshToken: String): Boolean {
|
||||
val response: RefreshTokenResponse
|
||||
try {
|
||||
response = requestJson<RefreshTokenRequest, RefreshTokenResponse>(
|
||||
ctx,
|
||||
"POST", "/api/User/refreshtoken",
|
||||
RefreshTokenRequest(refreshToken)
|
||||
)
|
||||
} catch (e: ApiRequestException) {
|
||||
if (e.message != null)
|
||||
Log.e("EasyEat", e.message!!)
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
with (ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE).edit()) {
|
||||
putString("auth-token", response.token)
|
||||
putString("refresh-token", response.refreshToken)
|
||||
apply()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun isLoggedIn(ctx: Context): Boolean {
|
||||
val prefs = ctx.getSharedPreferences("easyeat", Context.MODE_PRIVATE)
|
||||
val authToken = prefs.getString("auth-token", null)
|
||||
val refreshToken = prefs.getString("refresh-token", null) ?: return false
|
||||
|
||||
if (authToken == null) {
|
||||
return refreshAuthToken(ctx, refreshToken)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class UserInfoResponse(val id: Int, val userName: String, val email: String)
|
||||
|
||||
fun getUserInfo(ctx: Context): UserInfoResponse {
|
||||
val response = requestJson<Unit, UserInfoResponse>(ctx, "GET", "/api/User/get", null)
|
||||
|
||||
return response
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package tech.mercantec.easyeat.models
|
||||
|
||||
data class Ingredient(
|
||||
val Amount: Int,
|
||||
val Unit: String,
|
||||
val Element: String
|
||||
)
|
@ -1,11 +1,13 @@
|
||||
package tech.mercantec.easyeat.ui.dishes
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import tech.mercantec.easyeat.CreateDishActivity
|
||||
import tech.mercantec.easyeat.databinding.FragmentDishesBinding
|
||||
import tech.mercantec.easyeat.models.Dish
|
||||
|
||||
@ -25,6 +27,11 @@ class DishesFragment : Fragment() {
|
||||
_binding = FragmentDishesBinding.inflate(inflater, container, false)
|
||||
val root: View = binding.root
|
||||
|
||||
binding.addDish.setOnClickListener {
|
||||
val intent = Intent(requireContext(), CreateDishActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
context?.let { context ->
|
||||
binding.dishesList.setOnItemClickListener { parent, view, position, id ->
|
||||
val selectedItem = parent.getItemAtPosition(position) as Dish
|
||||
@ -47,9 +54,13 @@ class DishesFragment : Fragment() {
|
||||
binding.dishesList.adapter = DishAdapter(context, listItems)
|
||||
}
|
||||
|
||||
|
||||
return root
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
|
@ -1,42 +0,0 @@
|
||||
package tech.mercantec.easyeat.ui.notifications
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import tech.mercantec.easyeat.databinding.FragmentNotificationsBinding
|
||||
|
||||
class NotificationsFragment : Fragment() {
|
||||
|
||||
private var _binding: FragmentNotificationsBinding? = null
|
||||
|
||||
// This property is only valid between onCreateView and
|
||||
// onDestroyView.
|
||||
private val binding get() = _binding!!
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
val notificationsViewModel =
|
||||
ViewModelProvider(this).get(NotificationsViewModel::class.java)
|
||||
|
||||
_binding = FragmentNotificationsBinding.inflate(inflater, container, false)
|
||||
val root: View = binding.root
|
||||
|
||||
val textView: TextView = binding.textNotifications
|
||||
notificationsViewModel.text.observe(viewLifecycleOwner) {
|
||||
textView.text = it
|
||||
}
|
||||
return root
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
_binding = null
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package tech.mercantec.easyeat.ui.notifications
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class NotificationsViewModel : ViewModel() {
|
||||
|
||||
private val _text = MutableLiveData<String>().apply {
|
||||
value = "This is notifications Fragment"
|
||||
}
|
||||
val text: LiveData<String> = _text
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package tech.mercantec.easyeat.ui.profile
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.Fragment
|
||||
import tech.mercantec.easyeat.databinding.FragmentProfileBinding
|
||||
import tech.mercantec.easyeat.helpers.ApiRequestException
|
||||
import tech.mercantec.easyeat.helpers.UserInfoResponse
|
||||
import tech.mercantec.easyeat.helpers.getUserInfo
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class ProfileFragment : Fragment() {
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val binding = FragmentProfileBinding.inflate(inflater, container, false)
|
||||
|
||||
thread {
|
||||
val userInfo: UserInfoResponse
|
||||
try {
|
||||
userInfo = getUserInfo(requireContext())
|
||||
} catch (e: ApiRequestException) {
|
||||
activity?.runOnUiThread {
|
||||
Toast.makeText(activity?.applicationContext, e.message, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
return@thread
|
||||
}
|
||||
|
||||
activity?.runOnUiThread {
|
||||
binding.username.text = userInfo.userName
|
||||
binding.email.text = userInfo.email
|
||||
}
|
||||
}
|
||||
|
||||
return binding.root
|
||||
}
|
||||
}
|
10
app/app/src/main/res/drawable/ic_account_circle_24px.xml
Normal file
10
app/app/src/main/res/drawable/ic_account_circle_24px.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M234,684Q285,645 348,622.5Q411,600 480,600Q549,600 612,622.5Q675,645 726,684Q761,643 780.5,591Q800,539 800,480Q800,347 706.5,253.5Q613,160 480,160Q347,160 253.5,253.5Q160,347 160,480Q160,539 179.5,591Q199,643 234,684ZM480,520Q421,520 380.5,479.5Q340,439 340,380Q340,321 380.5,280.5Q421,240 480,240Q539,240 579.5,280.5Q620,321 620,380Q620,439 579.5,479.5Q539,520 480,520ZM480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,397 111.5,324Q143,251 197,197Q251,143 324,111.5Q397,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,563 848.5,636Q817,709 763,763Q709,817 636,848.5Q563,880 480,880Z"/>
|
||||
</vector>
|
@ -1,9 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z" />
|
||||
</vector>
|
10
app/app/src/main/res/drawable/ic_person_24px.xml
Normal file
10
app/app/src/main/res/drawable/ic_person_24px.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M480,480Q414,480 367,433Q320,386 320,320Q320,254 367,207Q414,160 480,160Q546,160 593,207Q640,254 640,320Q640,386 593,433Q546,480 480,480ZM160,800L160,688Q160,654 177.5,625.5Q195,597 224,582Q286,551 350,535.5Q414,520 480,520Q546,520 610,535.5Q674,551 736,582Q765,597 782.5,625.5Q800,654 800,688L800,800L160,800Z"/>
|
||||
</vector>
|
@ -27,5 +27,13 @@
|
||||
android:text="Add Ingredient"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="16dp"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/saveDishButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Save"
|
||||
android:layout_gravity="right"
|
||||
android:layout_marginTop="16dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="8dp">
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="8dp">
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Ingredient Field -->
|
||||
<TextView
|
||||
@ -14,6 +17,7 @@
|
||||
android:text="@string/ingredient_label" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/ingredientNameEditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="58dp"
|
||||
android:hint="Ingredient name" />
|
||||
@ -26,7 +30,7 @@
|
||||
android:gravity="center_vertical"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<!-- Amount field (fixed width) -->
|
||||
<!-- Amount field -->
|
||||
<LinearLayout
|
||||
android:layout_width="174dp"
|
||||
android:layout_height="wrap_content"
|
||||
@ -38,12 +42,13 @@
|
||||
android:text="@string/amount_label" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/ingredientAmountEditText"
|
||||
android:layout_width="173dp"
|
||||
android:layout_height="48dp"
|
||||
android:hint="0" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Measurement field (fill rest) -->
|
||||
<!-- Measurement field -->
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
@ -62,7 +67,7 @@
|
||||
android:layout_height="48dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Remove Button (fixed width) -->
|
||||
<!-- Remove Button -->
|
||||
<Button
|
||||
android:id="@+id/removeButton"
|
||||
android:layout_width="48dp"
|
||||
@ -72,9 +77,5 @@
|
||||
android:textSize="20dp"
|
||||
android:backgroundTint="@color/red" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</ScrollView>
|
||||
|
@ -8,19 +8,6 @@
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="?attr/actionBarSize">
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_dish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:contentDescription="@string/add_label"
|
||||
app:srcCompat="@android:drawable/ic_input_add"
|
||||
app:backgroundTint="@color/cyan"
|
||||
app:tint="@android:color/white"
|
||||
app:layout_constraintBottom_toTopOf="@id/nav_view"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
|
||||
<fragment
|
||||
android:id="@+id/nav_host_fragment_activity_main"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
|
@ -1,12 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/dishes_fragment_root"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- Your list view -->
|
||||
<ListView
|
||||
android:id="@+id/dishes_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
/>
|
||||
android:divider="@android:color/darker_gray"
|
||||
android:dividerHeight="1dp" />
|
||||
|
||||
<!-- FloatingActionButton -->
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/add_dish"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:backgroundTint="@color/cyan"
|
||||
app:srcCompat="@android:drawable/ic_input_add"
|
||||
app:tint="@android:color/white"/>
|
||||
</FrameLayout>
|
||||
|
@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.notifications.NotificationsFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_notifications"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
53
app/app/src/main/res/layout/fragment_profile.xml
Normal file
53
app/app/src/main/res/layout/fragment_profile.xml
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingStart="30sp"
|
||||
android:paddingEnd="30sp"
|
||||
android:gravity="center">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/loading"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:indeterminate="true"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:src="@drawable/ic_account_circle_24px"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/username"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/loading"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/email"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"
|
||||
android:textAlignment="center"
|
||||
android:text="@string/loading"
|
||||
/>
|
||||
|
||||
<Button
|
||||
android:layout_marginTop="40dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/edit_profile_label"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
@ -3,17 +3,17 @@
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_dishes"
|
||||
android:icon="@drawable/ic_restaurant_black_24px"
|
||||
android:icon="@drawable/ic_restaurant_24px"
|
||||
android:title="@string/title_your_dishes" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_shopping_list"
|
||||
android:icon="@drawable/ic_list_alt_black_24px"
|
||||
android:icon="@drawable/ic_list_alt_24px"
|
||||
android:title="@string/title_shopping_list" />
|
||||
|
||||
<item
|
||||
android:id="@+id/navigation_notifications"
|
||||
android:icon="@drawable/ic_notifications_black_24dp"
|
||||
android:title="@string/title_notifications" />
|
||||
android:id="@+id/navigation_profile"
|
||||
android:icon="@drawable/ic_person_24px"
|
||||
android:title="@string/title_profile" />
|
||||
|
||||
</menu>
|
@ -18,8 +18,8 @@
|
||||
tools:layout="@layout/fragment_shopping_list" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_notifications"
|
||||
android:name="tech.mercantec.easyeat.ui.notifications.NotificationsFragment"
|
||||
android:label="@string/title_notifications"
|
||||
tools:layout="@layout/fragment_notifications" />
|
||||
android:id="@+id/navigation_profile"
|
||||
android:name="tech.mercantec.easyeat.ui.profile.ProfileFragment"
|
||||
android:label="@string/title_profile"
|
||||
tools:layout="@layout/fragment_profile" />
|
||||
</navigation>
|
@ -1,9 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">EasyEat</string>
|
||||
<string name="title_activity_main">MainActivity</string>
|
||||
<string name="title_your_dishes">Your Dishes</string>
|
||||
<string name="title_shopping_list">Shopping list</string>
|
||||
<string name="title_notifications">Notifications</string>
|
||||
<string name="title_profile">Profile</string>
|
||||
<string name="welcome_heading">Welcome to <font color="#0099BA">EasyEat</font></string>
|
||||
<string name="login_label">Login</string>
|
||||
<string name="login_heading">Login to EasyEat</string>
|
||||
@ -22,5 +21,6 @@
|
||||
<string name="measurement_label">Measurement</string>
|
||||
<string name="amount_label">Amount</string>
|
||||
<string name="add_label">Add</string>
|
||||
|
||||
<string name="edit_profile_label">Edit profile</string>
|
||||
<string name="loading">Loading…</string>
|
||||
</resources>
|
||||
|
20
backend/API/appsettings.example.json
Normal file
20
backend/API/appsettings.example.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
|
||||
"ConnectionStrings": {
|
||||
"Database": "Data Source=database.sqlite3"
|
||||
},
|
||||
|
||||
"JwtSettings": {
|
||||
"Issuer": "TemperatureAlarmApi",
|
||||
"Audience": "Customers",
|
||||
"Key": ""
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user