mirror of
https://github.com/a-mayb3/KanbanCloneAndroid.git
synced 2026-03-21 18:15:38 +01:00
Compare commits
No commits in common. "110f356d78691c40bef775ca6d6ecf3bddc88cd8" and "9c2703831327578add93fe7e8bc1883c1c354551" have entirely different histories.
110f356d78
...
9c27038313
15 changed files with 34 additions and 431 deletions
|
|
@ -51,7 +51,6 @@ dependencies {
|
||||||
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
|
||||||
implementation("com.auth0.android:jwtdecode:2.0.1")
|
implementation("com.auth0.android:jwtdecode:2.0.1")
|
||||||
implementation(libs.androidx.recyclerview)
|
|
||||||
|
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools" >
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
@ -14,19 +14,13 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.KanbanCloneAndroid"
|
android:theme="@style/Theme.KanbanCloneAndroid"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true" >
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.CreateProjectActivity"
|
android:name="com.campusaula.edbole.kanban_clone_android.LoginActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".ui.ProjectDetailActivity"
|
android:name="com.campusaula.edbole.kanban_clone_android.MainActivity"
|
||||||
android:exported="false" />
|
android:exported="true" >
|
||||||
<activity
|
|
||||||
android:name=".ui.LoginActivity"
|
|
||||||
android:exported="false" />
|
|
||||||
<activity
|
|
||||||
android:name=".ui.MainActivity"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,25 @@
|
||||||
package com.campusaula.edbole.kanban_clone_android.ui
|
package com.campusaula.edbole.kanban_clone_android
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.AppCompatButton
|
|
||||||
import androidx.appcompat.widget.AppCompatEditText
|
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.campusaula.edbole.kanban_clone_android.R
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.ApiService
|
import com.campusaula.edbole.kanban_clone_android.network.ApiService
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
|
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.ErrorResponse
|
import com.campusaula.edbole.kanban_clone_android.kanban.ErrorResponse
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.UserLogin
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import retrofit2.Retrofit
|
import retrofit2.Retrofit
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity() {
|
class LoginActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var emailInput : AppCompatEditText
|
private lateinit var emailInput : androidx.appcompat.widget.AppCompatEditText
|
||||||
private lateinit var passwordInput : AppCompatEditText
|
private lateinit var passwordInput : androidx.appcompat.widget.AppCompatEditText
|
||||||
|
|
||||||
private lateinit var loginButton : AppCompatButton
|
private lateinit var loginButton : androidx.appcompat.widget.AppCompatButton
|
||||||
private lateinit var logonButton : AppCompatButton
|
private lateinit var logonButton : androidx.appcompat.widget.AppCompatButton
|
||||||
|
|
||||||
private lateinit var retrofit : Retrofit
|
private lateinit var retrofit : Retrofit
|
||||||
private lateinit var api : ApiService
|
private lateinit var api : ApiService
|
||||||
|
|
@ -53,14 +47,14 @@ class LoginActivity : AppCompatActivity() {
|
||||||
val password = passwordInput.text.toString()
|
val password = passwordInput.text.toString()
|
||||||
|
|
||||||
if (email.isEmpty() && password.isEmpty()) {
|
if (email.isEmpty() && password.isEmpty()) {
|
||||||
Toast.makeText(this, "Please enter email and password", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this, "Please enter email and password", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
return@setOnClickListener
|
return@setOnClickListener
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch{
|
lifecycleScope.launch{
|
||||||
try {
|
try {
|
||||||
val loginResponse = api.login(
|
val loginResponse = api.login(
|
||||||
UserLogin(
|
com.campusaula.edbole.kanban_clone_android.kanban.UserLogin(
|
||||||
email = email,
|
email = email,
|
||||||
password = password
|
password = password
|
||||||
)
|
)
|
||||||
|
|
@ -73,14 +67,10 @@ class LoginActivity : AppCompatActivity() {
|
||||||
// Después del login exitoso OkHttp/CookieJar habrá guardado las cookies.
|
// Después del login exitoso OkHttp/CookieJar habrá guardado las cookies.
|
||||||
val authValue = RetrofitInstance.getAuthCookieForUrl(baseUrl)
|
val authValue = RetrofitInstance.getAuthCookieForUrl(baseUrl)
|
||||||
if (authValue != null) {
|
if (authValue != null) {
|
||||||
Toast.makeText(this@LoginActivity, "Auth cookie guardada", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this@LoginActivity, "Auth cookie guardada", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this@LoginActivity, "Login OK pero no se encontró cookie de auth", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this@LoginActivity, "Login OK pero no se encontró cookie de auth", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
// Navegar a MainActivity
|
|
||||||
val intent = Intent(this@LoginActivity, MainActivity::class.java)
|
|
||||||
startActivity(intent)
|
|
||||||
finish()
|
|
||||||
} else {
|
} else {
|
||||||
if (loginResponse.code() == 401) {
|
if (loginResponse.code() == 401) {
|
||||||
// parse error body if possible
|
// parse error body if possible
|
||||||
|
|
@ -95,14 +85,14 @@ class LoginActivity : AppCompatActivity() {
|
||||||
// clear stored cookies for base host
|
// clear stored cookies for base host
|
||||||
RetrofitInstance.clearCookiesForHost(baseHost)
|
RetrofitInstance.clearCookiesForHost(baseHost)
|
||||||
|
|
||||||
Toast.makeText(this@LoginActivity, "Login failed (401): $errMsg", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this@LoginActivity, "Login failed (401): $errMsg", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this@LoginActivity, "Login failed: ${loginResponse.code()}", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this@LoginActivity, "Login failed: ${loginResponse.code()}", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (ex: Exception){
|
} catch (ex: Exception){
|
||||||
Toast.makeText(this@LoginActivity, "Login failed: ${ex.message}", Toast.LENGTH_SHORT).show()
|
android.widget.Toast.makeText(this@LoginActivity, "Login failed: ${ex.message}", android.widget.Toast.LENGTH_SHORT).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,17 +1,16 @@
|
||||||
package com.campusaula.edbole.kanban_clone_android.ui
|
package com.campusaula.edbole.kanban_clone_android
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import com.campusaula.edbole.kanban_clone_android.R
|
|
||||||
|
|
||||||
class CreateProjectActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContentView(R.layout.activity_create_project)
|
setContentView(R.layout.activity_main)
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
||||||
|
|
@ -8,11 +8,6 @@ class Project{
|
||||||
val description: String = ""
|
val description: String = ""
|
||||||
val users: List<User> = emptyList()
|
val users: List<User> = emptyList()
|
||||||
val tasks: List<Task> = emptyList()
|
val tasks: List<Task> = emptyList()
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "Project(id=$id, name='$name', description='$description', users=$users, tasks=$tasks)"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ProjectBase(
|
data class ProjectBase(
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ interface ApiService {
|
||||||
@POST("auth/login/")
|
@POST("auth/login/")
|
||||||
suspend fun login(@Body userLogin: UserLogin): Response<LoginResponse>
|
suspend fun login(@Body userLogin: UserLogin): Response<LoginResponse>
|
||||||
|
|
||||||
@GET("me/logout/")
|
@POST("me/logout/")
|
||||||
suspend fun logout(): Response<Unit>
|
suspend fun logout(): Response<Unit>
|
||||||
|
|
||||||
@DELETE("me/delete-me/")
|
@DELETE("me/delete-me/")
|
||||||
|
|
|
||||||
|
|
@ -1,101 +0,0 @@
|
||||||
package com.campusaula.edbole.kanban_clone_android.ui
|
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.widget.Button
|
|
||||||
import android.widget.TextView
|
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.R
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.Project
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.ApiService
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
private lateinit var api: ApiService
|
|
||||||
private lateinit var projectList : List<Project>
|
|
||||||
|
|
||||||
private lateinit var loggedInAs: TextView
|
|
||||||
private lateinit var logoutButton: Button
|
|
||||||
private lateinit var addProjectActionButton: FloatingActionButton
|
|
||||||
private lateinit var projectsRecyclerView: RecyclerView
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
enableEdgeToEdge()
|
|
||||||
setContentView(R.layout.activity_main)
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
|
||||||
insets
|
|
||||||
}
|
|
||||||
|
|
||||||
api = RetrofitInstance.getRetrofit(applicationContext).create(ApiService::class.java)
|
|
||||||
projectList = emptyList()
|
|
||||||
|
|
||||||
/* Activity components */
|
|
||||||
loggedInAs = findViewById(R.id.loggedInAs)
|
|
||||||
logoutButton = findViewById(R.id.logoutButton)
|
|
||||||
addProjectActionButton = findViewById(R.id.addProjectActionButton)
|
|
||||||
projectsRecyclerView = findViewById(R.id.projectsRecyclerView)
|
|
||||||
projectsRecyclerView.layoutManager = androidx.recyclerview.widget.LinearLayoutManager(this)
|
|
||||||
val adapter = ProjectItemAdapter(projectList) { project ->
|
|
||||||
val intent = Intent(this, ProjectDetailActivity::class.java)
|
|
||||||
intent.putExtra("project_id", project.id)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
projectsRecyclerView.adapter = adapter
|
|
||||||
|
|
||||||
addProjectActionButton.setOnClickListener {
|
|
||||||
val intent = Intent(this, CreateProjectActivity::class.java)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Getting the logged-in user info */
|
|
||||||
lifecycleScope.launch{
|
|
||||||
|
|
||||||
val getMe = api.getMe()
|
|
||||||
if (getMe.isSuccessful){
|
|
||||||
val user = getMe.body()
|
|
||||||
loggedInAs.text = "Logged in as: ${user?.name}"
|
|
||||||
projectList = api.getAllProjects().body()!!
|
|
||||||
adapter.submitList(projectList)
|
|
||||||
} else {
|
|
||||||
val intent = Intent(this@MainActivity, LoginActivity::class.java)
|
|
||||||
startActivity(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
logoutButton.setOnClickListener {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val logoutResponse = api.logout()
|
|
||||||
if (logoutResponse.isSuccessful) {
|
|
||||||
// Clear cookies for the API host
|
|
||||||
RetrofitInstance.clearCookiesForHost(
|
|
||||||
"10.0.2.2:8000"
|
|
||||||
)
|
|
||||||
// Navigate back to the login screen
|
|
||||||
val intent =
|
|
||||||
Intent(this@MainActivity, LoginActivity::class.java)
|
|
||||||
startActivity(intent)
|
|
||||||
finish() // Optional: close the MainActivity so it's removed from the back stack
|
|
||||||
} else {
|
|
||||||
Toast.makeText(
|
|
||||||
this@MainActivity,
|
|
||||||
"Logout failed",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
package com.campusaula.edbole.kanban_clone_android.ui
|
|
||||||
|
|
||||||
import android.health.connect.datatypes.units.Percentage
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.util.Log
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.R
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.Project
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.Task
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.TaskStatus
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.ApiService
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.network.RetrofitInstance
|
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
class ProjectDetailActivity : AppCompatActivity() {
|
|
||||||
|
|
||||||
private lateinit var api: ApiService
|
|
||||||
|
|
||||||
private lateinit var projectTitleText : TextView
|
|
||||||
private lateinit var projectDescriptionText : TextView
|
|
||||||
private lateinit var completedPercentageText: TextView
|
|
||||||
private lateinit var returnActionButton: FloatingActionButton
|
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
|
||||||
super.onCreate(savedInstanceState)
|
|
||||||
enableEdgeToEdge()
|
|
||||||
setContentView(R.layout.activity_project_detail)
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
|
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
||||||
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
|
|
||||||
insets
|
|
||||||
}
|
|
||||||
api = RetrofitInstance.getRetrofit(applicationContext).create(ApiService::class.java)
|
|
||||||
projectTitleText = findViewById(R.id.projectTitleText)
|
|
||||||
projectDescriptionText = findViewById(R.id.projectDescriptionText)
|
|
||||||
completedPercentageText = findViewById(R.id.completedPercentageText)
|
|
||||||
returnActionButton = findViewById(R.id.returnActionButton)
|
|
||||||
returnActionButton.setOnClickListener { finish() }
|
|
||||||
|
|
||||||
val projectId : Int = intent.getIntExtra("project_id", -1)
|
|
||||||
|
|
||||||
if (projectId > 0) {
|
|
||||||
Log.d("ProjectDetailActivity", "Received project ID: $projectId")
|
|
||||||
lifecycleScope.launch {
|
|
||||||
try {
|
|
||||||
val projectResponse = api.getProjectById(projectId)
|
|
||||||
|
|
||||||
if (projectResponse.isSuccessful && projectResponse.body() != null) {
|
|
||||||
Log.d("ProjectDetailActivity", "Fetched project: ${projectResponse.body()!!.name}")
|
|
||||||
val project = projectResponse.body()!!
|
|
||||||
|
|
||||||
|
|
||||||
Log.d("ProjectDetailActivity", "Displaying project details for: $project")
|
|
||||||
|
|
||||||
projectTitleText.text = project.name
|
|
||||||
projectDescriptionText.text = project.description
|
|
||||||
|
|
||||||
var percentageFinished = 0.0;
|
|
||||||
val tasks: List<Task> = project.tasks
|
|
||||||
val totalTasks: Int = tasks.size
|
|
||||||
val perTaskPercentage = if (totalTasks > 0) (1.0 / totalTasks)*100 else 0.0
|
|
||||||
|
|
||||||
for (task in tasks) {
|
|
||||||
if (task.status == TaskStatus.COMPLETED) {
|
|
||||||
percentageFinished += perTaskPercentage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
completedPercentageText.text = "Completed: ${"%.2f".format(percentageFinished * 100)}%"
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
Log.e("ProjectDetailActivity", "Failed to fetch project: ${projectResponse.code()} - ${projectResponse.message()}")
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e("ProjectDetailActivity", "Error fetching project", e)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.e("ProjectDetailActivity", "No project ID found in intent")
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
package com.campusaula.edbole.kanban_clone_android.ui
|
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.R
|
|
||||||
import com.campusaula.edbole.kanban_clone_android.kanban.Project
|
|
||||||
|
|
||||||
class ProjectItemAdapter(
|
|
||||||
private var items: List<Project>,
|
|
||||||
private val onItemClick: ((Project) -> Unit)? = null
|
|
||||||
) : RecyclerView.Adapter<ProjectItemAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
fun submitList(newList: List<Project>) {
|
|
||||||
items = newList
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
val view = LayoutInflater.from(parent.context)
|
|
||||||
.inflate(R.layout.item_project, parent, false)
|
|
||||||
return ViewHolder(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val project = items[position]
|
|
||||||
holder.bind(project)
|
|
||||||
holder.itemView.setOnClickListener { onItemClick?.invoke(project) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
|
||||||
|
|
||||||
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
||||||
private val nameTv: TextView = itemView.findViewById(R.id.projectName)
|
|
||||||
private val descTv: TextView = itemView.findViewById(R.id.projectDescription)
|
|
||||||
|
|
||||||
fun bind(project: Project) {
|
|
||||||
nameTv.text = project.id.toString() + " " + project.name
|
|
||||||
descTv.text = project.description
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".ui.CreateProjectActivity">
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.campusaula.edbole.kanban_clone_android.ui.LoginActivity">
|
tools:context="com.campusaula.edbole.kanban_clone_android.LoginActivity">
|
||||||
|
|
||||||
<EditText
|
<EditText
|
||||||
android:layout_width="350dp"
|
android:layout_width="350dp"
|
||||||
|
|
|
||||||
|
|
@ -5,50 +5,15 @@
|
||||||
android:id="@+id/main"
|
android:id="@+id/main"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.campusaula.edbole.kanban_clone_android.ui.MainActivity">
|
tools:context="com.campusaula.edbole.kanban_clone_android.MainActivity">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="Logged in as: "
|
android:text="Hello World!"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
android:id="@+id/loggedInAs"
|
|
||||||
android:textAlignment="textStart"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintVertical_bias="0.0"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginStart="16dp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:text="Not you? Log out here..."
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="33dp"
|
|
||||||
android:id="@+id/logoutButton"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/loggedInAs"
|
|
||||||
app:layout_constraintStart_toStartOf="@+id/loggedInAs"
|
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
|
||||||
android:textSize="8sp" />
|
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
tools:layout_editor_absoluteX="1dp"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/logoutButton"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:id="@+id/projectsRecyclerView" />
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="true"
|
|
||||||
app:srcCompat="@android:drawable/ic_input_add"
|
|
||||||
android:id="@+id/addProjectActionButton"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:id="@+id/main"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".ui.ProjectDetailActivity">
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:clickable="true"
|
|
||||||
app:srcCompat="@android:drawable/ic_menu_revert"
|
|
||||||
android:id="@+id/returnActionButton"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:text="Project Name"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/projectTitleText"
|
|
||||||
android:padding="12dp"
|
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:textSize="24sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:text="Completed: 100%"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/completedPercentageText"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/projectTitleText"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:paddingRight="12dp"
|
|
||||||
android:paddingLeft="12dp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:id="@+id/projectDescriptionText"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/completedPercentageText"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.5"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
android:text="Project description"
|
|
||||||
android:padding="12dp" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -1,34 +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="wrap_content"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:layout_margin="8dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/projectName"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Project name"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/projectDescription"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="Project description"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:maxLines="2"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/projectName"
|
|
||||||
android:layout_marginTop="4dp" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
|
|
@ -10,7 +10,6 @@ activity = "1.12.2"
|
||||||
constraintlayout = "2.2.1"
|
constraintlayout = "2.2.1"
|
||||||
okhttp = "4.11.0"
|
okhttp = "4.11.0"
|
||||||
retrofit = "2.9.0"
|
retrofit = "2.9.0"
|
||||||
recyclerview = "1.4.0"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
|
@ -25,7 +24,6 @@ okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhtt
|
||||||
okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
|
okhttp-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp" }
|
||||||
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
||||||
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
|
retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit" }
|
||||||
androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version.ref = "recyclerview" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue