swift – Create buttons with MVVM architecture

im trying to migrate my very large swift view controller to mvvm but it still feels very large, can you guys give me any advice

What this controller does is simple it shows a UIView on which i can draw the buttons that I display are here to manage the lines that i have drawn on the canvas.

For example to delete the last line drawn, delete all lines, change the color etc …

What I want to do is to create my buttons while conforming to MVVM, so its not as ugly as my view controller is right now

@objc class VideoEditorViewController: UIViewController {
    
    let canvas = Canvas()
    let picker = UIColorPickerViewController()
    
    
    func setCanvasUI() {
        self.view.addSubview(canvas)
        canvas.backgroundColor = .clear
        let undoButton = CanvasButtonsViewModel(frame: .zero)
        undoButton.configure(with: CanvasModelButtonModel(image:
                                                        UIImage(systemName: "arrowshape.turn.up.left.fill")?
                                                        .withTintColor(.white, renderingMode: .alwaysOriginal), width: 50, height: 50, backgroundColor: .white))
        undoButton.addTarget(self, action: #selector(handleUndo), for: .touchUpInside)
        let colorPicker = CanvasButtonsViewModel(frame: .zero)
        colorPicker.configure(with: CanvasModelButtonModel(image:
                                                        UIImage(systemName: "pencil.circle")?
                                                        .withTintColor(.white, renderingMode: .alwaysOriginal), width: 50, height: 50, backgroundColor: .white))
        colorPicker.addTarget(self, action: #selector(ColorPicker), for: .touchUpInside)
        let trashCanButton = CanvasButtonsViewModel(frame: .zero)
        trashCanButton.configure(with: CanvasModelButtonModel(image:
                                                        UIImage(systemName: "trash")?
                                                        .withTintColor(.white, renderingMode: .alwaysOriginal), width: 50, height: 50, backgroundColor: .white))
        trashCanButton.addTarget(self, action: #selector(handleClear), for: .touchUpInside)
        let uploadViewButton = CanvasButtonsViewModel(frame: .zero)
        uploadViewButton.configure(with: CanvasModelButtonModel(image:
                                                                    UIImage(systemName: "envelope")?
                                                                    .withTintColor(.white, renderingMode: .alwaysOriginal), width: 51, height: 48, backgroundColor: .white))
        let test = CanvasButtonsViewModel(frame: .zero)
        test.configure(with: CanvasModelButtonModel(image:
                                                                    UIImage(systemName: "pencil.circle")?
                                                                    .withTintColor(.white, renderingMode: .alwaysOriginal), width: 51, height: 48, backgroundColor: .white))
        test.addTarget(self, action: #selector(testdraw), for: .touchUpInside)
        let stackView = UIStackView(arrangedSubviews: (
            undoButton,
            trashCanButton,
            colorPicker,
            uploadViewButton,
            test
            
        ))
        view.addSubview(stackView)
        stackView.axis = .vertical
        stackView.bringSubviewToFront(self.view)
        stackView.spacing = 30
        stackView.snp.makeConstraints { (make) in
            make.right.equalTo(view.snp_rightMargin).offset(-20)
            make.top.equalTo(view.snp_topMargin)
        }
        canvas.frame = view.frame
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        setCanvasUI()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}


extension VideoEditorViewController: UIColorPickerViewControllerDelegate, UIImagePickerControllerDelegate {
    @objc func handleUndo() {
        canvas.undo()
    }
    @objc func handleClear() {
        canvas.undoAll()
    }
    @objc func ColorPicker() {
        present(picker, animated: true, completion: nil)
        canvas.setStrokeColor(color: picker.selectedColor)
    }
    @objc func testdraw() {
        if (canvas.isDrawable == false) {
            canvas.setDrawable(state: true)
            return
        }
        if (canvas.isDrawable == true) {
            canvas.setDrawable(state: false)
            return
        }
    }
}

Canvas View :

import Foundation
import UIKit
import SnapKit

class Canvas: UIView {
    
    private var strokeColor = UIColor.black
    private var strokeWidth: Float = 10
    public var isDrawable: Bool = false
    
    public func setStrokeColor(color: UIColor) {
        self.strokeColor = color
    }
    
    public func setDrawable(state: Bool) {
        self.isDrawable = state
    }
    
    public func undo() {
        _ = lines.popLast()
        setNeedsDisplay()
    }
    public func undoAll() {
        lines.removeAll()
        setNeedsDisplay()
    }
    
    public func changeWidth(width: Float) {
        self.strokeWidth = width
        setNeedsDisplay()
    }
    public func draw() {
        guard let context = UIGraphicsGetCurrentContext() else { return }
    
        lines.forEach { (line) in
            context.setStrokeColor(line.color.cgColor)
            context.setLineWidth(CGFloat(line.strokeWidth))
            context.setLineCap(.round)
        for(i, p) in line.points.enumerated() {
                if (i == 0) {
                    context.move(to: p)
                } else {
                    context.addLine(to: p)
                }
            }
            context.strokePath()
        }
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        if (isDrawable == true) {
            draw()
        }
    }
    var lines = (Line)()
    
    
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        lines.append(Line.init(strokeWidth: strokeWidth, color: strokeColor, points: (), drawable: isDrawable))
    }
    
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        if (isDrawable == true) {
            guard let point = touches.first?.location(in: nil) else { return }
        
            guard var lastLine = lines.popLast() else { return }
            lastLine.points.append(point)
            lines.append(lastLine)
            print(point)
            setNeedsDisplay()
        }
    }
}

Canvas Struct to draw lines :

struct Line {
    let strokeWidth: Float
    let color: UIColor
    var points: (CGPoint)
    var drawable: Bool
}

My view model

final class CanvasButtonsViewModel: UIButton {
    
    let image: UIImageView = {
        let image = UIImageView()
        image.image = UIImage()
        image.image?.withTintColor(.white, renderingMode: .alwaysOriginal)
        return image
    }()

    func setConfig(size: CGFloat) -> UIImage.SymbolConfiguration {
        let largeConfig = UIImage.SymbolConfiguration(pointSize: size, weight: .bold, scale: .large)
        return largeConfig
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func configure(with viewModel: CanvasModelButtonModel) {
        self.addSubview(image)
        image.image = viewModel.image
        image.frame = CGRect(x: 0, y: 0, width: viewModel.width, height: viewModel.height)
    }
    override func layoutSubviews() {
        super.layoutSubviews()
    }
}

The model

struct CanvasModelButtonModel {
    let image: UIImage?
    let width: CGFloat
    let height: CGFloat
    let backgroundColor: UIColor?
}