Files
VRCX/src/vr.pug
Natsumi 938fff63d0 Electron support for Linux (#1074)
* init

* SQLite changes

* Move html folder, edit build scripts

* AppApi interface

* Build flags

* AppApi inheritance

* Finishing touches

* Merge upstream changes

* Test CI

* Fix class inits

* Rename AppApi

* Merge upstream changes

* Fix SQLiteLegacy on Linux, Add Linux interop, build tools

* Linux specific localisation strings

* Make it run

* Bring back most of Linux functionality

* Clean up

* Fix TTS voices

* Fix UI var

* Changes

* Electron minimise to tray

* Remove separate toggle for WlxOverlay

* Fixes

* Touchups

* Move csproj

* Window zoom, Desktop Notifications, VR check on Linux

* Fix desktop notifications, VR check spam

* Fix building on Linux

* Clean up

* Fix WebApi headers

* Rewrite VRCX updater

* Clean up

* Linux updater

* Add Linux to build action

* init

* SQLite changes

* Move html folder, edit build scripts

* AppApi interface

* Build flags

* AppApi inheritance

* Finishing touches

* Merge upstream changes

* Test CI

* Fix class inits

* Rename AppApi

* Merge upstream changes

* Fix SQLiteLegacy on Linux, Add Linux interop, build tools

* Linux specific localisation strings

* Make it run

* Bring back most of Linux functionality

* Clean up

* Fix TTS voices

* Changes

* Electron minimise to tray

* Remove separate toggle for WlxOverlay

* Fixes

* Touchups

* Move csproj

* Window zoom, Desktop Notifications, VR check on Linux

* Fix desktop notifications, VR check spam

* Fix building on Linux

* Clean up

* Fix WebApi headers

* Rewrite VRCX updater

* Clean up

* Linux updater

* Add Linux to build action

* Test updater

* Rebase and handle merge conflicts

* Fix Linux updater

* Fix Linux app restart

* Fix friend order

* Handle AppImageInstaller, show an install message on Linux

* Updates to the AppImage installer

* Fix Linux updater, fix set version, check for .NET, copy wine prefix

* Handle random errors

* Rotate tall prints

* try fix Linux restart bug

* Final

---------

Co-authored-by: rs189 <35667100+rs189@users.noreply.github.com>
2025-01-11 13:09:44 +13:00

590 lines
53 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
doctype html
html
head
meta(http-equiv="Content-Type" content="text/html;charset=utf-8")
meta(http-equiv="Cache-Control" content="no-cache")
meta(http-equiv="referrer" content="no-referrer")
meta(http-equiv="viewport" content="width=device-width,initial-scale=1,user-scalable=no")
title VRCXVR
link(rel="stylesheet" href="vr.css")
link(rel="stylesheet" href="flags.css")
body
.x-app#x-app(class="x-app-type" :class="{ background: appType === '1' && config && config.backgroundEnabled }")
template(v-if="appType === '1'")
.x-container(style="flex:1")
.x-friend-list(ref="list" style="color:#aaa")
template(v-if="config && config.minimalFeed")
template(v-for="feed in wristFeed")
.x-friend-item(v-if="feed.type === 'GPS'" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
i.el-icon-loading(v-if="feed.isTraveling" style="margin-right:5px")
| #[span.name(v-text="feed.displayName")] #[location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")]
div(v-else-if="feed.type === 'Offline'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] ✖️
div(v-else-if="feed.type === 'Online'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] ✔
template(v-if="feed.worldName")
| #[location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName" style="margin-left:5px")]
div(v-else-if="feed.type === 'Status'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" style="margin-right:5px")]
template(v-if="feed.statusDescription === feed.previousStatusDescription")
i.x-user-status(:class="statusClass(feed.previousStatus)")
i.el-icon-right
i.x-user-status(:class="statusClass(feed.status)")
template(v-else)
| #[i.x-user-status(:class="statusClass(feed.status)")] {{feed.statusDescription}}
div(v-else-if="feed.type === 'OnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ▶️ #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
div(v-else-if="feed.type === 'OnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ◀️ #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
div(v-else-if="feed.type === 'OnPlayerJoining'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
span.spin ▶️
span.name(v-text="feed.displayName" style="margin-left:30px")
div(v-else-if="feed.type === 'Location'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")
div(v-else-if="feed.type === 'VideoPlay'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🎵 #[span.name(v-if="feed.displayName" v-text="feed.displayName" style="margin-right:5px" :style="{'color':feed.tagColour}")]
template(v-if="feed.videoName")
| #[span(v-text="feed.videoName")]
template(v-else)
| #[span(v-text="feed.videoUrl")]
div(v-else-if="feed.type === 'invite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 📨 #[span.name(v-text="feed.senderUsername")] #[location(:location="feed.details.worldId" :hint="feed.details.worldName")] #[span(v-text="feed.details.inviteMessage")]
div(v-else-if="feed.type === 'requestInvite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 📩 #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.details.requestMessage")]
div(v-else-if="feed.type === 'inviteResponse'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💬 #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.details.responseMessage")]
div(v-else-if="feed.type === 'requestInviteResponse'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💬 #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.details.responseMessage")]
div(v-else-if="feed.type === 'friendRequest'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💚 #[span.name(v-text="feed.senderUsername")]
div(v-else-if="feed.type === 'Friend'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💖 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'Unfriend'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💔 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'DisplayName'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 📃 #[span.name(v-text="feed.previousDisplayName")] #[i.el-icon-right] #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'TrustLevel'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🤝 #[span.name(v-text="feed.displayName")] {{ feed.previousTrustLevel }} #[i.el-icon-right] {{ feed.trustLevel }}
div(v-else-if="feed.type === 'boop'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 👉 #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.message")]
div(v-else-if="feed.type === 'groupChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.message")]
div(v-else-if="feed.type === 'group.announcement'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.informative'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.invite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.joinRequest'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.transfer'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🏷️ #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.queueReady'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 📨 #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'instance.closed'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 📫 #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'PortalSpawn'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
template(v-if="feed.displayName")
| ✨ #[span.name(v-text="feed.displayName" style="margin-right:5px" :style="{'color':feed.tagColour}")]
| #[location(:location="feed.instanceId" :hint="feed.worldName" :grouphint="feed.groupName")]
template(v-else)
| ✨ User has spawned a portal
div(v-else-if="feed.type === 'AvatarChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🧍 #[span.name(v-text="feed.displayName" style="margin-right:5px" :style="{'color':feed.tagColour}")]
template(v-if="feed.releaseStatus === 'public'")
| #[i.x-user-status.online]&nbsp;
template(v-else-if="feed.releaseStatus === 'private'")
| #[i.x-user-status.askme]&nbsp;
| {{ feed.name }}
template(v-if="feed.description && feed.description !== feed.name")
| - {{ feed.description }}
div(v-else-if="feed.type === 'ChatBoxMessage'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 💬 #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] #[span(v-text="feed.text")]
div(v-else-if="feed.type === 'Event'" class="x-friend-item")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🛑 #[span.name(v-text="feed.data")]
div(v-else-if="feed.type === 'External'" class="x-friend-item")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🟠 #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'BlockedOnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ▶️ 🚫 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'BlockedOnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ◀️ 🚫 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'MutedOnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ▶️ 🔇 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'MutedOnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ◀️ 🔇 #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'Blocked'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🚫 #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
div(v-else-if="feed.type === 'Unblocked'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| ⭕ #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
div(v-else-if="feed.type === 'Muted'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🔇 #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
div(v-else-if="feed.type === 'Unmuted'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| 🎤 #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
template(v-else)
template(v-for="feed in wristFeed")
.x-friend-item(v-if="feed.type === 'GPS'" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
template(v-if="feed.isTraveling")
| #[span.name(v-text="feed.displayName")] is traveling to #[location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")]
template(v-else)
| #[span.name(v-text="feed.displayName")] is in #[location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")]
div(v-else-if="feed.type === 'Offline'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] has logged out
div(v-else-if="feed.type === 'Online'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")]
span(style="margin-left:5px;margin-right:5px") has logged in
template(v-if="feed.worldName")
| to #[location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")]
div(v-else-if="feed.type === 'Status'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" style="margin-right:5px")]
template(v-if="feed.statusDescription === feed.previousStatusDescription")
i.x-user-status(:class="statusClass(feed.previousStatus)")
i.el-icon-right
i.x-user-status(:class="statusClass(feed.status)")
template(v-else)
| #[i.x-user-status(:class="statusClass(feed.status)")] {{feed.statusDescription}}
div(v-else-if="feed.type === 'OnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has joined
div(v-else-if="feed.type === 'OnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has left
div(v-else-if="feed.type === 'OnPlayerJoining'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] is joining
div(v-else-if="feed.type === 'Location'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName")
div(v-else-if="feed.type === 'VideoPlay'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
span(style="margin-left:5px;margin-right:5px") changed video to
template(v-if="feed.videoName")
| #[span(v-text="feed.videoName")]
template(v-else)
| #[span(v-text="feed.videoUrl")]
div(v-else-if="feed.type === 'invite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] has invited you to #[location(:location="feed.details.worldId" :hint="feed.details.worldName")] #[span(v-text="feed.details.inviteMessage")]
div(v-else-if="feed.type === 'requestInvite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] has requested an invite #[span(v-text="feed.details.requestMessage")]
div(v-else-if="feed.type === 'inviteResponse'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] has responded to your invite #[span(v-text="feed.details.responseMessage")]
div(v-else-if="feed.type === 'requestInviteResponse'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] has responded to your invite request #[span(v-text="feed.details.responseMessage")]
div(v-else-if="feed.type === 'friendRequest'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] has sent you a friend request
div(v-else-if="feed.type === 'Friend'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] is now your friend
div(v-else-if="feed.type === 'Unfriend'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] is no longer your friend
div(v-else-if="feed.type === 'DisplayName'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.previousDisplayName")] changed their name to #[span.name(v-text="feed.displayName")]
div(v-else-if="feed.type === 'TrustLevel'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName")] trust level is now {{ feed.trustLevel }}
div(v-else-if="feed.type === 'boop'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.message")]
div(v-else-if="feed.type === 'groupChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.senderUsername")] #[span(v-text="feed.message")]
div(v-else-if="feed.type === 'group.announcement'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.informative'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.invite'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.joinRequest'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.transfer'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'group.queueReady'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'instance.closed'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'PortalSpawn'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
template(v-if="feed.displayName")
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has spawned a portal to
| #[location(:location="feed.instanceId" :hint="feed.worldName" :grouphint="feed.groupName" style="margin-left:5px")]
template(v-else)
| User has spawned a portal
div(v-else-if="feed.type === 'AvatarChange'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")]
span(style="margin-left:5px;margin-right:5px") changed into avatar
template(v-if="feed.releaseStatus === 'public'")
| #[i.x-user-status.online]
template(v-else)
| #[i.x-user-status.askme]
| {{ feed.name }}
template(v-if="feed.description && feed.description !== feed.name")
| - {{ feed.description }}
div(v-else-if="feed.type === 'ChatBoxMessage'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] said #[span(v-text="feed.text")]
div(v-else-if="feed.type === 'Event'" class="x-friend-item")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| Event: #[span.name(v-text="feed.data")]
div(v-else-if="feed.type === 'External'" class="x-friend-item")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| External: #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] #[span.name(v-text="feed.message")]
div(v-else-if="feed.type === 'BlockedOnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| Blocked user #[span.name(v-text="feed.displayName")] has joined
div(v-else-if="feed.type === 'BlockedOnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| Blocked user #[span.name(v-text="feed.displayName")] has left
div(v-else-if="feed.type === 'MutedOnPlayerJoined'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| Muted user #[span.name(v-text="feed.displayName")] has joined
div(v-else-if="feed.type === 'MutedOnPlayerLeft'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| Muted user #[span.name(v-text="feed.displayName")] has left
div(v-else-if="feed.type === 'Blocked'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has blocked you
div(v-else-if="feed.type === 'Unblocked'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has unblocked you
div(v-else-if="feed.type === 'Muted'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has muted you
div(v-else-if="feed.type === 'Unmuted'" class="x-friend-item" :class="{ friend: feed.isFriend, favorite: feed.isFavorite }")
.detail
span.extra
span.time {{ feed.created_at | formatDate }}
| #[span.name(v-text="feed.displayName" :style="{'color':feed.tagColour}")] has unmuted you
.x-containerbottom
div(style="display:flex;flex-direction:row;flex-wrap:wrap")
div(v-for="device in devices" class="tracker-container")
div(v-if="device[0] === 'headset'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/headset_quest_status_off.png" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-else-if="device[2] === 'charging'" src="images/headset_quest_status_ready_charging.png")
img(v-else-if="device[3] < 20" src="images/headset_quest_status_ready_low.png")
img(v-else src="images/headset_quest_status_ready.png")
span {{ device[3] }}%
div(v-if="device[0] === 'leftController'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/left_controller_status_off.png" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-else-if="device[2] === 'charging'" src="images/left_controller_status_ready_charging.png")
img(v-else-if="device[3] < 20" src="images/left_controller_status_ready_low.png")
img(v-else src="images/left_controller_status_ready.png")
span {{ device[3] }}%
div(v-else-if="device[0] === 'rightController'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/right_controller_status_off.png")
img(v-else-if="device[2] === 'charging'" src="images/right_controller_status_ready_charging.png")
img(v-else-if="device[3] < 20" src="images/right_controller_status_ready_low.png")
img(v-else src="images/right_controller_status_ready.png")
span {{ device[3] }}%
div(v-else-if="device[0] === 'controller'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/controller_status_off.png")
img(v-else-if="device[2] === 'charging'" src="images/controller_status_ready_charging.png")
img(v-else-if="device[3] < 20" src="images/controller_status_ready_low.png")
img(v-else src="images/controller_status_ready.png")
span {{ device[3] }}%
div(v-else-if="device[0] === 'tracker'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/tracker_status_off.png")
img(v-else-if="device[2] === 'charging'" src="images/tracker_status_ready_charging.png")
img(v-else-if="device[3] < 20" src="images/tracker_status_ready_low.png")
img(v-else src="images/tracker_status_ready.png")
span {{ device[3] }}%
div(v-else-if="device[0] === 'base'" class="tracker-device" :class="trackingResultToClass(device[4])")
img(v-if="device[1] !== 'connected'" src="images/base_status_off.png")
img(v-else src="images/base_status_ready.png")
span(v-if="device[3] !== 100") {{ device[3] }}x
.x-containerbottom
template(v-if="nowPlaying.playing")
span(style="float:right;padding-left:10px") {{ nowPlaying.remainingText }}
marquee-text {{ nowPlaying.name }}
div.np-progress-bar(:style="{ width: nowPlaying.percentage + '%' }")
template(v-if="lastLocation.date !== 0")
template(v-if="config && config.minimalFeed")
span(style="float:right") {{ lastLocationTimer }}
template(v-if="onlineForTimer")
|&nbsp;/ {{ onlineForTimer }}
template(v-if="pcUptime")
|&nbsp;/ {{ pcUptime }}
span(style="display:inline-block") {{ lastLocation.playerList.length }}
span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? ` (${lastLocation.friendList.length})` : ''}}
template(v-else)
span(style="float:right") {{ $t('vr.status.timer') }} {{ lastLocationTimer }}
template(v-if="onlineForTimer")
|&nbsp;/ {{ onlineForTimer }}
template(v-if="pcUptime")
|&nbsp;/ {{ pcUptime }}
span(style="display:inline-block") {{ $t('vr.status.players') }} {{ lastLocation.playerList.length }}
span(style="display:inline-block;font-weight:bold") {{ lastLocation.friendList.length !== 0 ? ` (${lastLocation.friendList.length})` : ''}}
br
span(style="float:right") {{ currentTime }}
span(v-if="config && cpuUsageEnabled" style="display:inline-block;margin-right:5px") {{ $t('vr.status.cpu') }} {{ cpuUsage }}%
span(style="display:inline-block") {{ $t('vr.status.online') }} {{ onlineFriendCount }} {{ customInfo }}
template(v-else)
svg(class="np-progress-circle")
circle(class="np-progress-circle-stroke" cx="60" cy="60" stroke="white" r="30" fill="transparent" stroke-width="60")
.hud-feed
div(v-for="feed in hudFeed")
.item(:class="{ friend: feed.isFriend, favorite: feed.isFavorite }") #[span(v-if="feed.isMaster") 👑]#[span(v-if="feed.isModerator") ⚔️]#[strong.name(v-text="feed.displayName" :style="{'color':feed.colour}")]
template(v-if="feed.type === 'ChangeAvatar'")
span(style="margin-left:10px;color:#a3a3a3") ChangeAvatar
span(v-if="!feed.inCache" style="color:#aaa;margin-left:10px") #[i.el-icon-download]
span(v-text="feed.avatar.name" style="margin-left:10px")
span(v-if="feed.avatar.releaseStatus === 'public'" style="margin-left:10px;color:#67c23a") (Public)
span(v-else-if="feed.avatar.releaseStatus === 'private'" style="margin-left:10px;color:#e6a23c") (Private)
template(v-else-if="feed.type === 'ChangeStatus'")
span(style="margin-left:10px;color:#a3a3a3") ChangeStatus
span(v-if="feed.status !== feed.previousStatus")
i.x-user-status(:class="statusClass(feed.previousStatus)" style="margin-left:10px;width:20px;height:20px")
span
i.el-icon-right
i.x-user-status(:class="statusClass(feed.status)" style="width:20px;height:20px")
span(v-if="feed.statusDescription !== feed.previousStatusDescription" v-text="feed.statusDescription" style="margin-left:10px")
template(v-else-if="feed.type === 'ChangeGroup'")
span(style="margin-left:10px;color:#a3a3a3") ChangeGroup
span(v-text="feed.groupName" style="margin-left:10px")
template(v-else-if="feed.type === 'ChatBoxMessage'")
span(style="margin-left:10px;color:#a3a3a3") ChatBox
span(v-text="feed.text" style="margin-left:10px;white-space:normal")
template(v-else-if="feed.type === 'PortalSpawn'")
span(style="margin-left:10px;color:#a3a3a3") PortalSpawn
location(:location="feed.location" :hint="feed.worldName" :grouphint="feed.groupName" :link="false" style="margin-left:10px")
template(v-else-if="feed.type === 'OnPlayerJoined'")
span(style="margin-left:10px;color:#a3a3a3") has joined
span(v-if="feed.platform === 'Desktop'" style="color:#409eff;margin-left:10px") Desktop
span(v-else-if="feed.platform === 'VR'" style="color:#409eff;margin-left:10px") VR
span(v-else-if="feed.platform === 'Quest'" style="color:#67c23a;margin-left:10px") Quest
span(v-else-if="feed.platform === 'iOS'" style="color:#c7c7ce;margin-left:10px") iOS
span(v-if="!feed.inCache" style="color:#aaa;margin-left:10px") #[i.el-icon-download]
span(v-text="feed.avatar.name" style="margin-left:10px")
template(v-else-if="feed.type === 'SpawnEmoji'")
span(style="margin-left:10px;color:#a3a3a3") SpawnEmoji
span(v-text="feed.text" style="margin-left:10px")
span(v-else-if="feed.color === 'yellow'" v-text="feed.text" style="color:yellow;margin-left:10px")
span(v-else style="margin-left:10px;color:#a3a3a3" v-text="feed.text")
template(v-if="feed.combo > 1")
span.combo(style="margin-left:10px") x{{ feed.combo }}
.hud-timeout(v-if="hudTimeout.length > 0")
.hud-timeout-feed
div(v-for="feed in hudTimeout")
p.item ({{ feed.time }}s) {{ feed.displayName }}
svg(version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve")
path(fill="#ED1B24" d="M68.6,96.5L87,78.1c1.6-1.6,1.6-4.1,0-5.7s-4.1-1.6-5.7,0L62.9,90.9L44.5,72.5l18.4-18.4c1.6-1.6,1.6-4.1,0-5.7c-1.6-1.6-4.1-1.6-5.7,0L38.9,66.8l-6.4-6.4L21.2,71.8C11,82,9.7,97.9,17.4,109.5L0,126.9l8.5,8.5L25.9,118c11.6,7.7,27.5,6.4,37.8-3.8L75,102.9C75,102.9,68.6,96.5,68.6,96.5z")
path(fill="#ED1B24" d="M102.9,75l11.3-11.3c10.3-10.3,11.5-26.1,3.8-37.8l17.4-17.4L126.9,0l-17.4,17.4C97.9,9.7,82,11,71.8,21.2L60.5,32.5C102,74,60.8,32.9,102.9,75z")
script(src="vendor.js")
script(src="vr.js")