From 0d89ada58251265753e210d8614033a4ca83e735 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Wed, 19 Jul 2017 15:08:50 +0200 Subject: [PATCH 01/14] rename Elements.js to elements.js --- randomwallpaper@iflow.space/{Elements.js => elements.js} | 0 randomwallpaper@iflow.space/extension.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename randomwallpaper@iflow.space/{Elements.js => elements.js} (100%) diff --git a/randomwallpaper@iflow.space/Elements.js b/randomwallpaper@iflow.space/elements.js similarity index 100% rename from randomwallpaper@iflow.space/Elements.js rename to randomwallpaper@iflow.space/elements.js diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index bfebcc7..295bb14 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -11,7 +11,7 @@ const Main = imports.ui.main; const St = imports.gi.St; const PanelMenu = imports.ui.panelMenu; const PopupMenu = imports.ui.popupMenu; -const CustomElements = Self.imports.Elements; +const CustomElements = Self.imports.elements; const Tweener = imports.ui.tweener; // Filesystem From 768581594aefe5123a762beab2a99ef81bd0209e Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Wed, 19 Jul 2017 15:09:34 +0200 Subject: [PATCH 02/14] Bump version number --- randomwallpaper@iflow.space/metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/randomwallpaper@iflow.space/metadata.json b/randomwallpaper@iflow.space/metadata.json index a7ad97f..6e23a20 100644 --- a/randomwallpaper@iflow.space/metadata.json +++ b/randomwallpaper@iflow.space/metadata.json @@ -12,5 +12,5 @@ "settings-schema": "org.gnome.shell.extensions.space.iflow.randomwallpaper", "name": "Random Wallpaper", "description": "Fetches a random wallpaper from desktopper.co and sets it as desktop background", - "version": 1.1 + "version": 1.2 } From cebed1715abaca54756a4825757c3a12898d73ed Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Wed, 19 Jul 2017 15:20:29 +0200 Subject: [PATCH 03/14] Extend adapters from BaseAdapter --- randomwallpaper@iflow.space/sourceAdapter.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index d510ba1..6dfcc07 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -1,11 +1,29 @@ const Lang = imports.lang; +const Self = imports.misc.extensionUtils.getCurrentExtension(); // network requests const Soup = imports.gi.Soup; const Json = imports.gi.Json; +const LoggerModule = Self.imports.logger; + +let BaseAdapter = new Lang.Class({ + Name: "BaseAdapter", + + logge: null, + + _init: function () { + this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter'); + }, + + requestRandomImage: function () { + this.logger.error("requestRandomImage not implemented") + } +}); + let DesktopperAdapter = new Lang.Class({ Name: "DesktopperAdapter", + Extends: BaseAdapter, /* fetch a random image url from desktopper.cc and call callback function with the URL of the image @@ -34,6 +52,7 @@ let DesktopperAdapter = new Lang.Class({ let WallheavenAdapter = new Lang.Class({ Name: "WallheavenAdapter", + Extends: BaseAdapter, // query options options: { From d428fec51269efec59768dd1e33717f703e58f83 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 13:48:13 +0200 Subject: [PATCH 04/14] Implement history module --- randomwallpaper@iflow.space/extension.js | 15 +- randomwallpaper@iflow.space/history.js | 154 +++++++++++++++++ randomwallpaper@iflow.space/logger.js | 2 +- randomwallpaper@iflow.space/sourceAdapter.js | 22 +-- .../wallpaperController.js | 163 ++++-------------- 5 files changed, 210 insertions(+), 146 deletions(-) create mode 100644 randomwallpaper@iflow.space/history.js diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index 295bb14..c50ea9e 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -6,6 +6,8 @@ const Shell = imports.gi.Shell; const Self = imports.misc.extensionUtils.getCurrentExtension(); const WallpaperController = Self.imports.wallpaperController; +const LoggerModule = Self.imports.logger; + // UI Imports const Main = imports.ui.main; const St = imports.gi.St; @@ -33,9 +35,11 @@ let panelEntry; let RandomWallpaperEntry = new Lang.Class({ Extends: PanelMenu.Button, Name: "RandomWallpaperEntry", + logger: null, _init: function(menuAlignment, nameText) { this.parent(menuAlignment, nameText); + this.logger = new LoggerModule.Logger('RWG3', 'RandomWallpaperEntry'); // Panelmenu Icon this.statusIcon = new CustomElements.StatusElement(); @@ -110,15 +114,16 @@ let RandomWallpaperEntry = new Lang.Class({ setHistoryList: function() { this.historySection.removeAll(); - let history = this.history = wallpaperController.getHistory(); + let historyController = wallpaperController.getHistoryController(); + let history = historyController.history; if (history.length <= 1) { this.clearHistoryList(); return; - }; + } - for (var i = 1; i < history.length; i++) { - let historyid = history[i]; + for (let i = 1; i < history.length; i++) { + let historyid = history[i].id; let tmp = new CustomElements.HistoryElement(historyid, i); tmp.actor.connect('key-focus-in', onEnter); @@ -128,7 +133,7 @@ let RandomWallpaperEntry = new Lang.Class({ tmp.connect('activate', onSelect); this.historySection.addMenuItem(tmp); - }; + } function onLeave(actor) { wallpaperController.resetWallpaper(); diff --git a/randomwallpaper@iflow.space/history.js b/randomwallpaper@iflow.space/history.js new file mode 100644 index 0000000..ff89eb8 --- /dev/null +++ b/randomwallpaper@iflow.space/history.js @@ -0,0 +1,154 @@ +const Lang = imports.lang; +const Mainloop = imports.gi.GLib; + +// Filesystem +const Gio = imports.gi.Gio; + +const Self = imports.misc.extensionUtils.getCurrentExtension(); +const Prefs = Self.imports.settings; + +const LoggerModule = Self.imports.logger; + +let HistoryEntry = new Lang.Class({ + Name: "HistoryEntry", + timestamp: null, + id: null, + path: null, + src: null, + + _init: function(historyId, path, src) { + this.timestamp = new Date().getTime(); + this.id = historyId; + this.path = path; + this.src = src; + }, +}); + +let HistoryController = new Lang.Class({ + Name: "HistoryController", + _settings: null, + _wallpaperlocation: null, + + logger: null, + size: 10, + history: [], + + _init: function(wallpaperlocation) { + this.logger = new LoggerModule.Logger('RWG3', 'HistoryController'); + + this._settings = new Prefs.Settings(); + this._wallpaperlocation = wallpaperlocation; + + this.load(); + }, + + insert: function(historyElement) { + this.history.unshift(historyElement); + this._deleteOldPictures(); + this.save(); + }, + + /** + * Set the given id to to the first history element (the current one) + * @param id + * @returns {boolean} + */ + promoteToActive: function(id) { + let element = this.get(id); + if (element === null) { + return false; + } + + element.timestamp = new Date().getTime(); + this.history = this.history.sort((elem1, elem2) => { return elem1.timestamp < elem2.timestamp }); + this.save(); + + return true; + }, + + /** + * Returns the corresponding HistoryEntry or null + * @param id + * @returns {*} + */ + get: function(id) { + for (let elem of this.history) { + if (elem.id == id) { + return elem; + } + } + + return null; + }, + + /** + * Load the history from the gschema + */ + load: function() { + this.size = this._settings.get('history-length', 'int'); + let stringHistory = this._settings.get('history', 'strv'); + this.history = stringHistory.map(elem => { + return JSON.parse(elem) + }); + }, + + /** + * Save the history to the gschema + */ + save: function() { + let stringHistory = this.history.map(elem => { return JSON.stringify(elem) }); + this._settings.set('history', 'strv', stringHistory); + }, + + /** + * Clear the history and delete all photos except the current one. + * @returns {boolean} + */ + clear() { + let firstHistoryElement = this.history[0]; + + if (firstHistoryElement) + this.history = [firstHistoryElement]; + + let directory = Gio.file_new_for_path(this._wallpaperlocation); + let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); + + let fileinfo; + let deleteFile; + + do { + + fileinfo = enumerator.next_file(null); + + if (!fileinfo) { + break; + } + + let id = fileinfo.get_name(); + + // ignore hidden files and first element + if (id[0] != '.' && id != firstHistoryElement.id) { + deleteFile = Gio.file_new_for_path(this._wallpaperlocation + id); + deleteFile.delete(null); + } + + } while(fileinfo); + + this.save(); + return true; + }, + + /** + * Delete all pictures that have no slot in the history. + * @private + */ + _deleteOldPictures: function() { + this.size = this._settings.get('history-length', 'int'); + let deleteFile; + while(this.history.length > this.size) { + deleteFile = Gio.file_new_for_path(this.history.pop().path); + deleteFile.delete(null); + } + }, + +}); \ No newline at end of file diff --git a/randomwallpaper@iflow.space/logger.js b/randomwallpaper@iflow.space/logger.js index 61b2356..d0a4fc0 100644 --- a/randomwallpaper@iflow.space/logger.js +++ b/randomwallpaper@iflow.space/logger.js @@ -22,7 +22,7 @@ let Logger = new Lang.Class({ this._log("INFO", message); }, - warning: function (message) { + warn: function (message) { this._log("WARNING", message); }, diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index 6dfcc07..66512c4 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -9,8 +9,8 @@ const LoggerModule = Self.imports.logger; let BaseAdapter = new Lang.Class({ Name: "BaseAdapter", + logger: null, - logge: null, _init: function () { this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter'); @@ -18,6 +18,12 @@ let BaseAdapter = new Lang.Class({ requestRandomImage: function () { this.logger.error("requestRandomImage not implemented") + }, + + fileName: function(uri) + { + let base = new String(uri).substring(uri.lastIndexOf('/') + 1); + return base; } }); @@ -34,9 +40,7 @@ let DesktopperAdapter = new Lang.Class({ let parser = new Json.Parser(); - var _this = this; - - session.queue_message(message, function (session, message) { + session.queue_message(message, (session, message) => { parser.load_from_data(message.response_body.data, -1); let data = parser.get_root().get_object(); @@ -73,7 +77,7 @@ let WallheavenAdapter = new Lang.Class({ let options = this.options; let optionsString = ""; - for (var key in options) { + for (let key in options) { if (options.hasOwnProperty(key)) { if (Array.isArray(options[key])) { optionsString += key + "=" + options[key].join() + "&"; @@ -89,9 +93,7 @@ let WallheavenAdapter = new Lang.Class({ let message = Soup.Message.new('GET', url); - var _this = this; - - session.queue_message(message, function (session, message) { + session.queue_message(message, (session, message) => { let body = message.response_body.data; let urlArray = body.match(new RegExp(/http[s]*:\/\/alpha.wallhaven.cc\/wallpaper\/[0-9]+/g)); @@ -101,11 +103,11 @@ let WallheavenAdapter = new Lang.Class({ }); // get a random entry from the array - var url = uniqueUrlArray[Math.floor(Math.random() * uniqueUrlArray.length)]; + let url = uniqueUrlArray[Math.floor(Math.random() * uniqueUrlArray.length)]; message = Soup.Message.new('GET', url); - session.queue_message(message, function () { + session.queue_message(message, () => { let body = message.response_body.data; let imageUrl = body.match(new RegExp(/\/\/wallpapers.wallhaven.cc\/wallpapers\/full\/.*?"/))[0]; imageUrl = imageUrl.slice(0, -1); diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js index 0025fc8..b359461 100644 --- a/randomwallpaper@iflow.space/wallpaperController.js +++ b/randomwallpaper@iflow.space/wallpaperController.js @@ -14,6 +14,7 @@ const SourceAdapter = Self.imports.sourceAdapter; const Convenience = Self.imports.convenience; const Prefs = Self.imports.settings; const Timer = Self.imports.timer; +const HistoryModule = Self.imports.history; const LoggerModule = Self.imports.logger; @@ -24,9 +25,8 @@ let WallpaperController = new Lang.Class({ wallpaperlocation: '', currentWallpaper: '', - historySize: 10, - history: [], - imageSourceAdapter: undefined, + _historyController: null, + imageSourceAdapter: null, _timer: null, _autoFetch : { @@ -44,6 +44,7 @@ let WallpaperController = new Lang.Class({ this.wallpaperlocation = this.extensionMeta.path + '/wallpapers/'; this._timer = new Timer.AFTimer(); + this._historyController = new HistoryModule.HistoryController(this.wallpaperlocation); this._settings = new Prefs.Settings(); this._settings.observe('history-length', this._updateHistory.bind(this)); @@ -54,7 +55,6 @@ let WallpaperController = new Lang.Class({ this._updateHistory(); this._updateAutoFetching(); - this.history = this._loadHistory(); this.currentWallpaper = this._getCurrentWallpaper(); this._desktopperAdapter = new SourceAdapter.DesktopperAdapter(); @@ -64,7 +64,7 @@ let WallpaperController = new Lang.Class({ }, _updateHistory: function() { - this.historySize = this._settings.get('history-length', 'int'); + this._historyController.load(); }, _updateAutoFetching: function() { @@ -108,20 +108,16 @@ let WallpaperController = new Lang.Class({ the written file as parameter. */ _fetchFile: function(uri, callback){ + //extract the name from the url and let date = new Date(); - let inputbuffer; - - //extract the name from the desktopper url and add timestamp prefix - let name = date.getTime() + uri.substr(uri.lastIndexOf('.')); + let name = date.getTime()+'_'+this.imageSourceAdapter.fileName(uri); // timestamp ensures uniqueness let output_file = Gio.file_new_for_path(this.wallpaperlocation + String(name)); let output_stream = output_file.create(0, null); let input_file = Gio.file_new_for_uri(uri); - let _this = this; - - input_file.load_contents_async(null, function(file, result){ + input_file.load_contents_async(null, (file, result) => { let contents = file.load_contents_finish(result)[1]; output_stream.write(contents, null); @@ -132,38 +128,8 @@ let WallpaperController = new Lang.Class({ }); }, - /* - Set a new timestamp as name for the given file - and adapt the history - */ - _setNewFileName: function(historyid) { - let date = new Date(); - let file = Gio.file_new_for_path(this.wallpaperlocation + historyid); - let name = date.getTime() + historyid.substr(historyid.lastIndexOf('.')); - let newFile = Gio.file_new_for_path(this.wallpaperlocation + name); - - for (var i = 0; i < this.history.length; i++) { - if(this.history[i] == historyid) { - file.move(newFile, Gio.FileCopyFlags.NONE, null, function(){ - }); - - // TODO: error handling, what if move fails? - - this.history[i] = name; - - this.history.sort(); - this.history.reverse(); - - return name; - } - } - - return false; - }, - _setBackground: function(path, callback){ let background_setting = new Gio.Settings({schema: "org.gnome.desktop.background"}); - this.deleteOldPictures(); /* inspired from: @@ -192,69 +158,36 @@ let WallpaperController = new Lang.Class({ return background_setting.get_string("picture-uri").replace(/^(file:\/\/)/, ""); }, - _loadHistory: function () { - let directory = Gio.file_new_for_path(this.wallpaperlocation); - let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); + setWallpaper: function(historyId) { + let historyElement = this._historyController.get(historyId); - let fileinfo; - let history = []; - - do { - fileinfo = enumerator.next_file(null); - - if (!fileinfo) { - break; - } - - let name = fileinfo.get_name(); - - // ignore hidden files - if (name[0] != '.') { - history.push(fileinfo.get_name()); - } - - } while(fileinfo); - - history.sort(); - history.reverse(); - - return history; - }, - - deleteOldPictures: function() { - this.historySize = this._settings.get('history-length', 'int'); - let deleteFile; - while(this.history.length > this.historySize) { - deleteFile = Gio.file_new_for_path(this.wallpaperlocation + this.history.pop()); - deleteFile.delete(null); + if(this._historyController.promoteToActive(historyElement.id)) { + this._setBackground(historyElement.path); + this.currentWallpaper = this._getCurrentWallpaper(); + } else { + this.logger.warn("The history id ("+historyElement.id+") could not be found.") + // TODO: Error handling history id not found. } }, - setWallpaper: function(historyEntry, keepName) { - if (!keepName) { - historyEntry = this._setNewFileName(historyEntry); - } - this._setBackground(this.wallpaperlocation + historyEntry); - this.currentWallpaper = this._getCurrentWallpaper(); - }, - fetchNewWallpaper: function(callback) { this._startLoadingHooks.forEach((element) => { element(); }); this._timer.begin(); // reset timer - let _this = this; this._requestRandomImageFromAdapter((imageUrl) => { - this.logger.debug("Requesting image: "+imageUrl); + this.logger.info("Requesting image: "+imageUrl); - _this._fetchFile(imageUrl, (historyid, path) => { - // insert file into history - _this.history.unshift(historyid); + this._fetchFile(imageUrl, (historyid, path) => { + let historyElement = new HistoryModule.HistoryEntry(historyid, path, imageUrl); + + this._setBackground(path, () => { + // insert file into history + this._historyController.insert(historyElement); - _this._setBackground(_this.wallpaperlocation + historyid, function(){ // call callback if given - _this._stopLoadingHooks.forEach((element) => { + this._stopLoadingHooks.forEach((element) => { element(null); }); if (callback) { @@ -270,16 +203,15 @@ let WallpaperController = new Lang.Class({ return; } - let _this = this; delay = delay || 200; - this.timeout = Mainloop.timeout_add(Mainloop.PRIORITY_DEFAULT, delay, function(){ - _this.timeout = null; - if (_this._resetWallpaper) { - _this._setBackground(_this.currentWallpaper); - _this._resetWallpaper = false; + this.timeout = Mainloop.timeout_add(Mainloop.PRIORITY_DEFAULT, delay, () => { + this.timeout = null; + if (this._resetWallpaper) { + this._setBackground(this.currentWallpaper); + this._resetWallpaper = false; } else { - _this._setBackground(_this.wallpaperlocation + _this.previewId); + this._setBackground(this.wallpaperlocation + this.previewId); } return false; }); @@ -297,41 +229,12 @@ let WallpaperController = new Lang.Class({ this._backgroundTimout(); }, - getHistory: function() { - return this.history; + getHistoryController: function() { + return this._historyController; }, deleteHistory: function() { - let firstHistoryElement = this.history[0]; - - if (firstHistoryElement) - this.history = [firstHistoryElement]; - - let directory = Gio.file_new_for_path(this.wallpaperlocation); - let enumerator = directory.enumerate_children('', Gio.FileQueryInfoFlags.NONE, null); - - let fileinfo; - let deleteFile; - - do { - - fileinfo = enumerator.next_file(null); - - if (!fileinfo) { - break; - }; - - let name = fileinfo.get_name(); - - // ignore hidden files and first element - if (name[0] != '.' && name != firstHistoryElement) { - deleteFile = Gio.file_new_for_path(this.wallpaperlocation + name); - deleteFile.delete(null); - }; - - } while(fileinfo); - - return true; + this._historyController.clear(); }, menuShowHook: function() { From 99801819a50e5778de59f804a01804fe9d650991 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 14:01:54 +0200 Subject: [PATCH 05/14] Add build script --- .gitignore | 3 +++ build.sh | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100755 build.sh diff --git a/.gitignore b/.gitignore index ff4d610..9d6886d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ .idea +# ready to deploy to gnome extensions +random-wallpaper-gnome3.zip + # Temporary ui files **/*~ diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..e178ac5 --- /dev/null +++ b/build.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +BASEDIR='randomwallpaper@iflow.space' +ZIPNAME='random-wallpaper-gnome3.zip' + +rm $ZIPNAME +rm $BASEDIR/schemas/gschemas.compiled +rm $BASEDIR/wallpapers/* +glib-compile-schemas $BASEDIR/schemas/ + +cd $BASEDIR +zip -r $ZIPNAME . +mv $ZIPNAME .. \ No newline at end of file From 2818fb169a15cf34d954a070d141c83e60cb1e9a Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 14:02:27 +0200 Subject: [PATCH 06/14] Remove images folder --- .../images/shuffle-icon.png | Bin 6779 -> 0 bytes .../images/shuffle-icon.svg | 14 -------------- 2 files changed, 14 deletions(-) delete mode 100644 randomwallpaper@iflow.space/images/shuffle-icon.png delete mode 100644 randomwallpaper@iflow.space/images/shuffle-icon.svg diff --git a/randomwallpaper@iflow.space/images/shuffle-icon.png b/randomwallpaper@iflow.space/images/shuffle-icon.png deleted file mode 100644 index c2e2a88986f1ea6ddac2ed4bd066c39d78b0db5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6779 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 diff --git a/randomwallpaper@iflow.space/images/shuffle-icon.svg b/randomwallpaper@iflow.space/images/shuffle-icon.svg deleted file mode 100644 index c651f29..0000000 --- a/randomwallpaper@iflow.space/images/shuffle-icon.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - From 9774a70244b6b3cb8c9ae307ab7a4d7b4257a55a Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 14:16:08 +0200 Subject: [PATCH 07/14] Add settings button to popup menu --- randomwallpaper@iflow.space/extension.js | 15 +++++++++++++++ .../wallpaperController.js | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index c50ea9e..857f1b6 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -68,6 +68,10 @@ let RandomWallpaperEntry = new Lang.Class({ this.openFolder = new PopupMenu.PopupMenuItem('Open Wallpaper Folder'); this.menu.addMenuItem(this.openFolder); + // settings button + this.openSettings = new PopupMenu.PopupMenuItem('Settings'); + this.menu.addMenuItem(this.openSettings); + //this.menu.addMenuItem(new CustomElements.DelaySlider(60)); /* add eventlistener @@ -93,6 +97,17 @@ let RandomWallpaperEntry = new Lang.Class({ Gio.AppInfo.launch_default_for_uri(uri, global.create_app_launch_context(0, -1)) }); + this.openSettings.connect("activate", function(){ + // call gnome settings tool for this extension + let app = Shell.AppSystem.get_default().lookup_app("gnome-shell-extension-prefs.desktop"); + if( app!=null ) { + // only works in Gnome >= 3.12 + let info = app.get_app_info(); + let timestamp = global.display.get_current_time_roundtrip(); + info.launch_uris([Self.uuid], global.create_app_launch_context(timestamp, -1)); + } + }); + this.menu.actor.connect('show', function() { this.newWallpaperItem.show(); wallpaperController.menuShowHook(); diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js index b359461..cb50be0 100644 --- a/randomwallpaper@iflow.space/wallpaperController.js +++ b/randomwallpaper@iflow.space/wallpaperController.js @@ -118,7 +118,7 @@ let WallpaperController = new Lang.Class({ let input_file = Gio.file_new_for_uri(uri); input_file.load_contents_async(null, (file, result) => { - let contents = file.load_contents_finish(result)[1]; + let contents = file.load_contents_finish(result)[1]; // TODO: error handling. This failes due to: "An unexpected TLS packet was received." output_stream.write(contents, null); // call callback with the name and the full filepath of the written file as parameter From 42a8123f4ebaf5ab6c51cb521866cbc5c121a7b5 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 16:29:13 +0200 Subject: [PATCH 08/14] Add expandable information to the history element --- randomwallpaper@iflow.space/elements.js | 184 ++++++------------ randomwallpaper@iflow.space/extension.js | 2 +- randomwallpaper@iflow.space/history.js | 15 +- randomwallpaper@iflow.space/sourceAdapter.js | 23 ++- .../wallpaperController.js | 9 +- 5 files changed, 95 insertions(+), 138 deletions(-) diff --git a/randomwallpaper@iflow.space/elements.js b/randomwallpaper@iflow.space/elements.js index 97401be..e57c61b 100644 --- a/randomwallpaper@iflow.space/elements.js +++ b/randomwallpaper@iflow.space/elements.js @@ -3,32 +3,33 @@ const PopupMenu = imports.ui.popupMenu; const St = imports.gi.St; const Slider = imports.ui.slider; const Tweener = imports.ui.tweener; +const Util = imports.misc.util; const Self = imports.misc.extensionUtils.getCurrentExtension(); const Timer = Self.imports.timer; const HistoryElement = new Lang.Class({ Name: 'HistoryElement', - Extends: PopupMenu.PopupBaseMenuItem, - historyId: null, + Extends: PopupMenu.PopupSubMenuMenuItem, + historyEntry: null, - _init: function(historyId, index, params) { - index = String(index)+'.' || '0.'; + _init: function (historyEntry, index) { + index = String(index) + '.' || '0.'; - this.parent(params); + this.parent("", true); - let timestamp = parseInt(historyId.slice(0, historyId.lastIndexOf('.'))); + let timestamp = historyEntry.timestamp; let date = new Date(timestamp); let timeString = date.toLocaleTimeString(); - let dateString = date.toLocaleDateString(); + let dateString = date.toLocaleDateString(); - this.label = new St.Label({ + this.realLabel = new St.Label({ text: index, style_class: 'rwg-history-index' }); - this.actor.add_child(this.label); + this.actor.insert_child_below(this.realLabel, this.label); this._container = new St.BoxLayout({ vertical: true @@ -46,10 +47,44 @@ const HistoryElement = new Lang.Class({ }); this._container.add_child(this.timeLabel); - this.historyId = historyId; - this.actor.historyId = historyId; // extend the actor with the historyId + this.historyEntry = historyEntry; + this.actor.historyId = historyEntry.id; // extend the actor with the historyId + + this.actor.insert_child_above(this._container, this.realLabel); + + if (this.historyEntry.source && this.historyEntry.source !== null) { + + if (this.historyEntry.source.author !== null + && this.historyEntry.source.authorUrl !== null) { + this.authorItem = new PopupMenu.PopupMenuItem('Image By: ' + this.historyEntry.source.author); + this.authorItem.connect('activate', () => { + Util.spawn(['xdg-open', this.historyEntry.source.authorUrl]); + }); + + this.menu.addMenuItem(this.authorItem); + } + + if (this.historyEntry.source.source !== null + && this.historyEntry.source.sourceUrl !== null) { + this.sourceItem = new PopupMenu.PopupMenuItem('Image From: ' + this.historyEntry.source.source); + this.sourceItem.connect('activate', () => { + Util.spawn(['xdg-open', this.historyEntry.source.sourceUrl]); + }); + + this.menu.addMenuItem(this.sourceItem); + } + + this.imageUrlItem = new PopupMenu.PopupMenuItem('Open Image In Browser'); + this.imageUrlItem.connect('activate', () => { + Util.spawn(['xdg-open', this.historyEntry.source.imageUrl]); + }); + + this.menu.addMenuItem(this.imageUrlItem); + + } else { + this.menu.addMenuItem(new PopupMenu.PopupMenuItem('Unknown source.')); + } - this.actor.add_child(this._container); } }); @@ -64,7 +99,7 @@ const NewWallpaperElement = new Lang.Class({ Name: 'NewWallpaperElement', Extends: PopupMenu.PopupBaseMenuItem, - _init: function(params) { + _init: function (params) { this.parent(params); this._timer = new Timer.AFTimer(); @@ -87,7 +122,7 @@ const NewWallpaperElement = new Lang.Class({ this.actor.add_child(this._container); }, - show: function() { + show: function () { if (this._timer.isActive()) { let remainingMinutes = this._timer.remainingMinutes(); let minutes = remainingMinutes % 60; @@ -115,7 +150,7 @@ const StatusElement = new Lang.Class({ Name: 'StatusElement', Extends: St.Icon, - _init: function() { + _init: function () { this.parent({ icon_name: 'preferences-desktop-wallpaper-symbolic', @@ -125,19 +160,19 @@ const StatusElement = new Lang.Class({ let _this = this; this.loadingTweenIn = { - opacity:20, - time:1, - transition:'easeInOutSine', - onComplete: function() { + opacity: 20, + time: 1, + transition: 'easeInOutSine', + onComplete: function () { Tweener.addTween(_this, _this.loadingTweenOut); } - } + }; this.loadingTweenOut = { - opacity:255, - time:1, - transition:'easeInOutSine', - onComplete: function() { + opacity: 255, + time: 1, + transition: 'easeInOutSine', + onComplete: function () { if (_this.isLoading) { Tweener.addTween(_this, _this.loadingTweenIn); } else { @@ -149,112 +184,15 @@ const StatusElement = new Lang.Class({ }, - startLoading: function() { + startLoading: function () { this.isLoading = true; Tweener.addTween(this, this.loadingTweenOut); }, - stopLoading: function() { + stopLoading: function () { this.isLoading = false; Tweener.removeTweens(this); this.opacity = 255; } }); - -// ------------------------------------------------------------------------------- - -// borrowed from: https://github.com/eonpatapon/gnome-shell-extensions-mediaplayer -const SliderItem = new Lang.Class({ - Name: 'SliderItem', - Extends: PopupMenu.PopupBaseMenuItem, - - _init: function(value) { - this.parent(); - - this._box = new St.Table({style_class: 'slider-item'}); - - this._slider = new Slider.Slider(value); - - this._box.add(this._slider.actor, {row: 0, col: 2, x_expand: true}); - this.actor.add(this._box, {span: -1, expand: true}); - }, - - setValue: function(value) { - this._slider.setValue(value); - }, - - getValue: function() { - return this._slider._getCurrentValue(); - }, - - setIcon: function(icon) { - this._icon.icon_name = icon + '-symbolic'; - }, - - connect: function(signal, callback) { - this._slider.connect(signal, callback); - } -}); - - -/** - * Widget for setting the delay for the next Wallpaper-change. - * @type {Lang.Class} - */ -const DelaySlider = new Lang.Class({ - Name: 'DelaySlider', - Extends: SliderItem, - - _MINUTES_MAX: 59, - _MINUTES_MIN: 5, - _HOURS_MAX: 48, - _HOURS_MIN: 1, - - /** - * Construct a new Widget. - * @private - */ - _init: function(minutes){ - this.parent(0, ''); // value MUST be specified! - this.setMinutes(minutes); // Set the real value. - }, - - /** - * Set the value of the slider to x minutes. - * @param minutes the value in minutes between _MINUTES_MAX and _MINUTES_MIN - */ - setMinutes: function(minutes){ - // Validate: - if (isNaN(minutes) || minutes < this._MINUTES_MIN || minutes > this._HOURS_MAX*60){ - throw TypeError("'minutes' should be an integer between " - +this._MINUTES_MIN+" and "+this._HOURS_MAX*60); - } - - let value = 0; - if (minutes <= this._MINUTES_MAX){ - value = (minutes - this._MINUTES_MIN) / (this._MINUTES_MAX - this._MINUTES_MIN) / 2; - } else { - value = (((minutes / 60) - this._HOURS_MIN) / (this._HOURS_MAX - this._HOURS_MIN) / 2) + 0.5; - } - - this.setValue(value); - }, - - /** - * Get the value in minutes from the slider. - * @return int the value in minutes. - */ - getMinutes: function(){ - let minutes = 0; - if (this.getValue() < 0.5) { - minutes = this._MINUTES_MIN + (this.getValue() * 2) * (this._MINUTES_MAX - this._MINUTES_MIN); - } else { - minutes = (this._HOURS_MIN + (this.getValue() - 0.5) * 2 * (this._HOURS_MAX - this._HOURS_MIN)) * 60; - } - - return (minutes < this._MINUTES_MIN) ? this._MINUTES_MIN : Math.floor(minutes); - } -}); - -// ------------------------------------------------------------------------------- diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index 857f1b6..651b672 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -139,7 +139,7 @@ let RandomWallpaperEntry = new Lang.Class({ for (let i = 1; i < history.length; i++) { let historyid = history[i].id; - let tmp = new CustomElements.HistoryElement(historyid, i); + let tmp = new CustomElements.HistoryElement(history[i], i); tmp.actor.connect('key-focus-in', onEnter); tmp.actor.connect('key-focus-out', onLeave); diff --git a/randomwallpaper@iflow.space/history.js b/randomwallpaper@iflow.space/history.js index ff89eb8..405fcdb 100644 --- a/randomwallpaper@iflow.space/history.js +++ b/randomwallpaper@iflow.space/history.js @@ -14,13 +14,18 @@ let HistoryEntry = new Lang.Class({ timestamp: null, id: null, path: null, - src: null, + source: null, - _init: function(historyId, path, src) { + _init: function(author, source, url) { this.timestamp = new Date().getTime(); - this.id = historyId; - this.path = path; - this.src = src; + + this.source = { + author: author, + authorUrl: null, + source: source, + sourceUrl: null, + imageUrl: url + }; }, }); diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index 66512c4..ff4a069 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -5,6 +5,8 @@ const Self = imports.misc.extensionUtils.getCurrentExtension(); const Soup = imports.gi.Soup; const Json = imports.gi.Json; +const HistoryModule = Self.imports.history; + const LoggerModule = Self.imports.logger; let BaseAdapter = new Lang.Class({ @@ -16,15 +18,22 @@ let BaseAdapter = new Lang.Class({ this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter'); }, - requestRandomImage: function () { - this.logger.error("requestRandomImage not implemented") + /** + * Retrieves a new url for an image and calls the given callback with an HistoryEntry as parameter. + * @param callback + */ + requestRandomImage: function (callback) { + this.logger.error("requestRandomImage not implemented"); + + callback(null); }, fileName: function(uri) { let base = new String(uri).substring(uri.lastIndexOf('/') + 1); return base; - } + }, + }); let DesktopperAdapter = new Lang.Class({ @@ -48,7 +57,9 @@ let DesktopperAdapter = new Lang.Class({ let imageUrl = response.get_object_member('image').get_string_member('url'); if (callback) { - callback(imageUrl); + let historyEntry = new HistoryModule.HistoryEntry(null, 'desktopper.co', imageUrl); + historyEntry.source.sourceUrl = 'https://www.desktoppr.co/'; + callback(historyEntry); } }); } @@ -114,7 +125,9 @@ let WallheavenAdapter = new Lang.Class({ imageUrl = 'http:' + imageUrl; if (callback) { - callback(imageUrl); + let historyEntry = new HistoryModule.HistoryEntry(null, 'wallhaven.cc', imageUrl); + historyEntry.source.sourceUrl = 'https://alpha.wallhaven.cc/'; + callback(historyEntry); } }) diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js index cb50be0..5e7696c 100644 --- a/randomwallpaper@iflow.space/wallpaperController.js +++ b/randomwallpaper@iflow.space/wallpaperController.js @@ -176,11 +176,12 @@ let WallpaperController = new Lang.Class({ }); this._timer.begin(); // reset timer - this._requestRandomImageFromAdapter((imageUrl) => { - this.logger.info("Requesting image: "+imageUrl); + this._requestRandomImageFromAdapter((historyElement) => { + this.logger.info("Requesting image: "+historyElement.source.imageUrl); - this._fetchFile(imageUrl, (historyid, path) => { - let historyElement = new HistoryModule.HistoryEntry(historyid, path, imageUrl); + this._fetchFile(historyElement.source.imageUrl, (historyId, path) => { + historyElement.path = path; + historyElement.id = historyId; this._setBackground(path, () => { // insert file into history From ab429305677949845c408cca27509cbdd9ddaf0d Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 17:09:44 +0200 Subject: [PATCH 09/14] Add unsplash adapter. --- randomwallpaper@iflow.space/settings.ui | 2 +- randomwallpaper@iflow.space/sourceAdapter.js | 40 +++++++++++++++++-- .../wallpaperController.js | 4 ++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/randomwallpaper@iflow.space/settings.ui b/randomwallpaper@iflow.space/settings.ui index 58bb260..9406008 100644 --- a/randomwallpaper@iflow.space/settings.ui +++ b/randomwallpaper@iflow.space/settings.ui @@ -115,7 +115,7 @@ 0 desktoppr.co - unsplash.com (not implemented, defaults to desktopper) + unsplash.com (experimental) alpha.wallheaven.cc (experimental) diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index ff4a069..c3a84d6 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -39,10 +39,7 @@ let BaseAdapter = new Lang.Class({ let DesktopperAdapter = new Lang.Class({ Name: "DesktopperAdapter", Extends: BaseAdapter, - /* - fetch a random image url from desktopper.cc - and call callback function with the URL of the image - */ + requestRandomImage: function (callback) { let session = new Soup.SessionAsync(); let message = Soup.Message.new('GET', 'https://api.desktoppr.co/1/wallpapers/random'); @@ -65,6 +62,41 @@ let DesktopperAdapter = new Lang.Class({ } }); +let UnsplashAdapter = new Lang.Class({ + Name: "UnsplashAdapter", + Extends: BaseAdapter, + + sourceName: 'Unsplash', + sourceUrl: 'https://unsplash.com/', + + requestRandomImage: function (callback) { + let session = new Soup.SessionAsync(); + let url = 'https://api.unsplash.com/photos/random'; + url += '?client_id=64daf439e9b579dd566620c0b07022706522d87b255d06dd01d5470b7f193b8d'; + let message = Soup.Message.new('GET', url); + + let utmParameters = '?utm_source=RandomWallpaperGnome3&utm_medium=referral&utm_campaign=api-credit'; + + session.queue_message(message, (session, message) => { + let data = JSON.parse(message.response_body.data); + + let imageUrl = data.links.download; + let authorName = data.user.name; + let authorUrl = data.user.links.html; + + this.logger.debug(authorName); + this.logger.debug(authorUrl); + + if (callback) { + let historyEntry = new HistoryModule.HistoryEntry(authorName, this.sourceName, imageUrl+utmParameters); + historyEntry.source.sourceUrl = this.sourceUrl+utmParameters; + historyEntry.source.authorUrl = authorUrl+utmParameters; + callback(historyEntry); + } + }); + } +}); + let WallheavenAdapter = new Lang.Class({ Name: "WallheavenAdapter", Extends: BaseAdapter, diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js index 5e7696c..a4c015c 100644 --- a/randomwallpaper@iflow.space/wallpaperController.js +++ b/randomwallpaper@iflow.space/wallpaperController.js @@ -58,6 +58,7 @@ let WallpaperController = new Lang.Class({ this.currentWallpaper = this._getCurrentWallpaper(); this._desktopperAdapter = new SourceAdapter.DesktopperAdapter(); + this._unsplashAdapter = new SourceAdapter.UnsplashAdapter(); this._wallheavenAdapter = new SourceAdapter.WallheavenAdapter(); this.logger = new LoggerModule.Logger('RWG3', 'WallpaperController'); @@ -91,6 +92,9 @@ let WallpaperController = new Lang.Class({ case 0: this.imageSourceAdapter = this._desktopperAdapter; break; + case 1: + this.imageSourceAdapter = this._unsplashAdapter; + break; case 2: this.imageSourceAdapter = this._wallheavenAdapter; break; From 1e5dabe0b00062e64c8b4b136f7e764b60a917a2 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 20:54:23 +0200 Subject: [PATCH 10/14] Implement source settings. --- randomwallpaper@iflow.space/prefs.js | 117 +++++ .../schemas/gschemas.compiled | Bin 792 -> 2208 bytes ...ns.space.iflow.randomwallpaper.gschema.xml | 87 +++- randomwallpaper@iflow.space/settings.js | 46 +- randomwallpaper@iflow.space/settings.ui | 405 +++++++++++++++++- randomwallpaper@iflow.space/sourceAdapter.js | 177 ++++++-- 6 files changed, 747 insertions(+), 85 deletions(-) diff --git a/randomwallpaper@iflow.space/prefs.js b/randomwallpaper@iflow.space/prefs.js index e088260..4fbd998 100644 --- a/randomwallpaper@iflow.space/prefs.js +++ b/randomwallpaper@iflow.space/prefs.js @@ -12,6 +12,11 @@ const Gettext = imports.gettext.domain('space.iflow.randomwallpaper'); //const _ = Gettext.gettext; const RWG_SETTINGS_SCHEMA = 'org.gnome.shell.extensions.space.iflow.randomwallpaper'; +const RWG_SETTINGS_SCHEMA_DESKTOPPER = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.desktopper'; +const RWG_SETTINGS_SCHEMA_UNSPLASH = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.unsplash'; +const RWG_SETTINGS_SCHEMA_WALLHEAVEN = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.wallheaven'; + +const LoggerModule = Self.imports.logger; function init() { //Convenience.initTranslations(); @@ -28,6 +33,14 @@ function buildPrefsWidget() { /* UI Setup */ const RandomWallpaperSettings = new Lang.Class({ Name: 'RandomWallpaper.Settings', + logger: null, + + currentSourceSettingsWidget: null, + + noSettings: null, + desktopperSettings: null, + unsplashSettings: null, + wallheavenSettings: null, _init: function () { this._settings = Convenience.getSettings(RWG_SETTINGS_SCHEMA); @@ -35,6 +48,25 @@ const RandomWallpaperSettings = new Lang.Class({ //this._builder.set_translation_domain(Self.metadata['gettext-domain']); this._builder.add_from_file(Self.path + '/settings.ui'); + this.logger = new LoggerModule.Logger('RWG3', 'RandomWallpaper.Settings'); + + this.noSettings = this._builder.get_object('no-settings'); + + // Desktopper Settings + this._desktopper_settings = Convenience.getSettings(RWG_SETTINGS_SCHEMA_DESKTOPPER); + this.desktopperSettings = this._builder.get_object('desktopper-settings'); + this.bindDesktopper(); + + // Unsplash Settings + this._unsplash_settings = Convenience.getSettings(RWG_SETTINGS_SCHEMA_UNSPLASH); + this.unsplashSettings = this._builder.get_object('unsplash-settings'); + this.bindUnsplash(); + + // Wallheaven Settings + this._wallheaven_settings = Convenience.getSettings(RWG_SETTINGS_SCHEMA_WALLHEAVEN); + this.wallheavenSettings = this._builder.get_object('wallheaven-settings'); + this.bindWallheaven(); + this._toggleAfSliders(); this.widget = this._builder.get_object('main-widget'); @@ -43,6 +75,31 @@ const RandomWallpaperSettings = new Lang.Class({ this._toggleAfSliders(); }.bind(this)); + this._builder.get_object('source-combo').connect('changed', (sourceCombo) => { + let container = this._builder.get_object('source-settings-frame'); + if (this.currentSourceSettingsWidget !== null) { + container.remove(this.currentSourceSettingsWidget); + } + + switch (sourceCombo.active) { + case 0: // desktopper + this.currentSourceSettingsWidget = this.desktopperSettings; + break; + case 1: // unsplash + this.currentSourceSettingsWidget = this.unsplashSettings; + break; + case 2: // wallheaven + this.currentSourceSettingsWidget = this.wallheavenSettings; + break; + default: + this.currentSourceSettingsWidget = this.noSettings; + break; + } + + container.add(this.currentSourceSettingsWidget); + + }); + this._settings.bind('history-length', this._builder.get_object('history-length'), 'value', @@ -73,6 +130,66 @@ const RandomWallpaperSettings = new Lang.Class({ this._builder.get_object('duration-slider-hours').set_sensitive(false); this._builder.get_object('duration-slider-minutes').set_sensitive(false); } + }, + + bindDesktopper: function () { + this._desktopper_settings.bind('allow-unsafe', + this._builder.get_object('desktopper-allow-unsafe'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + }, + + bindUnsplash: function () { + this._unsplash_settings.bind('unsplash-keyword', + this._builder.get_object('unsplash-keyword'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._unsplash_settings.bind('username', + this._builder.get_object('unsplash-username'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + + this._unsplash_settings.bind('image-width', + this._builder.get_object('unsplash-image-width'), + 'value', + Gio.SettingsBindFlags.DEFAULT); + this._unsplash_settings.bind('image-height', + this._builder.get_object('unsplash-image-height'), + 'value', + Gio.SettingsBindFlags.DEFAULT); + }, + + bindWallheaven: function () { + this._wallheaven_settings.bind('wallheaven-keyword', + this._builder.get_object('wallheaven-keyword'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + this._wallheaven_settings.bind('resolutions', + this._builder.get_object('wallheaven-resolutions'), + 'text', + Gio.SettingsBindFlags.DEFAULT); + + this._wallheaven_settings.bind('category-general', + this._builder.get_object('wallheaven-category-general'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._wallheaven_settings.bind('category-anime', + this._builder.get_object('wallheaven-category-anime'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._wallheaven_settings.bind('category-people', + this._builder.get_object('wallheaven-category-people'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._wallheaven_settings.bind('allow-sfw', + this._builder.get_object('wallheaven-allow-sfw'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._wallheaven_settings.bind('allow-sketchy', + this._builder.get_object('wallheaven-allow-sketchy'), + 'active', + Gio.SettingsBindFlags.DEFAULT); } }); diff --git a/randomwallpaper@iflow.space/schemas/gschemas.compiled b/randomwallpaper@iflow.space/schemas/gschemas.compiled index 16e327e6d9d16f2c3f96247ce3e4e4f822b04fb8..bfc7a7683682c8f1ab9d2569a510ac9935d25ca3 100644 GIT binary patch literal 2208 zcmb_dO=uNY7`>YM8>=EnTojQ?WrlR-#TY}Z+E&muhy_tBp<^xj)}` z?tNc>D-&Oasc5uyz{@$e7B#emzz^Euuk#zbJMheYUx-053!GRW#P2tDKBB%GAM`{2 z5qJW^pWmH)MO|RPUC?&}2N&aUtq^szQ%m@ApCC>k$}e|JvOhWdKL+ktDnyi2+)5Z# zm8(4!1g<)os!;n;s9hb)VdeTGK~!@S8J44JO$I?MW0kmBsN+CtkCRxK)-)_va9_pV zxYw&sW)Bd#mla}6Tm)W2s9R6&QYT*xeF}IBv1fYS8|vgsq2CA2AhObnA?oCv&>sVz zA*PP~)XDvlFM|F*a0?bt%x|SSJRT&lvmXk5#aM@e_0RGdf;Cbp0^-6?O6@(60gi zMijXwXa6Z+2XeUg{;u2XPtN|Uf!&CiOW)hn$yY)D5;%y+e%t$yI{9+wL%_p`vHE8p zQ72yv-2+}nY`VAgKkDQwq2B@iizsSL&Kf@@Vxu1N%8W9X34*PQKbCKeTfT4Gw&&|K zO2#RoSyDHPiN|@UXVnk0ROMwA>oF$R!S!rMw5_Aj&ryMlwJP&vqrqP?OCx7QrNdrR zJYwgjF+y4C(KL!*6&BvUdrEQPG!}P`MneCqwdH?Zl7y|x^ zxcbZS1JucR$6N$nK`cl*jlap4L7xQPL=^rer@!w2J2BDOk6*vxIOO!-2H+=%wFkH1 zj>ZFKTA&^=%kQTUjgK8}IBw-cqKAWL}}^M%;F zt+(gs=H8y3PdDVWX8^Q!Yd_S!z9#Kwhb;qrP|*Q-)b_AURRw-`Dk@Zo49sxwqjkiF z9ip0}M{4vZo{LKjUFP8&G$)p!-?&Q~^EBVYDvASR-}d#4()Pvq(Hl~x$^bH&P&C#31sZx#m#G>De#&Hksd;WmP|5X0Z4FbPG6rLidr-p#% c$Q%FDk delta 293 zcmZ1=ID>71h-(A`7-%p-XfVkt%E0g+2q1Dk3?MoNh^KD1y$4bNVw*8|FiZi`GZ+~d z7$-Y2<=2B)tPEug3xM=)AQrFQ;l=?}0b;WQ#ZLg~vp{^HwvHQQI*1KYe*;KM1FiSE z;CLLQ9>fNz2RX?Zh_9}W(*%iw*!)282q2vR#HCZbZi2)?Y%Yc}e})2(AP|@Rw~_%# xfY@w64Glp091yFWH+=^Z2eJ8p;tzoIZy<(w7sO^@@L~7^q$QX)*D*IS0szoWIpzQW diff --git a/randomwallpaper@iflow.space/schemas/org.gnome.shell.extensions.space.iflow.randomwallpaper.gschema.xml b/randomwallpaper@iflow.space/schemas/org.gnome.shell.extensions.space.iflow.randomwallpaper.gschema.xml index 71b93bd..715a32b 100644 --- a/randomwallpaper@iflow.space/schemas/org.gnome.shell.extensions.space.iflow.randomwallpaper.gschema.xml +++ b/randomwallpaper@iflow.space/schemas/org.gnome.shell.extensions.space.iflow.randomwallpaper.gschema.xml @@ -2,13 +2,13 @@ - - - + + + + id='org.gnome.shell.extensions.space.iflow.randomwallpaper'> 10 @@ -38,9 +38,9 @@ - 'desktoppr' - Wallpaper Source - Describs the adapter that will be used. + 'desktoppr' + Wallpaper Source + Describs the adapter that will be used. @@ -56,4 +56,77 @@ + + + + false + Allow Unsafe + Weather the extension should fetch images that are rated as unsafe. + + + + + + "" + Keyword + The keyword will be used to search images. + + + "" + Username + Only fetch random images of a given user. + + + 1920 + Image Width + The width of the image. + + + 1080 + Image Width + The height of the image. + + + + + + "" + Keyword + The keyword will be used to search images. + + + "1920x1200, 1920x1080, 2560x1440, 2560x1600, 3840x1080" + Resolutions + The acceptable resolutions. + + + true + SFW + Weather safe images are allowed. + + + false + Sketchy + Weather sketchy images are allowed. + + + + true + Category General + Weather the general category should be searched. + + + true + Category Anime + Weather the anime category should be searched. + + + true + Category People + Weather the people category should be searched. + + diff --git a/randomwallpaper@iflow.space/settings.js b/randomwallpaper@iflow.space/settings.js index bb1970a..84fe953 100644 --- a/randomwallpaper@iflow.space/settings.js +++ b/randomwallpaper@iflow.space/settings.js @@ -6,31 +6,37 @@ const Self = imports.misc.extensionUtils.getCurrentExtension(); const Convenience = Self.imports.convenience; let Settings = new Lang.Class({ - Name: "Settings", + Name: "Settings", _settings: null, - _init: function() { - this._settings = Convenience.getSettings(); - }, + /** + * Settings object. + * + * @param [schema] + * @private + */ + _init: function (schema) { + this._settings = Convenience.getSettings(schema); + }, - observe: function(key, callback) { - this._settings.connect('changed::'+key, callback); - }, + observe: function (key, callback) { + this._settings.connect('changed::' + key, callback); + }, - set: function(key, type, value) { - if (this._settings['set_'+type](key, value)){ - Gio.Settings.sync(); // wait for write - } else { - throw "Could not set " + key + " (type: " + type + ") with the value " + value; - } - }, + set: function (key, type, value) { + if (this._settings['set_' + type](key, value)) { + Gio.Settings.sync(); // wait for write + } else { + throw "Could not set " + key + " (type: " + type + ") with the value " + value; + } + }, - get: function(key, type) { - return this._settings['get_'+type](key); - }, + get: function (key, type) { + return this._settings['get_' + type](key); + }, - getSourceAdapter: function() { + getSourceAdapter: function () { global.log(this._settings.get_enum('source')); - return null; - } + return null; + } }); diff --git a/randomwallpaper@iflow.space/settings.ui b/randomwallpaper@iflow.space/settings.ui index 9406008..13eb4c8 100644 --- a/randomwallpaper@iflow.space/settings.ui +++ b/randomwallpaper@iflow.space/settings.ui @@ -2,6 +2,29 @@ + + True + False + 10 + 10 + 10 + 10 + vertical + + + Allow unsafe images (also fetch images that are marked as unsafe) + True + True + False + True + + + False + True + 0 + + + 23 1 @@ -131,34 +154,22 @@ - + True False True 0 in - + + + + True False - 12 - - - True - False - 10 - 10 - No Settings Available - - - + Source Settings - - - 0 @@ -466,4 +477,362 @@ + + True + False + 10 + 10 + 10 + 10 + No Settings Available + + + + 1 + 1000000 + 1 + 10 + + + 1 + 1000000 + 1 + 10 + + + True + False + 10 + 10 + 10 + 10 + vertical + + + True + False + start + Username + + + False + True + 0 + + + + + True + True + 10 + @username + + + False + True + 1 + + + + + True + False + start + Keyword + + + False + True + 2 + + + + + True + True + 10 + Enter a keyword ... + + + False + True + 3 + + + + + True + False + + + True + False + 5 + True + vertical + + + True + False + start + Image Width + + + False + True + 0 + + + + + True + True + number + unsplash-image-width + + + True + True + 1 + + + + + False + True + 0 + + + + + True + False + 5 + True + vertical + + + True + False + start + Image Height + + + False + True + 0 + + + + + True + True + number + unsplash-image-height + + + True + True + 1 + + + + + False + True + 1 + + + + + False + True + 4 + + + + + True + False + 10 + 10 + 10 + 10 + vertical + + + True + False + start + Keyword + + + False + True + 0 + + + + + True + True + 10 + Enter a keyword ... + + + False + True + 1 + + + + + True + False + start + Allowed Content Ratings + + + False + True + 2 + + + + + True + False + 10 + start + + + SFW (Safe for work) + True + True + False + True + + + True + True + 0 + + + + + Sketchy + True + True + False + True + + + True + True + 1 + + + + + False + True + 3 + + + + + True + False + start + Categories + + + False + True + 4 + + + + + True + False + 10 + start + + + General + True + True + False + True + + + True + True + 0 + + + + + Anime + True + True + False + True + + + True + True + 1 + + + + + People + True + True + False + True + + + True + True + 2 + + + + + False + True + 5 + + + + + True + False + start + Resolutions + + + False + True + 6 + + + + + True + True + 1920x1080, 1920x1200 + + + False + True + 7 + + + diff --git a/randomwallpaper@iflow.space/sourceAdapter.js b/randomwallpaper@iflow.space/sourceAdapter.js index c3a84d6..3305226 100644 --- a/randomwallpaper@iflow.space/sourceAdapter.js +++ b/randomwallpaper@iflow.space/sourceAdapter.js @@ -5,6 +5,11 @@ const Self = imports.misc.extensionUtils.getCurrentExtension(); const Soup = imports.gi.Soup; const Json = imports.gi.Json; +const RWG_SETTINGS_SCHEMA_DESKTOPPER = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.desktopper'; +const RWG_SETTINGS_SCHEMA_UNSPLASH = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.unsplash'; +const RWG_SETTINGS_SCHEMA_WALLHEAVEN = 'org.gnome.shell.extensions.space.iflow.randomwallpaper.wallheaven'; + +const SettingsModule = Self.imports.settings; const HistoryModule = Self.imports.history; const LoggerModule = Self.imports.logger; @@ -13,7 +18,6 @@ let BaseAdapter = new Lang.Class({ Name: "BaseAdapter", logger: null, - _init: function () { this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter'); }, @@ -28,8 +32,7 @@ let BaseAdapter = new Lang.Class({ callback(null); }, - fileName: function(uri) - { + fileName: function (uri) { let base = new String(uri).substring(uri.lastIndexOf('/') + 1); return base; }, @@ -40,18 +43,33 @@ let DesktopperAdapter = new Lang.Class({ Name: "DesktopperAdapter", Extends: BaseAdapter, + _settings: null, + + _init: function () { + this.parent(); + + this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_DESKTOPPER); + }, + requestRandomImage: function (callback) { let session = new Soup.SessionAsync(); - let message = Soup.Message.new('GET', 'https://api.desktoppr.co/1/wallpapers/random'); - let parser = new Json.Parser(); + let url = 'https://api.desktoppr.co/1/wallpapers/random'; + let allowUnsafe = this._settings.get('allow-unsafe', 'boolean'); + if (allowUnsafe) { + url += '?safe_filter=all'; + } else { + url += '?safe_filter=safe'; + } + url = encodeURI(url); + this.logger.debug("Base URL: " + url); + + let message = Soup.Message.new('GET', url); session.queue_message(message, (session, message) => { - parser.load_from_data(message.response_body.data, -1); - - let data = parser.get_root().get_object(); - let response = data.get_object_member('response'); - let imageUrl = response.get_object_member('image').get_string_member('url'); + let data = JSON.parse(message.response_body.data); + let response = data.response; + let imageUrl = encodeURI(response.image.url); if (callback) { let historyEntry = new HistoryModule.HistoryEntry(null, 'desktopper.co', imageUrl); @@ -69,10 +87,32 @@ let UnsplashAdapter = new Lang.Class({ sourceName: 'Unsplash', sourceUrl: 'https://unsplash.com/', + _settings: null, + + // query options + options: { + 'username': '', + 'query': '', + 'w': 1920, + 'h': 1080, + }, + + _init: function () { + this.parent(); + + this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_UNSPLASH); + }, + requestRandomImage: function (callback) { let session = new Soup.SessionAsync(); - let url = 'https://api.unsplash.com/photos/random'; - url += '?client_id=64daf439e9b579dd566620c0b07022706522d87b255d06dd01d5470b7f193b8d'; + + this._readOptionsFromSettings(); + let optionsString = this._generateOptionsString(); + let url = 'https://api.unsplash.com/photos/random?' + optionsString; + url += 'client_id=64daf439e9b579dd566620c0b07022706522d87b255d06dd01d5470b7f193b8d'; + url = encodeURI(url); + this.logger.debug("Base URL: " + url); + let message = Soup.Message.new('GET', url); let utmParameters = '?utm_source=RandomWallpaperGnome3&utm_medium=referral&utm_campaign=api-credit'; @@ -80,59 +120,75 @@ let UnsplashAdapter = new Lang.Class({ session.queue_message(message, (session, message) => { let data = JSON.parse(message.response_body.data); - let imageUrl = data.links.download; + let imageUrl = encodeURI(data.links.download + utmParameters); let authorName = data.user.name; - let authorUrl = data.user.links.html; - - this.logger.debug(authorName); - this.logger.debug(authorUrl); + let authorUrl = encodeURI(data.user.links.html); if (callback) { - let historyEntry = new HistoryModule.HistoryEntry(authorName, this.sourceName, imageUrl+utmParameters); - historyEntry.source.sourceUrl = this.sourceUrl+utmParameters; - historyEntry.source.authorUrl = authorUrl+utmParameters; + let historyEntry = new HistoryModule.HistoryEntry(authorName, this.sourceName, encodeURI(imageUrl)); + historyEntry.source.sourceUrl = encodeURI(this.sourceUrl + utmParameters); + historyEntry.source.authorUrl = encodeURI(authorUrl + utmParameters); callback(historyEntry); } }); + }, + + _generateOptionsString: function () { + let options = this.options; + let optionsString = ""; + + for (let key in options) { + if (options.hasOwnProperty(key)) { + if (options[key]) { + optionsString += key + "=" + options[key] + "&"; + } + } + } + + return optionsString; + }, + + _readOptionsFromSettings: function () { + this.options.query = this._settings.get('unsplash-keyword', 'string'); + + this.options.username = this._settings.get('username', 'string'); + if (this.options.username[0] === '@') { + this.options.username = this.options.username.substring(1); // remove @ prefix + } + + this.options.w = this._settings.get('image-width', 'int'); + this.options.h = this._settings.get('image-height', 'int'); } }); let WallheavenAdapter = new Lang.Class({ Name: "WallheavenAdapter", Extends: BaseAdapter, + _settings: null, // query options options: { 'q': '', 'purity': '110', // SFW, sketchy 'sorting': 'random', - 'category': '111', // General, Anime, People + 'categories': '111', // General, Anime, People 'resolutions': ['1920x1200', '2560x1440'] }, - /* - fetch a random image url from wallheaven.cc with the given options - and call callback function with the URL of the image - */ + _init: function () { + this.parent(); + + this._settings = new SettingsModule.Settings(RWG_SETTINGS_SCHEMA_WALLHEAVEN); + }, + requestRandomImage: function (callback) { let session = new Soup.SessionAsync(); - let options = this.options; - let optionsString = ""; - - for (let key in options) { - if (options.hasOwnProperty(key)) { - if (Array.isArray(options[key])) { - optionsString += key + "=" + options[key].join() + "&"; - } else { - optionsString += key + "=" + options[key] + "&"; - } - } - } - // remove last '&' - optionsString = optionsString.slice(0, -1); - + this._readOptionsFromSettings(); + let optionsString = this._generateOptionsString(); let url = 'http://alpha.wallhaven.cc/search?' + optionsString; + url = encodeURI(url); + this.logger.debug("Base URL: " + url); let message = Soup.Message.new('GET', url); @@ -155,6 +211,7 @@ let WallheavenAdapter = new Lang.Class({ let imageUrl = body.match(new RegExp(/\/\/wallpapers.wallhaven.cc\/wallpapers\/full\/.*?"/))[0]; imageUrl = imageUrl.slice(0, -1); imageUrl = 'http:' + imageUrl; + imageUrl = encodeURI(imageUrl); if (callback) { let historyEntry = new HistoryModule.HistoryEntry(null, 'wallhaven.cc', imageUrl); @@ -165,5 +222,45 @@ let WallheavenAdapter = new Lang.Class({ }); + }, + + _generateOptionsString: function () { + let options = this.options; + let optionsString = ""; + + for (let key in options) { + if (options.hasOwnProperty(key)) { + if (Array.isArray(options[key])) { + optionsString += key + "=" + options[key].join() + "&"; + } else { + if (options[key]) { + optionsString += key + "=" + options[key] + "&"; + } + } + } + } + + return optionsString; + }, + + _readOptionsFromSettings: function () { + this.options.q = this._settings.get('wallheaven-keyword', 'string'); + + this.options.resolutions = this._settings.get('resolutions', 'string').split(','); + this.options.resolutions = this.options.resolutions.map((elem) => { + return elem.trim(); + }); + + let categories = []; + categories.push(+this._settings.get('category-general', 'boolean')); // + is implicit conversion to int + categories.push(+this._settings.get('category-anime', 'boolean')); + categories.push(+this._settings.get('category-people', 'boolean')); + this.options.categories = categories.join(''); + + let purity = []; + purity.push(+this._settings.get('allow-sfw', 'boolean')); + purity.push(+this._settings.get('allow-sketchy', 'boolean')); + purity.push(0); // required by wallheaven + this.options.purity = purity.join(''); } }); From 491484c74d771213f3a589ec77194b0e586a9b9d Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 21:49:54 +0200 Subject: [PATCH 11/14] Add current background element. --- randomwallpaper@iflow.space/elements.js | 31 ++++++++++++++++------ randomwallpaper@iflow.space/extension.js | 20 +++++++++++++- randomwallpaper@iflow.space/stylesheet.css | 10 +++---- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/randomwallpaper@iflow.space/elements.js b/randomwallpaper@iflow.space/elements.js index e57c61b..856cd1f 100644 --- a/randomwallpaper@iflow.space/elements.js +++ b/randomwallpaper@iflow.space/elements.js @@ -1,7 +1,6 @@ const Lang = imports.lang; const PopupMenu = imports.ui.popupMenu; const St = imports.gi.St; -const Slider = imports.ui.slider; const Tweener = imports.ui.tweener; const Util = imports.misc.util; @@ -14,9 +13,7 @@ const HistoryElement = new Lang.Class({ historyEntry: null, _init: function (historyEntry, index) { - index = String(index) + '.' || '0.'; - - this.parent("", true); + this.parent("", false); let timestamp = historyEntry.timestamp; let date = new Date(timestamp); @@ -24,12 +21,19 @@ const HistoryElement = new Lang.Class({ let timeString = date.toLocaleTimeString(); let dateString = date.toLocaleDateString(); - this.realLabel = new St.Label({ - text: index, + let prefixText; + if (index === 0) { + prefixtext = "Current Background"; + } else { + prefixtext = String(index) + '.'; + } + this.prefixLabel = new St.Label({ + text: prefixtext, style_class: 'rwg-history-index' }); - this.actor.insert_child_below(this.realLabel, this.label); + this.actor.insert_child_above(this.prefixLabel, this.label); + this.label.destroy(); this._container = new St.BoxLayout({ vertical: true @@ -50,7 +54,9 @@ const HistoryElement = new Lang.Class({ this.historyEntry = historyEntry; this.actor.historyId = historyEntry.id; // extend the actor with the historyId - this.actor.insert_child_above(this._container, this.realLabel); + if (index !== 0) { + this.actor.insert_child_above(this._container, this.prefixLabel); + } if (this.historyEntry.source && this.historyEntry.source !== null) { @@ -88,6 +94,15 @@ const HistoryElement = new Lang.Class({ } }); +const CurrentImageElement = new Lang.Class({ + Name: 'CurrentImageElement', + Extends: HistoryElement, + + _init: function(historyElement) { + this.parent(historyElement, 0); + } +}); + /** * Element for the New Wallpaper button and the remaining time for the auto fetch * feature. diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js index 651b672..0dc81e8 100644 --- a/randomwallpaper@iflow.space/extension.js +++ b/randomwallpaper@iflow.space/extension.js @@ -52,6 +52,11 @@ let RandomWallpaperEntry = new Lang.Class({ this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + // current background section + this.currentBackgroundSection = new PopupMenu.PopupMenuSection(); + this.menu.addMenuItem(this.currentBackgroundSection); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + // history section this.historySection = new PopupMenu.PopupMenuSection(); this.menu.addMenuItem(this.historySection); @@ -72,7 +77,6 @@ let RandomWallpaperEntry = new Lang.Class({ this.openSettings = new PopupMenu.PopupMenuItem('Settings'); this.menu.addMenuItem(this.openSettings); - //this.menu.addMenuItem(new CustomElements.DelaySlider(60)); /* add eventlistener */ @@ -126,7 +130,21 @@ let RandomWallpaperEntry = new Lang.Class({ }, + setCurrentBackgroundElement: function () { + this.currentBackgroundSection.removeAll(); + + let historyController = wallpaperController.getHistoryController(); + let history = historyController.history; + + if (history.length > 0) { + let currentImage = new CustomElements.CurrentImageElement(history[0]); + this.currentBackgroundSection.addMenuItem(currentImage); + } + }, + setHistoryList: function() { + this.setCurrentBackgroundElement(); + this.historySection.removeAll(); let historyController = wallpaperController.getHistoryController(); diff --git a/randomwallpaper@iflow.space/stylesheet.css b/randomwallpaper@iflow.space/stylesheet.css index 2e7a466..872fd5f 100644 --- a/randomwallpaper@iflow.space/stylesheet.css +++ b/randomwallpaper@iflow.space/stylesheet.css @@ -1,9 +1,7 @@ .rwg_system_status_icon { - /*icon-size: 1.09em;*/ icon-size: 1em; - /*padding: 0 5px;*/ - padding: 0 0; + padding: 0 0; position: absolute; -webkit-animation:spin 4s linear infinite; -moz-animation:spin 4s linear infinite; @@ -26,25 +24,23 @@ .rwg-recent-lable { width: 100%; - /*font-weight: bold;*/ font-size: 90%; text-align: left; border: 0; } .rwg-history-index { + text-align: left; padding-top: .35em; font-size: 130%; - font-weight: lighter; + font-weight: lighter; } .rwg-history-date { - /*padding-top: .35em;*/ font-size: 100%; } .rwg-history-time { - /*padding-top: .35em;*/ font-size: 100%; font-weight: lighter; } \ No newline at end of file From 894d7644832692dd7ba0b88ee670f18d77a41d0a Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 22:18:31 +0200 Subject: [PATCH 12/14] Add new icon --- icon.png | Bin 4336 -> 1327 bytes icon.svg | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 icon.svg diff --git a/icon.png b/icon.png index f241bc56305c383f135b7d08c95c852f387aba2d..da3594c7ed0f910eb8ba509ffcfd22e434e68b4c 100644 GIT binary patch literal 1327 zcmeAS@N?(olHy`uVBq!ia0vp^DIm4nJ z@ErkR#;MwT(m+AU64!{5;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq<{vk@pN$v zshIQjZhS^?y2SC1_bt_PbGD!9b4c^J;q_lK_3eTetg1Is`k9zt=dPctR+VgFXxOS9UguzVd#P zi>%cb!&|qU%5;3)j4I`WgZF#HhgVIQHjRyk_v^{HX>$s8FqgkmnRwD>(yn!1g2Q6x zx__ILa`oz7wOZdgK9DI8@7^f7xqITvm+^(~?tG7kj10Bhma=tgbiuDL4By`VcDU)Y z)LwDpjW5eO85y*-S9cs;HuYS{FX5zF=i?V#G~qpbI6mS1z3&f;H19e&F3VJsn}6`e z4gL)}+{-ex=Dt6%_~NZyvh4hIPmW|L+S=aTQCG`WT%7rIvutJ1{avB|c&Fx+-TBh_ zV6_gK|Ii`==50d4GMt-s%_>dG37ltJ{LJ@ZAB(3-kcUc;Uys-%k0ld)?v$e_!)QP28mSb@6fk*!^mmc3*N&zP`?ENf18+!?e`I%$NC7AA4`A{%-B{T$8ux zO@zq90`_@!f5V^Nm{e)AUP&Y?#40#b!1wZo;`Gg@CeG%I|0V=+oCp7;v+GXBP13R6 z7yi=!)#uNWclK0DzkQp3I&RjK-Q~{>?B`G1x9*F=vdpB4AJ#Wdhw(&hKPkOpJ^!MW zEBCE26%!NNxZ}t4IlMPJY9`oL-zxn0h-1~NQ@3CJ+SR#mVSeH3Yx0xI()cfhNAmLK zKYDXBIQ2L~!zwNDbMyaiT2U|ikY$tOo_p5~?f&uF%nM(#HZnT8`QyhxpjR`qPq`U& z+>Y(#7T?!&|NZ2B+s;2fdgI3R6)SHl)#gf`U#g>Z~g)fwz z-6pwINj#-sgZM;`iN4IGZh*Sn7PNDE8Q8x!Lm(r{%%1d^R~^KzZbl`wB%Fx zi%T!tXUyHZyyV&G37kohV(a4m-h7#B(RW6(+x9q0cAU}Vc;{W#r2Q?ob4p^{Z^y>| z*x|%3(bfn|@S3w%r7R3k<~giUG3SD&wv=rEFf+}4k*p!2BJ=LRMCJJ(SFUE+wJtGX zfp~1}doJ1ak*zopr03`Nl=>Px# literal 4336 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 ATL1t6 diff --git a/icon.svg b/icon.svg new file mode 100644 index 0000000..65a781f --- /dev/null +++ b/icon.svg @@ -0,0 +1,83 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + From 59c8e9153985ef7dbda7764501e04ce499f93a9d Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 22:28:00 +0200 Subject: [PATCH 13/14] Add Full name to license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8ebd522..52271fd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 ifl0w +Copyright (c) 2014 Wolfgang Rumpler Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From f59d13388d2db4c1a4f56988b0d5559e7e4a98c6 Mon Sep 17 00:00:00 2001 From: Wolfgang Rumpler Date: Thu, 20 Jul 2017 22:34:54 +0200 Subject: [PATCH 14/14] Bump to version 2.0 --- randomwallpaper@iflow.space/metadata.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/randomwallpaper@iflow.space/metadata.json b/randomwallpaper@iflow.space/metadata.json index 6e23a20..68770b7 100644 --- a/randomwallpaper@iflow.space/metadata.json +++ b/randomwallpaper@iflow.space/metadata.json @@ -11,6 +11,7 @@ "uuid": "randomwallpaper@iflow.space", "settings-schema": "org.gnome.shell.extensions.space.iflow.randomwallpaper", "name": "Random Wallpaper", - "description": "Fetches a random wallpaper from desktopper.co and sets it as desktop background", - "version": 1.2 + "description": "Fetches a random wallpaper from an online source and sets it as desktop background. \nThe desktop background can be updated periodically or manually.", + "version": 2.0, + "url": "https://github.com/ifl0w/RandomWallpaperGnome3" }