UIPickerView с выбором времени свободных слотов

swift

#1

Всем привет! Есть UIPickerView, состоящий из двух компонентов - часы и минуты.
На основании рабочего времени, формируется массив часов и минут. В каждом часе минуты с интервалом по 5 минут - [0, 5, 10, 15, 20 … 55 ]

Проблема заключается в том, что из этого массива необходимо удалить занятые слоты.
К примеру, занятый слот - начало действия с 14:15, окончание 15:00. И мне, соответсвенно, необходимо вырезать этот промежуток из массива. Получается - в структуре часа, где value равно 14, в его массиве минут, нужно выдернуть все остальные минуты. А в структуре 15, в массиве минут, удалить 0.

Никак не могу додумать алгоритм.
Может, у кого-то будут идеи?
Заранее, спасибо за ответ! :slight_smile:

UPD:
Забыл про очень важную вещь - при выборе времени, нужно учитывать, что на прохождение задачи уйдет 45 минут. Соответсвенно, если у нас 13:30 и занятое время с 13:50, то промежуток 13:30 - 14:35 также должен быть недоступен.


#2

Нужно будет трекать самому при каждом выборе.
Используйте делегат pickerView:didSelectRow:inComponent:
Собирайте выбранное время и сравнивайте с массивом уже занятых позиций, и если не подходит, выставляйте ближайшее разрешенное.


#3

Идея заключается в том, что когда на сабвью добавляется пикер и отрабатывают методы dataSource, на пикере отображаются уже только свободные слоты ) Ну то есть нет на пикере того времени, которое не может быть выставлено.


#4

Я начал с первого действия - получения вообще текущего времени, от которого буду отталкиваться.

Так, как интервал времени у нас по 5, то при клике на пикер, пользователь видит самое первое доступное время.

Добавил extension на тип Date -

enum DateRoundingType {
    case round
    case ceil
    case floor
}

extension Date {
    func rounded(minutes: TimeInterval, rounding: DateRoundingType = .round) -> Date {
        return rounded(seconds: minutes * 60, rounding: rounding)
    }
    func rounded(seconds: TimeInterval, rounding: DateRoundingType = .round) -> Date {
        var roundedInterval: TimeInterval = 0
        switch rounding  {
        case .round:
            roundedInterval = (timeIntervalSinceReferenceDate / seconds).rounded() * seconds
        case .ceil:
            roundedInterval = ceil(timeIntervalSinceReferenceDate / seconds) * seconds
        case .floor:
            roundedInterval = floor(timeIntervalSinceReferenceDate / seconds) * seconds
        }
        return Date(timeIntervalSinceReferenceDate: roundedInterval)
    }
}

Добавил тип с которым буду работать

struct AvailableHour {
    var value: Int
    var timestamp: TimeInterval
    var minute: [Int]
}

struct AvailableMinute {
    var value: Int
}

И написал первый метод

 let minutesInHours = [0, 5, 10, 15 ,20, 25, 30, 35, 40, 45, 50, 55]
    func getNearestTime() {
        let nearestDate = Date().rounded(minutes: 5, rounding: .ceil)
        let hour = Calendar.current.component(.hour, from: nearestDate)
        let minute = Calendar.current.component(.minute, from: nearestDate)
        var availableHour = AvailableHour(value: hour,
                                          timestamp: nearestDate.timeIntervalSince1970,
                                          minute: [minute])

        minutesInHours.forEach {
            if $0 > minute {
                availableHour.minute.append($0)
            }
        }
        
        availableHours.append(availableHour)

        calculateAvailableHours()
    }

А вот как дальше быть, с методом calculateAvailableHours - не знаю :frowning:

Пока что просто добавил все минуты до конца рабочего дня

func calculateAvailableHours() {
    guard let startHour = availableHours.first else { return }

    var currentHour = startHour.value
    let endHour = endWorkday.value

    while currentHour < endHour {
        let nextHour = currentHour + 1
        
        availableHours.append(AvailableHour(value: nextHour, timestamp: 0, minute: minutesInHours))
        currentHour = nextHour
    }
} 

Соответсвенно, если у нас рабочий день до 20:30, а сейчас время 15:11 - На пикере будет 15:15 и можно будет переключать до 20:30. Но осталось только удалить занятые слоты. И пока не знаю как