Added about page, and better file operation.
This commit is contained in:
		
							parent
							
								
									aded0b6400
								
							
						
					
					
						commit
						c25f04ad15
					
				
							
								
								
									
										3
									
								
								dub.json
								
								
								
								
							
							
						
						
									
										3
									
								
								dub.json
								
								
								
								
							|  | @ -4,7 +4,8 @@ | ||||||
| 	], | 	], | ||||||
| 	"copyright": "Copyright © 2022, Andrew Lalis", | 	"copyright": "Copyright © 2022, Andrew Lalis", | ||||||
| 	"dependencies": { | 	"dependencies": { | ||||||
| 		"gtk-d": "~>3.10.0" | 		"gtk-d": "~>3.10.0", | ||||||
|  | 		"dsh": "~>1.6.1" | ||||||
| 	}, | 	}, | ||||||
| 	"stringImportPaths": [ | 	"stringImportPaths": [ | ||||||
| 		"resources" | 		"resources" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| { | { | ||||||
| 	"fileVersion": 1, | 	"fileVersion": 1, | ||||||
| 	"versions": { | 	"versions": { | ||||||
|  | 		"dsh": "1.6.1", | ||||||
| 		"gtk-d": "3.10.0" | 		"gtk-d": "3.10.0" | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -107,6 +107,7 @@ | ||||||
|                         <property name="can_focus">False</property> |                         <property name="can_focus">False</property> | ||||||
|                         <property name="use_underline">True</property> |                         <property name="use_underline">True</property> | ||||||
|                         <property name="use_stock">True</property> |                         <property name="use_stock">True</property> | ||||||
|  |                         <signal name="activate" handler="onAboutMenuActivated" swapped="no"/> | ||||||
|                       </object> |                       </object> | ||||||
|                     </child> |                     </child> | ||||||
|                   </object> |                   </object> | ||||||
|  |  | ||||||
							
								
								
									
										53
									
								
								source/app.d
								
								
								
								
							
							
						
						
									
										53
									
								
								source/app.d
								
								
								
								
							|  | @ -2,6 +2,9 @@ import model; | ||||||
| 
 | 
 | ||||||
| import std.stdio; | import std.stdio; | ||||||
| import std.functional : toDelegate; | import std.functional : toDelegate; | ||||||
|  | import dsh : getHomeDir; | ||||||
|  | import std.path; | ||||||
|  | import std.file; | ||||||
| 
 | 
 | ||||||
| import gtk.MainWindow; | import gtk.MainWindow; | ||||||
| import gtk.Main; | import gtk.Main; | ||||||
|  | @ -63,6 +66,7 @@ void main(string[] args) { | ||||||
| 	builder.addCallbackSymbol("onSaveAsMenuActivated", &onSaveAsMenuActivated); | 	builder.addCallbackSymbol("onSaveAsMenuActivated", &onSaveAsMenuActivated); | ||||||
| 	builder.addCallbackSymbol("onOpenMenuActivated", &onOpenMenuActivated); | 	builder.addCallbackSymbol("onOpenMenuActivated", &onOpenMenuActivated); | ||||||
| 	builder.addCallbackSymbol("onQuitMenuActivated", &onWindowDestroy); | 	builder.addCallbackSymbol("onQuitMenuActivated", &onWindowDestroy); | ||||||
|  | 	builder.addCallbackSymbol("onAboutMenuActivated", &onAboutMenuActivated); | ||||||
| 	builder.connectSignals(null); | 	builder.connectSignals(null); | ||||||
| 
 | 
 | ||||||
| 	taskList = cast(ListBox) builder.getObject("taskList"); | 	taskList = cast(ListBox) builder.getObject("taskList"); | ||||||
|  | @ -71,13 +75,32 @@ void main(string[] args) { | ||||||
| 	taskEntry = cast(Entry) builder.getObject("addTaskEntry"); | 	taskEntry = cast(Entry) builder.getObject("addTaskEntry"); | ||||||
| 
 | 
 | ||||||
| 	todoModel = new ToDoModel(); | 	todoModel = new ToDoModel(); | ||||||
| 	todoModel.addListener(ModelUpdateListener.of(toDelegate(&itemsUpdated))); | 	string lastOpenPath = buildPath(getHomeDir(), ".config/todo-d/last-open.txt"); | ||||||
|  | 	if (exists(lastOpenPath)) { | ||||||
|  | 		import std.string : strip; | ||||||
|  | 		string lastOpenFile = readText(lastOpenPath).strip; | ||||||
|  | 		todoModel.openFromJson(lastOpenFile); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	window = cast(ApplicationWindow) builder.getObject("window"); | 	window = cast(ApplicationWindow) builder.getObject("window"); | ||||||
|  | 	auto listener = new UIModelUpdateListener(window); | ||||||
|  | 	todoModel.addListener(listener); | ||||||
|  | 
 | ||||||
|  | 	// Trigger UI updates once before rendering the window.
 | ||||||
|  | 	todoModel.notifyListeners(); | ||||||
|  | 	listener.fileUpdated(todoModel.getOpenFilename()); | ||||||
|  | 
 | ||||||
| 	window.showAll(); | 	window.showAll(); | ||||||
| 	Main.run(); | 	Main.run(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | class UIModelUpdateListener : ModelUpdateListener { | ||||||
|  | 	private ApplicationWindow window; | ||||||
|  | 
 | ||||||
|  | 	this(ApplicationWindow window) { | ||||||
|  | 		this.window = window; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	void itemsUpdated(ToDoItem[] items) { | 	void itemsUpdated(ToDoItem[] items) { | ||||||
| 		taskList.removeAll(); | 		taskList.removeAll(); | ||||||
| 		foreach (item; items) { | 		foreach (item; items) { | ||||||
|  | @ -91,6 +114,16 @@ void itemsUpdated(ToDoItem[] items) { | ||||||
| 		taskList.showAll(); | 		taskList.showAll(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |     void fileUpdated(string filename) { | ||||||
|  | 		if (filename is null) { | ||||||
|  | 			window.setTitle("todo-d"); | ||||||
|  | 		} else { | ||||||
|  | 			window.setTitle("todo-d - " ~ filename); | ||||||
|  | 		} | ||||||
|  | 		window.showAll(); | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool taskListKeyPressed(GdkEventKey* event, Widget w) { | bool taskListKeyPressed(GdkEventKey* event, Widget w) { | ||||||
| 	int idx = taskList.getSelectedRow().getIndex(); | 	int idx = taskList.getSelectedRow().getIndex(); | ||||||
| 	int selectedPrio = idx + 1; | 	int selectedPrio = idx + 1; | ||||||
|  | @ -146,6 +179,12 @@ extern (C) void onWindowDestroy() { | ||||||
| 	Main.quit(); | 	Main.quit(); | ||||||
| 	if (todoModel.getOpenFilename() !is null) { | 	if (todoModel.getOpenFilename() !is null) { | ||||||
| 		todoModel.saveToJson(todoModel.getOpenFilename()); | 		todoModel.saveToJson(todoModel.getOpenFilename()); | ||||||
|  | 		string configPath = buildPath(getHomeDir(), ".config/todo-d/"); | ||||||
|  | 		if (!exists(configPath)) { | ||||||
|  | 			mkdirRecurse(configPath); | ||||||
|  | 		} | ||||||
|  | 		string lastOpenFile = buildPath(configPath, "last-open.txt"); | ||||||
|  | 		std.file.write(lastOpenFile, todoModel.getOpenFilename()); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -191,3 +230,15 @@ extern (C) void onOpenMenuActivated() { | ||||||
| 	} | 	} | ||||||
| 	dialog.close(); | 	dialog.close(); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | extern (C) void onAboutMenuActivated() { | ||||||
|  | 	import gtk.AboutDialog; | ||||||
|  | 	AboutDialog dialog = new AboutDialog(); | ||||||
|  | 	dialog.setProgramName("Todo-D"); | ||||||
|  | 	dialog.setLicenseType(GtkLicense.MIT_X11); | ||||||
|  | 	dialog.setAuthors(["Andrew Lalis"]); | ||||||
|  | 	dialog.setComments("A simple To-Do app written in D using GTK."); | ||||||
|  | 	dialog.setWebsite("https://github.com/andrewlalis/todo-d"); | ||||||
|  | 	dialog.run(); | ||||||
|  | 	dialog.destroy(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -13,14 +13,7 @@ class ToDoItem { | ||||||
| 
 | 
 | ||||||
| interface ModelUpdateListener { | interface ModelUpdateListener { | ||||||
|     void itemsUpdated(ToDoItem[] items); |     void itemsUpdated(ToDoItem[] items); | ||||||
| 
 |     void fileUpdated(string filename); | ||||||
|     static ModelUpdateListener of(void delegate(ToDoItem[]) dg) { |  | ||||||
|         return new class ModelUpdateListener { |  | ||||||
|             void itemsUpdated(ToDoItem[] items) { |  | ||||||
|                 dg(items); |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| class ToDoModel { | class ToDoModel { | ||||||
|  | @ -108,7 +101,10 @@ class ToDoModel { | ||||||
|             ); |             ); | ||||||
|             items ~= item; |             items ~= item; | ||||||
|         } |         } | ||||||
|  |         if (openFilename != filename) { | ||||||
|             openFilename = filename; |             openFilename = filename; | ||||||
|  |             foreach (l; listeners) l.fileUpdated(filename); | ||||||
|  |         } | ||||||
|         sort!((a, b) => a.priority < b.priority)(items); |         sort!((a, b) => a.priority < b.priority)(items); | ||||||
|         normalizePrio(); |         normalizePrio(); | ||||||
|         notifyListeners(); |         notifyListeners(); | ||||||
|  | @ -128,12 +124,16 @@ class ToDoModel { | ||||||
|         } |         } | ||||||
|         j["items"] = JSONValue(itemObjs); |         j["items"] = JSONValue(itemObjs); | ||||||
|         write(filename, toJSON(j, true)); |         write(filename, toJSON(j, true)); | ||||||
|  |         if (openFilename != filename) { | ||||||
|             openFilename = filename; |             openFilename = filename; | ||||||
|  |             foreach (l; listeners) l.fileUpdated(filename); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void clear() { |     void clear() { | ||||||
|         items = []; |         items = []; | ||||||
|         openFilename = null; |         openFilename = null; | ||||||
|  |         foreach (l; listeners) l.fileUpdated(openFilename); | ||||||
|         notifyListeners(); |         notifyListeners(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue