An overview of what I am trying to achieve I am trying to make a notifications tableview and each notification is group by its created date, so the tableview sections will be the number of created date, each section with the notifications created at this date in the section title. I have searched a lot but didn't get an absolute answer how to make with RxDataSource the array is dynamic get loaded with dates received through an API?
class T : UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return array.count
}
}
All what I have found is to set the sections static like so
ViewModel.AllNotificationsObservable
.map({ [NotificationSectionViewModel(header: "Yet", items: $0.filter{$0.createAt.toDate()!.toString(format: "yyyy-MM-dd") == Date().toString(format: "yyyy-MM-dd") }),
NotificationSectionViewModel(header: "Yesterday", items: $0)
]
})
.bind(to: NotificationTableView.rx.items(dataSource: ViewModel.dataSource))
.disposed(by: notificationDisposeBag)
this is my struct
struct NotificationSectionViewModel {
var header: String
var items: [AllNotificationModel]
}
extension NotificationSectionViewModel: SectionModelType {
typealias NotificationItem = AllNotificationModel
init(original: NotificationSectionViewModel, items: [AllNotificationModel]) {
self = original
self.items = items
}
}
and this the data model
class AllNotificationModel : Codable {
let id, userID : Int
let title, body, createAt: String
enum CodingKeys: String, CodingKey {
case id, title, body
case userID = "user_id"
case createAt = "create at"
}
}
what I am trying to achieve
need header to be like this
“Today”: [
{
"id": 2421,
"user_id": 39,
"title": "todayNotification",
"body": "test",
"create at": "2021-02-26 17:33:44"
},
{
"id": 2349,
"user_id": 39,
"title": "check",
"body": "test",
"create at": "2021-02-26 09:36:05"
},
{
"id": 2206,
"user_id": 39,
"title": "New Deal",
"body": "new Deal 2",
"create at": "2021-02-26 13:43:16"
} ]
“Yesterday”: [
{
"id": 2134,
"user_id": 39,
"title": "Closed Deal",
"body": “deal deal”,
"create at": "2021-02-25 13:21:30"
} ]
“2021-02-24”: [
{
"id": 2134,
"user_id": 39,
"title": "Closed Deal",
"body": “deal”,
"create at": "2021-02-24 13:21:30"
},
{
"id": 2063,
"user_id": 39,
"title": "New Deal",
"body": "new Deal",
"create at": "2021-02-24 13:21:16"
}]
I figured out the answer
override func bind(ViewModel: NotificationViewModel) {
ViewModel.dataSource.configureCell = { [unowned self] (dataSource, tableview, indexPath, item) in
let cell = tableview.dequeueReusableCell(withIdentifier: self.CellIdentifier, for: indexPath) as! NotificationTableViewCell
cell.setDataToUI(notificationData: item)
return cell
}
ViewModel.dataSource.titleForHeaderInSection = { (dataSource, index) in
let section = dataSource[index]
return section.header
}
var finalSections = [NotificationSectionViewModel]()
var sortedFinal = [NotificationSectionViewModel]()
var result = [String : [AllNotificationModel]]()
ViewModel.AllNotificationsObservable
.map({ section in
for (i, dict) in section.enumerated() {
result[(section[i].createAt.toDate()?.toString(format: "yyyy-MM-dd"))!, default: []].append(dict)
}
for (key, value) in result {
finalSections.append(NotificationSectionViewModel(header: key, items: value))
}
sortedFinal = finalSections.sorted(by: >)
for final in 0...sortedFinal.count - 1 {
if self.getTodayDate() == sortedFinal[final].header {
sortedFinal[final].header = "Today"
}
else if self.getYesterDay() == sortedFinal[final].header {
sortedFinal[final].header = "Yesterday"
}
else {
sortedFinal[final].header = convertDateFormater(sortedFinal[final].header)
}
}
return sortedFinal
})
.bind(to: NotificationTableView.rx.items(dataSource: ViewModel.dataSource))
.disposed(by: notificationDisposeBag)
}
This is my cell class
class NotificationTableViewCell: UITableViewCell {
@IBOutlet weak var notificationImageIcon: UIImageView!
@IBOutlet weak var notificationBodyMessage: UILabel!
@IBOutlet weak var notificationTime: UILabel!
@IBOutlet weak var seenNotificationView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
selectionStyle = .none
}
func setDataToUI(notificationData: AllNotificationModel) {
DispatchQueue.main.async {
self.seenNotificationView.isHidden = true
self.notificationBodyMessage.text = notificationData.body
self.notificationTime.text = self.convertDateFormater(notificationData.createAt)
}
}
func convertDateFormater(_ date: String) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let date = dateFormatter.date(from: date)
dateFormatter.dateFormat = "h:mm a"
return dateFormatter.string(from: date!)
}
}
I used these two function to get the today and the yesterday dates
extension UIViewController {
func getTodayDate() -> String {
let currentDate = Date()
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
let dateString = df.string(from: currentDate)
return dateString
}
func getYesterDay() -> String {
let currentDate = Date.yesterday
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
let dateString = df.string(from: currentDate)
return dateString
}
}