diff options
-rw-r--r-- | .github/workflows/ci.yml | 2 | ||||
-rw-r--r-- | src/images/icons/star_orange.svg | 6 | ||||
-rw-r--r-- | src/images/icons/star_orange_stroke.svg | 6 | ||||
-rw-r--r-- | src/images/icons/star_transparent.svg | 6 | ||||
-rw-r--r-- | src/js/port_handler.js | 20 | ||||
-rw-r--r-- | src/js/tabs/options.js | 11 | ||||
-rw-r--r-- | src/js/tabs/setup.js | 4 | ||||
-rw-r--r-- | src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js | 6 | ||||
-rw-r--r-- | src/tabs/presets/FavoritePresets.js | 15 | ||||
-rw-r--r-- | src/tabs/presets/TitlePanel/PresetTitlePanel.css | 18 | ||||
-rw-r--r-- | src/tabs/presets/TitlePanel/PresetTitlePanel.js | 88 | ||||
-rw-r--r-- | src/tabs/presets/TitlePanel/PresetTitlePanelBody.html | 1 | ||||
-rw-r--r-- | src/tabs/presets/presets.js | 4 |
13 files changed, 155 insertions, 32 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b479041a..55b4de27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,7 +81,7 @@ jobs: cache: yarn - name: Install Java JDK 8 - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 if: ${{ matrix.name == 'Android' }} with: distribution: temurin diff --git a/src/images/icons/star_orange.svg b/src/images/icons/star_orange.svg new file mode 100644 index 00000000..7be1447a --- /dev/null +++ b/src/images/icons/star_orange.svg @@ -0,0 +1,6 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> + <g id="Layer_1"> + <title>Layer 1</title> + <path stroke="#ffbb00" stroke-width="2" id="svg_1" d="m3.08281,39.47823l35.8418,0l11.07539,-34.04956l11.0754,34.04956l35.84179,0l-28.99657,21.04355l11.07596,34.04956l-28.99658,-21.04412l-28.99658,21.04412l11.07597,-34.04956l-28.99658,-21.04355z" fill="#ffbb00"/> + </g> +</svg>
\ No newline at end of file diff --git a/src/images/icons/star_orange_stroke.svg b/src/images/icons/star_orange_stroke.svg new file mode 100644 index 00000000..71fe5fe7 --- /dev/null +++ b/src/images/icons/star_orange_stroke.svg @@ -0,0 +1,6 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> + <g id="Layer_1"> + <title>Layer 1</title> + <path stroke="#ffbb00" stroke-width="2" id="svg_1" d="m3.08281,39.47823l35.8418,0l11.07539,-34.04956l11.0754,34.04956l35.84179,0l-28.99657,21.04355l11.07596,34.04956l-28.99658,-21.04412l-28.99658,21.04412l11.07597,-34.04956l-28.99658,-21.04355z" fill="none"/> + </g> +</svg>
\ No newline at end of file diff --git a/src/images/icons/star_transparent.svg b/src/images/icons/star_transparent.svg new file mode 100644 index 00000000..a1b233d5 --- /dev/null +++ b/src/images/icons/star_transparent.svg @@ -0,0 +1,6 @@ +<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> + <g id="Layer_1"> + <title>Layer 1</title> + <path stroke="#9c9c9c" stroke-width="2" id="svg_1" d="m3.08281,39.47823l35.8418,0l11.07539,-34.04956l11.0754,34.04956l35.84179,0l-28.99657,21.04355l11.07596,34.04956l-28.99658,-21.04412l-28.99658,21.04412l11.07597,-34.04956l-28.99658,-21.04355z" fill="none"/> + </g> +</svg>
\ No newline at end of file diff --git a/src/js/port_handler.js b/src/js/port_handler.js index aed0da48..8d10afe6 100644 --- a/src/js/port_handler.js +++ b/src/js/port_handler.js @@ -26,9 +26,6 @@ PortHandler.initialize = function () { this.selectList = document.querySelector(portPickerElementSelector); this.initialWidth = this.selectList.offsetWidth + 12; - this.showVirtualMode = ConfigStorage.get('showVirtualMode').showVirtualMode; - this.showAllSerialDevices = ConfigStorage.get('showAllSerialDevices').showAllSerialDevices; - // fill dropdown with version numbers generateVirtualApiVersions(); @@ -120,8 +117,17 @@ PortHandler.initialize = function () { } }, MDNS_INTERVAL); - // start listening, check after TIMEOUT_CHECK ms - this.check(); + this.reinitialize(); // just to prevent code redundancy +}; + +PortHandler.reinitialize = function () { + this.initialPorts = false; + if (this.usbCheckLoop) { + clearTimeout(this.usbCheckLoop); + } + this.showVirtualMode = ConfigStorage.get('showVirtualMode').showVirtualMode; + this.showAllSerialDevices = ConfigStorage.get('showAllSerialDevices').showAllSerialDevices; + this.check(); // start listening, check after TIMEOUT_CHECK ms }; PortHandler.check = function () { @@ -135,7 +141,7 @@ PortHandler.check = function () { self.check_serial_devices(); } - setTimeout(function () { + self.usbCheckLoop = setTimeout(function () { self.check(); }, TIMEOUT_CHECK); }; @@ -197,7 +203,7 @@ PortHandler.check_usb_devices = function (callback) { data: {isManual: true}, })); - self.portPickerElement.val('DFU').change(); + self.portPickerElement.val('DFU').trigger('change'); self.setPortsInputWidth(); } self.dfu_available = true; diff --git a/src/js/tabs/options.js b/src/js/tabs/options.js index 5f6b7535..b75d4c38 100644 --- a/src/js/tabs/options.js +++ b/src/js/tabs/options.js @@ -133,8 +133,10 @@ options.initShowAllSerialDevices = function() { const result = ConfigStorage.get('showAllSerialDevices'); showAllSerialDevicesElement .prop('checked', !!result.showAllSerialDevices) - .on('change', () => ConfigStorage.set({ showAllSerialDevices: showAllSerialDevicesElement.is(':checked') })) - .trigger('change'); + .on('change', () => { + ConfigStorage.set({ showAllSerialDevices: showAllSerialDevicesElement.is(':checked') }); + PortHandler.reinitialize(); + }); }; options.initShowVirtualMode = function() { @@ -144,9 +146,8 @@ options.initShowVirtualMode = function() { .prop('checked', !!result.showVirtualMode) .on('change', () => { ConfigStorage.set({ showVirtualMode: showVirtualModeElement.is(':checked') }); - PortHandler.initialPorts = false; - }) - .trigger('change'); + PortHandler.reinitialize(); + }); }; options.initCordovaForceComputerUI = function () { diff --git a/src/js/tabs/setup.js b/src/js/tabs/setup.js index 7bdd6421..7a119b86 100644 --- a/src/js/tabs/setup.js +++ b/src/js/tabs/setup.js @@ -54,9 +54,7 @@ setup.initialize = function (callback) { } else if (semver.gte(FC.CONFIG.apiVersion, API_VERSION_1_41)) { restoreButton.addClass('disabled'); - if (!PortHandler.showVirtualMode) { - $('.backupRestore').hide(); - } + $('.backupRestore').hide(); } // initialize 3D Model diff --git a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js index 9f110bf1..cbf4e075 100644 --- a/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js +++ b/src/tabs/presets/DetailedDialog/PresetsDetailedDialog.js @@ -1,13 +1,14 @@ 'use strict'; class PresetsDetailedDialog { - constructor(domDialog, pickedPresetList, onPresetPickedCallback) { + constructor(domDialog, pickedPresetList, onPresetPickedCallback, favoritePresets) { this._domDialog = domDialog; this._pickedPresetList = pickedPresetList; this._finalDialogYesNoSettings = {}; this._onPresetPickedCallback = onPresetPickedCallback; this._openPromiseResolve = undefined; this._isDescriptionHtml = false; + this._favoritePresets = favoritePresets; } load() { @@ -71,7 +72,8 @@ class PresetsDetailedDialog { } this._titlePanel.empty(); - const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, false, () => this._setLoadingState(false)); + const titlePanel = new PresetTitlePanel(this._titlePanel, this._preset, false, + () => this._setLoadingState(false), this._favoritePresets); titlePanel.load(); this._loadOptionsSelect(); this._updateFinalCliText(); diff --git a/src/tabs/presets/FavoritePresets.js b/src/tabs/presets/FavoritePresets.js index f5799ba5..9693d7d5 100644 --- a/src/tabs/presets/FavoritePresets.js +++ b/src/tabs/presets/FavoritePresets.js @@ -53,6 +53,16 @@ class FavoritePresetsData { return preset; } + delete(presetPath) { + const index = this._favoritePresetsList.findIndex((preset) => preset.presetPath === presetPath); + + if (index >= 0) { + this._favoritePresetsList.splice(index, 1); + this._sort(); + this._purgeOldPresets(); + } + } + findPreset(presetPath) { return this._favoritePresetsList.find((preset) => preset.presetPath === presetPath); } @@ -69,6 +79,11 @@ class FavoritePresetsClass { preset.lastPickDate = favoritePreset.lastPickDate; } + delete(preset) { + this._favoritePresetsData.delete(preset.fullPath); + preset.lastPickDate = undefined; + } + addLastPickDate(presets) { for (let preset of presets) { let favoritePreset = this._favoritePresetsData.findPreset(preset.fullPath); diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.css b/src/tabs/presets/TitlePanel/PresetTitlePanel.css index bdd086d6..e9481d12 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanel.css +++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.css @@ -1,5 +1,6 @@ .preset_title_panel { color: var(--defaultText); + position: relative; } .preset_title_panel_border { @@ -14,11 +15,26 @@ .preset_title_panel_title { font-size: 1.5em; font-weight: bold; - display: block; + display: inline-block; margin-bottom: 1ex; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + width: calc(100% - 30px); +} + +.preset_title_panel_star { + background-image: url(../../../images/icons/star_orange.svg); + width: 25px; + height: 25px; + background-size: cover; + border-radius: 5px; + padding: 5px; + background-origin: content-box; + background-repeat: no-repeat; + position: absolute; + right: -6px; + top: -5px; } .preset_title_panel_category { diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanel.js b/src/tabs/presets/TitlePanel/PresetTitlePanel.js index ec2b66f5..8c49760d 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanel.js +++ b/src/tabs/presets/TitlePanel/PresetTitlePanel.js @@ -2,7 +2,7 @@ class PresetTitlePanel { - constructor(parentDiv, preset, clickable, onLoadedCallback) + constructor(parentDiv, preset, clickable, onLoadedCallback, favoritePresets) { PresetTitlePanel.s_panelCounter ++; this._parentDiv = parentDiv; @@ -10,16 +10,45 @@ class PresetTitlePanel this._domId = `preset_title_panel_${PresetTitlePanel.s_panelCounter}`; this._preset = preset; this._clickable = clickable; + this._favoritePresets = favoritePresets; this._parentDiv.append(`<div class="${this._domId}"></div>`); this._domWrapperDiv = $(`.${this._domId}`); this._domWrapperDiv.toggle(false); + this._starJustClicked = false; + this._mouseOnStar = false; + this._mouseOnPanel = false; + this._clickable = clickable; if (clickable) { this._domWrapperDiv.addClass("preset_title_panel_border"); // setting up hover effect here, because if setup in SCC it stops working after background animation like - this._domWrapperDiv.animate({ backgroundColor.... - this._domWrapperDiv.on("mouseenter", () => this._domWrapperDiv.css({"background-color": "var(--subtleAccent)"})); - this._domWrapperDiv.on("mouseleave", () => this._domWrapperDiv.css({"background-color": "var(--boxBackground)"})); + } + } + + _updateHoverEffects() { + let starMouseHover = false; + + if (this._clickable && this._mouseOnPanel && !this._mouseOnStar) { + this._domWrapperDiv.css({"background-color": "var(--subtleAccent)"}); + } else { + this._domWrapperDiv.css({"background-color": "var(--boxBackground)"}); + } + + if (this._mouseOnStar || (this._mouseOnPanel && this._clickable)) { + this._domStar.css({"background-color": "var(--subtleAccent)"}); + starMouseHover = true; + } else { + this._domWrapperDiv.css({"background-color": "var(--boxBackground)"}); + this._domStar.css({"background-color": "var(--boxBackground)"}); + } + + if (this._preset.lastPickDate) { + this._domStar.css("background-image", "url('../../../images/icons/star_orange.svg')"); + } else if (starMouseHover) { + this._domStar.css("background-image", "url('../../../images/icons/star_orange_stroke.svg')"); + } else { + this._domStar.css("background-image", "url('../../../images/icons/star_transparent.svg')"); } } @@ -30,14 +59,24 @@ class PresetTitlePanel subscribeClick(presetsDetailedDialog, presetsRepo) { this._domWrapperDiv.on("click", () => { - presetsDetailedDialog.open(this._preset, presetsRepo).then(isPresetPicked => { - if (isPresetPicked) { - const color = this._domWrapperDiv.css( "background-color" ); - this._domWrapperDiv.css('background-color', 'green'); - this._domWrapperDiv.animate({ backgroundColor: color }, 2000); - this.setPicked(true); - } - }); + if (!this._starJustClicked) { + this._showPresetsDetailedDialog(presetsDetailedDialog, presetsRepo); + } + + this._starJustClicked = false; + }); + } + + _showPresetsDetailedDialog(presetsDetailedDialog, presetsRepo) { + presetsDetailedDialog.open(this._preset, presetsRepo).then(isPresetPicked => { + if (isPresetPicked) { + const color = this._domWrapperDiv.css( "background-color" ); + this._domWrapperDiv.css('background-color', 'green'); + this._domWrapperDiv.animate({ backgroundColor: color }, 2000); + this.setPicked(true); + } + + this._updateHoverEffects(); }); } @@ -70,6 +109,12 @@ class PresetTitlePanel this._domStatusCommunity.toggle(this._preset.status === "COMMUNITY"); this._domStatusExperimental.toggle(this._preset.status === "EXPERIMENTAL"); this.setPicked(this._preset.isPicked); + this._setupStar(); + + this._domWrapperDiv.on("mouseenter", () => { this._mouseOnPanel = true; this._updateHoverEffects(); }); + this._domWrapperDiv.on("mouseleave", () => { this._mouseOnPanel = false; this._updateHoverEffects(); } ); + this._domStar.on("mouseenter", () => { this._mouseOnStar = true; this._updateHoverEffects(); }); + this._domStar.on("mouseleave", () => { this._mouseOnStar = false; this._updateHoverEffects(); }); i18n.localizePage(); this._domWrapperDiv.toggle(true); @@ -79,6 +124,7 @@ class PresetTitlePanel _readDom() { this._domTitle = this._domWrapperDiv.find('.preset_title_panel_title'); + this._domStar = this._domWrapperDiv.find('.preset_title_panel_star'); this._domCategory = this._domWrapperDiv.find('.preset_title_panel_category'); this._domAuthor = this._domWrapperDiv.find('.preset_title_panel_author_text'); this._domKeywords = this._domWrapperDiv.find('.preset_title_panel_keywords_text'); @@ -88,6 +134,26 @@ class PresetTitlePanel this._domStatusExperimental = this._domWrapperDiv.find('.preset_title_panel_status_experimental'); } + _setupStar() { + this._updateHoverEffects(); + + this._domStar.on("click", () => { + this._starJustClicked = true; + this._processStarClick(); + }); + } + + _processStarClick() { + if (this._preset.lastPickDate) { + this._favoritePresets.delete(this._preset); + } else { + this._favoritePresets.add(this._preset); + } + + this._favoritePresets.saveToStorage(); + this._updateHoverEffects(); + } + remove() { this._domWrapperDiv.remove(); diff --git a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html index 081c53eb..7dd031ba 100644 --- a/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html +++ b/src/tabs/presets/TitlePanel/PresetTitlePanelBody.html @@ -1,4 +1,5 @@ <div class="preset_title_panel"> + <span class="preset_title_panel_star"></span> <div> <span class="preset_title_panel_title"></span> </div> diff --git a/src/tabs/presets/presets.js b/src/tabs/presets/presets.js index f5e89656..fd7936e7 100644 --- a/src/tabs/presets/presets.js +++ b/src/tabs/presets/presets.js @@ -269,7 +269,7 @@ presets.onHtmlLoad = function(callback) { this.setupBackupWarning(); this._inputTextFilter.attr("placeholder", "example: \"karate race\", or \"5'' freestyle\""); - this.presetsDetailedDialog = new PresetsDetailedDialog($("#presets_detailed_dialog"), this.pickedPresetList, () => this.onPresetPickedCallback()); + this.presetsDetailedDialog = new PresetsDetailedDialog($("#presets_detailed_dialog"), this.pickedPresetList, () => this.onPresetPickedCallback(), favoritePresets); this.presetsSourcesDialog = new PresetsSourcesDialog($("#presets_sources_dialog")); this.presetsDetailedDialog.load() @@ -460,7 +460,7 @@ presets.displayPresets = function(fitPresets) { this._domListNoFound.toggle(fitPresets.length === 0); fitPresets.forEach(preset => { - const presetPanel = new PresetTitlePanel(this._divPresetList, preset, true); + const presetPanel = new PresetTitlePanel(this._divPresetList, preset, true, undefined, favoritePresets); presetPanel.load(); this._presetPanels.push(presetPanel); presetPanel.subscribeClick(this.presetsDetailedDialog, this.presetsRepo); |