feat: Very basic day view with the day's events

This commit is contained in:
Peter Vacho 2024-12-30 14:40:50 +01:00
parent 0b6546c269
commit 5620bd4277
Signed by: school
GPG key ID: 8CFC3837052871B4
10 changed files with 167 additions and 8 deletions

View file

@ -1,6 +1,7 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
id("kotlin-parcelize")
}
android {

View file

@ -16,6 +16,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.NeatCalendar"
tools:targetApi="31">
<activity
android:name=".activities.DayViewActivity"
android:exported="false" />
<activity
android:name=".activities.CalendarActivity"
android:exported="false" />

View file

@ -2,6 +2,7 @@ package com.p_vacho.neat_calendar.activities
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.widget.ImageButton
import android.widget.TextView
import androidx.activity.enableEdgeToEdge
@ -140,11 +141,12 @@ class CalendarActivity : AppCompatActivity() {
// Add the actual days of the current month
for (i in 1..daysInMonth) {
val eventsForDay = eventsByDay[i] ?: emptyList()
days.add(CalendarDay(dayNumber = i.toString(), hasEvents = eventsForDay.isNotEmpty())) }
days.add(CalendarDay(dayNumber = i.toString(), eventsForDay))
}
// Set up RecyclerView
rvCalendar.layoutManager = GridLayoutManager(this@CalendarActivity, 7) // 7 columns for days of the week
rvCalendar.adapter = CalendarAdapter(days)
rvCalendar.adapter = CalendarAdapter(days) { day -> navigateToDayActivity(day) }
}
}
@ -155,4 +157,21 @@ class CalendarActivity : AppCompatActivity() {
finish() // Close the login screen
}
private fun navigateToDayActivity(day: CalendarDay) {
// TODO: Handle the placeholder days in a better way, using an empty string
// feels very odd.
if (day.dayNumber.isEmpty()) {
Log.w("Calendar", "User clicked on placeholder value")
return
}
var intent = Intent(this, DayViewActivity::class.java)
intent.putParcelableArrayListExtra(
"events", ArrayList(day.events)
)
val formattedDate = currentYearMonth.atDay(day.dayNumber.toInt()).toString()
intent.putExtra("date", formattedDate)
startActivity(intent)
// Don't finish the current activity, we want to be able to go back here
}
}

View file

@ -0,0 +1,43 @@
package com.p_vacho.neat_calendar.activities
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.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.p_vacho.neat_calendar.R
import com.p_vacho.neat_calendar.adapters.EventAdapter
import com.p_vacho.neat_calendar.api.models.EventResponse
class DayViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_day_view)
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
}
val date = intent.getStringExtra("date")!!
// The getParcelableArrayListExtra wants the class as a second argument to
// be more type-safe, but this is only supported since api 33, which is over
// our min api version, so we can ignore this deprecation for now.
@Suppress("DEPRECATION")
val events = intent.getParcelableArrayListExtra<EventResponse>("events")!!
val tvDate: TextView = findViewById(R.id.tvDate)
val rvEvents: RecyclerView = findViewById(R.id.rvEvents)
// Set up UI
tvDate.text = date
rvEvents.layoutManager = LinearLayoutManager(this)
rvEvents.adapter = EventAdapter(events)
}
}

View file

@ -8,7 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.p_vacho.neat_calendar.R
import com.p_vacho.neat_calendar.models.CalendarDay
class CalendarAdapter(private val days: List<CalendarDay>) :
class CalendarAdapter(private val days: List<CalendarDay>, private val onDayClicked: (CalendarDay) -> Unit) :
RecyclerView.Adapter<CalendarAdapter.DayViewHolder>() {
class DayViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
@ -28,11 +28,16 @@ class CalendarAdapter(private val days: List<CalendarDay>) :
holder.tvDay.text = day.dayNumber
// Visually indicate days with events
if (day.hasEvents) {
if (day.events.isNotEmpty()) {
holder.tvDay.setBackgroundResource(R.drawable.event_indicator_background)
} else {
holder.tvDay.setBackgroundResource(android.R.color.transparent)
}
// Trigger the click listener with the clicked day
holder.itemView.setOnClickListener {
onDayClicked(day)
}
}
override fun getItemCount(): Int = days.size

View file

@ -0,0 +1,32 @@
package com.p_vacho.neat_calendar.adapters
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.p_vacho.neat_calendar.R
import com.p_vacho.neat_calendar.api.models.EventResponse
class EventAdapter(private val events: List<EventResponse>) :
RecyclerView.Adapter<EventAdapter.EventViewHolder>() {
class EventViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val tvTitle: TextView = itemView.findViewById(R.id.tvTitle)
val tvDescription: TextView = itemView.findViewById(R.id.tvDescription)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EventViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_event, parent, false)
return EventViewHolder(view)
}
override fun onBindViewHolder(holder: EventViewHolder, position: Int) {
val event = events[position]
holder.tvTitle.text = event.title
holder.tvDescription.text = event.description
}
override fun getItemCount(): Int = events.size
}

View file

@ -1,7 +1,10 @@
package com.p_vacho.neat_calendar.api.models
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import java.time.OffsetDateTime
@Parcelize
data class EventResponse(
val id: String,
val title: String,
@ -13,4 +16,4 @@ data class EventResponse(
val owner_user_id: String,
val attendee_ids: List<String>,
val created_at: OffsetDateTime
)
): Parcelable

View file

@ -1,6 +1,11 @@
package com.p_vacho.neat_calendar.models
import android.os.Parcelable
import com.p_vacho.neat_calendar.api.models.EventResponse
import kotlinx.parcelize.Parcelize
@Parcelize
data class CalendarDay(
val dayNumber: String, // Day of the month (e.g., "1", "2", ...)
val hasEvents: Boolean = false
)
val dayNumber: String,
val events: List<EventResponse> = emptyList() // Add this property
): Parcelable

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".activities.DayViewActivity">
<TextView
android:id="@+id/tvDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp"
android:textStyle="bold"
android:layout_gravity="center"
tools:text="2025-01-01"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rvEvents"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">
<TextView
android:id="@+id/tvTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold" />
<TextView
android:id="@+id/tvDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:paddingTop="4dp" />
</LinearLayout>