Ajout de l’hostname et d’un répository pour le Token
This commit is contained in:
parent
ee751bdddb
commit
a911de59b1
16 changed files with 264 additions and 45 deletions
|
@ -1,18 +1,21 @@
|
||||||
package com.example.palto.data
|
package com.example.palto.data.local
|
||||||
|
|
||||||
|
import com.example.palto.data.Result
|
||||||
import com.example.palto.data.model.LoggedInUser
|
import com.example.palto.data.model.LoggedInUser
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that handles authentication w/ login credentials and retrieves user information.
|
* Class that handles authentication w/ login credentials and retrieves user information.
|
||||||
*/
|
*/
|
||||||
class LoginDataSource {
|
class LocalDataSource {
|
||||||
|
|
||||||
fun login(username: String, password: String): Result<LoggedInUser> {
|
fun login(username: String, password: String): Result<LoggedInUser> {
|
||||||
try {
|
try {
|
||||||
// TODO: handle loggedInUser authentication
|
|
||||||
|
|
||||||
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
|
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
|
||||||
return Result.Success(fakeUser)
|
return Result.Success(fakeUser)
|
||||||
|
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
return Result.Error(IOException("Error logging in", e))
|
return Result.Error(IOException("Error logging in", e))
|
||||||
}
|
}
|
|
@ -1,9 +1,14 @@
|
||||||
package com.example.palto.data.model
|
package com.example.palto.data.model
|
||||||
|
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data class that captures user information for logged in users retrieved from LoginRepository
|
* Data class that captures user information for logged in users retrieved from LoginRepository
|
||||||
*/
|
*/
|
||||||
data class LoggedInUser(
|
data class LoggedInUser(
|
||||||
val userId: String,
|
val id: String,
|
||||||
val displayName: String
|
val username: String,
|
||||||
)
|
val first_name: String,
|
||||||
|
val last_name: String,
|
||||||
|
val email: String
|
||||||
|
) : Serializable
|
||||||
|
|
10
app/src/main/java/com/example/palto/data/model/Tokens.kt
Normal file
10
app/src/main/java/com/example/palto/data/model/Tokens.kt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
package com.example.palto.data.model
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data class that captures tokens for logged in users retrieved from LoginRepository
|
||||||
|
*/
|
||||||
|
data class Tokens(
|
||||||
|
val refresh: String,
|
||||||
|
val access: String
|
||||||
|
) : Serializable
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.example.palto.data.network
|
||||||
|
|
||||||
|
import com.example.palto.data.Result
|
||||||
|
import com.example.palto.data.model.LoggedInUser
|
||||||
|
import com.example.palto.data.model.Tokens
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that handles API calls.
|
||||||
|
*/
|
||||||
|
class ServerDataSource {
|
||||||
|
|
||||||
|
private var hostname: String? = null
|
||||||
|
|
||||||
|
fun requestToken(hostname: String, username: String, password: String): Result<Tokens> {
|
||||||
|
try {
|
||||||
|
val tokens = Tokens()
|
||||||
|
return Result.Success()
|
||||||
|
} catch () {
|
||||||
|
return Result.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun refreshToken(): Result<Tokens> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun verifyToken(): Boolean {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun login(hostname: String, username: String, password: String): Result<LoggedInUser> {
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
|
||||||
|
return Result.Success(fakeUser)
|
||||||
|
*/
|
||||||
|
return
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
return Result.Error(IOException("Error logging in", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun logout() {
|
||||||
|
// TODO: revoke authentication
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,17 @@
|
||||||
package com.example.palto.data
|
package com.example.palto.data.repository
|
||||||
|
|
||||||
|
import com.example.palto.data.Result
|
||||||
|
import com.example.palto.data.network.ServerDataSource
|
||||||
import com.example.palto.data.model.LoggedInUser
|
import com.example.palto.data.model.LoggedInUser
|
||||||
|
import com.example.palto.data.model.Tokens
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that requests authentication and user information from the remote data source and
|
* Class that requests authentication and user information from the remote data source and
|
||||||
* maintains an in-memory cache of login status and user credentials information.
|
* maintains an in-memory cache of login status and user credentials information.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class LoginRepository(val dataSource: LoginDataSource) {
|
class LoginRepository(val dataSource: ServerDataSource) {
|
||||||
|
|
||||||
// in-memory cache of the loggedInUser object
|
|
||||||
var user: LoggedInUser? = null
|
var user: LoggedInUser? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
@ -27,12 +29,16 @@ class LoginRepository(val dataSource: LoginDataSource) {
|
||||||
dataSource.logout()
|
dataSource.logout()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun login(username: String, password: String): Result<LoggedInUser> {
|
fun login(
|
||||||
|
hostname: String,
|
||||||
|
username: String,
|
||||||
|
password: String
|
||||||
|
): Result<LoggedInUser> {
|
||||||
// handle login
|
// handle login
|
||||||
val result = dataSource.login(username, password)
|
val result = dataSource.login(hostname, username, password)
|
||||||
|
|
||||||
if (result is Result.Success) {
|
if (result is Result.Success) {
|
||||||
setLoggedInUser(result.data)
|
setTokens(result.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.example.palto.data.repository
|
||||||
|
|
||||||
|
import com.example.palto.data.Result
|
||||||
|
import com.example.palto.data.network.ServerDataSource
|
||||||
|
import com.example.palto.data.model.LoggedInUser
|
||||||
|
import com.example.palto.data.model.Tokens
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that requests authentication and user information from the remote data source and
|
||||||
|
* maintains an in-memory cache of login status and user credentials information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class TokensRepository(val dataSource: ServerDataSource) {
|
||||||
|
|
||||||
|
var tokens: Tokens? = null
|
||||||
|
private set
|
||||||
|
|
||||||
|
/*
|
||||||
|
val isLoggedIn: Boolean
|
||||||
|
get() = user != null
|
||||||
|
*/
|
||||||
|
|
||||||
|
init {
|
||||||
|
// If user credentials will be cached in local storage, it is recommended it be encrypted
|
||||||
|
// @see https://developer.android.com/training/articles/keystore
|
||||||
|
tokens = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun login(username: String, password: String): Result<LoggedInUser> {
|
||||||
|
// handle login
|
||||||
|
val result = dataSource.login(username, password)
|
||||||
|
|
||||||
|
if (result is Result.Success) {
|
||||||
|
setLoggedInUser(result.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
private fun setTokens(tokens: Tokens) {
|
||||||
|
this.tokens = tokens
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ package com.example.palto.ui.login
|
||||||
* Data validation state of the login form.
|
* Data validation state of the login form.
|
||||||
*/
|
*/
|
||||||
data class LoginFormState(
|
data class LoginFormState(
|
||||||
|
val hostnameError: Int? = null,
|
||||||
val usernameError: Int? = null,
|
val usernameError: Int? = null,
|
||||||
val passwordError: Int? = null,
|
val passwordError: Int? = null,
|
||||||
val isDataValid: Boolean = false
|
val isDataValid: Boolean = false
|
||||||
|
|
|
@ -45,6 +45,7 @@ class LoginFragment : Fragment() {
|
||||||
loginViewModel = ViewModelProvider(this, LoginViewModelFactory())
|
loginViewModel = ViewModelProvider(this, LoginViewModelFactory())
|
||||||
.get(LoginViewModel::class.java)
|
.get(LoginViewModel::class.java)
|
||||||
|
|
||||||
|
val hostnameEditText = binding.hostname
|
||||||
val usernameEditText = binding.username
|
val usernameEditText = binding.username
|
||||||
val passwordEditText = binding.password
|
val passwordEditText = binding.password
|
||||||
val loginButton = binding.login
|
val loginButton = binding.login
|
||||||
|
@ -57,6 +58,9 @@ class LoginFragment : Fragment() {
|
||||||
return@Observer
|
return@Observer
|
||||||
}
|
}
|
||||||
loginButton.isEnabled = loginFormState.isDataValid
|
loginButton.isEnabled = loginFormState.isDataValid
|
||||||
|
loginFormState.hostnameError?.let {
|
||||||
|
hostnameEditText.error = getString(it)
|
||||||
|
}
|
||||||
loginFormState.usernameError?.let {
|
loginFormState.usernameError?.let {
|
||||||
usernameEditText.error = getString(it)
|
usernameEditText.error = getString(it)
|
||||||
}
|
}
|
||||||
|
@ -79,26 +83,25 @@ class LoginFragment : Fragment() {
|
||||||
})
|
})
|
||||||
|
|
||||||
val afterTextChangedListener = object : TextWatcher {
|
val afterTextChangedListener = object : TextWatcher {
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { }
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { }
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
loginViewModel.loginDataChanged(
|
loginViewModel.loginDataChanged(
|
||||||
|
hostnameEditText.text.toString(),
|
||||||
usernameEditText.text.toString(),
|
usernameEditText.text.toString(),
|
||||||
passwordEditText.text.toString()
|
passwordEditText.text.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
hostnameEditText.addTextChangedListener(afterTextChangedListener)
|
||||||
usernameEditText.addTextChangedListener(afterTextChangedListener)
|
usernameEditText.addTextChangedListener(afterTextChangedListener)
|
||||||
passwordEditText.addTextChangedListener(afterTextChangedListener)
|
passwordEditText.addTextChangedListener(afterTextChangedListener)
|
||||||
passwordEditText.setOnEditorActionListener { _, actionId, _ ->
|
passwordEditText.setOnEditorActionListener { _, actionId, _ ->
|
||||||
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
if (actionId == EditorInfo.IME_ACTION_DONE) {
|
||||||
loginViewModel.login(
|
loginViewModel.login(
|
||||||
|
hostnameEditText.text.toString(),
|
||||||
usernameEditText.text.toString(),
|
usernameEditText.text.toString(),
|
||||||
passwordEditText.text.toString()
|
passwordEditText.text.toString()
|
||||||
)
|
)
|
||||||
|
@ -110,6 +113,7 @@ class LoginFragment : Fragment() {
|
||||||
loginButton.setOnClickListener {
|
loginButton.setOnClickListener {
|
||||||
loadingProgressBar.visibility = View.VISIBLE
|
loadingProgressBar.visibility = View.VISIBLE
|
||||||
loginViewModel.login(
|
loginViewModel.login(
|
||||||
|
hostnameEditText.text.toString(),
|
||||||
usernameEditText.text.toString(),
|
usernameEditText.text.toString(),
|
||||||
passwordEditText.text.toString()
|
passwordEditText.text.toString()
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import android.util.Patterns
|
import android.util.Patterns
|
||||||
import com.example.palto.data.LoginRepository
|
import com.example.palto.data.repository.LoginRepository
|
||||||
import com.example.palto.data.Result
|
import com.example.palto.data.Result
|
||||||
|
|
||||||
import com.example.palto.R
|
import com.example.palto.R
|
||||||
|
@ -17,7 +17,10 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel()
|
||||||
private val _loginResult = MutableLiveData<LoginResult>()
|
private val _loginResult = MutableLiveData<LoginResult>()
|
||||||
val loginResult: LiveData<LoginResult> = _loginResult
|
val loginResult: LiveData<LoginResult> = _loginResult
|
||||||
|
|
||||||
fun login(username: String, password: String) {
|
fun login(
|
||||||
|
hostname: String,
|
||||||
|
username: String,
|
||||||
|
password: String) {
|
||||||
// can be launched in a separate asynchronous job
|
// can be launched in a separate asynchronous job
|
||||||
val result = loginRepository.login(username, password)
|
val result = loginRepository.login(username, password)
|
||||||
|
|
||||||
|
@ -29,8 +32,13 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loginDataChanged(username: String, password: String) {
|
fun loginDataChanged(
|
||||||
if (!isUserNameValid(username)) {
|
hostname: String,
|
||||||
|
username: String,
|
||||||
|
password: String) {
|
||||||
|
if (!isHostNameValid(hostname)) {
|
||||||
|
_loginForm.value = LoginFormState(hostnameError = R.string.invalid_hostname)
|
||||||
|
} else if (!isUserNameValid(username)) {
|
||||||
_loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
|
_loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
|
||||||
} else if (!isPasswordValid(password)) {
|
} else if (!isPasswordValid(password)) {
|
||||||
_loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
|
_loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
|
||||||
|
@ -39,6 +47,10 @@ class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isHostNameValid(hostname: String): Boolean {
|
||||||
|
return hostname.isNotBlank()
|
||||||
|
}
|
||||||
|
|
||||||
// A placeholder username validation check
|
// A placeholder username validation check
|
||||||
private fun isUserNameValid(username: String): Boolean {
|
private fun isUserNameValid(username: String): Boolean {
|
||||||
return if (username.contains("@")) {
|
return if (username.contains("@")) {
|
||||||
|
|
|
@ -2,8 +2,8 @@ package com.example.palto.ui.login
|
||||||
|
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import com.example.palto.data.LoginDataSource
|
import com.example.palto.data.network.ServerDataSource
|
||||||
import com.example.palto.data.LoginRepository
|
import com.example.palto.data.repository.LoginRepository
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ViewModel provider factory to instantiate LoginViewModel.
|
* ViewModel provider factory to instantiate LoginViewModel.
|
||||||
|
@ -16,7 +16,7 @@ class LoginViewModelFactory : ViewModelProvider.Factory {
|
||||||
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
|
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
|
||||||
return LoginViewModel(
|
return LoginViewModel(
|
||||||
loginRepository = LoginRepository(
|
loginRepository = LoginRepository(
|
||||||
dataSource = LoginDataSource()
|
dataSource = ServerDataSource()
|
||||||
)
|
)
|
||||||
) as T
|
) as T
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.example.palto.ui.sheet
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import android.os.Bundle
|
||||||
|
import androidx.fragment.app.Fragment
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import com.example.palto.R
|
||||||
|
|
||||||
|
class SheetDetailFragment : Fragment() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance() = SheetDetailFragment()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var viewModel: SheetDetailViewModel
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
return inflater.inflate(R.layout.fragment_sheet_detail, container, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
|
super.onActivityCreated(savedInstanceState)
|
||||||
|
viewModel = ViewModelProvider(this).get(SheetDetailViewModel::class.java)
|
||||||
|
// TODO: Use the ViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.example.palto.ui.sheet
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class SheetDetailViewModel : ViewModel() {
|
||||||
|
// TODO: Implement the ViewModel
|
||||||
|
}
|
|
@ -11,27 +11,44 @@
|
||||||
android:paddingBottom="@dimen/fragment_vertical_margin"
|
android:paddingBottom="@dimen/fragment_vertical_margin"
|
||||||
tools:context=".ui.login.LoginFragment">
|
tools:context=".ui.login.LoginFragment">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/hostname"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginTop="64dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:autofillHints="@string/prompt_server"
|
||||||
|
android:hint="@string/prompt_hostname"
|
||||||
|
android:inputType="text"
|
||||||
|
android:selectAllOnFocus="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/username"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/username"
|
android:id="@+id/username"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginTop="96dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:autofillHints="@string/prompt_email"
|
android:autofillHints="@string/prompt_username"
|
||||||
android:hint="@string/prompt_email"
|
android:hint="@string/prompt_username"
|
||||||
android:inputType="textEmailAddress"
|
android:inputType="text"
|
||||||
android:selectAllOnFocus="true"
|
android:selectAllOnFocus="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/password"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toBottomOf="@+id/hostname" />
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:id="@+id/password"
|
android:id="@+id/password"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
android:autofillHints="@string/prompt_password"
|
android:autofillHints="@string/prompt_password"
|
||||||
android:hint="@string/prompt_password"
|
android:hint="@string/prompt_password"
|
||||||
|
@ -39,25 +56,38 @@
|
||||||
android:imeOptions="actionDone"
|
android:imeOptions="actionDone"
|
||||||
android:inputType="textPassword"
|
android:inputType="textPassword"
|
||||||
android:selectAllOnFocus="true"
|
android:selectAllOnFocus="true"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/helpmsg"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/username" />
|
app:layout_constraintTop_toBottomOf="@+id/username" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/helpmsg"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Identifiants Invalides"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/login"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/password" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/login"
|
android:id="@+id/login"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="start"
|
android:layout_gravity="start"
|
||||||
android:layout_marginStart="48dp"
|
android:layout_marginStart="48dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="48dp"
|
android:layout_marginEnd="48dp"
|
||||||
android:layout_marginBottom="64dp"
|
android:layout_marginBottom="64dp"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:text="@string/action_sign_in"
|
android:text="@string/action_sign_in"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/password"
|
app:layout_constraintTop_toBottomOf="@+id/helpmsg"
|
||||||
app:layout_constraintVertical_bias="0.2" />
|
app:layout_constraintVertical_bias="0.2" />
|
||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
|
@ -75,4 +105,5 @@
|
||||||
app:layout_constraintStart_toStartOf="@+id/password"
|
app:layout_constraintStart_toStartOf="@+id/password"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_bias="0.3" />
|
app:layout_constraintVertical_bias="0.3" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
13
app/src/main/res/layout/fragment_sheet_detail.xml
Normal file
13
app/src/main/res/layout/fragment_sheet_detail.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".ui.sheet.SheetDetailFragment">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:text="Hello" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
|
@ -21,9 +21,10 @@
|
||||||
android:id="@+id/itemFragment"
|
android:id="@+id/itemFragment"
|
||||||
android:name="com.example.palto.ItemFragment"
|
android:name="com.example.palto.ItemFragment"
|
||||||
android:label="fragment_item_list"
|
android:label="fragment_item_list"
|
||||||
tools:layout="@layout/fragment_item_list" >
|
tools:layout="@layout/fragment_item_list" />
|
||||||
<action
|
<fragment
|
||||||
android:id="@+id/action_itemFragment_to_ficheFragment"
|
android:id="@+id/sheetDetailFragment"
|
||||||
app:destination="@id/ficheFragment" />
|
android:name="com.example.palto.ui.sheet.SheetDetailFragment"
|
||||||
</fragment>
|
android:label="fragment_sheet_detail"
|
||||||
|
tools:layout="@layout/fragment_sheet_detail" />
|
||||||
</navigation>
|
</navigation>
|
|
@ -1,12 +1,14 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">Palto</string>
|
<string name="app_name">Palto</string>
|
||||||
<!-- Strings related to login -->
|
<!-- Strings related to login -->
|
||||||
<string name="prompt_email">Email</string>
|
<string name="prompt_hostname">Serveur</string>
|
||||||
<string name="prompt_password">Password</string>
|
<string name="prompt_username">Nom d’utilisateur</string>
|
||||||
<string name="action_sign_in">Sign in or register</string>
|
<string name="prompt_password">Mot de passe</string>
|
||||||
|
<string name="action_sign_in">Connexion</string>
|
||||||
<string name="action_sign_in_short">Sign in</string>
|
<string name="action_sign_in_short">Sign in</string>
|
||||||
<string name="welcome">"Welcome!"</string>
|
<string name="welcome">"Bienvenue !"</string>
|
||||||
<string name="invalid_username">Not a valid username</string>
|
<string name="invalid_hostname">Serveur inaccessible</string>
|
||||||
<string name="invalid_password">Password must be >5 characters</string>
|
<string name="invalid_username">Nom d’utilisateur non valide</string>
|
||||||
<string name="login_failed">"Login failed"</string>
|
<string name="invalid_password">Mot de passe invalide</string>
|
||||||
|
<string name="login_failed">"Erreur de connexion !"</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue