Add Info Page

This commit is contained in:
Mathieu Sanchez 2020-04-14 16:44:17 +02:00
parent 02b3c53a0a
commit dd91303137
23 changed files with 496 additions and 76 deletions

View File

@ -26,6 +26,10 @@ android {
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
applicationVariants.all { variant ->
variant.resValue "string", "versionName", variant.versionName
}
buildTypes { buildTypes {
release { release {
minifyEnabled false minifyEnabled false
@ -66,7 +70,11 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0'
kapt 'androidx.room:room-compiler:2.2.5' kapt 'androidx.room:room-compiler:2.2.5'
// kapt 'com.android.databinding:compiler:3.1.4' // PDF
implementation 'com.tom_roush:pdfbox-android:1.8.10.1'
// Gson
implementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.ext:junit:1.1.1'

View File

@ -1,5 +1,30 @@
package fr.sanchezm.attestationsCovid19.data.db package fr.sanchezm.attestationsCovid19.data.db
import android.content.Context
import fr.sanchezm.attestationsCovid19.data.db.dao.AttestationDao
import fr.sanchezm.attestationsCovid19.data.db.dao.ProfileDao
class MyDatabase private constructor(private val path: String) {
private val _profileDao: ProfileDao? = null
private val _attestationDao: AttestationDao? = null
fun profileDao() : ProfileDao = _profileDao ?: ProfileDao(path)
fun attestationDao() : AttestationDao = _attestationDao ?: AttestationDao(path)
companion object {
@Volatile
private var instance: MyDatabase? = null
private val LOCK = Any()
operator fun invoke(context: Context) = instance ?: synchronized(LOCK) {
instance ?: MyDatabase(context.filesDir.path).also { instance = it }
}
}
}
/*
import android.content.Context import android.content.Context
import androidx.room.Database import androidx.room.Database
import androidx.room.Room import androidx.room.Room
@ -33,4 +58,5 @@ abstract class MyDatabase private constructor() : RoomDatabase() {
) )
.build() .build()
} }
} }
*/

View File

@ -1,20 +1,14 @@
package fr.sanchezm.attestationsCovid19.data.db.dao package fr.sanchezm.attestationsCovid19.data.db.dao
import androidx.lifecycle.LiveData class AttestationDao(private val path: String) {
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import fr.sanchezm.attestationsCovid19.data.db.entity.Attestation
import fr.sanchezm.attestationsCovid19.data.db.entity.CURRENT_ATTESTATION_ID
import fr.sanchezm.attestationsCovid19.data.db.entity.CURRENT_PROFILE_ID
import fr.sanchezm.attestationsCovid19.data.db.entity.Profile
@Dao }
interface AttestationDao {
@Insert
fun insert(attestation: Attestation)
@Query(value = "SELECT * FROM attestation WHERE id = $CURRENT_ATTESTATION_ID") //@Dao
fun getAttestation(): LiveData<Attestation> //interface AttestationDao {
} // @Insert
// fun insert(attestation: Attestation)
//
// @Query(value = "SELECT * FROM attestation WHERE id = $CURRENT_ATTESTATION_ID")
// fun getAttestation(): LiveData<Attestation>
//}

View File

@ -1,18 +1,46 @@
package fr.sanchezm.attestationsCovid19.data.db.dao package fr.sanchezm.attestationsCovid19.data.db.dao
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.room.Dao import androidx.lifecycle.MutableLiveData
import androidx.room.Insert import com.google.gson.Gson
import androidx.room.OnConflictStrategy
import androidx.room.Query
import fr.sanchezm.attestationsCovid19.data.db.entity.CURRENT_PROFILE_ID
import fr.sanchezm.attestationsCovid19.data.db.entity.Profile import fr.sanchezm.attestationsCovid19.data.db.entity.Profile
import java.io.File
@Dao class ProfileDao(private val path: String) {
interface ProfileDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(profile: Profile)
@Query(value = "SELECT * FROM profile WHERE id = $CURRENT_PROFILE_ID") private var _profile = MutableLiveData<Profile>()
fun getProfile(): LiveData<Profile> private var fileName = "profile.db"
}
fun getProfile(): LiveData<Profile> =
_profile
fun updateProfile(profile: Profile) {
_profile.value = profile
save()
}
init {
load()
}
private fun load() {
val file = File("$path/$fileName")
if (file.exists()) {
_profile.value = Gson().fromJson(file.readText(Charsets.UTF_8), Profile::class.java)
}
}
private fun save() {
File("$path/$fileName").writeText(Gson().toJson(this))
}
}
//@Dao
//interface ProfileDao {
// @Insert(onConflict = OnConflictStrategy.REPLACE)
// fun insert(profile: Profile)
//
// @Query(value = "SELECT * FROM profile WHERE id = $CURRENT_PROFILE_ID")
// fun getProfile(): LiveData<Profile>
//}

View File

@ -5,19 +5,23 @@ import fr.sanchezm.attestationsCovid19.data.db.dao.ProfileDao
import fr.sanchezm.attestationsCovid19.data.db.entity.Attestation import fr.sanchezm.attestationsCovid19.data.db.entity.Attestation
import fr.sanchezm.attestationsCovid19.data.db.entity.Profile import fr.sanchezm.attestationsCovid19.data.db.entity.Profile
class AttestationRepository private constructor(private val attestationDao: AttestationDao) { class AttestationRepository private constructor(/*private val attestationDao: AttestationDao*/) {
fun getProfile() = attestationDao.getAttestation() // fun getAttestation() = attestationDao.getAttestation()
fun insertProfile(attestation: Attestation) = attestationDao.insert(attestation) fun createAttestation() {
}
// fun insertAttestation(attestation: Attestation) = attestationDao.insert(attestation)
companion object { companion object {
@Volatile @Volatile
private var instance: AttestationRepository? = null private var instance: AttestationRepository? = null
fun getInstance(attestationDao: AttestationDao) = fun getInstance(/*attestationDao: AttestationDao*/) =
instance ?: synchronized(this) { instance ?: synchronized(this) {
instance ?: AttestationRepository(attestationDao).also { instance = it } // instance ?: AttestationRepository(attestationDao).also { instance = it }
instance ?: AttestationRepository().also { instance = it }
} }
} }
} }

View File

@ -1,21 +1,35 @@
package fr.sanchezm.attestationsCovid19.data.repository package fr.sanchezm.attestationsCovid19.data.repository
import fr.sanchezm.attestationsCovid19.data.db.dao.ProfileDao import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import fr.sanchezm.attestationsCovid19.data.db.entity.Profile import fr.sanchezm.attestationsCovid19.data.db.entity.Profile
class ProfileRepository private constructor(private val profileDao: ProfileDao) { class ProfileRepository private constructor(/*private val profileDao: ProfileDao*/) {
fun getProfile() = profileDao.getProfile() private var _profile = MutableLiveData(Profile(
"Mathieu",
"Sanchez",
"19/11/1997",
"Perpignan",
"33 Rue Salvador Dali",
"Canohes",
"66680"
))
fun insertProfile(profile: Profile) = profileDao.insert(profile) fun getProfile(): LiveData<Profile> = _profile
// fun insertProfile(profile: Profile) = profileDao.insert(profile)
fun insertProfile(profile: Profile) {
_profile.value = profile
}
companion object { companion object {
@Volatile @Volatile
private var instance: ProfileRepository? = null private var instance: ProfileRepository? = null
fun getInstance(profileDao: ProfileDao) = fun getInstance(/*profileDao: ProfileDao*/) =
instance ?: synchronized(this) { instance ?: synchronized(this) {
instance ?: ProfileRepository(profileDao).also { instance = it } instance ?: ProfileRepository(/*profileDao*/).also { instance = it }
} }
} }
} }

View File

@ -1,12 +1,15 @@
package fr.sanchezm.attestationsCovid19.ui.add package fr.sanchezm.attestationsCovid19.ui.add
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.databinding.DataBindingUtil import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.google.android.material.snackbar.Snackbar
import fr.sanchezm.attestationsCovid19.R import fr.sanchezm.attestationsCovid19.R
import fr.sanchezm.attestationsCovid19.databinding.FragmentAddAttestationBinding import fr.sanchezm.attestationsCovid19.databinding.FragmentAddAttestationBinding
import fr.sanchezm.attestationsCovid19.utilities.InjectorUtils import fr.sanchezm.attestationsCovid19.utilities.InjectorUtils
@ -31,14 +34,26 @@ class AddFragment : Fragment() {
this.viewModel = addViewModel this.viewModel = addViewModel
} }
bindMessage(binding.context)
return binding.root return binding.root
} }
private fun bindMessage(context: View) {
addViewModel.errorMessage.observe(viewLifecycleOwner, Observer {
it.getContentIfNotHandled()?.let { stringId ->
Snackbar.make(context, stringId, Snackbar.LENGTH_SHORT ).show()
}
});
}
private fun initializeUi() { private fun initializeUi() {
val factory = context?.let { InjectorUtils.provideAddViewModelFactory(it) } // val factory = context?.let { InjectorUtils.provideAddViewModelFactory(it) }
addViewModel = factory?.let { // addViewModel = factory?.let {
ViewModelProvider(this, it) // ViewModelProvider(this, it)
.get(AddViewModel::class.java) // .get(AddViewModel::class.java)
}!! // }!!
val factory = InjectorUtils.provideAddViewModelFactory()
addViewModel = ViewModelProvider(this, factory)
.get(AddViewModel::class.java)
} }
} }

View File

@ -2,12 +2,24 @@ package fr.sanchezm.attestationsCovid19.ui.add
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import fr.sanchezm.attestationsCovid19.R
import fr.sanchezm.attestationsCovid19.data.db.entity.Profile import fr.sanchezm.attestationsCovid19.data.db.entity.Profile
import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository
import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository
import fr.sanchezm.attestationsCovid19.utilities.Event
class AddViewModel(private val profileRepository: ProfileRepository) : ViewModel() { class AddViewModel(
private val profileRepository: ProfileRepository,
private val attestationRepository: AttestationRepository
) : ViewModel() {
private val _errorMessage = MutableLiveData<Event<Int>>()
val errorMessage: LiveData<Event<Int>>
get() = _errorMessage
val firstName = MutableLiveData<String>() val firstName = MutableLiveData<String>()
val lastName = MutableLiveData<String>() val lastName = MutableLiveData<String>()
@ -19,12 +31,22 @@ class AddViewModel(private val profileRepository: ProfileRepository) : ViewModel
val exitDate = MutableLiveData<String>() val exitDate = MutableLiveData<String>()
val exitHour = MutableLiveData<String>() val exitHour = MutableLiveData<String>()
val reason1 = MutableLiveData(false)
val reason2 = MutableLiveData(false)
val reason3 = MutableLiveData(false)
val reason4 = MutableLiveData(false)
val reason5 = MutableLiveData(false)
val reason6 = MutableLiveData(false)
val reason7 = MutableLiveData(false)
@SuppressLint("LongLogTag") @SuppressLint("LongLogTag")
fun onGenerateAttestationClick() { fun onGenerateAttestationClick() {
if (checkAllValue()) { if (checkAllValue()) {
profileRepository.insertProfile(getProfileFromView()) profileRepository.insertProfile(getProfileFromView())
attestationRepository.createAttestation()
} else { } else {
Log.e("onGenerateAttestationClick", "Cannot add profile") _errorMessage.value = Event(R.string.error_cannot_create_attestation)
Log.e("onGenerateAttestationClick", "Cannot generate Attestation")
} }
} }
@ -64,6 +86,19 @@ class AddViewModel(private val profileRepository: ProfileRepository) : ViewModel
&& !address.value.isNullOrEmpty() && !address.value.isNullOrEmpty()
&& !city.value.isNullOrEmpty() && !city.value.isNullOrEmpty()
&& !postalCode.value.isNullOrEmpty() && !postalCode.value.isNullOrEmpty()
&& !exitDate.value.isNullOrEmpty()
&& !exitHour.value.isNullOrEmpty()
&& checkAtLeastOneReasonSelected()
}
private fun checkAtLeastOneReasonSelected(): Boolean {
return reason1.value!!
|| reason2.value!!
|| reason3.value!!
|| reason4.value!!
|| reason5.value!!
|| reason6.value!!
|| reason7.value!!
} }
} }

View File

@ -2,13 +2,17 @@ package fr.sanchezm.attestationsCovid19.ui.add
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository
import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository
class AddViewModelFactory(private val profileRepository: ProfileRepository) : class AddViewModelFactory(
private val profileRepository: ProfileRepository,
private val attestationRepository: AttestationRepository
) :
ViewModelProvider.NewInstanceFactory() { ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T { override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return AddViewModel(profileRepository) as T return AddViewModel(profileRepository, attestationRepository) as T
} }
} }

View File

@ -23,7 +23,7 @@ class AttestationsFragment : Fragment() {
initializeUi() initializeUi()
val binding = DataBindingUtil.inflate<FragmentAttestationsBinding>( val binding = DataBindingUtil.inflate<FragmentAttestationsBinding>(
inflater, inflater,
R.layout.fragment_add_attestation, R.layout.fragment_attestations,
container, container,
false false
).apply { ).apply {
@ -35,10 +35,13 @@ class AttestationsFragment : Fragment() {
} }
private fun initializeUi() { private fun initializeUi() {
val factory = context?.let { InjectorUtils.provideAddViewModelFactory(it) } // val factory = context?.let { InjectorUtils.provideAttestationViewModel(it) }
attestationsViewModel = factory?.let { // attestationsViewModel = factory?.let {
ViewModelProvider(this, it) // ViewModelProvider(this, it)
.get(AttestationsViewModel::class.java) // .get(AttestationsViewModel::class.java)
}!! // }!!
val factory = InjectorUtils.provideAttestationViewModel()
attestationsViewModel = ViewModelProvider(this, factory)
.get(AttestationsViewModel::class.java)
} }
} }

View File

@ -1,14 +1,12 @@
package fr.sanchezm.attestationsCovid19.ui.attestations package fr.sanchezm.attestationsCovid19.ui.attestations
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository
class AttestationsViewModel(private val attestationRepository: AttestationRepository) : ViewModel() { class AttestationsViewModel(private val attestationRepository: AttestationRepository) : ViewModel() {
private val _text = MutableLiveData<String>().apply { // private val _text = MutableLiveData<String>().apply {
value = "This is dashboard Fragment" // value = "This is dashboard Fragment"
} // }
val text: LiveData<String> = _text // val text: LiveData<String> = _text
} }

View File

@ -0,0 +1,40 @@
package fr.sanchezm.attestationsCovid19.ui.info
import android.os.Bundle;
import android.text.method.LinkMovementMethod
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView
import androidx.fragment.app.Fragment
import fr.sanchezm.attestationsCovid19.BuildConfig
import fr.sanchezm.attestationsCovid19.R;
class InfoFragment : Fragment() {
override fun onCreateView(
inflater:LayoutInflater,
container:ViewGroup?,
savedInstanceState:Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_info, container, false)
root.findViewById<TextView>(R.id.develop_by).movementMethod = LinkMovementMethod.getInstance()
root.findViewById<TextView>(R.id.version).text = getVersionText()
return root
}
private fun getVersionText(): String {
val versionText = getString(R.string.version_number);
val versionName = BuildConfig.VERSION_NAME
return "$versionText $versionName"
}
}

View File

@ -0,0 +1,17 @@
package fr.sanchezm.attestationsCovid19.utilities
open class Event<out T>(private val content: T) {
var hasBeenHandled = false
private set
fun getContentIfNotHandled(): T? {
return if (hasBeenHandled) {
null
} else {
hasBeenHandled = true
content
}
}
fun peekContent(): T = content
}

View File

@ -5,20 +5,30 @@ import fr.sanchezm.attestationsCovid19.data.db.MyDatabase
import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository import fr.sanchezm.attestationsCovid19.data.repository.AttestationRepository
import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository import fr.sanchezm.attestationsCovid19.data.repository.ProfileRepository
import fr.sanchezm.attestationsCovid19.ui.add.AddViewModelFactory import fr.sanchezm.attestationsCovid19.ui.add.AddViewModelFactory
import fr.sanchezm.attestationsCovid19.ui.attestations.AttestationsViewModel import fr.sanchezm.attestationsCovid19.ui.attestations.AttestationsViewModelFactory
object InjectorUtils { object InjectorUtils {
fun provideAddViewModelFactory(context: Context): AddViewModelFactory { fun provideAddViewModelFactory(context: Context): AddViewModelFactory {
// val profileRepository =
// ProfileRepository.getInstance()
// val attestationRepository =
// AttestationRepository.getInstance()
val profileRepository = val profileRepository =
ProfileRepository.getInstance(MyDatabase.invoke(context).profileDao()) ProfileRepository.getInstance(MyDatabase.invoke(context).profileDao())
val attestationRepository =
AttestationRepository.getInstance(MyDatabase.invoke(context).attestationDao())
return AddViewModelFactory(profileRepository = profileRepository) return AddViewModelFactory(profileRepository, attestationRepository)
} }
fun provideAttestationViewModel(context: Context): AttestationsViewModel { fun provideAttestationViewModel(/*context: Context*/): AttestationsViewModelFactory {
val attestationRepository = AttestationRepository.getInstance(MyDatabase.invoke(context).attestationDao()) val attestationRepository =
return AttestationsViewModel(attestationRepository) AttestationRepository.getInstance()
// val attestationRepository =
// AttestationRepository.getInstance(MyDatabase.invoke(context).attestationDao())
return AttestationsViewModelFactory(attestationRepository)
} }
} }

View File

@ -0,0 +1,9 @@
<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,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z"/>
</vector>

View File

@ -0,0 +1,79 @@
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="30dp"
android:paddingVertical="20dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:layout_marginTop="15dp"
android:textStyle="bold"
android:textColor="?attr/colorPrimaryDark"
android:text="@string/title_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/explication_1"
android:text="@string/explication_1"
android:layout_marginTop="40dp"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<TextView
android:id="@+id/explication_2"
android:text="@string/explication_2"
style="@style/TextView"
android:justificationMode="inter_word"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_1" />
<TextView
android:id="@+id/explication_3"
android:text="@string/explication_3"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_2" />
<TextView
android:id="@+id/explication_4"
android:text="@string/explication_4"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_3" />
<TextView
android:id="@+id/develop_by"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="?attr/colorPrimaryDark"
android:text="@string/develop_by"
android:layout_marginBottom="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/version" />
<TextView
android:id="@+id/version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/version_number"
android:textSize="12sp"
android:textColor="?attr/colorAccent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -13,6 +13,7 @@
<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/context"
tools:context=".ui.add.AddFragment"> tools:context=".ui.add.AddFragment">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
@ -27,12 +28,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:paddingHorizontal="50dp" android:paddingHorizontal="30dp"
android:paddingVertical="20dp"> android:paddingVertical="20dp">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textStyle="bold"
android:text="@string/attestation_title" android:text="@string/attestation_title"
android:textColor="?attr/colorPrimary" android:textColor="?attr/colorPrimary"
android:textSize="25sp" /> android:textSize="25sp" />
@ -71,7 +73,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPersonName|textCapWords" android:inputType="textPersonName|textCapWords"
android:text="@{viewModel.lastName}" /> android:text="@={viewModel.lastName}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -86,7 +88,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="date" android:inputType="date"
android:text="@{viewModel.birthday}" /> android:text="@={viewModel.birthday}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -101,7 +103,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text|textCapWords" android:inputType="text|textCapWords"
android:text="@{viewModel.birthPlace}" /> android:text="@={viewModel.birthPlace}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -116,7 +118,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textPostalAddress|textCapWords" android:inputType="textPostalAddress|textCapWords"
android:text="@{viewModel.address}" /> android:text="@={viewModel.address}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -131,7 +133,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text|textCapWords" android:inputType="text|textCapWords"
android:text="@{viewModel.city}" /> android:text="@={viewModel.city}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -146,7 +148,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="text|textCapWords" android:inputType="text|textCapWords"
android:text="@{viewModel.postalCode}" /> android:text="@={viewModel.postalCode}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -161,7 +163,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="date" android:inputType="date"
android:text="@{viewModel.exitDate}" /> android:text="@={viewModel.exitDate}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -176,7 +178,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="time" android:inputType="time"
android:text="@{viewModel.exitHour}" /> android:text="@={viewModel.exitHour}" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
@ -193,6 +195,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason1}"
android:text="@string/reason_1" /> android:text="@string/reason_1" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -200,6 +203,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason2}"
android:text="@string/reason_2" /> android:text="@string/reason_2" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -207,6 +211,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason3}"
android:text="@string/reason_3" /> android:text="@string/reason_3" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -214,6 +219,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason4}"
android:text="@string/reason_4" /> android:text="@string/reason_4" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -221,6 +227,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason5}"
android:text="@string/reason_5" /> android:text="@string/reason_5" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -228,6 +235,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason6}"
android:text="@string/reason_6" /> android:text="@string/reason_6" />
<com.google.android.material.checkbox.MaterialCheckBox <com.google.android.material.checkbox.MaterialCheckBox
@ -235,6 +243,7 @@
style="@style/MaterialCheckBox" style="@style/MaterialCheckBox"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:checked="@={viewModel.reason7}"
android:text="@string/reason_7" /> android:text="@string/reason_7" />
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton

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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="30dp"
android:paddingVertical="20dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="30sp"
android:layout_marginTop="15dp"
android:textStyle="bold"
android:textColor="?attr/colorPrimaryDark"
android:text="@string/title_info"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/explication_1"
android:text="@string/explication_1"
android:layout_marginTop="40dp"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" />
<TextView
android:id="@+id/explication_2"
android:text="@string/explication_2"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_1" />
<TextView
android:id="@+id/explication_3"
android:text="@string/explication_3"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_2" />
<TextView
android:id="@+id/explication_4"
android:text="@string/explication_4"
style="@style/TextView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/explication_3" />
<TextView
android:id="@+id/develop_by"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="?attr/colorPrimaryDark"
android:text="@string/develop_by"
android:layout_marginBottom="5dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@+id/version" />
<TextView
android:id="@+id/version"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/version_number"
android:textSize="12sp"
android:textColor="?attr/colorAccent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -14,4 +14,10 @@
android:title="@string/title_attestations" android:title="@string/title_attestations"
app:itemBackground="?attr/itemBackground" /> app:itemBackground="?attr/itemBackground" />
<item
android:id="@+id/navigation_info"
android:icon="@drawable/ic_info_24dp"
android:title="@string/title_info"
app:itemBackground="?attr/itemBackground" />
</menu> </menu>

View File

@ -17,4 +17,10 @@
android:label="@string/title_attestations" android:label="@string/title_attestations"
tools:layout="@layout/fragment_attestations" /> tools:layout="@layout/fragment_attestations" />
<fragment
android:id="@+id/navigation_info"
android:name="fr.sanchezm.attestationsCovid19.ui.info.InfoFragment"
android:label="@string/title_info"
tools:layout="@layout/fragment_info" />
</navigation> </navigation>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TextView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">@dimen/margin20dp</item>
<item name="android:textColor">@color/colorPrimary</item>
<item name="android:textSize">@dimen/textSize18sp</item>
<item name="android:justificationMode">inter_word</item>
</style>
</resources>

View File

@ -2,10 +2,14 @@
<string name="app_name">Attestation de déplacement dérogatoire</string> <string name="app_name">Attestation de déplacement dérogatoire</string>
<string name="title_add">Nouvelle Attestation</string> <string name="title_add">Nouvelle Attestation</string>
<string name="title_attestations">Mes Attestations</string> <string name="title_attestations">Mes Attestations</string>
<string name="title_info">À Propos</string>
<!-- Attestation Fragment -->
<string name="attestation_title">Attestation de déplacement dérogatoire</string> <string name="attestation_title">Attestation de déplacement dérogatoire</string>
<string name="attestation_subtitle">#RestonsChezNous</string> <string name="attestation_subtitle">#RestonsChezNous</string>
<string name="error_cannot_create_attestation">Erreur lors de la génération de l\'attestation, tout les champs ne sont pas compléter</string>
<!-- Field for attestation -->
<string name="first_name">Prénom</string> <string name="first_name">Prénom</string>
<string name="last_name">Nom</string> <string name="last_name">Nom</string>
<string name="birthday">Date de naissance</string> <string name="birthday">Date de naissance</string>
@ -18,6 +22,7 @@
<string name="exit_hour">Heure de sortie</string> <string name="exit_hour">Heure de sortie</string>
<string name="generate_attestation_button">Générer l\'attestation</string> <string name="generate_attestation_button">Générer l\'attestation</string>
<!-- Reasons for leaving house -->
<string name="reason_1">Déplacements entre le domicile et le lieu dexercice de lactivité professionnelle, lorsqu\'ils sont indispensables à l\'exercice dactivités ne pouvant être organisées sous forme de télétravail ou déplacements professionnels ne pouvant être différés.</string> <string name="reason_1">Déplacements entre le domicile et le lieu dexercice de lactivité professionnelle, lorsqu\'ils sont indispensables à l\'exercice dactivités ne pouvant être organisées sous forme de télétravail ou déplacements professionnels ne pouvant être différés.</string>
<string name="reason_2">Déplacements pour effectuer des achats de fournitures nécessaires à lactivité professionnelle et des achats de première nécessité dans des établissements dont les activités demeurent autorisées</string> <string name="reason_2">Déplacements pour effectuer des achats de fournitures nécessaires à lactivité professionnelle et des achats de première nécessité dans des établissements dont les activités demeurent autorisées</string>
<string name="reason_3">Consultations et soins ne pouvant être assurés à distance et ne pouvant être différés ; consultations et soins des patients atteints d\'une affection de longue durée.</string> <string name="reason_3">Consultations et soins ne pouvant être assurés à distance et ne pouvant être différés ; consultations et soins des patients atteints d\'une affection de longue durée.</string>
@ -25,4 +30,13 @@
<string name="reason_5">Déplacements brefs, dans la limite d\'une heure quotidienne et dans un rayon maximal d\'un kilomètre autour du domicile, liés soit à l\'activité physique individuelle des personnes, à l\'exclusion de toute pratique sportive collective et de toute proximité avec d\'autres personnes, soit à la promenade avec les seules personnes regroupées dans un même domicile, soit aux besoins des animaux de compagnie.</string> <string name="reason_5">Déplacements brefs, dans la limite d\'une heure quotidienne et dans un rayon maximal d\'un kilomètre autour du domicile, liés soit à l\'activité physique individuelle des personnes, à l\'exclusion de toute pratique sportive collective et de toute proximité avec d\'autres personnes, soit à la promenade avec les seules personnes regroupées dans un même domicile, soit aux besoins des animaux de compagnie.</string>
<string name="reason_6">Convocation judiciaire ou administrative.</string> <string name="reason_6">Convocation judiciaire ou administrative.</string>
<string name="reason_7">Participation à des missions dintérêt général sur demande de lautorité administrative.</string> <string name="reason_7">Participation à des missions dintérêt général sur demande de lautorité administrative.</string>
<!-- Info Fragment -->
<string name="explication_1">- Merci de n\'utiliser l\'application quand cas de nécessité.</string>
<string name="explication_2">- Cette application n\'aura jamais de publicité.</string>
<string name="explication_3">- Toutes les données sont stockées uniquement sur votre téléphone, utilisable hors ligne.</string>
<string name="explication_4">- Application non gouvernementale ni officiel, développer par un étudiant.</string>
<string name="develop_by">"Développer avec ❤️ par
<a href="https://www.sanchezm.fr/">Mathieu Sanchez</a>"</string>
<string name="version_number">Version :</string>
</resources> </resources>

View File

@ -34,7 +34,17 @@
<item name="android:textColor">@color/colorAccent</item> <item name="android:textColor">@color/colorAccent</item>
</style> </style>
<style name="TextView" parent="Widget.MaterialComponents.TextView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginTop">@dimen/margin20dp</item>
<item name="android:textColor">@color/colorPrimary</item>
<item name="android:textSize">@dimen/textSize18sp</item>
</style>
<dimen name="textSize18sp">18sp</dimen>
<dimen name="textInputCornerRadius">20dp</dimen> <dimen name="textInputCornerRadius">20dp</dimen>
<dimen name="margin20dp">20dp</dimen>
<dimen name="margin5dp">5dp</dimen> <dimen name="margin5dp">5dp</dimen>
<dimen name="emptySize">0dp</dimen> <dimen name="emptySize">0dp</dimen>
</resources> </resources>