Skip to content

Commit

Permalink
added datee and time field
Browse files Browse the repository at this point in the history
  • Loading branch information
aman-alfresco committed Jan 25, 2024
1 parent dad213c commit 625a9d3
Show file tree
Hide file tree
Showing 20 changed files with 395 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import java.util.TimeZone

const val DATE_FORMAT_1 = "yyyy-MM-dd"
const val DATE_FORMAT_2 = "dd-MMM-yyyy"
const val DATE_FORMAT_2_1 = "dd-MM-yyyy"
const val DATE_FORMAT_3 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
const val DATE_FORMAT_4 = "dd MMM yyyy"
const val DATE_FORMAT_5 = "yyyy-MM-dd'T'HH:mm:ss'Z'"
Expand Down
9 changes: 9 additions & 0 deletions component/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ android {
buildFeatures {
viewBinding true
}
buildFeatures { // Enables Jetpack Compose for this module
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.4"
}
}

kapt {
Expand Down Expand Up @@ -40,6 +46,9 @@ dependencies {
implementation libs.epoxy.core
kapt libs.epoxy.processor

implementation libs.ui
implementation libs.activity.compose

// Testing
testImplementation libs.junit
androidTestImplementation libs.androidx.test.core
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,16 @@ package com.alfresco.content.component
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import com.alfresco.content.DATE_FORMAT_2_1
import com.alfresco.content.DATE_FORMAT_6
import com.alfresco.content.data.payloads.FieldType
import com.alfresco.content.data.payloads.FieldsData
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.CompositeDateValidator
import com.google.android.material.datepicker.DateValidatorPointBackward
import com.google.android.material.datepicker.DateValidatorPointForward
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.timepicker.MaterialTimePicker
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
Expand All @@ -29,6 +34,7 @@ data class DatePickerBuilder(
var isFutureDate: Boolean = false,
var onSuccess: DatePickerOnSuccess? = null,
var onFailure: DatePickerOnFailure? = null,
var fieldsData: FieldsData? = null,
) {

private val dateFormatddMMMyy = "dd-MMM-yy"
Expand Down Expand Up @@ -65,25 +71,56 @@ data class DatePickerBuilder(

val constraintsBuilder = CalendarConstraints.Builder()

constraintsBuilder.setValidator(CompositeDateValidator.allOf(getValidators()))
constraintsBuilder.setValidator(CompositeDateValidator.allOf(getValidators(fieldsData)))

val datePicker = MaterialDatePicker.Builder.datePicker().apply {
if (isFrom) {
setTitleText(context.getString(R.string.hint_range_from_date))
if (fieldsData != null) {
setTitleText(fieldsData?.name)
} else {
setTitleText(context.getString(R.string.hint_range_to_date))
if (isFrom) {
setTitleText(context.getString(R.string.hint_range_from_date))
} else {
setTitleText(context.getString(R.string.hint_range_to_date))
}
}
setSelection(getSelectionDate())
setCalendarConstraints(constraintsBuilder.build())
}.build()

datePicker.show(fragmentManager, DatePickerBuilder::class.java.simpleName)

val timePicker = MaterialTimePicker
.Builder()
.setTitleText(fieldsData?.name)
.build()

var stringDateTime = ""
datePicker.addOnPositiveButtonClickListener {
val date = Date(it)
val stringDate = getFormatDate(date)
onSuccess?.invoke(stringDate)
if (fieldsData?.type == FieldType.DATETIME.value()) {
stringDateTime = getFormatDate(date)
timePicker.show(fragmentManager, DatePickerBuilder::class.java.name)
} else if (fieldsData?.type == FieldType.DATE.value()) {
onSuccess?.invoke(getFormatDate(date))
}
}

timePicker.addOnPositiveButtonClickListener {
val hour = timePicker.hour
val minute = timePicker.minute
println("string date $stringDateTime || $hour || $minute")
val combinedDateTime = "$stringDateTime $hour:$minute"
onSuccess?.invoke(combinedDateTime)
}

timePicker.addOnNegativeButtonClickListener {
onFailure?.invoke()
}

timePicker.addOnCancelListener {
onFailure?.invoke()
}

datePicker.addOnCancelListener {
onFailure?.invoke()
}
Expand All @@ -92,27 +129,42 @@ data class DatePickerBuilder(
}
}

private fun getValidators(): ArrayList<CalendarConstraints.DateValidator> {
private fun getValidators(fieldsData: FieldsData? = null): ArrayList<CalendarConstraints.DateValidator> {
val validators: ArrayList<CalendarConstraints.DateValidator> = ArrayList()
var endDate = MaterialDatePicker.todayInUtcMilliseconds()
var requiredEndDate = false
if (isFrom) {
if (toDate.isNotEmpty()) {
toDate.getDateFromString()?.let { date ->
endDate = Date(date.time.plus(addOneDay)).time

if (fieldsData != null) {
fieldsData.minValue?.apply {
this.getDateFromString(getFieldDateFormat(fieldsData))?.let { date ->
validators.add(DateValidatorPointForward.from(date.time))
}
}

fieldsData.maxValue?.apply {
this.getDateFromString(getFieldDateFormat(fieldsData))?.let { date ->
validators.add(DateValidatorPointBackward.before(date.time))
}
requiredEndDate = true
}
} else {
if (fromDate.isNotEmpty()) {
fromDate.getDateFromString()?.let { date ->
validators.add(DateValidatorPointForward.from(date.time))
if (isFrom) {
if (toDate.isNotEmpty()) {
toDate.getDateFromString()?.let { date ->
endDate = Date(date.time.plus(addOneDay)).time
}
requiredEndDate = true
}
} else {
if (fromDate.isNotEmpty()) {
fromDate.getDateFromString()?.let { date ->
validators.add(DateValidatorPointForward.from(date.time))
}
requiredEndDate = !isFutureDate
}
requiredEndDate = !isFutureDate
}
}
if (requiredEndDate) {
validators.add(DateValidatorPointBackward.before(endDate))
if (requiredEndDate) {
validators.add(DateValidatorPointBackward.before(endDate))
}
}

return validators
Expand Down Expand Up @@ -140,8 +192,8 @@ data class DatePickerBuilder(
return SimpleDateFormat(dateFormat, Locale.ENGLISH).format(currentTime)
}

private fun String.getDateFromString(): Date? {
return SimpleDateFormat(dateFormat, Locale.ENGLISH).parse(this)
private fun String.getDateFromString(format: String = dateFormat): Date? {
return SimpleDateFormat(format, Locale.ENGLISH).parse(this)
}

private fun String.getddMMyyyyStringDate(): String? {
Expand All @@ -162,4 +214,12 @@ data class DatePickerBuilder(
calendar[Calendar.YEAR] = splitDate[2].toInt()
return calendar.timeInMillis
}

private fun getFieldDateFormat(fieldsData: FieldsData? = null): String {
return when (fieldsData?.type) {
FieldType.DATETIME.value() -> DATE_FORMAT_6
FieldType.DATE.value() -> DATE_FORMAT_2_1
else -> dateFormat
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ enum class FieldType {
INTEGER,
AMOUNT,
BOOLEAN,
DATETIME,
DATE,
;

fun value() = name.lowercase()
Expand Down
2 changes: 2 additions & 0 deletions process-app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,15 @@ dependencies {
implementation project(':common')
implementation project(':actions')
implementation project(':data')
implementation project(':component')

implementation libs.androidx.core
implementation libs.androidx.appcompat
implementation libs.androidx.lifecycle.runtime
implementation libs.activity.compose
implementation platform(libs.compose.bom)
implementation libs.ui
implementation libs.activity.compose
implementation libs.ui.graphics
implementation libs.ui.tooling.preview
implementation libs.material3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fun NavigationComponent() {
NavHost(navController = navController, startDestination = "first_screen") {
composable("first_screen") {
// Replace with the content of your first fragment
FormFragment(navController = navController)
FormFragment(navController)
}
// Add more composable entries for other fragments in your navigation graph
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,55 @@
package com.alfresco.content.process

import android.os.Bundle
import androidx.activity.ComponentActivity
import android.view.ViewGroup
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.fragment.app.FragmentContainerView
import com.alfresco.content.process.ui.ProcessFormFragment
import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme

class ProcessFormActivity : ComponentActivity() {
class ProcessFormActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AlfrescoBaseTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
NavigationComponent()
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
composeApp()
}
}
}
}

private fun composeApp() {
val fragmentManager = supportFragmentManager
val containerId = resources.getIdentifier("frame_container", "id", packageName)

// Check if the fragment is already added

// Create FragmentContainerView and add it to the activity
val fragmentContainer = FragmentContainerView(this).apply {
id = containerId
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
)
}
setContentView(fragmentContainer)

fragmentManager
.beginTransaction()
.replace(fragmentContainer.id, ProcessFormFragment(), "firstFragment")
.commit()
}
}

@Preview(showBackground = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
Expand Down Expand Up @@ -41,6 +37,7 @@ import com.alfresco.content.process.FormViewState
import com.alfresco.content.process.ui.components.AmountInputField
import com.alfresco.content.process.ui.components.CheckBoxField
import com.alfresco.content.process.ui.components.CustomLinearProgressIndicator
import com.alfresco.content.process.ui.components.DateTimeField
import com.alfresco.content.process.ui.components.IntegerInputField
import com.alfresco.content.process.ui.components.MultiLineInputField
import com.alfresco.content.process.ui.components.SingleLineInputField
Expand Down Expand Up @@ -77,13 +74,6 @@ fun FormFragment(navController: NavController) {
)
}

@Composable
fun BackButton(onClick: () -> Unit) {
IconButton(onClick = onClick) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back")
}
}

@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun FormDetailScreen(padding: PaddingValues, state: FormViewState, viewModel: FormViewModel) {
Expand Down Expand Up @@ -162,6 +152,17 @@ fun FormDetailScreen(padding: PaddingValues, state: FormViewState, viewModel: Fo
field,
)
}

FieldType.DATETIME.value(), FieldType.DATE.value() -> {
var textFieldValue by remember { mutableStateOf(field.value as? String ?: "") }
DateTimeField(
dateTimeValue = textFieldValue,
onValueChanged = { newText ->
textFieldValue = newText
},
field,
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.alfresco.content.process.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import com.alfresco.content.process.NavigationComponent
import com.alfresco.content.process.ui.theme.AlfrescoBaseTheme

class ProcessFormFragment : Fragment() {

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
return ComposeView(requireContext()).apply {
layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
setContent {
AlfrescoBaseTheme {
NavigationComponent()
}
}
}
}
}

@Composable
fun BackButton(onClick: () -> Unit) {
IconButton(onClick = onClick) {
Icon(imageVector = Icons.Default.ArrowBack, contentDescription = "Back")
}
}
Loading

0 comments on commit 625a9d3

Please sign in to comment.