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/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
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
diff --git a/icon.png b/icon.png
index f241bc5..da3594c 100644
Binary files a/icon.png and b/icon.png differ
diff --git a/icon.svg b/icon.svg
new file mode 100644
index 0000000..65a781f
--- /dev/null
+++ b/icon.svg
@@ -0,0 +1,83 @@
+
+
diff --git a/randomwallpaper@iflow.space/Elements.js b/randomwallpaper@iflow.space/Elements.js
deleted file mode 100644
index 97401be..0000000
--- a/randomwallpaper@iflow.space/Elements.js
+++ /dev/null
@@ -1,260 +0,0 @@
-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 Self = imports.misc.extensionUtils.getCurrentExtension();
-const Timer = Self.imports.timer;
-
-const HistoryElement = new Lang.Class({
- Name: 'HistoryElement',
- Extends: PopupMenu.PopupBaseMenuItem,
- historyId: null,
-
- _init: function(historyId, index, params) {
- index = String(index)+'.' || '0.';
-
- this.parent(params);
-
- let timestamp = parseInt(historyId.slice(0, historyId.lastIndexOf('.')));
- let date = new Date(timestamp);
-
- let timeString = date.toLocaleTimeString();
- let dateString = date.toLocaleDateString();
-
- this.label = new St.Label({
- text: index,
- style_class: 'rwg-history-index'
- });
-
- this.actor.add_child(this.label);
-
- this._container = new St.BoxLayout({
- vertical: true
- });
-
- this.dateLabel = new St.Label({
- text: dateString,
- style_class: 'rwg-history-date'
- });
- this._container.add_child(this.dateLabel);
-
- this.timeLabel = new St.Label({
- text: timeString,
- style_class: 'rwg-history-time'
- });
- this._container.add_child(this.timeLabel);
-
- this.historyId = historyId;
- this.actor.historyId = historyId; // extend the actor with the historyId
-
- this.actor.add_child(this._container);
- }
-});
-
-/**
- * Element for the New Wallpaper button and the remaining time for the auto fetch
- * feature.
- * The remaining time will only be displayed if the af-feature is activated.
- *
- * @type {Lang.Class}
- */
-const NewWallpaperElement = new Lang.Class({
- Name: 'NewWallpaperElement',
- Extends: PopupMenu.PopupBaseMenuItem,
-
- _init: function(params) {
- this.parent(params);
-
- this._timer = new Timer.AFTimer();
-
- this._container = new St.BoxLayout({
- vertical: true
- });
-
- this._newWPLabel = new St.Label({
- text: 'New Wallpaper',
- style_class: 'rwg-new-lable'
- });
- this._container.add_child(this._newWPLabel);
-
- this._remainingLabel = new St.Label({
- text: '1 minute remaining'
- });
- this._container.add_child(this._remainingLabel);
-
- this.actor.add_child(this._container);
- },
-
- show: function() {
- if (this._timer.isActive()) {
- let remainingMinutes = this._timer.remainingMinutes();
- let minutes = remainingMinutes % 60;
- let hours = Math.floor(remainingMinutes / 60);
-
- let hoursText = hours.toString();
- hoursText += (hours == 1) ? ' hour' : ' hours';
- let minText = minutes.toString();
- minText += (minutes == 1) ? ' minute' : ' minutes';
-
- if (hours >= 1) {
- this._remainingLabel.text = '... ' + hoursText + ' and ' + minText + ' remaining.'
- } else {
- this._remainingLabel.text = '... ' + minText + ' remaining.'
- }
-
- this._remainingLabel.show();
- } else {
- this._remainingLabel.hide();
- }
- }
-});
-
-const StatusElement = new Lang.Class({
- Name: 'StatusElement',
- Extends: St.Icon,
-
- _init: function() {
-
- this.parent({
- icon_name: 'preferences-desktop-wallpaper-symbolic',
- style_class: 'system-status-icon'
- });
-
- let _this = this;
-
- this.loadingTweenIn = {
- opacity:20,
- time:1,
- transition:'easeInOutSine',
- onComplete: function() {
- Tweener.addTween(_this, _this.loadingTweenOut);
- }
- }
-
- this.loadingTweenOut = {
- opacity:255,
- time:1,
- transition:'easeInOutSine',
- onComplete: function() {
- if (_this.isLoading) {
- Tweener.addTween(_this, _this.loadingTweenIn);
- } else {
- return false;
- }
- return true;
- }
- }
-
- },
-
- startLoading: function() {
- this.isLoading = true;
- Tweener.addTween(this, this.loadingTweenOut);
- },
-
- 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/elements.js b/randomwallpaper@iflow.space/elements.js
new file mode 100644
index 0000000..856cd1f
--- /dev/null
+++ b/randomwallpaper@iflow.space/elements.js
@@ -0,0 +1,213 @@
+const Lang = imports.lang;
+const PopupMenu = imports.ui.popupMenu;
+const St = imports.gi.St;
+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.PopupSubMenuMenuItem,
+ historyEntry: null,
+
+ _init: function (historyEntry, index) {
+ this.parent("", false);
+
+ let timestamp = historyEntry.timestamp;
+ let date = new Date(timestamp);
+
+ let timeString = date.toLocaleTimeString();
+ let dateString = date.toLocaleDateString();
+
+ 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_above(this.prefixLabel, this.label);
+ this.label.destroy();
+
+ this._container = new St.BoxLayout({
+ vertical: true
+ });
+
+ this.dateLabel = new St.Label({
+ text: dateString,
+ style_class: 'rwg-history-date'
+ });
+ this._container.add_child(this.dateLabel);
+
+ this.timeLabel = new St.Label({
+ text: timeString,
+ style_class: 'rwg-history-time'
+ });
+ this._container.add_child(this.timeLabel);
+
+ this.historyEntry = historyEntry;
+ this.actor.historyId = historyEntry.id; // extend the actor with the historyId
+
+ if (index !== 0) {
+ this.actor.insert_child_above(this._container, this.prefixLabel);
+ }
+
+ 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.'));
+ }
+
+ }
+});
+
+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.
+ * The remaining time will only be displayed if the af-feature is activated.
+ *
+ * @type {Lang.Class}
+ */
+const NewWallpaperElement = new Lang.Class({
+ Name: 'NewWallpaperElement',
+ Extends: PopupMenu.PopupBaseMenuItem,
+
+ _init: function (params) {
+ this.parent(params);
+
+ this._timer = new Timer.AFTimer();
+
+ this._container = new St.BoxLayout({
+ vertical: true
+ });
+
+ this._newWPLabel = new St.Label({
+ text: 'New Wallpaper',
+ style_class: 'rwg-new-lable'
+ });
+ this._container.add_child(this._newWPLabel);
+
+ this._remainingLabel = new St.Label({
+ text: '1 minute remaining'
+ });
+ this._container.add_child(this._remainingLabel);
+
+ this.actor.add_child(this._container);
+ },
+
+ show: function () {
+ if (this._timer.isActive()) {
+ let remainingMinutes = this._timer.remainingMinutes();
+ let minutes = remainingMinutes % 60;
+ let hours = Math.floor(remainingMinutes / 60);
+
+ let hoursText = hours.toString();
+ hoursText += (hours == 1) ? ' hour' : ' hours';
+ let minText = minutes.toString();
+ minText += (minutes == 1) ? ' minute' : ' minutes';
+
+ if (hours >= 1) {
+ this._remainingLabel.text = '... ' + hoursText + ' and ' + minText + ' remaining.'
+ } else {
+ this._remainingLabel.text = '... ' + minText + ' remaining.'
+ }
+
+ this._remainingLabel.show();
+ } else {
+ this._remainingLabel.hide();
+ }
+ }
+});
+
+const StatusElement = new Lang.Class({
+ Name: 'StatusElement',
+ Extends: St.Icon,
+
+ _init: function () {
+
+ this.parent({
+ icon_name: 'preferences-desktop-wallpaper-symbolic',
+ style_class: 'system-status-icon'
+ });
+
+ let _this = this;
+
+ this.loadingTweenIn = {
+ opacity: 20,
+ time: 1,
+ transition: 'easeInOutSine',
+ onComplete: function () {
+ Tweener.addTween(_this, _this.loadingTweenOut);
+ }
+ };
+
+ this.loadingTweenOut = {
+ opacity: 255,
+ time: 1,
+ transition: 'easeInOutSine',
+ onComplete: function () {
+ if (_this.isLoading) {
+ Tweener.addTween(_this, _this.loadingTweenIn);
+ } else {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ },
+
+ startLoading: function () {
+ this.isLoading = true;
+ Tweener.addTween(this, this.loadingTweenOut);
+ },
+
+ stopLoading: function () {
+ this.isLoading = false;
+ Tweener.removeTweens(this);
+ this.opacity = 255;
+ }
+
+});
diff --git a/randomwallpaper@iflow.space/extension.js b/randomwallpaper@iflow.space/extension.js
index bfebcc7..0dc81e8 100644
--- a/randomwallpaper@iflow.space/extension.js
+++ b/randomwallpaper@iflow.space/extension.js
@@ -6,12 +6,14 @@ 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;
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
@@ -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();
@@ -48,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);
@@ -64,7 +73,10 @@ let RandomWallpaperEntry = new Lang.Class({
this.openFolder = new PopupMenu.PopupMenuItem('Open Wallpaper Folder');
this.menu.addMenuItem(this.openFolder);
- //this.menu.addMenuItem(new CustomElements.DelaySlider(60));
+ // settings button
+ this.openSettings = new PopupMenu.PopupMenuItem('Settings');
+ this.menu.addMenuItem(this.openSettings);
+
/*
add eventlistener
*/
@@ -89,6 +101,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();
@@ -107,19 +130,34 @@ 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 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];
- let tmp = new CustomElements.HistoryElement(historyid, i);
+ for (let i = 1; i < history.length; i++) {
+ let historyid = history[i].id;
+ let tmp = new CustomElements.HistoryElement(history[i], i);
tmp.actor.connect('key-focus-in', onEnter);
tmp.actor.connect('key-focus-out', onLeave);
@@ -128,7 +166,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..405fcdb
--- /dev/null
+++ b/randomwallpaper@iflow.space/history.js
@@ -0,0 +1,159 @@
+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,
+ source: null,
+
+ _init: function(author, source, url) {
+ this.timestamp = new Date().getTime();
+
+ this.source = {
+ author: author,
+ authorUrl: null,
+ source: source,
+ sourceUrl: null,
+ imageUrl: url
+ };
+ },
+});
+
+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/images/shuffle-icon.png b/randomwallpaper@iflow.space/images/shuffle-icon.png
deleted file mode 100644
index c2e2a88..0000000
Binary files a/randomwallpaper@iflow.space/images/shuffle-icon.png and /dev/null differ
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 @@
-
-
-
-
-
-
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/metadata.json b/randomwallpaper@iflow.space/metadata.json
index a7ad97f..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.1
+ "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"
}
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 16e327e..bfc7a76 100644
Binary files a/randomwallpaper@iflow.space/schemas/gschemas.compiled and b/randomwallpaper@iflow.space/schemas/gschemas.compiled differ
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 58bb260..13eb4c8 100644
--- a/randomwallpaper@iflow.space/settings.ui
+++ b/randomwallpaper@iflow.space/settings.ui
@@ -2,6 +2,29 @@
+
23
1
@@ -115,7 +138,7 @@
0
- desktoppr.co
- - unsplash.com (not implemented, defaults to desktopper)
+ - unsplash.com (experimental)
- alpha.wallheaven.cc (experimental)
@@ -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 d510ba1..3305226 100644
--- a/randomwallpaper@iflow.space/sourceAdapter.js
+++ b/randomwallpaper@iflow.space/sourceAdapter.js
@@ -1,78 +1,198 @@
const Lang = imports.lang;
+const Self = imports.misc.extensionUtils.getCurrentExtension();
// network requests
const Soup = imports.gi.Soup;
const Json = imports.gi.Json;
-let DesktopperAdapter = new Lang.Class({
- Name: "DesktopperAdapter",
- /*
- fetch a random image url from desktopper.cc
- and call callback function with the URL of the image
+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;
+
+let BaseAdapter = new Lang.Class({
+ Name: "BaseAdapter",
+ logger: null,
+
+ _init: function () {
+ this.logger = new LoggerModule.Logger('RWG3', 'BaseAdapter');
+ },
+
+ /**
+ * 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({
+ 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);
- var _this = this;
+ let message = Soup.Message.new('GET', url);
- session.queue_message(message, function (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');
+ session.queue_message(message, (session, message) => {
+ let data = JSON.parse(message.response_body.data);
+ let response = data.response;
+ let imageUrl = encodeURI(response.image.url);
if (callback) {
- callback(imageUrl);
+ let historyEntry = new HistoryModule.HistoryEntry(null, 'desktopper.co', imageUrl);
+ historyEntry.source.sourceUrl = 'https://www.desktoppr.co/';
+ callback(historyEntry);
}
});
}
});
+let UnsplashAdapter = new Lang.Class({
+ Name: "UnsplashAdapter",
+ Extends: BaseAdapter,
+
+ 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();
+
+ 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';
+
+ session.queue_message(message, (session, message) => {
+ let data = JSON.parse(message.response_body.data);
+
+ let imageUrl = encodeURI(data.links.download + utmParameters);
+ let authorName = data.user.name;
+ let authorUrl = encodeURI(data.user.links.html);
+
+ if (callback) {
+ 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 (var 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);
- 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));
@@ -82,22 +202,65 @@ 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);
imageUrl = 'http:' + imageUrl;
+ imageUrl = encodeURI(imageUrl);
if (callback) {
- callback(imageUrl);
+ let historyEntry = new HistoryModule.HistoryEntry(null, 'wallhaven.cc', imageUrl);
+ historyEntry.source.sourceUrl = 'https://alpha.wallhaven.cc/';
+ callback(historyEntry);
}
})
});
+ },
+
+ _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('');
}
});
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
diff --git a/randomwallpaper@iflow.space/wallpaperController.js b/randomwallpaper@iflow.space/wallpaperController.js
index 0025fc8..a4c015c 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,17 +55,17 @@ let WallpaperController = new Lang.Class({
this._updateHistory();
this._updateAutoFetching();
- this.history = this._loadHistory();
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');
},
_updateHistory: function() {
- this.historySize = this._settings.get('history-length', 'int');
+ this._historyController.load();
},
_updateAutoFetching: function() {
@@ -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;
@@ -108,21 +112,17 @@ 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){
- let contents = file.load_contents_finish(result)[1];
+ input_file.load_contents_async(null, (file, result) => {
+ 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
@@ -132,38 +132,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 +162,37 @@ 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._requestRandomImageFromAdapter((historyElement) => {
+ this.logger.info("Requesting image: "+historyElement.source.imageUrl);
- _this._fetchFile(imageUrl, (historyid, path) => {
- // insert file into history
- _this.history.unshift(historyid);
+ this._fetchFile(historyElement.source.imageUrl, (historyId, path) => {
+ historyElement.path = path;
+ historyElement.id = historyId;
+
+ 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 +208,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 +234,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() {