diff --git a/app/src/main/java/org/linphone/core/CoreContext.kt b/app/src/main/java/org/linphone/core/CoreContext.kt
index dfdb54d0c..554066080 100644
--- a/app/src/main/java/org/linphone/core/CoreContext.kt
+++ b/app/src/main/java/org/linphone/core/CoreContext.kt
@@ -121,16 +121,16 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
@WorkerThread
override fun onConfiguringStatus(
core: Core,
- status: Config.ConfiguringState?,
+ status: ConfiguringState?,
message: String?
) {
Log.i("$TAG Configuring state changed [$status]")
- if (status == Config.ConfiguringState.Successful) {
+ if (status == ConfiguringState.Successful) {
val text = context.getString(
org.linphone.R.string.assistant_qr_code_provisioning_done
)
greenToastToShowEvent.postValue(Event(Pair(text, org.linphone.R.drawable.smiley)))
- } else if (status == Config.ConfiguringState.Failed) {
+ } else if (status == ConfiguringState.Failed) {
val text = context.getString(
org.linphone.R.string.assistant_qr_code_provisioning_done
)
diff --git a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
index 6f48c1182..3f9d8dc4b 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/fragment/ConversationInfoFragment.kt
@@ -211,8 +211,12 @@ class ConversationInfoFragment : SlidingPaneChildFragment() {
}
binding.setAddParticipantsClickListener {
- val action = ConversationInfoFragmentDirections.actionConversationInfoFragmentToAddParticipantsFragment()
- findNavController().navigate(action)
+ if (findNavController().currentDestination?.id == R.id.conversationInfoFragment) {
+ Log.i("$TAG Going into participant picker fragment")
+ val action =
+ ConversationInfoFragmentDirections.actionConversationInfoFragmentToAddParticipantsFragment()
+ findNavController().navigate(action)
+ }
}
binding.setEditSubjectClickListener {
diff --git a/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt b/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt
index d5b6f21a1..f3eb0534d 100644
--- a/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/chat/model/MessageModel.kt
@@ -581,7 +581,7 @@ class MessageModel @WorkerThread constructor(
hideYear = false
)
val startTime = TimestampUtils.timeToString(timestamp)
- val end = timestamp + (duration * 60)
+ val end = timestamp + duration
val endTime = TimestampUtils.timeToString(end)
meetingDate.postValue(date)
meetingTime.postValue("$startTime - $endTime")
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/EditMeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/EditMeetingFragment.kt
new file mode 100644
index 000000000..0034270fd
--- /dev/null
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/EditMeetingFragment.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2010-2023 Belledonne Communications SARL.
+ *
+ * This file is part of linphone-android
+ * (see https://www.linphone.org).
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.linphone.ui.main.meetings.fragment
+
+import android.os.Bundle
+import android.text.format.DateFormat
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.UiThread
+import androidx.lifecycle.ViewModelProvider
+import androidx.navigation.fragment.findNavController
+import androidx.navigation.fragment.navArgs
+import com.google.android.material.datepicker.CalendarConstraints
+import com.google.android.material.datepicker.DateValidatorPointForward
+import com.google.android.material.datepicker.MaterialDatePicker
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
+import org.linphone.R
+import org.linphone.core.tools.Log
+import org.linphone.databinding.MeetingEditFragmentBinding
+import org.linphone.ui.main.fragment.SlidingPaneChildFragment
+import org.linphone.ui.main.meetings.viewmodel.ScheduleMeetingViewModel
+import org.linphone.utils.Event
+
+@UiThread
+class EditMeetingFragment : SlidingPaneChildFragment() {
+ companion object {
+ private const val TAG = "[Edit Meeting Fragment]"
+ }
+
+ private lateinit var binding: MeetingEditFragmentBinding
+
+ private lateinit var viewModel: ScheduleMeetingViewModel
+
+ private val args: EditMeetingFragmentArgs by navArgs()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = MeetingEditFragmentBinding.inflate(layoutInflater)
+ return binding.root
+ }
+
+ override fun goBack(): Boolean {
+ return findNavController().popBackStack()
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ binding.lifecycleOwner = viewLifecycleOwner
+
+ viewModel = ViewModelProvider(this)[ScheduleMeetingViewModel::class.java]
+ binding.viewModel = viewModel
+
+ val conferenceUri = args.conferenceUri
+ Log.i("$TAG Found conference URI [$conferenceUri] in arguments")
+ viewModel.loadExistingConferenceInfoFromUri(conferenceUri)
+
+ binding.setBackClickListener {
+ goBack()
+ }
+
+ binding.setPickStartDateClickListener {
+ val constraintsBuilder =
+ CalendarConstraints.Builder()
+ .setValidator(DateValidatorPointForward.now())
+ val picker =
+ MaterialDatePicker.Builder.datePicker()
+ .setCalendarConstraints(constraintsBuilder.build())
+ .setTitleText(R.string.meeting_schedule_pick_start_date_title)
+ .setSelection(viewModel.getCurrentlySelectedStartDate())
+ .build()
+ picker.addOnPositiveButtonClickListener {
+ val selection = picker.selection
+ if (selection != null) {
+ viewModel.setStartDate(selection)
+ }
+ }
+ picker.show(parentFragmentManager, "Start date picker")
+ }
+
+ binding.setPickEndDateClickListener {
+ val constraintsBuilder =
+ CalendarConstraints.Builder()
+ .setValidator(
+ DateValidatorPointForward.from(viewModel.getCurrentlySelectedStartDate())
+ )
+ val picker =
+ MaterialDatePicker.Builder.datePicker()
+ .setCalendarConstraints(constraintsBuilder.build())
+ .setTitleText(R.string.meeting_schedule_pick_end_date_title)
+ .setSelection(viewModel.getCurrentlySelectedEndDate())
+ .build()
+ picker.addOnPositiveButtonClickListener {
+ val selection = picker.selection
+ if (selection != null) {
+ viewModel.setEndDate(selection)
+ }
+ }
+ picker.show(parentFragmentManager, "End date picker")
+ }
+
+ binding.setPickStartTimeClickListener {
+ val isSystem24Hour = DateFormat.is24HourFormat(requireContext())
+ val clockFormat = if (isSystem24Hour) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H
+ val picker =
+ MaterialTimePicker.Builder()
+ .setTimeFormat(clockFormat)
+ .setTitleText(R.string.meeting_schedule_pick_start_time_title)
+ .setHour(viewModel.startHour)
+ .setMinute(viewModel.startMinutes)
+ .build()
+ picker.addOnPositiveButtonClickListener {
+ viewModel.setStartTime(picker.hour, picker.minute)
+ }
+ picker.show(parentFragmentManager, "Start time picker")
+ }
+
+ binding.setPickEndTimeClickListener {
+ val isSystem24Hour = DateFormat.is24HourFormat(
+ requireContext()
+ )
+ val clockFormat = if (isSystem24Hour) TimeFormat.CLOCK_24H else TimeFormat.CLOCK_12H
+ val picker =
+ MaterialTimePicker.Builder()
+ .setTimeFormat(clockFormat)
+ .setTitleText(R.string.meeting_schedule_pick_end_time_title)
+ .setHour(viewModel.endHour)
+ .setMinute(viewModel.endMinutes)
+ .build()
+ picker.addOnPositiveButtonClickListener {
+ viewModel.setEndTime(picker.hour, picker.minute)
+ }
+ picker.show(parentFragmentManager, "End time picker")
+ }
+
+ binding.setPickParticipantsClickListener {
+ if (findNavController().currentDestination?.id == R.id.editMeetingFragment) {
+ Log.i("$TAG Going into participant picker fragment")
+ val action =
+ EditMeetingFragmentDirections.actionEditMeetingFragmentToAddParticipantsFragment()
+ findNavController().navigate(action)
+ }
+ }
+
+ viewModel.conferenceCreatedEvent.observe(viewLifecycleOwner) {
+ it.consume {
+ Log.i("$TAG Conference was scheduled, leaving fragment and ask list to refresh")
+ sharedViewModel.forceRefreshMeetingsListEvent.value = Event(true)
+ goBack()
+ }
+ }
+
+ sharedViewModel.listOfSelectedSipUrisEvent.observe(viewLifecycleOwner) {
+ it.consume { list ->
+ Log.i(
+ "$TAG Found [${list.size}] new participants to add to the meeting, let's do it"
+ )
+ viewModel.addParticipants(list)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
index e20224e30..78747ae95 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/MeetingFragment.kt
@@ -95,6 +95,19 @@ class MeetingFragment : SlidingPaneChildFragment() {
goBack()
}
+ binding.setEditClickListener {
+ val conferenceUri = viewModel.sipUri.value.orEmpty()
+ if (conferenceUri.isNotEmpty()) {
+ Log.i(
+ "$TAG Navigating to meeting edit fragment with conference URI [$conferenceUri]"
+ )
+ val action = MeetingFragmentDirections.actionMeetingFragmentToEditMeetingFragment(
+ conferenceUri
+ )
+ findNavController().navigate(action)
+ }
+ }
+
binding.setShareClickListener {
copyMeetingAddressIntoClipboard(uri)
}
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt b/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt
index e81ff3970..2ed9258e2 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/fragment/ScheduleMeetingFragment.kt
@@ -158,9 +158,12 @@ class ScheduleMeetingFragment : GenericFragment() {
}
binding.setPickParticipantsClickListener {
- Log.i("$TAG Going into participant picker fragment")
- val action = ScheduleMeetingFragmentDirections.actionScheduleMeetingFragmentToAddParticipantsFragment()
- findNavController().navigate(action)
+ if (findNavController().currentDestination?.id == R.id.scheduleMeetingFragment) {
+ Log.i("$TAG Going into participant picker fragment")
+ val action =
+ ScheduleMeetingFragmentDirections.actionScheduleMeetingFragmentToAddParticipantsFragment()
+ findNavController().navigate(action)
+ }
}
viewModel.conferenceCreatedEvent.observe(viewLifecycleOwner) {
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt
index 9e4ee504d..e5f1c8062 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/model/MeetingModel.kt
@@ -49,7 +49,7 @@ class MeetingModel @WorkerThread constructor(private val conferenceInfo: Confere
private val startTime = TimestampUtils.timeToString(timestamp)
- private val endTime = TimestampUtils.timeToString(timestamp + (conferenceInfo.duration * 60))
+ private val endTime = TimestampUtils.timeToString(timestamp + conferenceInfo.duration)
val time = "$startTime - $endTime"
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
index aede6ba6b..37b2100ae 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingViewModel.kt
@@ -130,7 +130,7 @@ class MeetingViewModel @UiThread constructor() : ViewModel() {
hideYear = false
)
val startTime = TimestampUtils.timeToString(timestamp)
- val end = timestamp + (duration * 60)
+ val end = timestamp + duration
val endTime = TimestampUtils.timeToString(end)
startTimeStamp.postValue(timestamp * 1000)
endTimeStamp.postValue(end * 1000)
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt
index f0b788ebb..51fbdc03d 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/MeetingWaitingRoomViewModel.kt
@@ -326,7 +326,7 @@ class MeetingWaitingRoomViewModel @UiThread constructor() : ViewModel() {
hideYear = false
)
val startTime = TimestampUtils.timeToString(timestamp)
- val end = timestamp + (duration * 60)
+ val end = timestamp + duration
val endTime = TimestampUtils.timeToString(end)
dateTime.postValue("$date | $startTime - $endTime")
diff --git a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/ScheduleMeetingViewModel.kt b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/ScheduleMeetingViewModel.kt
index 28e0d5647..f3e0e6cfd 100644
--- a/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/ScheduleMeetingViewModel.kt
+++ b/app/src/main/java/org/linphone/ui/main/meetings/viewmodel/ScheduleMeetingViewModel.kt
@@ -19,6 +19,7 @@
*/
package org.linphone.ui.main.meetings.viewmodel
+import androidx.annotation.AnyThread
import androidx.annotation.UiThread
import androidx.annotation.WorkerThread
import androidx.lifecycle.MutableLiveData
@@ -30,6 +31,7 @@ import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.R
import org.linphone.core.Address
import org.linphone.core.ChatRoom
+import org.linphone.core.ConferenceInfo
import org.linphone.core.ConferenceScheduler
import org.linphone.core.ConferenceSchedulerListenerStub
import org.linphone.core.Factory
@@ -85,6 +87,8 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
private lateinit var conferenceScheduler: ConferenceScheduler
+ private lateinit var conferenceInfoToEdit: ConferenceInfo
+
private val conferenceSchedulerListener = object : ConferenceSchedulerListenerStub() {
@WorkerThread
override fun onStateChanged(
@@ -99,9 +103,16 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
}
ConferenceScheduler.State.Ready -> {
val conferenceAddress = conferenceScheduler.info?.uri
- Log.i(
- "$TAG Conference info created, address will be ${conferenceAddress?.asStringUriOnly()}"
- )
+ if (::conferenceInfoToEdit.isInitialized) {
+ Log.i(
+ "$TAG Conference info [${conferenceInfoToEdit.uri?.asStringUriOnly()}] has been updated"
+ )
+ } else {
+ Log.i(
+ "$TAG Conference info created, address will be [${conferenceAddress?.asStringUriOnly()}]"
+ )
+ }
+
if (sendInvitations.value == true) {
Log.i("$TAG User asked for invitations to be sent, let's do it")
val chatRoomParams = coreContext.core.createDefaultChatRoomParams()
@@ -179,19 +190,7 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
computeDateLabels()
computeTimeLabels()
-
- timezone.value = AppUtils.getFormattedString(
- R.string.meeting_schedule_timezone_title,
- TimeZone.getDefault().displayName.replaceFirstChar {
- if (it.isLowerCase()) {
- it.titlecase(
- Locale.getDefault()
- )
- } else {
- it.toString()
- }
- }
- )
+ updateTimezone()
}
override fun onCleared() {
@@ -204,6 +203,64 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
}
}
+ @UiThread
+ fun loadExistingConferenceInfoFromUri(conferenceUri: String) {
+ coreContext.postOnCoreThread { core ->
+ val conferenceAddress = core.interpretUrl(conferenceUri, false)
+ if (conferenceAddress == null) {
+ Log.e("$TAG Failed to parse conference URI [$conferenceUri], abort")
+ return@postOnCoreThread
+ }
+
+ val conferenceInfo = core.findConferenceInformationFromUri(conferenceAddress)
+ if (conferenceInfo == null) {
+ Log.e(
+ "$TAG Failed to find a conference info matching URI [${conferenceAddress.asString()}], abort"
+ )
+ return@postOnCoreThread
+ }
+
+ conferenceInfoToEdit = conferenceInfo
+ Log.i(
+ "$TAG Found conference info matching URI [${conferenceInfo.uri?.asString()}] with subject [${conferenceInfo.subject}]"
+ )
+ subject.postValue(conferenceInfo.subject)
+ description.postValue(conferenceInfo.description)
+
+ isBroadcastSelected.postValue(false) // TODO FIXME
+
+ startHour = 0
+ startMinutes = 0
+ endHour = 0
+ endMinutes = 0
+ startTimestamp = conferenceInfo.dateTime * 1000 /* Linphone timestamps are in seconds */
+ endTimestamp = (conferenceInfo.dateTime + conferenceInfo.duration) * 1000 /* Linphone timestamps are in seconds */
+ Log.i(
+ "$TAG Loaded start date is [$startTimestamp], loaded end date is [$endTimestamp]"
+ )
+ computeDateLabels()
+ computeTimeLabels()
+ updateTimezone()
+
+ val list = arrayListOf()
+ for (participant in conferenceInfo.participantInfos) {
+ val address = participant.address
+ val avatarModel = coreContext.contactsManager.getContactAvatarModelForAddress(
+ address
+ )
+ val model = SelectedAddressModel(address, avatarModel) {
+ // onRemoveFromSelection
+ }
+ list.add(model)
+ Log.i("$TAG Loaded participant [${address.asStringUriOnly()}]")
+ }
+ Log.i(
+ "$TAG [${list.size}] participants loaded from found conference info"
+ )
+ participants.postValue(list)
+ }
+ }
+
@UiThread
fun getCurrentlySelectedStartDate(): Long {
return startTimestamp
@@ -292,6 +349,8 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
}
}
+ // TODO FIXME handle speakers when in broadcast mode
+
@UiThread
fun schedule() {
coreContext.postOnCoreThread { core ->
@@ -339,12 +398,64 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
}
conferenceScheduler.account = localAccount
- // Will trigger the conference creation/update automatically
+ // Will trigger the conference creation automatically
conferenceScheduler.info = conferenceInfo
}
}
@UiThread
+ fun update() {
+ coreContext.postOnCoreThread { core ->
+ Log.i(
+ "$TAG Updating ${if (isBroadcastSelected.value == true) "broadcast" else "meeting"}"
+ )
+ if (!::conferenceInfoToEdit.isInitialized) {
+ Log.e("No conference info to edit found!")
+ return@postOnCoreThread
+ }
+
+ operationInProgress.postValue(true)
+
+ val conferenceInfo = conferenceInfoToEdit
+ conferenceInfo.subject = subject.value
+ conferenceInfo.description = description.value
+
+ val startTime = startTimestamp / 1000 // Linphone expects timestamp in seconds
+ conferenceInfo.dateTime = startTime
+ val duration = ((endTimestamp - startTimestamp) / 1000).toInt() // Linphone expects duration in seconds
+ conferenceInfo.duration = duration
+
+ val participantsList = participants.value.orEmpty()
+ val participantsInfoList = arrayListOf()
+ for (participant in participantsList) {
+ val info = Factory.instance().createParticipantInfo(participant.address)
+ if (info == null) {
+ Log.e(
+ "$TAG Failed to create Participant Info from address [${participant.address.asStringUriOnly()}]"
+ )
+ continue
+ }
+
+ // For meetings, all participants must have Speaker role
+ info.role = Participant.Role.Speaker
+ participantsInfoList.add(info)
+ }
+
+ val participantsInfoArray = arrayOfNulls(participantsInfoList.size)
+ participantsInfoList.toArray(participantsInfoArray)
+ conferenceInfo.setParticipantInfos(participantsInfoArray)
+
+ if (!::conferenceScheduler.isInitialized) {
+ conferenceScheduler = core.createConferenceScheduler()
+ conferenceScheduler.addListener(conferenceSchedulerListener)
+ }
+
+ // Will trigger the conference update automatically
+ conferenceScheduler.info = conferenceInfo
+ }
+ }
+
+ @AnyThread
private fun computeDateLabels() {
val start = TimestampUtils.toString(
startTimestamp,
@@ -353,7 +464,7 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
shortDate = false,
hideYear = false
)
- fromDate.value = start
+ fromDate.postValue(start)
Log.i("$TAG Computed start date for timestamp [$startTimestamp] is [$start]")
val end = TimestampUtils.toString(
@@ -363,25 +474,47 @@ class ScheduleMeetingViewModel @UiThread constructor() : ViewModel() {
shortDate = false,
hideYear = false
)
- toDate.value = end
+ toDate.postValue(end)
Log.i("$TAG Computed end date for timestamp [$endTimestamp] is [$end]")
}
- @UiThread
+ @AnyThread
private fun computeTimeLabels() {
val cal = Calendar.getInstance()
cal.timeInMillis = startTimestamp
- cal.set(Calendar.HOUR_OF_DAY, startHour)
- cal.set(Calendar.MINUTE, startMinutes)
+ if (startHour != 0 && startMinutes != 0) {
+ cal.set(Calendar.HOUR_OF_DAY, startHour)
+ cal.set(Calendar.MINUTE, startMinutes)
+ }
val start = TimestampUtils.timeToString(cal.timeInMillis, timestampInSecs = false)
Log.i("$TAG Computed start time for timestamp [$startTimestamp] is [$start]")
- fromTime.value = start
+ fromTime.postValue(start)
cal.timeInMillis = endTimestamp
- cal.set(Calendar.HOUR_OF_DAY, endHour)
- cal.set(Calendar.MINUTE, endMinutes)
+ if (endHour != 0 && endMinutes != 0) {
+ cal.set(Calendar.HOUR_OF_DAY, endHour)
+ cal.set(Calendar.MINUTE, endMinutes)
+ }
val end = TimestampUtils.timeToString(cal.timeInMillis, timestampInSecs = false)
Log.i("$TAG Computed end time for timestamp [$endTimestamp] is [$end]")
- toTime.value = end
+ toTime.postValue(end)
+ }
+
+ @AnyThread
+ private fun updateTimezone() {
+ timezone.postValue(
+ AppUtils.getFormattedString(
+ R.string.meeting_schedule_timezone_title,
+ TimeZone.getDefault().displayName.replaceFirstChar {
+ if (it.isLowerCase()) {
+ it.titlecase(
+ Locale.getDefault()
+ )
+ } else {
+ it.toString()
+ }
+ }
+ )
+ )
}
}
diff --git a/app/src/main/res/layout/meeting_edit_fragment.xml b/app/src/main/res/layout/meeting_edit_fragment.xml
new file mode 100644
index 000000000..597b73459
--- /dev/null
+++ b/app/src/main/res/layout/meeting_edit_fragment.xml
@@ -0,0 +1,415 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/meeting_fragment.xml b/app/src/main/res/layout/meeting_fragment.xml
index 588297f22..a023d4508 100644
--- a/app/src/main/res/layout/meeting_fragment.xml
+++ b/app/src/main/res/layout/meeting_fragment.xml
@@ -7,6 +7,9 @@
+
@@ -53,12 +56,13 @@
+ app:layout_constraintBottom_toBottomOf="parent">
-
-
+
+
diff --git a/app/src/main/res/navigation/meetings_nav_graph.xml b/app/src/main/res/navigation/meetings_nav_graph.xml
index d3998b3ee..a0c03d3de 100644
--- a/app/src/main/res/navigation/meetings_nav_graph.xml
+++ b/app/src/main/res/navigation/meetings_nav_graph.xml
@@ -24,11 +24,42 @@
app:destination="@id/emptyFragment"
app:popUpTo="@id/meetingFragment"
app:popUpToInclusive="true" />
+
+ app:launchSingleTop="true"/>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 24bbe0cfd..a3905f043 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -489,6 +489,7 @@
Meeting has been deleted
Description
Create
+ Edit meeting
Join