[gnome-weather/wip/ewlsh/gtk4] Port to ESM



commit 25482696d589b7fa9a3f4477eb555f63cf0692a8
Author: Evan Welsh <contact evanwelsh com>
Date:   Mon Jan 17 02:16:50 2022 -0800

    Port to ESM

 data/application.css                       |  12 +-
 src/app/city.js                            |  27 ++-
 src/app/currentLocationController.js       |  15 +-
 src/app/dailyForecast.js                   |  19 +-
 src/app/entry.js                           | 279 ++++++++---------------------
 src/app/hourlyForecast.js                  |  20 +--
 src/app/main.js                            |  63 +++----
 src/app/thermometer.js                     |  27 +--
 src/app/world.js                           |  12 +-
 src/misc/util.js                           | 114 ++++++------
 src/org.gnome.Weather.BackgroundService.in |  12 +-
 src/org.gnome.Weather.in                   |   8 +-
 src/service/main.js                        |  17 +-
 src/service/searchProvider.js              |  18 +-
 src/shared/world.js                        |  10 +-
 15 files changed, 257 insertions(+), 396 deletions(-)
---
diff --git a/data/application.css b/data/application.css
index f477fef..5bba87b 100644
--- a/data/application.css
+++ b/data/application.css
@@ -1,3 +1,9 @@
+@define-color temp_chart_fill_color rgba(248, 228, 92, 0.5);
+@define-color temp_chart_stroke_color rgba(246, 211, 45, 1.0);
+
+@define-color thermometer_warm_color rgb(245, 194, 17);
+@define-color thermometer_cold_color rgb(28, 113, 216);
+
 #places-label {
     font-weight: bold;
 }
@@ -67,12 +73,6 @@ WeatherThermometer > label.low {
     background-color: white;
 }
 
-@define-color temp_chart_fill_color rgba(248, 228, 92, 0.5);
-@define-color temp_chart_stroke_color rgba(246, 211, 45, 1.0);
-
-@define-color thermometer_warm_color rgb(245, 194, 17);
-@define-color thermometer_cold_color rgb(28, 113, 216);
-
 #updated-time-label {
     font-size: 9pt;
 }
diff --git a/src/app/city.js b/src/app/city.js
index 1f09e57..9e937d9 100644
--- a/src/app/city.js
+++ b/src/app/city.js
@@ -16,26 +16,24 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const Adw = imports.gi.Adw;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gdk = imports.gi.Gdk;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
+import Adw from 'gi://Adw';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
 
-const WorldView = imports.app.world;
-const HourlyForecast = imports.app.hourlyForecast;
-const DailyForecast = imports.app.dailyForecast;
-const Util = imports.misc.util;
+import * as WorldView from './world.js';
+import * as Util from '../misc/util.js';
 
-const SPINNER_SIZE = 128;
+import './hourlyForecast.js';
+import './dailyForecast.js';
 
 const SCROLLING_ANIMATION_TIME = 400000; //us
 
 const UPDATED_TIME_TIMEOUT = 60; //s
 
-var WeatherWidget = GObject.registerClass({
+export const WeatherWidget = GObject.registerClass({
     Template: 'resource:///org/gnome/Weather/weather-widget.ui',
     InternalChildren: [
         'conditionsImage',
@@ -274,8 +272,7 @@ var WeatherWidget = GObject.registerClass({
 
 WeatherWidget.set_layout_manager_type(Adw.ClampLayout);
 
-
-var WeatherView = GObject.registerClass({
+export const WeatherView = GObject.registerClass({
     Template: 'resource:///org/gnome/Weather/city.ui',
     InternalChildren: ['spinner', 'stack']
 }, class WeatherView extends Gtk.Widget {
diff --git a/src/app/currentLocationController.js b/src/app/currentLocationController.js
index 644ac63..8c891d6 100644
--- a/src/app/currentLocationController.js
+++ b/src/app/currentLocationController.js
@@ -16,21 +16,20 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const GLib = imports.gi.GLib;
-const Gio = imports.gi.Gio;
-const Lang = imports.lang;
-const GWeather = imports.gi.GWeather;
-const Geoclue = imports.gi.Geoclue;
+import GLib from 'gi://GLib';
+import GWeather from 'gi://GWeather';
+import Geoclue from 'gi://Geoclue';
 
-const Util = imports.misc.util;
+import * as Util from '../misc/util.js';
 
-var AutoLocation = {
+/** @enum {number} */
+export const AutoLocation = {
     DISABLED: 0,
     ENABLED: 1,
     NOT_AVAILABLE: 2
 };
 
-var CurrentLocationController = class CurrentLocationController {
+export class CurrentLocationController {
     constructor(world) {
         this._world = world;
         this._processStarted = false;
diff --git a/src/app/dailyForecast.js b/src/app/dailyForecast.js
index 881a91e..aab4d00 100644
--- a/src/app/dailyForecast.js
+++ b/src/app/dailyForecast.js
@@ -16,18 +16,15 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const Gdk = imports.gi.Gdk;
-const GWeather = imports.gi.GWeather;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
 
-const Thermometer = imports.app.thermometer;
+import * as Thermometer from './thermometer.js';
+import * as Util from '../misc/util.js';
 
-const Util = imports.misc.util;
-
-var DailyForecastBox = GObject.registerClass(class DailyForecastBox extends Gtk.Box {
+export const DailyForecastBox = GObject.registerClass(class DailyForecastBox extends Gtk.Box {
 
     _init() {
         super._init({
@@ -165,7 +162,7 @@ var DailyForecastBox = GObject.registerClass(class DailyForecastBox extends Gtk.
     }
 });
 
-var DayEntry = GObject.registerClass({
+export const DayEntry = GObject.registerClass({
     Template: 'resource:///org/gnome/Weather/day-entry.ui',
     InternalChildren: ['nameLabel', 'dateLabel', 'image',
         'thermometer',
diff --git a/src/app/entry.js b/src/app/entry.js
index fff170c..698bb93 100644
--- a/src/app/entry.js
+++ b/src/app/entry.js
@@ -1,33 +1,11 @@
-const { Gio, GLib, GWeather, GObject, Gtk, Gdk } = imports.gi;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
 
-const World = imports.app.world;
+import * as World from './world.js';
 
-const LocationItem = GObject.registerClass(
-    {
-        Properties: {
-            'display-name': GObject.ParamSpec.string("display-name", "Display name", "", 
GObject.ParamFlags.READWRITE, ''),
-            'location': GObject.ParamSpec.object("location", "Display name", "", 
GObject.ParamFlags.READWRITE, GWeather.Location.$gtype),
-            'local-compare-name': GObject.ParamSpec.string("local-compare-name", "Local compare name", "", 
GObject.ParamFlags.READWRITE, ''),
-            'english-compare-name': GObject.ParamSpec.string("english-compare-name", "English compare name", 
"", GObject.ParamFlags.READWRITE, ''),
-        }
-    },
-    class LocationItem extends GObject.Object { }
-);
-
-/**
- * @param {string} displayName
- * @param {GWeather.Location} location
- * @param {string} localCompareName
- * @param {string} englishCompareName
- */
-function buildLocationItem(displayName, location, localCompareName, englishCompareName) {
-    const item = new LocationItem();
-    item.displayName = displayName;
-    item.location = location;
-    item.localCompareName = localCompareName;
-    item.englishCompareName = englishCompareName;
-    return item;
-}
 
 GWeather.Location.prototype[Symbol.iterator] = function* () {
     let child = this.next_child(null);
@@ -40,133 +18,57 @@ GWeather.Location.prototype[Symbol.iterator] = function* () {
 
 /** @typedef {Gio.ListModel} ListModel */
 
+function getAllCitiesAndWeatherStations() {
+    const locations = [];
+    for (const region of GWeather.Location.get_world()) {
+        for (const country of region) {
+            for (const location of country) {
+                const level = location.get_level();
+                if (level === GWeather.LocationLevel.ADM1) {
+                    locations.push(location);
+
+                    for (const cityOrStation of location) {
+                        const level = cityOrStation.get_level()
+
+                        if (level === GWeather.LocationLevel.WEATHER_STATION || level === 
GWeather.LocationLevel.CITY) {
+                            locations.push(cityOrStation);
+                        }
+                    }
+                } else if (level === GWeather.LocationLevel.CITY) {
+                    locations.push(location);
+                } else if (level === GWeather.LocationLevel.WEATHER_STATION) {
+                    locations.push(location);
+                }
+            }
+        }
+    }
+    return locations;
+}
+
 const LocationListModel = GObject.registerClass(
     {
         Implements: [Gio.ListModel]
     },
-    class LocationListModel extends Gtk.Widget {
+    class LocationListModel extends GObject.Object {
         _init() {
             super._init();
 
-            this._top = GWeather.Location.get_world();
             this._show_named_timezones = false;
 
             this._list = [];
         }
 
-        /**
-         * @param {GWeather.Location} loc
-         * @param {string | null} parent_display_name
-         * @param {string | null} parent_compare_local_name
-         * @param {string | null} parent_compare_english_name
-         * @param {boolean} show_named_timezones
-         */
-        _fill_location_list_model(
-            loc,
-            parent_display_name,
-            parent_compare_local_name,
-            parent_compare_english_name,
-            show_named_timezones
-        ) {
-            let children = [...loc];
-            /** @type {string | null} */
-            let display_name;
-            /** @type {string | null} */
-            let local_compare_name;
-            /** @type {string | null} */
-            let english_compare_name;
-
-            switch (loc.get_level()) {
-                case GWeather.LocationLevel.WORLD:
-                case GWeather.LocationLevel.REGION:
-                    /* Ignore these levels of hierarchy; just recurse, passing on
-                     * the names from the parent node.
-                     */
-                    children.forEach(child => {
-                        this._fill_location_list_model(child,
-                            parent_display_name,
-                            parent_compare_local_name,
-                            parent_compare_english_name,
-                            show_named_timezones);
-                    });
-                    break;
-
-                case GWeather.LocationLevel.COUNTRY:
-                    /* Recurse, initializing the names to the country name */
-                    children.forEach(child => {
-                        this._fill_location_list_model(child,
-                            loc.get_name(),
-                            loc.get_sort_name(),
-                            loc.get_english_name(),
-                            show_named_timezones);
-                    });
-                    break;
-
-                case GWeather.LocationLevel.ADM1:
-                    /* Recurse, adding the ADM1 name to the country name */
-                    /* Translators: this is the name of a location followed by a region, for example:
-                     * 'London, United Kingdom'
-                     * You shouldn't need to translate this string unless the language has a different comma.
-                     */
-                    display_name = _("%s, %s").format(loc.get_name(), parent_display_name);
-                    local_compare_name = _("%s, %s").format(loc.get_sort_name(), parent_compare_local_name);
-                    english_compare_name = _("%s, %s").format(loc.get_english_name(), 
parent_compare_english_name);
-
-                    children.forEach(child => {
-                        this._fill_location_list_model(child,
-                            display_name, local_compare_name, english_compare_name,
-                            show_named_timezones);
-                    });
-
-                    break;
-
-                case GWeather.LocationLevel.CITY:
-                /* If there are multiple (<location>) children, we use the one
-                 * closest to the city center.
-                 *
-                 * Locations are already sorted by increasing distance from
-                 * the city.
-                 */
-                case GWeather.LocationLevel.WEATHER_STATION:
-                    /* <location> with no parent <city> */
-                    /* Translators: this is the name of a location followed by a region, for example:
-                     * 'London, United Kingdom'
-                     * You shouldn't need to translate this string unless the language has a different comma.
-                     */
-                    display_name = _("%s, %s").format(
-                        loc.get_name(), parent_display_name);
-                    local_compare_name = _("%s, %s").format(
-                        loc.get_sort_name(), parent_compare_local_name);
-                    english_compare_name = _("%s, %s").format(
-                        loc.get_english_name(), parent_compare_english_name);
-
-                    this._list.push(buildLocationItem(display_name, loc, local_compare_name, 
english_compare_name));
-                    break;
-                case GWeather.LocationLevel.NAMED_TIMEZONE:
-                    if (show_named_timezones) {
-                        this._list.push(buildLocationItem(loc.get_name(), loc, loc.get_sort_name(), 
loc.get_english_sort_name()));
-                    }
-                    break;
-
-                case GWeather.LocationLevel.DETACHED:
-                    throw new Error('No detached locations!');
-            }
-        }
-
         /**
          * @this {ListModel & this}
          */
         fill() {
-            if (!this._top) {
-                throw new Error('Failed to load location data');
-            }
+            this._list.push(...getAllCitiesAndWeatherStations());
 
-            this._fill_location_list_model(this._top, null, null, null, this._show_named_timezones);
             this.items_changed(0, 0, this._list.length);
         }
 
         vfunc_get_item_type() {
-            return LocationItem.$gtype;
+            return GWeather.Location.$gtype;
         }
 
         vfunc_get_n_items() {
@@ -181,10 +83,8 @@ const LocationListModel = GObject.registerClass(
         }
     }
 );
-LocationListModel.set_layout_manager_type(Gtk.BinLayout);
-LocationListModel.set_css_name('entry');
 
-var LocationSearchEntry = GObject.registerClass(
+export const LocationSearchEntry = GObject.registerClass(
     {
         Properties: {
             'location': GObject.ParamSpec.object("location", "location", "location", 
GObject.ParamFlags.READWRITE, GWeather.Location.$gtype)
@@ -197,47 +97,48 @@ var LocationSearchEntry = GObject.registerClass(
         _init() {
             super._init();
 
-            try {
-                this._model = new LocationListModel();
-                this._location = null;
+            this._model = new LocationListModel();
+            this._location = null;
 
-                this._entry = new Gtk.SearchEntry();
+            this._entry = new Gtk.SearchEntry();
 
-                this._entry.set_parent(this);
-                this._entry.set_hexpand(true);
-                this._popup = null;
+            this._entry.set_parent(this);
+            this._entry.set_hexpand(true);
+            this._popup = null;
 
 
-                this._entry.connect("search-changed", (source) => {
-                    const text = source.get_text();
+            this._entry.connect("search-changed", (source) => {
+                const text = source.get_text();
 
-                    if (text === null || text === '') {
-                        this._filter?.set_search(null);
-                        this.emit('search-updated', null);
+                if (text === null || text === '') {
+                    this._filter?.set_search(null);
+                    this.emit('search-updated', null);
 
-                        if (this._popup && this._popup.visible) {
-                            this._popup.visible = false;
-                        }
-                        return;
+                    if (this._popup && this._popup.visible) {
+                        this._popup.visible = false;
                     }
+                    return;
+                }
 
-                    if (this._popup && !this._popup.visible) {
-                        this._popup.visible = true;
-                        this._entry?.grab_focus();
-                    }
+                if (this._popup && !this._popup.visible) {
+                    this._popup.visible = true;
+                    this._entry?.grab_focus();
+                }
 
-                    this._filter?.set_search(text);
-                    this.emit('search-updated', text);
-                });
+                this._filter?.set_search(text);
+                this.emit('search-updated', text);
+            });
 
+            imports.mainloop.idle_add(() => {
                 try {
                     this._model.fill();
+
                 } catch (error) {
                     console.error(error);
                 }
-            } catch (e) {
-                logError(e);
-            }
+
+                return false;
+            });
         }
 
         set location(loc) {
@@ -249,36 +150,6 @@ var LocationSearchEntry = GObject.registerClass(
             return this._location ?? null;
         }
 
-        /**
-         * @param {Gtk.Orientation} orientation
-         * @param {number} for_size
-         */
-        vfunc_measure(orientation, for_size) {
-            return this._entry.measure(orientation, for_size);
-        }
-
-        /**
-         * @param {number} width
-         * @param {number} height
-         * @param {number} baseline
-         */
-        vfunc_size_allocate(width, height, baseline) {
-            super.vfunc_size_allocate(width, height, baseline);
-
-            this._entry.size_allocate(new Gdk.Rectangle({
-                x: 0,
-                y: 0,
-                width,
-                height
-            }), baseline);
-
-
-        }
-
-        vfunc_grab_focus() {
-            return this._entry.grab_focus();
-        }
-
         /**
          * @param {Gtk.ListView} listview 
          */
@@ -296,13 +167,11 @@ var LocationSearchEntry = GObject.registerClass(
             listview.set_model(selection);
         }
 
-
-
         _populateModel() {
             let filter = new Gtk.StringFilter();
             this._filter = filter;
-            const expr = Gtk.ClosureExpression.new(GObject.TYPE_STRING, (self) => {
-                return self.displayName ?? "";
+            const expr = Gtk.ClosureExpression.new(GObject.TYPE_STRING, (location) => {
+                return location._cachedName ?? (location._cachedName = location.get_name());
             }, []);
             filter.set_expression(expr);
 
@@ -316,10 +185,10 @@ var LocationSearchEntry = GObject.registerClass(
             selection.set_selected(GLib.MAXUINT32);
             selection.set_autoselect(false);
             selection.connect('notify::selected', (selection) => {
-                const item = selection.get_selected_item();
+                const location = selection.get_selected_item();
 
-                if (item instanceof LocationItem) {
-                    this.location = item.location;
+                if (location instanceof GWeather.Location) {
+                    this.location = location;
 
                     if (this._popup) {
                         this._popup.popdown();
@@ -337,11 +206,13 @@ var LocationSearchEntry = GObject.registerClass(
             });
             this._bindId = factory.connect("bind", (source, listitem) => {
                 const row = listitem.get_child();
-                /** @type {typeof LocationItem.prototype} */
-                const item = listitem.get_item();
+                /** @type {GWeather.Location} */
+                const location = listitem.get_item();
 
                 if (row instanceof World.LocationRow) {
-                    row.locationName = item.display_name;
+                    const parentName = location.get_parent().get_name();
+                    const locationName = location.get_name();
+                    row.locationName = parentName ? [locationName, parentName].join(', ') : locationName;
                 }
             });
 
@@ -356,3 +227,5 @@ var LocationSearchEntry = GObject.registerClass(
     }
 );
 
+LocationSearchEntry.set_layout_manager_type(Gtk.BinLayout);
+
diff --git a/src/app/hourlyForecast.js b/src/app/hourlyForecast.js
index 81d52e6..1393281 100644
--- a/src/app/hourlyForecast.js
+++ b/src/app/hourlyForecast.js
@@ -16,20 +16,20 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gdk = imports.gi.Gdk;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
-const Graphene = imports.gi.Graphene;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Gdk from 'gi://Gdk';
+import GWeather from 'gi://GWeather';
+import Graphene from 'gi://Graphene';
 
-const Util = imports.misc.util;
+import * as Util from '../misc/util.js';
 
 // In microseconds
 const TWENTY_FOUR_HOURS = 24 * 3600 * 1000 * 1000;
 
-var HourlyForecastBox = GObject.registerClass(class HourlyForecastBox extends Gtk.Box {
+export const HourlyForecastBox = GObject.registerClass(class HourlyForecastBox extends Gtk.Box {
     _init() {
         super._init({
             orientation: Gtk.Orientation.HORIZONTAL,
@@ -217,7 +217,7 @@ var HourlyForecastBox = GObject.registerClass(class HourlyForecastBox extends Gt
     }
 });
 
-var HourEntry = GObject.registerClass({
+export const HourEntry = GObject.registerClass({
     Template: 'resource:///org/gnome/Weather/hour-entry.ui',
 
     InternalChildren: ['timeLabel', 'image', 'temperatureLabel'],
diff --git a/src/app/main.js b/src/app/main.js
index 40bbe6f..b7fb91a 100644
--- a/src/app/main.js
+++ b/src/app/main.js
@@ -18,38 +18,35 @@
 
 pkg.initFormat();
 pkg.initGettext();
-window.ngettext = imports.gettext.ngettext;
-
-pkg.require({
-    'Gdk': '4.0',
-    'Gio': '2.0',
-    'GLib': '2.0',
-    'GObject': '2.0',
-    'Gtk': '4.0',
-    'Adw': '1',
-    'GWeather': '4.0'
-});
-
-const ByteArray = imports.byteArray;
-const Adw = imports.gi.Adw;
-const Gdk = imports.gi.Gdk;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
+globalThis.ngettext = imports.gettext.ngettext;
+
+import 'gi://Gdk?version=4.0';
+import 'gi://Gio?version=2.0';
+import 'gi://GLib?version=2.0';
+import 'gi://GObject?version=2.0';
+import 'gi://Gtk?version=4.0';
+import 'gi://Adw?version=1';
+import 'gi://GWeather?version=4.0';
+
+import Adw from 'gi://Adw';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import GWeather from 'gi://GWeather';
 
 // ensure the type before we call to GtkBuilder
-imports.app.entry;
+import './entry.js';
 
-const Util = imports.misc.util;
-const Window = imports.app.window;
-const World = imports.shared.world;
-const CurrentLocationController = imports.app.currentLocationController;
+import * as Util from '../misc/util.js';
+import * as Window from './window.js';
+import * as World from '../shared/world.js';
+import * as CurrentLocationController from './currentLocationController.js';
 
 
-const ShellIntegrationInterface = ByteArray.toString(
-    Gio.resources_lookup_data('/org/gnome/shell/ShellWeatherIntegration.xml', 0).get_data());
+const ShellIntegrationInterface = new TextDecoder().decode(
+    Gio.resources_lookup_data('/org/gnome/shell/ShellWeatherIntegration.xml', 0).get_data()
+);
 
 function initEnvironment() {
     window.getApp = function () {
@@ -207,13 +204,13 @@ const Application = GObject.registerClass(
 
             // Store a weak reference to the window for cleanup...
             this.mainWindow = window;
-
+console.log('created...')
             return window;
         }
 
         _showWindowWhenReady(win) {
             let notifyId;
-
+            win.present();
             if (this.model.loading) {
                 let timeoutId;
                 let model = this.model;
@@ -221,7 +218,7 @@ const Application = GObject.registerClass(
                 timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, function () {
                     log('Timeout during model load, perhaps the network is not available?');
                     model.disconnect(notifyId);
-                    win.show();
+                    
                     return false;
                 });
                 notifyId = this.model.connect('notify::loading', function (model) {
@@ -230,16 +227,14 @@ const Application = GObject.registerClass(
 
                     model.disconnect(notifyId);
                     GLib.source_remove(timeoutId);
-                    win.show();
                 });
-            } else {
-                win.show();
             }
 
             return win;
         }
 
         vfunc_activate() {
+            console.log('activated')
             let win = this._createWindow();
             win.showDefault();
             this._showWindowWhenReady(win);
@@ -290,7 +285,7 @@ let ShellIntegration = class ShellIntegration {
     }
 };
 
-function main(argv) {
+export function main(argv) {
     initEnvironment();
 
     let application = new Application();
diff --git a/src/app/thermometer.js b/src/app/thermometer.js
index 3e3a733..31853c5 100644
--- a/src/app/thermometer.js
+++ b/src/app/thermometer.js
@@ -19,17 +19,15 @@
  * SPDX-License-Identifier: GPL-3.0-or-later
  */
 
-const GObject = imports.gi.GObject;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const Gdk = imports.gi.Gdk;
-const Gtk = imports.gi.Gtk;
-const Graphene = imports.gi.Graphene;
-const Gsk = imports.gi.Gsk;
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
+import Graphene from 'gi://Graphene';
+import Gsk from 'gi://Gsk';
 
-const Util = imports.misc.util;
+import * as Util from '../misc/util.js';
 
-var TemperatureRange = class TemperatureRange {
+export class TemperatureRange {
   dailyLow;
   dailyHigh;
   weeklyLow;
@@ -123,12 +121,9 @@ const ThermometerScale = GObject.registerClass({
   }
 });
 
-// This will be import.meta.url when converted to ESM.
-const url = Gio.File.parse_name(imports.app.entry.__file__).get_uri();
-
-var Thermometer = GObject.registerClass({
+export const Thermometer = GObject.registerClass({
   CssName: 'WeatherThermometer',
-  Template: GLib.Uri.resolve_relative(url, './thermometer.ui', 0),
+  Template: GLib.Uri.resolve_relative(import.meta.url, './thermometer.ui', 0),
   InternalChildren: ['scale', 'highLabel', 'lowLabel'],
   Properties: {
     'range': GObject.ParamSpec.jsobject(
@@ -143,10 +138,6 @@ var Thermometer = GObject.registerClass({
     super._init(params);
 
     this.layoutManager.orientation = Gtk.Orientation.VERTICAL;
-
-    this._scale = this.get_template_child(Thermometer, 'scale');
-    this._highLabel = this.get_template_child(Thermometer, 'highLabel');
-    this._lowLabel = this.get_template_child(Thermometer, 'lowLabel');
   }
 
   vfunc_root() {
diff --git a/src/app/world.js b/src/app/world.js
index ecf72e2..a493ccf 100644
--- a/src/app/world.js
+++ b/src/app/world.js
@@ -17,16 +17,12 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const Gtk = imports.gi.Gtk;
-const GWeather = imports.gi.GWeather;
+import GObject from 'gi://GObject';
+import Gtk from 'gi://Gtk';
 
-const CurrentLocationController = imports.app.currentLocationController;
-const Util = imports.misc.util;
 
 // TODO: Finish converting into a proper GObject w/ properties
-const LocationRow = GObject.registerClass(class LocationRow extends Gtk.Widget {
+export const LocationRow = GObject.registerClass(class LocationRow extends Gtk.Widget {
 
     _init(locationName, isCurrentLocation) {
         super._init({});
@@ -309,4 +305,4 @@ class _WorldContentView extends Gtk.Popover {
     }
 };
 
-var WorldContentView = GObject.registerClass(_WorldContentView);
+export const WorldContentView = GObject.registerClass(_WorldContentView);
diff --git a/src/misc/util.js b/src/misc/util.js
index c15ff20..b390dbf 100644
--- a/src/misc/util.js
+++ b/src/misc/util.js
@@ -24,13 +24,14 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-const Gdk = imports.gi.Gdk;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const Gtk = imports.gi.Gtk;
-const Adw = imports.gi.Adw;
-const System = imports.system;
-const GWeather = imports.gi.GWeather;
+import Adw from 'gi://Adw';
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import Gtk from 'gi://Gtk';
+import Gdk from 'gi://Gdk';
+import GWeather from 'gi://GWeather';
+
+import * as System from 'system';
 
 function loadUI(resourcePath, objects) {
     let ui = new Gtk.Builder();
@@ -48,45 +49,27 @@ function loadStyleSheet(resource) {
     let provider = new Gtk.CssProvider();
     provider.load_from_file(Gio.File.new_for_uri(resource));
     Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(),
-                                             provider,
-                                             Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+        provider,
+        Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
 }
 
 function arrayEqual(one, two) {
-    if (one.length != two.length)
+    if (one.length !== two.length)
         return false;
 
-    for (let i = 0; i < one.length; i++)
-        if (one[i] != two[i])
-            return false;
-
-    return true;
+    return one.every((a, i) => a === two[i]);
 }
 
-function getSettings(schemaId, path) {
-    const GioSSS = Gio.SettingsSchemaSource;
-    let schemaSource;
-
-    if (!pkg.moduledir.startsWith('resource://')) {
-        // Running from the source tree
-        schemaSource = GioSSS.new_from_directory(pkg.pkgdatadir,
-                                                 GioSSS.get_default(),
-                                                 false);
-    } else {
-        schemaSource = GioSSS.get_default();
-    }
+function getSettings(schemaId) {
+    const schemaSource = Gio.SettingsSchemaSource.get_default();
+    const schemaObj = schemaSource.lookup(schemaId, true);
 
-    let schemaObj = schemaSource.lookup(schemaId, true);
     if (!schemaObj) {
-        log('Missing GSettings schema ' + schemaId);
+        log(`Missing GSettings schema ${schemaId}`);
         System.exit(1);
     }
 
-    if (path === undefined)
-        return new Gio.Settings({ settings_schema: schemaObj });
-    else
-        return new Gio.Settings({ settings_schema: schemaObj,
-                                  path: path });
+    return new Gio.Settings({ settings_schema: schemaObj });
 }
 
 function getWeatherConditions(info) {
@@ -96,13 +79,6 @@ function getWeatherConditions(info) {
     return conditions;
 }
 
-function isCdm(c) {
-    return ((c >= 0x0300 && c <= 0x036F) ||
-        (c >= 0x1DC0 && c <= 0x1DFF)  ||
-        (c >= 0x20D0 && c <= 0x20FF)  ||
-        (c >= 0xFE20 && c <= 0xFE2F));
-}
-
 function normalizeCasefoldAndUnaccent(str) {
     // The one and only!
     // Travelled all over gnome, from tracker to gnome-shell to gnome-control-center,
@@ -123,8 +99,8 @@ function normalizeCasefoldAndUnaccent(str) {
 }
 
 function getTemperature(info) {
-    let [ok1, ] = info.get_value_temp_min(GWeather.TemperatureUnit.DEFAULT);
-    let [ok2, ] = info.get_value_temp_max(GWeather.TemperatureUnit.DEFAULT);
+    let [ok1,] = info.get_value_temp_min(GWeather.TemperatureUnit.DEFAULT);
+    let [ok2,] = info.get_value_temp_max(GWeather.TemperatureUnit.DEFAULT);
 
     if (ok1 && ok2) {
         /* TRANSLATORS: this is the temperature string, minimum and maximum.
@@ -152,37 +128,37 @@ function easeOutCubic(value) {
 
 function getNight(date) {
     return GLib.DateTime.new_local(date.get_year(),
-                                   date.get_month(),
-                                   date.get_day_of_month(),
-                                   2, 0, 0);
+        date.get_month(),
+        date.get_day_of_month(),
+        2, 0, 0);
 }
 
 function getMorning(date) {
     return GLib.DateTime.new_local(date.get_year(),
-                                   date.get_month(),
-                                   date.get_day_of_month(),
-                                   7, 0, 0);
+        date.get_month(),
+        date.get_day_of_month(),
+        7, 0, 0);
 }
 
 function getDay(date) {
     return GLib.DateTime.new_local(date.get_year(),
-                                   date.get_month(),
-                                   date.get_day_of_month(),
-                                   12, 0, 0);
+        date.get_month(),
+        date.get_day_of_month(),
+        12, 0, 0);
 }
 
 function getAfternoon(date) {
     return GLib.DateTime.new_local(date.get_year(),
-                                   date.get_month(),
-                                   date.get_day_of_month(),
-                                   17, 0, 0);
+        date.get_month(),
+        date.get_day_of_month(),
+        17, 0, 0);
 }
 
 function getEvening(date) {
     return GLib.DateTime.new_local(date.get_year(),
-                                   date.get_month(),
-                                   date.get_day_of_month(),
-                                   22, 0, 0);
+        date.get_month(),
+        date.get_day_of_month(),
+        22, 0, 0);
 }
 
 function getDateTime(info) {
@@ -209,3 +185,25 @@ function getTempString(info) {
 function isDarkTheme() {
     return Adw.StyleManager.get_default().dark;
 }
+
+export {
+    loadUI,
+    formatTemperature,
+    getDateTime,
+    getTemp,
+    getEvening,
+    isDarkTheme,
+    getAfternoon,
+    getTempString,
+    getNight,
+    normalizeCasefoldAndUnaccent,
+    arrayEqual,
+    getSettings,
+    loadStyleSheet,
+    getMorning,
+    getTemperature,
+    getDay,
+    easeOutCubic,
+    getEnabledProviders,
+    getWeatherConditions
+}
\ No newline at end of file
diff --git a/src/org.gnome.Weather.BackgroundService.in b/src/org.gnome.Weather.BackgroundService.in
index 9e44933..03f47c0 100755
--- a/src/org.gnome.Weather.BackgroundService.in
+++ b/src/org.gnome.Weather.BackgroundService.in
@@ -3,4 +3,14 @@ imports.package.init({ name: "@APP_ID@",
                         version: "@VERSION@",
                         prefix: "@prefix@",
                         libdir: "@libdir@" });
-imports.package.run(imports.service.main);
+
+import('resource:///org/gnome/Weather@profile@/js/service/main.js').then(({ main }) => {
+    main([imports.system.programInvocationName, ...imports.system.programArgs]);
+}).catch(error => {
+    logError(error);
+    System.exit(1);
+}).finally(() => {
+    imports.mainloop.quit();
+});
+
+imports.mainloop.run();
\ No newline at end of file
diff --git a/src/org.gnome.Weather.in b/src/org.gnome.Weather.in
index 9c26b18..b3a6153 100755
--- a/src/org.gnome.Weather.in
+++ b/src/org.gnome.Weather.in
@@ -3,4 +3,10 @@ imports.package.init({ name: "@APP_ID@",
                         version: "@VERSION@",
                         prefix: "@prefix@",
                         libdir: "@libdir@" });
-imports.package.run(imports.app.main);
+
+import(`resource:///org/gnome/Weather@profile@/js/app/main.js`).then(({ main }) => {
+    main([imports.system.programInvocationName, ...imports.system.programArgs]);
+}).catch(error => {
+    logError(error);
+    System.exit(1);
+});
diff --git a/src/service/main.js b/src/service/main.js
index b28e3d3..db74c10 100644
--- a/src/service/main.js
+++ b/src/service/main.js
@@ -23,14 +23,13 @@ pkg.require({ 'Gio': '2.0',
               'GObject': '2.0',
               'GWeather': '4.0' });
 
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const GWeather = imports.gi.GWeather;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GObject from 'gi://GObject';
+import GWeather from 'gi://GWeather';
 
-const Util = imports.misc.util;
-const SearchProvider = imports.service.searchProvider;
-const World = imports.shared.world;
+import * as SearchProvider from './searchProvider.js';
+import * as World from '../shared/world.js';
 
 function initEnvironment() {
     window.getApp = function() {
@@ -47,7 +46,7 @@ const BackgroundService = GObject.registerClass(
                       inactivity_timeout: 60000 });
         GLib.set_application_name(_("Weather"));
 
-        this._searchProvider = new SearchProvider.SearchProvider(this);
+        this._searchProvider = new SearchProvider.WeatherSearchProvider(this);
 
         if (!pkg.moduledir.startsWith('resource://'))
             this.debug = true;
@@ -106,7 +105,7 @@ const BackgroundService = GObject.registerClass(
     }
 });
 
-function main(argv) {
+export function main(argv) {
     initEnvironment();
 
     return (new BackgroundService()).run(argv);
diff --git a/src/service/searchProvider.js b/src/service/searchProvider.js
index 8936afb..0b650fc 100644
--- a/src/service/searchProvider.js
+++ b/src/service/searchProvider.js
@@ -16,16 +16,16 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const ByteArray = imports.byteArray;
-const Gio = imports.gi.Gio;
-const GLib = imports.gi.GLib;
-const GWeather = imports.gi.GWeather;
-const Lang = imports.lang;
+import Gio from 'gi://Gio';
+import GLib from 'gi://GLib';
+import GWeather from 'gi://GWeather';
 
-const Util = imports.misc.util;
-const World = imports.shared.world;
+import * as Util from '../misc/util.js';
 
-const SearchProviderInterface = 
ByteArray.toString(Gio.resources_lookup_data('/org/gnome/shell/ShellSearchProvider2.xml', 0).get_data());
+
+const SearchProviderInterface = new TextDecoder().decode(
+    Gio.resources_lookup_data('/org/gnome/shell/ShellSearchProvider2.xml', 0).get_data()
+);
 
 function getCountryName(location) {
     while (location &&
@@ -35,7 +35,7 @@ function getCountryName(location) {
     return location.get_name();
 }
 
-var SearchProvider = class WeatherSearchProvider {
+export class WeatherSearchProvider {
     constructor(application) {
         this._app = application;
 
diff --git a/src/shared/world.js b/src/shared/world.js
index 081edf0..3badf5b 100644
--- a/src/shared/world.js
+++ b/src/shared/world.js
@@ -16,13 +16,13 @@
 // with Gnome Weather; if not, write to the Free Software Foundation,
 // Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-const GLib = imports.gi.GLib;
-const GObject = imports.gi.GObject;
-const GWeather = imports.gi.GWeather;
+import GObject from 'gi://GObject';
+import GLib from 'gi://GLib';
+import GWeather from 'gi://GWeather';
 
-const Util = imports.misc.util;
+import * as Util from '../misc/util.js';
 
-var WorldModel = GObject.registerClass({
+export const WorldModel = GObject.registerClass({
     Signals: {
         'current-location-changed': { param_types: [ GWeather.Info ] },
         'location-added': { param_types: [ GWeather.Info, GObject.Boolean ] },


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]