diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e8b8e562f435e54068d380049311cd84d97bc715..e67137529512eb78e394877497f482cdde5a3e29 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <application + android:name=".App" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" @@ -16,8 +17,13 @@ <activity android:name=".network.AuthentificationActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> + <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.LAUNCHER" /> + <category android:name="android.intent.category.BROWSABLE" /> + <data android:scheme="https" + android:host="android-tasks-api.herokuapp.com" + android:pathPrefix="/api-docs/index.html"/> </intent-filter> </activity> <activity android:name=".userInfo.UserInfoActivity" /> diff --git a/app/src/main/java/com/clemhaowen/dm_td2/App.kt b/app/src/main/java/com/clemhaowen/dm_td2/App.kt new file mode 100644 index 0000000000000000000000000000000000000000..b9d95dee7db5b2ca602ea8791ea7d0592edd7ba2 --- /dev/null +++ b/app/src/main/java/com/clemhaowen/dm_td2/App.kt @@ -0,0 +1,11 @@ +package com.clemhaowen.dm_td2 + +import android.app.Application +import com.clemhaowen.dm_td2.network.Api + +class App: Application() { + override fun onCreate() { + super.onCreate() + Api.Companion.INSTANCE = com.clemhaowen.dm_td2.network.Api(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/clemhaowen/dm_td2/network/Api.kt b/app/src/main/java/com/clemhaowen/dm_td2/network/Api.kt index 9164760442a7b0cb7315d378d89b6efbe1103fa4..9d7171f5fc057d6a85f1e31aabb09a2e9ae016ec 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/network/Api.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/network/Api.kt @@ -1,15 +1,25 @@ package com.clemhaowen.dm_td2.network +import android.content.Context +import androidx.preference.PreferenceManager import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory import kotlinx.serialization.json.Json import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import retrofit2.Retrofit -object Api { +class Api(private val context: Context) { + // constantes qui serviront à faire les requêtes - private const val BASE_URL = "https://android-tasks-api.herokuapp.com/api/" - private const val TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyOTAsImV4cCI6MTYzODg4NTIyMX0.NSGoVvI5U18v4xMHB-_SDFArkT-Exz8S-aXp1ptqNb4" + companion object { + private const val BASE_URL = "https://android-tasks-api.herokuapp.com/api/" + //private const val TOKEN = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyOTAsImV4cCI6MTYzODg4NTIyMX0.NSGoVvI5U18v4xMHB-_SDFArkT-Exz8S-aXp1ptqNb4" + lateinit var INSTANCE: Api + } + + private fun getToken() : String { + return PreferenceManager.getDefaultSharedPreferences(context).getString(SHARED_PREF_TOKEN_KEY, "")!! + } // on construit une instance de parseur de JSON: private val jsonSerializer = Json { @@ -27,7 +37,7 @@ object Api { .addInterceptor { chain -> // intercepteur qui ajoute le `header` d'authentification avec votre token: val newRequest = chain.request().newBuilder() - .addHeader("Authorization", "Bearer $TOKEN") + .addHeader("Authorization", "Bearer ${getToken()}") .build() chain.proceed(newRequest) } diff --git a/app/src/main/java/com/clemhaowen/dm_td2/network/LoginFragment.kt b/app/src/main/java/com/clemhaowen/dm_td2/network/LoginFragment.kt index 047aed804a6c8d44fc76efccf811bd53eb1306a0..68ce4bd1c7752581c9250d14acc10fe4e7ae4c54 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/network/LoginFragment.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/network/LoginFragment.kt @@ -11,13 +11,14 @@ import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.edit import androidx.lifecycle.lifecycleScope +import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import com.clemhaowen.dm_td2.R import com.clemhaowen.dm_td2.network.LoginForm import kotlinx.coroutines.launch class LoginFragment : Fragment() { - private val userService = Api.userService + private val userService = Api.INSTANCE.userService override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -40,36 +41,16 @@ class LoginFragment : Fragment() { PreferenceManager.getDefaultSharedPreferences(context).edit { putString(SHARED_PREF_TOKEN_KEY, loginResponse.body()?.token) } - AlertDialog.Builder(context!!).apply { - setMessage("Logged in.") - setPositiveButton("OK") { _, _ -> - } - setCancelable(true) - show() - } + findNavController().navigate(R.id.action_loginFragment_to_taskListFragment) } else{ Toast.makeText(context, "Your email or password is incorrect.\nIf you don't have an account please sign up first.", Toast.LENGTH_LONG).show() - AlertDialog.Builder(context!!).apply { - setMessage("Your email or password is incorrect.\n" + - "If you don't have an account please sign up first.") - setPositiveButton("OK") { _, _ -> - } - setCancelable(true) - show() - } } } } else { - AlertDialog.Builder(context!!).apply { - setMessage("Please fill in the 2 blanks.") - setPositiveButton("OK") { _, _ -> - } - setCancelable(true) - show() - } + Toast.makeText(context, "Please fill in the 2 blanks.", Toast.LENGTH_LONG).show() } } } diff --git a/app/src/main/java/com/clemhaowen/dm_td2/network/TasksRepository.kt b/app/src/main/java/com/clemhaowen/dm_td2/network/TasksRepository.kt index 5ae8a5329bbaa22017cdec6ef974e18d22e0f213..ed6f1341868f5cf8d459423224c002761a69b3c2 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/network/TasksRepository.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/network/TasksRepository.kt @@ -7,7 +7,7 @@ import retrofit2.http.Body import retrofit2.http.Path class TasksRepository { - private val tasksWebService = Api.tasksWebService + private val tasksWebService = Api.INSTANCE.tasksWebService // Ces deux variables encapsulent la même donnée: // [_taskList] est modifiable mais privée donc inaccessible à l'extérieur de cette classe diff --git a/app/src/main/java/com/clemhaowen/dm_td2/task/TaskActivity.kt b/app/src/main/java/com/clemhaowen/dm_td2/task/TaskActivity.kt index cb945c986a04160d72bb204f9e78cb1c79b93f45..0d495183789d4443e5c5373fa76ea54b0e21c368 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/task/TaskActivity.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/task/TaskActivity.kt @@ -18,7 +18,6 @@ class TaskActivity : AppCompatActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_task) val createButton = findViewById<Button>(R.id.button) - var resultCode = 666 val titleEditText = findViewById<EditText>(R.id.titleEditText) val descriptionEditText = findViewById<EditText>(R.id.descriptionEditText) //val serializableExtra = intent?.getSerializableExtra("editTask") @@ -29,7 +28,7 @@ class TaskActivity : AppCompatActivity() { var newTask = Task(id = task?.id ?: java.util.UUID.randomUUID().toString(), title = titleEditText.text.toString(), description = descriptionEditText.text.toString()) intent.putExtra("newTask", newTask) - setResult(resultCode, intent) + setResult(200, intent) TASK_KEY = "newTask" finish() } diff --git a/app/src/main/java/com/clemhaowen/dm_td2/task/TaskFragment.kt b/app/src/main/java/com/clemhaowen/dm_td2/task/TaskFragment.kt new file mode 100644 index 0000000000000000000000000000000000000000..6fbdf6151b4b6428731885ac9f80dd7f56383749 --- /dev/null +++ b/app/src/main/java/com/clemhaowen/dm_td2/task/TaskFragment.kt @@ -0,0 +1,57 @@ +package com.clemhaowen.dm_td2.task + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Button +import android.widget.EditText +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs +import com.clemhaowen.dm_td2.R +import com.clemhaowen.dm_td2.tasklist.Task +import com.clemhaowen.dm_td2.tasklist.TaskListViewModel + + +class TaskFragment : Fragment() { + // On récupère une instance de ViewModel + private val viewModel: TaskListViewModel by activityViewModels() + val args : TaskFragmentArgs by navArgs() + + companion object { + var TASK_KEY = "" + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_task, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + val createButton = view.findViewById<Button>(R.id.fragmentButton) + val titleEditText = view.findViewById<EditText>(R.id.fragmentTitleEditText) + val descriptionEditText = view.findViewById<EditText>(R.id.fragmentDescriptionEditText) + + val task = args.editTask + titleEditText.setText(task?.title) + descriptionEditText.setText(task?.description) + createButton.setOnClickListener{ + var newTask = Task(id = task?.id ?: java.util.UUID.randomUUID().toString(), title = titleEditText.text.toString(), description = descriptionEditText.text.toString()) + if (task == null) { + viewModel.addTask(newTask) + } + else { + viewModel.editTask(newTask) + } + findNavController().popBackStack() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/clemhaowen/dm_td2/tasklist/TaskListFragment.kt b/app/src/main/java/com/clemhaowen/dm_td2/tasklist/TaskListFragment.kt index b5c50ef6fba77da136ec3c9d91827b9e121457ba..cfddda3c356fea073add84193bcb61ba5ff03000 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/tasklist/TaskListFragment.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/tasklist/TaskListFragment.kt @@ -8,10 +8,14 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope import androidx.lifecycle.observe +import androidx.navigation.fragment.findNavController +import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import coil.load @@ -21,13 +25,14 @@ import com.clemhaowen.dm_td2.R import com.clemhaowen.dm_td2.network.Api import com.clemhaowen.dm_td2.network.TasksRepository import com.clemhaowen.dm_td2.task.TaskActivity +import com.clemhaowen.dm_td2.task.TaskFragment +import com.clemhaowen.dm_td2.task.TaskFragmentArgs import com.clemhaowen.dm_td2.userInfo.UserInfoActivity import com.google.android.material.floatingactionbutton.FloatingActionButton import kotlinx.coroutines.launch import java.util.* class TaskListFragment : Fragment() { - //private var taskList = mutableListOf("Task 1", "Task 2", "Task 3") /*private val taskList = mutableListOf( @@ -40,7 +45,7 @@ class TaskListFragment : Fragment() { val taskListAdapter = TaskListAdapter() // On récupère une instance de ViewModel - private val viewModel: TaskListViewModel by viewModels() + private val viewModel: TaskListViewModel by activityViewModels() // TODO delete this line when refactoring is done. //private val tasksRepository = TasksRepository() @@ -76,15 +81,17 @@ class TaskListFragment : Fragment() { } (recyclerView?.adapter as TaskListAdapter).onEditClickListener = { task -> - val intent = Intent(activity, TaskActivity::class.java) + /*val intent = Intent(activity, TaskActivity::class.java) intent.putExtra("editTask", task) - startActivityForResult(intent, EDIT_TASK_REQUEST_CODE) + startActivityForResult(intent, EDIT_TASK_REQUEST_CODE)*/ /*val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ } startForResult.launch(intent)*/ - (recyclerView?.adapter as TaskListAdapter).notifyDataSetChanged() + val action = TaskListFragmentDirections.actionTaskListFragmentToTaskFragment(task) + findNavController().navigate(action) + //(recyclerView?.adapter as TaskListAdapter).notifyDataSetChanged() } // TODO comment this when refactoring is done. @@ -107,8 +114,9 @@ class TaskListFragment : Fragment() { val createButton = view.findViewById<FloatingActionButton>(R.id.floatingActionButton) createButton.setOnClickListener { - val intent = Intent(activity, TaskActivity::class.java) - startActivityForResult(intent, ADD_TASK_REQUEST_CODE) + /*val intent = Intent(activity, TaskActivity::class.java) + startActivityForResult(intent, ADD_TASK_REQUEST_CODE)*/ + findNavController().navigate(TaskListFragmentDirections.actionTaskListFragmentToTaskFragment()) //taskList.add(Task(id = UUID.randomUUID().toString(), title = "Task ${taskList.size + 1}")) (recyclerView?.adapter as TaskListAdapter).notifyDataSetChanged() } @@ -139,7 +147,7 @@ class TaskListFragment : Fragment() { override fun onResume() { super.onResume() lifecycleScope.launch { - val userInfoResponse = Api.userService.getInfo() + val userInfoResponse = Api.INSTANCE.userService.getInfo() if (userInfoResponse.isSuccessful) { val userInfo = userInfoResponse.body()!! val textView = view?.findViewById<TextView>(R.id.textViewInfo) diff --git a/app/src/main/java/com/clemhaowen/dm_td2/userInfo/UserInfoActivity.kt b/app/src/main/java/com/clemhaowen/dm_td2/userInfo/UserInfoActivity.kt index 93ace1b50c77f1c65537fe5c83b97471397b5c2c..6a519fe3ed99d9b9d7e03724679e731603aec818 100644 --- a/app/src/main/java/com/clemhaowen/dm_td2/userInfo/UserInfoActivity.kt +++ b/app/src/main/java/com/clemhaowen/dm_td2/userInfo/UserInfoActivity.kt @@ -28,7 +28,7 @@ import okhttp3.RequestBody.Companion.toRequestBody import java.io.File class UserInfoActivity : AppCompatActivity() { - private val userService = Api.userService + private val userService = Api.INSTANCE.userService // register private val pickInGallery = registerForActivityResult(ActivityResultContracts.GetContent()) { diff --git a/app/src/main/res/layout/fragment_task.xml b/app/src/main/res/layout/fragment_task.xml new file mode 100644 index 0000000000000000000000000000000000000000..edb92e9329fa76cef041514e10d9078b2903698a --- /dev/null +++ b/app/src/main/res/layout/fragment_task.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout 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=".task.TaskFragment" + android:orientation="vertical"> + + <EditText + android:id="@+id/fragmentTitleEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ems="10" + android:inputType="textPersonName" + android:textAlignment="center" + tools:text="@android:string/unknownName" /> + + <EditText + android:id="@+id/fragmentDescriptionEditText" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ems="10" + android:gravity="start|top" + android:inputType="textMultiLine" + tools:text="@android:string/unknownName" /> + + <Button + android:id="@+id/fragmentButton" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="Validate" /> +</LinearLayout> \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 08cd2b825bf3571ce51aad1a7cf2cbd128154171..4910873d51dec75179b999032a797a4e5ffa2d0d 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -17,15 +17,45 @@ <action android:id="@+id/action_authentificationFragment_to_signupFragment" app:destination="@id/signupFragment" /> + <deepLink + android:id="@+id/deepLink" + app:uri="https://android-tasks-api.herokuapp.com/api-docs/index.html" /> </fragment> <fragment android:id="@+id/loginFragment" android:name="com.clemhaowen.dm_td2.network.LoginFragment" android:label="fragment_login" - tools:layout="@layout/fragment_login" /> + tools:layout="@layout/fragment_login" > + <action + android:id="@+id/action_loginFragment_to_taskListFragment" + app:destination="@id/taskListFragment" /> + </fragment> <fragment android:id="@+id/signupFragment" android:name="com.clemhaowen.dm_td2.network.SignupFragment" android:label="fragment_signup" - tools:layout="@layout/fragment_signup" /> + tools:layout="@layout/fragment_signup" > + <action + android:id="@+id/action_signupFragment_to_taskListFragment" + app:destination="@id/taskListFragment" /> + </fragment> + <fragment + android:id="@+id/taskListFragment" + android:name="com.clemhaowen.dm_td2.tasklist.TaskListFragment" + android:label="TaskListFragment" > + <action + android:id="@+id/action_taskListFragment_to_taskFragment" + app:destination="@id/taskFragment" /> + </fragment> + <fragment + android:id="@+id/taskFragment" + android:name="com.clemhaowen.dm_td2.task.TaskFragment" + android:label="fragment_task" + tools:layout="@layout/fragment_task" > + <argument + android:name="editTask" + app:argType="com.clemhaowen.dm_td2.tasklist.Task" + app:nullable="true" + android:defaultValue="@null" /> + </fragment> </navigation> \ No newline at end of file