ToDo List Swift

322 views Asked by At

I am making an application in Swift language with UIKIT the application is as follows ToDo List in which I need to output tasks as follows 1 there should be only two sections completed with the button marked and unfulfilled now I have reached the point that I have each new ToDo created in a new section. What to do? Here is my code and what I got as a datasource I have an array inside an array

import UIKit

class TableViewController: UITableViewController {
    
    private var arrExecuteToDo = [String]()
    private var todos = [[ToDoItem]]()
    private var selectedIndex: Int?   // global var for the operation of the row index in the extension
    private var todoStatus: [ToDoStatus] = [.completed, .planed]
    
    enum Constants {
        static let addTaskIndentifier: String = "addTaskVc"
        static let cellIndentifier: String = "ToDoCell"
        static let mainStoryboard: String = "Main"
        static let secondVC: String = "secondVC"
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
        
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == Constants.addTaskIndentifier {
            let addTaskVC = segue.destination as? AddTaskViewController // create a link to the second view controller
            addTaskVC?.type = .create
            addTaskVC?.delegate = self // subscribe it to the delegate of the second controller
        }
    }

    // MARK: - Table view Data Source
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        todos[section].count
    }
    
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        todos.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.cellIndentifier,
                                                       for: indexPath) as? TableViewCell else { return UITableViewCell() }  // cast on your cell
        _ = todos[indexPath.row] // pick up the current body by cell index
        let todo = todos[indexPath.section]
        cell.configureCell(with: todo[indexPath.row]) // config a cell from a cell
        return cell
    }
    
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let secondeVC = UIStoryboard(name: Constants.mainStoryboard, bundle: .main).instantiateViewController(
            withIdentifier: Constants.secondVC) as? AddTaskViewController else {
            fatalError("Unable to Instantiate Quotes View Controller")
        }
        
        let todoSection = todos[indexPath.section]
        
        _ = secondeVC.view
        secondeVC.configure(with: todoSection[indexPath.row])
        secondeVC.type = .edit
        secondeVC.delegate = self
        navigationController?.pushViewController(secondeVC, animated: true)
        
        selectedIndex = indexPath.row
    }
    
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { // swipe deleted todo
        if (editingStyle == UITableViewCell.EditingStyle.delete) {
            todos.remove(at: indexPath.section)
            tableView.reloadData()
        }
    }
}

// MARK: - Extensions
extension TableViewController: AddTaskVCDelegate {
    // here we get data from the second view
    func didCreateToDo(todo: ToDoItem) {
        todos.append([todo]) // add a new element to the array
        tableView.reloadData() // reload the table
    }
    
    func didUpdateToDo(todo: ToDoItem) {
        guard let index = selectedIndex else { return }
        todos[index] = [todo]
        tableView.reloadData()
    }
    
    func didDeleteToDo() { // add protocol method for delete todo
        guard let index = selectedIndex else { return }
        todos.remove(at: index)
        tableView.reloadData()
    }
    
    
}

I thought that the problem is how I display the sections of the table, but I did not find how to change it as I need it

1

There are 1 answers

4
Ahmet Hakan YILDIRIM On

Because you create a separate section for each task in your code, a new section is created for each new ToDo. You say you only need two parts: "Completed" and "Uncompleted". To fix this situation, you need to use a separate array for both parts.

Here are the steps you need to do:

1-) Define the todos array as a single array of type [ToDoItem]. This series will include completed and unfinished tasks.

private var todos = [ToDoItem]()

2-) Remove the todoStatus array because it will no longer be associated with any partition.

private var todoStatus: [ToDoStatus] = [.completed, .planned] 

3-) Let the numberOfSections function return 2 as a constant. This value can remain constant as there will always be only two partitions.

override func numberOfSections(in tableView: UITableView) -> Int {
return 2

}

4-) Update the tableView(_:numberOfRowsInSection:) function. Filter the todos array accordingly to return the number of tasks in each section.

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 { 
    return todos.filter { $0.status == .completed }.count
} else { 
    return todos.filter { $0.status == .planned }.count
}

}

5-) Update the cellForRowAt function. Based on the section number and line number, get the corresponding ToDo and configure the cell.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: Constants.cellIndentifier, for: indexPath) as? TableViewCell else {
    return UITableViewCell()
}

let todo: ToDoItem
if indexPath.section == 0 { 
    let completedTodos = todos.filter { $0.status == .completed }
    todo = completedTodos[indexPath.row]
} else { 
    let plannedTodos = todos.filter { $0.status == .planned }
    todo = plannedTodos[indexPath.row]
}

cell.configureCell(with: todo)
return cell

}

With these changes, you will keep all the ToDo items within the todos array and filter the related tasks in each section.