细分组件

This commit is contained in:
wurou 2022-09-23 16:04:35 +08:00
parent 9191e09646
commit 861ad2a586
39 changed files with 1570 additions and 3258 deletions

9
global.d.ts vendored
View File

@ -1,9 +0,0 @@
interface WebActivity {
start(): Promise<any>;
cancel(): void;
}
declare var WebActivity: {
prototype: WebActivity;
new(name: string, data?: any): WebActivity;
};

View File

@ -0,0 +1,193 @@
import {html, css, LitElement, HTMLTemplateResult} from 'lit'
import {customElement, property, query} from 'lit/decorators.js'
@customElement('brightness-slider')
export class BrightnessSlider extends LitElement {
@query('.progress') progress!: HTMLDivElement
@query('.sliderBar') sliderBar!: HTMLDivElement
@property({type: String}) id = ''
@property({type: String}) _coverLen = ''
@property({type: Number}) innerWidth = 0
@property({type: Number}) distance = 0
@property({type: Number}) currentDistance = 0
@property({type: Number}) barWidth = 0
@property({type: Number}) max = 100
@property({type: Number}) value = 1
@property() touchAction = {
// 触摸开始落点
start: {
offsetX: 0,
offsetY: 0,
clientX: 0,
clientY: 0,
},
// 触摸结束落点
last: {
offsetX: 0,
offsetY: 0,
clientX: 0,
clientY: 0,
},
}
@property({type: String})
get coverLen() {
return this._coverLen
}
set coverLen(value: string) {
this.style.setProperty('--cover-length', value)
this._coverLen = value
}
render(): HTMLTemplateResult {
return html`
<div
class="sliderBar"
data-icon="brightness"
value=${this.value}
max=${this.max}
@touchstart=${this}
@touchmove=${this}
@touchend=${this}
>
<div class="progress"></div>
</div>
`
}
static styles = css`
:host {
width: inherit;
height: inherit;
dislay: block;
--cover-length: 3.78px; // 亮度为1
--background-lm: rgba(255, 255, 255, 0.5);
--background-dm: rgba(0, 0, 0, 0.15);
--progress-background-lm: rgba(255, 255, 255, 0.8);
--progress-background-dm: rgba(255, 255, 255, 0.7);
}
.sliderBar {
width: inherit;
height: inherit;
position: absolute;
left: 0px;
right: 0px;
background: var(--background-lm);
}
.progress {
width: var(--cover-length);
height: 100%;
position: absolute;
left: 0px;
right: 0px;
background: var(--progress-background-lm);
}
.sliderBar::before {
position: absolute;
content: attr(data-icon);
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
@media screen and (max-width: 1200px) {
.sliderBar {
border-radius: 16px;
}
.progress {
border-radius: 16px;
}
.sliderBar::before {
width: 48px;
height: 48px;
left: 29px;
top: 29px;
font-size: 48px;
}
}
@media screen and (max-width: 600px) {
.sliderBar {
border-radius: 8px;
}
.progress {
border-radius: 8px;
}
.sliderBar::before {
width: 24px;
height: 24px;
left: 14px;
top: 24px;
font-size: 24px;
}
}
`
firstUpdated() {
if (this.value) {
let len = Math.floor((this.value * this.sliderBar.offsetWidth) / this.max)
this.coverLen = len.toString()
}
}
handleEvent(event: TouchEvent) {
switch (event.type) {
case 'touchstart':
this.touchAction.start.clientX = event.touches[0].clientX
this.barWidth = this.sliderBar.offsetWidth
break
case 'touchmove':
this.touchAction.last.clientX = event.touches[0].clientX
this.distance =
this.touchAction.last.clientX - this.touchAction.start.clientX
this.currentDistance = this.distance + this.progress.offsetWidth
if (this.currentDistance < 0) {
// this.currentDistance = 0;
this.currentDistance = this.barWidth / this.max
}
if (this.currentDistance > this.barWidth) {
this.currentDistance = this.barWidth
}
this.progress.style.setProperty('width', this.currentDistance + 'px')
break
case 'touchend':
this.value = Math.floor(
(this.currentDistance * this.max) / this.barWidth
)
this.dispatchEvent(
new CustomEvent('brightness-slider-change', {
detail: {
value: this.value,
},
bubbles: true,
composed: true,
})
)
break
}
}
setValue(value: number) {
this.value = value
let len = Math.floor((value * this.sliderBar.offsetWidth) / this.max)
this.coverLen = len.toString()
}
}
declare global {
interface HTMLElementTagNameMap {
'brightness-slider': BrightnessSlider
}
}

View File

@ -0,0 +1 @@
export * from './brightness-slider.js'

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/brightness-slider",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./brightness-slider.js": {
"default": "./brightness-slider.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -4,5 +4,5 @@
"composite": true, "composite": true,
"rootDir": "../../" "rootDir": "../../"
}, },
"include": ["../../../global.d.ts", "*.ts"] "include": ["*.ts"]
} }

View File

@ -1,93 +0,0 @@
# icon-item
用于显示下拉控件栏中的icon。
分为两类:
`IconType.BASE`类型:
须传入`icon`(用于图标内容)`bgchange`(用于点击图标时的样式变化)`bgchange`未传参时,默认图标点击时不改变图标背景
`IconType.WITH_STATE`类型:
须传入`icon`(用于图标内容)`stateDesc`(用于蓝牙、wifi状态显示)
可选参数`settingsKey`: 用于settingsObsever。
`IconType.BASE_WITHOUT_BORDER`类型:
须传入`icon`(用于图标内容),图标不带边框。
示例:
```html
<icon-item type=${IconType.WITH_STATE} icon="wifi-4" bgchange=true settingsKey="wifi.enabled" stateDesc=""></icon-item>
<icon-item type=${IconType.BASE} icon="crop"></icon-item>
<icon-item type=${IconType.BASE} icon="brightness" bgchange=true settingsKey="screen.automatic-brightness"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item>
```
# icons-online
对`icon-item`的进一步组合、封装。
分为两类:
`IconsOneLineType.BASE`类型:
需传入`count`,为所插入插槽元素的个数默认数值为4
需插入插槽元素显示为一个box框框内是由短竖线分隔开的基本图标。
`IconsOneLineType.WITH_STATE`类型:
需传入`count`,为所插入插槽元素的个数默认数值为2
需插入插槽元素,显示为一行带状态的图标。
示例:
```html
<icons-one-line type=${IconsOneLineType.WITH_STATE}>
<icon-item type=${IconType.WITH_STATE} icon="wifi-4" isActive=true settingsKey="wifi.enabled" stateDesc=""></icon-item>
<icon-item type=${IconType.WITH_STATE} icon="bluetooth" isActive=true settingsKey="bluetooth.enabled"></icon-item>
</icons-one-line>
<icons-one-line type=${IconsOneLineType.BASE} count=3>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="crop"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="video"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="camera"></icon-item>
</icons-one-line>
```
# header-bar
用于显示下拉控件栏、下拉通知栏最顶部的header。
分为两类:
`HeaderBarType.ONLY_TIME`类型:
header中显示时间和任意图标需插入插槽元素
`HeaderBarType.DATE_TIME`类型:
header中显示日期、星期、时间和任意图标需插入插槽元素
示例:
```html
<header-bar type=${HeaderBarType.ONLY_TIME}>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="compose"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item>
</header-bar>
<header-bar type=${HeaderBarType.DATE_TIME}>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item>
</header-bar>
```
# control-center
下拉控件栏组件。
包括`header-bar`和中间控件部分。中间控件部分由slot元素插入。
```html
<control-center>
<div class="brightness"></div>
<icon-item type=${IconType.BASE} icon="brightness"></icon-item>
</control-center>
```
# control-center-bar
`control-center`实例
说明: 因现有下拉栏顶部的状态栏是采用`background-image:-moz-element(#statusbar-icons)`方式获取,所以使用`slot`获取。
```html
<control-center-bar>
<div slot="status-bar"></div>
</control-center-bar>
```

View File

@ -1,926 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult } from 'lit'
import { customElement, property, query } from 'lit/decorators.js'
import { settingsObserver as settingsObserver} from "./mock_settings_observer";
import { IconsOneLine, IconsOneLineType } from './icons-one-line'
import { IconItem, IconType } from './icon-item';
import { PullDownMenuType } from './pull-down-menu';
import './icons-one-line';
import './icon-item';
import './pull-down-menu';
import './light-slider';
import "./gaia-container";
// import "../gaia_dialog/gaia-dialog-list.js";
// import WifiContext from "../../js/utils/origin/wifi/wifi_context.js";
import IconDB from "./icondb";
import { LightSlider } from './light-slider';
// import WifiNetworkList from "../../js/utils/origin/wifi/wifi_network_list.js";
// import WifiItem from "../../js/utils/origin/wifi/wifi_item.js";
// import BtTemplateFactory from '../../js/utils/origin/bluetooth/bt_template_factory.js';
// import ListView from '../../js/utils/origin/mvvm/list_view.js';
// import BtContext from '../../js/utils/origin/bluetooth/bluetooth_context.js';
// import BluetoothItem from "../../js/utils/origin/bluetooth/bluetooth_item.js";
const WIFIENABLED = "wifi.enabled";
// const BLUETOOTHENABLED = "bluetooth.enabled";
// const BRIGHTNESS = "screen.brightness";
// const AUTOBRIGHTNESS = "screen.automatic-brightness";
const GEOLOCATIONENABLED = "geolocation.enabled";
const WIFI_HOTSPOT = "tethering.wifi.enabled";
const LOCK_SCREEN_KEY = "screen.orientation.lock";
// const AUDIO_VOLUME_NOTIFICATION = "audio.volume.notification";
// const VIBRATEENABLED = "vibration.enabled";
// const WIFI_SSID_KEY = "tethering.wifi.ssid";
// const WIFI_SECURITY_KEY = "tethering.wifi.security.type";
// const WIFI_PASSWORD_KEY = "tethering.wifi.security.password";
let _debug = false;
_debug = true;
let debug = function (msg?: string | any) {
console.log(msg);
};
if (_debug) {
debug = function btp_debug(msg) {
console.log('--> [ControlCenter]: ' + msg);
};
}
@customElement('control-center-bar')
export class ControlCenterBar extends LitElement {
@query('gaia-container') icons!: any;
@query('gaia-dialog-list#wifi-list') wifiListDialog!: any;
@query('gaia-dialog-list#bluetooth-list') bluetoothListDialog!: any;
@query('icons-one-line[type="base"]') cameraPhoto!: IconsOneLine;
@query('icon-item[icon="bluetooth"]') bluetooth!: IconItem;
@query('icon-item[icon="wifi-4"]') wifi!: IconItem;
@query('icon-item[icon="brightness"]') autoBrightness!: IconItem;
@query('#screen-brightness') brightness!: LightSlider;
@property({type: IconDB}) icondb = new IconDB();
@property() settings = {
wifi: false,
airplaneMode: false,
data: false,
bluetooth: false,
wifihotspot: false,
geolocation: false,
screenLock: false,
brightness: 1,
autoBrightness: false,
};
@property({type: Number}) iconsLeft = 0;
@property({type: Number}) iconsRight = 0;
@property({type: Boolean}) airplaneModeSwitching = false;
@property({type: Number}) lastWindowWidth = window.innerWidth;
@property({type: Number}) lastWindowHeight = window.innerHeight;
@property() pairedDevicesListView = null;
@property({type: String}) iconOnlyElements = ["data", "airplane-mode", "geolocation", "wifi-hotspot", "dark-mode", "sound", "auto-rotate", "addons"];
@property({type: []}) startupOrder !: any[];
@property({type: Boolean}) draggable = false;
@property({type: Number}) minRange = 10; // 最小滑动距离
@property() touchAction = { // 触摸开始落点
start: {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0
},
last: { // 触摸结束落点
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0
}
}
@property({type: Number}) preVolumeValue = 1;
@property({type: IconItem}) wifiHotspot!: IconItem;
@property({type: IconItem}) autoRotate!: IconItem;
@property({type: IconItem}) sound!: IconItem;
@property({type: IconItem}) airplaneMode!: IconItem;
@property({type: IconItem}) data!: IconItem;
@property({type: IconItem}) geolocation!: IconItem;
@property({type: Number}) timer!: NodeJS.Timeout;
render(): HTMLTemplateResult {
console.log("dddd render");
return html`
<slot name="status-bar"></slot>
<pull-down-menu type=${PullDownMenuType.HEADER_WITH_TIME}>
<icons-one-line type=${IconsOneLineType.WITH_STATE}>
<icon-item type=${IconType.WITH_STATE} id="wifi" icon="wifi-4" bgchange=true settingsKey="wifi.enabled" stateDesc=""></icon-item>
<icon-item type=${IconType.WITH_STATE} id="bluetooth" icon="bluetooth" bgchange=true settingsKey="bluetooth.enabled"></icon-item>
</icons-one-line>
<div class="icon-section">
<gaia-container id="icon-only"></gaia-container>
</div>
<div class="brightness">
<light-slider id="screen-brightness"></light-slider>
<icon-item type=${IconType.BASE} icon="brightness" bgchange=true settingsKey="screen.automatic-brightness"></icon-item>
</div>
<icons-one-line type=${IconsOneLineType.BASE}>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="crop"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="video"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="camera"></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="o"></icon-item>
</icons-one-line>
<div class="button-wrapper">
<div id="toggle-button"></div>
</div>
<div class="media-player"></div>
<gaia-dialog-list id="wifi-list" hidden>
<h1>WLAN</h1>
<h2>WLAN列表</h2>
</gaia-dialog-list>
<gaia-dialog-list id="bluetooth-list" hidden>
<h1></h1>
<h2></h2>
</gaia-dialog-list>
</pull-down-menu>
`
}
static styles = css`
:host {
--background-color-lm: rgba(217, 217, 217, 0.65);
--background-color-dm: rgba(89, 89, 89, 0.68);
width: inherit;
height: inherit;
display: block;
background: var(--background-color-lm);
backdrop-filter: blur(120px);
transform: translateY(0);
transition: transform 300ms ease, visibility 300ms;
visibility: hidden;
}
:host([open]) {
visibility: visible;
}
::slotted(div) {
background-image: -moz-element(#statusbar-icons);
background-repeat: no-repeat;
width: 100%;
height: 3rem;
filter: none;
// background-position: 600px center;
background-position: right;
}
pull-down-menu {
// width: 100%;
// height: calc(100% - 3rem)
position; absolute;
top: 140px;
left: 628px;
width: 512px;
}
icons-one-line {
width: 512px;
height: 112px;
}
icons-one-line[type='with-state'] {
position: relative;
top: 40px;
}
.icon-section {
// width: inherit;
// height: 238px;
width: 540px;
height: 268px;
position: relative;
top: 72px;
left: -9px;
}
gaia-container {
width: 100%;
height: 100%;
display: flex;
flex-flow: row wrap;
align-content: flex-start;
box-sizing: padding-box;
}
.icon-container {
// height: 119px;
// width: 128px;
height: 134px;
width: 135px;
position: relative;
display: inline-block;
}
.icon-container > icon-item {
position: absolute;
top: 0;
left: 0;
transition: transform 0.2s, opacity 0.2s;
transform: translate(12px, 7.5px);
}
gaia-container:not(.loading) > .gaia-container-child:not(.added):not(.dragging) {
transition: transform 0.2s;
}
gaia-container > .gaia-container-child.dragging {
z-index: 1;
will-change: transform;
}
.brightness {
display: flex;
align-items: center;
justify-content: space-between;
position: relative;
// top: 104px;
top: 89px; //104-15
}
#screen-brightness {
width: 378px;
height: 104px;
}
icons-one-line[type='base'] {
position: relative;
top: 136px;
}
#toggle-button {
width: 88px;
height: 10px;
background: rgba(255, 255, 255, 0.35);
border-radius: 16px;
}
.media-player { // 占位隐藏
// width: inherit;
// height: 134px;
// position: relative;
// top: 200px;
// border: 1px solid white;
// height: 67px;
// top: 100px;
// border: 0.5px solid white;
}
.button-wrapper {
position: relative;
top: 168px;
display: flex;
justify-content: center;
}
:host([dark-mode]) {
width: inherit;
height: inherit;
display: block;
background: var(--background-color-dm);
backdrop-filter: blur(120px);
}
[disabled="true"] {
pointer-events: none;
opacity: 0.2;
}
`
firstUpdated() {
this.iconAdded().then(() => {
this.monitorWifiChange();
this.monitorTetheringStatusChange();
window.addEventListener("send-to-control-center", this.toggleActive.bind(this));
this.monitorAirplaneModeChange();
this.monitorBluetoothChange();
this.cameraPhoto.addEventListener("click", this.handleCamera.bind(this));
// ["click", "touchstart", "touchend", "drag-end",
["touch-start", "touchend", "drag-end",
"drag-rearrange", "drag-finish"].forEach(eventName => {
this.icons.addEventListener(eventName, this.handleContainerEvent.bind(this))
});
[this.wifiListDialog, this.bluetoothListDialog].forEach(dialog => {
dialog.addEventListener("more-settings", this.handleNavigate.bind(this));
});
window.addEventListener("touchstart", this.handleStart.bind(this));
window.addEventListener("touchmove", this.handleMove.bind(this));
window.addEventListener("editor-action", this.handleEditor.bind(this));
window.addEventListener("icon-item-click", this.handleIconButtonClick.bind(this));
window.addEventListener("more-info-action", this.showListDialog.bind(this));
});
}
iconAdded() {
return new Promise((resolve: (value: void) => void) => {
this.icondb.init().then(() => {
// return this.icondb.getAll((result: any) => {
// console.log("iconAdded icondb getAll ", result);
// if (result) {
// let id = result.id;
// this.startupOrder.push(id);
// this.iconOnlyElements = this.startupOrder;
// }
// return Promise.resolve();
// });
}).then(() => {
this.addIcon();
resolve();
});
});
}
toggleActive() {
if (this.autoBrightness.active == this.settings.autoBrightness) {
this.autoBrightness.activeOrInactive(!this.settings.autoBrightness);
}
if (this.geolocation.active == this.settings.geolocation) {
this.geolocation.activeOrInactive(!this.settings.geolocation);
}
if (this.wifiHotspot.active == this.settings.wifihotspot) {
this.wifiHotspot.activeOrInactive(!this.settings.wifihotspot);
}
if (this.autoRotate.active == this.settings.screenLock) {
this.autoRotate.activeOrInactive(!this.settings.screenLock);
}
if (this.brightness.value == this.settings.brightness) {
// this.brightness.value = this.settings.brightness;
this.brightness.setValue(this.settings.brightness);
}
}
monitorWifiChange() {
// WifiItem(this.wifiStatusText).enabled = true;
// WifiItem(this.wifi.stateDesc).enabled = true;
window.addEventListener("wifi-enabled", this.handleWifiChange.bind(this));
window.addEventListener("wifi-disabled", this.handleWifiChange.bind(this));
window.addEventListener("wifi-statuschange", this.handleWifiChange.bind(this));
}
monitorAirplaneModeChange() {
window.addEventListener("send-airplaneMode-status", (evt: any) => {
let value = evt.detail.value;
this.airplaneModeSwitching = false;
let target = this.airplaneMode; // 飞行模式element
switch (value) {
case "enabled":
this.setSettingEnabled("airplaneMode", true);
target.activeOrInactive(false); // addClass
this.wifiHotspot.setAttribute("disabled", "true"); // 飞行模式下禁用wifi热点和移动数据
this.data.setAttribute("disabled", "true");
if (this.data.active) {
this.data.activeOrInactive(true);
}
break;
case "disabled":
this.setSettingEnabled("airplaneMode", false);
target.activeOrInactive(true);// removeClass
this.wifiHotspot.removeAttribute("disabled");
this.data.removeAttribute("disabled");
if (!this.data.active) {
this.data.activeOrInactive(false);
}
break;
case "enabling":
this.airplaneModeSwitching = true;
break;
case "disabling":
this.airplaneModeSwitching = true;
break;
}
});
}
monitorBluetoothChange() {
window.addEventListener("bluetooth-enabled", this.handleBlueToothChange.bind(this));
window.addEventListener("bluetooth-disabled", this.handleBlueToothChange.bind(this));
}
monitorTetheringStatusChange() {
window.addEventListener("tethering-status-change", evt => {
settingsObserver.getValue(WIFIENABLED).then(wifiEnabled => {
if (!wifiEnabled && (evt as any).detail === 0) { // wifi打开状态下wifi热点打开再关闭, 应恢复wifi
settingsObserver.setValue([{name: WIFIENABLED, value: true }]);
}
});
});
}
setSettingEnabled(settingKey: string, enabled: any) {
(this.settings as any)[settingKey] = enabled;
}
onPairedDeviceItemClick(deviceItem: any) {
debug('onPairedDeviceItemClick(): deviceItem.address = ' +
deviceItem.address);
debug('onPairedDeviceItemClick(): deviceItem.paired = ' +
deviceItem.paired);
}
handleWifiChange(evt: Event) {
evt.preventDefault();
switch (evt.type) {
case "wifi-enabled":
// debug("handleWifiChange wifi-enabled!!");
this.setSettingEnabled("wifi", true);
this.wifi.activeOrInactive(false);
this.scan();
break;
case "wifi-disabled":
// debug("handleWifiChange wifi-disabled!!");
this.setSettingEnabled("wifi", false);
this.wifi.activeOrInactive(true);
/*
WifiItem(this.wifi.stateDesc).enabled = false;
*/
break;
case "wifi-statuschange":
// debug("handleWifiChange wifi-statuschange!!");
let scanStates = new Set(["connected", "connectingfailed", "disconnected"]);
if (scanStates.has((evt as any).detail.event.status)) {
this.scan();
}
break;
}
}
handleBlueToothChange(event: Event) {
// event.preventDefault();
switch (event.type) {
case "bluetooth-enabled":
this.setSettingEnabled("bluetooth", true);
this.bluetooth.activeOrInactive(false);
// let pairedDeviceTemplate =
// BtTemplateFactory("paired", this.onPairedDeviceItemClick.bind(this));
// this.pairedDevicesListView = ListView(this.bluetoothListDialog,
// BtContext.getPairedDevices(),
// pairedDeviceTemplate);
(this.pairedDevicesListView as any).enabled = true;
break;
case "bluetooth-disabled":
this.setSettingEnabled("bluetooth", false);
this.bluetooth.activeOrInactive(true);
if (this.pairedDevicesListView) {
(this.pairedDevicesListView as any).enabled = false;
}
break;
}
}
handleEditor() {
let dragAndDrop = this.icons.getAttribute("drag-and-drop");
this.icons.setAttribute("drag-and-drop", (!dragAndDrop).toString());
this.draggable = !dragAndDrop;
}
handleSettings() {
let activity = new WebActivity("configure", {});
activity.start().then(() => {}, () => {});
}
showListDialog(event: Event) {
let target = (event as any).detail;
switch (target) {
case "wifi-4":
this.wifiListDialog.open(event);
break;
case "bluetooth":
this.bluetoothListDialog.open(event);
break;
}
}
handleIconButtonClick(event: any) {
let target = event.detail.target;
console.log("handleIconButtonClick target: ", target);
console.log("handleIconButtonClick event.detail: ", event.detail);
let isContainer = target.parentElement?.parentElement?.parentElement?.id == "icon-only";
if (isContainer && this.draggable) {
return;
}
let isActive = event.detail.isActive;
let id = event.detail.id;
switch (id) {
case "wifi":
if (this.airplaneModeSwitching) {
return;
}
this.fireEvent(id, !isActive);
break;
case "bluetooth":
if (this.airplaneModeSwitching) {
return;
}
let enabled = this.settings.bluetooth;
var toggleb = enabled ?
"request-disable-bluetooth" :
"request-enable-bluetooth";
this.dispatchEvent(
new CustomEvent(toggleb, {
bubbles: true,
composed: true,
})
);
break;
case "screen-auto-brightness":
this.fireEvent(id, !isActive);
break;
case "airplane-mode":
if (this.airplaneModeSwitching) {
return;
}
var toggle = isActive ?
"request-airplane-mode-disable" :
"request-airplane-mode-enable";
this.dispatchEvent(
new CustomEvent(toggle, {
bubbles: true,
composed: true,
})
);
if (isActive) {
this.wifiHotspot.removeAttribute("disabled");
this.data.removeAttribute("disabled");
} else {
this.wifiHotspot.setAttribute("disabled", "true");
this.data.setAttribute("disabled", "true");
}
break;
case "geolocation":
this.fireEvent(id, !isActive);
break;
case "wifi-hotspot":
if (this.airplaneModeSwitching) {
return;
}
this.fireEvent(id, !isActive);
break;
case "dark-mode":
break;
case "sound":
if (this.sound.icon == "alarm") {
this.sound.icon = "mute";
this.fireEvent("mute", 0);
} else if (this.sound.icon == "mute") {
this.sound.icon = "alarm";
this.fireEvent("alarm", this.preVolumeValue);
}
break;
case "auto-rotate":
this.fireEvent(id, !isActive);
break;
}
}
handleIconButtonPress(event: any) {
let target = event.detail.target;
let isContainer = target.parentElement?.parentElement?.parentElement?.id == "icon-only";
if (isContainer && this.draggable) {
return;
}
if (target.className == "icon-container") {
target = target.children[0];
}
if (target.getAttribute("disabled") === "true") {
return;
}
this.close();
let section = target.id;
this.timer = setTimeout(() => {
let activity = new WebActivity("moz_configure_window", {
data: {
target: "device",
section: section
}
});
activity.start();
}, 800);
}
handleIconButtonPressEnd(event: any) {
let target = event.target;
let isContainer = target.parentElement?.parentElement?.parentElement?.id == "icon-only";
if (isContainer && this.draggable) {
return;
}
clearTimeout(this.timer);
}
handleNavigate(event: any) {
let section = event.target.id;
let activity = new WebActivity("moz_configure_window", {
data: {
target: "device",
section: section
}
});
activity.start();
}
handleCamera(event: any) {
let target = event.target.icon;
switch (target) {
case "crop":
this.dispatchEvent(
new CustomEvent("volumedown+sleep", {
bubbles: true,
composed: true,
})
);
this.close();
break;
case "video":
let takeVideo = new WebActivity("record", {
type: "videos"
});
takeVideo.start();
this.close();
break;
case "camera":
let takePhotos = new WebActivity("record", {
type: "photos"
});
takePhotos.start();
this.close();
break;
case "shut-down":
// powerManager.powerOff();
break;
}
}
handleContainerEvent(event: Event) {
switch (event.type) {
case "icon-item-click":
this.handleIconButtonClick(event);
break;
case "touch-start":
this.handleIconButtonPress(event);
break;
case "touchend":
this.handleIconButtonPressEnd(event);
break;
case "drag-end":
case "drag-rearrange":
case "drag-finish":
this.handleContainerDrag(event);
break;
}
}
handleContainerDrag(e: any) {
switch(e.type) {
// Activate drag-and-drop immediately for selected icons
case "touchstart":
this.icons.dragAndDropTimeout = 0;
break;
case "drag-finish":
debug("Drag-finish");
// Restore normal drag-and-drop after dragging selected icons
this.icons.dragAndDropTimeout = -1;
break;
// Handle icon editing and dragging to the end of the icon grid.
case "drag-end":
debug("Drag-end, target: " + (e.detail.dropTarget ?
e.detail.dropTarget.firstElementChild : "none"));//e.detail.target --> div.icon-container
if (e.detail.dropTarget === null &&
e.detail.clientX >= this.iconsLeft &&
e.detail.clientX < this.iconsRight) {
// If the drop target is null, and the client coordinates are
// within the panel, we must be dropping over the start or end of
// the container.
e.preventDefault();
let bottom = e.detail.clientY < this.lastWindowHeight / 2;
debug("Reordering dragged icon to " +
(bottom ? "bottom" : "top"));
this.icons.reorderChild(e.detail.target,
bottom ? this.icons.firstChild : null as any,
this.storeIconOrder.bind(this));
break;
}
break;
// Save the icon grid after rearrangement
case "drag-rearrange":
debug("Drag rearrange");
this.storeIconOrder();
break;
}
}
scan() {
// WifiNetworkList(this.wifiListDialog).scan();
}
clearList(enabled: boolean) {
console.log(enabled);
// WifiNetworkList(this.wifiListDialog).clear(enabled);
}
activeOrInactive(isActive: boolean, element: HTMLElement) {
if (element.id === "sound") {
element.classList.add("active");
return;
}
isActive ? element.classList.remove("active") :
element.classList.add("active");
}
addIcon() {
this.iconOnlyElements.forEach((icon) => {
let iconDiv = document.createElement("icon-item");
iconDiv.type = "base";
iconDiv.id = icon;
let key = null;
switch (icon) {
case "data":
iconDiv.icon = "data";
iconDiv.bgchange = true;
break;
case "airplane-mode":
iconDiv.icon = "airplane";
iconDiv.bgchange = true;
break;
case "geolocation":
key = GEOLOCATIONENABLED;
iconDiv.icon = "location";
iconDiv.bgchange = true;
break;
case "wifi-hotspot":
key = WIFI_HOTSPOT;
iconDiv.icon = "tethering";
iconDiv.bgchange = true;
break;
case "dark-mode":
iconDiv.icon = "themes";
iconDiv.bgchange = true;
break;
case "auto-rotate":
key = LOCK_SCREEN_KEY;
iconDiv.icon = "sync";
iconDiv.bgchange = true;
break;
case "sound":
iconDiv.icon = "alarm";
iconDiv.id = "sound";
iconDiv.bgchange = true;
break;
// 填充 无意义
case "addons":
iconDiv.icon = "addons";
iconDiv.id = "addons";
iconDiv.bgchange = true;
break;
}
if (key) {
iconDiv.settingsKey = key;
}
// iconDiv.id = icon;
// iconDiv.setAttribute("id", icon);
(this as any)[this.toCamelCase(iconDiv.id)] = iconDiv;
this.addIconContainer(iconDiv);
});
}
addIconContainer(iconDiv: IconItem) {
let container = document.createElement("div") as HTMLElement;
container.classList.add("icon-container");
(container as any).order = -1;
container.appendChild(iconDiv);
if (!container.parentNode) {
this.icons.appendChild(container);
this.refreshGridSize();
}
}
refreshGridSize() {
let children = this.icons.children;
let visibleChildren = 0;
let cols = 4;
let firstVisibleChild = -1;
for (let i = 0, iLen = children.length; i < iLen; i++) {
// if ((children[i] as HTMLElement).style.display !== "none") {
visibleChildren ++;
if (firstVisibleChild === -1) {
firstVisibleChild = i;
this.iconsLeft = this.icons.getChildOffsetRect((children[i]) as HTMLElement).left;
} else if (visibleChildren === cols) {
this.iconsRight = this.icons.getChildOffsetRect(children[i] as HTMLElement).right;
}
// }
}
}
toCamelCase(str: string) {
return str.replace(/\-(.)/g, function replacer(str, p1) {
console.log(str);
return p1.toUpperCase();
});
}
storeIconOrder() {
let storedOrders = [];
let children = this.icons.children;
for (let i = 0, iLen = children.length; i < iLen; i++) {
let icon = children[i].firstElementChild as Element;
storedOrders.push({ id: icon.id, order: i });
}
this.icondb.set(storedOrders).then(
() => {},
(e) => {
console.error("Error storing icon order", e);
});
}
handleStart(event: TouchEvent) {
this.touchAction.start.pageX = event.touches[0].pageX;
this.touchAction.start.pageY = event.touches[0].pageY;
}
handleMove(event: TouchEvent) {
this.touchAction.last.pageX = event.touches[0].pageX;
this.touchAction.last.pageY = event.touches[0].pageY;
let distanceY = this.touchAction.last.pageY - this.touchAction.start.pageY;
if (this.touchAction.start.pageY > 0 &&
this.touchAction.start.pageY < this.minRange &&
this.touchAction.start.pageX > window.screen.width / 2
&& distanceY >= this.minRange) {
this.open();
}
if (this.touchAction.start.pageY > window.screen.height - this.minRange
&& this.touchAction.start.pageY <= window.screen.height) {
this.close();
}
}
open() {
let isOpen = this.getAttribute("open");
if (isOpen !== "") {
this.setAttribute("open", "");
}
}
close() {
let isOpen = this.getAttribute("open");
if (isOpen == "") {
this.removeAttribute("open");
}
}
fireEvent(name: string, value: string | boolean | number) {
this.dispatchEvent(
new CustomEvent("control-center-dispatched", {
detail: {
name,
value
},
bubbles: true,
composed: true,
})
)
}
}
declare global {
interface HTMLElementTagNameMap {
'control-center-bar': ControlCenterBar
}
}

View File

@ -1,103 +0,0 @@
export default class GaiaContainerChild {
constructor(element) {
this._element = element;
this.markDirty();
}
get element() {
return this._element;
}
/**
* The element that will contain the child element and control its position.
*/
get container() {
if (!this._container) {
// Create container
let container = document.createElement("div");
container.classList.add("gaia-container-child");
container.style.position = "absolute";
container.style.top = "0";
container.style.left = "0";
container.appendChild(this.element);//this.element是div.icon-container
this._container = container;
}
return this._container;
}
/**
* The element that will be added to the container that will
* control the element's transform.
*/
get master() {
if (!this._master) {
// Create master
let master = document.createElement("div");
master.style.visibility = "hidden";
this._master = master;
}
return this._master;
}
/**
* Clears any cached style properties. To be used if elements are
* manipulated outside of the methods of this object.
*/
markDirty() {
this._lastElementWidth = null;
this._lastElementHeight = null;
this._lastElementDisplay = null;
this._lastElementOrder = null;
this._lastMasterTop = null;
this._lastMasterLeft = null;
}
/**
* Synchronise the size of the master with the managed child element.
*/
synchroniseMaster() {
let master = this.master;
let element = this.element;
let style = window.getComputedStyle(element);
let display = style.display;
let order = style.order;
let width = element.offsetWidth;
let height = element.offsetHeight;
if (this._lastElementWidth !== width ||
this._lastElementHeight !== height ||
this._lastElementDisplay !== display ||
this._lastElementOrder !== order) {
this._lastElementWidth = width;
this._lastElementHeight = height;
this._lastElementDisplay = display;
this._lastElementOrder = order;
master.style.width = width + "px";
master.style.height = height + "px";
master.style.display = display;
master.style.order = order;
}
}
/**
* Synchronise the container's transform with the position of the master.
*/
synchroniseContainer() {
let master = this.master;
let container = this.container;
let top = master.offsetTop;
let left = master.offsetLeft;
if (this._lastMasterTop !== top ||
this._lastMasterLeft !== left) {
this._lastMasterTop = top;
this._lastMasterLeft = left;
container.style.transform = "translate(" + left + "px, " + top + "px)";
}
}
}

View File

@ -1,789 +0,0 @@
import GaiaContainerChild from "./gaia-container-child.js";
/**
* The time, in ms, to wait for an animation to start in response to a state
* change, before removing the associated style class.
*/
const STATE_CHANGE_TIMEOUT = 100;
/**
* The time, in ms, to wait before initiating a drag-and-drop from a
* long-press.
*/
const DEFAULT_DND_TIMEOUT = 300;
/**
* The distance, in CSS pixels, in which a touch or mouse point can deviate
* before it being discarded for initiation of a drag-and-drop action.
*/
const DND_THRESHOLD = 5;
/**
* The minimum time between sending move events during drag-and-drop.
*/
const DND_MOVE_THROTTLE = 50;
class GaiaContainer extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this.shadowRoot.innerHTML = this.template;
}
connectedCallback() {
this._frozen = false;
this._pendingStateChanges = [];
this._children = [];
this._dnd = {
// Whether drag-and-drop is enabled
enabled: false,
// The time, in ms, to wait before initiating a drag-and-drop from a
// long-press
delay: DEFAULT_DND_TIMEOUT,
// Timeout used to initiate drag-and-drop actions
timeout: null,
// The child that was tapped/clicked
child: null,
// Whether a drag is active
active: false,
// The start point of the drag action
start: {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0
},
// The last point of the drag action
last: {
pageX: 0,
pageY: 0,
clientX: 0,
clientY: 0,
timeStamp: 0
},
// Timeout used to send drag-move events
moveTimeout: null,
// The last time a move event was fired
lastMoveEventTime: 0,
// Whether to capture the next click event
clickCapture: false,
};
let dndObserverCallback = (mutations) => {
if (this._dnd.enabled !== this.dragAndDrop) {
this._dnd.enabled = this.dragAndDrop;
if (this._dnd.enabled) {
this.addEventListener("touchstart", this);
this.addEventListener("touchmove", this);
this.addEventListener("touchcancel", this);
this.addEventListener("touchend", this);
this.addEventListener("mousedown", this);
this.addEventListener("mousemove", this);
this.addEventListener("mouseup", this);
this.addEventListener("click", this, true);
this.addEventListener("contextmenu", this, true);
} else {
this.cancelDrag();
this.removeEventListener("touchstart", this);
this.removeEventListener("touchmove", this);
this.removeEventListener("touchcancel", this);
this.removeEventListener("touchend", this);
this.removeEventListener("mousedown", this);
this.removeEventListener("mousemove", this);
this.removeEventListener("mouseup", this);
this.removeEventListener("click", this, true);
this.removeEventListener("contextmenu", this, true);
}
}
};
this.dndObserver = new MutationObserver(dndObserverCallback);
this.dndObserver.observe(this, {
attributes: true,
attributeFilter: ["drag-and-drop"]
});
dndObserverCallback(null);
}
get children() { //div.icon-container
return this._children.map((child) => {
return child.element;
});
}
get firstChild() {
return this._children.length ?
this._children[0].element :
null;
}
get lastChild() {
const length = this._children.length;
return (length ?
this._children[length - 1].element :
null);
}
get dragAndDrop() {
return (this.getAttribute("drag-and-drop") !== null);
}
get dragAndDropTimeout() {
return this._dnd.delay;
}
set dragAndDropTimeout(timeout) {
if (timeout >= 0) {
this._dnd.delay = timeout;
} else {
this._dnd.delay = DEFAULT_DND_TIMEOUT;
}
}
realAppendChild() {
let proto = HTMLElement.prototype.appendChild;
let func = proto.apply(this, arguments);
return func;
}
realRemoveChild() {
let proto = HTMLElement.prototype.removeChild;
let func = proto.apply(this, arguments);
return func;
}
realInsertBefore() {
let proto = HTMLElement.prototype.insertBefore;
let func = proto.apply(this, arguments);
return func;
}
realReplaceChild() {
let proto = HTMLElement.prototype.replaceChild;
let func = proto.apply(this, arguments);
return func;
}
appendChild(element, callback) {
this.insertBefore(element, null, callback);
}
removeChild(element, callback) {
let children = this._children;
let childToRemove = null;
for (let child of children) {
if (child.element === element) {
childToRemove = child;
break;
}
}
if (childToRemove === null) {
throw "removeChild called on unknown child";
}
let that = this;
this.changeState(childToRemove, "removed", () => {
that.realRemoveChild(childToRemove.container);
that.realRemoveChild(childToRemove.master);
// Find the child again. We need to do this in case the container was
// manipulated between removing the child and this callback being reached.
for (let i = 0, iLen = children.length; i < iLen; i++) {
if (children[i] === childToRemove) {
children.splice(i, 1);
break;
}
}
if (callback) {
callback();
}
this.synchronise();
});
}
replaceChild(newElement, oldElement, callback) {
if (!newElement || !oldElement) {
throw "replaceChild called with null arguments";
}
// Unparent the newElement if necessary (with support for gaia-container)
if (newElement.parentNode) {
newElement.parentNode.removeChild(newElement, () => {
this.replaceChild(newElement, oldElement, callback);
});
if (newElement.parentNode) {
return;
}
}
// Remove the old child and add the new one, but don't run the removed/
// added state changes.
let children = this._children;
for (let i = 0, iLen = children.length; i < iLen; i++) {
let oldChild = children[i];
if (oldChild.element === oldElement) {
let newChild = new GaiaContainerChild(newElement);
this.realInsertBefore(newChild.container, oldChild.container);
this.realInsertBefore(newChild.master, oldChild.master);
this.realRemoveChild(oldChild.container);
this.realRemoveChild(oldChild.master);
this.children.splice(i, 1, newChild);
this.synchronise();
if (callback) {
callback();
}
return;
}
}
throw "removeChild called on unknown child";
}
/**
* Reorders the given element to appear before referenceElement.
*/
reorderChild(element, referenceElement, callback) {
if (!element) {
throw "reorderChild called with null element";
}
let children = this._children;
let child = null;
let childIndex = null;
let referenceChild = null;
let referenceChildIndex = null;
for (let i = 0, iLen = children.length; i < iLen; i++) {
if (children[i].element === element) {
child = children[i];
childIndex = i;
} else if (children[i].element === referenceElement) {
referenceChild = children[i];
referenceChildIndex = i;
}
if (child && (referenceChild || !referenceElement)) {
this.realRemoveChild(child.container);
this.realRemoveChild(child.master);
children.splice(childIndex, 1);
if (referenceChild) {
this.realInsertBefore(child.container, referenceChild.container);
this.realInsertBefore(child.master, referenceChild.master);
} else {
(children.length === 0) ?
this.realAppendChild(child.container):
this.realInsertBefore(child.container, children[0].master);
this.realAppendChild(child.master);
}
referenceChild ?
children.splice(
referenceChildIndex - (childIndex < referenceChildIndex) ? 1 : 0,
0, child) :
children.splice(children.length, 0, child);
this.synchronise();
if (callback) {
callback();
}
return;
}
}
throw child ? "reorderChild called on unknown reference element" :
"reorderChild called on unknown child";
}
insertBefore(element, reference, callback) {
let children = this._children;
let childToInsert = new GaiaContainerChild(element);
// console.log("childToInsert: ",childToInsert);// gaia-container-child
// console.log("children: ", children);//包括gaia-container-child 、icon-container等
let referenceIndex = -1;
if (reference !== null) {
for (let i = 0, iLen = children.length; i < iLen; i++) {
if (children[i].element === reference) {
referenceIndex = i;
break;
}
}
if (referenceIndex === -1) {
throw "insertBefore called on unknown child";
}
}
if (referenceIndex === -1) {
(children.length === 0) ?
this.realAppendChild(childToInsert.container):
this.realInsertBefore(childToInsert.container, children[0].master);
this.realAppendChild(childToInsert.master);
children.push(childToInsert);
} else {
this.realInsertBefore(childToInsert.container,
children[referenceIndex].container);
this.realInsertBefore(childToInsert.master,
children[referenceIndex].master);
children.splice(referenceIndex, 0, childToInsert);
}
this.changeState(childToInsert, "added", callback);
this.synchronise();
}
/**
* Used to execute a state-change of a child that may possibly be animated.
* @state will be added to the child's class-list. If an animation starts that
* has the same name, that animation will complete and @callback will be
* called. Otherwise, the class will be removed and @callback called on the
* next frame.
*/
changeState(child, state, callback) {
// Check that the child is still attached to this parent (can happen if
// the child is removed while frozen).
if (child.container.parentNode !== this) {
return;
}
// Check for a redundant state change.
if (child.container.classList.contains(state)) {
return;
}
// Queue up state change if we're frozen.
if (this._frozen) {
this._pendingStateChanges.push(
this.changeState.bind(this, child, state, callback));
return;
}
let animStart = (e) => {
if (!e.animationName.endsWith(state)) {
return;
}
child.container.removeEventListener("animationstart", animStart);
window.clearTimeout(child[state]);
delete child[state];
let self = this;
child.container.addEventListener("animationend", function animEnd() {
child.container.removeEventListener("animationend", animEnd);
child.container.classList.remove(state);
if (callback) {
callback();
}
});
};
child.container.addEventListener("animationstart", animStart);
child.container.classList.add(state);
child[state] = window.setTimeout(() => {
delete child[state];
child.container.removeEventListener("animationstart", animStart);
child.container.classList.remove(state);
if (callback) {
callback();
}
}, STATE_CHANGE_TIMEOUT);
}
getChildOffsetRect(element) {
let children = this._children;
for (let i = 0, iLen = children.length; i < iLen; i++) {
let child = children[i];
if (child.element === element) {
let top = child._lastMasterTop;
let left = child._lastMasterLeft;
let width = child._lastElementWidth;
let height = child._lastElementHeight;
return {
top: top,
left: left,
width: width,
height: height,
right: left + width,
bottom: top + height
};
}
}
throw "getChildOffsetRect called on unknown child";
}
getChildFromPoint(x, y) {
let children = this._children;
for (let parent = this.parentElement; parent; parent = parent.parentElement) {
x += parent.scrollLeft - parent.offsetLeft;
y += parent.scrollTop - parent.offsetTop;
}
for (let i = 0, iLen = children.length; i < iLen; i++) {
let child = children[i];
if (x >= child._lastMasterLeft &&
y >= child._lastMasterTop &&
x < child._lastMasterLeft + child._lastElementWidth &&
y < child._lastMasterTop + child._lastElementHeight) {
return child.element;
}
}
return null;
}
cancelDrag() {
if (this._dnd.timeout !== null) {
clearTimeout(this._dnd.timeout);
this._dnd.timeout = null;
}
if (this._dnd.moveTimeout !== null) {
clearTimeout(this._dnd.moveTimeout);
this._dnd.moveTimeout = null;
}
if (this._dnd.active) {
this._dnd.child.container.classList.remove("dragging");
this._dnd.child.container.style.position = "absolute";
this._dnd.child.container.style.top = "0";
this._dnd.child.container.style.left = "0";
this._dnd.child.markDirty();
this._dnd.child = null;
this._dnd.active = false;
this.synchronise();
this._dnd.clickCapture = true;
this.dispatchEvent(new CustomEvent("drag-finish"));
}
}
startDrag() {
if (!this.dispatchEvent(new CustomEvent("drag-start", {
cancelable: true,
detail: {
target: this._dnd.child.element,
pageX: this._dnd.start.pageX,
pageY: this._dnd.start.pageY,
clientX: this._dnd.start.clientX,
clientY: this._dnd.start.clientY
}
}))) {
return;
}
this._dnd.active = true;
this._dnd.child.container.classList.add("dragging");
this._dnd.child.container.style.position = "fixed";
let rect = this.getBoundingClientRect();
this._dnd.child.container.style.top = rect.top + "px";
this._dnd.child.container.style.left = rect.left + "px";
}
continueDrag() {
if (!this._dnd.active) {
return;
}
let left = this._dnd.child.master.offsetLeft +
(this._dnd.last.pageX - this._dnd.start.pageX);
let top = this._dnd.child.master.offsetTop +
(this._dnd.last.pageY - this._dnd.start.pageY);
this._dnd.child.container.style.transform =
"translate(" + left + "px, " + top + "px)";
if (this._dnd.moveTimeout === null) {
let delay = Math.max(0, DND_MOVE_THROTTLE -
(this._dnd.last.timeStamp - this._dnd.lastMoveEventTime));
this._dnd.moveTimeout = setTimeout(() => {
this._dnd.moveTimeout = null;
this._dnd.lastMoveEventTime = this._dnd.last.timeStamp;
this.dispatchEvent(new CustomEvent("drag-move", {
detail: {
target: this._dnd.child.element,
pageX: this._dnd.last.pageX,
pageY: this._dnd.last.pageY,
clientX: this._dnd.last.clientX,
clientY: this._dnd.last.clientY
}
}));
}, delay);
}
}
endDrag(event) {
if (this._dnd.active) {
let dropTarget = this.getChildFromPoint(this._dnd.last.clientX,
this._dnd.last.clientY);
if (this.dispatchEvent(new CustomEvent("drag-end", {
cancelable: true,
detail: {
target: this._dnd.child.element,
dropTarget: dropTarget,
pageX: this._dnd.last.pageX,
pageY: this._dnd.last.pageY,
clientX: this._dnd.last.clientX,
clientY: this._dnd.last.clientY
}
}))) {
let children = this._children;
if (dropTarget && dropTarget !== this._dnd.child.element) {
let dropChild = null;
let dropIndex = -1;
let childIndex = -1;
let insertBefore = true;
for (let i = 0, iLen = children.length; i < iLen; i++) {
if (children[i] === this._dnd.child) {
childIndex = i;
if (!dropChild) {
insertBefore = false;
}
}
if (children[i].element === dropTarget) {
dropChild = children[i];
dropIndex = i;
}
if (dropIndex >= 0 && childIndex >= 0) {
break;
}
}
if (dropIndex >= 0 && childIndex >= 0) {
// Default action, rearrange the dragged child to before or after
// the child underneath the touch/mouse point.
this.realRemoveChild(this._dnd.child.container);
this.realRemoveChild(this._dnd.child.master);
this.realInsertBefore(this._dnd.child.container,
insertBefore ? dropChild.container :
dropChild.container.nextSibling);
this.realInsertBefore(this._dnd.child.master,
insertBefore ? dropChild.master :
dropChild.master.nextSibling);
children.splice(dropIndex, 0,
children.splice(childIndex, 1)[0]);
this.dispatchEvent(new CustomEvent("drag-rearrange"));
}
}
}
} else if (this._dnd.timeout !== null) {
let handled = !this.dispatchEvent(new CustomEvent("activate", {
cancelable: true,
detail: {
target: this._dnd.child.element
}
}));
if (handled) {
event.stopImmediatePropagation();
event.preventDefault();
}
}
this.cancelDrag();
}
handleEvent(event) {
switch (event.type) {
case "touchstart":
case "mousedown":
if (this._dnd.active || this._dnd.timeout) {
this.cancelDrag();
break;
}
if (event instanceof MouseEvent) {
this._dnd.start.pageX = event.pageX;
this._dnd.start.pageY = event.pageY;
this._dnd.start.clientX = event.clientX;
this._dnd.start.clientY = event.clientY;
// this._dnd.start.clientX = event.pageX;
// this._dnd.start.clientY = event.pageY;
} else {
this._dnd.start.pageX = event.touches[0].pageX;
this._dnd.start.pageY = event.touches[0].pageY;
this._dnd.start.clientX = event.touches[0].clientX;
this._dnd.start.clientY = event.touches[0].clientY;
}
this._dnd.last.pageX = this._dnd.start.pageX;
this._dnd.last.pageY = this._dnd.start.pageY;
this._dnd.last.clientX = this._dnd.start.clientX;
this._dnd.last.clientY = this._dnd.start.clientY;
this._dnd.last.timeStamp = event.timeStamp;
let target = event.target;//gaia-app-icon
for (; target.parentNode !== this; target = target.parentNode) {
if (target === this || !target.parentNode) {
return;
}
}
// Find the child
let children = this._children;
for (let child of children) {
if (child.container === target) {
this._dnd.child = child;
break;
}
}
if (!this._dnd.child) {
return;
}
if (this._dnd.delay > 0) {
this._dnd.timeout = setTimeout(() => {
this._dnd.timeout = null;
this.startDrag();
}, this._dnd.delay);
} else {
this.startDrag();
}
break;
case "touchmove":
case "mousemove":
let pageX, pageY, clientX, clientY;
if (event instanceof MouseEvent) {
pageX = event.pageX;
pageY = event.pageY;
clientX = event.clientX;
clientY = event.clientY;
} else {
pageX = event.touches[0].pageX;
pageY = event.touches[0].pageY;
clientX = event.touches[0].clientX;
clientY = event.touches[0].clientY;
}
if (this._dnd.timeout) {
if (Math.abs(pageX - this._dnd.start.pageX) > DND_THRESHOLD ||
Math.abs(pageY - this._dnd.start.pageY) > DND_THRESHOLD) {
clearTimeout(this._dnd.timeout);
this._dnd.timeout = null;
}
} else if (this._dnd.active) {
event.preventDefault();
this._dnd.last.pageX = pageX;
this._dnd.last.pageY = pageY;
this._dnd.last.clientX = clientX;
this._dnd.last.clientY = clientY;
this._dnd.last.timeStamp = event.timeStamp;
this.continueDrag();
}
break;
case "touchcancel":
this.cancelDrag();
break;
case "touchend":
case "mouseup":
if (this._dnd.active) {
event.preventDefault();
event.stopImmediatePropagation();
}
this.endDrag(event);
break;
case "click":
if (this._dnd.clickCapture) {
this._dnd.clickCapture = false;
event.preventDefault();
event.stopImmediatePropagation();
}
break;
case "contextmenu":
if (this._dnd.active || this._dnd.timeout) {
event.stopImmediatePropagation();
// event.preventDefault();
}
break;
}
}
/**
* Temporarily disables element position synchronisation. Useful when adding
* multiple elements to the container at the same time, or in quick
* succession.
*/
freeze() {
this._frozen = true;
}
/**
* Enables element position synchronisation after freeze() has been called.
*/
thaw() {
if (this._frozen) {
this._frozen = false;
for (let callback of this._pendingStateChanges) {
callback();
}
this._pendingStateChanges = [];
this.synchronise();
}
}
/**
* Synchronise positions between the managed container and all children.
* This is called automatically when adding/inserting or removing children,
* but must be called manually if the managed container is manipulated
* outside of these methods (for example, if style properties change, or
* if it's resized).
*/
synchronise() {
if (this._frozen) {
return;
}
let child;
for (child of this._children) {
if (!this._dnd.active || child !== this._dnd.child) {
child.synchroniseMaster();
}
}
for (child of this._children) {
if (!this._dnd.active || child !== this._dnd.child) {
child.synchroniseContainer();
}
}
}
shadowStyle = `
:host {
position: relative;
display: block;
}
`
template = `
<slot></slot>
<style>${this.shadowStyle}</style>
`
}
customElements.define("gaia-container", GaiaContainer);

View File

@ -1,289 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult, nothing } from 'lit'
import { customElement, property, query, state } from 'lit/decorators.js'
export enum HeaderBarType {
ONLY_TIME = 'only-time',
DATE_TIME = 'date-time'
}
@customElement('header-bar')
export class HeaderBar extends LitElement {
@state() updateTimeTimeout!: number;
@state() updateDateTimeout!: number;
@property({type: HeaderBarType}) type = '';
@query('#time') time!: HTMLDivElement;
@query('#date') date!: HTMLDivElement;
getTime(): HTMLTemplateResult {
return html`
<div class="time-outer">
<div id="time"></div>
<div class="time-icons">
<slot></slot>
</div>
</div>
`;
}
getTimeAndDate(): HTMLTemplateResult {
return html`
<div class="time-date-outer">
<div class="time-date">
<div id="time"></div>
<div id="date"></div>
</div>
<div class="time-date-icons">
<slot></slot>
</div>
</div>
`;
}
render() {
switch (this.type) {
case HeaderBarType.ONLY_TIME:
return this.getTime();
case HeaderBarType.DATE_TIME:
return this.getTimeAndDate();
default:
console.error('unhandled 【header-bar】 type');
return nothing;
}
}
static styles = css`
:host {
--only-time-color-lm: #292929;
--only-time-color-dm: #F0F0F0;
--time-date-time-color-lm: #404040;
--time-date-date-color-lm: #000000;
--time-date-time-color-dm: #E0E0E0;
--time-date-date-color-dm: #E0E0E0;
width: inherit;
height: inherit
}
.time-outer {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.time-outer > #time {
height: 52px;
line-height: 52px;
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
font-size: 52px;
color: var(--only-time-color-lm);
}
.time-icons {
display: flex;
width: 136px;
position: relative;
right: 4px;
}
.time-icons > ::slotted(*) {
display: flex;
}
.time-icons > ::slotted(:last-child) {
position: relative;
left: 40px;
}
.time-date-outer {
width: 100%;
height: 100%;
display: flex;
align-items: end;
}
.time-date {
height: 100%;
width: 100%;
display: flex;
align-items: end;
line-height: 64px;
vertical-align: middle;
font-family: 'OPPOSans';
font-style: normal;
font-weight: 400;
position: relative;
left: 10px;
}
.time-date > #time {
color: var(--time-date-time-color-lm);
font-size: 64px;
}
#date {
height: 34px;
line-height: 34px;
position: relative;
left: 22px;
font-size: 26px;
opacity: 0.6;
color: var(--time-date-date-color-lm);
mix-blend-mode: normal;
}
.time-date-icons {
position: relative;
right: 11px;
}
.host([deep-mode]) .time-outer > #time {
height: 52px;
line-height: 52px;
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
font-size: 52px;
color: var(--only-time-color-dm);
}
.host([deep-mode]) .time-date > #time {
color: var(--time-date-time-color-dm);
font-size: 64px;
}
.host([deep-mode]) #date {
height: 34px;
line-height: 34px;
position: relative;
left: 22px;
font-size: 26px;
opacity: 0.6;
color: var(--time-date-date-color-dm);
mix-blend-mode: normal;
}
`
firstUpdated() {
this.autoUpdateDateTime();
}
autoUpdateDateTime() {
switch (this.type) {
case HeaderBarType.ONLY_TIME:
window.clearTimeout(this.updateTimeTimeout);
this.autoUpdateTime();
break;
case HeaderBarType.DATE_TIME:
window.clearTimeout(this.updateDateTimeout);
window.clearTimeout(this.updateTimeTimeout);
this.autoUpdateDate();
this.autoUpdateTime();
break;
}
}
autoUpdateTime() {
var d = new Date();
this.time.innerHTML = this.formatTime(d);
let self = this;
var remainMillisecond = (60 - d.getSeconds()) * 1000;
this.updateTimeTimeout = window.setTimeout(() => {
self.autoUpdateTime();
}, remainMillisecond);
}
autoUpdateDate() {
var d = new Date();
this.date.innerHTML = this.formatDate(d) + " " + this.getWeekDay();
let remainMillisecond = (24 - d.getHours()) * 3600 * 1000 -
d.getMinutes() * 60 * 1000 - d.getMilliseconds();
let self = this;
this.updateDateTimeout = window.setTimeout(
function updateDateTimeout() {
self.autoUpdateDate();
}, remainMillisecond);
}
getWeekDay() {
var d = new Date();
let daynumber = d.getDay();
let day = "";
switch (daynumber) {
case 0:
day = "周日";
break;
case 1:
day = "周一";
break;
case 2:
day = "周二";
break;
case 3:
day = "周三";
break;
case 4:
day = "周四";
break;
case 5:
day = "周五";
break;
case 6:
day = "周六";
break;
}
return day;
}
formatDate(d: Date | string, iso?: boolean) {
if (d instanceof Date) {
if (iso) {
let date = d.toISOString(); // Thu Oct 07 2021 07:45:18 GMT+0800
date = date.split("T")[0];
return date;
} else {
return d.toLocaleString(navigator.languages as string[], {
// year: 'numeric',
month: 'long',
day: '2-digit',
});
}
} else {
return d;
}
}
formatTime(d: Date | string, iso?: boolean) {
if (d instanceof Date) {
if (iso) {
let time = d.toLocaleTimeString();
time = time.split(" ")[0];
if (time.indexOf(":") === 1) {
time = `0${time}`;
}
return time;
} else {
return d.toLocaleString(navigator.languages as string[], {
// hour12: (navigator as any).mozHour12,
hour12: false,
hour: "numeric",
minute: "numeric",
});
}
} else {
if (d.indexOf(":") == 1) {
d = "0" + d;
}
return d;
}
}
}
declare global {
interface HTMLElementTagNameMap {
'header-bar': HeaderBar
}
}

View File

@ -1,318 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult, nothing } from 'lit'
import { customElement, property, eventOptions, query, state } from 'lit/decorators.js'
export enum IconType {
BASE = 'base',
BASE_WITHOUT_BORDER = 'base-without-border',
WITH_STATE = 'with-state'
}
@customElement('icon-item')
export class IconItem extends LitElement {
@property({type: IconType}) type = '';
@property({type: String}) icon = '';
@property({type: String}) stateDesc = '';
@property({type: String}) settingsKey = '';
@property({type: Boolean}) bgchange = false;
@property({type: String}) id = '';
@property({type: Boolean}) active = false;
@state({}) timer!: NodeJS.Timeout;
@query('.more-info-icon') moreInfoIcon!: HTMLDivElement;
@query('.icon-button') iconBtn!: HTMLDivElement;
getbase(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-item】缺少 icon 参数');
return nothing;
}
const iconstyle = html`
<style>
:host {
width: 104px;
height: 104px;
}
</style>
`;
return html `
<div class="icon-button icon-base with-border" data-icon=${this.icon} @click=${this.handleClick} @touchstart=${this.handlePress} @touchend=${this.handlePressEnd}>
${iconstyle}
</div>
`;
}
getbaseWithOutBorder(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-item】缺少 icon 参数');
return nothing;
}
return html `
<div class="icon-button icon-base without-border" data-icon=${this.icon} @click=${this.handleClick} @touchstart=${this.handlePress} @touchend=${this.handlePressEnd}>
</div>
`;
}
getwithstate(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-item】缺少 icon 参数');
return nothing;
}
const iconstyle = html`
<style>
:host {
width: 240px;
height: 108px;
}
</style>
`;
return html`
<div class="icon-button icon-with-state with-border config-activity" data-icon=${this.icon} @click=${this.handleClick} @touchstart=${this.handlePress} @touchend=${this.handlePressEnd}>
<p>${this.stateDesc}</p>
<div class="more-info-icon" @click=${this.handleInfo} data-icon="expand-left"></div>
${iconstyle}
</div>
`;
}
@eventOptions({passive: false})
handleClick(event: Event) {
let isActive = true; // 闹铃
if (this.bgchange) {
let target = event.target as HTMLElement;
if (target.nodeName == "P") {
target = target.parentElement as HTMLElement;
}
if (target.className == "more-info-icon") {
target = target.parentElement as HTMLElement;
}
isActive = target.classList.contains("active");
this.activeOrInactive(isActive, target);
}
// if (this.type == IconType.WITH_STATE) {
// if (target.className == "more-info-icon") {
// target = target.parentElement as HTMLElement;
// }
// if (target.classList.contains("active")) {
// this.moreInfoIcon.dataset.icon = "expand-left";
// } else {
// this.moreInfoIcon.dataset.icon = "";
// }
// }
let self = this;
window.dispatchEvent(new CustomEvent("icon-item-click", {
detail: {
id: self.id ? self.id : self.icon,
isActive: isActive,
target: self
}
}));
}
handleInfo() {
let self = this;
window.dispatchEvent(new CustomEvent("more-info-action", {detail: self.icon}));
}
handlePress(event: Event) {
let target = event.target as HTMLElement;
if (target.nodeName == "P") {
target = target.parentElement as HTMLElement;
}
if (this.getAttribute("disabled") === "true") {
return;
}
let section = this.icon;
this.timer = setTimeout(() => {
let activity = new WebActivity("moz_configure_window", {
data: {
target: "device",
section: section
}
});
activity.start();
}, 300);
let self = this;
window.dispatchEvent(new CustomEvent("touch-start", {
detail: {
id: self.id ? self.id : self.icon,
target: self
}
}));
}
handlePressEnd() {
clearTimeout(this.timer);
}
activeOrInactive(isActive: boolean, element?: HTMLElement) {
if (element == null) {
isActive ? this.iconBtn.classList.remove("active") :
this.iconBtn.classList.add("active");
this.active = isActive;
} else {
isActive ? element.classList.remove("active") :
element.classList.add("active");
}
}
render(): HTMLTemplateResult | typeof nothing {
switch (this.type) {
case IconType.BASE:
return this.getbase();
case IconType.BASE_WITHOUT_BORDER:
return this.getbaseWithOutBorder();
case IconType.WITH_STATE:
return this.getwithstate();
default:
console.error('unhandled 【icon-item】 type')
return nothing;
}
}
addClass(className: string[]) {
this.iconBtn.classList.add(...className);
}
removeClass(className: string) {
this.iconBtn.classList.remove(className);
}
getClassList() {
return this.iconBtn.classList;
}
static styles = css`
:host {
--background-active: #1D98F5;
--background-lm: rgba(255, 255, 255, 0.35);
--background-dm: rgba(0, 0, 0, 0.15);
--text-color-lm: #4D4D4D;
--text-color-dm: #D1D1D1;
--text-color-active: #FFFFFF;
}
.active {
background-color: var(--background-active) !important;
color: var(--text-color-active) !important;
}
.with-border {
width: 100%;
height: 100%;
display: flex;
align-items: center;
border-radius: 16px;
background: var(--background-lm);
}
.icon-button::before {
width: 48px;
height: 48px;
line-height: 48px;
text-align: center;
vertical-align: middle;
content: attr(data-icon);
font-size: 48px;
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
.icon-with-state::before {
position: relative;
left: 22px;
}
.icon-base {
justify-content: center;
}
.more-info-icon {
width: 16px;
height: 16px;
position: relative;
left: 58px;
}
.more-info-icon::after {
width: 16px;
height: 16px;
text-align: center;
vertical-align: middle;
line-height: 16px;
content: attr(data-icon);
font-size: 16px;
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
p {
width: 100px;
height: 20px;
position: relative;
left: 34px;
color: var(--text-color-lm);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
font-size: 21px;
line-height: 20px;
mix-blend-mode: normal;
}
.active > p {
color: var(--text-color-active);
}
:host([deep-mode]) .with-border {
width: 100%;
height: 100%;
display: flex;
align-items: center;
border-radius: 16px;
// border-radius: 8px;
background: var(--background-dm);
}
:host([deep-mode]) p {
width: 100px;
height: 20px;
position: relative;
left: 34px;
color: var(--text-color-dm);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
font-size: 21px;
line-height: 20px;
mix-blend-mode: normal;
}
`
}
declare global {
interface HTMLElementTagNameMap {
'icon-item': IconItem
}
}

View File

@ -1,88 +0,0 @@
export default class IconDB {
db: any;
DB_NAME = 'icon-db';
DB_ORDER_STORE = 'order';
DB_VERSION = 1;
init() {
return new Promise((resolve: (value: void) => void, reject) => {
var req = window.indexedDB.open(this.DB_NAME, this.DB_VERSION);
req.onupgradeneeded = this.upgradeSchema;
req.onsuccess = () => {
this.db = req.result;
resolve();
};
req.onerror = (e) => {
console.error('Error opening icon db', e);
reject(e);
};
});
}
upgradeSchema(e: any) {
var db = e.target.result;
var fromVersion = e.oldVersion;
if (fromVersion < 1) {
var store = db.createObjectStore(this.DB_ORDER_STORE, { keyPath: 'id' });
store.createIndex('order', 'order', { unique: false });
}
}
set(data: any) {
return new Promise((resolve, reject) => {
var txn = this.db.transaction(this.DB_ORDER_STORE,
'readwrite');
for (var entry of data) {
if (!entry.id) {
continue;
}
if (typeof entry.order !== 'undefined') {
txn.objectStore(this.DB_ORDER_STORE).
put({ id: entry.id, order: entry.order });
}
}
txn.oncomplete = resolve;
txn.onerror = reject;
});
}
remove(id: string) {
return new Promise((resolve, reject) => {
var txn = this.db.transaction(this.DB_ORDER_STORE, 'readwrite');
txn.objectStore(this.DB_ORDER_STORE).delete(id);
txn.oncomplete = resolve;
txn.onerror = reject;
});
}
getAll(onResult: Function) {
return new Promise((resolve: (value?: any) => void) => {
try {
var txn = this.db.transaction(this.DB_ORDER_STORE, 'readonly');
var orderStore = txn.objectStore(this.DB_ORDER_STORE);
var cursor = orderStore.index('order').openCursor();
var results: any[] = [];
cursor.onsuccess = (e: any) => {
var cursor = e.target.result;
if (cursor) {
var result = cursor.value;
console.log("ffff result: ", result);
if (onResult) {
onResult(result);
}
cursor.continue();
}
};
txn.oncomplete = () => {
resolve(results);
};
} catch (error) {
resolve("error");
}
});
}
}

View File

@ -1,137 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult, nothing } from 'lit'
import { customElement, property, queryAssignedElements } from 'lit/decorators.js'
export enum IconsOneLineType {
BASE = 'base',
WITH_STATE = 'with-state'
}
@customElement('icons-one-line')
export class IconsOneLine extends LitElement {
@property({type: IconsOneLineType}) type = '';
@property({type: Number}) count = 2;
@queryAssignedElements({flatten: true}) slotElements!: HTMLSlotElement[];
getbase(): HTMLTemplateResult {
const colorstyle = this.count !== 4
? html`
<style>
.icon-only > div > ::slotted(*) {
width: calc(100% / ${this.count}) !important;
}
</style>
`
: nothing;
return html`
<div class="icon-only">
<div>
<slot></slot>
</div>
${colorstyle}
</div>
`;
}
getIconWithState(): HTMLTemplateResult {
return html`
<div class="icon-with-state">
<slot></slot>
</div>
`;
}
firstUpdated() {
this.count = this.slotElements.length;
}
render() {
switch (this.type) {
case IconsOneLineType.BASE:
return this.getbase();
case IconsOneLineType.WITH_STATE:
return this.getIconWithState();
default:
console.error('unhandled 【icons-one-line】 type')
return nothing;
}
}
static styles = css`
:host {
--background-lm: #FFFFFF;
--background-dm: #000000;
--opacity-lm: 0.75;
--opacity-dm: 0.25;
--line-border-lm: rgba(0, 0, 0, 0.07);
--line-border-dm: rgba(255, 255, 255, 0.07);
width: inherit;
height: inherit;
background: var(--background-lm);
mix-blend-mode: normal;
opacity: var(--opacity-lm);
border-radius: 16px;
}
.icon-with-state {
width: 100%;
display: flex;
align-items: center;
// justify-content: space-around;
justify-content: space-between;
}
.icon-only {
width: inherit;
height: inherit;
background: inherit;
border-radius: inherit;
opacity: inherit;
}
.icon-only > div {
display: flex;
align-items: center;
height: 100%;
}
.icon-only > div > ::slotted(*) {
width: 25%;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-left: 2px solid var(--line-border-lm);
border-radius: 2px;
}
.icon-only > div > ::slotted(:first-child) {
border-left-style: none;
}
:host([deep-mode]) {
width: inherit;
height: inherit;
background: var(--background-dm);
mix-blend-mode: normal;
opacity: var(--opacity-dm);
border-radius: 16px;
}
:host([deep-mode]) .icon-only > div > ::slotted(*) {
width: 25%;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
border-left: 2px solid var(--line-border-dm);
border-radius: 2px;
}
`
}
declare global {
interface HTMLElementTagNameMap {
'icons-one-line': IconsOneLine
}
}

View File

@ -1 +0,0 @@
export * from './control-center-bar.js'

View File

@ -1,153 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult } from 'lit'
import { customElement, property, query } from 'lit/decorators.js'
@customElement('light-slider')
export class LightSlider extends LitElement {
@query('.progress') progress!: HTMLDivElement;
@query('.sliderBar') sliderBar!: HTMLDivElement;
@property({type: String}) id = '';
@property({type: String}) _coverLen = '';
@property({type: Number}) innerWidth = 0;
@property({type: Number}) distance = 0;
@property({type: Number}) currentDistance = 0;
@property({type: Number}) barWidth = 0;
@property({type: Number}) max = 100;
@property({type: Number}) value = 1;
@property() touchAction = {
// 触摸开始落点
start: {
offsetX: 0,
offsetY: 0,
clientX: 0,
clientY: 0
},
// 触摸结束落点
last: {
offsetX: 0,
offsetY: 0,
clientX: 0,
clientY: 0
}
}
@property({type: String})
get coverLen() {
return this._coverLen;
}
set coverLen(value: string) {
this.style.setProperty('--cover-length', value);
this._coverLen = value;
}
render(): HTMLTemplateResult {
return html`
<div class="sliderBar" data-icon="brightness" value=${this.value} max=${this.max} @touchstart=${this} @touchmove=${this} @touchend=${this}>
<div class="progress"></div>
</div>
`
}
static styles = css`
:host {
width: inherit;
height: inherit;
dislay: block;
--cover-length: 3.78px; // 亮度为1
--background-lm: rgba(255, 255, 255, 0.5);
--background-dm: rgba(0, 0, 0, 0.15);
--progress-background-lm: rgba(255, 255, 255, 0.8);
--progress-background-dm: rgba(255, 255, 255, 0.7);
}
.sliderBar {
width: inherit;
height: inherit;
position: absolute;
left: 0px;
right: 0px;
background: var(--background-lm);
border-radius: 16px;
}
.progress {
width: var(--cover-length);
height: 100%;
position: absolute;
left: 0px;
right: 0px;
background: var(--progress-background-lm);
border-radius: 16px;
}
.sliderBar::before {
position: absolute;
width: 48px;
height: 48px;
left: 29px;
top: 29px;
content: attr(data-icon);
font-size: 48px;
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
`
firstUpdated() {
if (this.value) {
let len = Math.floor(this.value * this.sliderBar.offsetWidth / this.max);
this.coverLen = len.toString();
}
}
handleEvent(event: TouchEvent) {
switch (event.type) {
case "touchstart":
this.touchAction.start.clientX = event.touches[0].clientX;
this.barWidth = this.sliderBar.offsetWidth;
break;
case "touchmove":
this.touchAction.last.clientX = event.touches[0].clientX;
this.distance = this.touchAction.last.clientX - this.touchAction.start.clientX;
this.currentDistance = this.distance + this.progress.offsetWidth;
if (this.currentDistance < 0) {
// this.currentDistance = 0;
this.currentDistance = this.barWidth / this.max;
}
if (this.currentDistance > this.barWidth) {
this.currentDistance = this.barWidth;
}
this.progress.style.setProperty('width', this.currentDistance + 'px');
break;
case "touchend":
this.value = Math.floor(this.currentDistance * this.max / this.barWidth);
this.dispatchEvent(new CustomEvent("light-slider-change", {
detail: {
value: this.value
},
bubbles: true,
composed: true,
}));
break;
}
}
setValue(value: number) {
console.log("light00 set value: ", value);
this.value = value;
console.log("light00 set this.value: ", this.value);
let len = Math.floor(value * this.sliderBar.offsetWidth / this.max);
this.coverLen = len.toString();
console.log("light00 set this.coverLen: ", this.coverLen);
}
}
declare global {
interface HTMLElementTagNameMap {
'light-slider': LightSlider
}
}

View File

@ -1,88 +0,0 @@
interface Obj {
name?: string;
value?: any;
callback: (name: string, value: any)=> void;
}
interface Pair {
name: string;
value: any;
}
export var settingsObserver = {
_keyvaluepairs: [] as Pair[], // 存放设定的设置键值对
_observers: [] as Obj[], // 存放observe方法存入的
getValue: function(name: string) {
// return new Promise((resolve: (value: any) => void) => {
// resolve(true);
// })
return new Promise(resovle => {
let value;
this._keyvaluepairs.forEach((pair: any) => {
if(pair.name == name) {
value = pair.value;
}
});
return resovle(value);
})
},
observe: function(name: string, defaultValue: any, callback: (name: string, value: any)=> void, observeOnly: boolean) {
if (!observeOnly) {
this.getValue(name).then((value) => {
callback(name, value !== null && value !== void 0 ? value : defaultValue); // 重启前设置值为false或0时重启后返回的值不应该为默认值
});
}
this._observers.push({
name,
callback
});
},
setValue: function(args: any[]) {
return new Promise((resovle: (value: void)=> void) => {
// 将传入的设置值更新/设置入_keyvaluepairs
args.forEach((pair: any) => {
let targetPair = this._keyvaluepairs.find((item: any) => {
return item.name == pair.name
});
if (targetPair as any) {
// 在_keyvaluepairs根据pair.name找到了相同的设置值更新键值对的value
(targetPair as any).value = pair.value;
} else {
// 在_keyvaluepairs不存在该设置值新增键值对
let newPair = {
name: pair.name,
value: pair.value
};
this._keyvaluepairs.push(newPair);
}
// 同时检查_observers中是否有该设置值变化时的回调
this._observers.forEach(ob => {
ob.name = pair.name && ob.callback?.(pair.name, pair.value);
});
resovle();
});
})
},
getBatch: function (names: string[]) {
return new Promise((resolve: ({}) => void) => {
let result = [];
for (let index = 0; index < names.length; index++) {
const name = names[index];
let value = true;
result.push({name, value: value});
}
if (result.length == names.length) {
resolve(result);
}
})
}
}

View File

@ -1,37 +0,0 @@
{
"name": "@star-web-components/control-center-bar",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./icon-item.js": {
"default": "./icon-item.js"
},
"./icons-one-line.js": {
"default": "./icons-one-line.js"
},
"./header-bar.js": {
"default": "./header-bar.js"
},
"./light-slider.js": {
"default": "./light-slider.js"
},
"./pull-down-menu.js": {
"default": "./pull-down-menu.js"
},
"./control-center-bar.js": {
"default": "./control-center-bar.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -1,128 +0,0 @@
import { html, css, LitElement, HTMLTemplateResult, nothing } from 'lit'
import { customElement, property, queryAssignedElements } from 'lit/decorators.js'
import { HeaderBarType } from './header-bar';
import { IconItem, IconType } from './icon-item';
import './icon-item';
import './header-bar';
export enum PullDownMenuType {
HEADER_WITH_TIME = 'header-with-time',
HEADER_WITH_DATE_TIME = 'header-with-date-time'
}
@customElement('pull-down-menu')
export class PullDownMenu extends LitElement {
@property({type: PullDownMenuType}) type = '';
@queryAssignedElements({flatten: true}) slotElements!: HTMLSlotElement[];
getOnlyTime(): HTMLTemplateResult {
return html`
<div class="inner">
<header-bar type=${HeaderBarType.ONLY_TIME}>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="compose" @click=${this}></icon-item>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings" @click=${this}></icon-item>
</header-bar>
<div class="all-quick-icons">
<slot @slotchange=${this}></slot>
</div>
</div>
`
}
getTimeAndDate(): HTMLTemplateResult {
return html`
<div class="inner">
<header-bar type=${HeaderBarType.DATE_TIME}>
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings" @click=${this}></icon-item>
</header-bar>
<div class="others">
<slot @slotchange=${this}></slot>
</div>
</div>
`
}
render(): HTMLTemplateResult | typeof nothing {
switch (this.type) {
case PullDownMenuType.HEADER_WITH_TIME:
return this.getOnlyTime();
case PullDownMenuType.HEADER_WITH_DATE_TIME:
return this.getTimeAndDate();
default:
console.error('unhandled 【pull-down-menu】 type');
return nothing;
}
}
static styles = css`
:host {
width: inherit;
height: inherit;
position: absolute;
left: 0px;
top: 0px;
}
:host([open]) {
transform: translateY(0);
transition: transform 300ms ease, visibility 300ms;
will-change: transform;
visibility: visible;
}
.inner {
width: inherit;
height: inherit;
display: flex;
flex-direction: column;
align-items: center;
}
header-bar[type='only-time'] {
dispaly: flex;
width: 512px;
height: 52px;
}
header-bar[type='date-time'] {
dispaly: flex;
width: 860px;
height: 64px;
}
.all-quick-icons {
width: 100%;
height: calc(100% - 52px);
position: relative;
top: 40px;
}
.others {
display: flex;
flex-direction: column;
position: absolute;
top: 100px;
}
`
handleEvent(event: Event) {
switch (event.type) {
case "click":
switch ((event.target as IconItem).icon) {
case "compose":
window.dispatchEvent(new CustomEvent("editor-action"));
break;
case "settings":
let activity = new WebActivity("configure", {});
activity.start().then(() => {}, () => {});
break;
}
break;
}
}
}
declare global {
interface HTMLElementTagNameMap {
'pull-down-menu': PullDownMenu
}
}

View File

@ -0,0 +1,173 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {customElement, property, queryAssignedElements} from 'lit/decorators.js'
import {HeaderBarType} from '../header-bar/header-bar.js'
import {IconControlBar, IconControlBarType} from '../icon-control-bar/icon-control-bar.js'
import {WebActivity} from './interface.js'
import '../icon-control-bar/icon-control-bar.js'
import '../header-bar/header-bar.js'
export enum DropDownMenuType {
HEADER_WITH_TIME = 'header-with-time',
HEADER_WITH_DATE_TIME = 'header-with-date-time',
}
@customElement('pull-down-menu')
export class DropDownMenu extends LitElement {
@property({type: DropDownMenuType}) type = ''
@queryAssignedElements({flatten: true}) slotElements!: HTMLSlotElement[]
getOnlyTime(): HTMLTemplateResult {
return html`
<div class="inner">
<header-bar type=${HeaderBarType.ONLY_TIME}>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="compose"
@click=${this}
></icon-control-bar>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="settings"
@click=${this}
></icon-control-bar>
</header-bar>
<div class="all-quick-icons">
<slot @slotchange=${this}></slot>
</div>
</div>
`
}
getTimeAndDate(): HTMLTemplateResult {
return html`
<div class="inner">
<header-bar type=${HeaderBarType.DATE_TIME}>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="settings"
@click=${this}
></icon-control-bar>
</header-bar>
<div class="others">
<slot @slotchange=${this}></slot>
</div>
</div>
`
}
render(): HTMLTemplateResult | typeof nothing {
switch (this.type) {
case DropDownMenuType.HEADER_WITH_TIME:
return this.getOnlyTime()
case DropDownMenuType.HEADER_WITH_DATE_TIME:
return this.getTimeAndDate()
default:
console.error('unhandled 【pull-down-menu】 type')
return nothing
}
}
static styles = css`
:host {
width: inherit;
height: inherit;
position: absolute;
left: 0px;
top: 0px;
}
:host([open]) {
transform: translateY(0);
transition: transform 300ms ease, visibility 300ms;
will-change: transform;
visibility: visible;
}
.inner {
width: inherit;
height: inherit;
display: flex;
flex-direction: column;
align-items: center;
}
@media screen and (max-width: 1200px) {
header-bar[type='only-time'] {
dispaly: flex;
width: 512px;
height: 52px;
}
header-bar[type='date-time'] {
dispaly: flex;
width: 860px;
height: 64px;
}
.all-quick-icons {
width: 100%;
height: calc(100% - 52px);
position: relative;
top: 40px;
}
.others {
display: flex;
flex-direction: column;
position: absolute;
top: 100px;
}
}
@media screen and (max-width: 600px) {
header-bar[type='only-time'] {
dispaly: flex;
width: 256px;
height: 26px;
}
header-bar[type='date-time'] {
dispaly: flex;
width: 430px;
height: 32px;
}
.all-quick-icons {
width: 100%;
height: calc(100% - 26px);
position: relative;
top: 20px;
}
.others {
display: flex;
flex-direction: column;
position: absolute;
top: 50px;
}
}
`
handleEvent(event: Event) {
switch (event.type) {
case 'click':
switch ((event.target as IconControlBar).icon) {
case 'compose':
window.dispatchEvent(new CustomEvent('editor-action'))
break
case 'settings':
let activity = new WebActivity('configure', {})
activity.start().then(
() => {},
() => {}
)
break
}
break
}
}
}
declare global {
interface HTMLElementTagNameMap {
'pull-down-menu': DropDownMenu
}
}

View File

@ -0,0 +1 @@
export * from './drop-down-menu.js'

View File

@ -0,0 +1,9 @@
export interface WebActivity {
start(): Promise<any>
cancel(): void
}
export var WebActivity: {
prototype: WebActivity
new (name: string, data?: any): WebActivity
}

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/drop-down-menu",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./drop-down-menu.js": {
"default": "./drop-down-menu.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,13 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": [
"*.ts",
"../icon-control-bar/icon-control-bar.js",
"../header-bar/header-bar.js",
"./interface.js"
]
}

View File

@ -0,0 +1,327 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {customElement, property, query, state} from 'lit/decorators.js'
export enum HeaderBarType {
ONLY_TIME = 'only-time',
DATE_TIME = 'date-time',
}
@customElement('header-bar')
export class HeaderBar extends LitElement {
@state() updateTimeTimeout!: number
@state() updateDateTimeout!: number
@property({type: HeaderBarType}) type = ''
@query('#time') time!: HTMLDivElement
@query('#date') date!: HTMLDivElement
getTime(): HTMLTemplateResult {
return html`
<div class="time-outer">
<div id="time"></div>
<div class="time-icons">
<slot></slot>
</div>
</div>
`
}
getTimeAndDate(): HTMLTemplateResult {
return html`
<div class="time-date-outer">
<div class="time-date">
<div id="time"></div>
<div id="date"></div>
</div>
<div class="time-date-icons">
<slot></slot>
</div>
</div>
`
}
render() {
switch (this.type) {
case HeaderBarType.ONLY_TIME:
return this.getTime()
case HeaderBarType.DATE_TIME:
return this.getTimeAndDate()
default:
console.error('unhandled 【header-bar】 type')
return nothing
}
}
static styles = css`
:host {
--only-time-color-lm: #292929;
--only-time-color-dm: #f0f0f0;
--time-date-time-color-lm: #404040;
--time-date-date-color-lm: #000000;
--time-date-time-color-dm: #e0e0e0;
--time-date-date-color-dm: #e0e0e0;
width: inherit;
height: inherit;
}
.time-outer {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: space-between;
}
.time-outer > #time {
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
color: var(--only-time-color-lm);
}
.time-icons > ::slotted(*) {
display: flex;
}
.time-date-outer {
width: 100%;
height: 100%;
display: flex;
align-items: end;
}
.time-date {
height: 100%;
width: 100%;
display: flex;
align-items: end;
vertical-align: middle;
font-family: 'OPPOSans';
font-style: normal;
font-weight: 400;
position: relative;
}
.time-date > #time {
color: var(--time-date-time-color-lm);
}
#date {
position: relative;
opacity: 0.6;
color: var(--time-date-date-color-lm);
mix-blend-mode: normal;
}
.host([deep-mode]) .time-outer > #time {
color: var(--only-time-color-dm);
}
.host([deep-mode]) #date {
color: var(--time-date-date-color-dm);
}
@media screen and (max-width: 1200px) {
.time-outer > #time {
height: 52px;
line-height: 52px;
font-size: 52px;
}
.time-icons {
display: flex;
width: 136px;
position: relative;
right: 4px;
}
.time-icons > ::slotted(:last-child) {
position: relative;
left: 40px;
}
.time-date {
line-height: 64px;
left: 10px;
}
.time-date > #time {
font-size: 64px;
}
#date {
height: 34px;
line-height: 34px;
left: 22px;
font-size: 26px;
}
.time-date-icons {
position: relative;
right: 11px;
}
}
@media screen and (max-width: 600px) {
.time-outer > #time {
height: 26px;
line-height: 26px;
font-size: 26px;
}
.time-icons {
display: flex;
width: 68px;
position: relative;
right: 2px;
}
.time-icons > ::slotted(:last-child) {
position: relative;
left: 20px;
}
.time-date {
line-height: 32px;
left: 5px;
}
.time-date > #time {
font-size: 32px;
}
#date {
height: 17px;
line-height: 17px;
left: 11px;
font-size: 13px;
}
.time-date-icons {
position: relative;
right: 5.5px;
}
}
`
firstUpdated() {
this.autoUpdateDateTime()
}
autoUpdateDateTime() {
switch (this.type) {
case HeaderBarType.ONLY_TIME:
window.clearTimeout(this.updateTimeTimeout)
this.autoUpdateTime()
break
case HeaderBarType.DATE_TIME:
window.clearTimeout(this.updateDateTimeout)
window.clearTimeout(this.updateTimeTimeout)
this.autoUpdateDate()
this.autoUpdateTime()
break
}
}
autoUpdateTime() {
var d = new Date()
this.time.innerHTML = this.formatTime(d)
let self = this
var remainMillisecond = (60 - d.getSeconds()) * 1000
this.updateTimeTimeout = window.setTimeout(() => {
self.autoUpdateTime()
}, remainMillisecond)
}
autoUpdateDate() {
var d = new Date()
this.date.innerHTML = this.formatDate(d) + ' ' + this.getWeekDay()
let remainMillisecond =
(24 - d.getHours()) * 3600 * 1000 -
d.getMinutes() * 60 * 1000 -
d.getMilliseconds()
let self = this
this.updateDateTimeout = window.setTimeout(function updateDateTimeout() {
self.autoUpdateDate()
}, remainMillisecond)
}
getWeekDay() {
var d = new Date()
let daynumber = d.getDay()
let day = ''
switch (daynumber) {
case 0:
day = '周日'
break
case 1:
day = '周一'
break
case 2:
day = '周二'
break
case 3:
day = '周三'
break
case 4:
day = '周四'
break
case 5:
day = '周五'
break
case 6:
day = '周六'
break
}
return day
}
formatDate(d: Date | string, iso?: boolean) {
if (d instanceof Date) {
if (iso) {
let date = d.toISOString() // Thu Oct 07 2021 07:45:18 GMT+0800
date = date.split('T')[0]
return date
} else {
return d.toLocaleString(navigator.languages as string[], {
// year: 'numeric',
month: 'long',
day: '2-digit',
})
}
} else {
return d
}
}
formatTime(d: Date | string, iso?: boolean) {
if (d instanceof Date) {
if (iso) {
let time = d.toLocaleTimeString()
time = time.split(' ')[0]
if (time.indexOf(':') === 1) {
time = `0${time}`
}
return time
} else {
return d.toLocaleString(navigator.languages as string[], {
// hour12: (navigator as any).mozHour12,
hour12: false,
hour: 'numeric',
minute: 'numeric',
})
}
} else {
if (d.indexOf(':') == 1) {
d = '0' + d
}
return d
}
}
}
declare global {
interface HTMLElementTagNameMap {
'header-bar': HeaderBar
}
}

View File

@ -0,0 +1 @@
export * from './header-bar.js'

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/header-bar",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./header-bar.js": {
"default": "./header-bar.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -0,0 +1,170 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {customElement, property, queryAssignedElements} from 'lit/decorators.js'
export enum IconControlBarGroupType {
BASE = 'base',
WITH_STATE = 'with-state',
}
@customElement('icon-control-bar-group')
export class IconControlBarGroup extends LitElement {
@property({type: IconControlBarGroupType}) type = ''
@property({type: Number}) count = 2
@queryAssignedElements({flatten: true}) slotElements!: HTMLSlotElement[]
getbase(): HTMLTemplateResult {
const colorstyle =
this.count !== 4
? html`
<style>
.icon-only > div > ::slotted(*) {
width: calc(100% / ${this.count}) !important;
}
</style>
`
: nothing
return html`
<div class="icon-only">
<div>
<slot></slot>
</div>
${colorstyle}
</div>
`
}
getIconWithState(): HTMLTemplateResult {
return html`
<div class="icon-with-state">
<slot></slot>
</div>
`
}
firstUpdated() {
this.count = this.slotElements.length
}
render() {
switch (this.type) {
case IconControlBarGroupType.BASE:
return this.getbase()
case IconControlBarGroupType.WITH_STATE:
return this.getIconWithState()
default:
console.error('unhandled 【icon-control-bar-group】 type')
return nothing
}
}
static styles = css`
:host {
--background-lm: #ffffff;
--background-dm: #000000;
--opacity-lm: 0.75;
--opacity-dm: 0.25;
--line-border-lm: rgba(0, 0, 0, 0.07);
--line-border-dm: rgba(255, 255, 255, 0.07);
width: inherit;
height: inherit;
background: var(--background-lm);
mix-blend-mode: normal;
opacity: var(--opacity-lm);
}
.icon-with-state {
width: 100%;
display: flex;
align-items: center;
// justify-content: space-around;
justify-content: space-between;
}
.icon-only {
width: inherit;
height: inherit;
background: inherit;
border-radius: inherit;
opacity: inherit;
}
.icon-only > div {
display: flex;
align-items: center;
height: 100%;
}
.icon-only > div > ::slotted(*) {
width: 25%;
height: 30px;
display: flex;
align-items: center;
justify-content: center;
}
.icon-only > div > ::slotted(:first-child) {
border-left-style: none;
}
:host([deep-mode]) {
background: var(--background-dm);
}
// :host([deep-mode]) .icon-only > div > ::slotted(*) {
// width: 25%;
// // height: 30px;
// display: flex;
// align-items: center;
// justify-content: center;
// // border-left: 2px solid var(--line-border-dm);
// // border-radius: 2px;
// }
@media screen and (max-width: 1200px) {
:host {
border-radius: 16px;
}
.icon-only > div > ::slotted(*) {
height: 30px;
border-left: 2px solid var(--line-border-lm);
border-radius: 2px;
}
:host([deep-mode]) {
border-radius: 16px;
}
:host([deep-mode]) .icon-only > div > ::slotted(*) {
border-left: 2px solid var(--line-border-dm);
}
}
@media screen and (max-width: 600px) {
:host {
border-radius: 8px;
}
.icon-only > div > ::slotted(*) {
height: 15px;
border-left: 1px solid var(--line-border-lm);
border-radius: 1px;
}
:host([deep-mode]) {
border-radius: 8px;
}
:host([deep-mode]) .icon-only > div > ::slotted(*) {
border-left: 1px solid var(--line-border-dm);
}
}
`
}
declare global {
interface HTMLElementTagNameMap {
'icon-control-bar-group': IconControlBarGroup
}
}

View File

@ -0,0 +1 @@
export * from './icon-control-bar-group.js'

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/icon-control-bar-group",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./icon-control-bar-group.js": {
"default": "./icon-control-bar-group.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts"]
}

View File

@ -0,0 +1,426 @@
import {html, css, LitElement, HTMLTemplateResult, nothing} from 'lit'
import {
customElement,
property,
eventOptions,
query,
state,
} from 'lit/decorators.js'
import {WebActivity} from './interface.js'
export enum IconControlBarType {
BASE = 'base',
BASE_WITHOUT_BORDER = 'base-without-border',
WITH_STATE = 'with-state',
}
@customElement('icon-control-bar')
export class IconControlBar extends LitElement {
@property({type: IconControlBarType}) type = ''
@property({type: String}) icon = ''
@property({type: String}) stateDesc = ''
@property({type: String}) settingsKey = ''
@property({type: Boolean}) bgchange = false
@property({type: String}) id = ''
@property({type: Boolean}) active = false
@state({}) timer!: NodeJS.Timeout
@query('.more-info-icon') moreInfoIcon!: HTMLDivElement
@query('.icon-button') iconBtn!: HTMLDivElement
getbase(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-control-bar】缺少 icon 参数')
return nothing
}
const iconstyle = html`
<style>
@media screen and (max-width: 1200px) {
:host {
width: 104px;
height: 104px;
}
}
@media screen and (max-width: 600px) {
:host {
width: 52px;
height: 52px;
}
}
</style>
`
return html`
<div
class="icon-button icon-base with-border"
data-icon=${this.icon}
@click=${this.handleClick}
@touchstart=${this.handlePress}
@touchend=${this.handlePressEnd}
>
${iconstyle}
</div>
`
}
getbaseWithOutBorder(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-control-bar】缺少 icon 参数')
return nothing
}
return html`
<div
class="icon-button icon-base without-border"
data-icon=${this.icon}
@click=${this.handleClick}
@touchstart=${this.handlePress}
@touchend=${this.handlePressEnd}
></div>
`
}
getwithstate(): HTMLTemplateResult | typeof nothing {
if (!this.icon) {
console.error('【icon-control-bar】缺少 icon 参数')
return nothing
}
const iconstyle = html`
<style>
@media screen and (max-width: 1200px) {
:host {
width: 240px;
height: 108px;
}
}
@media screen and (max-width: 600px) {
:host {
width: 120px;
height: 54px;
}
}
</style>
`
return html`
<div
class="icon-button icon-with-state with-border config-activity"
data-icon=${this.icon}
@click=${this.handleClick}
@touchstart=${this.handlePress}
@touchend=${this.handlePressEnd}
>
<p>${this.stateDesc}</p>
<div
class="more-info-icon"
@click=${this.handleInfo}
data-icon="expand-left"
></div>
${iconstyle}
</div>
`
}
@eventOptions({passive: false})
handleClick(event: Event) {
let isActive = true // 闹铃
if (this.bgchange) {
let target = event.target as HTMLElement
if (target.nodeName == 'P') {
target = target.parentElement as HTMLElement
}
if (target.className == 'more-info-icon') {
target = target.parentElement as HTMLElement
}
isActive = target.classList.contains('active')
this.activeOrInactive(isActive, target)
}
// if (this.type == IconControlBarType.WITH_STATE) {
// if (target.className == "more-info-icon") {
// target = target.parentElement as HTMLElement;
// }
// if (target.classList.contains("active")) {
// this.moreInfoIcon.dataset.icon = "expand-left";
// } else {
// this.moreInfoIcon.dataset.icon = "";
// }
// }
let self = this
window.dispatchEvent(
new CustomEvent('icon-control-bar-click', {
detail: {
id: self.id ? self.id : self.icon,
isActive: isActive,
target: self,
},
})
)
}
handleInfo() {
let self = this
window.dispatchEvent(
new CustomEvent('more-info-action', {detail: self.icon})
)
}
handlePress(event: Event) {
let target = event.target as HTMLElement
if (target.nodeName == 'P') {
target = target.parentElement as HTMLElement
}
if (this.getAttribute('disabled') === 'true') {
return
}
let section = this.icon
this.timer = setTimeout(() => {
let activity = new WebActivity('moz_configure_window', {
data: {
target: 'device',
section: section,
},
})
activity.start()
}, 300)
let self = this
window.dispatchEvent(
new CustomEvent('touch-start', {
detail: {
id: self.id ? self.id : self.icon,
target: self,
},
})
)
}
handlePressEnd() {
clearTimeout(this.timer)
}
activeOrInactive(isActive: boolean, element?: HTMLElement) {
if (element == null) {
isActive
? this.iconBtn.classList.remove('active')
: this.iconBtn.classList.add('active')
this.active = isActive
} else {
isActive
? element.classList.remove('active')
: element.classList.add('active')
}
}
render(): HTMLTemplateResult | typeof nothing {
switch (this.type) {
case IconControlBarType.BASE:
return this.getbase()
case IconControlBarType.BASE_WITHOUT_BORDER:
return this.getbaseWithOutBorder()
case IconControlBarType.WITH_STATE:
return this.getwithstate()
default:
console.error('unhandled 【icon-control-bar】 type')
return nothing
}
}
addClass(className: string[]) {
this.iconBtn.classList.add(...className)
}
removeClass(className: string) {
this.iconBtn.classList.remove(className)
}
getClassList() {
return this.iconBtn.classList
}
static styles = css`
:host {
--background-active: #1d98f5;
--background-lm: rgba(255, 255, 255, 0.35);
--background-dm: rgba(0, 0, 0, 0.15);
--text-color-lm: #4d4d4d;
--text-color-dm: #d1d1d1;
--text-color-active: #ffffff;
}
.active {
background-color: var(--background-active) !important;
color: var(--text-color-active) !important;
}
.with-border {
width: 100%;
height: 100%;
display: flex;
align-items: center;
background: var(--background-lm);
}
.icon-button::before {
text-align: center;
vertical-align: middle;
content: attr(data-icon);
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
.icon-base {
justify-content: center;
}
.more-info-icon::after {
text-align: center;
vertical-align: middle;
content: attr(data-icon);
font-family: gaia-icons;
font-style: normal;
text-rendering: optimizelegibility;
font-weight: 500;
}
p {
position: relative;
color: var(--text-color-lm);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: OPPOSans;
font-style: normal;
mix-blend-mode: normal;
}
.active > p {
color: var(--text-color-active);
}
:host([deep-mode]) .with-border {
background: var(--background-dm);
}
:host([deep-mode]) p {
position: relative;
color: var(--text-color-dm);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-family: OPPOSans;
font-style: normal;
font-weight: 400;
mix-blend-mode: normal;
}
@media screen and (max-width: 600px) {
.with-border {
border-radius: 8px;
}
.icon-button::before {
width: 24px;
height: 24px;
line-height: 24px;
font-size: 24px;
}
.icon-with-state::before {
position: relative;
left: 11px;
}
.more-info-icon {
width: 8px;
height: 8px;
position: relative;
left: 29px;
}
.more-info-icon::after {
width: 8px;
height: 8px;
line-height: 8px;
font-size: 8px;
}
p {
width: 50px;
height: 10px;
left: 17px;
font-weight: 400;
font-size: 10.5px;
line-height: 10px;
}
:host([deep-mode]) p {
width: 50px;
height: 10px;
position: relative;
left: 17px;
font-weight: 400;
font-size: 10.5px;
line-height: 10px;
}
}
@media screen and (max-width: 1200px) {
.with-border {
border-radius: 16px;
}
.icon-button::before {
width: 48px;
height: 48px;
line-height: 48px;
font-size: 48px;
}
.icon-with-state::before {
position: relative;
left: 22px;
}
.more-info-icon {
width: 16px;
height: 16px;
position: relative;
left: 58px;
}
.more-info-icon::after {
width: 16px;
height: 16px;
line-height: 16px;
font-size: 16px;
}
p {
width: 100px;
height: 20px;
left: 34px;
font-size: 21px;
line-height: 20px;
}
}
`
}
declare global {
interface HTMLElementTagNameMap {
'icon-control-bar': IconControlBar
}
}

View File

@ -0,0 +1 @@
export * from './icon-control-bar.js'

View File

@ -0,0 +1,9 @@
export interface WebActivity {
start(): Promise<any>
cancel(): void
}
export var WebActivity: {
prototype: WebActivity
new (name: string, data?: any): WebActivity
}

View File

@ -0,0 +1,22 @@
{
"name": "@star-web-components/icon-control-bar",
"version": "0.0.1",
"description": "",
"type": "module",
"main": "./index.js",
"module": "./index.js",
"exports": {
".": {
"default": "./index.js"
},
"./index": {
"default": "./index.js"
},
"./icon-control-bar.js": {
"default": "./icon-control-bar.js"
},
"./package.json": "./package.json"
},
"author": "",
"license": "ISC"
}

View File

@ -0,0 +1,8 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"composite": true,
"rootDir": "../../"
},
"include": ["*.ts", "./interface.js"]
}

View File

@ -15,8 +15,8 @@ import './components/toast/toast'
import './components/picker/picker' import './components/picker/picker'
import './components/overflowmenu/overflowmenu' import './components/overflowmenu/overflowmenu'
import './components/slider/slider' import './components/slider/slider'
import './components/control-center/icon-item' import './components/icon-control-bar/icon-control-bar'
import './components/control-center/icons-one-line' import './components/icon-control-bar-group/icon-control-bar-group'
import './components/prompt/prompt' import './components/prompt/prompt'
import './components/digicipher/digicipher' import './components/digicipher/digicipher'
import './components/pattern-view/pattern-view' import './components/pattern-view/pattern-view'

View File

@ -1,101 +1,117 @@
import {html, css, LitElement} from 'lit' import {html, LitElement} from 'lit'
import {customElement, query} from 'lit/decorators.js' import {customElement, query} from 'lit/decorators.js'
import {IconItem, IconType} from "../../../components/control-center/icon-item" import {IconControlBarType} from '../../../components/icon-control-bar/icon-control-bar'
import "../../../components/control-center/icon-item" import '../../../components/icon-control-bar/icon-control-bar'
import {IconsOneLineType} from "../../../components/control-center/icons-one-line" import {IconControlBarGroupType} from '../../../components/icon-control-bar-group/icon-control-bar-group'
import {UlType} from "../../../components/ul/ul" import {UlType} from '../../../components/ul/ul'
import {HeaderBarType} from "../../../components/control-center/header-bar" import {HeaderBarType} from '../../../components/header-bar/header-bar'
import "../../../components/control-center/icons-one-line" import '../../../components/icon-control-bar-group/icon-control-bar-group'
import "../../../components/ul/ul" import '../../../components/ul/ul'
import "../../../components/control-center/header-bar" import '../../../components/header-bar/header-bar'
import "../../../components/control-center/pull-down-menu"
import "../../../components/control-center/control-center-bar"
@customElement('panel-control-center') @customElement('panel-control-center')
export class PanelControlCenter extends LitElement { export class PanelControlCenter extends LitElement {
@query('icon-item[icon="wifi-4"]') wifiIcon!: LitElement; @query('icon-control-bar[icon="wifi-4"]') wifiIcon!: LitElement
@query('icon-item[icon="crop"]') cropBtn!: LitElement; @query('icon-control-bar[icon="crop"]') cropBtn!: LitElement
@query('icon-item[icon="brightness"]') brightnessBtn!: LitElement; @query('icon-control-bar[icon="brightness"]') brightnessBtn!: LitElement
render() { render() {
return html` return html`
<star-ul type=${UlType.ONLY_HEADER} title="icon-item"> <star-ul type=${UlType.ONLY_HEADER} title="icon-control-bar">
<p>settingsObserver监测值</p> <p>settingsObserver监测值</p>
<icon-item type=${IconType.WITH_STATE} icon="wifi-4" bgchange=true settingsKey="wifi.enabled" stateDesc="fgfgfhhhh" @click=${this}></icon-item> <icon-control-bar
<br/> type=${IconControlBarType.WITH_STATE}
<p></p> icon="wifi-4"
<icon-item type=${IconType.BASE} icon="crop" @click=${this}></icon-item> bgchange="true"
<br/> settingsKey="wifi.enabled"
<p></p> stateDesc="fgfgfhhhh"
<icon-item type=${IconType.BASE} icon="brightness" bgchange=true settingsKey="screen.automatic-brightness" @click=${this}></icon-item> @click=${this}
<br/> ></icon-control-bar>
<p></p> <br />
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item> <p></p>
</star-ul> <icon-control-bar type=${IconControlBarType.BASE} icon="crop" @click=${this}></icon-control-bar>
<br />
<p></p>
<icon-control-bar
type=${IconControlBarType.BASE}
icon="brightness"
bgchange="true"
settingsKey="screen.automatic-brightness"
@click=${this}
></icon-control-bar>
<br />
<p></p>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="settings"
></icon-control-bar>
</star-ul>
<star-ul type=${UlType.ONLY_HEADER} title="icons-one-line"> <star-ul type=${UlType.ONLY_HEADER} title="icon-control-bar-group">
<p></p> <p></p>
<icons-one-line type=${IconsOneLineType.WITH_STATE}> <icon-control-bar-group type=${IconControlBarGroupType.WITH_STATE}>
<icon-item type=${IconType.WITH_STATE} icon="wifi-4" bgchange=true settingsKey="wifi.enabled" stateDesc=""></icon-item> <icon-control-bar
<icon-item type=${IconType.WITH_STATE} icon="bluetooth" bgchange=true settingsKey="bluetooth.enabled"></icon-item> type=${IconControlBarType.WITH_STATE}
<icon-item type=${IconType.WITH_STATE} icon="data" bgchange=true settingsKey="a.enabled"></icon-item> icon="wifi-4"
</icons-one-line> bgchange="true"
<br/> settingsKey="wifi.enabled"
<br/> stateDesc=""
<p>box框线</p> ></icon-control-bar>
<icons-one-line type=${IconsOneLineType.BASE} count=4> <icon-control-bar
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="crop"></icon-item> type=${IconControlBarType.WITH_STATE}
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="video"></icon-item> icon="bluetooth"
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="camera"></icon-item> bgchange="true"
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="o"></icon-item> settingsKey="bluetooth.enabled"
</icons-one-line> ></icon-control-bar>
<br/> <icon-control-bar
</star-ul> type=${IconControlBarType.WITH_STATE}
icon="data"
bgchange="true"
settingsKey="a.enabled"
></icon-control-bar>
</icon-control-bar-group>
<br />
<br />
<p>box框线</p>
<icon-control-bar-group type=${IconControlBarGroupType.BASE} count="4">
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="crop"
></icon-control-bar>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="video"
></icon-control-bar>
<icon-control-bar
type=${IconControlBarType.BASE_WITHOUT_BORDER}
icon="camera"
></icon-control-bar>
<icon-control-bar type=${IconControlBarType.BASE_WITHOUT_BORDER} icon="o"></icon-control-bar>
</icon-control-bar-group>
<br />
</star-ul>
<star-ul type=${UlType.ONLY_HEADER} title="header-bar">
<star-ul type=${UlType.ONLY_HEADER} title="header-bar"> <p>header带时间</p>
<p>header带时间</p> <header-bar type=${HeaderBarType.ONLY_TIME}>
<header-bar type=${HeaderBarType.ONLY_TIME}> <icon-control-bar
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="compose"></icon-item> type=${IconControlBarType.BASE_WITHOUT_BORDER}
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item> icon="compose"
</header-bar> ></icon-control-bar>
<br/> <icon-control-bar
<p>header带时间//</p> type=${IconControlBarType.BASE_WITHOUT_BORDER}
<header-bar type=${HeaderBarType.DATE_TIME}> icon="settings"
<icon-item type=${IconType.BASE_WITHOUT_BORDER} icon="settings"></icon-item> ></icon-control-bar>
</header-bar> </header-bar>
<br/> <br />
</star-ul> <p>header带时间//</p>
<header-bar type=${HeaderBarType.DATE_TIME}>
<icon-control-bar
<star-ul type=${UlType.ONLY_HEADER} title="control-center"> type=${IconControlBarType.BASE_WITHOUT_BORDER}
<control-center> icon="settings"
<panel-icon></panel-icon> ></icon-control-bar>
<icon-item type=${IconType.BASE} icon="brightness"></icon-item> </header-bar>
</control-center> <br />
</star-ul> </star-ul>
` `
// return html`
// <control-center>
// <panel-icon></panel-icon>
// <icon-item type=${IconType.BASE} icon="brightness"></icon-item>
// </control-center>
// `
// return html`
// <control-center-bar>
// </control-center-bar>
// `
}
static styles = css`
control-center-bar {
width: 1200px;
height: 1920px;
}
`;
handleEvent(event: Event) {
console.log("click on icon item: " + (event.target as IconItem).icon);
} }
} }

View File

@ -119,9 +119,6 @@ export class PanelRoot extends LitElement {
<hr /> <hr />
<star-li <star-li
type=${LiType.ICON_LABEL} type=${LiType.ICON_LABEL}
<<<<<<< HEAD
label="SliderTest"
=======
label="开关" label="开关"
icon="switch" icon="switch"
iconcolor="#EB7347" iconcolor="#EB7347"
@ -131,7 +128,6 @@ export class PanelRoot extends LitElement {
<star-li <star-li
type=${LiType.ICON_LABEL} type=${LiType.ICON_LABEL}
label="滑动条" label="滑动条"
>>>>>>> 45627df8470c7bd87bfd6e38897cf3b896b0234d
icon="scene" icon="scene"
iconcolor="#EB7347" iconcolor="#EB7347"
href="#slider" href="#slider"