diff --git a/.env b/.env new file mode 100644 index 00000000..72569e51 --- /dev/null +++ b/.env @@ -0,0 +1,5 @@ +API_ID=1025907 +API_HASH=452b0359b988148995f22ff0f4229750 +VERSION=0.8.6 +VERSION_FULL=0.8.6 (1) +BUILD=1 diff --git a/build.js b/build.js new file mode 100644 index 00000000..e2f48b59 --- /dev/null +++ b/build.js @@ -0,0 +1,39 @@ +// @ts-check + +const { spawn } = require('child_process'); + +const version = process.argv[2] || 'same'; +const changelog = ''; +const child = spawn(`npm`, ['run', 'change-version', version, changelog].filter(Boolean)); +child.stdout.on('data', (chunk) => { + console.log(chunk.toString()); +}); + +child.on('close', (code) => { + if(code != 0) { + console.log(`child process exited with code ${code}`); + } + + const child = spawn(`npm`, ['run', 'build']); + child.stdout.on('data', (chunk) => { + console.log(chunk.toString()); + }); + + child.on('close', (code) => { + if(code != 0) { + console.error(`child process exited with code ${code}`); + } else { + console.log('Compiled successfully.'); + } + }); +}); + +/* exec(`npm run change-version ${version}${changelog ? ' ' + changelog : ''}; npm run build`, (err, stdout, stderr) => { + if(err) { + return; + } + + // the *entire* stdout and stderr (buffered) + console.log(`stdout: ${stdout}`); + console.log(`stderr: ${stderr}`); +}); */ diff --git a/package-lock.json b/package-lock.json index fab6165f..ccc1c8ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8032,6 +8032,30 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true + }, + "dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "requires": { + "dotenv": "^8.2.0" + } + }, + "dotenv-webpack": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-7.0.3.tgz", + "integrity": "sha512-O0O9pOEwrk+n1zzR3T2uuXRlw64QxHSPeNN1GaiNBloQFNaCUL9V8jxSVz4jlXXFP/CIqK8YecWf8BAvsSgMjw==", + "dev": true, + "requires": { + "dotenv-defaults": "^2.0.2" + } + }, "duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", diff --git a/package.json b/package.json index 1199d7a4..1e3e0d2e 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "profile:dev": "webpack --profile --json > stats.json --config webpack.dev.js", "whybundled": "npm run profile && whybundled stats.json", "generate-mtproto-types": "node ./src/scripts/generate_mtproto_types.js src/", - "generate-changelog": "node ./src/scripts/generate_changelog.js" + "generate-changelog": "node ./src/scripts/generate_changelog.js", + "change-version": "node ./src/scripts/change_version.js" }, "author": "", "license": "GPL-3.0-only", @@ -43,6 +44,7 @@ "babel-preset-es2015": "^6.24.1", "compression": "^1.7.4", "css-loader": "^3.6.0", + "dotenv-webpack": "^7.0.3", "express": "^4.17.1", "fast-png": "^5.0.4", "handlebars": "^4.7.7", diff --git a/src/components/sidebarLeft/index.ts b/src/components/sidebarLeft/index.ts index 6198e218..d736fd4b 100644 --- a/src/components/sidebarLeft/index.ts +++ b/src/components/sidebarLeft/index.ts @@ -37,6 +37,8 @@ import App from "../../config/app"; import ButtonMenuToggle from "../buttonMenuToggle"; import replaceContent from "../../helpers/dom/replaceContent"; import sessionStorage from "../../lib/sessionStorage"; +import { CLICK_EVENT_NAME } from "../../helpers/dom/clickEvent"; +import { closeBtnMenu } from "../misc"; export const LEFT_COLUMN_ACTIVE_CLASSNAME = 'is-left-column-shown'; @@ -200,11 +202,18 @@ export class AppSidebarLeft extends SidebarSlider { const btnMenu = this.toolsBtn.querySelector('.btn-menu') as HTMLElement; - const btnMenuFooter = document.createElement('div'); + const btnMenuFooter = document.createElement('a'); + btnMenuFooter.href = 'https://github.com/morethanwords/tweb/blob/master/CHANGELOG.md'; + btnMenuFooter.target = '_blank'; + btnMenuFooter.rel = 'noopener noreferrer'; btnMenuFooter.classList.add('btn-menu-footer'); + btnMenuFooter.addEventListener(CLICK_EVENT_NAME, (e) => { + e.stopPropagation(); + closeBtnMenu(); + }); const t = document.createElement('span'); t.classList.add('btn-menu-footer-text'); - t.innerHTML = 'Telegram Web' + App.suffix + ' alpha ' + App.version; + t.innerHTML = 'Telegram Web' + App.suffix + ' alpha ' + App.versionFull; btnMenuFooter.append(t); btnMenu.classList.add('has-footer'); btnMenu.append(btnMenuFooter); diff --git a/src/config/app.ts b/src/config/app.ts index c1dac2c0..be231dba 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -14,9 +14,10 @@ import type { DcId } from "../types"; export const MAIN_DOMAIN = 'web.telegram.org'; const App = { - id: 1025907, - hash: '452b0359b988148995f22ff0f4229750', - version: '0.8.6', + id: +process.env.API_ID, + hash: process.env.API_HASH, + version: process.env.VERSION, + versionFull: process.env.VERSION_FULL, langPackVersion: '0.3.3', langPack: 'macos', langPackCode: 'en', diff --git a/src/lib/appManagers/apiUpdatesManager.ts b/src/lib/appManagers/apiUpdatesManager.ts index 48e46993..4a4e14b2 100644 --- a/src/lib/appManagers/apiUpdatesManager.ts +++ b/src/lib/appManagers/apiUpdatesManager.ts @@ -668,6 +668,10 @@ export class ApiUpdatesManager { state.date = 1; */ // state.pts -= 100; + /* state.date = 1628623682; + state.pts = 2007500; + state.seq = 503; */ + Object.assign(this.updatesState, state); this.log('will get difference', Object.assign({}, state)); diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index 143d2a92..eaefed52 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -648,7 +648,8 @@ export class AppDialogsManager { } public testDialogForFilter(dialog: Dialog, filter = appMessagesManager.filtersStorage.getFilter(this.filterId)) { - if((filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || + if(!dialog || + (filter && !appMessagesManager.filtersStorage.testDialogForFilter(dialog, filter)) || (!filter && this.filterId !== dialog.folder_id)) { return false; } diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index fdc21f25..a0976f4e 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -17,7 +17,7 @@ import { createPosterForVideo } from "../../helpers/files"; import { copy, getObjectKeysAndSort } from "../../helpers/object"; import { randomLong } from "../../helpers/random"; import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string"; -import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason } from "../../layer"; +import { Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs } from "../../layer"; import { InvokeApiOptions } from "../../types"; import I18n, { i18n, join, langPack, LangPackKey, _i18n } from "../langPack"; import { logger, LogTypes } from "../logger"; @@ -1728,14 +1728,16 @@ export class AppMessagesManager { // ! ВНИМАНИЕ: ОЧЕНЬ СЛОЖНАЯ ЛОГИКА: // ! если делать запрос сначала по папке 0, потом по папке 1, по индексу 0 в массиве будет один и тот же диалог, с dialog.pFlags.pinned, ЛОЛ??? // ! т.е., с запросом folder_id: 1, и exclude_pinned: 0, в результате будут ещё и закреплённые с папки 0 - return apiManager.invokeApiSingle('messages.getDialogs', { + const params: MessagesGetDialogs = { folder_id: folderId, offset_date: offsetDate, offset_id: offsetId, offset_peer: appPeersManager.getInputPeerById(offsetPeerId), limit, hash: 0 - }, { + }; + + return apiManager.invokeApiSingle('messages.getDialogs', params, { //timeout: APITIMEOUT, noErrorBox: true }).then((dialogsResult) => { @@ -1798,7 +1800,7 @@ export class AppMessagesManager { if(!appMessagesIdsManager.getServerMessageId(dialog.read_inbox_max_id) && !appMessagesIdsManager.getServerMessageId(dialog.read_outbox_max_id)) { noIdsDialogs[dialog.peerId] = dialog; - this.log.error('noIdsDialogs', dialog); + this.log.error('noIdsDialogs', dialog, params); /* if(dialog.peerId === -1213511294) { this.log.error('lun bot', folderId); diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts index 66fa3d90..4116c17f 100644 --- a/src/lib/appManagers/appStateManager.ts +++ b/src/lib/appManagers/appStateManager.ts @@ -26,7 +26,7 @@ import { nextRandomUint } from '../../helpers/random'; const REFRESH_EVERY = 24 * 60 * 60 * 1000; // 1 day //const REFRESH_EVERY_WEEK = 24 * 60 * 60 * 1000 * 7; // 7 days -const STATE_VERSION = App.version; +const STATE_VERSION = App.versionFull; export type Background = { type: 'color' | 'image' | 'default', diff --git a/src/lib/storages/dialogs.ts b/src/lib/storages/dialogs.ts index 933f1805..864d1c08 100644 --- a/src/lib/storages/dialogs.ts +++ b/src/lib/storages/dialogs.ts @@ -384,12 +384,12 @@ export default class DialogsStorage { // DO NOT TOUCH THESE LINES, SOME REAL MAGIC HERE. // * Read service chat when refreshing page with outgoing & getting new service outgoing message - if(incomingMessage && dialog.read_inbox_max_id >= dialog.top_message) { + /* if(incomingMessage && dialog.read_inbox_max_id >= dialog.top_message) { dialog.unread_count = 0; } dialog.read_inbox_max_id = this.appMessagesIdsManager.clearMessageId(dialog.read_inbox_max_id); - dialog.read_outbox_max_id = this.appMessagesIdsManager.clearMessageId(dialog.read_outbox_max_id); + dialog.read_outbox_max_id = this.appMessagesIdsManager.clearMessageId(dialog.read_outbox_max_id); */ // CAN TOUCH NOW if(peerId < 0 && pts) { @@ -555,10 +555,9 @@ export default class DialogsStorage { let mid: number, message: MyMessage; if(dialog.top_message) { - if(wasDialogBefore?.top_message && !this.appMessagesManager.getMessageByPeer(peerId, wasDialogBefore.top_message).deleted) { + mid = this.appMessagesIdsManager.generateMessageId(dialog.top_message);//dialog.top_message; + if(wasDialogBefore?.top_message && !this.appMessagesManager.getMessageByPeer(peerId, wasDialogBefore.top_message).deleted && wasDialogBefore.top_message >= mid) { mid = wasDialogBefore.top_message; - } else { - mid = this.appMessagesIdsManager.generateMessageId(dialog.top_message);//dialog.top_message; } message = this.appMessagesManager.getMessageByPeer(peerId, mid); @@ -594,7 +593,7 @@ export default class DialogsStorage { } dialog.top_message = mid; - dialog.unread_count = wasDialogBefore && dialog.read_inbox_max_id === this.appMessagesIdsManager.getServerMessageId(wasDialogBefore.read_inbox_max_id) ? wasDialogBefore.unread_count : dialog.unread_count; + // dialog.unread_count = wasDialogBefore && dialog.read_inbox_max_id === this.appMessagesIdsManager.getServerMessageId(wasDialogBefore.read_inbox_max_id) ? wasDialogBefore.unread_count : dialog.unread_count; dialog.read_inbox_max_id = this.appMessagesIdsManager.generateMessageId(wasDialogBefore && !dialog.read_inbox_max_id ? wasDialogBefore.read_inbox_max_id : dialog.read_inbox_max_id); dialog.read_outbox_max_id = this.appMessagesIdsManager.generateMessageId(wasDialogBefore && !dialog.read_outbox_max_id ? wasDialogBefore.read_outbox_max_id : dialog.read_outbox_max_id); @@ -612,8 +611,16 @@ export default class DialogsStorage { // Because we saved message without dialog present if(message.pFlags.is_outgoing) { - if(mid > dialog[message.pFlags.out ? 'read_outbox_max_id' : 'read_inbox_max_id']) message.pFlags.unread = true; - else delete message.pFlags.unread; + const isOut = message.pFlags.out; + if(mid > dialog[isOut ? 'read_outbox_max_id' : 'read_inbox_max_id']) { + message.pFlags.unread = true; + + if(!dialog.unread_count && !isOut) { + ++dialog.unread_count; + } + } else { + delete message.pFlags.unread; + } } const historyStorage = this.appMessagesManager.getHistoryStorage(peerId); diff --git a/src/scripts/change_version.js b/src/scripts/change_version.js new file mode 100644 index 00000000..afce7d19 --- /dev/null +++ b/src/scripts/change_version.js @@ -0,0 +1,50 @@ +/* + * https://github.com/morethanwords/tweb + * Copyright (C) 2019-2021 Eduard Kuzmenko + * https://github.com/morethanwords/tweb/blob/master/LICENSE + */ + +// @ts-check + +const fs = require('fs'); + +const version = process.argv[2]; +const changelog = process.argv[3]; + +const envStr = fs.readFileSync('./.env').toString(); +const env = {}; +envStr.split('\n').forEach(line => { + if(!line) return; + const [key, value] = line.split('=', 2); + env[key] = value; +}); + +if(version !== 'same') { + env.VERSION = version; +} + +env.BUILD = +env.BUILD + 1; +env.VERSION_FULL = `${env.VERSION} (${env.BUILD})`; + +const lines = []; +for(const key in env) { + lines.push(`${key}=${env[key]}`); +} +fs.writeFileSync('./.env', lines.join('\n') + '\n', 'utf-8'); + +if(changelog) { + const data = fs.readFileSync('./CHANGELOG.md'); + const fd = fs.openSync('./CHANGELOG.md', 'w+'); + const lines = [ + `### ${env.VERSION_FULL}` + ]; + changelog.trim().split('\n').forEach(line => { + lines.push(`* ${line}`); + }); + const insert = Buffer.from(lines.join('\n') + '\n\n'); + fs.writeSync(fd, insert, 0, insert.length, 0); + fs.writeSync(fd, data, 0, data.length, insert.length); + fs.close(fd, () => { + process.exit(0); + }); +} diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss index c96bfdb5..5d0f7be8 100644 --- a/src/scss/partials/_button.scss +++ b/src/scss/partials/_button.scss @@ -245,7 +245,8 @@ border-bottom-left-radius: inherit; border-bottom-right-radius: inherit; font-size: .875rem; - cursor: default; + color: currentColor; + // cursor: default; /* &-text { margin-top: -.125rem; diff --git a/webpack.common.js b/webpack.common.js index e49e0e00..2402b0b2 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -6,11 +6,12 @@ const postcssPresetEnv = require('postcss-preset-env'); const ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin'); const { RetryChunkLoadPlugin } = require('webpack-retry-chunk-load-plugin'); const fs = require('fs'); +const Dotenv = require('dotenv-webpack'); const allowedIPs = ['127.0.0.1']; const devMode = process.env.NODE_ENV !== 'production'; const useLocal = true; -const useLocalNotLocal = false; +const useLocalNotLocal = true; if(devMode) { console.log('DEVMODE IS ON!'); @@ -29,7 +30,7 @@ const opts = { }; const domain = 'yourdomain.com'; -const localIp = '192.168.93.209'; +const localIp = '192.168.93.183'; module.exports = { module: { @@ -141,6 +142,8 @@ module.exports = { }, plugins: [ + new Dotenv(), + new ServiceWorkerWebpackPlugin({ entry: path.join(__dirname, 'src/lib/serviceWorker/index.service.ts'), filename: 'sw.js',