Deux nouveaux fragments.

This commit is contained in:
biloute02 2023-12-14 22:32:55 +01:00
parent fdee234200
commit 9f03838fba
31 changed files with 684 additions and 79 deletions

12
.gitignore vendored
View file

@ -1,15 +1,9 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
local.properties
.idea
.DS_Store
/build
/captures
build
.externalNativeBuild
.cxx
local.properties

3
.idea/.gitignore vendored
View file

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

View file

@ -1 +0,0 @@
Palto

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="jbr-17 (2)" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.0" />
</component>
</project>

View file

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -30,6 +30,9 @@ android {
jvmTarget = "1.8"
}
buildToolsVersion = "33.0.1"
buildFeatures {
viewBinding = true
}
}
dependencies {
@ -39,6 +42,11 @@ dependencies {
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.navigation:navigation-fragment-ktx:2.7.5")
implementation("androidx.navigation:navigation-ui-ktx:2.7.5")
implementation("androidx.annotation:annotation:1.7.0")
implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.6.2")
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
implementation("androidx.legacy:legacy-support-v4:1.0.0")
implementation("androidx.recyclerview:recyclerview:1.3.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

View file

@ -0,0 +1,61 @@
package com.example.palto
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.palto.placeholder.PlaceholderContent
/**
* A fragment representing a list of Items.
*/
class ItemFragment : Fragment() {
private var columnCount = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
columnCount = it.getInt(ARG_COLUMN_COUNT)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_item_list, container, false)
// Set the adapter
if (view is RecyclerView) {
with(view) {
layoutManager = when {
columnCount <= 1 -> LinearLayoutManager(context)
else -> GridLayoutManager(context, columnCount)
}
adapter = MyItemRecyclerViewAdapter(PlaceholderContent.ITEMS)
}
}
return view
}
companion object {
// TODO: Customize parameter argument names
const val ARG_COLUMN_COUNT = "column-count"
// TODO: Customize parameter initialization
@JvmStatic
fun newInstance(columnCount: Int) =
ItemFragment().apply {
arguments = Bundle().apply {
putInt(ARG_COLUMN_COUNT, columnCount)
}
}
}
}

View file

@ -0,0 +1,49 @@
package com.example.palto
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.example.palto.placeholder.PlaceholderContent.PlaceholderItem
import com.example.palto.databinding.FragmentItemBinding
/**
* [RecyclerView.Adapter] that can display a [PlaceholderItem].
* TODO: Replace the implementation with code for your data type.
*/
class MyItemRecyclerViewAdapter(
private val values: List<PlaceholderItem>
) : RecyclerView.Adapter<MyItemRecyclerViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
FragmentItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val item = values[position]
holder.idView.text = item.id
holder.contentView.text = item.content
}
override fun getItemCount(): Int = values.size
inner class ViewHolder(binding: FragmentItemBinding) : RecyclerView.ViewHolder(binding.root) {
val idView: TextView = binding.itemNumber
val contentView: TextView = binding.content
override fun toString(): String {
return super.toString() + " '" + contentView.text + "'"
}
}
}

View file

@ -1,18 +1,21 @@
package com.example.palto
import android.app.Activity
import android.nfc.NfcAdapter
import android.nfc.Tag
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import java.net.URL
class PaltoActivity : AppCompatActivity() {
private var nfcAdapter: NfcAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
setContentView(R.layout.activity_palto)
// get the NFC Adapter
this.nfcAdapter = NfcAdapter.getDefaultAdapter(this)
@ -27,6 +30,12 @@ class PaltoActivity : AppCompatActivity() {
if (!(this.nfcAdapter!!.isEnabled)) {
Log.w("NFC", "NFC is not enabled")
}
// TEST
/*
val url = URL("https://www.faraphel.fr/palto/api/auth/token/")
val connection = url.openConnection()
val auth_data = Json.decodeFromString(connection.content)*/
}
override fun onResume() {

View file

@ -0,0 +1,24 @@
package com.example.palto.data
import com.example.palto.data.model.LoggedInUser
import java.io.IOException
/**
* Class that handles authentication w/ login credentials and retrieves user information.
*/
class LoginDataSource {
fun login(username: String, password: String): Result<LoggedInUser> {
try {
// TODO: handle loggedInUser authentication
val fakeUser = LoggedInUser(java.util.UUID.randomUUID().toString(), "Jane Doe")
return Result.Success(fakeUser)
} catch (e: Throwable) {
return Result.Error(IOException("Error logging in", e))
}
}
fun logout() {
// TODO: revoke authentication
}
}

View file

@ -0,0 +1,46 @@
package com.example.palto.data
import com.example.palto.data.model.LoggedInUser
/**
* 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 LoginRepository(val dataSource: LoginDataSource) {
// in-memory cache of the loggedInUser object
var user: LoggedInUser? = 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
user = null
}
fun logout() {
user = null
dataSource.logout()
}
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 setLoggedInUser(loggedInUser: LoggedInUser) {
this.user = loggedInUser
// If user credentials will be cached in local storage, it is recommended it be encrypted
// @see https://developer.android.com/training/articles/keystore
}
}

View file

@ -0,0 +1,18 @@
package com.example.palto.data
/**
* A generic class that holds a value with its loading status.
* @param <T>
*/
sealed class Result<out T : Any> {
data class Success<out T : Any>(val data: T) : Result<T>()
data class Error(val exception: Exception) : Result<Nothing>()
override fun toString(): String {
return when (this) {
is Success<*> -> "Success[data=$data]"
is Error -> "Error[exception=$exception]"
}
}
}

View file

@ -0,0 +1,9 @@
package com.example.palto.data.model
/**
* Data class that captures user information for logged in users retrieved from LoginRepository
*/
data class LoggedInUser(
val userId: String,
val displayName: String
)

View file

@ -0,0 +1,57 @@
package com.example.palto.placeholder
import java.util.ArrayList
import java.util.HashMap
/**
* Helper class for providing sample content for user interfaces created by
* Android template wizards.
*
* TODO: Replace all uses of this class before publishing your app.
*/
object PlaceholderContent {
/**
* An array of sample (placeholder) items.
*/
val ITEMS: MutableList<PlaceholderItem> = ArrayList()
/**
* A map of sample (placeholder) items, by ID.
*/
val ITEM_MAP: MutableMap<String, PlaceholderItem> = HashMap()
private val COUNT = 25
init {
// Add some sample items.
for (i in 1..COUNT) {
addItem(createPlaceholderItem(i))
}
}
private fun addItem(item: PlaceholderItem) {
ITEMS.add(item)
ITEM_MAP.put(item.id, item)
}
private fun createPlaceholderItem(position: Int): PlaceholderItem {
return PlaceholderItem(position.toString(), "Item " + position, makeDetails(position))
}
private fun makeDetails(position: Int): String {
val builder = StringBuilder()
builder.append("Details about Item: ").append(position)
for (i in 0..position - 1) {
builder.append("\nMore details information here.")
}
return builder.toString()
}
/**
* A placeholder item representing a piece of content.
*/
data class PlaceholderItem(val id: String, val content: String, val details: String) {
override fun toString(): String = content
}
}

View file

@ -0,0 +1,9 @@
package com.example.palto.ui.login
/**
* User details post authentication that is exposed to the UI
*/
data class LoggedInUserView(
val displayName: String
//... other data fields that may be accessible to the UI
)

View file

@ -0,0 +1,10 @@
package com.example.palto.ui.login
/**
* Data validation state of the login form.
*/
data class LoginFormState(
val usernameError: Int? = null,
val passwordError: Int? = null,
val isDataValid: Boolean = false
)

View file

@ -0,0 +1,131 @@
package com.example.palto.ui.login
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import android.widget.ProgressBar
import android.widget.Toast
import com.example.palto.databinding.FragmentLoginBinding
import com.example.palto.R
class LoginFragment : Fragment() {
private lateinit var loginViewModel: LoginViewModel
private var _binding: FragmentLoginBinding? = 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? {
_binding = FragmentLoginBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loginViewModel = ViewModelProvider(this, LoginViewModelFactory())
.get(LoginViewModel::class.java)
val usernameEditText = binding.username
val passwordEditText = binding.password
val loginButton = binding.login
val loadingProgressBar = binding.loading
loginViewModel.loginFormState.observe(viewLifecycleOwner,
Observer { loginFormState ->
if (loginFormState == null) {
return@Observer
}
loginButton.isEnabled = loginFormState.isDataValid
loginFormState.usernameError?.let {
usernameEditText.error = getString(it)
}
loginFormState.passwordError?.let {
passwordEditText.error = getString(it)
}
})
loginViewModel.loginResult.observe(viewLifecycleOwner,
Observer { loginResult ->
loginResult ?: return@Observer
loadingProgressBar.visibility = View.GONE
loginResult.error?.let {
showLoginFailed(it)
}
loginResult.success?.let {
updateUiWithUser(it)
}
})
val afterTextChangedListener = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// ignore
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
// ignore
}
override fun afterTextChanged(s: Editable) {
loginViewModel.loginDataChanged(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
}
}
usernameEditText.addTextChangedListener(afterTextChangedListener)
passwordEditText.addTextChangedListener(afterTextChangedListener)
passwordEditText.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
loginViewModel.login(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
}
false
}
loginButton.setOnClickListener {
loadingProgressBar.visibility = View.VISIBLE
loginViewModel.login(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
}
}
private fun updateUiWithUser(model: LoggedInUserView) {
val welcome = getString(R.string.welcome) + model.displayName
// TODO : initiate successful logged in experience
val appContext = context?.applicationContext ?: return
Toast.makeText(appContext, welcome, Toast.LENGTH_LONG).show()
}
private fun showLoginFailed(@StringRes errorString: Int) {
val appContext = context?.applicationContext ?: return
Toast.makeText(appContext, errorString, Toast.LENGTH_LONG).show()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -0,0 +1,9 @@
package com.example.palto.ui.login
/**
* Authentication result : success (user details) or error message.
*/
data class LoginResult(
val success: LoggedInUserView? = null,
val error: Int? = null
)

View file

@ -0,0 +1,55 @@
package com.example.palto.ui.login
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import android.util.Patterns
import com.example.palto.data.LoginRepository
import com.example.palto.data.Result
import com.example.palto.R
class LoginViewModel(private val loginRepository: LoginRepository) : ViewModel() {
private val _loginForm = MutableLiveData<LoginFormState>()
val loginFormState: LiveData<LoginFormState> = _loginForm
private val _loginResult = MutableLiveData<LoginResult>()
val loginResult: LiveData<LoginResult> = _loginResult
fun login(username: String, password: String) {
// can be launched in a separate asynchronous job
val result = loginRepository.login(username, password)
if (result is Result.Success) {
_loginResult.value =
LoginResult(success = LoggedInUserView(displayName = result.data.displayName))
} else {
_loginResult.value = LoginResult(error = R.string.login_failed)
}
}
fun loginDataChanged(username: String, password: String) {
if (!isUserNameValid(username)) {
_loginForm.value = LoginFormState(usernameError = R.string.invalid_username)
} else if (!isPasswordValid(password)) {
_loginForm.value = LoginFormState(passwordError = R.string.invalid_password)
} else {
_loginForm.value = LoginFormState(isDataValid = true)
}
}
// A placeholder username validation check
private fun isUserNameValid(username: String): Boolean {
return if (username.contains("@")) {
Patterns.EMAIL_ADDRESS.matcher(username).matches()
} else {
username.isNotBlank()
}
}
// A placeholder password validation check
private fun isPasswordValid(password: String): Boolean {
return password.length > 5
}
}

View file

@ -0,0 +1,25 @@
package com.example.palto.ui.login
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.example.palto.data.LoginDataSource
import com.example.palto.data.LoginRepository
/**
* ViewModel provider factory to instantiate LoginViewModel.
* Required given LoginViewModel has a non-empty constructor
*/
class LoginViewModelFactory : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
return LoginViewModel(
loginRepository = LoginRepository(
dataSource = LoginDataSource()
)
) as T
}
throw IllegalArgumentException("Unknown ViewModel class")
}
}

View file

@ -1,19 +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=".PaltoActivity">
<TextView
android:id="@+id/test_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,6 +1,19 @@
<?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">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/item_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
<TextView
android:id="@+id/content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:textAppearance="?attr/textAppearanceListItem" />
</LinearLayout>

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView 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:id="@+id/list"
android:name="com.example.palto.ItemFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
app:layoutManager="LinearLayoutManager"
tools:context=".ItemFragment"
tools:listitem="@layout/fragment_item" />

View file

@ -0,0 +1,78 @@
<?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:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/fragment_horizontal_margin"
android:paddingTop="@dimen/fragment_vertical_margin"
android:paddingRight="@dimen/fragment_horizontal_margin"
android:paddingBottom="@dimen/fragment_vertical_margin"
tools:context=".ui.login.LoginFragment">
<EditText
android:id="@+id/username"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="96dp"
android:layout_marginEnd="24dp"
android:autofillHints="@string/prompt_email"
android:hint="@string/prompt_email"
android:inputType="textEmailAddress"
android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="24dp"
android:autofillHints="@string/prompt_password"
android:hint="@string/prompt_password"
android:imeActionLabel="@string/action_sign_in_short"
android:imeOptions="actionDone"
android:inputType="textPassword"
android:selectAllOnFocus="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/username" />
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="start"
android:layout_marginStart="48dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="48dp"
android:layout_marginBottom="64dp"
android:enabled="false"
android:text="@string/action_sign_in"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/password"
app:layout_constraintVertical_bias="0.2" />
<ProgressBar
android:id="@+id/loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginStart="32dp"
android:layout_marginTop="64dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="64dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/password"
app:layout_constraintStart_toStartOf="@+id/password"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.3" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -2,4 +2,24 @@
<navigation 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:id="@+id/nav_graph" />
android:id="@+id/nav_graph"
app:startDestination="@id/loginFragment">
<fragment
android:id="@+id/loginFragment"
android:name="com.example.palto.ui.login.LoginFragment"
android:label="fragment_login"
tools:layout="@layout/fragment_login" >
<action
android:id="@+id/action_loginFragment_to_itemFragment"
app:destination="@id/itemFragment"
app:enterAnim="@android:anim/slide_in_left"
app:exitAnim="@android:anim/slide_in_left"
app:popEnterAnim="@android:anim/slide_in_left"
app:popExitAnim="@android:anim/slide_in_left" />
</fragment>
<fragment
android:id="@+id/itemFragment"
android:name="com.example.palto.ItemFragment"
android:label="fragment_item_list"
tools:layout="@layout/fragment_item_list" />
</navigation>

View file

@ -0,0 +1,6 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="fragment_horizontal_margin">16dp</dimen>
<dimen name="fragment_vertical_margin">16dp</dimen>
<dimen name="text_margin">16dp</dimen>
</resources>

View file

@ -1,3 +1,12 @@
<resources>
<string name="app_name">Palto</string>
<!-- Strings related to login -->
<string name="prompt_email">Email</string>
<string name="prompt_password">Password</string>
<string name="action_sign_in">Sign in or register</string>
<string name="action_sign_in_short">Sign in</string>
<string name="welcome">"Welcome!"</string>
<string name="invalid_username">Not a valid username</string>
<string name="invalid_password">Password must be >5 characters</string>
<string name="login_failed">"Login failed"</string>
</resources>