From 02422319ca56683e69ded4a69618cfaeafb97cbd Mon Sep 17 00:00:00 2001 From: Xuan Sang LE Date: Tue, 30 Jan 2018 14:47:27 +0100 Subject: [PATCH] add file sync mechanism between apps --- src/core/core.coffee | 8 +++ src/core/gui.coffee | 47 +++++++------ src/core/tags/afx-file-view.js | 10 +-- src/core/vfs.coffee | 66 ++++++++++++++++--- .../CoreServices/PushNotification.coffee | 1 + src/packages/Files/main.coffee | 20 +++--- src/packages/MarkOn/main.coffee | 53 ++++++++++++++- src/packages/NotePad/package.json | 2 +- 8 files changed, 161 insertions(+), 46 deletions(-) diff --git a/src/core/core.coffee b/src/core/core.coffee index 56524e2..4b5995d 100644 --- a/src/core/core.coffee +++ b/src/core/core.coffee @@ -88,7 +88,15 @@ self.OS or= ($ "#wrapper").empty() _GUI.clearTheme() _courrier.observable = riot.observable() + _courrier.quota = 0 _OS.APP = {} + _OS.setting = + user: {} + applications: {} + desktop: {} + appearance: {} + VFS: {} + system: {} _PM.processes = {} _PM.pidalloc = 0 diff --git a/src/core/gui.coffee b/src/core/gui.coffee index 4e1582e..8567183 100644 --- a/src/core/gui.coffee +++ b/src/core/gui.coffee @@ -61,7 +61,7 @@ self.OS.GUI = _courrier.osfail "Cannot read service script: #{srv} ", e, s appsByMime: (mime) -> - metas = ( a.meta for k, a of _OS.APP when a and a.type is 1) + metas = ( v for k, v of _OS.setting.system.packages when v.app ) mimes = ( m.mimes for m in metas when m) apps = [] # search app by mimes @@ -80,9 +80,9 @@ self.OS.GUI = openWith: (it) -> return unless it - console.log "open #{it.path}" + return _GUI.launch it.app if it.type is "app" and it.app apps = _GUI.appsByMime ( if it.type is "dir" then "dir" else it.mime ) - return OS.info "No application available to open #{it.filename}" if apps.length is 0 + return _courrier.osinfo "No application available to open #{it.filename}" if apps.length is 0 return _GUI.launch apps[0].app, [it.path] if apps.length is 1 list = ( { text: e.app, icon: e.icon, iconclass: e.iconclass } for e in apps ) _GUI.openDialog "SelectionDialog", ( d ) -> @@ -186,8 +186,8 @@ self.OS.GUI = # desktop default file manager desktop = $ "#desktop" + fp = _OS.setting.desktop.path.asFileHandler() desktop[0].fetch = () -> - fp = _OS.setting.desktop.path.asFileHandler() fn = () -> fp.read (d) -> return _courrier.osfail d.error, (_API.throwe "OS.VFS"), d.error if d.error @@ -239,7 +239,9 @@ self.OS.GUI = console.log "context menu handler for desktop" desktop[0].fetch() - _courrier.trigger "desktoploaded" + _courrier.observable.on "VFS", (d) -> + desktop[0].fetch() if d.data.file.hash() is fp.hash() or d.data.file.parent().hash() is fp.hash() + _courrier.ostrigger "desktoploaded" # mount it riot.mount desktop , (e, s) -> @@ -256,7 +258,7 @@ self.OS.GUI = child: [ { text: "Application", - child: [], + child: ( v for k, v of _OS.setting.system.packages when v.app ), dataid: "sys-apps" iconclass: "fa fa-adn", onmenuselect: (d) -> @@ -273,13 +275,7 @@ self.OS.GUI = return _API.handler.logout() if d.item.data.dataid is "sys-logout" _GUI.launch d.item.data.app unless d.item.data.dataid - #now get app list - _API.packages.fetch (r) -> - if r.result - r.result = ( it for it in r.result when it.app ) - v.text = v.name for k, v of r.result - menu.child[0].child = r.result if r.result - ($ "[data-id = 'os_menu']", "#syspanel")[0].set "items", [menu] + ($ "[data-id = 'os_menu']", "#syspanel")[0].set "items", [menu] #console.log menu @@ -329,14 +325,23 @@ self.OS.GUI = _GUI.initDM() _courrier.observable.one "syspanelloaded", () -> # TODO load packages list then build system menu - # push startup services - # TODO: get services list from user setting - _GUI.buildSystemMenu() - _GUI.pushServices [ - "CoreServices/PushNotification", - "CoreServices/Spotlight", - "CoreServices/Calendar" - ] + _API.packages.fetch (r) -> + if r.result + for k, v of r.result + v.text = v.name + v.filename = k + v.type = "app" + v.mime = "antos/app" + v.iconclass = "fa fa-adn" unless v.iconclass or v.icon + _OS.setting.system.packages = if r.result then r.result else + _GUI.buildSystemMenu() + # push startup services + # TODO: get services list from user setting + _GUI.pushServices [ + "CoreServices/PushNotification", + "CoreServices/Spotlight", + "CoreServices/Calendar" + ] # startup application here _courrier.observable.one "desktoploaded", () -> diff --git a/src/core/tags/afx-file-view.js b/src/core/tags/afx-file-view.js index a65153e..f09c9e1 100644 --- a/src/core/tags/afx-file-view.js +++ b/src/core/tags/afx-file-view.js @@ -62,7 +62,8 @@ v.text = v.filename if(v.text.length > 10) v.text = v.text.substring(0,9) + "..." - v.iconclass = v.type + v.iconclass = v.iconclass?v.iconclass:v.type + v.icon = v.icon items.push(v) }) self.refs.listview.root.set("items", items) @@ -71,7 +72,7 @@ var rows = [] $.each(self.data, function(i,v){ if(v.filename[0] == '.' && !self.showhidden) return - var row = [{value:v.filename, iconclass: v.type},{value:v.mime},{value:v.size},{idx:i}] + var row = [{value:v.filename, iconclass: v.iconclass?v.iconclass:v.type, icon:v.icon},{value:v.mime},{value:v.size},{idx:i}] rows.push(row) }) self.refs.gridview.root.set("rows",rows) @@ -94,7 +95,8 @@ v.nodes = [] v.open = false } - v.iconclass = v.type + v.iconclass = v.iconclass?v.iconclass:v.type + v.icon = v.icon nodes.push(v) }) return nodes @@ -186,7 +188,7 @@ }) self.root.observable.on("filedbclick", function(e){ if(e.id != self.rid ) return - if(e.data.type == "file" && self.onfileopen) + if(e.data.type != "dir" && self.onfileopen) self.onfileopen(e.data) else if(self.chdir && e.data.type == "dir") self.chdir(e.data.path) diff --git a/src/core/vfs.coffee b/src/core/vfs.coffee index b3bbf59..f2ae311 100644 --- a/src/core/vfs.coffee +++ b/src/core/vfs.coffee @@ -64,7 +64,7 @@ class BasicFileHandler me.meta (d) -> if d.error return if err then err d else _courrier.osfail d.error, (_API.throwe "OS.VFS"), d.error - me.meta = d.result + me.info = d.result me.ready = true f() @@ -73,19 +73,28 @@ class BasicFileHandler @onready (() -> me.action "read", null, f) write: (d, f) -> - @action "write", d, f + me = @ + @action "write", d, (r) -> + _courrier.ostrigger "VFS", { m: "write", file: me } if r.result + f r mk: (d, f) -> me = @ - @onready (() -> me.action "mk", d, f) + @onready (() -> me.action "mk", d, (r) -> + _courrier.ostrigger "VFS", { m: "mk", file: me } if r.result + f r) remove: (f) -> me = @ - @onready (() -> me.action "remove", null, f) + @onready (() -> me.action "remove", null, (r) -> + _courrier.ostrigger "VFS", { m: "remove", file: me } if r.result + f r) upload: (f) -> me = @ - @onready (() -> me.action "upload", null, f) + @onready (() -> me.action "upload", null, (r) -> + _courrier.ostrigger "VFS", { m: "upload", file: me } if r.result + f r) download: (f) -> me = @ @@ -93,7 +102,9 @@ class BasicFileHandler move: (d, f) -> me = @ - @onready (() -> me.action "move", d, f) + @onready (() -> me.action "move", d, (r) -> + _courrier.ostrigger "VFS", { m: "move", file: d.asFileHandler() } if r.result + f r) execute: (f) -> me = @ @@ -123,21 +134,21 @@ class RemoteFileHandler extends self.OS.API.VFS.BasicFileHandler me = @ switch n when "read" - return _API.handler.scandir @path, f if @meta.type is "dir" + return _API.handler.scandir @path, f if @info.type is "dir" #read the file _API.handler.readfile @path, f when "mk" - return f { error: "#{@path} is not a directory" } if @meta.type is "file" + return f { error: "#{@path} is not a directory" } if @info.type is "file" _API.handler.mkdir "#{@path}/#{p}", f when "write" _API.handler.write @path, p, f when "upload" - return if @meta.type is "file" + return if @info.type is "file" _API.handler.upload @path, f when "remove" _API.handler.delete @path, f when "download" - return if @meta.type is "dir" + return if @info.type is "dir" _API.handler.fileblob @path, (d) -> blob = new Blob [d], { type: "octet/stream" } _API.saveblob me.basename, blob @@ -152,6 +163,41 @@ self.OS.API.VFS.RemoteFileHandler = RemoteFileHandler class ApplicationHandler extends self.OS.API.VFS.BasicFileHandler constructor: (path) -> super path + @info = _OS.setting.system.packages[@basename] if @basename + @ready = true + + meta: (f) -> + f() + + action: (n, p, f) -> + me = @ + switch n + when "read" + return f { result: @info } if @info + return unless @isRoot() + f { result: ( v for k, v of _OS.setting.system.packages ) } + + when "mk" + return + + when "write" + return + + when "upload" + # install + return + + when "remove" + #uninstall + return + + when "download" + return + + when "move" + return + else + return _courrier.osfail "VFS unknown action: #{n}", (_API.throwe "OS.VFS"), n self.OS.API.VFS.ApplicationHandler = ApplicationHandler diff --git a/src/packages/CoreServices/PushNotification.coffee b/src/packages/CoreServices/PushNotification.coffee index 10adc23..763d1b5 100644 --- a/src/packages/CoreServices/PushNotification.coffee +++ b/src/packages/CoreServices/PushNotification.coffee @@ -32,6 +32,7 @@ class PushNotification extends this.OS.GUI.BaseService @subscribe "fail", (o) -> me.pushout 'FAIL', o @subscribe "error", (o) -> me.pushout 'ERROR', o @subscribe "info", (o) -> me.pushout 'INFO', o + @subscribe "VFS", (o) -> me.pushout 'INFO', o @subscribe "loading", (o) -> me.pending.push o.id diff --git a/src/packages/Files/main.coffee b/src/packages/Files/main.coffee index a1177ac..3c81fea 100644 --- a/src/packages/Files/main.coffee +++ b/src/packages/Files/main.coffee @@ -19,7 +19,6 @@ class Files extends this.OS.GUI.BaseApplication @view.set "onfileopen", (e) -> return unless e return if e.type is "dir" - #console.log e me._gui.openWith e @favo.set "onlistselect", (e) -> @@ -52,6 +51,8 @@ class Files extends this.OS.GUI.BaseApplication @favo.set "items", mntpoints #@favo.set "selected", -1 @applySetting() + @subscribe "VFS", (d) -> + me.chdir null if d.data.file.hash() is me.currdir.hash() or d.data.file.parent().hash() is me.currdir.hash() @chdir null applySetting: (k) -> @@ -86,7 +87,7 @@ class Files extends this.OS.GUI.BaseApplication child: [ { text: "New file", dataid: "#{@name}-mkf" }, { text: "New folder", dataid: "#{@name}-mkdir" }, - { text: "Open with", dataid: "#{@name}-open" }, + { text: "Open", dataid: "#{@name}-open" }, { text: "Upload", dataid: "#{@name}-upload" }, { text: "Download", dataid: "#{@name}-download" }, { text: "Properties", dataid: "#{@name}-info" } @@ -165,7 +166,7 @@ class Files extends this.OS.GUI.BaseApplication return if d is file.filename file.path.asFileHandler() .move "#{me.currdir.path}/#{d}", (r) -> - if r.result then me.chdir null else me.error "Fail to rename to #{d}: #{r.error}" + me.error "Fail to rename to #{d}: #{r.error}" if r.error , "Rename", file.filename when "#{@name}-rm" @@ -175,7 +176,7 @@ class Files extends this.OS.GUI.BaseApplication return unless d file.path.asFileHandler() .remove (r) -> - if r.result then me.chdir null else me.error "Fail to delete #{file.filename}: #{r.error}" + me.error "Fail to delete #{file.filename}: #{r.error}" if r.error , "Delete" , { iconclass: "fa fa-question-circle", text: "Do you really want to delete: #{file.filename} ?" } @@ -200,7 +201,7 @@ class Files extends this.OS.GUI.BaseApplication @clipboard.file # duplicate file check .move "#{me.currdir.path}/#{@clipboard.file.basename}", (r) -> me.clipboard = undefined - if r.result then me.chdir null else me.error "Fail to paste: #{r.error}" + me.error "Fail to paste: #{r.error}" if r.error else @notify "Copy not yet implemented" @clipboard = undefined @@ -216,7 +217,7 @@ class Files extends this.OS.GUI.BaseApplication @openDialog "PromptDialog", (d) -> me.currdir.mk d, (r) -> - if r.result then me.chdir null else me.error "Fail to create #{d}: #{r.error}" + me.error "Fail to create #{d}: #{r.error}" if r.error , "New folder" when "#{@name}-mkf" @@ -224,7 +225,7 @@ class Files extends this.OS.GUI.BaseApplication (d) -> fp = "#{me.currdir.path}/#{d}".asFileHandler() fp.write "", (r) -> - if r.result then me.chdir null else me.error "Fail to create #{d}: #{r.error}" + me.error "Fail to create #{d}: #{r.error}" if r.error , "New file" when "#{@name}-info" @@ -234,11 +235,14 @@ class Files extends this.OS.GUI.BaseApplication when "#{@name}-upload" me = @ @currdir.upload (r) -> - if r.result then me.chdir null else me.error "Faile to upload to: #{d}: #{r.error}" + me.error "Faile to upload to: #{d}: #{r.error}" if r.error when "#{@name}-download" return unless file file.path.asFileHandler().download ()-> + when "#{@name}-open" + return unless file + @_gui.openWith file else console.log e diff --git a/src/packages/MarkOn/main.coffee b/src/packages/MarkOn/main.coffee index e5085a5..ea3f269 100644 --- a/src/packages/MarkOn/main.coffee +++ b/src/packages/MarkOn/main.coffee @@ -7,6 +7,7 @@ class MarkOn extends this.OS.GUI.BaseApplication markarea = @find "markarea" @container = @find "mycontainer" @previewOn = false + @currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else "Untitled".asFileHandler() @editor = new SimpleMDE element: markarea autofocus: true @@ -35,11 +36,13 @@ class MarkOn extends this.OS.GUI.BaseApplication #} } ] + @editor.codemirror.on "change", () -> console.log "thing changed" @on "vboxchange", (e) -> me.resizeContent() @resizeContent() - + @open @currfile + resizeContent: () -> children = ($ @container).children() titlebar = (($ @scheme).find ".afx-window-top")[0] @@ -47,5 +50,51 @@ class MarkOn extends this.OS.GUI.BaseApplication statusbar = children[4] cheight = ($ @scheme).height() - ($ titlebar).height() - ($ toolbar).height() - ($ statusbar).height() - 40 ($ children[2]).css("height", cheight + "px") - #($ children[2]).css("height", ) + + open: (file) -> + #find table + me = @ + file.read (d) -> + me.editor.value d + + + save: (file) -> + me = @ + file.write (file.getb64 "text/plain"), (d) -> + return me.error "Error saving file #{file.basename}" if d.error + file.dirty = false + file.text = file.basename + + menu: () -> + me = @ + menu = [{ + text: "File", + child: [ + { text: "Open", dataid: "#{@name}-Open" }, + { text: "Save", dataid: "#{@name}-Save" }, + { text: "Save as", dataid: "#{@name}-Saveas" } + ], + onmenuselect: (e) -> me.actionFile e + }] + menu + + actionFile: (e) -> + me = @ + saveas = () -> + me.openDialog "FileDiaLog", (d, n) -> + me.currfile.setPath "#{d}/#{n}" + me.save me.currfile + , "Save as", { file: me.currfile } + switch e.item.data.dataid + when "#{@name}-Open" + @openDialog "FileDiaLog", ( d, f ) -> + me.open "#{d}/#{f}".asFileHandler() + , "Open file" + when "#{@name}-Save" + @currfile.cache = @editor.value() + return @save @currfile if @currfile.basename + saveas() + when "#{@name}-Saveas" + @currfile.cache = @editor.value() + saveas() this.OS.register "MarkOn", MarkOn \ No newline at end of file diff --git a/src/packages/NotePad/package.json b/src/packages/NotePad/package.json index 775719a..27a296d 100644 --- a/src/packages/NotePad/package.json +++ b/src/packages/NotePad/package.json @@ -9,5 +9,5 @@ "version":"0.1a", "category":"System", "iconclass":"fa fa-pencil-square-o", - "mimes":[".*"] + "mimes":["text/.*"] } \ No newline at end of file