a158 2 minggu lalu
induk
melakukan
58b12e352b

+ 5 - 0
Client/Client.vcxproj

@@ -71,6 +71,11 @@
     <TargetName>NIM</TargetName>
     <ApplicationIcon>res\icons\app.ico</ApplicationIcon>
   </PropertyGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <PreprocessorDefinitions>_DEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+    </ClCompile>
+  </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'" Label="Configuration">
     <ClCompile>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>

+ 5 - 2
Client/src/app/main.cpp

@@ -67,11 +67,14 @@ int main(int argc, char *argv[])
             login.raise();
             login.activateWindow();
         });
-        mainWin->show();
         login.hide();
+        mainWin->show();
+        mainWin->raise();
+        mainWin->activateWindow();
     });
 
     Updater::scheduleCleanupAfterStart();
-    login.show();
+    if (!login.willAutoLogin())
+        login.show();
     return app.exec();
 }

+ 19 - 4
Client/src/auth/LoginWindow.cpp

@@ -253,14 +253,23 @@ void LoginWindow::tryAutoLogin()
 {
     if (m_skipAutoLogin)
         return;
-    const auto &u = UserSettings::instance();
-    if (!u.autoLogin() || !u.rememberPassword())
-        return;
-    if (m_account->text().trimmed().isEmpty() || m_password->text().isEmpty())
+    if (!willAutoLogin())
         return;
     QTimer::singleShot(0, this, &LoginWindow::onLogin);
 }
 
+bool LoginWindow::willAutoLogin() const
+{
+    if (m_skipAutoLogin)
+        return false;
+    const auto &u = UserSettings::instance();
+    if (!u.autoLogin() || !u.rememberPassword())
+        return false;
+    if (!m_account || !m_password)
+        return false;
+    return !m_account->text().trimmed().isEmpty() && !m_password->text().isEmpty();
+}
+
 void LoginWindow::onLogin()
 {
     if (m_loggingIn)
@@ -285,6 +294,12 @@ void LoginWindow::onLogin()
         if (!ImClient::ok(reply))
         {
             UiHelpers::setError(self->m_error, ImClient::messageOf(reply));
+            if (!self->isVisible())
+            {
+                self->show();
+                self->raise();
+                self->activateWindow();
+            }
             return;
         }
         const QString nickname = reply.value(QStringLiteral("nickname")).toString();

+ 1 - 0
Client/src/auth/LoginWindow.h

@@ -23,6 +23,7 @@ public:
     explicit LoginWindow(QWidget *parent = nullptr);
     QString lastAccount() const;
     void prepareAfterLogout();
+    bool willAutoLogin() const;
 
 signals:
     void loginSucceeded(const QString &account, const QString &nickname);

+ 2 - 6
Client/src/chat/FileCache.cpp

@@ -459,12 +459,8 @@ QPixmap FileCache::thumbnail(qint64 fileId, int maxEdge)
         }
         img = reader.read();
     }
-    else
-    {
-        const QByteArray data = bytes(fileId);
-        if (data.isEmpty() || !img.loadFromData(data))
-            return {};
-    }
+    if (img.isNull() && m_bytes.contains(fileId))
+        img.loadFromData(m_bytes.value(fileId));
     if (img.isNull())
         return {};
     const qreal dpr = qApp ? qApp->devicePixelRatio() : 1.0;

+ 7 - 0
Client/src/chat/StickerPanel.cpp

@@ -9,6 +9,7 @@
 #include <QLabel>
 #include <QPushButton>
 #include <QScrollArea>
+#include <QHideEvent>
 #include <QShowEvent>
 #include <QStackedWidget>
 #include <QTabBar>
@@ -66,6 +67,12 @@ void StickerPanel::showEvent(QShowEvent *event)
     reload();
 }
 
+void StickerPanel::hideEvent(QHideEvent *event)
+{
+    QWidget::hideEvent(event);
+    emit dismissed();
+}
+
 void StickerPanel::reload()
 {
     if (StickerCache::instance().packs().isEmpty())

+ 4 - 0
Client/src/chat/StickerPanel.h

@@ -4,6 +4,8 @@
 
 class QTabBar;
 class QStackedWidget;
+class QShowEvent;
+class QHideEvent;
 
 class StickerPanel : public QWidget
 {
@@ -15,9 +17,11 @@ public:
 
 signals:
     void stickerPicked(qint64 packId, const QString &code);
+    void dismissed();
 
 protected:
     void showEvent(QShowEvent *event) override;
+    void hideEvent(QHideEvent *event) override;
 
 private:
     void rebuild();

+ 2 - 1
Client/src/common/ClientConfig.h

@@ -6,7 +6,8 @@
 
 namespace ClientConfig
 {
-constexpr const char *kHost = "49.232.135.144";
+//constexpr const char *kHost = "49.232.135.144";
+constexpr const char* kHost = "192.168.94.166";
 constexpr uint16_t kPort = 6000;
 constexpr uint16_t kMagic = 0x494D;
 constexpr bool kLogEnabled = true;

File diff ditekan karena terlalu besar
+ 583 - 96
Client/src/mainframe/Client.cpp


+ 34 - 0
Client/src/mainframe/Client.h

@@ -1,6 +1,8 @@
 #pragma once
 
 #include <QtWidgets/QMainWindow>
+#include <QHash>
+#include <QList>
 #include <QPixmap>
 #include <QJsonObject>
 #include <QSet>
@@ -8,6 +10,7 @@
 
 class QShowEvent;
 class QCloseEvent;
+class QResizeEvent;
 class QEvent;
 class QPoint;
 class TitleBar;
@@ -42,6 +45,7 @@ protected:
     void showEvent(QShowEvent *event) override;
     void closeEvent(QCloseEvent *event) override;
     void changeEvent(QEvent *event) override;
+    void resizeEvent(QResizeEvent *event) override;
     bool eventFilter(QObject *watched, QEvent *event) override;
 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
     bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
@@ -99,9 +103,30 @@ private:
     QPixmap peerAvatar(qint64 uid, const QString &name, int size) const;
     QWidget *addBubble(bool mine, const QString &name, const QString &text, const QString &time,
                        int msgType = 1, int sendStatus = 0, qint64 msgId = 0, qint64 peerUid = 0);
+    QWidget *findMsgRow(qint64 msgId) const;
+    int chatTextMaxWidth(bool mine) const;
+    void relayoutTextBubbles();
     QWidget *findOutgoingRow(qint64 localId) const;
     void setBubbleSendState(QWidget *row, bool failed, bool sending = false);
     void scrollChatToBottom();
+    struct ChatPage
+    {
+        QScrollArea *scroll = nullptr;
+        QWidget *host = nullptr;
+        QVBoxLayout *lay = nullptr;
+        int scrollValue = 0;
+        int laidOutW = -1;
+        bool stickBottom = true;
+        QString fp;
+    };
+    ChatPage createChatPage();
+    void bindChatScroll(QScrollArea *scroll);
+    void stashChatPage(qint64 peerUid);
+    bool activateChatPage(qint64 peerUid);
+    bool chatPageHasAll(const QJsonArray &list) const;
+    void dropChatPage(qint64 peerUid);
+    void trimChatPages();
+    void rememberChatPageState();
     void clearBubbles();
     void enterMsgSelectMode(qint64 preselectId = 0);
     void exitMsgSelectMode();
@@ -178,6 +203,15 @@ private:
     QPushButton *m_newFriendsBtn = nullptr;
     QLabel *m_pendingBadge = nullptr;
     class StickerPanel *m_stickerPanel = nullptr;
+    QPushButton *m_emojiBtn = nullptr;
+    qint64 m_stickerDismissedAt = 0;
+    int m_lastTextBubbleMaxW = -1;
+    bool m_buildingHistory = false;
+    qint64 m_historyPeerUid = 0;
+    QString m_historyFp;
+    QHash<qint64, ChatPage> m_chatPages;
+    QList<qint64> m_chatPageOrder;
+    QStackedWidget *m_chatPageStack = nullptr;
 
     QStackedWidget *m_chatStack = nullptr;
     QWidget *m_chatEmpty = nullptr;

+ 6 - 29
Client/src/network/ImClient.cpp

@@ -6,7 +6,6 @@
 #include <QJsonArray>
 #include <QJsonDocument>
 #include <QJsonObject>
-#include <QStringList>
 #include <QtNetwork/QAbstractSocket>
 #include <QtNetwork/QTcpSocket>
 #include <QTimer>
@@ -28,38 +27,16 @@ namespace
         return doc.isObject() ? doc.object() : QJsonObject();
     }
 
-    QString redactJson(const QJsonObject &obj)
+    QString packetDump(const char *dir, quint16 type, quint16 cmd, quint32 seq, int bodyLen)
     {
-        if (obj.isEmpty())
-            return QString();
-        QJsonObject copy = obj;
-        const QStringList secrets = {
-            QStringLiteral("password"),
-            QStringLiteral("old_password"),
-            QStringLiteral("sms_code")
-        };
-        for (const QString &key : secrets)
-        {
-            if (copy.contains(key) && !copy.value(key).toString().isEmpty())
-                copy.insert(key, QStringLiteral("***"));
-        }
-        return QString::fromUtf8(QJsonDocument(copy).toJson(QJsonDocument::Indented)).trimmed();
-    }
-
-    QString packetDump(const char *dir, quint16 type, quint16 cmd, quint32 seq,
-                       const QJsonObject &body)
-    {
-        QString text = QStringLiteral("%1 %2/%3(%4/%5) seq=%6")
+        return QStringLiteral("%1 %2/%3(%4/%5) seq=%6 len=%7")
                            .arg(QLatin1String(dir))
                            .arg(QLatin1String(Proto::typeName(type)))
                            .arg(QLatin1String(Proto::cmdName(cmd)))
                            .arg(type)
                            .arg(cmd)
-                           .arg(seq);
-        const QString json = redactJson(body);
-        if (json.isEmpty())
-            return text;
-        return text + QLatin1Char('\n') + json;
+                           .arg(seq)
+                           .arg(bodyLen);
     }
 }
 
@@ -540,7 +517,7 @@ void ImClient::sendRaw(Proto::Type type, Proto::Cmd cmd, quint32 seq, const QByt
 {
     if (!isConnected())
         return;
-    LOG_DEBUG(packetDump(">> send", static_cast<quint16>(type), static_cast<quint16>(cmd), seq, parseBody(body)));
+    LOG_DEBUG(packetDump(">> send", static_cast<quint16>(type), static_cast<quint16>(cmd), seq, body.size()));
     m_socket->write(m_codec->encode(static_cast<quint16>(type), static_cast<quint16>(cmd), seq, body));
     m_socket->flush();
 }
@@ -624,7 +601,7 @@ void ImClient::onHeartbeat()
 void ImClient::handlePacket(const Proto::Packet &pkt)
 {
     const QJsonObject obj = parseBody(pkt.body);
-    LOG_DEBUG(packetDump("<< recv", pkt.type, pkt.cmd, pkt.seq, obj));
+    LOG_DEBUG(packetDump("<< recv", pkt.type, pkt.cmd, pkt.seq, pkt.body.size()));
 
     if (pkt.cmd == static_cast<quint16>(Proto::Cmd::Kicked))
     {

+ 1 - 25
server/src/net/packet_log.cpp

@@ -3,36 +3,17 @@
 #include <string>
 
 #include "common/logger.h"
-#include "util/json.h"
 
 namespace im {
 namespace {
 
-std::string redact_body(const std::string& body)
-{
-    if (body.empty()) {
-        return {};
-    }
-    ylib::json j;
-    if (!j.parse(body)) {
-        return body.size() > 512 ? body.substr(0, 512) + "..." : body;
-    }
-    const char* keys[] = {"password", "old_password", "sms_code"};
-    for (const char* key : keys) {
-        if (j.exist(key) && !j[key].to<std::string>().empty()) {
-            j[key] = "***";
-        }
-    }
-    return j.to_string();
-}
-
 void log_packet(const char* dir, ConnId connid, const Packet& pkt)
 {
     if (!Logger::enabled(LogLevel::Debug)) {
         return;
     }
     std::string msg;
-    msg.reserve(128 + pkt.body.size());
+    msg.reserve(128);
     msg += dir;
     msg += " conn=";
     msg += std::to_string(connid);
@@ -48,11 +29,6 @@ void log_packet(const char* dir, ConnId connid, const Packet& pkt)
     msg += std::to_string(pkt.seq);
     msg += " len=";
     msg += std::to_string(pkt.body.size());
-    const std::string body = redact_body(pkt.body.to_string());
-    if (!body.empty()) {
-        msg += "\n  ";
-        msg += body;
-    }
     Logger::debug(msg);
 }
 

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini