diff --git a/client_src/chat-message.css b/client_src/chat-message.css
deleted file mode 100644
index 46e0dcf..0000000
--- a/client_src/chat-message.css
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 铃之椅 - 把选择权还给用户, 让聊天权掌握在用户手中
- * Copyright 2024 满月叶
- * GitHub: https://github.com/MoonLeeeaf/LingChair-Web-Client
- * 本项目使用 Apache 2.0 协议开源
- *
- * Copyright 2024 MoonLeeeaf
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-.chat-message-right {
- display: flex;
- justify-content: flex-end;
- align-items: flex-start;
- margin: 13px;
-}
-
-.chat-message-left {
- display: flex;
- justify-content: flex-start;
- align-items: flex-start;
- margin: 13px;
-}
-
-.message-content {
- margin-top: 13px;
- margin-bottom: 7px;
- margin-left: 5px;
- margin-right: 5px;
- max-width: 100%;
- white-space: normal;
- word-break: break-all;
- font-size: medium;
- /* 使用了 CardView 就不需要边框了 */
- /* border: 1.3px solid; */
- padding: 15px;
- border-radius: 15px;
- /* 添加圆角样式 */
- /* 设置外边距为 7px */
-}
-
-.message-content-with-nickname-right {
- display: flex;
- align-items: center;
- margin: 7px;
- flex-direction: column;
- /* 垂直排列元素 */
- align-items: flex-end;
- /* 左对齐元素 */
-}
-
-.message-content-with-nickname-left {
- display: flex;
- align-items: center;
- margin: 7px;
- flex-direction: column;
- /* 垂直排列元素 */
- align-items: flex-start;
- /* 左对齐元素 */
-}
-
-.chat-message-left .message-content-with-nickname-left .nickname,
-.chat-message-right .message-content-with-nickname-right .nickname {
- margin-right: 5px;
- font-size: medium;
- margin-top: 3px;
-}
-
-.chat-message-left > .avatar,
-.chat-message-right > .avatar {
- width: 45px;
- height: 45px;
- border-radius: 50%;
-}
\ No newline at end of file
diff --git a/client_src/index.css b/client_src/index.css
deleted file mode 100644
index debc8f2..0000000
--- a/client_src/index.css
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 铃之椅 - 把选择权还给用户, 让聊天权掌握在用户手中
- * Copyright 2024 满月叶
- * GitHub: https://github.com/MoonLeeeaf/LingChair-Web-Client
- * 本项目使用 Apache 2.0 协议开源
- *
- * Copyright 2024 MoonLeeeaf
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
- html, body {
- max-height: 100%;
- margin: 0;
- padding: 0;
- /* overflow: hidden; */
- /*font: initial;*/
-}
-body {
- margin: 0;
- padding: 0;
-}
-.container {
- display: flex;
- flex-direction: column;
- overflow: auto;
-}
-.content {
- flex: 1;
-}
-
-.menu-on-message {
- margin-top: 60px;
- z-index: 100;
-}
-
-[n-id=pageChatSeesion]::after {
- content: "";
- position: sticky;
- bottom: 0;
- display: block;
- height: var(--pseudo-height); /* 设置伪元素的高度 */
- z-index: -1; /* 防止遮挡实际内容 */
- }
diff --git a/client_src/index.html b/client_src/index.html
deleted file mode 100644
index 8682440..0000000
--- a/client_src/index.html
+++ /dev/null
@@ -1,339 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 铃之椅
-
-
-
-
-
-
-
-
-
-
- -
-
-

-
-
-
- -
- settings
-
设置
-
- -
- exit_to_app
-
登出
-
-
- -
-
-
-
-
-
-
-
-
-
- -
- account_circle
-
资料
-
- -
- person_add
-
新的好友
-
-
- -
- settings
-
设置
-
- -
- cloud_circle
-
更换服务器
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 登录到 铃之椅
-
-
-
-
-
-
-
-
-
-
-
-
-
-
![]()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 修改昵称
-
-
-
-
-
-
-
-
-
-
-
- 新的好友请求
-
-
-
-
-
-
-
-
-
-
- 添加好友/群
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 设置
-
-
-
-
- -
- edit
-
修改昵称
-
- -
- account_circle
-
上传头像
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/client_src/index.js b/client_src/index.js
deleted file mode 100644
index e46a5ed..0000000
--- a/client_src/index.js
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * 铃之椅 - 把选择权还给用户, 让聊天权掌握在用户手中
- * Copyright 2024 满月叶
- * GitHub: https://github.com/MoonLeeeaf/LingChair-Web-Client
- * 本项目使用 Apache 2.0 协议开源
- *
- * Copyright 2024 MoonLeeeaf
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-const UrlArgs = new URL(location.href).searchParams
-
-// https://www.ruanyifeng.com/blog/2021/09/detecting-mobile-browser.html
-function isMobile() {
- return ('ontouchstart' in document.documentElement);
-}
-
-function setOnRightClick(e, cb) {
- if (!(e instanceof jQuery))
- e = $(e)
-
- let longPressTimer
- if (!cb) throw new Error("定义回调!!!!")
- e.on('contextmenu', function (e) {
- e.preventDefault() // 阻止默认右键菜单
- cb()
- })
-
- e.on('mousedown', function () {
- longPressTimer = setTimeout(function () {
- cb()
- }, 1000)
- })
-
- e.on('mouseup', function () {
- clearTimeout(longPressTimer)
- });
-}
-
-if (UrlArgs.get("debug")) {
- let script = document.createElement('script')
- script.src = "//cdn.jsdelivr.net/npm/eruda"
- document.body.appendChild(script)
- script.onload = () => eruda.init()
-}
-
-// 经常会因为这个指定ID为位置导致一些莫名BUG
-if (location.href.includes("#")) location.replace(location.href.substring(0, location.href.indexOf("#")))
-
-const mdui_snackbar = mdui.snackbar
-mdui.snackbar = (m) => {
- let t = m
- if (m instanceof Object)
- t = JSON.stringify(m)
- mdui_snackbar(t)
-}
-
-const checkEmpty = (i) => {
- if (i instanceof Array) {
- for (let k of i) {
- if (checkEmpty(k)) return true
- }
- }
-
- return (i == null) || ("" === i) || (0 === i)
-}
-
-function escapeHTML(str) {
- return str.replace(/[<>&"']/g, function (match) {
- switch (match) {
- case '<':
- return '<'
- case '>':
- return '>'
- case '&':
- return '&'
- case '"':
- return '"'
- case "'":
- return '''
- default:
- return match
- }
- })
-}
-
-class NData {
- static mount(node) {
- // 便捷获得指定组件
- let es = node.querySelectorAll("[n-id]")
- let ls = {}
- es.forEach((i) => ls[$(i).attr("n-id")] = $(i))
-
- // input 组件与 localStorage 绑定
- es = node.querySelectorAll("[n-input-ls]")
- es.forEach((e) => {
- let j = $(e)
- j.val(localStorage.getItem(j.attr("n-input-ls")))
- j.blur(() => localStorage.setItem(j.attr("n-input-ls"), j.val()))
- })
- return ls
- }
-}
-
-// 快捷获取指定视图
-let viewBinding = NData.mount($("#app").get(0))
-
-$.ajax({
- url: "res/config.json",
- dataType: "json",
- success: (c) => {
- viewBinding.appTitle.text(c.appTitle)
- if (!c.canChangeServer) {
- viewBinding.dialogSignInServerLabel.hide()
- viewBinding.drawerChangeServer.hide()
- }
- },
-})
-
-/* // Toolbar 快捷按钮绑定
-viewBinding.contactsRefresh.hide()
-viewBinding.contactsAdd.hide()
-viewBinding.tabChatList.on("show.mdui.tab", () => {
- viewBinding.contactsRefresh.hide()
- viewBinding.contactsAdd.hide()
-})
-viewBinding.tabContacts.on("show.mdui.tab", () => {
- viewBinding.contactsRefresh.show()
- viewBinding.contactsAdd.show()
-})
-viewBinding.tabChatSeesion.on("show.mdui.tab", () => {
- viewBinding.contactsRefresh.hide()
- viewBinding.contactsAdd.hide()
-}) */
-
-/* viewBinding.tabChatSeesion.hide() */
-
-// 关于页面
-viewBinding.menuAbout.click(() => mdui.alert('这是一个开源项目
作者: MoonLeeeaf
欢迎访问我们的项目主页', '关于 铃之椅', () => { }, { confirmText: "关闭" }))
-
-viewBinding.drawerChangeServer.click(() => {
- mdui.prompt('输入服务器地址...(为空则使用当前页面地址)', (value) => {
- localStorage.server = value
- mdui.snackbar("更新成功, 刷新页面生效")
- }, () => { }, {
- confirmText: "确定",
- cancelText: "取消"
- })
-})
-
-viewBinding.drawerSignOut.click(() => {
- mdui.confirm('确定要登出账号吗', () => {
- User.signOutAndReload()
- }, () => { }, {
- confirmText: "确定",
- cancelText: "取消"
- })
-})
-
-viewBinding.sendMsg.click((a) => {
- let text = viewBinding.inputMsg.val()
- if (text.trim() !== "")
- ChatMsgAdapter.send(text)
-})
-
-viewBinding.inputMsg.keydown((e) => {
- if (e.ctrlKey && e.keyCode === 13)
- viewBinding.sendMsg.click()
-})
-
-viewBinding.dialogSignInPasswd.keydown((e) => {
- if (e.keyCode === 13)
- viewBinding.dialogSignInEnter.click()
-})
-
-viewBinding.switchNotifications.click((a) => {
- if ((localStorage.useNotifications == "true" || localStorage.useNotifications != null) && localStorage.useNotifications != "false") {
- localStorage.useNotifications = "false"
- viewBinding.switchNotificationsIcon.text("notifications_off")
- } else {
- localStorage.useNotifications = "true"
- viewBinding.switchNotificationsIcon.text("notifications")
- }
-})
-if (localStorage.useNotifications == "true")
- viewBinding.switchNotificationsIcon.text("notifications")
-
-// https://www.runoob.com/w3cnote/javascript-copy-clipboard.html
-function copyText(t) {
- let btn = viewBinding.textCopierBtn
- btn.attr("data-clipboard-text", t)
- new ClipboardJS(btn.get(0)).on('success', (e) => {
- e.clearSelection()
- })
- btn.click()
-}
-
-// https://zhuanlan.zhihu.com/p/162910462
-Date.prototype.format = function (tms, format) {
- let tmd = new Date(tms)
- /*
- * 例子: format="YYYY-MM-dd hh:mm:ss";
- */
- var o = {
- "M+": tmd.getMonth() + 1, // month
- "d+": tmd.getDate(), // day
- "h+": tmd.getHours(), // hour
- "m+": tmd.getMinutes(), // minute
- "s+": tmd.getSeconds(), // second
- "q+": Math.floor((tmd.getMonth() + 3) / 3), // quarter
- "S": tmd.getMilliseconds()
- // millisecond
- }
- if (/(y+)/.test(format)) {
- format = format.replace(RegExp.$1, (tmd.getFullYear() + "")
- .substr(4 - RegExp.$1.length));
- }
- for (var k in o) {
- if (new RegExp("(" + k + ")").test(format)) {
- format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k]
- : ("00" + o[k]).substr(("" + o[k]).length));
- }
- }
- return format;
-}
-
-// new mdui.Drawer('#main-drawer').close()
-
-class NickCache {
- static data = {}
- static async getNick(name) {
- return await new Promise((res, rej) => {
- // 这个this别摆着不放啊 不然两下就会去世
- let nick = this.data[name]
- if (nick == null)
- client.emit("user.getNick", { name: localStorage.userName }, (re) => {
- let nk = re.data != null ? re.data.nick : name
- if (nk == null) nk = name
- this.data[name] = nk
- res(nk)
- })
- else
- res(nick)
- })
- }
-}
-
-// 既然已经有 Notification 了, 那用回中文也不过分吧 :)
-class 通知 {
- constructor() {
- this.args = {}
- this.title = ""
- }
- static checkAvailable() {
- return ("Notification" in window)
- }
- static async request() {
- if (!this.checkAvailable()) return false
- return (await Notification.requestPermission())
- }
- setId(id) {
- this.args.tag = id
- return this
- }
- setTitle(t) {
- this.title = t
- return this
- }
- setMessage(m) {
- this.args.body = m
- return this
- }
- setIcon(i) {
- this.args.icon = i
- return this
- }
- setImage(i) {
- this.args.image = i
- return this
- }
- setData(data) {
- this.args.data = data
- }
- show(onclick/*, onclose*/) {
- if (!通知.checkAvailable()) return
- if (localStorage.useNotifications !== "true") return
- let n = new Notification(this.title, this.args)
- n.onclick = onclick == null ? () => n.close() : (n) => onclick(n)
- // n.onclose = onclose
- // n.close()
- return n
- }
-}
-
-class ContactsList {
- static async reloadList() {
- client.emit("user.getFriends", {
- name: localStorage.userName,
- accessToken: await User.getAccessToken(),
- }, async (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
-
- viewBinding.contactsList.empty()
- let ls = re.data.friends
- for (let index in ls) {
- let name = ls[index]
- let dick = await NickCache.getNick(name)
- /*client.emit("user.getNick", { name: localStorage.userName }, (re) => {
- let nick = re.data == null ? re.data.nick : null
- let name = ls[index]*/
- $($.parseHTML(`` + dick + `
`)).appendTo(viewBinding.contactsList).click(() => {
- ChatMsgAdapter.switchTo(name, "single")
- })
- //})
- }
-
- })
- }
- // 添加联系人,好友或者群聊
- static add(name, type) {
- if (type == "single") {
-
- }
- }
- static openAddDialog() {
- new mdui.Dialog(viewBinding.dialogNewContact.get(0)).open()
- }
-}
-
-// 第一次写前端的消息加载, 代码很乱, 还请原谅~
-
-// v0.7.0 大改UI 畏惧了 太庞大了
-
-class ChatPage {
- static cached = {}
- constructor(name, type) {
-
- }
- static switchTo(name, type) {
- if (!this.cached[name])
- this.cached[name] = new ChatPage(name, type)
- }
-}
-
-class ChatMsgAdapter {
- static type
- static target
- // static msgList
- static minMsgId
- static time
- static bbn
- static resizeDick
- // 切换聊天对象
- static async switchTo(name, type) {
- viewBinding.tabChatSeesion.show()
- viewBinding.tabChatSeesion.text(await NickCache.getNick(name))
- viewBinding.tabChatSeesion.get(0).click()
-
- this.type = type
- this.target = name
- // this.msgList = []
- this.minMsgId = null
-
- viewBinding.pageChatSeesion.empty()
-
- await this.loadMore()
- this.scrollToBottom()
- }
- // 发送消息
- static async send(msg) {
- client.emit("user.sendSingleMsg", {
- name: localStorage.userName,
- target: this.target,
- msg: msg,
- accessToken: await User.getAccessToken(),
- }, async (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
-
- viewBinding.inputMsg.val("")
-
- // 微机课闲的没事干玩玩 发现私聊会多发一个(一个是本地的, 另一个是发送成功的) 选择一个关掉就好了
- // 这里我选择服务端不发送回调, 不然多设备同步会吵死
- // 错了 应该是客户端少发条才对 不然不能多设备同步
- if (ChatMsgAdapter.target !== localStorage.userName && ChatMsgAdapter.type === "single") {
- let i = ChatMsgAdapter.isAtBottom()
- await ChatMsgAdapter.addMsg(localStorage.userName, msg, re.data.time, re.data.msgid)
- if (i) ChatMsgAdapter.scrollToBottom()
- }
- })
- }
- static async getHistroy(start, limit) {
- return new Promise(async (res, rej) => {
- client.emit("user.getSingleChatHistroy", {
- name: localStorage.userName,
- target: this.target,
- limit: limit,
- accessToken: await User.getAccessToken(),
- startId: start,
- }, (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
- res(re.data.histroy)
- })
- })
- }
- static async loadMore(limit) {
- let histroy = await this.getHistroy(this.minMsgId, limit == null ? 13 : limit)
-
- if (histroy.length == 0)
- return mdui.snackbar("已经加载完了~")
-
- let re = this.minMsgId != null
- this.minMsgId = histroy[0].msgid - 1
- let sc = 0
- if (re) histroy = histroy.reverse()
- for (let index in histroy) {
- let i = histroy[index]
- let e = await this.addMsg(i.name, i.msg, i.time, re, i.msgid)
- // 因为某些因素直接DEBUG到吐血 断点继续都不报错 原因不明
- sc = sc + (e == null ? 25 : e.get(0).offsetTop)
- }
- window.scrollBy({
- top: sc,
- behavior: 'smooth'
- })
- }
- static addSystemMsg(m, re) {
- let e
- if (re)
- // 加到头部
- e = $($.parseHTML(m)).prependTo(viewBinding.pageChatSeesion)
- else
- // 加到尾部
- e = $($.parseHTML(m)).appendTo(viewBinding.pageChatSeesion)
- return e
- }
- static isAtBottom() {
- let elementRect = viewBinding.pageChatSeesion.get(0).getBoundingClientRect()
- return (elementRect.bottom <= window.innerHeight)
- }
- // 添加消息 返回消息的JQ对象
- // name: 用户id m: 消息 t: 时间戳 re: 默认加到尾部 msgid: 消息id
- static async addMsg(name, m, t, re, msgid) {
-
- let nick = await NickCache.getNick(name) // re.data == null ? name : re.data.nick
-
- let msg = escapeHTML(m)
-
- let temp
- if (name === localStorage.userName)
- temp = `
-
-
` + nick + `
-
- ` + msg + `
-
-
-
 + `)
-
`
- else
- temp = `
-
 + `)
-
-
` + nick + `
-
- ` + msg + `
-
-
-
`
-
- let bn = new Date(t).getMinutes()
- let e
- if (re) {
- this.addSystemMsg(temp, re)
- if (this.bbn != bn) {
- e = this.addSystemMsg(`` + new Date().format(t == null ? Date.parse("1000-1-1 00:00:00") : t, "yyyy年MM月dd日 hh:mm:ss") + `
`, re)
- this.time = bn
- }
- } else {
- if (this.bbn != bn) {
- e = this.addSystemMsg(`` + new Date().format(t == null ? Date.parse("1000-1-1 00:00:00") : t, "yyyy年MM月dd日 hh:mm:ss") + `
`, re)
- this.time = bn
- }
- this.addSystemMsg(temp, re)
- }
-
- this.bbn = new Date(t).getMinutes()
-
- return e
- }
- // 添加消息记录 作用在 UI 和 msgList
- /* static async addMsgLocal(name, m, t, msgid) {
- this.msgList.push({
- name: name,
- msg: m,
- msgid: msgid,
- })
-
- this.addMsg(name, m, t)
- } */
- // 从服务器加载一些聊天记录, limit默认=13
- static async loadMsgs(limit) {
- let histroy = await this.getHistroy(this.msgList[0] == null ? null : this.msgList[0].msgid - 1, limit == null ? 13 : limit)
- this.msgList = histroy
- }
- /* static async loadMsgsFromList(lst) {
- for (let index in lst) {
- let i = lst[index]
- await this.addMsg(i.name, i.msg, i.time)
- }
- } */
- static scrollToBottom() {
- // 吐了啊 原来这样就行了 我何必在子element去整啊
- viewBinding.chatPager.get(0).scrollBy({
- top: 1145141919810,
- behavior: 'smooth'
- })
- }
- // 从本地加载
- /*static loadMsgsFromLocal(target) {
- let data = localStorage["chat_msg_" + target]
- if (data == null || data === "[]")
- return []
-
- return JSON.parse(data)
- }
- // 把当前聊天记录储存到本地
- static saveToLocal() {
- localStorage["chat_msg_" + this.target] = JSON.stringify(this.msgList)
- }*/
- // 自动调整使输入框置底 CSS真tm靠不住啊
- static initInputResizer() {
- // 实验表面移动端切出输入法时会触发1-2次resize事件
- // 可以利用这个特性来实现自动滚动文本
- let resize = () => {
- viewBinding.pageChatSeesion.height(window.innerHeight - viewBinding.inputToolbar.height() - $("header.mdui-appbar").height() - viewBinding.chatTab.height() - 50)
- let ledi = this.resizeDick - window.innerHeight
- if (isMobile()) viewBinding.chatPager.get(0).scrollBy({
- // 5.19晚10:56分调配出来的秘方
- // < 0 为窗口变大
- // cnm的,调试十万次就你tm检测不到底是吧,就你语法天天错误是吧
- // 欺负我现在用不了电脑
- top: -(ledi) * ( (ledi < 0 && this.isAtBottom()) ? 6 : -1 ), // (ledi < 0 ? 6 : 6),
- behavior: 'smooth'
- })
- this.resizeDick = window.innerHeight
- }
- window.addEventListener("resize", resize)
- resize()
- }
- // 为消息设置长按/右键事件
- static initMsgElementEvents() {
- let listeners = {}
- let menu
- let callback = (e) => {
- if (menu) menu.close()
- // 从 span 切到 div
- if (e.get(0).tagName.toLowerCase() != "div") e = $(e.get(0).parentNode)
- // 从 消息框 切到 更上层
- e = $(e.get(0).parentNode)
- let menuHtml = $.parseHTML(``)
- let $menu = $(menuHtml)
- e.before($menu)
- menu = new mdui.Menu(e.get(0), menuHtml, {
- position: "bottom",
- align: "right",
- // covered: true,
- })
- $menu.on('closed.mdui.menu', () => {
- $(menuHtml).remove()
- })
- menu.open()
- }
- viewBinding.pageChatSeesion.on('contextmenu mousedown mouseup', '.message-content', (e) => {
- let eventType = e.type
- let self = $(e.target)
-
- // 根据事件类型执行不同操作
- switch (eventType) {
- case 'contextmenu':
- e.preventDefault() // 阻止默认行为
- callback(self)
- break
- case 'mousedown':
- listeners[self + ""] = setTimeout(() => {
- callback(self)
- }, 300) // 300颗够吗 应该够吧
- break
- case 'mouseup':
- clearTimeout(listeners[self + ""])
- listeners[self + ""] = null
- break
- }
- })
- }
-}
-
-class Hash {
- static md5(data) {
- return CryptoJS.MD5(data).toString(CryptoJS.enc.Base64)
- }
- static sha256(data) {
- return CryptoJS.SHA256(data).toString(CryptoJS.enc.Base64)
- }
-}
-
-class User {
- static myAccessToken
- // 登录账号 通过回调函数返回刷新令牌
- static signIn(name, passwd, cb) {
- client.emit("user.signIn", {
- name: name,
- passwd: Hash.sha256(passwd) + Hash.md5(passwd),
- }, (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
-
- cb(re)
- })
- }
- static signUp(name, passwd, cb) {
- client.emit("user.signUp", {
- name: name,
- passwd: Hash.sha256(passwd) + Hash.md5(passwd),
- }, (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
-
- cb(re)
- })
- }
- // 为登录对话框编写的
- static signInWithDialog(name, passwd) {
- this.signIn(name, passwd, (re) => {
- localStorage.refreshToken = re.data.refreshToken
- localStorage.isSignIn = true
-
- location.reload()
- })
- }
- static async setNick(nick, cb) {
- client.emit("user.setNick", {
- name: localStorage.userName,
- accessToken: await this.getAccessToken(),
- nick: nick,
- }, (re) => {
- if (re.code !== 0)
- return mdui.snackbar(re.msg)
- if (cb) cb()
- })
- }
- // 获取头像链接
- static getUserHeadUrl(name) {
- return client.io.uri + "/users_head/" + name + ".png"
- }
- static async getAccessToken(er) {
- if (this.myAccessToken == null)
- this.myAccessToken = await new Promise((res) => {
- client.emit("user.getAccessToken", { name: localStorage.userName, refreshToken: localStorage.refreshToken }, (r) => {
- if (r.data != null) res(r.data.accessToken)
- if (er != null) er(r.msg)
- })
- })
- return this.myAccessToken
- }
- static uploadHeadImage() {
- viewBinding.uploadHeadImage.click()
- }
- static async uploadHeadImageCallback(self) {
- let img = self.files[0]
- client.emit("user.setHeadImage", {
- name: localStorage.userName,
- accessToken: await User.getAccessToken(),
- headImage: img,
- }, (re) => mdui.snackbar(re.msg))
- }
- static auth() {
- client.emit("user.auth", { name: localStorage.userName, refreshToken: localStorage.refreshToken }, (re) => {
- if (re.code !== 0) {
- console.error(re)
- if (!re.invalid)
- return mdui.snackbar("验证用户失败!")
-
- mdui.alert("账号刷新令牌已过期, 请重新登录哦", "提示", () => User.signOutAndReload(), {
- confirmText: "确定",
- closeOnConfirm: false,
- closeOnEsc: false,
- modal: true,
- })
- }
- })
- }
- static signOutAndReload() {
- localStorage.refreshToken = ""
- localStorage.isSignIn = false
-
- setTimeout(() => location.reload(), 300)
- }
- static registerCallback() {
- client.on("msg.receive", async (a) => {
- if (checkEmpty([a.target, a.msg, a.type]))
- return
-
- if ((ChatMsgAdapter.target === a.target) && (ChatMsgAdapter.type === a.type)) {
- let i = ChatMsgAdapter.isAtBottom()
- await ChatMsgAdapter.addMsg(a.target, a.msg.msg, a.msg.time)
- if (i) ChatMsgAdapter.scrollToBottom()
- }
-
- let n = new 通知().setTitle("新消息 - " + await NickCache.getNick(a.target)).setMessage(a.msg.msg).setIcon(User.getUserHeadUrl(a.target)).show(async () => {
- await ChatMsgAdapter.switchTo(a.target, a.type)
- location.replace("#msgid_" + a.msg.msgid)
- n.close()
- })
- })
- }
- static async openProfileDialog(name) {
- viewBinding.dialogProfileHead.attr("src", User.getUserHeadUrl(name))
- viewBinding.dialogProfileNick.text(await NickCache.getNick(name))
- new mdui.Dialog(viewBinding.dialogProfile).open()
- }
-}
-
-// 没有刷新令牌需要重新登录 或者初始化
-if (!localStorage.refreshToken || localStorage.refreshToken === "")
- localStorage.isSignIn = false
-
-let client
-function setUpClient(server) {
- if (server && server !== "")
- client = new io(server, {
- auth: {
- name: localStorage.isSignIn === "false" ? null : localStorage.userName
- }
- })
- else
- client = new io({
- auth: {
- name: localStorage.isSignIn === "false" ? null : localStorage.userName
- }
- })
-
- client.on("connect", () => {
- User.auth()
- })
-}
-if (!localStorage.server || localStorage.server === "")
- setUpClient()
-else
- setUpClient(localStorage.server)
-
-// 登录到账号
-let dialogSignIn
-// 谨防 localStorage 字符串数据大坑
-if (localStorage.isSignIn == "false")
- dialogSignIn = new mdui.Dialog(viewBinding.dialogSignIn.get(0), {
- modal: true,
- closeOnEsc: false,
- history: false,
- }).open()
-else {
- (async () => viewBinding.userNick.text(await NickCache.getNick(localStorage.userName)))()
- let hello
- let nowHour = new Date().getHours()
- if (nowHour >= 6 && nowHour <= 11) hello = "早安"
- else if (nowHour == 12) hello = "中午好"
- else if (nowHour >= 13 && nowHour <= 18) hello = "下午好"
- else if (nowHour >= 19 && nowHour < 22) hello = "晚上好"
- else hello = "晚安"
- viewBinding.helloText.text(hello)
-
- viewBinding.userHead.attr("src", User.getUserHeadUrl(localStorage.userName))
-
- ContactsList.reloadList()
-
- User.registerCallback()
-}
-
-// 感谢AI的力量
-Stickyfill.add($("*").filter((a, b) => $(b).css('position') === 'sticky'))
-
-ChatMsgAdapter.initMsgElementEvents()
-
-ChatMsgAdapter.initInputResizer()
-
-function refreshAll() {
- ContactsList.reloadList()
- delete NickCache.data
- NickCache.data = {}
-}
diff --git a/client_src/mdui-prettier.css b/client_src/mdui-prettier.css
deleted file mode 100644
index 4b86b3b..0000000
--- a/client_src/mdui-prettier.css
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * ©2024 满月叶
- * GitHub: MoonLeeeaf
- * 是 UI 美化,好耶!
- */
-
-/* 美化UI */
-
-body {
- font-family: -apple-system, system-ui, -webkit-system-font;
-}
-.mdui-dialog {
- border-radius: 23px;
-}
-.mdui-menu {
- border-radius: 10px;
-}
-.mdui-menu-item > a {
- padding-right: 3px;
-}
-.mdui-btn:not(.mdui-btn-icon, .mdui-dialog-actions button, .mdui-dialog-actions a) {
- padding-left: 20px;
- padding-right: 20px;
- height: 40px;
- border-radius: 10px;
-}
-.mdui-dialog-actions a,
-.mdui-dialog-actions button {
- padding-left: 20px;
- padding-right: 20px;
- height: 40px;
- border-radius: 40px;
-}
-.mdui-select-open {
- border-radius: 10px;
-}
-@media not screen and (min-width: 768px) {
- .mdui-snackbar {
- border-radius: 10px;
- }
-}
-
-/* 配色方案 */
-
-.mdui-theme-color-auto {
- background-color: #fff;
-}
-
-@media (prefers-color-scheme: dark) {
- .mdui-theme-color-auto {
- background-color: #303030;
- }
-}
diff --git a/client_src/res/config.json b/client_src/res/config.json
deleted file mode 100644
index d8ada1e..0000000
--- a/client_src/res/config.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "appTitle": "",
- "canChangeServer": true
-}
\ No newline at end of file
diff --git a/client_src/res/default_head.png b/client_src/res/default_head.png
deleted file mode 100644
index 4f6f226..0000000
Binary files a/client_src/res/default_head.png and /dev/null differ
diff --git a/client_src/res/icon.ico b/client_src/res/icon.ico
deleted file mode 100644
index 8677e11..0000000
Binary files a/client_src/res/icon.ico and /dev/null differ
diff --git a/client_src/res/license.txt b/client_src/res/license.txt
deleted file mode 100644
index 5c226ee..0000000
--- a/client_src/res/license.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-Copyright 2024 MoonLeeeaf
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
\ No newline at end of file