local storage - fin
This commit is contained in:
		
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,3 @@
 | 
			
		||||
/target
 | 
			
		||||
/.idea
 | 
			
		||||
/todo-db.db3
 | 
			
		||||
/todolist-db.db3
 | 
			
		||||
							
								
								
									
										72
									
								
								src/db.rs
									
									
									
									
									
								
							
							
						
						
									
										72
									
								
								src/db.rs
									
									
									
									
									
								
							@@ -1,10 +1,8 @@
 | 
			
		||||
use crate::todo::{ChangeType, TaskColumn};
 | 
			
		||||
use rusqlite::{params, Connection, Error, Result};
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use rusqlite::{params, Connection, Result};
 | 
			
		||||
use crate::def;
 | 
			
		||||
use crate::def::Task;
 | 
			
		||||
 | 
			
		||||
pub(crate) fn startup(path: &Path) -> Result<(Connection)> {
 | 
			
		||||
    // let conn = Connection::open_in_memory()?;
 | 
			
		||||
    let conn = Connection::open(path)?;
 | 
			
		||||
    
 | 
			
		||||
    conn.execute(
 | 
			
		||||
@@ -16,32 +14,74 @@ pub(crate) fn startup(path: &Path) -> Result<(Connection)> {
 | 
			
		||||
        ()
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    // todo
 | 
			
		||||
    
 | 
			
		||||
    Ok(conn)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn get_tasks(conn: &Connection) -> Result<()> {
 | 
			
		||||
    let mut stmt = conn.prepare("SELECT checked, value FROM tasks")?;
 | 
			
		||||
    let task_iter = stmt.query_map([], |row| {
 | 
			
		||||
        Ok(Task {
 | 
			
		||||
            checked: row.get(0)?,
 | 
			
		||||
            value: row.get(1)?,
 | 
			
		||||
pub(crate) fn get_tasks(conn: &Connection) -> std::result::Result<Vec<TaskColumn>, Error> {
 | 
			
		||||
    let mut stmt = conn.prepare("SELECT id, checked, value FROM tasks")?;
 | 
			
		||||
    let tasks_iter = stmt.query_map([], |row| {
 | 
			
		||||
        Ok(TaskColumn {
 | 
			
		||||
            id: row.get(0)?,
 | 
			
		||||
            checked: row.get(1)?,
 | 
			
		||||
            value: row.get(2)?,
 | 
			
		||||
        })
 | 
			
		||||
    })?;
 | 
			
		||||
    
 | 
			
		||||
    for task in task_iter {
 | 
			
		||||
        println!("{:?}", task);
 | 
			
		||||
    let mut tasks = Vec::new();
 | 
			
		||||
    for task in tasks_iter {
 | 
			
		||||
        tasks.push(task?);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
    Ok(tasks)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn insert_task(task: Task, conn: &Connection) -> Result<()> {
 | 
			
		||||
pub(crate) fn insert_task(conn: &Connection, task: TaskColumn) -> Result<i64> {
 | 
			
		||||
    conn.execute(
 | 
			
		||||
        "INSERT INTO tasks (checked, value) VALUES (?1, ?2)",
 | 
			
		||||
        (&task.checked, &task.value),
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    Ok(conn.last_insert_rowid())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// happens if we un/select task or we rename the task
 | 
			
		||||
pub(crate) fn update_task(conn: &Connection, task: TaskColumn, change: ChangeType) -> Result<()> {
 | 
			
		||||
    let (query, params) = match change {
 | 
			
		||||
        ChangeType::Checked => (
 | 
			
		||||
            "UPDATE tasks SET checked = ?1 WHERE id = ?2",
 | 
			
		||||
            params![&task.checked, &task.id]
 | 
			
		||||
        ),
 | 
			
		||||
        ChangeType::Value => (
 | 
			
		||||
            "UPDATE tasks SET value = ?1 WHERE id = ?2",
 | 
			
		||||
            params![&task.value, &task.id]
 | 
			
		||||
        ),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    conn.execute(query, params)?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn update_unselect_tasks(conn: &Connection, checked: bool) -> Result<()> {
 | 
			
		||||
    conn.execute(
 | 
			
		||||
        "UPDATE tasks SET checked = ?1",
 | 
			
		||||
        (&checked,)
 | 
			
		||||
    )?;
 | 
			
		||||
    
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) fn delete_tasks(conn: &Connection, id: Option<usize>) -> Result<()> {
 | 
			
		||||
    let (query, params) = match id { 
 | 
			
		||||
        Some(t) => (
 | 
			
		||||
            "DELETE FROM tasks WHERE id = ?1",
 | 
			
		||||
            params![t.clone()]
 | 
			
		||||
        ),
 | 
			
		||||
        None => (
 | 
			
		||||
            "DELETE FROM tasks",
 | 
			
		||||
            params![]
 | 
			
		||||
        ),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    conn.execute(query, params)?;
 | 
			
		||||
    Ok(())
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								src/def.rs
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/def.rs
									
									
									
									
									
								
							@@ -1,35 +0,0 @@
 | 
			
		||||
use iced::Event;
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Task {
 | 
			
		||||
    pub(crate) checked: bool,
 | 
			
		||||
    pub(crate) value: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TaskData {
 | 
			
		||||
    pub(crate) checked: bool,
 | 
			
		||||
    pub(crate) value: String,
 | 
			
		||||
    pub(crate) edit: bool,
 | 
			
		||||
    pub(crate) can_update: bool,
 | 
			
		||||
    pub(crate) can_delete: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Todo {
 | 
			
		||||
    pub(crate) new_task: String,
 | 
			
		||||
    pub(crate) updated_task: String,
 | 
			
		||||
    pub(crate) tasks: Vec<TaskData>,
 | 
			
		||||
    pub(crate) completed_tasks: usize,
 | 
			
		||||
    pub(crate) local_storage: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum Message {
 | 
			
		||||
    AddTask,
 | 
			
		||||
    CheckTask(bool, usize),
 | 
			
		||||
    EditTask(usize),
 | 
			
		||||
    DeleteTask(usize),
 | 
			
		||||
    DeleteAll,
 | 
			
		||||
    ContentUpdated(bool, String),
 | 
			
		||||
    Event(Event),
 | 
			
		||||
    TaskPush(Option<usize>),
 | 
			
		||||
    StorageToggle(bool),
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										26
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -1,18 +1,14 @@
 | 
			
		||||
use std::path::Path;
 | 
			
		||||
use iced::window::Settings;
 | 
			
		||||
use iced::Size;
 | 
			
		||||
use def::Todo;
 | 
			
		||||
use crate::db::startup;
 | 
			
		||||
use crate::def::Task;
 | 
			
		||||
use todo::Todo;
 | 
			
		||||
 | 
			
		||||
mod todo;
 | 
			
		||||
mod def;
 | 
			
		||||
mod db;
 | 
			
		||||
 | 
			
		||||
/*fn main() -> iced::Result {
 | 
			
		||||
fn main() -> iced::Result {
 | 
			
		||||
    let settings = Settings {
 | 
			
		||||
        size: Size::new(500.0, 600.0),
 | 
			
		||||
        resizable: false,
 | 
			
		||||
        //resizable: false,
 | 
			
		||||
        ..Settings::default()
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
@@ -21,18 +17,20 @@ mod db;
 | 
			
		||||
        .theme(Todo::theme)
 | 
			
		||||
        .window(settings)
 | 
			
		||||
        .run()
 | 
			
		||||
}*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn main() {
 | 
			
		||||
    let path: &Path = Path::new("./todo-db.db3");
 | 
			
		||||
/*fn main() {
 | 
			
		||||
    let path: &Path = Path::new("./todolist-db.db3");
 | 
			
		||||
    let conn = startup(path);
 | 
			
		||||
    let t = Task {
 | 
			
		||||
        checked: true,
 | 
			
		||||
        value: String::from("Troll Ink"),
 | 
			
		||||
        value: String::from("JJ"),
 | 
			
		||||
    };
 | 
			
		||||
    let c = conn.unwrap();
 | 
			
		||||
    /*let r = db::insert_task(t, &c);
 | 
			
		||||
    println!("{:?}", r);*/
 | 
			
		||||
    let r = db::insert_task(t, &c);
 | 
			
		||||
    println!("{:?}", r);
 | 
			
		||||
    
 | 
			
		||||
    let rr = db::get_tasks(&c);
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
    let x = c.close();
 | 
			
		||||
}*/
 | 
			
		||||
							
								
								
									
										179
									
								
								src/todo.rs
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/todo.rs
									
									
									
									
									
								
							@@ -1,26 +1,77 @@
 | 
			
		||||
use iced::{event, keyboard, widget, Center, Element, Event, Length, Subscription, Task, Theme};
 | 
			
		||||
use iced::keyboard::key;
 | 
			
		||||
use iced::widget::{button, center, checkbox, column, row, scrollable, text_input, Space, Text};
 | 
			
		||||
use crate::def::{Message, TaskData, Todo};
 | 
			
		||||
use rusqlite::Connection;
 | 
			
		||||
use crate::db;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct TaskColumn {
 | 
			
		||||
     pub(crate) id: usize,
 | 
			
		||||
     pub(crate) checked: bool,
 | 
			
		||||
     pub(crate) value: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TaskData {
 | 
			
		||||
     id: usize,
 | 
			
		||||
     checked: bool,
 | 
			
		||||
     value: String,
 | 
			
		||||
     edit: bool,
 | 
			
		||||
     can_update: bool,
 | 
			
		||||
     can_delete: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub(crate) struct Todo {
 | 
			
		||||
     new_task: String,
 | 
			
		||||
     updated_task: String,
 | 
			
		||||
     tasks: Vec<TaskData>,
 | 
			
		||||
     completed_tasks: usize,
 | 
			
		||||
     local_storage: bool,
 | 
			
		||||
     conn: Connection,
 | 
			
		||||
     select_all: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
pub enum Message {
 | 
			
		||||
    AddTask,
 | 
			
		||||
    CheckTask(bool, usize),
 | 
			
		||||
    EditTask(usize),
 | 
			
		||||
    DeleteTask(usize),
 | 
			
		||||
    DeleteAll,
 | 
			
		||||
    ContentUpdated(bool, String),
 | 
			
		||||
    Event(Event),
 | 
			
		||||
    TaskPush(Option<usize>),
 | 
			
		||||
    StorageToggle(bool),
 | 
			
		||||
    ToggleUnselect(bool),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub enum ChangeType {
 | 
			
		||||
    Checked,
 | 
			
		||||
    Value,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Default for Todo {
 | 
			
		||||
    fn default() -> Self {
 | 
			
		||||
        Todo::new()
 | 
			
		||||
        // startup checks
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Todo {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self {
 | 
			
		||||
        let mut init = Self {
 | 
			
		||||
            new_task: String::new(),
 | 
			
		||||
            updated_task: String::new(),
 | 
			
		||||
            tasks: Vec::new(),
 | 
			
		||||
            completed_tasks: 0,
 | 
			
		||||
            local_storage: true,
 | 
			
		||||
        }
 | 
			
		||||
            local_storage: true, // todo eventually get this info from db - if no db set it to true
 | 
			
		||||
            conn: db::startup("./todolist-db.db3".as_ref()).expect("[ERROR] Failed to access the local storage"),
 | 
			
		||||
            select_all: false,
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        Self::load_data_from_db(&mut init);
 | 
			
		||||
        
 | 
			
		||||
        init
 | 
			
		||||
    }
 | 
			
		||||
    pub(crate) fn update(&mut self, message: Message) -> Task<Message> {
 | 
			
		||||
     pub(crate) fn update(&mut self, message: Message) -> Task<Message> {
 | 
			
		||||
        match message {
 | 
			
		||||
            Message::ContentUpdated(new, value) => {
 | 
			
		||||
                if new {
 | 
			
		||||
@@ -34,31 +85,60 @@ impl Todo {
 | 
			
		||||
            Message::AddTask => {
 | 
			
		||||
                if self.new_task.is_empty() { return Task::none(); }
 | 
			
		||||
 | 
			
		||||
                let data = TaskData {
 | 
			
		||||
 | 
			
		||||
                let result = db::insert_task(&self.conn, TaskColumn {
 | 
			
		||||
                    id: 0,
 | 
			
		||||
                    checked: false,
 | 
			
		||||
                    value: self.new_task.to_string(),
 | 
			
		||||
                    edit: false,
 | 
			
		||||
                    can_update: true,
 | 
			
		||||
                    can_delete: true,
 | 
			
		||||
                };
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                match result {
 | 
			
		||||
                    Ok(t) => {
 | 
			
		||||
                        let data = TaskData {
 | 
			
		||||
                            id: t as usize,
 | 
			
		||||
                            checked: false,
 | 
			
		||||
                            value: self.new_task.to_string(),
 | 
			
		||||
                            edit: false,
 | 
			
		||||
                            can_update: true,
 | 
			
		||||
                            can_delete: true,
 | 
			
		||||
                        };
 | 
			
		||||
                        self.tasks.push(data);
 | 
			
		||||
                    },
 | 
			
		||||
                    Err(e) => eprintln!("[ERROR] Failed to insert new task into DB:\n{e}"),
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                self.tasks.push(data);
 | 
			
		||||
                self.new_task = String::new();
 | 
			
		||||
 | 
			
		||||
                Task::none()
 | 
			
		||||
            },
 | 
			
		||||
            Message::DeleteTask(id) => {
 | 
			
		||||
                if self.tasks[id].checked {
 | 
			
		||||
            Message::DeleteTask(index) => {
 | 
			
		||||
                if self.tasks[index].checked {
 | 
			
		||||
                    self.completed_tasks -= 1;
 | 
			
		||||
                }
 | 
			
		||||
                self.tasks.remove(id);
 | 
			
		||||
                
 | 
			
		||||
                if let Err(e) = db::delete_tasks(&self.conn, Some(self.tasks[index].id)) {
 | 
			
		||||
                    eprintln!("[ERROR] Failed to delete task '{}':\n{e}", self.tasks[index].value);
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                self.tasks.remove(index);
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                Task::none()
 | 
			
		||||
            },
 | 
			
		||||
            }
 | 
			
		||||
            Message::CheckTask(choice, id) => {
 | 
			
		||||
                self.completed_tasks = if choice { self.completed_tasks + 1 } else { self.completed_tasks - 1 };
 | 
			
		||||
                self.tasks[id].checked = choice;
 | 
			
		||||
 | 
			
		||||
                let result = db::update_task(&self.conn, TaskColumn {
 | 
			
		||||
                    id: self.tasks[id].id,
 | 
			
		||||
                    checked: self.tasks[id].checked,
 | 
			
		||||
                    value: self.tasks[id].value.to_string(),
 | 
			
		||||
                }, ChangeType::Checked);
 | 
			
		||||
                
 | 
			
		||||
                if let Err(e) = result {
 | 
			
		||||
                    eprintln!("[ERROR] Failed to update checkbox in local storage:\n{e}");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Task::none()
 | 
			
		||||
            },
 | 
			
		||||
            Message::EditTask(id) => {
 | 
			
		||||
@@ -70,6 +150,16 @@ impl Todo {
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    self.tasks[id].value = self.updated_task.clone();
 | 
			
		||||
                    let result = db::update_task(&self.conn, TaskColumn {
 | 
			
		||||
                        id: self.tasks[id].id,
 | 
			
		||||
                        checked: self.tasks[id].checked,
 | 
			
		||||
                        value: self.tasks[id].value.to_string(),
 | 
			
		||||
                    }, ChangeType::Value);
 | 
			
		||||
                    
 | 
			
		||||
                    if let Err(e) = result {
 | 
			
		||||
                        eprintln!("[ERROR] Failed to update task '{}' in local storage:\n{e}", self.tasks[id].value);
 | 
			
		||||
                    }
 | 
			
		||||
                    
 | 
			
		||||
                    set_update = true;
 | 
			
		||||
                    self.updated_task = String::new();
 | 
			
		||||
                } else {
 | 
			
		||||
@@ -82,6 +172,10 @@ impl Todo {
 | 
			
		||||
                widget::focus_previous()
 | 
			
		||||
            },
 | 
			
		||||
            Message::DeleteAll => {
 | 
			
		||||
                if let Err(e) = db::delete_tasks(&self.conn, None) {
 | 
			
		||||
                    eprintln!("[ERROR] Failed to delete all tasks:\n{e}")
 | 
			
		||||
                }
 | 
			
		||||
                    
 | 
			
		||||
                self.new_task = String::from("");
 | 
			
		||||
                self.updated_task = String::from("");
 | 
			
		||||
                self.tasks.clear();
 | 
			
		||||
@@ -121,7 +215,8 @@ impl Todo {
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            Message::StorageToggle(toggle) => {
 | 
			
		||||
                self.local_storage = toggle;
 | 
			
		||||
                // todo must be enabled eventually
 | 
			
		||||
                //self.local_storage = toggle;
 | 
			
		||||
 | 
			
		||||
                /*
 | 
			
		||||
                todo
 | 
			
		||||
@@ -129,12 +224,32 @@ impl Todo {
 | 
			
		||||
                as the system should be running since the program startup
 | 
			
		||||
                */
 | 
			
		||||
                
 | 
			
		||||
                // also how do we even implement that
 | 
			
		||||
 | 
			
		||||
                Task::none()
 | 
			
		||||
            },
 | 
			
		||||
            Message::ToggleUnselect(toggle) => {
 | 
			
		||||
                self.select_all = toggle;
 | 
			
		||||
                for task in &mut self.tasks {
 | 
			
		||||
                    task.checked = toggle;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if toggle {
 | 
			
		||||
                    self.completed_tasks = self.tasks.len();
 | 
			
		||||
                } else { 
 | 
			
		||||
                    self.completed_tasks = 0;
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                if let Err(e) = db::update_unselect_tasks(&self.conn, toggle) {
 | 
			
		||||
                    eprintln!("[ERROR] Failed to update un/select all operation in database:\n{e}");
 | 
			
		||||
                }
 | 
			
		||||
                
 | 
			
		||||
                Task::none()
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn view(&self) -> Element<Message> {
 | 
			
		||||
     pub(crate) fn view(&self) -> Element<Message> {
 | 
			
		||||
        let input = text_input("Enter new task", &self.new_task)
 | 
			
		||||
            .width(300)
 | 
			
		||||
            .size(25)
 | 
			
		||||
@@ -186,8 +301,9 @@ impl Todo {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let status = Text::new(format!("{} / {}", self.completed_tasks, self.tasks.len()));
 | 
			
		||||
        let unselect = checkbox("Un/select all", self.select_all).on_toggle(Message::ToggleUnselect);
 | 
			
		||||
        let storage = checkbox("Local storage", self.local_storage).on_toggle(Message::StorageToggle);
 | 
			
		||||
        let footer = row![status, Space::with_width(Length::Fill), storage].padding(10);
 | 
			
		||||
        let footer = row![status, Space::with_width(Length::Fill), unselect, storage].padding(10).spacing(10);
 | 
			
		||||
 | 
			
		||||
        let mut output = column![new_task.padding(10)];
 | 
			
		||||
        output = if self.tasks.is_empty() { output.push(saved_tasks.height(Length::Fill)) } else { output.push(scrollable(saved_tasks).height(Length::Fill).spacing(10)) };
 | 
			
		||||
@@ -196,11 +312,11 @@ impl Todo {
 | 
			
		||||
        center(output).into()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn theme(&self) -> Theme {
 | 
			
		||||
     pub(crate) fn theme(&self) -> Theme {
 | 
			
		||||
        Theme::Dark
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn subscription(&self) -> Subscription<Message> {
 | 
			
		||||
     pub(crate) fn subscription(&self) -> Subscription<Message> {
 | 
			
		||||
        event::listen().map(Message::Event)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -212,4 +328,25 @@ impl Todo {
 | 
			
		||||
            task.can_delete = enable;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn load_data_from_db(&mut self) {
 | 
			
		||||
        if let Ok(t) = db::get_tasks(&self.conn) {
 | 
			
		||||
            for item in t {
 | 
			
		||||
                let data = TaskData {
 | 
			
		||||
                    id: item.id,
 | 
			
		||||
                    checked: item.checked,
 | 
			
		||||
                    value: item.value,
 | 
			
		||||
                    edit: false,
 | 
			
		||||
                    can_update: true,
 | 
			
		||||
                    can_delete: true,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                if item.checked {
 | 
			
		||||
                    self.completed_tasks += 1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                self.tasks.push(data);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user