Persistent To-Do Application

We will develop a console application which could have a friendly UX and persistent data storage. In this beginner project, we will demonstrate various object-oriented programming features and list manipulations along with file handling. Our end project would something like this.
 
Persistent To-Do Application 
 
Persistent To-Do Application
 
First, create a new console application and name it, such as - to-do app.
 
Persistent To-Do Application 
 
A new project will start. First, we will start off by creating the persistent data communication layer. For this, we are maintaining a file where our to-do task would be stored. We will create a class named DataPersistence for that.
  1. public class DataPersistence  
  2.     {  
  3.          //constructor which would make the file if the file does not exist
  4.         public DataPersistence()  
  5.         {  
  6.             if (!File.Exists(fileName))  
  7.             {  
  8.                 File.Create(fileName);  
  9.             }  
  10.         }  
  11.   
  12.          //the file would be stored at the base directory
  13.         string fileName = AppDomain.CurrentDomain.BaseDirectory + "/app-data.txt";           
  14.   
  15.          //Function for loading up the data
  16.         public List<string> loadData()  
  17.         {  
  18.             return System.IO.File.ReadAllLines(fileName).ToList();  
  19.         }  
  20.   
  21.          //adding new task on my list
  22.         public bool addData(string model)  
  23.         {  
  24.             try  
  25.             {  
  26.                 using (System.IO.StreamWriter file =  
  27.             new System.IO.StreamWriter(fileName, true))  
  28.                 {  
  29.                     file.WriteLine(model);  
  30.                 }  
  31.                   
  32.                 return true;  
  33.             }  
  34.             catch (Exception)  
  35.             {  
  36.                 throw;  
  37.             }   
  38.         }  
  39.   
  40.          //reseting the whole list
  41.         public bool resetList()  
  42.         {  
  43.             File.WriteAllText(fileName, string.Empty);  
  44.             return true;  
  45.         }  
  46.   
  47.          //complete the task or remove the task from the list
  48.         internal bool completeTask(string selectedTask)  
  49.         {  
  50.             try  
  51.             {  
  52.                 var lines = File.ReadAllLines(fileName).Where(line => line.Trim() != selectedTask.Trim()).ToArray();  
  53.                 File.WriteAllLines(fileName, lines);  
  54.                 return true;  
  55.             }  
  56.             catch (Exception e)  
  57.             {  
  58.                 return false;  
  59.             }              
  60.         }  
  61.     }  
We now need to access this data from our application. For that, we create our class ToDoApp. It is advisable to separate the data layer and the application layer. This would create an instance of the DataPersistence class and all the functions will first perform operations on the local list then will move on to the file operations.
  1. public class ToDoApp  
  2.     {  
  3.         private List<string> toDoList = new List<string>(); 
  4.  
  5.         DataPersistence dp = new DataPersistence();  //creating an instance of dataPersistence class
  6.   
  7.         public List<string> fetchData()  
  8.         {  
  9.             //loading the data from the file
  10.             toDoList = dp.loadData();  
  11.             return toDoList;  
  12.         }  
  13.   
  14.          //its time to add new task to our list
  15.         public bool addData(string model)  
  16.         {  
  17.             try  
  18.             {  
  19.                 if (model == null || model == "")  
  20.                 {  
  21.                     return false;  
  22.                 }  
  23.   
  24.                 toDoList.Add(model);  
  25.                 dp.addData(model);  
  26.                 return true;  
  27.             }  
  28.             catch (Exception e)  
  29.             {  
  30.                 return false;  
  31.             }  
  32.         }  
  33.   
  34.          //user might want to reset the whole list
  35.         public bool resetList()  
  36.         {  
  37.             try  
  38.             {  
  39.                 toDoList.Clear();  
  40.                 return dp.resetList();  
  41.             }  
  42.             catch (Exception e)  
  43.             {  
  44.                 throw;  
  45.             }  
  46.         }  
  47.   
  48.          //to complete or delete the task from our to-do list
  49.         internal bool completeTask(string userInput)  
  50.         {  
  51.             try  
  52.             {  
  53.                 toDoList = dp.loadData();  
  54.                 int index = Convert.ToInt32(userInput) -1;  
  55.                 if (index <= toDoList.Count)  
  56.                 {  
  57.                     string selectedTask = toDoList.ElementAt(index);  
  58.                     toDoList.Remove(selectedTask);  
  59.                     return dp.completeTask(selectedTask);  
  60.                 }  
  61.   
  62.                 return false;  
  63.             }  
  64.             catch (Exception e)  
  65.             {  
  66.                 return false;  
  67.             }  
  68.         }  
  69.     }  
These classes are standalone classes. We need to access these from our main class.  
  1. class Program  
  2.    {  
  3.        static void Main(string[] args)  
  4.        {  
  5.            Console.Title = "To-Do Application";              //creating a title for our application
  6.            fetchData();              
  7.            Console.ReadLine();  
  8.        }  
  9.   
  10.        private static void fetchData(string message = null
  11.        {  
  12.            Console.Clear();  
  13.             
  14.             //N.B : We would never access the data accessing class from this main class.
  15.            ToDoApp app = new ToDoApp();  //creating an instance of the middle layer 

  16.            List<string> list = app.fetchData();  
  17.            Console.WriteLine("\t \t \t \t \t Welcome to the To-Do application \n");  
  18.            Console.WriteLine("\t [ Press x to Exit ] \t [ Enter index to complete task ] \t [ Press r to Reset ] \n \n");  
  19.   
  20.            int num = 1;  
  21.            foreach(string text in list)  
  22.            {  
  23.                Console.WriteLine("\t" + num.ToString() + ".  " + text + "\n");  //for displaying the data from the list
  24.                num++;  
  25.            }  
  26.   
  27.            if(message!="" && message!= null)  
  28.            {  
  29.                Console.WriteLine("\t \t \t \t"+message);   
  30.            }  
  31.   
  32.            Console.WriteLine("\n Write Task or press operational key to continue");  
  33.            string userInput = Console.ReadLine();  //awaiting user input
  34.            switchTask(userInput);  
  35.        }  
  36.   
  37.       //A function to operate differently on the basis of user input
  38.        private static void switchTask(string userInput)  
  39.        {  
  40.            ToDoApp app = new ToDoApp();  
  41.            switch (userInput.ToLower())  
  42.            {  
  43.                case "x"//to exit the console
  44.                    Console.Clear();                      
  45.                    Environment.Exit(0);  
  46.                    break;                 
  47.                case "r":  
  48.                    app.resetList();  
  49.                    fetchData("Reset succesfull !");  
  50.                    break;  
  51.                default:  
  52.                    int index;  
  53.                    bool isNumeric = int.TryParse(userInput, out index);  
  54.                    if (!isNumeric)  
  55.                    {  
  56.                        app.addData(userInput);  
  57.                        fetchData("Added Succesfully !");  
  58.                    }  
  59.                    else  
  60.                    {  
  61.                        bool isOkay = app.completeTask(userInput);  
  62.                        if (isOkay)  
  63.                            fetchData(@"Completed Task "+ userInput + " successfully !");  
  64.                        else  
  65.                            fetchData(@"No task at " + userInput + " !");   
  66.                    }  
  67.                    break;  

  68.                   //Note that after every operation we are returning it back to the fetchData() function with a feedback message. This would allow the user to re-enter as much as they want.
  69.            }  
  70.        }  
  71.    }