Multiple deletion of meetings (function activated by long click on meeting cell)

This commit is contained in:
Christophe Deschamps 2022-09-22 23:57:47 +02:00
parent cfb71d14c4
commit 7d9b79a9f8
10 changed files with 126 additions and 28 deletions

View file

@ -39,6 +39,8 @@ class ScheduledConferenceData {
let isConferenceCancelled = MutableLiveData(false)
let canEdit = MutableLiveData(false)
let isFinished : Bool
let selectedForDeletion = MutableLiveData(false)
init (conferenceInfo: ConferenceInfo, isFinished: Bool = false) {
self.conferenceInfo = conferenceInfo

View file

@ -32,6 +32,7 @@ class ScheduledConferencesViewModel {
var daySplitted : [Date : [ScheduledConferenceData]] = [:]
var coreDelegate: CoreDelegateStub?
var showTerminated = MutableLiveData(false)
let editionEnabled = MutableLiveData(false)
init () {

View file

@ -141,7 +141,8 @@ import IQKeyboardManager
scheduleForm.addSubview(viaChatView)
viaChatView.alignUnder(view: descriptionInput,withMargin: form_margin).matchParentSideBorders(insetedByDx: form_margin).alignParentBottom(withMargin: form_margin*4).done()
let viaChatSwitch = StyledCheckBox(liveValue: ConferenceSchedulingViewModel.shared.sendInviteViaChat)
let viaChatSwitch = StyledCheckBox()
viaChatSwitch.liveValue = ConferenceSchedulingViewModel.shared.sendInviteViaChat
viaChatView.addSubview(viaChatSwitch)
viaChatSwitch.alignParentLeft().done()

View file

@ -27,6 +27,7 @@ class ScheduledConferencesCell: UITableViewCell {
let corner_radius = 7.0
let border_width = 2.0
static let button_size = 40
let delete_checkbox_margin = 5
let clockIcon = UIImageView(image: UIImage(named: "conference_schedule_time_default"))
let timeDuration = StyledLabel(VoipTheme.conference_invite_desc_font)
@ -48,6 +49,7 @@ class ScheduledConferencesCell: UITableViewCell {
var owningTableView : UITableView? = nil
let joinEditDelete = UIStackView()
let expandedRows = UIStackView()
let selectionCheckBox = StyledCheckBox()
var conferenceData: ScheduledConferenceData? = nil {
didSet {
@ -88,7 +90,7 @@ class ScheduledConferencesCell: UITableViewCell {
} else {
self.participants.alignParentBottom(withMargin: 10).done()
}
self.selectionCheckBox.liveValue = data.selectedForDeletion
}
}
}
@ -105,7 +107,7 @@ class ScheduledConferencesCell: UITableViewCell {
contentView.addSubview(clockIcon)
clockIcon.alignParentTop(withMargin: 15).square(15).alignParentLeft(withMargin: 10).done()
contentView.addSubview(timeDuration)
timeDuration.alignParentTop(withMargin: 15).toRightOf(clockIcon,withLeftMargin:10).alignHorizontalCenterWith(clockIcon).done()
@ -117,10 +119,10 @@ class ScheduledConferencesCell: UITableViewCell {
subjectCancel.axis = .vertical
contentView.addSubview(subjectCancel)
subjectCancel.alignUnder(view: timeDuration,withMargin: 15).alignParentLeft(withMargin: 10).done()
subjectCancel.addArrangedSubview(cancelledLabel)
subjectCancel.addArrangedSubview(subject)
contentView.addSubview(participantsIcon)
participantsIcon.alignUnder(view: subject,withMargin: 15).square(15).alignParentLeft(withMargin: 10).done()
@ -133,8 +135,8 @@ class ScheduledConferencesCell: UITableViewCell {
infoConf.imageView?.contentMode = .scaleAspectFit
infoConf.alignUnder(view: subject,withMargin: 15).square(30).alignParentRight(withMargin: 10).alignHorizontalCenterWith(participantsIcon).done()
infoConf.applyTintedIcons(tintedIcons: VoipTheme.conference_info_button)
contentView.addSubview(participants)
participants.alignUnder(view: subject,withMargin: 15).toRightOf(participantsIcon,withLeftMargin:10).toRightOf(participantsIcon,withLeftMargin:10).toLeftOf(infoConf,withRightMargin: 15).done()
@ -142,7 +144,7 @@ class ScheduledConferencesCell: UITableViewCell {
expandedRows.spacing = 10
contentView.addSubview(expandedRows)
expandedRows.alignUnder(view: participants,withMargin: 15).matchParentSideBorders(insetedByDx:10).done()
expandedRows.addArrangedSubview(descriptionTitle)
expandedRows.addArrangedSubview(descriptionValue)
@ -163,10 +165,10 @@ class ScheduledConferencesCell: UITableViewCell {
joinEditDelete.axis = .horizontal
joinEditDelete.spacing = 10
joinEditDelete.distribution = .equalSpacing
contentView.addSubview(joinEditDelete)
joinEditDelete.alignUnder(view: expandedRows,withMargin: 15).alignParentRight(withMargin: 10).done()
joinEditDelete.addArrangedSubview(joinConf)
joinConf.width(150).done()
@ -204,6 +206,14 @@ class ScheduledConferencesCell: UITableViewCell {
deleteConf.onClick {
self.askConfirmationTodeleteEntry()
}
contentView.addSubview(selectionCheckBox)
selectionCheckBox.alignParentRight(withMargin: delete_checkbox_margin).alignUnder(view:organiser, withMargin: delete_checkbox_margin).done()
ScheduledConferencesViewModel.shared.editionEnabled.readCurrentAndObserve { editing in
self.selectionCheckBox.isHidden = editing != true
}
onLongClick {
ScheduledConferencesViewModel.shared.editionEnabled.value = true
}
}
func askConfirmationTodeleteEntry() {

View file

@ -27,6 +27,7 @@ import linphonesw
let conferenceListView = UITableView()
let noConference = StyledLabel(VoipTheme.empty_list_font,VoipTexts.conference_no_schedule)
let filters = UIStackView()
let selectAllButton = CallControlButton(buttonTheme:VoipTheme.nav_button("deselect_all"))
static let compositeDescription = UICompositeViewDescription(ScheduledConferencesView.self, statusBar: StatusBarView.self, tabBar: nil, sideMenu: SideMenuView.self, fullscreen: false, isLeftFragment: false,fragmentWith: nil)
static func compositeViewDescription() -> UICompositeViewDescription! { return compositeDescription }
@ -36,15 +37,27 @@ import linphonesw
super.viewDidLoad(
backAction: {
PhoneMainView.instance().popView(self.compositeViewDescription())
if (ScheduledConferencesViewModel.shared.editionEnabled.value == true) {
ScheduledConferencesViewModel.shared.editionEnabled.value = false
} else {
PhoneMainView.instance().popView(self.compositeViewDescription())
}
},nextAction: {
ConferenceSchedulingViewModel.shared.reset()
PhoneMainView.instance().changeCurrentView(ConferenceSchedulingView.compositeDescription)
if (ScheduledConferencesViewModel.shared.editionEnabled.value == true) {
self.deleteSelection()
} else {
ConferenceSchedulingViewModel.shared.reset()
PhoneMainView.instance().changeCurrentView(ConferenceSchedulingView.compositeDescription)
}
},
nextActionEnableCondition: MutableLiveData(),
title:VoipTexts.conference_scheduled)
super.nextButton.applyTintedIcons(tintedIcons: VoipTheme.conference_create_button)
// Select all
selectAllButton.setImage(UIImage(named: "deselect_all"), for: .selected)
selectAllButton.setImage(UIImage(named: "select_all_default"), for: .normal)
topBar.addSubview(selectAllButton)
selectAllButton.toLeftOf(nextButton,withRightMargin: CGFloat(side_buttons_margin)).matchParentHeight().done()
// Filter buttons
let showTerminated = getFilterButton(title: VoipTexts.conference_scheduled_terminated_filter)
@ -93,6 +106,29 @@ import linphonesw
view.addSubview(noConference)
noConference.center().done()
ScheduledConferencesViewModel.shared.editionEnabled.readCurrentAndObserve { editing in
if (editing == true) {
self.selectAllButton.isSelected = false
self.selectAllButton.isHidden = false
super.nextButton.setImage(UIImage(named: "delete_default"), for: .normal)
super.nextButton.setImage(UIImage(named: "delete_disabled"), for: .disabled)
super.nextButton.setImage(UIImage(named: "delete_default"), for: .highlighted)
super.backButton.setImage(UIImage(named: "cancel_edit_default"), for: .normal)
self.nextButton.isEnabled = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0 > 0
} else {
self.selectAllButton.isHidden = true
ScheduledConferencesViewModel.shared.conferences.value?.forEach {$0.selectedForDeletion.value = false}
super.nextButton.applyTintedIcons(tintedIcons: VoipTheme.conference_create_button)
super.backButton.setImage(UIImage(named: "back_default"), for: .normal)
self.nextButton.isEnabled = true
}
}
self.selectAllButton.onClick {
let selectIt = !self.selectAllButton.isSelected
ScheduledConferencesViewModel.shared.conferences.value?.forEach {$0.selectedForDeletion.value = selectIt}
}
}
func getFilterButton(title:String) -> UIButton {
@ -118,6 +154,7 @@ import linphonesw
self.conferenceListView.matchParentSideBorders(insetedByDx: 10).alignUnder(view: filters,withMargin: self.form_margin).alignParentBottom().done()
noConference.isHidden = !ScheduledConferencesViewModel.shared.daySplitted.isEmpty
super.nextButton.isEnabled = Core.get().defaultAccount != nil
ScheduledConferencesViewModel.shared.editionEnabled.value = false
}
// TableView datasource delegate
@ -163,6 +200,12 @@ import linphonesw
}
cell.conferenceData = data
cell.owningTableView = tableView
data.selectedForDeletion.readCurrentAndObserve { selected in
let selectedCount = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0
let totalCount = ScheduledConferencesViewModel.shared.conferences.value?.count ?? 0
self.nextButton.isEnabled = selectedCount > 0
self.selectAllButton.isSelected = selectedCount == totalCount
}
return cell
}
@ -175,4 +218,20 @@ import linphonesw
}
}
func deleteSelection () {
let selectedCount = ScheduledConferencesViewModel.shared.conferences.value?.filter{$0.selectedForDeletion.value == true}.count ?? 0
let delete = ButtonAttributes(text:VoipTexts.conference_info_confirm_removal_delete, action: {
ScheduledConferencesViewModel.shared.conferences.value?.forEach {
Core.get().deleteConferenceInformation(conferenceInfo: $0.conferenceInfo)
ScheduledConferencesViewModel.shared.computeConferenceInfoList()
self.conferenceListView.reloadData()
}
VoipDialog.toast(message: selectedCount == 1 ? VoipTexts.conference_info_removed : VoipTexts.conference_infos_removed)
ScheduledConferencesViewModel.shared.editionEnabled.value = false
}, isDestructive:false)
let cancel = ButtonAttributes(text:VoipTexts.cancel, action: {}, isDestructive:true)
VoipDialog(message:selectedCount == 1 ? VoipTexts.conference_info_confirm_removal : VoipTexts.conference_infos_confirm_removal, givenButtons: [cancel,delete]).show()
}
}

View file

@ -446,8 +446,8 @@ extension UIView {
// to avoid the unused variable warning
}
// Onclick
// Single click
class TapGestureRecognizer: UITapGestureRecognizer {
var action : (()->Void)? = nil
}
@ -466,6 +466,22 @@ extension UIView {
sender.action!()
}
// Long click
class LongPressGestureRecognizer: UILongPressGestureRecognizer {
var action : (()->Void)? = nil
}
func onLongClick(action : @escaping ()->Void ){
let tap = LongPressGestureRecognizer(target: self , action: #selector(self.handleLongClick(_:)))
tap.action = action
tap.cancelsTouchesInView = false
self.addGestureRecognizer(tap)
self.isUserInteractionEnabled = true
}
@objc func handleLongClick(_ sender: LongPressGestureRecognizer) {
sender.action!()
}
func VIEW<T>( _ desc: UICompositeViewDescription) -> T{
return PhoneMainView.instance().mainViewController.getCachedController(desc.name) as! T
}

View file

@ -90,7 +90,10 @@ import UIKit
@objc static let conference_group_call_title = NSLocalizedString("Start a group call",comment:"")
@objc static let conference_incoming_title = NSLocalizedString("Incoming group call",comment:"")
@objc static let conference_info_confirm_removal = NSLocalizedString("Do you really want to delete this meeting?",comment:"")
@objc static let conference_infos_confirm_removal = NSLocalizedString("Do you really want to delete these meetings?",comment:"")
@objc static let conference_info_removed = NSLocalizedString("Meeting info has been deleted",comment:"")
@objc static let conference_infos_removed = NSLocalizedString("Meeting infos have been deleted",comment:"")
@objc static let conference_invite_join = NSLocalizedString("Join",comment:"")
@objc static let conference_invite_participants_count = NSLocalizedString("%d participants",comment:"")
@objc static let conference_invite_title = NSLocalizedString("Meeting invite:",comment:"")

View file

@ -403,6 +403,12 @@ import UIKit
UIButton.State.disabled.rawValue : TintableIcon(name: "voip_conference_new",tintColor: LightDarkColor(voip_light_gray,voip_light_gray)),
]
static let generic_delete_button = [
UIButton.State.normal.rawValue : TintableIcon(name: "voip_conference_new",tintColor: LightDarkColor(voip_dark_gray,voip_dark_gray)),
UIButton.State.highlighted.rawValue : TintableIcon(name: "voip_conference_new",tintColor: LightDarkColor(primary_color,primary_color)),
UIButton.State.disabled.rawValue : TintableIcon(name: "voip_conference_new",tintColor: LightDarkColor(voip_light_gray,voip_light_gray)),
]
}

View file

@ -27,27 +27,27 @@ class StyledCheckBox: UIButton {
// layout constants
let button_size = 25.0
var liveValue : MutableLiveData<Bool>? = nil {
didSet {
liveValue?.readCurrentAndObserve { (value) in
self.isSelected = value!
}
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
init (liveValue:MutableLiveData<Bool>) {
init () {
super.init(frame: .zero)
setBackgroundImage(UIImage(named:"voip_checkbox_unchecked")/*?.tinted(with: VoipTheme.light_grey_color)*/,for: .normal) // tinting not working with those icons
setBackgroundImage(UIImage(named:"voip_checkbox_checked")/*?.tinted(with: VoipTheme.primary_color)*/,for: .selected)
onClick {
liveValue.value = !liveValue.value!
self.isSelected = liveValue.value!
self.liveValue?.value = self.liveValue?.value != true
self.isSelected = self.liveValue?.value == true
}
size(w: button_size,h: button_size).done()
liveValue.readCurrentAndObserve { (value) in
self.isSelected = value!
}
size(w: button_size,h: button_size).done()
}