TASK: #104293 - add homescreen function for storing apps' order
This commit is contained in:
parent
b12d05000e
commit
0d64d0e603
|
@ -20,3 +20,4 @@
|
|||
- add dock
|
||||
- add function for dragging icon into dock
|
||||
- add function for dragging icon into container
|
||||
- add homescreen function for storing apps' order
|
||||
|
|
|
@ -23,6 +23,10 @@ export default class DockChild {
|
|||
x: 0,
|
||||
y: 0,
|
||||
}
|
||||
|
||||
// 状态计时器
|
||||
removed: number | undefined = undefined
|
||||
added: number | undefined = undefined
|
||||
constructor(_element: HTMLElement, manager: StarDock) {
|
||||
this._element = _element
|
||||
this.manager = manager
|
||||
|
@ -82,6 +86,7 @@ export default class DockChild {
|
|||
this._lastMasterWidth = this._master.offsetWidth
|
||||
this._lastMasterHeight = this._master.offsetHeight
|
||||
this.center.x = left + this._lastMasterWidth / 2
|
||||
this.center.y = top + this._lastMasterHeight / 2
|
||||
!this.container.classList.contains('dragging') &&
|
||||
(container.style.transform = 'translate(' + left + 'px, ' + top + 'px)')
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {html, css, LitElement, CSSResultGroup} from 'lit'
|
||||
import {customElement, query, state} from 'lit/decorators.js'
|
||||
import {customElement, query} from 'lit/decorators.js'
|
||||
import DockChild from './dock-child'
|
||||
import customStyle from './style'
|
||||
interface DragAndDrop {
|
||||
|
@ -59,6 +59,7 @@ interface DragAndDrop {
|
|||
const DND_MOVE_THROTTLE = 50
|
||||
const DND_THRESHOLD = 5
|
||||
const DEFAULT_DND_TIMEOUT = 300
|
||||
const STATE_CHANGE_TIMEOUT = 100
|
||||
|
||||
@customElement('star-dock')
|
||||
export default class StarDock extends LitElement {
|
||||
|
@ -111,27 +112,40 @@ export default class StarDock extends LitElement {
|
|||
},
|
||||
}
|
||||
|
||||
appendContainerChild = (element: HTMLElement, options?: number) => {
|
||||
appendContainerChild = (
|
||||
element: HTMLElement,
|
||||
order?: number,
|
||||
callback?: Function
|
||||
) => {
|
||||
const child =
|
||||
this.getChildByElement(element) || new DockChild(element, this)
|
||||
this._children.push(child)
|
||||
this.container.appendChild(child.master)
|
||||
if (typeof order == 'number') {
|
||||
child.order = order
|
||||
}
|
||||
this.changeState(child, 'added', callback)
|
||||
}
|
||||
|
||||
removeContainerChild = (element: HTMLElement) => {
|
||||
removeContainerChild = (element: HTMLElement, callback?: Function) => {
|
||||
const target = this.getChildByElement(element)
|
||||
if (!target) return null
|
||||
this._children = this._children.filter((child) => child !== target)
|
||||
this.changeState(target, 'removed', callback)
|
||||
target.master.remove()
|
||||
return target
|
||||
}
|
||||
realRemoveChild = (element: HTMLElement) => {}
|
||||
realRemoveChild = (element: HTMLElement) => {
|
||||
element
|
||||
}
|
||||
|
||||
realInsertBefore = (element: HTMLElement, reference: HTMLElement) => {
|
||||
element.style.order = reference.style.order
|
||||
this.container.insertBefore(element, reference)
|
||||
}
|
||||
|
||||
realInsertAfter = (element: HTMLElement, reference: HTMLElement) => {
|
||||
element.style.order = reference.style.order
|
||||
if (reference.nextSibling) {
|
||||
this.container.insertBefore(element, reference.nextElementSibling)
|
||||
} else {
|
||||
|
@ -142,10 +156,14 @@ export default class StarDock extends LitElement {
|
|||
|
||||
synchronise() {
|
||||
for (const child of this._children) {
|
||||
child.master.style.order = String(child.order)
|
||||
child.synchroniseContainer()
|
||||
}
|
||||
|
||||
this.reorderChild()
|
||||
if (this._children.length) {
|
||||
this._gridSize = this._children[0].master.offsetWidth
|
||||
}
|
||||
}
|
||||
|
||||
reorderChild() {
|
||||
|
@ -188,7 +206,6 @@ export default class StarDock extends LitElement {
|
|||
handleEvent(event: TouchEvent) {
|
||||
switch (event.type) {
|
||||
case 'touchstart':
|
||||
case 'click':
|
||||
case 'mousedown':
|
||||
if (this._dnd.active || this._dnd.timeout) {
|
||||
break
|
||||
|
@ -217,7 +234,10 @@ export default class StarDock extends LitElement {
|
|||
// Find the child
|
||||
let children = [...this._children]
|
||||
for (let child of children) {
|
||||
if (child.element === target || child.master === target) {
|
||||
if (
|
||||
child.master === target ||
|
||||
child.master.compareDocumentPosition(target) & 16
|
||||
) {
|
||||
this._dnd.child = child
|
||||
break
|
||||
}
|
||||
|
@ -276,6 +296,8 @@ export default class StarDock extends LitElement {
|
|||
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX)
|
||||
const centerY =
|
||||
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY)
|
||||
const gridHeight = this._dnd.child.master.offsetHeight
|
||||
const gridWidth = this._dnd.child.master.offsetWidth
|
||||
if (centerY < this.offsetTop) {
|
||||
this.dropPosition = 'outter'
|
||||
this.dispatchEvent(
|
||||
|
@ -284,6 +306,8 @@ export default class StarDock extends LitElement {
|
|||
target: this._dnd.child.element,
|
||||
centerX,
|
||||
centerY,
|
||||
gridHeight,
|
||||
gridWidth,
|
||||
},
|
||||
composed: true,
|
||||
})
|
||||
|
@ -313,7 +337,7 @@ export default class StarDock extends LitElement {
|
|||
event.preventDefault()
|
||||
}
|
||||
|
||||
this.endDrag(event)
|
||||
this.endDrag()
|
||||
break
|
||||
|
||||
case 'contextmenu':
|
||||
|
@ -346,6 +370,8 @@ export default class StarDock extends LitElement {
|
|||
element: HTMLElement | DockChild
|
||||
centerX: number
|
||||
centerY: number
|
||||
gridHeight: number
|
||||
gridWidth: number
|
||||
}) => {
|
||||
const {element, centerX, centerY} = info
|
||||
const dropChild = this.getChildFromPoint(centerX, centerY)
|
||||
|
@ -362,9 +388,9 @@ export default class StarDock extends LitElement {
|
|||
|
||||
child.container.style.transform =
|
||||
'translate(' +
|
||||
(centerX - (child.master.offsetWidth || this._gridSize) / 2) +
|
||||
(centerX - this._gridSize / 2) +
|
||||
'px, ' +
|
||||
(centerY - (child.master.offsetHeight || this._gridSize) / 2) +
|
||||
(centerY - this._gridSize / 2) +
|
||||
'px)'
|
||||
|
||||
if (!dropChild) {
|
||||
|
@ -391,6 +417,7 @@ export default class StarDock extends LitElement {
|
|||
if (this.container.lastElementChild == this._dragChild!.master)
|
||||
return true
|
||||
|
||||
this._dragChild!.order = this._children.length
|
||||
this.container.appendChild(this._dragChild?.master!)
|
||||
}
|
||||
}
|
||||
|
@ -503,18 +530,28 @@ export default class StarDock extends LitElement {
|
|||
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX),
|
||||
centerY:
|
||||
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY),
|
||||
gridHeight: this._dnd.child.master.offsetHeight,
|
||||
gridWidth: this._dnd.child.master.offsetWidth,
|
||||
})
|
||||
}
|
||||
endDrag = (evt: TouchEvent) => {
|
||||
endDrag = () => {
|
||||
if (this._dnd.active) {
|
||||
const centerX =
|
||||
this._dnd.center.x + (this._dnd.last.pageX - this._dnd.start.pageX)
|
||||
const centerY =
|
||||
this._dnd.center.y + (this._dnd.last.pageY - this._dnd.start.pageY)
|
||||
const gridHeight = this._dnd.child.master.offsetHeight
|
||||
const gridWidth = this._dnd.child.master.offsetWidth
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('dock-drag-end', {
|
||||
detail: {target: this._dnd.child.element, centerX, centerY},
|
||||
detail: {
|
||||
target: this._dnd.child.element,
|
||||
centerX,
|
||||
centerY,
|
||||
gridHeight,
|
||||
gridWidth,
|
||||
},
|
||||
composed: true,
|
||||
})
|
||||
)
|
||||
|
@ -534,7 +571,9 @@ export default class StarDock extends LitElement {
|
|||
/**
|
||||
* 根据元素获取节点信息
|
||||
*/
|
||||
getElementInfo = (element: HTMLElement) => {}
|
||||
getElementInfo = (element: HTMLElement) => {
|
||||
element
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取手指落点元素
|
||||
|
@ -561,8 +600,6 @@ export default class StarDock extends LitElement {
|
|||
}
|
||||
|
||||
protected firstUpdated(): void {
|
||||
this._gridSize = 100
|
||||
|
||||
this.container.addEventListener('touchstart', this)
|
||||
this.container.addEventListener('click', this)
|
||||
this.container.addEventListener('touchmove', this)
|
||||
|
@ -577,6 +614,57 @@ export default class StarDock extends LitElement {
|
|||
this._containerOffset.left = this.container.offsetLeft
|
||||
}
|
||||
|
||||
changeState(
|
||||
child: DockChild,
|
||||
state: 'added' | 'removed',
|
||||
callback?: Function
|
||||
) {
|
||||
// Check that the child is still attached to this parent (can happen if
|
||||
// the child is removed while frozen).
|
||||
if (
|
||||
(child.master.parentElement as HTMLElement).parentNode !== this.shadowRoot
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Check for a redundant state change.
|
||||
if (child.container.classList.contains(state)) {
|
||||
return
|
||||
}
|
||||
|
||||
let animStart = (e: AnimationEvent) => {
|
||||
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)
|
||||
}
|
||||
|
||||
protected render() {
|
||||
return html`
|
||||
<div id="container"></div>
|
||||
|
@ -589,24 +677,25 @@ export default class StarDock extends LitElement {
|
|||
// position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
margin-bottom: var(--dock-margin-bottom, 60px);
|
||||
margin-bottom: var(--dock-margin-bottom);
|
||||
width: 100%;
|
||||
height: var(--dock-height, 92px);
|
||||
height: var(--dock-container-height);
|
||||
}
|
||||
|
||||
#container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: auto auto 0;
|
||||
min-width: var(--dock-min-width, 760px);
|
||||
min-width: var(--dock-min-width, 100%);
|
||||
max-width: 100%;
|
||||
height: var(--dock-height, 92px);
|
||||
height: var(--dock-container-height);
|
||||
|
||||
background-color: rgba(1, 1, 1, 0.5);
|
||||
}
|
||||
|
||||
.dock-child-master {
|
||||
max-width: var(--dock-grid-width, 92px);
|
||||
max-height: var(--dock-grid-width, 92px);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
|
@ -615,8 +704,10 @@ export default class StarDock extends LitElement {
|
|||
top: 0;
|
||||
left: 0;
|
||||
z-index: 0;
|
||||
width: var(--icon-size);
|
||||
height: var(--icon-size);
|
||||
}
|
||||
.dock-child-container:not(.dragging) {
|
||||
.dock-child-container:not(.dragging):not(.added) {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
.dock-child-container.dragging {
|
||||
|
|
|
@ -7,9 +7,10 @@ export default css`
|
|||
/** dock 与屏幕底部距离 */
|
||||
--dock-margin-bottom: var(--dock-bottom, 30px);
|
||||
/** dock 最小宽度 */
|
||||
--dock-min-width: 760px;
|
||||
// --dock-min-width: 760px;
|
||||
--dock-min-width: 100%;
|
||||
/** dock 高度 */
|
||||
--dock-height: 140px;
|
||||
--dock-container-height: var(--dock-height, 140px);
|
||||
/** dock 图标宽度 */
|
||||
--dock-grid-width: var(--icon-size, 100px);
|
||||
}
|
||||
|
|
|
@ -55,12 +55,12 @@ const DND_THRESHOLD = 5
|
|||
/**
|
||||
* 图标重叠时,确认要合并为或并入一个文件夹的时间
|
||||
*/
|
||||
const MERGE_FORDER_TIME = 700
|
||||
// const MERGE_FORDER_TIME = 700
|
||||
|
||||
/**
|
||||
* 与文件夹交互的计时器时长
|
||||
*/
|
||||
const FORDER_OPERATE_TIME = 500
|
||||
// const FORDER_OPERATE_TIME = 500
|
||||
|
||||
/**
|
||||
* 悬停交换时长
|
||||
|
@ -91,9 +91,9 @@ const cubic_bezier = (
|
|||
)
|
||||
}
|
||||
|
||||
@customElement('star-container')
|
||||
@customElement('gaia-container')
|
||||
class GaiaContainer extends LitElement {
|
||||
name: string = 'star-container'
|
||||
name: string = 'gaia-container'
|
||||
row: number = 6
|
||||
column: number = 4
|
||||
_frozen: boolean = false
|
||||
|
@ -275,7 +275,9 @@ class GaiaContainer extends LitElement {
|
|||
}
|
||||
}
|
||||
}
|
||||
window.addEventListener('resize', this.changeLayout)
|
||||
window.addEventListener('resize', () => {
|
||||
this.firstUpdated().then(this.changeLayout)
|
||||
})
|
||||
this.dndObserver = new MutationObserver(dndObserverCallback)
|
||||
|
||||
dndObserverCallback()
|
||||
|
@ -354,7 +356,7 @@ class GaiaContainer extends LitElement {
|
|||
// 同时触发划动时,不同触发原因的优先级顺序,越后越优先
|
||||
typeIndex = ['reset', 'swipe', 'mouseup', 'touchend']
|
||||
// 划动计时器
|
||||
timer: number | undefined = undefined
|
||||
timer: Function | undefined = undefined
|
||||
// 触发划动的原因类型
|
||||
slideType: string = ''
|
||||
|
||||
|
@ -362,20 +364,29 @@ class GaiaContainer extends LitElement {
|
|||
if (
|
||||
!element ||
|
||||
this.typeIndex.indexOf(this.slideType) > this.typeIndex.indexOf(type)
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.slideType = ''
|
||||
}
|
||||
const targetPagination = this.pages.indexOf(element)
|
||||
const animateTime = 450
|
||||
const target = -element.offsetLeft
|
||||
const origin = this.offsetX
|
||||
// 移动总距离
|
||||
const distance = target - origin
|
||||
const startTime = new Date().getTime()
|
||||
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('pagination-change', {
|
||||
detail: targetPagination,
|
||||
composed: true,
|
||||
})
|
||||
)
|
||||
|
||||
this.slideType = type
|
||||
this.timer = setInterval(() => {
|
||||
this.timer = () => {
|
||||
requestAnimationFrame(() => {
|
||||
const cur = new Date().getTime()
|
||||
const t = (cur - startTime) / animateTime
|
||||
|
@ -394,7 +405,7 @@ class GaiaContainer extends LitElement {
|
|||
this._dnd.top +
|
||||
'px)'
|
||||
// 控制与文件夹交互时的拖拽操作
|
||||
const child = this._dnd.child as unknown as GaiaContainerChild
|
||||
// const child = this._dnd.child as unknown as GaiaContainerChild
|
||||
// if (child) {
|
||||
// child.container.style.setProperty(
|
||||
// '--offset-position-left',
|
||||
|
@ -408,7 +419,7 @@ class GaiaContainer extends LitElement {
|
|||
}
|
||||
|
||||
if (ratio >= 1) {
|
||||
clearInterval(this.timer)
|
||||
// clearInterval(this.timer)
|
||||
this.timer = undefined
|
||||
this.slideType = ''
|
||||
this.offsetX = target
|
||||
|
@ -420,9 +431,12 @@ class GaiaContainer extends LitElement {
|
|||
this.status &= ~STATUS.SWIPE
|
||||
// 如果处于拖拽状态则更新一次落点位置
|
||||
this.continueDrag()
|
||||
} else if (this.timer) {
|
||||
this.timer()
|
||||
}
|
||||
})
|
||||
}, 10)
|
||||
}
|
||||
this.timer()
|
||||
}
|
||||
|
||||
destroyFolder = (evt: Event) => {
|
||||
|
@ -439,6 +453,12 @@ class GaiaContainer extends LitElement {
|
|||
return this.shadowRoot && this.shadowRoot.querySelector('style')
|
||||
}
|
||||
|
||||
get elements() {
|
||||
return this._children.map((child) => {
|
||||
return child.element
|
||||
})
|
||||
}
|
||||
|
||||
get offsetX() {
|
||||
return this._offsetX
|
||||
}
|
||||
|
@ -595,6 +615,7 @@ class GaiaContainer extends LitElement {
|
|||
getFolderGridIdByCoordinate(x: number, y: number, pagination: number = 0) {
|
||||
if (!this.openedFolder || !this.openedFolder._status) return -1
|
||||
let page = this.pages[this.openedFolder.pagination]
|
||||
pagination
|
||||
|
||||
x += page.scrollLeft - page.offsetLeft - this.openedFolder._lastMasterLeft!
|
||||
y += page.scrollTop - page.offsetTop - this.openedFolder._lastMasterTop!
|
||||
|
@ -663,7 +684,6 @@ class GaiaContainer extends LitElement {
|
|||
}
|
||||
} else {
|
||||
// 不是拖拽中的元素,放入下一页
|
||||
this.realRemoveChild(element)
|
||||
this.realAppendChild(++pagination, element)
|
||||
}
|
||||
}
|
||||
|
@ -734,7 +754,7 @@ class GaiaContainer extends LitElement {
|
|||
// 越界后重新拿出来放入下一个页面
|
||||
if (!this._dnd.child && pagination) {
|
||||
// 非拖拽元素导致的越界,后插元素直接加入下一个页面
|
||||
return this.realAppendChild(+pagination + 1, arguments[0])
|
||||
return this.realAppendChild(+pagination + 1, args[0])
|
||||
}
|
||||
|
||||
// 同时记录被后插元素为无法交换元素
|
||||
|
@ -785,14 +805,8 @@ class GaiaContainer extends LitElement {
|
|||
|
||||
removeContainerChild(element: HTMLElement, callback?: Function) {
|
||||
let children = this._children
|
||||
let childToRemove: GaiaContainerChild | null = null
|
||||
|
||||
for (let child of children) {
|
||||
if (child.element === element) {
|
||||
childToRemove = child
|
||||
break
|
||||
}
|
||||
}
|
||||
let childToRemove: GaiaContainerChild | null =
|
||||
this.getChildByElement(element)
|
||||
|
||||
if (childToRemove === null) {
|
||||
throw 'removeChild called on unknown child'
|
||||
|
@ -1012,11 +1026,9 @@ class GaiaContainer extends LitElement {
|
|||
let referenceIndex = -1
|
||||
|
||||
if (reference !== null) {
|
||||
for (
|
||||
let i = 0, child = children[i], iLen = children.length;
|
||||
i < iLen;
|
||||
i++
|
||||
) {
|
||||
for (let i = 0, iLen = children.length; i < iLen; i++) {
|
||||
const child = children[i]
|
||||
|
||||
if (child.element === reference) {
|
||||
referenceIndex = i
|
||||
break
|
||||
|
@ -1036,12 +1048,11 @@ class GaiaContainer extends LitElement {
|
|||
}
|
||||
}
|
||||
|
||||
children.push(childToInsert)
|
||||
if (folderName && this.folders[folderName]) {
|
||||
// 属于文件夹内的图标
|
||||
children.push(childToInsert)
|
||||
this.folders[folderName].addAppIcon(childToInsert.master)
|
||||
} else if (referenceIndex === -1) {
|
||||
children.push(childToInsert)
|
||||
this.realAppendChild(pagination ?? 0, childToInsert.master)
|
||||
} else {
|
||||
const referenceNode = children[referenceIndex].folderName
|
||||
|
@ -1053,20 +1064,24 @@ class GaiaContainer extends LitElement {
|
|||
|
||||
if (folderName && !this.folders[folderName]) {
|
||||
// 有文件夹名但不存在该文件夹,则将该图标转化为文件夹
|
||||
this.appToFolder(childToInsert.master)
|
||||
// this.appToFolder(childToInsert.master)
|
||||
}
|
||||
|
||||
childToInsert.isWidget && (childToInsert.isStatic = true)
|
||||
|
||||
this.changeState(childToInsert, 'added', callback)
|
||||
// this.synchronise()
|
||||
childToInsert.synchroniseContainer()
|
||||
const setGridId = () => {
|
||||
childToInsert.gridId = this.getGridIdByCoordinate(
|
||||
childToInsert._lastMasterLeft!,
|
||||
childToInsert._lastMasterTop!,
|
||||
childToInsert.pagination
|
||||
)
|
||||
if (anchorCoordinate) {
|
||||
childToInsert.anchor()
|
||||
} else {
|
||||
childToInsert.gridId = this.getGridIdByCoordinate(
|
||||
childToInsert.master.offsetLeft,
|
||||
childToInsert.master.offsetTop,
|
||||
childToInsert.pagination
|
||||
)
|
||||
}
|
||||
childToInsert.synchroniseContainer()
|
||||
}
|
||||
if (this.ready) {
|
||||
setGridId()
|
||||
|
@ -1190,7 +1205,8 @@ class GaiaContainer extends LitElement {
|
|||
// TODO:还需要考虑跨文件夹移动
|
||||
if (
|
||||
typeof child?.pagination == 'number' &&
|
||||
child.pagination !== this._dnd.child.pagination
|
||||
child.pagination !== this._dnd.child.pagination &&
|
||||
this._dnd.child
|
||||
) {
|
||||
// 当被选中元素与被移动元素页码不一致时,+
|
||||
this._dnd.isSpanning = true
|
||||
|
@ -1282,7 +1298,7 @@ class GaiaContainer extends LitElement {
|
|||
this._dnd.child.container.classList.add('dragging')
|
||||
// this._dnd.child.isStatic = false
|
||||
// this._dnd.child.container.style.position = "fixed";
|
||||
let rect = this.getBoundingClientRect()
|
||||
// let rect = this.getBoundingClientRect()
|
||||
// this._dnd.child.container.style.top = rect.top + 'px'
|
||||
// this._dnd.child.container.style.left = rect.left - this.offsetX + 'px'
|
||||
this._dnd.pagination = this.pagination
|
||||
|
@ -1375,28 +1391,24 @@ class GaiaContainer extends LitElement {
|
|||
const distanceY =
|
||||
gridY ??
|
||||
this._dnd.gridPosition.y + this._dnd.last.pageY - this._dnd.start.pageY
|
||||
let {dropTarget, dropChild, isPage, pagination, gridId} =
|
||||
this.getChildFromPoint(distanceX, distanceY)
|
||||
let {dropTarget, dropChild, isPage, gridId} = this.getChildFromPoint(
|
||||
distanceX,
|
||||
distanceY
|
||||
)
|
||||
const child = this._dnd.child
|
||||
let dropStatus = false
|
||||
|
||||
// while (gridId < 0) {
|
||||
// gridId += this.column
|
||||
// }
|
||||
// while (gridId > 23) {
|
||||
// gridId -= this.column
|
||||
// }
|
||||
|
||||
if (
|
||||
this._staticElements.includes(dropTarget) &&
|
||||
(child !== dropChild || (gridId == dropChild.gridId && mode == 'delay'))
|
||||
) {
|
||||
// @ts-ignore
|
||||
return
|
||||
}
|
||||
|
||||
this._dnd.dropTarget = dropTarget
|
||||
// 拖拽元素悬浮页面默认为当前页面
|
||||
const suspendingPage = isPage ? dropTarget! : this.pages[this.pagination]
|
||||
// const suspendingPage = isPage ? dropTarget! : this.pages[this.pagination]
|
||||
if (child.isTail && isPage) {
|
||||
if (this._dnd.lastDropChild) {
|
||||
this._dnd.lastDropChild.master.classList.remove('merging')
|
||||
|
@ -1624,6 +1636,8 @@ class GaiaContainer extends LitElement {
|
|||
centerY: number
|
||||
row: number
|
||||
column: number
|
||||
gridHeight: number
|
||||
gridWidth: number
|
||||
}
|
||||
) {
|
||||
this.dragInType = DragInType.PAGES
|
||||
|
@ -1646,20 +1660,13 @@ class GaiaContainer extends LitElement {
|
|||
this._dnd.child.container.classList.add('dragging')
|
||||
}
|
||||
|
||||
centerX =
|
||||
centerX -
|
||||
(this._dnd.child.column / 2 + 0.25) * this.gridWidth +
|
||||
this.left +
|
||||
page.offsetLeft
|
||||
centerY =
|
||||
centerY -
|
||||
(this._dnd.child.row / 2 + 0.5) * this.gridHeight +
|
||||
this.top +
|
||||
page.offsetTop
|
||||
gridX = centerX + this.gridWidth / 2
|
||||
gridY = centerY + this.gridHeight / 2
|
||||
let containerX = centerX - this.gridWidth / 2 - this.left
|
||||
let containerY = centerY - this.gridHeight / 2 - this.top
|
||||
|
||||
this._dnd.child.container.style.transform = `translate(${centerX}px, ${centerY}px)`
|
||||
gridX = containerX + this.gridWidth / 2
|
||||
gridY = containerY + this.gridHeight / 2
|
||||
|
||||
this._dnd.child.container.style.transform = `translate(${containerX}px, ${containerY}px)`
|
||||
}
|
||||
this.dropElement(mode, true, gridX, gridY)
|
||||
}
|
||||
|
@ -1772,6 +1779,17 @@ class GaiaContainer extends LitElement {
|
|||
|
||||
endDrag(event: Event) {
|
||||
if (this._dnd.active) {
|
||||
const centerX =
|
||||
this.left +
|
||||
this._dnd.center.x +
|
||||
(this._dnd.last.pageX - this._dnd.start.pageX)
|
||||
const centerY =
|
||||
this.top +
|
||||
this._dnd.center.y +
|
||||
(this._dnd.last.pageY - this._dnd.start.pageY)
|
||||
|
||||
const elementHeight = this._dnd.child.element.offsetHeight
|
||||
const elementWidth = this._dnd.child.element.offsetWidth
|
||||
this.dropElement('immediately')
|
||||
this.dispatchEvent(
|
||||
new CustomEvent('drag-end', {
|
||||
|
@ -1783,13 +1801,24 @@ class GaiaContainer extends LitElement {
|
|||
pageY: this._dnd.last.pageY,
|
||||
clientX: this._dnd.last.clientX,
|
||||
clientY: this._dnd.last.clientY,
|
||||
centerX,
|
||||
centerY,
|
||||
gridHeight: elementHeight,
|
||||
gridWidth: elementWidth,
|
||||
},
|
||||
composed: true,
|
||||
})
|
||||
)
|
||||
} else if (this._dnd.timeout !== null && this._dnd.child?.isFolder) {
|
||||
this._dnd.child.open()
|
||||
} else if (this._dnd.timeout !== null && this._dnd.child?.element) {
|
||||
} else if (
|
||||
!(
|
||||
this.status & // 不处于四种状态的任何一种时,才可以发送 activate 事件
|
||||
(STATUS.DRAG | STATUS.SWIPE | STATUS.TURN | STATUS.SORT)
|
||||
) &&
|
||||
this._dnd.timeout !== null &&
|
||||
this._dnd.child?.element
|
||||
) {
|
||||
let handled = !this.dispatchEvent(
|
||||
new CustomEvent('activate', {
|
||||
cancelable: true,
|
||||
|
@ -1834,7 +1863,6 @@ class GaiaContainer extends LitElement {
|
|||
case 'mousedown':
|
||||
this.istouching = true
|
||||
if (this.timer) {
|
||||
clearInterval(this.timer)
|
||||
this.timer = undefined
|
||||
this.slideType = ''
|
||||
}
|
||||
|
@ -1944,15 +1972,17 @@ class GaiaContainer extends LitElement {
|
|||
}
|
||||
|
||||
if (this._dnd.child?.priority == 1 && !this._dnd.child.isFolder) {
|
||||
const {top, left} = this.getBoundingClientRect()
|
||||
const centerX =
|
||||
left +
|
||||
this.left +
|
||||
this._dnd.center.x +
|
||||
(this._dnd.last.pageX - this._dnd.start.pageX)
|
||||
const centerY =
|
||||
top +
|
||||
this.top +
|
||||
this._dnd.center.y +
|
||||
(this._dnd.last.pageY - this._dnd.start.pageY)
|
||||
|
||||
const elementHeight = this._dnd.child.element.offsetHeight
|
||||
const elementWidth = this._dnd.child.element.offsetWidth
|
||||
if (centerY > this.offsetHeight) {
|
||||
this.dragPosition = 'outter'
|
||||
if (!this.throttle) {
|
||||
|
@ -1961,8 +1991,8 @@ class GaiaContainer extends LitElement {
|
|||
new CustomEvent('out-of-container', {
|
||||
detail: {
|
||||
element: this._dnd.child?.element,
|
||||
gridHeight: this.gridHeight,
|
||||
gridWidth: this.gridWidth,
|
||||
gridHeight: elementHeight,
|
||||
gridWidth: elementWidth,
|
||||
centerX: centerX,
|
||||
centerY: centerY,
|
||||
},
|
||||
|
@ -2181,7 +2211,7 @@ class GaiaContainer extends LitElement {
|
|||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'star-container': GaiaContainer
|
||||
'gaia-container': GaiaContainer
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -333,7 +333,7 @@ export default class ExchangeStrategy {
|
|||
if (gridId === undefined) {
|
||||
ergodic(-1 * direction)
|
||||
}
|
||||
return gridId !== undefined ? [[gridId]] : gridId
|
||||
return gridId !== undefined ? [[gridId]] : undefined
|
||||
}
|
||||
|
||||
const place = () => {
|
||||
|
@ -529,6 +529,7 @@ export default class ExchangeStrategy {
|
|||
placedRecorder?: PlacedRecorder
|
||||
childCoordinate?: GaiaContainer['childCoordinate']
|
||||
} {
|
||||
forceDrop
|
||||
const {column: mColumn} = this.manager
|
||||
// 子节点右下角单元格所在的网格ID
|
||||
const edge_bottom_right =
|
||||
|
@ -546,7 +547,7 @@ export default class ExchangeStrategy {
|
|||
this.placedRecorder = {}
|
||||
this.placedChild.add(child)
|
||||
this.pickChild(child, recorder)
|
||||
const dropChild = recorder[gridId]
|
||||
// const dropChild = recorder[gridId]
|
||||
// 获取被挤占位置的元素,按照优先级排序
|
||||
const pickChildren = this.getChildrenByGridArea(
|
||||
gridId,
|
||||
|
|
|
@ -32,7 +32,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
|
|||
gridWidth: number = 0
|
||||
|
||||
constructor(manager: GaiaContainer, name?: string) {
|
||||
super(null, 1, 1, undefined, manager)
|
||||
super(undefined, 1, 1, undefined, manager)
|
||||
this.name = this.checkAndGetFolderName(name)
|
||||
this._id = `folder-${new Date().getTime()}`
|
||||
this.init()
|
||||
|
@ -375,6 +375,7 @@ export default class GaiaContainerFolder extends GaiaContainerChild {
|
|||
|
||||
handleEvent(evt: TouchEvent) {
|
||||
switch (evt.type) {
|
||||
// @ts-ignore
|
||||
case 'touchend':
|
||||
if (this._status && evt.target === this.container) {
|
||||
this.close()
|
||||
|
|
|
@ -66,6 +66,7 @@ class GaiaContainerPage {
|
|||
div.className = `gaia-container-page`
|
||||
div.style.setProperty('--pagination', pagination)
|
||||
|
||||
// 影子页面,用于检测旋转屏幕后能否仍容纳当前页面的子节点
|
||||
const shadowPage = div.cloneNode() as HTMLElement
|
||||
shadowPage.classList.add('shadow')
|
||||
this._shadowPagesMap.set(div, shadowPage)
|
||||
|
@ -75,6 +76,14 @@ class GaiaContainerPage {
|
|||
this.observe(div)
|
||||
this._manager.childCoordinate[this._pages.length - 1] = {}
|
||||
|
||||
this._manager.dispatchEvent(
|
||||
new CustomEvent('page-change', {
|
||||
detail: {
|
||||
addIndex: this._pages.indexOf(div),
|
||||
},
|
||||
composed: true,
|
||||
})
|
||||
)
|
||||
return {
|
||||
page: div,
|
||||
shadowPage,
|
||||
|
@ -103,6 +112,14 @@ class GaiaContainerPage {
|
|||
return
|
||||
}
|
||||
delete this._pages[index]
|
||||
this._manager.dispatchEvent(
|
||||
new CustomEvent('page-change', {
|
||||
detail: {
|
||||
deleteIndex: index,
|
||||
},
|
||||
composed: true,
|
||||
})
|
||||
)
|
||||
if (index > -1) {
|
||||
page?.remove?.()
|
||||
let flag = false
|
||||
|
@ -130,6 +147,10 @@ class GaiaContainerPage {
|
|||
callback(this._pages[i], i, this._pages)
|
||||
}
|
||||
}
|
||||
|
||||
indexOf = (page: HTMLElement) => {
|
||||
return this._pages.indexOf(page)
|
||||
}
|
||||
}
|
||||
|
||||
export default GaiaContainerPage
|
||||
|
|
|
@ -2,7 +2,5 @@ import {css} from 'lit'
|
|||
|
||||
export default css`
|
||||
:host {
|
||||
/* 图标大小 */
|
||||
--icon-size: 92px;
|
||||
}
|
||||
`
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
import {html, css, LitElement, TemplateResult} from 'lit'
|
||||
import {customElement, property, query, state} from 'lit/decorators.js'
|
||||
import {html, css, LitElement} from 'lit'
|
||||
import {customElement, query, state} from 'lit/decorators.js'
|
||||
import GaiaContainer from '../../../components/grid-container/container'
|
||||
import GaiaContainerChild from '../../../components/grid-container/gaia-container-child'
|
||||
import homescreenStyle from './homescreen-style'
|
||||
import StarDock from '../../../components/dock/dock'
|
||||
import {IndicatorPagePoint} from '../../../components/indicator/indicator-page-point'
|
||||
|
||||
import './icon'
|
||||
import SiteIcon from './icon'
|
||||
|
||||
@customElement('panel-homescreen')
|
||||
export class PanelContainer extends LitElement {
|
||||
container!: GaiaContainer
|
||||
dock!: StarDock
|
||||
icons: {[prop: string]: GaiaContainerChild} = {}
|
||||
pageIndicator!: IndicatorPagePoint
|
||||
@query('.reset') resetBtn!: HTMLElement
|
||||
@query('#row') rowInput!: HTMLInputElement
|
||||
@query('#column') columnInput!: HTMLInputElement
|
||||
|
@ -59,45 +62,86 @@ export class PanelContainer extends LitElement {
|
|||
this.shadowRoot?.appendChild(this.container)
|
||||
this.container.sortMode = true
|
||||
|
||||
// 页面指示器
|
||||
this.pageIndicator = new IndicatorPagePoint()
|
||||
this.pageIndicator.edit = true
|
||||
this.shadowRoot?.appendChild(this.pageIndicator)
|
||||
|
||||
// dock
|
||||
this.dock = new StarDock()
|
||||
this.shadowRoot?.appendChild(this.dock)
|
||||
this.dock.sortMode = true
|
||||
|
||||
//
|
||||
// 存储全局变量
|
||||
;(window as any).dock = this.dock
|
||||
;(window as any).container = this.container
|
||||
;(window as any).home = this
|
||||
|
||||
// this.addAppIcon(2, 2)
|
||||
|
||||
// container 相关事件
|
||||
this.addEventListener('out-of-container', this)
|
||||
this.addEventListener('drag-return-container', this)
|
||||
this.addEventListener('out-of-dock', this)
|
||||
this.addEventListener('drag-start', this)
|
||||
this.addEventListener('drag-move', this)
|
||||
this.addEventListener('drag-end', this)
|
||||
this.addEventListener('drag-and-drop', this)
|
||||
this.addEventListener('page-change', this)
|
||||
this.addEventListener('pagination-change', this)
|
||||
|
||||
// dock 相关事件
|
||||
this.addEventListener('out-of-dock', this)
|
||||
this.addEventListener('dock-drag-start', this)
|
||||
this.addEventListener('dock-drag-move', this)
|
||||
this.addEventListener('dock-drag-end', this)
|
||||
|
||||
this.parentElement!.addEventListener('animationend', () => {
|
||||
this.container.changeLayout()
|
||||
this.addAppIcon(1, 1)
|
||||
let promise = new Promise((res) => {
|
||||
res(undefined)
|
||||
})
|
||||
for (let i = 0; i < 24; i++) {
|
||||
promise = promise.then(() => {
|
||||
return new Promise((res) => {
|
||||
this.addAppIcon(1, 1)
|
||||
res(undefined)
|
||||
let containerOrderString = localStorage.getItem('containerOrder')
|
||||
let dockOrderString = localStorage.getItem('dockOrder')
|
||||
|
||||
if (containerOrderString && dockOrderString) {
|
||||
let containerOrder: {[prop: string]: any}[] =
|
||||
JSON.parse(containerOrderString)
|
||||
let dockOrder: {[prop: string]: any}[] = JSON.parse(dockOrderString)
|
||||
|
||||
containerOrder.forEach((record) => {
|
||||
const icon = document.createElement('site-icon')
|
||||
|
||||
icon.setAttribute('color', record.color)
|
||||
icon.name = record.name
|
||||
|
||||
this.container.appendContainerChild(icon, {
|
||||
row: record.row,
|
||||
column: record.column,
|
||||
anchorCoordinate: record.anchorCoordinate,
|
||||
pagination: record.pagination,
|
||||
folderName: record.folderName,
|
||||
})
|
||||
})
|
||||
|
||||
dockOrder.forEach((record) => {
|
||||
const icon = document.createElement('site-icon')
|
||||
|
||||
icon.setAttribute('color', record.color)
|
||||
icon.name = record.name
|
||||
|
||||
this.dock.appendContainerChild(icon, record.order)
|
||||
})
|
||||
} else {
|
||||
this.addAppIcon(1, 1)
|
||||
let promise = new Promise((res) => {
|
||||
res(undefined)
|
||||
})
|
||||
for (let i = 0; i < 24; i++) {
|
||||
promise = promise.then(() => {
|
||||
return new Promise((res) => {
|
||||
this.addAppIcon(1, 1)
|
||||
res(undefined)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
this.container.synchronise()
|
||||
this.dock.synchronise()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -111,11 +155,15 @@ export class PanelContainer extends LitElement {
|
|||
handleEvent(evt: CustomEvent) {
|
||||
switch (evt.type) {
|
||||
case 'out-of-container':
|
||||
// @ts-ignore
|
||||
if (!this.prepareToTransfer) return
|
||||
const outPage = this.container.pages[this.container.pagination]
|
||||
this.dragInDock = this.dock.dragIn({
|
||||
element: this.elementPlaceholder,
|
||||
centerX: evt.detail.centerX,
|
||||
centerY: evt.detail.centerY,
|
||||
centerX: evt.detail.centerX - outPage.offsetLeft,
|
||||
centerY: evt.detail.centerY - outPage.offsetTop,
|
||||
gridHeight: evt.detail.gridHeight,
|
||||
gridWidth: evt.detail.gridWidth,
|
||||
})
|
||||
break
|
||||
case 'drag-return-container':
|
||||
|
@ -125,14 +173,17 @@ export class PanelContainer extends LitElement {
|
|||
case 'out-of-dock':
|
||||
this.prepareToTransfer = true
|
||||
|
||||
const {target, centerX, centerY} = evt.detail
|
||||
const {centerX, centerY, gridHeight, gridWidth} = evt.detail
|
||||
this.container._dnd.active = true
|
||||
const page = this.container.pages[this.container.pagination]
|
||||
this.container.dragIn('delay', {
|
||||
element: this.elementPlaceholder,
|
||||
centerX,
|
||||
centerY,
|
||||
centerX: centerX + page.offsetLeft,
|
||||
centerY: centerY + page.offsetTop,
|
||||
row: 1,
|
||||
column: 1,
|
||||
gridHeight,
|
||||
gridWidth,
|
||||
})
|
||||
break
|
||||
case 'drag-and-drop':
|
||||
|
@ -158,24 +209,28 @@ export class PanelContainer extends LitElement {
|
|||
this.container.removeContainerChild(evt.detail.target)
|
||||
}
|
||||
setTimeout(() => {
|
||||
// this.dock.removeContainerChild(this.elementPlaceholder)
|
||||
this.dock.synchronise()
|
||||
this.container._dnd.active = false
|
||||
}, 10)
|
||||
|
||||
break
|
||||
case 'dock-drag-end':
|
||||
// @ts-ignore
|
||||
if (!this.prepareToTransfer) return
|
||||
if (!this.dragInContainer) {
|
||||
// 此时拖拽进 container 标志未显示为 true 也不意味着放置失败,
|
||||
// 可能是尚未进行尝试,尝试立即放置拖拽中的图标
|
||||
const {target, centerX, centerY} = evt.detail
|
||||
const {centerX, centerY, gridHeight, gridWidth} = evt.detail
|
||||
|
||||
const page = this.container.pages[this.container.pagination]
|
||||
this.container.dragIn('immediately', {
|
||||
element: this.elementPlaceholder,
|
||||
centerX,
|
||||
centerY,
|
||||
centerX: centerX + page.offsetLeft,
|
||||
centerY: centerY + page.offsetTop,
|
||||
row: 1,
|
||||
column: 1,
|
||||
gridHeight,
|
||||
gridWidth,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -186,7 +241,6 @@ export class PanelContainer extends LitElement {
|
|||
this.container._dnd.child.container.classList.remove('dragging')
|
||||
this.container._dnd.child = undefined
|
||||
this.container.synchronise()
|
||||
this.container._dnd.active = false
|
||||
}
|
||||
|
||||
this.dock.removeContainerChild(evt.detail.target)
|
||||
|
@ -196,14 +250,57 @@ export class PanelContainer extends LitElement {
|
|||
|
||||
this.dragInContainer = false
|
||||
this.prepareToTransfer = false
|
||||
this.container._dnd.child = null
|
||||
this.container._dnd.active = false
|
||||
this.dock.synchronise()
|
||||
break
|
||||
|
||||
case 'page-change':
|
||||
this.pageIndicator.total = this.container.pages.length
|
||||
this.pageIndicator.index = this.container.pagination + 1
|
||||
break
|
||||
case 'pagination-change':
|
||||
this.pageIndicator.index = this.container.pagination + 1
|
||||
break
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@state() test!: string
|
||||
storeAppOrder() {
|
||||
let containerOrders: {[prop: string]: any} = []
|
||||
let dockOrders: {[prop: string]: any} = []
|
||||
let containerChildren = this.container._children
|
||||
let dockChildren = this.dock._children
|
||||
|
||||
containerChildren.forEach((child) => {
|
||||
const info = {
|
||||
name: (child.element as SiteIcon).name,
|
||||
color: (child.element as SiteIcon).color,
|
||||
row: child.row,
|
||||
column: child.column,
|
||||
pagination: child.pagination,
|
||||
anchorCoordinate: child.anchorCoordinate,
|
||||
forderName: child.folderName,
|
||||
}
|
||||
|
||||
containerOrders.push(info)
|
||||
})
|
||||
|
||||
dockChildren.forEach((child) => {
|
||||
const info = {
|
||||
name: (child.element as SiteIcon).name,
|
||||
color: (child.element as SiteIcon).color,
|
||||
order: child.order,
|
||||
}
|
||||
|
||||
dockOrders.push(info)
|
||||
})
|
||||
|
||||
localStorage.setItem('containerOrder', JSON.stringify(containerOrders))
|
||||
localStorage.setItem('dockOrder', JSON.stringify(dockOrders))
|
||||
}
|
||||
|
||||
@state()
|
||||
protected styles: {[subModule: string]: string} = new Proxy(
|
||||
{},
|
||||
|
@ -258,8 +355,9 @@ export class PanelContainer extends LitElement {
|
|||
--container-margin-left: 20px;
|
||||
/** 控制 dock 距离屏幕底部的距离 */
|
||||
--dock-bottom: 10px;
|
||||
--icon-size: 92px;
|
||||
}
|
||||
star-container {
|
||||
gaia-container {
|
||||
height: 80vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
@ -299,6 +397,17 @@ export class PanelContainer extends LitElement {
|
|||
border: 1px solid black;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.gaia-container-child::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
display: block;
|
||||
width: 4px;
|
||||
height: 2px;
|
||||
background-color: pink;
|
||||
}
|
||||
`,
|
||||
homescreenStyle,
|
||||
]
|
||||
|
|
|
@ -2,7 +2,7 @@ import {css} from 'lit'
|
|||
|
||||
export default css`
|
||||
/* 图标归位时的动画 */
|
||||
star-container:not(.loading)
|
||||
gaia-container:not(.loading)
|
||||
.gaia-container-child:not(.added):not(.dragging) {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
|
|
@ -15,8 +15,9 @@ export default css`
|
|||
opacity: 0;
|
||||
}
|
||||
|
||||
:host() #subtitle {
|
||||
#subtitle {
|
||||
transition: opacity 0.2s;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#image-container {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {html, css, LitElement} from 'lit'
|
||||
import {html, LitElement} from 'lit'
|
||||
import {customElement, property, query} from 'lit/decorators.js'
|
||||
import style from './icon-style'
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ export class PanelIndicators extends LitElement {
|
|||
@queryAll('.myindicator') private myindicators!: IndicatorPagePoint
|
||||
|
||||
handleEvent(evt: Event) {
|
||||
this.myindicators
|
||||
switch (evt.type) {
|
||||
case 'click':
|
||||
evt.preventDefault() // iOS上不禁止按钮默认行为,将会双击按钮强制放缩屏幕
|
||||
|
|
Loading…
Reference in New Issue