From 4b090e6918e1a3a69f11e50dedc610753df64f38 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Thu, 5 Sep 2024 20:08:12 +0300 Subject: [PATCH 01/23] add utils file --- .../MainActivity.kt | 121 +---------------- .../HijriDatePickerPlusApplication/Utils.kt | 123 ++++++++++++++++++ 2 files changed, 124 insertions(+), 120 deletions(-) create mode 100644 app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index 8d8e0df..4cab080 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -279,19 +279,7 @@ fun YearSelectionScreen( } } -// Helper function to get weekday name -fun getWeekday(islamicCalendar: IslamicCalendar): String { - return when (islamicCalendar.get(Calendar.DAY_OF_WEEK)) { - Calendar.SUNDAY -> "Sunday" - Calendar.MONDAY -> "Monday" - Calendar.TUESDAY -> "Tuesday" - Calendar.WEDNESDAY -> "Wednesday" - Calendar.THURSDAY -> "Thursday" - Calendar.FRIDAY -> "Friday" - Calendar.SATURDAY -> "Saturday" - else -> "" - } -} + @Composable fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> Unit) { @@ -320,42 +308,6 @@ fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> } -fun getHijriMonthAbbr(month: Int): String { - return when (month) { - 0 -> "MUH" - 1 -> "SAF" - 2 -> "RAB-I" - 3 -> "RAB-II" - 4 -> "JUM-I" - 5 -> "JUM-II" - 6 -> "RAJ" - 7 -> "SHA" - 8 -> "RAM" - 9 -> "SHAW" - 10 -> "DHU-Q" - 11 -> "DHU-H" - else -> "" - } -} - -fun getHijriMonthName(month: Int): String { - return when (month % 12) { // Handle month overflow - 0 -> "Muharram" - 1 -> "Safar" - 2 -> "Rabi' al-Awwal" - 3 -> "Rabi' al-Thani" - 4 -> "Jumada al-Awwal" - 5 -> "Jumada al-Thani" - 6 -> "Rajab" - 7 -> "Sha'ban" - 8 -> "Ramadan" - 9 -> "Shawwal" - 10 -> "Dhu al-Qi'dah" - 11 -> "Dhu al-Hijjah" - else -> "" - } -} - @Composable fun MonthGridWithDays( selectedYear: Int, @@ -423,77 +375,6 @@ fun MonthGridWithDays( } -fun getHijriDaysInMonth(year: Int, month: Int): Int { - return try { - val hijriCalendar = IslamicCalendar(year, month, 1) - hijriCalendar.add(Calendar.MONTH, 1) - hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) - hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) - hijriCalendar.get(Calendar.DAY_OF_MONTH) - } catch (e: Exception) { - 30 // Default to 30 days if there's an error - } -} - - -object HijriCalendarDataCache { - - // Cache days for each year separately, with each year holding month-to-days mapping - private val cachedYearlyMonthDays = mutableMapOf>() // Changed to store Int instead of List - - // Precompute all the months and their number of days for the given year - fun initializeForYear(year: Int) { - if (cachedYearlyMonthDays[year] == null) { - cachedYearlyMonthDays[year] = mutableMapOf() - for (month in 0..11) { - cachedYearlyMonthDays[year]?.set(month, getDaysInHijriMonth(year, month)) - } - } - } - - // Retrieve cached number of days for a given year and month, and calculate if not cached - fun getDaysForMonth(year: Int, month: Int): Int { - // Check if the year is cached - if (cachedYearlyMonthDays[year] == null) { - initializeForYear(year) // Initialize the year if not already cached - } - // Check if the month is cached - return cachedYearlyMonthDays[year]?.get(month) ?: getDaysInHijriMonth(year, month) - } - - // Compute the number of days in a Hijri month and cache it - private fun getDaysInHijriMonth(year: Int, month: Int): Int { - // Check if the year is already cached - if (cachedYearlyMonthDays[year] == null) { - cachedYearlyMonthDays[year] = mutableMapOf() // Initialize the map for this year if not present - } - - // Check if the month is already cached - val cachedDays = cachedYearlyMonthDays[year]?.get(month) - if (cachedDays != null) { - return cachedDays // Return cached number of days if available - } - - // If not cached, calculate the number of days in the month - return try { - val hijriCalendar = IslamicCalendar(year, month, 1) - hijriCalendar.add(Calendar.MONTH, 1) - hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) - hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) - val daysInMonth = hijriCalendar.get(Calendar.DAY_OF_MONTH) - - // Cache the result for future use - cachedYearlyMonthDays[year]?.put(month, daysInMonth) - - daysInMonth // Return the calculated number of days - } catch (e: Exception) { - 30 // Default to 30 days if there's an error - } - } -} - - - @Preview(showBackground = true) diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt new file mode 100644 index 0000000..8d9ba18 --- /dev/null +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt @@ -0,0 +1,123 @@ +package com.sdody.HijriDatePickerPlusApplication + +import android.icu.util.IslamicCalendar +import java.util.Calendar + +// Helper function to get weekday name +fun getWeekday(islamicCalendar: IslamicCalendar): String { + return when (islamicCalendar.get(Calendar.DAY_OF_WEEK)) { + Calendar.SUNDAY -> "Sunday" + Calendar.MONDAY -> "Monday" + Calendar.TUESDAY -> "Tuesday" + Calendar.WEDNESDAY -> "Wednesday" + Calendar.THURSDAY -> "Thursday" + Calendar.FRIDAY -> "Friday" + Calendar.SATURDAY -> "Saturday" + else -> "" + } +} + +fun getHijriMonthAbbr(month: Int): String { + return when (month) { + 0 -> "MUH" + 1 -> "SAF" + 2 -> "RAB-I" + 3 -> "RAB-II" + 4 -> "JUM-I" + 5 -> "JUM-II" + 6 -> "RAJ" + 7 -> "SHA" + 8 -> "RAM" + 9 -> "SHAW" + 10 -> "DHU-Q" + 11 -> "DHU-H" + else -> "" + } +} + +fun getHijriMonthName(month: Int): String { + return when (month % 12) { // Handle month overflow + 0 -> "Muharram" + 1 -> "Safar" + 2 -> "Rabi' al-Awwal" + 3 -> "Rabi' al-Thani" + 4 -> "Jumada al-Awwal" + 5 -> "Jumada al-Thani" + 6 -> "Rajab" + 7 -> "Sha'ban" + 8 -> "Ramadan" + 9 -> "Shawwal" + 10 -> "Dhu al-Qi'dah" + 11 -> "Dhu al-Hijjah" + else -> "" + } +} + +fun getHijriDaysInMonth(year: Int, month: Int): Int { + return try { + val hijriCalendar = IslamicCalendar(year, month, 1) + hijriCalendar.add(Calendar.MONTH, 1) + hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) + hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) + hijriCalendar.get(Calendar.DAY_OF_MONTH) + } catch (e: Exception) { + 30 // Default to 30 days if there's an error + } +} + + +object HijriCalendarDataCache { + + // Cache days for each year separately, with each year holding month-to-days mapping + private val cachedYearlyMonthDays = mutableMapOf>() // Changed to store Int instead of List + + // Precompute all the months and their number of days for the given year + fun initializeForYear(year: Int) { + if (cachedYearlyMonthDays[year] == null) { + cachedYearlyMonthDays[year] = mutableMapOf() + for (month in 0..11) { + cachedYearlyMonthDays[year]?.set(month, getDaysInHijriMonth(year, month)) + } + } + } + + // Retrieve cached number of days for a given year and month, and calculate if not cached + fun getDaysForMonth(year: Int, month: Int): Int { + // Check if the year is cached + if (cachedYearlyMonthDays[year] == null) { + initializeForYear(year) // Initialize the year if not already cached + } + // Check if the month is cached + return cachedYearlyMonthDays[year]?.get(month) ?: getDaysInHijriMonth(year, month) + } + + // Compute the number of days in a Hijri month and cache it + private fun getDaysInHijriMonth(year: Int, month: Int): Int { + // Check if the year is already cached + if (cachedYearlyMonthDays[year] == null) { + cachedYearlyMonthDays[year] = mutableMapOf() // Initialize the map for this year if not present + } + + // Check if the month is already cached + val cachedDays = cachedYearlyMonthDays[year]?.get(month) + if (cachedDays != null) { + return cachedDays // Return cached number of days if available + } + + // If not cached, calculate the number of days in the month + return try { + val hijriCalendar = IslamicCalendar(year, month, 1) + hijriCalendar.add(Calendar.MONTH, 1) + hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) + hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) + val daysInMonth = hijriCalendar.get(Calendar.DAY_OF_MONTH) + + // Cache the result for future use + cachedYearlyMonthDays[year]?.put(month, daysInMonth) + + daysInMonth // Return the calculated number of days + } catch (e: Exception) { + 30 // Default to 30 days if there's an error + } + } +} \ No newline at end of file From 2fe0f2eca498ba4370ac664f5b4f1cd39c8367f1 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 01:20:28 +0300 Subject: [PATCH 02/23] add function to show picker and make it more simple --- .../MainActivity.kt | 192 +++++++----------- gradle/libs.versions.toml | 1 + 2 files changed, 78 insertions(+), 115 deletions(-) diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index 4cab080..7e7e87e 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -39,45 +39,38 @@ class MainActivity : ComponentActivity() { println("Days in Muharram: ${getHijriDaysInMonth(1309, 0)}") println("Days in Safar: ${getHijriDaysInMonth(1309, 1)}") - - // Get the current Hijri date - val currentHijriCalendar = IslamicCalendar() - val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) - val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) - val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) - HijriCalendarDataCache.initializeForYear(currentHijriYear) - setContent { HijriDatePickerButton( - initialYear = currentHijriYear, - initialMonth = currentHijriMonth, - initialDay = currentHijriDay ) } } } - @Composable fun HijriDatePickerButton( - initialYear: Int, - initialMonth: Int, - initialDay: Int + ) { + // Get the current Hijri date + val currentHijriCalendar = IslamicCalendar() + val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) + val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) + val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) + + HijriCalendarDataCache.initializeForYear(currentHijriYear) + // State to hold the selected Hijri date, starting with the current Hijri date - val selectedDate = remember { mutableStateOf("$initialDay-${getHijriMonthName(initialMonth)}-$initialYear") } + val selectedDate = remember { mutableStateOf("$currentHijriDay-${getHijriMonthName(currentHijriMonth)}-$currentHijriDay") } - // State to control dialog visibility - initialized to false + // State to control dialog visibility var showDialog by remember { mutableStateOf(false) } // State for preselected date (used when reopening the picker) - val preselectedYear = remember { mutableStateOf(initialYear) } - val preselectedMonth = remember { mutableStateOf(initialMonth) } - val preselectedDay = remember { mutableStateOf(initialDay) } + val preselectedYear = remember { mutableStateOf(currentHijriYear) } + val preselectedMonth = remember { mutableStateOf(currentHijriMonth) } + val preselectedDay = remember { mutableStateOf(currentHijriDay) } // Center the button in a Box Box( - modifier = Modifier - .fillMaxSize(), + modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center ) { // Button to show the Hijri Date Picker @@ -85,9 +78,7 @@ fun HijriDatePickerButton( onClick = { showDialog = true // Open the dialog }, - modifier = Modifier - .width(250.dp) - .height(70.dp) + modifier = Modifier.width(250.dp).height(70.dp) ) { Text( text = selectedDate.value, @@ -129,7 +120,7 @@ fun HijriDatePickerDialogWithThreeSections( onDateSelected: (Int, Int, Int) -> Unit, onConfirm: () -> Unit, onDismissRequest: () -> Unit, - initialShowYearSelection: Boolean = true + initialShowYearSelection: Boolean = true // Always show year selection when opening the dialog ) { var selectedYear by remember { mutableStateOf(initialYear) } var selectedMonth by remember { mutableStateOf(initialMonth) } @@ -144,43 +135,36 @@ fun HijriDatePickerDialogWithThreeSections( Dialog(onDismissRequest = onDismissRequest) { Surface( - modifier = Modifier - .fillMaxWidth() - .heightIn(min = 400.dp, max = 500.dp) - .padding(16.dp), + modifier = Modifier.fillMaxWidth().heightIn(min = 400.dp, max = 500.dp).padding(16.dp), shape = MaterialTheme.shapes.medium ) { Column( - modifier = Modifier - .fillMaxWidth() - .background(Color.White) + modifier = Modifier.fillMaxWidth().background(Color.White) ) { - // Pass the selected (or preselected) date to the header + // Header section with the selected date val cal = IslamicCalendar(selectedYear, selectedMonth, selectedDay) // Pass the callback to trigger year selection HeaderSection(islamicCalendar = cal) { - showYearSelection = true // Show year selection on click + showYearSelection = true // Toggle to show year selection when the year is clicked } Spacer(modifier = Modifier.height(8.dp)) - // Show the year selection or the month grid + // Show either the year selection screen or the month grid if (showYearSelection) { YearSelectionScreen( selectedYear = selectedYear, onYearSelected = { year -> selectedYear = year - showYearSelection = false // Switch to month grid after year is selected + showYearSelection = false // Switch back to month grid after year is selected }, - currentYear = initialYear // Pass the preselected year to focus + currentYear = initialYear // Pass the preselected year to focus on it ) } else { // Month Grid with Days Section Box( - modifier = Modifier - .weight(1f) - .fillMaxWidth() + modifier = Modifier.weight(1f).fillMaxWidth() ) { MonthGridWithDays( selectedYear = selectedYear, @@ -189,14 +173,16 @@ fun HijriDatePickerDialogWithThreeSections( selectedMonth = month selectedDay = day onDateSelected(year, month, day) - } + }, + preselectedMonth = selectedMonth, // Pass the preselected month + preselectedDay = selectedDay // Pass the preselected day ) } } Spacer(modifier = Modifier.height(16.dp)) - // Footer with next month name + // Footer with Confirm and Cancel buttons FooterSection( nextMonthName = getHijriMonthName(selectedMonth), onConfirm = onConfirm, @@ -210,10 +196,7 @@ fun HijriDatePickerDialogWithThreeSections( @Composable fun HeaderSection(islamicCalendar: IslamicCalendar, onYearClick: () -> Unit) { Column( - modifier = Modifier - .fillMaxWidth() - .background(Color(0xFF008080)) // Use a teal-like color similar to the image - .padding(16.dp), + modifier = Modifier.fillMaxWidth().background(Color(0xFF008080)).padding(16.dp), horizontalAlignment = Alignment.CenterHorizontally ) { // Display the weekday at the top @@ -226,17 +209,16 @@ fun HeaderSection(islamicCalendar: IslamicCalendar, onYearClick: () -> Unit) { Text(text = islamicCalendar.get(Calendar.DAY_OF_MONTH).toString(), color = Color.White, fontSize = 40.sp) } - // Display the year at the bottom and make it clickable + // Display the year at the bottom and make it clickable to trigger year selection Text( text = islamicCalendar.get(Calendar.YEAR).toString(), color = Color.White, fontSize = 24.sp, - modifier = Modifier.clickable { onYearClick() } // Clicking the year triggers the year selection + modifier = Modifier.clickable { onYearClick() } // Trigger year selection when the year is clicked ) } } - @Composable fun YearSelectionScreen( selectedYear: Int, @@ -279,91 +261,53 @@ fun YearSelectionScreen( } } - - -@Composable -fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> Unit) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - // Display the name of the next month - Text(text = nextMonthName, fontSize = 18.sp, modifier = Modifier.padding(bottom = 8.dp)) - - // Cancel and Confirm buttons - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Button(onClick = onCancel) { - Text(text = "Cancel") - } - Button(onClick = onConfirm) { - Text(text = "OK") - } - } - } -} - - @Composable fun MonthGridWithDays( selectedYear: Int, - onDaySelected: (Int, Int, Int) -> Unit + onDaySelected: (Int, Int, Int) -> Unit, + preselectedMonth: Int, + preselectedDay: Int ) { // State to track the selected day and month - var selectedMonthState by remember { mutableStateOf(0) } - var selectedDayState by remember { mutableStateOf(1) } + var selectedMonthState by remember { mutableStateOf(preselectedMonth) } + var selectedDayState by remember { mutableStateOf(preselectedDay) } LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding(horizontal = 16.dp) + modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp) ) { items(12) { month -> // Month Header Text( text = getHijriMonthName(month), fontSize = 20.sp, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp), + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), color = Color(0xFF008080) ) // Retrieve cached days for the current month - val daysInMonth = HijriCalendarDataCache.getDaysForMonth(year = selectedYear,month) + val daysInMonth = HijriCalendarDataCache.getDaysForMonth(selectedYear, month) // Wrapping LazyVerticalGrid in a fixed height to avoid performance issues Box( - modifier = Modifier - .fillMaxWidth() - .height(200.dp) // Adjust height to fit your UI + modifier = Modifier.fillMaxWidth().height(200.dp) ) { LazyVerticalGrid( columns = GridCells.Fixed(7), // 7 days in a week modifier = Modifier.fillMaxSize(), content = { items(daysInMonth) { day -> - val adjustedDay = day+1 + val adjustedDay = day + 1 Box( - modifier = Modifier - .size(40.dp) - .clickable { - selectedMonthState = month - selectedDayState = adjustedDay - onDaySelected(selectedYear, month, adjustedDay) - } - .background( - if (month == selectedMonthState && adjustedDay == selectedDayState) - Color(0xFF008080) else Color.LightGray - ) - .padding(8.dp), + modifier = Modifier.size(40.dp).clickable { + selectedMonthState = month + selectedDayState = adjustedDay + onDaySelected(selectedYear, month, adjustedDay) + }.background( + if (month == selectedMonthState && adjustedDay == selectedDayState) + Color(0xFF008080) else Color.LightGray + ).padding(8.dp), contentAlignment = Alignment.Center ) { - Text(text = "$adjustedDay", fontSize = 16.sp, color = Color.White) } } @@ -375,22 +319,40 @@ fun MonthGridWithDays( } +@Composable +fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> Unit) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Display the name of the next month + Text(text = nextMonthName, fontSize = 18.sp, modifier = Modifier.padding(bottom = 8.dp)) + + // Cancel and Confirm buttons + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Button(onClick = onCancel) { + Text(text = "Cancel") + } + Button(onClick = onConfirm) { + Text(text = "OK") + } + } + } +} @Preview(showBackground = true) @Composable fun PreviewHijriDatePickerButton() { // Get the current Hijri date - val currentHijriCalendar = IslamicCalendar() - val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) - val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) - val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) - HijriDatePickerButton( - initialYear = currentHijriYear, - initialMonth = currentHijriMonth, - initialDay = currentHijriDay - ) + + HijriDatePickerButton() } @Preview(showBackground = true) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f078972..a2d67e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,6 +42,7 @@ material3 = { module = "androidx.compose.material3:material3", version.ref = "ma ummalqura-calendar = { module = "com.github.msarhan:ummalqura-calendar", version.ref = "ummalquraCalendar" } [plugins] +android-library = { id = "com.android.library", version = "7.4.2" } android-application = { id = "com.android.application", version.ref = "agp" } jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } From 3e7374a9e7f49b1ebe1d78e96214f0c13078888e Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 01:59:15 +0300 Subject: [PATCH 03/23] add function to show picker --- .../MainActivity.kt | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index 7e7e87e..139df65 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -40,11 +40,72 @@ class MainActivity : ComponentActivity() { println("Days in Safar: ${getHijriDaysInMonth(1309, 1)}") setContent { - HijriDatePickerButton( - ) + HijriDatePickerButton() + + // Example of how you can trigger the date picker from anywhere + /* showHijriDatePicker( + initialYear = 1446, // Pass the initial year, e.g., current Hijri year + initialMonth = 1, // Initial month + initialDay = 10, // Initial day + onDateSelected = { year, month, day -> + // Handle date selected (year, month, day) + println("Selected Date: $day-${getHijriMonthName(month)}-$year") + }, + onConfirm = { + // Handle confirm click + println("Date Picker Confirmed") + }, + onDismissRequest = { + // Handle dismiss + println("Date Picker Dismissed") + } + )*/ } } } + +@Composable +fun showHijriDatePicker( + initialYear: Int, + initialMonth: Int, + initialDay: Int, + onDateSelected: (Int, Int, Int) -> Unit, + onConfirm: () -> Unit, + onDismissRequest: () -> Unit +) { + // State for preselected date + val preselectedYear = remember { mutableStateOf(initialYear) } + val preselectedMonth = remember { mutableStateOf(initialMonth) } + val preselectedDay = remember { mutableStateOf(initialDay) } + + // Dialog visibility is controlled outside (no button, it will be triggered by external events) + var showDialog by remember { mutableStateOf(true) } + + if (showDialog) { + HijriDatePickerDialogWithThreeSections( + initialYear = preselectedYear.value, + initialMonth = preselectedMonth.value, + initialDay = preselectedDay.value, + onDateSelected = { year, month, day -> + // Update the preselected date for the next opening + preselectedYear.value = year + preselectedMonth.value = month + preselectedDay.value = day + onDateSelected(year, month, day) // Call the provided callback + }, + onConfirm = { + showDialog = false // Close the dialog when Confirm is clicked + onConfirm() // Call the confirm callback + }, + onDismissRequest = { + showDialog = false // Close the dialog when dismissed + onDismissRequest() // Call the dismiss callback + }, + initialShowYearSelection = true // Always show year selection first + ) + } +} + @Composable fun HijriDatePickerButton( From 1105a6c51bf7849439c9a9cdadcefccff099c39a Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:42:59 +0300 Subject: [PATCH 04/23] add library files --- HijriDatePickerLib/.gitignore | 1 + HijriDatePickerLib/build.gradle.kts | 43 +++++++++++++++++++ HijriDatePickerLib/consumer-rules.pro | 0 HijriDatePickerLib/proguard-rules.pro | 21 +++++++++ .../src/main/AndroidManifest.xml | 4 ++ build.gradle.kts | 1 + gradle/libs.versions.toml | 2 + settings.gradle.kts | 1 + 8 files changed, 73 insertions(+) create mode 100644 HijriDatePickerLib/.gitignore create mode 100644 HijriDatePickerLib/build.gradle.kts create mode 100644 HijriDatePickerLib/consumer-rules.pro create mode 100644 HijriDatePickerLib/proguard-rules.pro create mode 100644 HijriDatePickerLib/src/main/AndroidManifest.xml diff --git a/HijriDatePickerLib/.gitignore b/HijriDatePickerLib/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/HijriDatePickerLib/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts new file mode 100644 index 0000000..2f16204 --- /dev/null +++ b/HijriDatePickerLib/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + alias(libs.plugins.android.library) + alias(libs.plugins.jetbrains.kotlin.android) +} + +android { + namespace = "com.sdody.hijridatepickerlib" + compileSdk = 34 + + defaultConfig { + minSdk = 28 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.material) + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) +} \ No newline at end of file diff --git a/HijriDatePickerLib/consumer-rules.pro b/HijriDatePickerLib/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/HijriDatePickerLib/proguard-rules.pro b/HijriDatePickerLib/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/HijriDatePickerLib/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/AndroidManifest.xml b/HijriDatePickerLib/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/HijriDatePickerLib/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index f74b04b..e3f8a07 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,4 +2,5 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.jetbrains.kotlin.android) apply false + alias(libs.plugins.android.library) apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a2d67e4..ec7ae7e 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ lifecycleRuntimeKtxVersion = "2.3.1" material = "1.12.0" material3 = "1.2.1" ummalquraCalendar = "2.0.2" +appcompat = "1.7.0" [libraries] android-joda = { module = "net.danlew:android.joda", version.ref = "androidJoda" } @@ -40,6 +41,7 @@ kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-c material = { module = "com.google.android.material:material", version.ref = "material" } material3 = { module = "androidx.compose.material3:material3", version.ref = "material3" } ummalqura-calendar = { module = "com.github.msarhan:ummalqura-calendar", version.ref = "ummalquraCalendar" } +androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } [plugins] android-library = { id = "com.android.library", version = "7.4.2" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 5dc0189..69f4726 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -21,3 +21,4 @@ dependencyResolutionManagement { rootProject.name = "My Application" include(":app") +include(":HijriDatePickerLib") From b713221650b6fd827a82451fa1b985781712b7e0 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:43:42 +0300 Subject: [PATCH 05/23] add library files --- .../sdody/hijridatepickerlib/FooterSection.kt | 40 ++++++ .../sdody/hijridatepickerlib/HeaderSection.kt | 46 +++++++ .../HijriDatePickerButton.kt | 86 ++++++++++++ .../HijriDatePickerDialogWithThreeSections.kt | 104 +++++++++++++++ .../hijridatepickerlib/MonthGridWithDays.kt | 81 ++++++++++++ .../com/sdody/hijridatepickerlib/Utils.kt | 123 ++++++++++++++++++ .../hijridatepickerlib/YearSelectionScreen.kt | 60 +++++++++ .../hijridatepickerlib/showHijriDatePicker.kt | 68 ++++++++++ 8 files changed, 608 insertions(+) create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/Utils.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt create mode 100644 HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt new file mode 100644 index 0000000..3096c0f --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt @@ -0,0 +1,40 @@ +package com.sdody.hijridatepickerpluslib + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> Unit) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Display the name of the next month + Text(text = nextMonthName, fontSize = 18.sp, modifier = Modifier.padding(bottom = 8.dp)) + + // Cancel and Confirm buttons + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Button(onClick = onCancel) { + Text(text = "Cancel") + } + Button(onClick = onConfirm) { + Text(text = "OK") + } + } + } +} diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt new file mode 100644 index 0000000..1d4c52b --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt @@ -0,0 +1,46 @@ +package com.sdody.hijridatepickerpluslib + +import android.icu.util.IslamicCalendar +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import java.util.Calendar + + +@Composable +fun HeaderSection(islamicCalendar: IslamicCalendar, onYearClick: () -> Unit) { + Column( + modifier = Modifier.fillMaxWidth().background(Color(0xFF008080)).padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Display the weekday at the top + Text(text = getWeekday(islamicCalendar), color = Color.White, fontSize = 18.sp) + + // Display the month abbreviation and day number + Row(verticalAlignment = Alignment.CenterVertically) { + Text(text = getHijriMonthAbbr(islamicCalendar.get(Calendar.MONTH)), color = Color.White, fontSize = 30.sp) + Spacer(modifier = Modifier.width(16.dp)) + Text(text = islamicCalendar.get(Calendar.DAY_OF_MONTH).toString(), color = Color.White, fontSize = 40.sp) + } + + // Display the year at the bottom and make it clickable to trigger year selection + Text( + text = islamicCalendar.get(Calendar.YEAR).toString(), + color = Color.White, + fontSize = 24.sp, + modifier = Modifier.clickable { onYearClick() } // Trigger year selection when the year is clicked + ) + } +} diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt new file mode 100644 index 0000000..e101ad6 --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt @@ -0,0 +1,86 @@ +package com.sdody.hijridatepickerpluslib + +import android.icu.util.IslamicCalendar +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import java.util.Calendar + +@Composable +fun HijriDatePickerButton( + +) { + // Get the current Hijri date + val currentHijriCalendar = IslamicCalendar() + val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) + val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) + val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) + + HijriCalendarDataCache.initializeForYear(currentHijriYear) + + // State to hold the selected Hijri date, starting with the current Hijri date + val selectedDate = remember { mutableStateOf("$currentHijriDay-${getHijriMonthName(currentHijriMonth)}-$currentHijriDay") } + + // State to control dialog visibility + var showDialog by remember { mutableStateOf(false) } + + // State for preselected date (used when reopening the picker) + val preselectedYear = remember { mutableStateOf(currentHijriYear) } + val preselectedMonth = remember { mutableStateOf(currentHijriMonth) } + val preselectedDay = remember { mutableStateOf(currentHijriDay) } + + // Center the button in a Box + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + // Button to show the Hijri Date Picker + Button( + onClick = { + showDialog = true // Open the dialog + }, + modifier = Modifier.width(250.dp).height(70.dp) + ) { + Text( + text = selectedDate.value, + fontSize = 20.sp // Increase the font size for better visibility + ) + } + } + + // Show the custom Hijri Date Picker Dialog only when showDialog is true + if (showDialog) { + HijriDatePickerDialogWithThreeSections( + initialYear = preselectedYear.value, + initialMonth = preselectedMonth.value, + initialDay = preselectedDay.value, + onDateSelected = { year, month, day -> + // Update the selected date state + selectedDate.value = "$day-${getHijriMonthName(month)}-$year" + // Update the preselected date for next opening + preselectedYear.value = year + preselectedMonth.value = month + preselectedDay.value = day + }, + onConfirm = { + showDialog = false // Close the dialog when Confirm is clicked + }, + onDismissRequest = { + showDialog = false // Close the dialog when Cancel is clicked or dismissed + }, + initialShowYearSelection = true // Always show year selection first + ) + } +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt new file mode 100644 index 0000000..df4eb4b --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt @@ -0,0 +1,104 @@ +package com.sdody.hijridatepickerpluslib + +import android.icu.util.IslamicCalendar +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog + +@Composable +fun HijriDatePickerDialogWithThreeSections( + initialYear: Int, + initialMonth: Int, + initialDay: Int, + onDateSelected: (Int, Int, Int) -> Unit, + onConfirm: () -> Unit, + onDismissRequest: () -> Unit, + initialShowYearSelection: Boolean = true // Always show year selection when opening the dialog +) { + var selectedYear by remember { mutableStateOf(initialYear) } + var selectedMonth by remember { mutableStateOf(initialMonth) } + var selectedDay by remember { mutableStateOf(initialDay) } + var showYearSelection by remember { mutableStateOf(initialShowYearSelection) } + + // Ensure selected day is valid for the selected month + val daysInMonth = getHijriDaysInMonth(selectedYear, selectedMonth) + if (selectedDay > daysInMonth) { + selectedDay = daysInMonth + } + + Dialog(onDismissRequest = onDismissRequest) { + Surface( + modifier = Modifier.fillMaxWidth().heightIn(min = 400.dp, max = 500.dp).padding(16.dp), + shape = MaterialTheme.shapes.medium + ) { + Column( + modifier = Modifier.fillMaxWidth().background(Color.White) + ) { + // Header section with the selected date + val cal = IslamicCalendar(selectedYear, selectedMonth, selectedDay) + + // Pass the callback to trigger year selection + HeaderSection(islamicCalendar = cal) { + showYearSelection = true // Toggle to show year selection when the year is clicked + } + + Spacer(modifier = Modifier.height(8.dp)) + + // Show either the year selection screen or the month grid + if (showYearSelection) { + YearSelectionScreen( + selectedYear = selectedYear, + onYearSelected = { year -> + selectedYear = year + showYearSelection = false // Switch back to month grid after year is selected + }, + currentYear = initialYear // Pass the preselected year to focus on it + ) + } else { + // Month Grid with Days Section + Box( + modifier = Modifier.weight(1f).fillMaxWidth() + ) { + MonthGridWithDays( + selectedYear = selectedYear, + onDaySelected = { year, month, day -> + selectedYear = year + selectedMonth = month + selectedDay = day + onDateSelected(year, month, day) + }, + preselectedMonth = selectedMonth, // Pass the preselected month + preselectedDay = selectedDay // Pass the preselected day + ) + } + } + + Spacer(modifier = Modifier.height(16.dp)) + + // Footer with Confirm and Cancel buttons + FooterSection( + nextMonthName = getHijriMonthName(selectedMonth), + onConfirm = onConfirm, + onCancel = onDismissRequest + ) + } + } + } +} + diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt new file mode 100644 index 0000000..ac1ca27 --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt @@ -0,0 +1,81 @@ +package com.sdody.hijridatepickerpluslib + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.grid.GridCells +import androidx.compose.foundation.lazy.grid.LazyVerticalGrid +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun MonthGridWithDays( + selectedYear: Int, + onDaySelected: (Int, Int, Int) -> Unit, + preselectedMonth: Int, + preselectedDay: Int +) { + // State to track the selected day and month + var selectedMonthState by remember { mutableStateOf(preselectedMonth) } + var selectedDayState by remember { mutableStateOf(preselectedDay) } + + LazyColumn( + modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp) + ) { + items(12) { month -> + // Month Header + Text( + text = getHijriMonthName(month), + fontSize = 20.sp, + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), + color = Color(0xFF008080) + ) + + // Retrieve cached days for the current month + val daysInMonth = HijriCalendarDataCache.getDaysForMonth(selectedYear, month) + + // Wrapping LazyVerticalGrid in a fixed height to avoid performance issues + Box( + modifier = Modifier.fillMaxWidth().height(200.dp) + ) { + LazyVerticalGrid( + columns = GridCells.Fixed(7), // 7 days in a week + modifier = Modifier.fillMaxSize(), + content = { + items(daysInMonth) { day -> + val adjustedDay = day + 1 + Box( + modifier = Modifier.size(40.dp).clickable { + selectedMonthState = month + selectedDayState = adjustedDay + onDaySelected(selectedYear, month, adjustedDay) + }.background( + if (month == selectedMonthState && adjustedDay == selectedDayState) + Color(0xFF008080) else Color.LightGray + ).padding(8.dp), + contentAlignment = Alignment.Center + ) { + Text(text = "$adjustedDay", fontSize = 16.sp, color = Color.White) + } + } + } + ) + } + } + } +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/Utils.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/Utils.kt new file mode 100644 index 0000000..2a26aed --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/Utils.kt @@ -0,0 +1,123 @@ +package com.sdody.hijridatepickerpluslib + +import android.icu.util.IslamicCalendar +import java.util.Calendar + + +// Helper function to get weekday name +fun getWeekday(islamicCalendar: IslamicCalendar): String { + return when (islamicCalendar.get(Calendar.DAY_OF_WEEK)) { + Calendar.SUNDAY -> "Sunday" + Calendar.MONDAY -> "Monday" + Calendar.TUESDAY -> "Tuesday" + Calendar.WEDNESDAY -> "Wednesday" + Calendar.THURSDAY -> "Thursday" + Calendar.FRIDAY -> "Friday" + Calendar.SATURDAY -> "Saturday" + else -> "" + } +} + +fun getHijriMonthAbbr(month: Int): String { + return when (month) { + 0 -> "MUH" + 1 -> "SAF" + 2 -> "RAB-I" + 3 -> "RAB-II" + 4 -> "JUM-I" + 5 -> "JUM-II" + 6 -> "RAJ" + 7 -> "SHA" + 8 -> "RAM" + 9 -> "SHAW" + 10 -> "DHU-Q" + 11 -> "DHU-H" + else -> "" + } +} + +fun getHijriMonthName(month: Int): String { + return when (month % 12) { // Handle month overflow + 0 -> "Muharram" + 1 -> "Safar" + 2 -> "Rabi' al-Awwal" + 3 -> "Rabi' al-Thani" + 4 -> "Jumada al-Awwal" + 5 -> "Jumada al-Thani" + 6 -> "Rajab" + 7 -> "Sha'ban" + 8 -> "Ramadan" + 9 -> "Shawwal" + 10 -> "Dhu al-Qi'dah" + 11 -> "Dhu al-Hijjah" + else -> "" + } +} + +fun getHijriDaysInMonth(year: Int, month: Int): Int { + return try { + val hijriCalendar = IslamicCalendar(year, month, 1) + hijriCalendar.add(Calendar.MONTH, 1) + hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) + hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) + hijriCalendar.get(Calendar.DAY_OF_MONTH) + } catch (e: Exception) { + 30 // Default to 30 days if there's an error + } +} + +object HijriCalendarDataCache { + + // Cache days for each year separately, with each year holding month-to-days mapping + private val cachedYearlyMonthDays = mutableMapOf>() // Changed to store Int instead of List + + // Precompute all the months and their number of days for the given year + fun initializeForYear(year: Int) { + if (cachedYearlyMonthDays[year] == null) { + cachedYearlyMonthDays[year] = mutableMapOf() + for (month in 0..11) { + cachedYearlyMonthDays[year]?.set(month, getDaysInHijriMonth(year, month)) + } + } + } + + // Retrieve cached number of days for a given year and month, and calculate if not cached + fun getDaysForMonth(year: Int, month: Int): Int { + // Check if the year is cached + if (cachedYearlyMonthDays[year] == null) { + initializeForYear(year) // Initialize the year if not already cached + } + // Check if the month is cached + return cachedYearlyMonthDays[year]?.get(month) ?: getDaysInHijriMonth(year, month) + } + + // Compute the number of days in a Hijri month and cache it + private fun getDaysInHijriMonth(year: Int, month: Int): Int { + // Check if the year is already cached + if (cachedYearlyMonthDays[year] == null) { + cachedYearlyMonthDays[year] = mutableMapOf() // Initialize the map for this year if not present + } + + // Check if the month is already cached + val cachedDays = cachedYearlyMonthDays[year]?.get(month) + if (cachedDays != null) { + return cachedDays // Return cached number of days if available + } + + // If not cached, calculate the number of days in the month + return try { + val hijriCalendar = IslamicCalendar(year, month, 1) + hijriCalendar.add(Calendar.MONTH, 1) + hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) + hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) + val daysInMonth = hijriCalendar.get(Calendar.DAY_OF_MONTH) + + // Cache the result for future use + cachedYearlyMonthDays[year]?.put(month, daysInMonth) + + daysInMonth // Return the calculated number of days + } catch (e: Exception) { + 30 // Default to 30 days if there's an error + } + } +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt new file mode 100644 index 0000000..8ee5a0b --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt @@ -0,0 +1,60 @@ +package com.sdody.hijridatepickerpluslib + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp + +@Composable +fun YearSelectionScreen( + selectedYear: Int, + onYearSelected: (Int) -> Unit, + currentYear: Int // Pass the current year to scroll into view +) { + // The valid range of years for the Umm Al-Qura calendar + val minHijriYear = 1300 // Starting year (~1900 AD) + val maxHijriYear = 1500 // Ending year (~2077 AD) + val years = (minHijriYear..maxHijriYear).toList() // Generate the valid range of years + + // State to scroll directly to the current year index + val listState = rememberLazyListState() + + // Automatically scroll to the current year when the year selection screen appears + LaunchedEffect(Unit) { + listState.scrollToItem(currentYear - minHijriYear) // Scroll to the current year index + } + + LazyColumn( + state = listState, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .background(Color.White), + horizontalAlignment = Alignment.CenterHorizontally + ) { + items(years) { year -> + Text( + text = "$year", + fontSize = 28.sp, + modifier = Modifier + .fillMaxWidth() + .padding(16.dp) + .clickable { onYearSelected(year) }, // Year is selected on click + color = if (year == selectedYear) Color.Blue else Color.Black, + textAlign = TextAlign.Center + ) + } + } +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt new file mode 100644 index 0000000..a5ad828 --- /dev/null +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt @@ -0,0 +1,68 @@ +package com.sdody.hijridatepickerpluslib + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue + +// Example of how you can trigger the date picker from anywhere +/* showHijriDatePicker( + initialYear = 1446, // Pass the initial year, e.g., current Hijri year + initialMonth = 1, // Initial month + initialDay = 10, // Initial day + onDateSelected = { year, month, day -> + // Handle date selected (year, month, day) + println("Selected Date: $day-${getHijriMonthName(month)}-$year") + }, + onConfirm = { + // Handle confirm click + println("Date Picker Confirmed") + }, + onDismissRequest = { + // Handle dismiss + println("Date Picker Dismissed") + } + )*/ + +@Composable +fun showHijriDatePicker( + initialYear: Int, + initialMonth: Int, + initialDay: Int, + onDateSelected: (Int, Int, Int) -> Unit, + onConfirm: () -> Unit, + onDismissRequest: () -> Unit +) { + // State for preselected date + val preselectedYear = remember { mutableStateOf(initialYear) } + val preselectedMonth = remember { mutableStateOf(initialMonth) } + val preselectedDay = remember { mutableStateOf(initialDay) } + + // Dialog visibility is controlled outside (no button, it will be triggered by external events) + var showDialog by remember { mutableStateOf(true) } + + if (showDialog) { + HijriDatePickerDialogWithThreeSections( + initialYear = preselectedYear.value, + initialMonth = preselectedMonth.value, + initialDay = preselectedDay.value, + onDateSelected = { year, month, day -> + // Update the preselected date for the next opening + preselectedYear.value = year + preselectedMonth.value = month + preselectedDay.value = day + onDateSelected(year, month, day) // Call the provided callback + }, + onConfirm = { + showDialog = false // Close the dialog when Confirm is clicked + onConfirm() // Call the confirm callback + }, + onDismissRequest = { + showDialog = false // Close the dialog when dismissed + onDismissRequest() // Call the dismiss callback + }, + initialShowYearSelection = true // Always show year selection first + ) + } +} \ No newline at end of file From 6436d536a891ec4f155a3676efecb103f1a1bab7 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:51:34 +0300 Subject: [PATCH 06/23] build lib --- .idea/gradle.xml | 1 + HijriDatePickerLib/build.gradle.kts | 23 +++++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0897082..875e518 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -9,6 +9,7 @@ diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 2f16204..6a04251 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -35,9 +35,28 @@ android { dependencies { implementation(libs.androidx.core.ktx) - implementation(libs.androidx.appcompat) - implementation(libs.material) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) + implementation(libs.ummalqura.calendar) + implementation( libs.material3) + implementation (libs.material) + implementation (libs.androidx.lifecycle.runtime.ktx.v231) + implementation (libs.androidx.foundation) + implementation (libs.android.joda) + implementation (libs.kotlinx.coroutines.core) + implementation (libs.kotlinx.coroutines.android) + + } \ No newline at end of file From 824e59852dae1b923a59792fbc8acaf35347b2e9 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:57:34 +0300 Subject: [PATCH 07/23] Update README.md Signed-off-by: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index f782b91..4f5f472 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -Here's an updated version of your README, reflecting the switch to using the `IslamicCalendar` instead of the Umm Al-Qura calendar and emphasizing its broader support: ---- # HijriDatePickerPlus @@ -64,6 +62,5 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file For any questions or support regarding this project, you can contact the project maintainer at: [mohamed.ma872@gmail.com](mailto:mohamed.ma872@gmail.com) ---- +[![](https://jitpack.io/v/mohamedma872/HijriDatePickerPlus.svg)](https://jitpack.io/#mohamedma872/HijriDatePickerPlus) -This README explains that the switch to the `IslamicCalendar` provides a more globally applicable solution, while still highlighting the key features and improvements of the Hijri Date Picker. From 04df34e85ec39510713b698f61bf4193dbb69afa Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 02:58:45 +0300 Subject: [PATCH 08/23] add some file to gradle --- HijriDatePickerLib/build.gradle.kts | 2 -- build.gradle.kts | 2 +- settings.gradle.kts | 1 + 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 6a04251..8ed1c6d 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -57,6 +57,4 @@ dependencies { implementation (libs.android.joda) implementation (libs.kotlinx.coroutines.core) implementation (libs.kotlinx.coroutines.android) - - } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index e3f8a07..394c82a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,4 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.android.library) apply false -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 69f4726..ca6bfad 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,6 +16,7 @@ dependencyResolutionManagement { repositories { google() mavenCentral() + maven { url = uri("https://jitpack.io") } } } From 2b1e59059483e61c6194cebfe6d5f6f5f7b47e34 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 03:10:21 +0300 Subject: [PATCH 09/23] add maven publish --- HijriDatePickerLib/build.gradle.kts | 1 + app/build.gradle.kts | 1 + .../MainActivity.kt | 403 +----------------- 3 files changed, 3 insertions(+), 402 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 8ed1c6d..2018395 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -1,6 +1,7 @@ plugins { alias(libs.plugins.android.library) alias(libs.plugins.jetbrains.kotlin.android) + id("maven-publish") } android { diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 13f9721..895a5f1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -75,5 +75,6 @@ dependencies { implementation (libs.kotlinx.coroutines.core) implementation (libs.kotlinx.coroutines.android) + implementation ("com.github.mohamedma872:HijriDatePickerPlus:v1.0.1") } \ No newline at end of file diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index 139df65..c7f5f75 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -40,7 +40,7 @@ class MainActivity : ComponentActivity() { println("Days in Safar: ${getHijriDaysInMonth(1309, 1)}") setContent { - HijriDatePickerButton() + // HijriDatePickerButton() // Example of how you can trigger the date picker from anywhere /* showHijriDatePicker( @@ -63,404 +63,3 @@ class MainActivity : ComponentActivity() { } } } - -@Composable -fun showHijriDatePicker( - initialYear: Int, - initialMonth: Int, - initialDay: Int, - onDateSelected: (Int, Int, Int) -> Unit, - onConfirm: () -> Unit, - onDismissRequest: () -> Unit -) { - // State for preselected date - val preselectedYear = remember { mutableStateOf(initialYear) } - val preselectedMonth = remember { mutableStateOf(initialMonth) } - val preselectedDay = remember { mutableStateOf(initialDay) } - - // Dialog visibility is controlled outside (no button, it will be triggered by external events) - var showDialog by remember { mutableStateOf(true) } - - if (showDialog) { - HijriDatePickerDialogWithThreeSections( - initialYear = preselectedYear.value, - initialMonth = preselectedMonth.value, - initialDay = preselectedDay.value, - onDateSelected = { year, month, day -> - // Update the preselected date for the next opening - preselectedYear.value = year - preselectedMonth.value = month - preselectedDay.value = day - onDateSelected(year, month, day) // Call the provided callback - }, - onConfirm = { - showDialog = false // Close the dialog when Confirm is clicked - onConfirm() // Call the confirm callback - }, - onDismissRequest = { - showDialog = false // Close the dialog when dismissed - onDismissRequest() // Call the dismiss callback - }, - initialShowYearSelection = true // Always show year selection first - ) - } -} - -@Composable -fun HijriDatePickerButton( - -) { - // Get the current Hijri date - val currentHijriCalendar = IslamicCalendar() - val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) - val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) - val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) - - HijriCalendarDataCache.initializeForYear(currentHijriYear) - - // State to hold the selected Hijri date, starting with the current Hijri date - val selectedDate = remember { mutableStateOf("$currentHijriDay-${getHijriMonthName(currentHijriMonth)}-$currentHijriDay") } - - // State to control dialog visibility - var showDialog by remember { mutableStateOf(false) } - - // State for preselected date (used when reopening the picker) - val preselectedYear = remember { mutableStateOf(currentHijriYear) } - val preselectedMonth = remember { mutableStateOf(currentHijriMonth) } - val preselectedDay = remember { mutableStateOf(currentHijriDay) } - - // Center the button in a Box - Box( - modifier = Modifier.fillMaxSize(), - contentAlignment = Alignment.Center - ) { - // Button to show the Hijri Date Picker - Button( - onClick = { - showDialog = true // Open the dialog - }, - modifier = Modifier.width(250.dp).height(70.dp) - ) { - Text( - text = selectedDate.value, - fontSize = 20.sp // Increase the font size for better visibility - ) - } - } - - // Show the custom Hijri Date Picker Dialog only when showDialog is true - if (showDialog) { - HijriDatePickerDialogWithThreeSections( - initialYear = preselectedYear.value, - initialMonth = preselectedMonth.value, - initialDay = preselectedDay.value, - onDateSelected = { year, month, day -> - // Update the selected date state - selectedDate.value = "$day-${getHijriMonthName(month)}-$year" - // Update the preselected date for next opening - preselectedYear.value = year - preselectedMonth.value = month - preselectedDay.value = day - }, - onConfirm = { - showDialog = false // Close the dialog when Confirm is clicked - }, - onDismissRequest = { - showDialog = false // Close the dialog when Cancel is clicked or dismissed - }, - initialShowYearSelection = true // Always show year selection first - ) - } -} - -@Composable -fun HijriDatePickerDialogWithThreeSections( - initialYear: Int, - initialMonth: Int, - initialDay: Int, - onDateSelected: (Int, Int, Int) -> Unit, - onConfirm: () -> Unit, - onDismissRequest: () -> Unit, - initialShowYearSelection: Boolean = true // Always show year selection when opening the dialog -) { - var selectedYear by remember { mutableStateOf(initialYear) } - var selectedMonth by remember { mutableStateOf(initialMonth) } - var selectedDay by remember { mutableStateOf(initialDay) } - var showYearSelection by remember { mutableStateOf(initialShowYearSelection) } - - // Ensure selected day is valid for the selected month - val daysInMonth = getHijriDaysInMonth(selectedYear, selectedMonth) - if (selectedDay > daysInMonth) { - selectedDay = daysInMonth - } - - Dialog(onDismissRequest = onDismissRequest) { - Surface( - modifier = Modifier.fillMaxWidth().heightIn(min = 400.dp, max = 500.dp).padding(16.dp), - shape = MaterialTheme.shapes.medium - ) { - Column( - modifier = Modifier.fillMaxWidth().background(Color.White) - ) { - // Header section with the selected date - val cal = IslamicCalendar(selectedYear, selectedMonth, selectedDay) - - // Pass the callback to trigger year selection - HeaderSection(islamicCalendar = cal) { - showYearSelection = true // Toggle to show year selection when the year is clicked - } - - Spacer(modifier = Modifier.height(8.dp)) - - // Show either the year selection screen or the month grid - if (showYearSelection) { - YearSelectionScreen( - selectedYear = selectedYear, - onYearSelected = { year -> - selectedYear = year - showYearSelection = false // Switch back to month grid after year is selected - }, - currentYear = initialYear // Pass the preselected year to focus on it - ) - } else { - // Month Grid with Days Section - Box( - modifier = Modifier.weight(1f).fillMaxWidth() - ) { - MonthGridWithDays( - selectedYear = selectedYear, - onDaySelected = { year, month, day -> - selectedYear = year - selectedMonth = month - selectedDay = day - onDateSelected(year, month, day) - }, - preselectedMonth = selectedMonth, // Pass the preselected month - preselectedDay = selectedDay // Pass the preselected day - ) - } - } - - Spacer(modifier = Modifier.height(16.dp)) - - // Footer with Confirm and Cancel buttons - FooterSection( - nextMonthName = getHijriMonthName(selectedMonth), - onConfirm = onConfirm, - onCancel = onDismissRequest - ) - } - } - } -} - -@Composable -fun HeaderSection(islamicCalendar: IslamicCalendar, onYearClick: () -> Unit) { - Column( - modifier = Modifier.fillMaxWidth().background(Color(0xFF008080)).padding(16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - // Display the weekday at the top - Text(text = getWeekday(islamicCalendar), color = Color.White, fontSize = 18.sp) - - // Display the month abbreviation and day number - Row(verticalAlignment = Alignment.CenterVertically) { - Text(text = getHijriMonthAbbr(islamicCalendar.get(Calendar.MONTH)), color = Color.White, fontSize = 30.sp) - Spacer(modifier = Modifier.width(16.dp)) - Text(text = islamicCalendar.get(Calendar.DAY_OF_MONTH).toString(), color = Color.White, fontSize = 40.sp) - } - - // Display the year at the bottom and make it clickable to trigger year selection - Text( - text = islamicCalendar.get(Calendar.YEAR).toString(), - color = Color.White, - fontSize = 24.sp, - modifier = Modifier.clickable { onYearClick() } // Trigger year selection when the year is clicked - ) - } -} - -@Composable -fun YearSelectionScreen( - selectedYear: Int, - onYearSelected: (Int) -> Unit, - currentYear: Int // Pass the current year to scroll into view -) { - // The valid range of years for the Umm Al-Qura calendar - val minHijriYear = 1300 // Starting year (~1900 AD) - val maxHijriYear = 1500 // Ending year (~2077 AD) - val years = (minHijriYear..maxHijriYear).toList() // Generate the valid range of years - - // State to scroll directly to the current year index - val listState = rememberLazyListState() - - // Automatically scroll to the current year when the year selection screen appears - LaunchedEffect(Unit) { - listState.scrollToItem(currentYear - minHijriYear) // Scroll to the current year index - } - - LazyColumn( - state = listState, - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - .background(Color.White), - horizontalAlignment = Alignment.CenterHorizontally - ) { - items(years) { year -> - Text( - text = "$year", - fontSize = 28.sp, - modifier = Modifier - .fillMaxWidth() - .padding(16.dp) - .clickable { onYearSelected(year) }, // Year is selected on click - color = if (year == selectedYear) Color.Blue else Color.Black, - textAlign = TextAlign.Center - ) - } - } -} - -@Composable -fun MonthGridWithDays( - selectedYear: Int, - onDaySelected: (Int, Int, Int) -> Unit, - preselectedMonth: Int, - preselectedDay: Int -) { - // State to track the selected day and month - var selectedMonthState by remember { mutableStateOf(preselectedMonth) } - var selectedDayState by remember { mutableStateOf(preselectedDay) } - - LazyColumn( - modifier = Modifier.fillMaxSize().padding(horizontal = 16.dp) - ) { - items(12) { month -> - // Month Header - Text( - text = getHijriMonthName(month), - fontSize = 20.sp, - modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp), - color = Color(0xFF008080) - ) - - // Retrieve cached days for the current month - val daysInMonth = HijriCalendarDataCache.getDaysForMonth(selectedYear, month) - - // Wrapping LazyVerticalGrid in a fixed height to avoid performance issues - Box( - modifier = Modifier.fillMaxWidth().height(200.dp) - ) { - LazyVerticalGrid( - columns = GridCells.Fixed(7), // 7 days in a week - modifier = Modifier.fillMaxSize(), - content = { - items(daysInMonth) { day -> - val adjustedDay = day + 1 - Box( - modifier = Modifier.size(40.dp).clickable { - selectedMonthState = month - selectedDayState = adjustedDay - onDaySelected(selectedYear, month, adjustedDay) - }.background( - if (month == selectedMonthState && adjustedDay == selectedDayState) - Color(0xFF008080) else Color.LightGray - ).padding(8.dp), - contentAlignment = Alignment.Center - ) { - Text(text = "$adjustedDay", fontSize = 16.sp, color = Color.White) - } - } - } - ) - } - } - } -} - - -@Composable -fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> Unit) { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - horizontalAlignment = Alignment.CenterHorizontally - ) { - // Display the name of the next month - Text(text = nextMonthName, fontSize = 18.sp, modifier = Modifier.padding(bottom = 8.dp)) - - // Cancel and Confirm buttons - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Button(onClick = onCancel) { - Text(text = "Cancel") - } - Button(onClick = onConfirm) { - Text(text = "OK") - } - } - } -} - - -@Preview(showBackground = true) -@Composable -fun PreviewHijriDatePickerButton() { - // Get the current Hijri date - - - HijriDatePickerButton() -} - -@Preview(showBackground = true) -@Composable -fun PreviewHeaderSection() { - HeaderSection(IslamicCalendar(1446, 6, 9)){ - // showYearSelection = true // When the year is clicked, show the year selection screen - } - - -} - -@Preview(showBackground = true) -@Composable -fun PreviewFooterSection() { - FooterSection( - nextMonthName = "Rajab", - onConfirm = {}, - onCancel = {} - ) -} - -@Preview(showBackground = true) -@Composable -fun PreviewYearSelectionScreen() { -// YearSelectionScreen( -// selectedYear = 1446, -// onYearSelected = {} -// ) -} - -@Preview(showBackground = true) -@Composable -fun PreviewHijriDatePickerDialogWithThreeSections() { - val daysInMonth = getHijriDaysInMonth(1446, 0) // Muharram in 1446 - println("Days in Muharram 1446: $daysInMonth") - - HijriCalendarDataCache.initializeForYear(1446) - - HijriDatePickerDialogWithThreeSections( - initialYear = 1446, - initialMonth = 2, - initialDay = 9, - onDateSelected = { _, _, _ -> }, - onConfirm = {}, - onDismissRequest = {}, - initialShowYearSelection = false // Set this to true to show the year selection - - ) -} From 367a94ad9e64c74501ba13790796789547710a97 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 03:18:03 +0300 Subject: [PATCH 10/23] add some updates to maven and gradle --- app/build.gradle.kts | 2 +- build.gradle.kts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 895a5f1..03a4965 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -75,6 +75,6 @@ dependencies { implementation (libs.kotlinx.coroutines.core) implementation (libs.kotlinx.coroutines.android) - implementation ("com.github.mohamedma872:HijriDatePickerPlus:v1.0.1") + // implementation ("com.github.mohamedma872:HijriDatePickerPlus:v1.0.1") } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 394c82a..acd3273 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,6 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.android.library) apply false + id("maven-publish") + } From a74832e930c07ce5a1082d2cb9412bb06eab5782 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 03:54:53 +0300 Subject: [PATCH 11/23] add library as project to main app --- HijriDatePickerLib/build.gradle.kts | 19 ++- app/build.gradle.kts | 9 +- .../MainActivity.kt | 8 +- .../HijriDatePickerPlusApplication/Utils.kt | 123 ------------------ .../ui/theme/Color.kt | 11 -- .../ui/theme/Theme.kt | 57 -------- .../ui/theme/Type.kt | 34 ----- 7 files changed, 15 insertions(+), 246 deletions(-) delete mode 100644 app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt delete mode 100644 app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Color.kt delete mode 100644 app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Theme.kt delete mode 100644 app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Type.kt diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 2018395..04c41ba 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -31,31 +31,30 @@ android { kotlinOptions { jvmTarget = "1.8" } + buildFeatures { + compose = true + } + composeOptions { + kotlinCompilerExtensionVersion = "1.5.1" + } } + dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) - implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) - testImplementation(libs.junit) - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.androidx.espresso.core) - androidTestImplementation(platform(libs.androidx.compose.bom)) - androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation(libs.ummalqura.calendar) implementation( libs.material3) implementation (libs.material) implementation (libs.androidx.lifecycle.runtime.ktx.v231) implementation (libs.androidx.foundation) implementation (libs.android.joda) - implementation (libs.kotlinx.coroutines.core) - implementation (libs.kotlinx.coroutines.android) -} \ No newline at end of file +} + diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 03a4965..2bd5a14 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,14 +66,7 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation(libs.ummalqura.calendar) - implementation( libs.material3) - implementation (libs.material) - implementation (libs.androidx.lifecycle.runtime.ktx.v231) - implementation (libs.androidx.foundation) - implementation (libs.android.joda) - implementation (libs.kotlinx.coroutines.core) - implementation (libs.kotlinx.coroutines.android) + implementation(project(":HijriDatePickerLib")) // implementation ("com.github.mohamedma872:HijriDatePickerPlus:v1.0.1") diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index c7f5f75..47627ef 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.sp import androidx.compose.ui.window.Dialog +import com.sdody.hijridatepickerpluslib.HijriDatePickerButton import java.util.Calendar class MainActivity : ComponentActivity() { @@ -36,11 +37,12 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) // Initialize Hijri calendar data for the selected year - println("Days in Muharram: ${getHijriDaysInMonth(1309, 0)}") - println("Days in Safar: ${getHijriDaysInMonth(1309, 1)}") + // println("Days in Muharram: ${getHijriDaysInMonth(1309, 0)}") + // println("Days in Safar: ${getHijriDaysInMonth(1309, 1)}") setContent { - // HijriDatePickerButton() + + HijriDatePickerButton() // Example of how you can trigger the date picker from anywhere /* showHijriDatePicker( diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt deleted file mode 100644 index 8d9ba18..0000000 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/Utils.kt +++ /dev/null @@ -1,123 +0,0 @@ -package com.sdody.HijriDatePickerPlusApplication - -import android.icu.util.IslamicCalendar -import java.util.Calendar - -// Helper function to get weekday name -fun getWeekday(islamicCalendar: IslamicCalendar): String { - return when (islamicCalendar.get(Calendar.DAY_OF_WEEK)) { - Calendar.SUNDAY -> "Sunday" - Calendar.MONDAY -> "Monday" - Calendar.TUESDAY -> "Tuesday" - Calendar.WEDNESDAY -> "Wednesday" - Calendar.THURSDAY -> "Thursday" - Calendar.FRIDAY -> "Friday" - Calendar.SATURDAY -> "Saturday" - else -> "" - } -} - -fun getHijriMonthAbbr(month: Int): String { - return when (month) { - 0 -> "MUH" - 1 -> "SAF" - 2 -> "RAB-I" - 3 -> "RAB-II" - 4 -> "JUM-I" - 5 -> "JUM-II" - 6 -> "RAJ" - 7 -> "SHA" - 8 -> "RAM" - 9 -> "SHAW" - 10 -> "DHU-Q" - 11 -> "DHU-H" - else -> "" - } -} - -fun getHijriMonthName(month: Int): String { - return when (month % 12) { // Handle month overflow - 0 -> "Muharram" - 1 -> "Safar" - 2 -> "Rabi' al-Awwal" - 3 -> "Rabi' al-Thani" - 4 -> "Jumada al-Awwal" - 5 -> "Jumada al-Thani" - 6 -> "Rajab" - 7 -> "Sha'ban" - 8 -> "Ramadan" - 9 -> "Shawwal" - 10 -> "Dhu al-Qi'dah" - 11 -> "Dhu al-Hijjah" - else -> "" - } -} - -fun getHijriDaysInMonth(year: Int, month: Int): Int { - return try { - val hijriCalendar = IslamicCalendar(year, month, 1) - hijriCalendar.add(Calendar.MONTH, 1) - hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) - hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) - hijriCalendar.get(Calendar.DAY_OF_MONTH) - } catch (e: Exception) { - 30 // Default to 30 days if there's an error - } -} - - -object HijriCalendarDataCache { - - // Cache days for each year separately, with each year holding month-to-days mapping - private val cachedYearlyMonthDays = mutableMapOf>() // Changed to store Int instead of List - - // Precompute all the months and their number of days for the given year - fun initializeForYear(year: Int) { - if (cachedYearlyMonthDays[year] == null) { - cachedYearlyMonthDays[year] = mutableMapOf() - for (month in 0..11) { - cachedYearlyMonthDays[year]?.set(month, getDaysInHijriMonth(year, month)) - } - } - } - - // Retrieve cached number of days for a given year and month, and calculate if not cached - fun getDaysForMonth(year: Int, month: Int): Int { - // Check if the year is cached - if (cachedYearlyMonthDays[year] == null) { - initializeForYear(year) // Initialize the year if not already cached - } - // Check if the month is cached - return cachedYearlyMonthDays[year]?.get(month) ?: getDaysInHijriMonth(year, month) - } - - // Compute the number of days in a Hijri month and cache it - private fun getDaysInHijriMonth(year: Int, month: Int): Int { - // Check if the year is already cached - if (cachedYearlyMonthDays[year] == null) { - cachedYearlyMonthDays[year] = mutableMapOf() // Initialize the map for this year if not present - } - - // Check if the month is already cached - val cachedDays = cachedYearlyMonthDays[year]?.get(month) - if (cachedDays != null) { - return cachedDays // Return cached number of days if available - } - - // If not cached, calculate the number of days in the month - return try { - val hijriCalendar = IslamicCalendar(year, month, 1) - hijriCalendar.add(Calendar.MONTH, 1) - hijriCalendar.set(Calendar.DAY_OF_MONTH, 1) - hijriCalendar.add(Calendar.DAY_OF_MONTH, -1) - val daysInMonth = hijriCalendar.get(Calendar.DAY_OF_MONTH) - - // Cache the result for future use - cachedYearlyMonthDays[year]?.put(month, daysInMonth) - - daysInMonth // Return the calculated number of days - } catch (e: Exception) { - 30 // Default to 30 days if there's an error - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Color.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Color.kt deleted file mode 100644 index 82ad55f..0000000 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Color.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.sdody.HijriDatePickerPlusApplication.ui.theme - -import androidx.compose.ui.graphics.Color - -val Purple80 = Color(0xFFD0BCFF) -val PurpleGrey80 = Color(0xFFCCC2DC) -val Pink80 = Color(0xFFEFB8C8) - -val Purple40 = Color(0xFF6650a4) -val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Theme.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Theme.kt deleted file mode 100644 index b47bd68..0000000 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Theme.kt +++ /dev/null @@ -1,57 +0,0 @@ -package com.sdody.HijriDatePickerPlusApplication.ui.theme - -import android.os.Build -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.darkColorScheme -import androidx.compose.material3.dynamicDarkColorScheme -import androidx.compose.material3.dynamicLightColorScheme -import androidx.compose.material3.lightColorScheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalContext - -private val DarkColorScheme = darkColorScheme( - primary = Purple80, - secondary = PurpleGrey80, - tertiary = Pink80 -) - -private val LightColorScheme = lightColorScheme( - primary = Purple40, - secondary = PurpleGrey40, - tertiary = Pink40 - - /* Other default colors to override - background = Color(0xFFFFFBFE), - surface = Color(0xFFFFFBFE), - onPrimary = Color.White, - onSecondary = Color.White, - onTertiary = Color.White, - onBackground = Color(0xFF1C1B1F), - onSurface = Color(0xFF1C1B1F), - */ -) - -@Composable -fun MyApplicationTheme( - darkTheme: Boolean = isSystemInDarkTheme(), - // Dynamic color is available on Android 12+ - dynamicColor: Boolean = true, - content: @Composable () -> Unit -) { - val colorScheme = when { - dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { - val context = LocalContext.current - if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) - } - - darkTheme -> DarkColorScheme - else -> LightColorScheme - } - - MaterialTheme( - colorScheme = colorScheme, - typography = Typography, - content = content - ) -} \ No newline at end of file diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Type.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Type.kt deleted file mode 100644 index 5db5b25..0000000 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/ui/theme/Type.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.sdody.HijriDatePickerPlusApplication.ui.theme - -import androidx.compose.material3.Typography -import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.sp - -// Set of Material typography styles to start with -val Typography = Typography( - bodyLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 16.sp, - lineHeight = 24.sp, - letterSpacing = 0.5.sp - ) - /* Other default text styles to override - titleLarge = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Normal, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp - ), - labelSmall = TextStyle( - fontFamily = FontFamily.Default, - fontWeight = FontWeight.Medium, - fontSize = 11.sp, - lineHeight = 16.sp, - letterSpacing = 0.5.sp - ) - */ -) \ No newline at end of file From 5adb3189dcb91a0bad65503df52794d59241426d Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 04:02:14 +0300 Subject: [PATCH 12/23] add MavenPublication to lib --- HijriDatePickerLib/build.gradle.kts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 04c41ba..11cb794 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -57,4 +57,15 @@ dependencies { implementation (libs.androidx.foundation) implementation (libs.android.joda) } - +afterEvaluate { + publishing { + publications { + create("maven") { + from(components["release"]) + groupId = "com.sdody" + artifactId = "hijridatepickerlib" + version = "1.0.0" // You can update this version as needed + } + } + } +} \ No newline at end of file From 0eec7de207c403138ea6a366c811925dc55cd1f4 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 04:45:44 +0300 Subject: [PATCH 13/23] update groupId , artifactId --- HijriDatePickerLib/build.gradle.kts | 2 +- app/build.gradle.kts | 4 ++-- build.gradle.kts | 3 +-- settings.gradle.kts | 1 + 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 11cb794..bf626c9 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -62,7 +62,7 @@ afterEvaluate { publications { create("maven") { from(components["release"]) - groupId = "com.sdody" + groupId = "com.github.mohamedma872" artifactId = "hijridatepickerlib" version = "1.0.0" // You can update this version as needed } diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2bd5a14..b10089c 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,8 +66,8 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation(project(":HijriDatePickerLib")) + // implementation(project(":HijriDatePickerLib")) - // implementation ("com.github.mohamedma872:HijriDatePickerPlus:v1.0.1") + implementation ("com.github.mohamedma872:HijriDatePickerLib:1.0.0") } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index acd3273..82c2e33 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,5 +4,4 @@ plugins { alias(libs.plugins.jetbrains.kotlin.android) apply false alias(libs.plugins.android.library) apply false id("maven-publish") - -} +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index ca6bfad..85309ee 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -18,6 +18,7 @@ dependencyResolutionManagement { mavenCentral() maven { url = uri("https://jitpack.io") } } + } rootProject.name = "My Application" From 1f9422bf3185253d62866b675eb3d07cee05bad9 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 05:12:54 +0300 Subject: [PATCH 14/23] update groupId , artifactId --- HijriDatePickerLib/build.gradle.kts | 3 --- 1 file changed, 3 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index bf626c9..876ed49 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -62,9 +62,6 @@ afterEvaluate { publications { create("maven") { from(components["release"]) - groupId = "com.github.mohamedma872" - artifactId = "hijridatepickerlib" - version = "1.0.0" // You can update this version as needed } } } From 98e814d36f2293a684ca80072a31803c5d33bc25 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 05:12:54 +0300 Subject: [PATCH 15/23] update gradle --- HijriDatePickerLib/build.gradle.kts | 9 +++------ app/build.gradle.kts | 6 +++--- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index bf626c9..f8aaa1e 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -25,11 +25,11 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } buildFeatures { compose = true @@ -62,9 +62,6 @@ afterEvaluate { publications { create("maven") { from(components["release"]) - groupId = "com.github.mohamedma872" - artifactId = "hijridatepickerlib" - version = "1.0.0" // You can update this version as needed } } } diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b10089c..b87ebaf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -30,11 +30,11 @@ android { } } compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 } kotlinOptions { - jvmTarget = "1.8" + jvmTarget = "11" } buildFeatures { compose = true From 9bb763e33276e8c20dcd814d6f3916033074997c Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 05:47:06 +0300 Subject: [PATCH 16/23] Merge remote-tracking branch 'origin/Development' into Development --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b250ca9..fa42a58 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,8 +66,8 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - // implementation(project(":HijriDatePickerLib")) + implementation(project(":HijriDatePickerLib")) - implementation ("com.github.mohamedma872:HijriDatePickerLib:1.0.0") + // implementation ("com.github.mohamedma872:HijriDatePickerLib:1.0.0") } \ No newline at end of file From b2ff613591a5949cbc95388316c263ec95746da2 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 05:55:40 +0300 Subject: [PATCH 17/23] stable release --- app/build.gradle.kts | 4 +-- .../MainActivity.kt | 30 ++----------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fa42a58..3fbf4d5 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -66,8 +66,8 @@ dependencies { androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) - implementation(project(":HijriDatePickerLib")) + // implementation(project(":HijriDatePickerLib")) - // implementation ("com.github.mohamedma872:HijriDatePickerLib:1.0.0") + implementation ("com.github.mohamedma872:HijriDatePickerPlus:Development-SNAPSHOT") } \ No newline at end of file diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index ec5807a..0fab766 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -1,36 +1,10 @@ package com.sdody.HijriDatePickerPlusApplication -import android.icu.util.IslamicCalendar + import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.* -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.grid.GridCells -import androidx.compose.foundation.lazy.grid.LazyVerticalGrid -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog import com.sdody.hijridatepickerpluslib.HijriDatePickerButton -import java.util.Calendar + class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { From 15608e3b5d5d15e1488d2ca24b7f895051c06ee4 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sat, 7 Sep 2024 06:18:34 +0300 Subject: [PATCH 18/23] Update README.md Signed-off-by: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> --- README.md | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/README.md b/README.md index 4f5f472..c8e07d3 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,84 @@ Unlike the Umm Al-Qura calendar, which is specific to Saudi Arabia and has known 3. Build and run the project on an Android device or emulator 4. Incorporate the Hijri date picker into your project by copying the necessary components from the codebase + + +## How to Use the Library + +To use **HijriDatePickerPlus** in your Android project, follow these steps: + +### 1. Add the Dependency + +First, add the dependency to your project's `build.gradle` file. Make sure your project is set up to use JitPack by adding the JitPack repository in your `settings.gradle` or `build.gradle` (for Gradle version catalog users, include this in your version catalog file): + +```groovy +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + maven { url = uri("https://jitpack.io") } + } +} +``` + +Then, add the following to your app-level `build.gradle` file under `dependencies`: + +```groovy +dependencies { + implementation 'com.github.mohamedma872:HijriDatePickerPlus:Tag' +} +``` + +Replace `Tag` with the latest version, which you can find [here](https://jitpack.io/#mohamedma872/HijriDatePickerPlus). + +### 2. Initialize and Display the Hijri Date Picker + +To use the date picker, simply call the **HijriDatePickerPlus** component in your Composable function. Here's an example of how to integrate it into your app: + +```kotlin +@Composable +fun ShowHijriDatePicker() { +// you can use that : + + HijriDatePickerButton() + +OR + showHijriDatePicker( + initialYear = 1446, // Pass the initial year, e.g., current Hijri year + initialMonth = 1, // Initial month + initialDay = 10, // Initial day + onDateSelected = { year, month, day -> + // Handle date selected (year, month, day) + println("Selected Date: $day-${getHijriMonthName(month)}-$year") + }, + onConfirm = { + // Handle confirm click + println("Date Picker Confirmed") + }, + onDismissRequest = { + // Handle dismiss + println("Date Picker Dismissed") + } + ) +} +``` +```kotlin +// Get the current Hijri date + val currentHijriCalendar = IslamicCalendar() + val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) + val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) + val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) +``` +### 3. Customize the Picker + +You can modify the picker to suit your design needs by adjusting properties such as: + +- **Year/Month/Day Display**: You can modify the visual appearance by changing the text size, colors, and layout in the `HeaderSection`, `YearSelectionScreen`, and `FooterSection` components. +- **Hijri Calendar**: The library uses the `IslamicCalendar` class for date calculations. You can directly interact with this class if you need further customization or region-specific adjustments. + + + ## Fixes and Solutions HijriDatePickerPlus implements a critical fix for date validation in the Hijri calendar, ensuring that selecting a day beyond the valid number of days in a month (e.g., selecting the 30th day in a month with only 29 days) doesn't cause the app to crash. The picker automatically adjusts the selected day to the correct number of days in each month. From 7dd3b53ef30f9b12fe540f561058c99256704b90 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:51:06 +0300 Subject: [PATCH 19/23] Update README.md Signed-off-by: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> --- README.md | 96 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 52 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index c8e07d3..8d649a0 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,30 @@ +Here’s the updated README with the additional section mentioning the `getIslamicCalendar` function and how to get the current date based on the calendar type: +--- # HijriDatePickerPlus -**HijriDatePickerPlus** is an advanced Android date picker built using Jetpack Compose, designed for selecting dates in the Hijri (Islamic) calendar. The picker now uses the widely supported `IslamicCalendar` class, which offers flexibility and broader compatibility across regions, although it is not specific to Saudi Arabia like Umm Al-Qura. +**HijriDatePickerPlus** is an advanced Android date picker built using Jetpack Compose, designed for selecting dates in the Hijri (Islamic) calendar. The picker now uses the widely supported `IslamicCalendar` class, offering flexibility and compatibility across various regions, with support for the "umalqura", "civil", or "islamic" calendar types. ## Features -- Full support for the **Islamic Calendar** system -- Custom date picker interface using Jetpack Compose -- Year selection with smooth scrolling and customizable font sizes -- Day picker automatically adjusts for the correct number of days in each Hijri month -- Ensures the app doesn't crash when selecting an invalid date in a Hijri month -- Lightweight and responsive UI for a smooth user experience +- Full support for **Islamic Calendar** systems, including **Umm Al-Qura**, **Islamic Civil**, and **General Islamic**. +- Custom date picker interface using Jetpack Compose. +- Year selection with smooth scrolling and customizable font sizes. +- Day picker automatically adjusts for the correct number of days in each Hijri month. +- Ensures the app doesn't crash when selecting an invalid date in a Hijri month. +- Lightweight and responsive UI for a smooth user experience. ## Why Use IslamicCalendar? -Unlike the Umm Al-Qura calendar, which is specific to Saudi Arabia and has known issues in some cases, **IslamicCalendar** provides broader support for the global Muslim community. It offers better flexibility and accuracy for most use cases and regions, making it a more reliable option for international users who may not need Umm Al-Qura specificity. +While the **Umm Al-Qura** calendar is specific to Saudi Arabia and suitable for regional use, the **IslamicCalendar** provides broader support globally. It offers flexibility for international users with support for various calendar types, including **Islamic Civil** and **General Islamic** calendars. ## How to Use 1. Clone the repository: `git clone https://github.com/YourUsername/HijriDatePickerPlus.git` -2. Open the project in Android Studio -3. Build and run the project on an Android device or emulator -4. Incorporate the Hijri date picker into your project by copying the necessary components from the codebase - - +2. Open the project in Android Studio. +3. Build and run the project on an Android device or emulator. +4. Incorporate the Hijri date picker into your project by copying the necessary components from the codebase. ## How to Use the Library @@ -62,49 +62,54 @@ To use the date picker, simply call the **HijriDatePickerPlus** component in you ```kotlin @Composable fun ShowHijriDatePicker() { -// you can use that : - - HijriDatePickerButton() - -OR + // Example of how to trigger the date picker using different calendar types showHijriDatePicker( - initialYear = 1446, // Pass the initial year, e.g., current Hijri year - initialMonth = 1, // Initial month - initialDay = 10, // Initial day - onDateSelected = { year, month, day -> - // Handle date selected (year, month, day) - println("Selected Date: $day-${getHijriMonthName(month)}-$year") - }, - onConfirm = { - // Handle confirm click - println("Date Picker Confirmed") - }, - onDismissRequest = { - // Handle dismiss - println("Date Picker Dismissed") - } - ) + initialYear = 1446, // Pass the initial year, e.g., current Hijri year + initialMonth = 1, // Initial month + initialDay = 10, // Initial day + onDateSelected = { year, month, day -> + // Handle date selected (year, month, day) + println("Selected Date: $day-${getHijriMonthName(month)}-$year") + }, + onConfirm = { year, month, day -> + // Handle the final confirmed date + println("Confirmed Date: $day-${getHijriMonthName(month)}-$year") + }, + onDismissRequest = { + // Handle the dismiss action + println("Date Picker Dismissed") + }, + calendarType = "umalqura" // Use "umalqura", "civil", or "islamic" + ) } ``` -```kotlin -// Get the current Hijri date - val currentHijriCalendar = IslamicCalendar() - val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) - val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) - val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) -``` + ### 3. Customize the Picker You can modify the picker to suit your design needs by adjusting properties such as: -- **Year/Month/Day Display**: You can modify the visual appearance by changing the text size, colors, and layout in the `HeaderSection`, `YearSelectionScreen`, and `FooterSection` components. -- **Hijri Calendar**: The library uses the `IslamicCalendar` class for date calculations. You can directly interact with this class if you need further customization or region-specific adjustments. +- **Year/Month/Day Display**: Modify the visual appearance by changing the text size, colors, and layout in the `HeaderSection`, `YearSelectionScreen`, and `FooterSection` components. +- **Hijri Calendar**: The library uses the `IslamicCalendar` class for date calculations. You can directly interact with this class for customization or region-specific adjustments. + +### Getting the Current Date Using the Desired Calendar Type +You can easily get the current date based on the **Umm Al-Qura**, **Islamic Civil**, or **General Islamic** calendar using the following function: +For example, to get the current date for the selected calendar type: + +```kotlin +// Get the current Hijri date using the desired calendar type +val currentHijriCalendar = getIslamicCalendar("umalqura") +val currentHijriYear = currentHijriCalendar.get(Calendar.YEAR) +val currentHijriMonth = currentHijriCalendar.get(Calendar.MONTH) +val currentHijriDay = currentHijriCalendar.get(Calendar.DAY_OF_MONTH) + +println("Current Hijri Date: $currentHijriDay-${getHijriMonthName(currentHijriMonth)}-$currentHijriYear") +``` ## Fixes and Solutions -HijriDatePickerPlus implements a critical fix for date validation in the Hijri calendar, ensuring that selecting a day beyond the valid number of days in a month (e.g., selecting the 30th day in a month with only 29 days) doesn't cause the app to crash. The picker automatically adjusts the selected day to the correct number of days in each month. +**HijriDatePickerPlus** implements a critical fix for date validation in the Hijri calendar, ensuring that selecting a day beyond the valid number of days in a month (e.g., selecting the 30th day in a month with only 29 days) doesn't cause the app to crash. The picker automatically adjusts the selected day to the correct number of days in each month. ## Installation @@ -142,3 +147,6 @@ For any questions or support regarding this project, you can contact the project [![](https://jitpack.io/v/mohamedma872/HijriDatePickerPlus.svg)](https://jitpack.io/#mohamedma872/HijriDatePickerPlus) +--- + +This updated README includes the mention of the `getIslamicCalendar` function and an example of how to use it to get the current Hijri date. Let me know if you need any further adjustments! From 40dc98f4495929d01f7b718946e0683163a5062e Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Sun, 8 Sep 2024 16:14:54 +0300 Subject: [PATCH 20/23] add preview for each function --- .../sdody/hijridatepickerlib/FooterSection.kt | 11 ++++++++++ .../sdody/hijridatepickerlib/HeaderSection.kt | 17 ++++++++++++++ .../HijriDatePickerButton.kt | 8 +++++++ .../HijriDatePickerDialogWithThreeSections.kt | 20 +++++++++++++++++ .../hijridatepickerlib/MonthGridWithDays.kt | 15 +++++++++++++ .../hijridatepickerlib/YearSelectionScreen.kt | 13 +++++++++++ .../hijridatepickerlib/showHijriDatePicker.kt | 22 +++++++++++++++++++ 7 files changed, 106 insertions(+) diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt index 3096c0f..1e47d95 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/FooterSection.kt @@ -10,6 +10,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -38,3 +39,13 @@ fun FooterSection(nextMonthName: String, onConfirm: () -> Unit, onCancel: () -> } } } + +@Preview(showBackground = true) +@Composable +fun PreviewFooterSection() { + FooterSection( + nextMonthName = "Safar", + onConfirm = { /* Handle confirm action in preview */ }, + onCancel = { /* Handle cancel action in preview */ } + ) +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt index 1d87707..12984dc 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HeaderSection.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -44,3 +45,19 @@ fun HeaderSection(calendar: Calendar, onYearClick: () -> Unit) { ) } } + +@Preview(showBackground = true) +@Composable +fun PreviewHeaderSection() { + // Creating an instance of IslamicCalendar for preview purposes + val calendar = IslamicCalendar().apply { + set(Calendar.YEAR, 1445) + set(Calendar.MONTH, 1) // Safar + set(Calendar.DAY_OF_MONTH, 5) + } + + // Preview the HeaderSection with a mock IslamicCalendar and a simple onYearClick action + HeaderSection(calendar = calendar, onYearClick = { + // Handle year click in preview + }) +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt index b49bcb2..5ef1d09 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -85,4 +86,11 @@ fun HijriDatePickerButton( "umalqura" // "umalqura", "civil", or "islamic" ) } +} + +@Preview(showBackground = true) +@Composable +fun PreviewHijriDatePickerButton() { + // Preview the HijriDatePickerButton with "umalqura" as calendar type + HijriDatePickerButton(calendarType = "umalqura") } \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt index 4b5278b..14de701 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog @@ -107,3 +108,22 @@ fun HijriDatePickerDialogWithThreeSections( } } +@Preview(showBackground = true) +@Composable +fun PreviewHijriDatePickerDialogWithThreeSections() { + HijriDatePickerDialogWithThreeSections( + initialYear = 1445, // Initial Hijri year + initialMonth = 1, // Safar (month index starts at 0) + initialDay = 5, // 5th day of Safar + onDateSelected = { year, month, day -> + // Handle date selection (preview action) + }, + onConfirm = { + // Handle confirm action (preview action) + }, + onDismissRequest = { + // Handle dismiss action (preview action) + }, + calendarType = "umalqura" // Simulate the "umalqura" calendar type for preview + ) +} \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt index 1e6ccc1..ba6f449 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/MonthGridWithDays.kt @@ -20,6 +20,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -79,4 +80,18 @@ fun MonthGridWithDays( } } } +} + +@Preview(showBackground = true) +@Composable +fun PreviewMonthGridWithDays() { + MonthGridWithDays( + selectedYear = 1445, // Example year + onDaySelected = { year, month, day -> + // Handle day selection (preview action) + }, + preselectedMonth = 1, // Safar (0-indexed month) + preselectedDay = 5, // Preselected day + calendarType = "umalqura" // Calendar type for preview + ) } \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt index 8ee5a0b..c47c12a 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/YearSelectionScreen.kt @@ -14,6 +14,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -57,4 +58,16 @@ fun YearSelectionScreen( ) } } +} + +@Preview(showBackground = true) +@Composable +fun PreviewYearSelectionScreen() { + YearSelectionScreen( + selectedYear = 1445, // Preselected year + onYearSelected = { year -> + // Handle year selection (preview action) + }, + currentYear = 1445 // Scroll to this year by default + ) } \ No newline at end of file diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt index b0b01f9..87af81a 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt @@ -5,6 +5,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue +import androidx.compose.ui.tooling.preview.Preview // Example of how you can trigger the date picker from anywhere /* showHijriDatePicker( @@ -70,3 +71,24 @@ fun showHijriDatePicker( ) } } + +@Preview(showBackground = true) +@Composable +fun PreviewHijriDatePicker() { + // Preview the Hijri Date Picker with some predefined values + showHijriDatePicker( + initialYear = 1445, // Initial year in Hijri calendar + initialMonth = 1, // Safar (0-indexed month) + initialDay = 1, // 1st day of Safar + onDateSelected = { year, month, day -> + // Handle date selection (preview action) + }, + onConfirm = { year, month, day -> + // Handle confirmation (preview action) + }, + onDismissRequest = { + // Handle dismissal (preview action) + }, + calendarType = "umalqura" // Calendar type for preview + ) +} \ No newline at end of file From 1884918ddbcf84e89b56412f2248413c21bf9b4d Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:05:35 +0300 Subject: [PATCH 21/23] change min sdk from 28 to 26 --- HijriDatePickerLib/build.gradle.kts | 2 +- app/build.gradle.kts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 5c6507a..29d0f06 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -9,7 +9,7 @@ android { compileSdk = 34 defaultConfig { - minSdk = 28 + minSdk = 26 testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") diff --git a/app/build.gradle.kts b/app/build.gradle.kts index edd5438..f82dc33 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -67,6 +67,7 @@ dependencies { debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) implementation(project(":HijriDatePickerLib")) + //implementation ("com.github.mohamedma872:HijriDatePickerPlus:Development-SNAPSHOT") } \ No newline at end of file From fa88ead67cd0e921fb4be700172b4e8668c77102 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Thu, 26 Sep 2024 16:59:02 +0300 Subject: [PATCH 22/23] delete the library of live cycle data --- HijriDatePickerLib/build.gradle.kts | 4 ++-- app/build.gradle.kts | 1 - gradle/libs.versions.toml | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/HijriDatePickerLib/build.gradle.kts b/HijriDatePickerLib/build.gradle.kts index 29d0f06..63857e8 100644 --- a/HijriDatePickerLib/build.gradle.kts +++ b/HijriDatePickerLib/build.gradle.kts @@ -44,7 +44,7 @@ android { dependencies { implementation(libs.androidx.core.ktx) - implementation(libs.androidx.lifecycle.runtime.ktx) + // implementation(libs.androidx.lifecycle.runtime.ktx) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) @@ -54,7 +54,7 @@ dependencies { debugImplementation(libs.androidx.ui.test.manifest) implementation( libs.material3) implementation (libs.material) - implementation (libs.androidx.lifecycle.runtime.ktx.v231) + // implementation (libs.androidx.lifecycle.runtime.ktx.v231) implementation (libs.androidx.foundation) implementation (libs.android.joda) } diff --git a/app/build.gradle.kts b/app/build.gradle.kts index f82dc33..e66132b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -52,7 +52,6 @@ android { dependencies { implementation(libs.androidx.core.ktx) - implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec7ae7e..80a4a25 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -26,7 +26,6 @@ androidx-lifecycle-runtime-ktx-v231 = { module = "androidx.lifecycle:lifecycle-r junit = { group = "junit", name = "junit", version.ref = "junit" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" } -androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" } androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" } androidx-ui = { group = "androidx.compose.ui", name = "ui" } From 96f86b9cd8afc14be21f97be3d516825bb327d53 Mon Sep 17 00:00:00 2001 From: mohammed Elsdody <31186483+mohamedma872@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:34:16 +0300 Subject: [PATCH 23/23] fix some issues --- .../HijriDatePickerButton.kt | 2 +- .../HijriDatePickerDialogWithThreeSections.kt | 43 ++++++++++++------- .../hijridatepickerlib/showHijriDatePicker.kt | 33 ++++++-------- .../MainActivity.kt | 15 +++++-- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt index 5ef1d09..5f1fa83 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerButton.kt @@ -76,7 +76,7 @@ fun HijriDatePickerButton( preselectedMonth.value = month preselectedDay.value = day }, - onConfirm = { + onConfirm = { year, month, day -> showDialog = false // Close the dialog when Confirm is clicked }, onDismissRequest = { diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt index 14de701..0c051b7 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/HijriDatePickerDialogWithThreeSections.kt @@ -27,8 +27,8 @@ fun HijriDatePickerDialogWithThreeSections( initialYear: Int, initialMonth: Int, initialDay: Int, - onDateSelected: (Int, Int, Int) -> Unit, - onConfirm: () -> Unit, + onDateSelected: (Int, Int, Int) -> Unit, // Call this when date is selected + onConfirm: (Int, Int, Int) -> Unit, // Pass the selected year, month, day onDismissRequest: () -> Unit, initialShowYearSelection: Boolean = true, // Always show year selection when opening the dialog calendarType: String @@ -39,25 +39,30 @@ fun HijriDatePickerDialogWithThreeSections( var showYearSelection by remember { mutableStateOf(initialShowYearSelection) } // Ensure selected day is valid for the selected month - val daysInMonth = getHijriDaysInMonth(selectedYear, selectedMonth,calendarType) + val daysInMonth = getHijriDaysInMonth(selectedYear, selectedMonth, calendarType) if (selectedDay > daysInMonth) { selectedDay = daysInMonth } Dialog(onDismissRequest = onDismissRequest) { Surface( - modifier = Modifier.fillMaxWidth().heightIn(min = 400.dp, max = 500.dp).padding(16.dp), + modifier = Modifier + .fillMaxWidth() + .heightIn(min = 400.dp, max = 500.dp) + .padding(16.dp), shape = MaterialTheme.shapes.medium ) { Column( - modifier = Modifier.fillMaxWidth().background(Color.White) + modifier = Modifier + .fillMaxWidth() + .background(Color.White) ) { // Header section with the selected date val calendar = getIslamicCalendar(calendarType) - // Set the specific year, month, and day on the calendar instance calendar.set(Calendar.YEAR, selectedYear) calendar.set(Calendar.MONTH, selectedMonth) calendar.set(Calendar.DAY_OF_MONTH, selectedDay) + // Pass the callback to trigger year selection HeaderSection(calendar = calendar) { showYearSelection = true // Toggle to show year selection when the year is clicked @@ -78,7 +83,9 @@ fun HijriDatePickerDialogWithThreeSections( } else { // Month Grid with Days Section Box( - modifier = Modifier.weight(1f).fillMaxWidth() + modifier = Modifier + .weight(1f) + .fillMaxWidth() ) { MonthGridWithDays( selectedYear = selectedYear, @@ -86,7 +93,7 @@ fun HijriDatePickerDialogWithThreeSections( selectedYear = year selectedMonth = month selectedDay = day - onDateSelected(year, month, day) + onDateSelected(year, month, day) // Update selected date }, preselectedMonth = selectedMonth, // Pass the preselected month preselectedDay = selectedDay, // Pass the preselected day @@ -100,14 +107,17 @@ fun HijriDatePickerDialogWithThreeSections( // Footer with Confirm and Cancel buttons FooterSection( nextMonthName = getHijriMonthName(selectedMonth), - onConfirm = onConfirm, - onCancel = onDismissRequest + onConfirm = { + onConfirm(selectedYear, selectedMonth, selectedDay) // Pass the selected date when confirmed + }, + onCancel = onDismissRequest // Handle dismissal when cancel is clicked ) } } } } + @Preview(showBackground = true) @Composable fun PreviewHijriDatePickerDialogWithThreeSections() { @@ -116,14 +126,17 @@ fun PreviewHijriDatePickerDialogWithThreeSections() { initialMonth = 1, // Safar (month index starts at 0) initialDay = 5, // 5th day of Safar onDateSelected = { year, month, day -> - // Handle date selection (preview action) + // Simulate the date selection in the preview (just log or print) + println("Date Selected in Preview: $day-${getHijriMonthName(month)}-$year") }, - onConfirm = { - // Handle confirm action (preview action) + onConfirm = { year, month, day -> + // Simulate confirmation action in the preview + println("Date Confirmed in Preview: $day-${getHijriMonthName(month)}-$year") }, onDismissRequest = { - // Handle dismiss action (preview action) + // Simulate dismiss action in the preview + println("Dialog Dismissed in Preview") }, calendarType = "umalqura" // Simulate the "umalqura" calendar type for preview ) -} \ No newline at end of file +} diff --git a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt index 87af81a..24ccf66 100644 --- a/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt +++ b/HijriDatePickerLib/src/main/java/com/sdody/hijridatepickerlib/showHijriDatePicker.kt @@ -37,41 +37,34 @@ fun showHijriDatePicker( onDismissRequest: () -> Unit, calendarType: String ) { - // State for preselected date - val preselectedYear = remember { mutableStateOf(initialYear) } - val preselectedMonth = remember { mutableStateOf(initialMonth) } - val preselectedDay = remember { mutableStateOf(initialDay) } - - // Dialog visibility is controlled outside (no button, it will be triggered by external events) + // The showDialog state is controlled outside, as this Composable doesn't have buttons. var showDialog by remember { mutableStateOf(true) } if (showDialog) { HijriDatePickerDialogWithThreeSections( - initialYear = preselectedYear.value, - initialMonth = preselectedMonth.value, - initialDay = preselectedDay.value, + initialYear = initialYear, // Preselected year from the lifted state + initialMonth = initialMonth, // Preselected month from the lifted state + initialDay = initialDay, // Preselected day from the lifted state onDateSelected = { year, month, day -> - // Update the preselected date for the next opening - preselectedYear.value = year - preselectedMonth.value = month - preselectedDay.value = day - onDateSelected(year, month, day) // Call the provided callback + // Update the selected date in the parent + onDateSelected(year, month, day) }, - onConfirm = { - showDialog = false // Close the dialog when Confirm is clicked + onConfirm = { year, month, day -> + showDialog = false // Close the dialog when Confirm is clicked // Pass the selected date to the confirm callback - onConfirm(preselectedYear.value, preselectedMonth.value, preselectedDay.value) + onConfirm(year, month, day) }, onDismissRequest = { - showDialog = false // Close the dialog when dismissed - onDismissRequest() // Call the dismiss callback + showDialog = false // Close the dialog when dismissed + onDismissRequest() // Call the dismiss callback }, initialShowYearSelection = true, // Always show year selection first - calendarType = calendarType // "umalqura", "civil", or "islamic" + calendarType = calendarType // Calendar type ("umalqura", "civil", or "islamic") ) } } + @Preview(showBackground = true) @Composable fun PreviewHijriDatePicker() { diff --git a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt index 5c698a2..20d9323 100644 --- a/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt +++ b/app/src/main/java/com/sdody/HijriDatePickerPlusApplication/MainActivity.kt @@ -21,18 +21,27 @@ class MainActivity : ComponentActivity() { setContent { // Use "umalqura", "civil", or "islamic" // HijriDatePickerButton(calendarType = "umalqura") + var lastSelectedYear = 1445 + var lastSelectedMonth = 1 + var lastSelectedDay = 1 // Example of how you can trigger the date picker from anywhere showHijriDatePicker( - initialYear = 1445, - initialMonth = 1, - initialDay = 1, + initialYear = lastSelectedYear, + initialMonth = lastSelectedMonth, + initialDay = lastSelectedDay, onDateSelected = { year, month, day -> // Handle date selection changes + lastSelectedYear = year + lastSelectedMonth = month + lastSelectedDay = day println("Selected date: $year-$month-$day") }, onConfirm = { year, month, day -> // Handle the final confirmed date here + lastSelectedYear = year + lastSelectedMonth = month + lastSelectedDay = day println("Confirmed date: $year-$month-$day") }, onDismissRequest = {