diff --git a/BUGFIX_DOUBLE_BUTTONS.md b/BUGFIX_DOUBLE_BUTTONS.md new file mode 100644 index 00000000..ea42e24d --- /dev/null +++ b/BUGFIX_DOUBLE_BUTTONS.md @@ -0,0 +1,213 @@ +# Bugfix: Doppelte Buttons in der Anrufdetailansicht + +## Problem + +In der Anrufdetailansicht (CallHistoryLayout) wurden die drei Aktionsbuttons "Anrufen", "Nachricht" und "Videoanruf" nach mehrmaligem Wechseln zwischen Tabs doppelt angezeigt. Sowohl die Icons als auch die Labels erschienen zweimal untereinander. + +### Symptome +- Buttons erscheinen normal beim ersten Besuch der Anrufe-Seite +- Nach Navigation zu einem anderen Tab (z.B. Kontakte) und Rückkehr zu Anrufe: noch OK +- Nach erneutem Wechsel (2-3 mal): Buttons werden doppelt angezeigt +- Besuch der Einstellungen (als Overlay) und Rückkehr behob das Problem temporär + +### Betroffene Dateien +- `Linphone/view/Page/Main/Call/CallPage.qml` +- `Linphone/view/Control/Container/Call/CallHistoryLayout.qml` +- `Linphone/view/Control/Button/LabelButton.qml` + +## Ursachen + +### 1. Nicht bereinigter StackView-Zustand +Die CallPage wird bei Tab-Wechseln durch einen Loader zerstört und neu erstellt. Der `rightPanelStackView` wurde bei der Neuerstellung nicht bereinigt, was zu Zustandsproblemen führte. + +### 2. Fehlerhafte Größenangaben bei LabelButtons +Die LabelButtons hatten explizite `width: 56` und `height: 56` Angaben, obwohl der tatsächliche Inhalt (Button 56x56 + Spacing 8 + Text ~20) größer war. Dies führte zu Layout-Inkonsistenzen bei der Neuberechnung. + +### 3. Fehlende Layout-Ausrichtung +Nach Entfernung der expliziten Größen fehlte eine konsistente vertikale Ausrichtung, was zu Verschiebungen des Videoanruf-Buttons führte. + +## Lösung + +### CallPage.qml +```qml +Component.onCompleted: { + console.log("[CallPage] Created, rightPanelStackView.depth:", rightPanelStackView.depth) + // Ensure clean state on creation + rightPanelStackView.clear() +} +``` +**Erklärung:** Bei jeder Neuerstellung der CallPage wird der StackView geleert, um einen sauberen Zustand sicherzustellen. + +### CallHistoryLayout.qml +```qml +RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: Utils.getSizeWithScreenRatio(72) + visible: !mainItem.isConference + + LabelButton { + Layout.alignment: Qt.AlignTop // Hinzugefügt + button.icon.width: Utils.getSizeWithScreenRatio(24) + button.icon.height: Utils.getSizeWithScreenRatio(24) + button.icon.source: AppIcons.phone + label: qsTr("contact_call_action") + // ... onClick handler + } + // Gleiche Änderung für alle drei LabelButtons +} +``` +**Änderungen:** +- Entfernt: `width: Utils.getSizeWithScreenRatio(56)` und `height: Utils.getSizeWithScreenRatio(56)` von allen LabelButtons +- Entfernt: `Layout.fillWidth: true` und `Layout.preferredHeight: childrenRect.height` vom RowLayout +- Hinzugefügt: `Layout.alignment: Qt.AlignTop` für konsistente vertikale Ausrichtung + +## Technischer Hintergrund + +### Navigation und Loader-Verhalten +Die CallPage befindet sich in einem Loader mit `active: mainStackLayout.currentIndex === 0`. Bei Tab-Wechseln: +1. `currentIndex` ändert sich +2. Loader wird inaktiv → CallPage wird zerstört +3. Bei Rückkehr wird Loader aktiv → Neue CallPage wird erstellt + +Im Gegensatz dazu öffnen die Einstellungen als Overlay (contextual menu), ohne die CallPage zu zerstören. + +### StackView-Verhalten +Der `rightPanelStackView` verwendet `replace()` für Übergänge. Bei schneller Neuerstellung und property-Änderungen (durch `onSelectedRowHistoryGuiChanged`) konnte es zu Race-Conditions kommen, die zu doppelten Einträgen führten. + +## Test-Szenario +1. App starten +2. Zu "Anrufe" navigieren +3. Einen Anruf in der Liste anklicken (Details werden rechts angezeigt) +4. Zu "Kontakte" wechseln +5. Zurück zu "Anrufe" wechseln +6. Schritte 4-5 mehrmals wiederholen +7. **Erwartetes Ergebnis:** Buttons bleiben korrekt (nicht doppelt, korrekt ausgerichtet) + +## Datum +2026-02-08 + +--- + +# Weitere Bugfixes (2026-02-08) + +## 1. ComboSetting zeigt gespeicherte Werte nicht an + +### Problem +Die Dropdown-Menüs für Sprache und Akzentfarbe in den Anzeigeeinstellungen zeigten den gespeicherten Wert nicht an. Das erste Element wurde immer angezeigt, auch wenn ein anderer Wert gespeichert war. + +### Ursache +Die `currentIndex`-Berechnung verglich das gesamte Model-Entry-Objekt (z.B. `{text: "English", value: "en"}`) mit dem gespeicherten String-Wert (`"en"`) mit `Utils.equalObject()`. Dies ergab immer `false`, da die Typen nicht übereinstimmen. + +### Lösung +**Datei:** `Linphone/view/Control/Button/Settings/ComboSetting.qml` + +```qml +ComboBox { + id: comboBox + // ... + valueRole: "value" + textRole: "text" + currentIndex: Utils.findIndex(model, function (entry) { + var currentVal = propertyOwnerGui + ? propertyOwnerGui.core[mainItem.propertyName] + : propertyOwner[mainItem.propertyName] + // Compare entry.value with the stored value (both are simple strings) + return entry.value === currentVal + }) + onCurrentValueChanged: { + var storedVal = propertyOwnerGui + ? propertyOwnerGui.core[mainItem.propertyName] + : propertyOwner[mainItem.propertyName] + // currentValue is now just the value string + binding.when = currentValue !== storedVal + } +``` + +## 2. CardDAV Benutzername und Realm werden nicht angezeigt + +### Problem +In den CardDAV-Einstellungen wurden gespeicherte Werte für Benutzername und Realm nicht in den Textfeldern angezeigt. + +### Ursache +Das `TextField.qml` hat einen Windows-Workaround im `Component.onCompleted`: +```qml +Component.onCompleted: { + text = "workaround" + resetText() +} +``` +Die imperative Zuweisung `text = "workaround"` bricht den deklarativen Binding zu `initialText`. Wenn der Core-Wert erst nach der Komponentenerstellung verfügbar ist, wird er nicht angezeigt. + +### Lösung +**Datei:** `Linphone/view/Control/Input/TextField.qml` + +```qml +Component.onCompleted: { + text = "workaround" + // Re-establish binding to initialText after workaround + text = Qt.binding(function() { return initialText }) +} +``` + +## 3. Dark Mode Probleme + +### 3a. ComboBox-Popup ist weiß im Dark Mode + +**Problem:** Das Dropdown-Popup der ComboBox hatte einen weißen Hintergrund im Dark Mode. + +**Ursache:** Das `Rectangle` im Popup-Hintergrund hatte keine `color`-Eigenschaft. + +**Lösung:** +**Datei:** `Linphone/view/Control/Button/ComboBox.qml` + +```qml +background: Item { + // ... + Rectangle { + id: cboxBg + anchors.fill: parent + radius: Utils.getSizeWithScreenRatio(15) + color: DefaultStyle.grey_100 // Hinzugefügt - passt sich Dark Mode an + } +``` + +### 3b. Beschreibungstext schwarz im Dark Mode + +**Problem:** Hinweistexte in den Anzeigeeinstellungen waren schwarz und kaum lesbar im Dark Mode. + +**Ursache:** Tippfehler: `main2_500main` statt `main2_500_main` + +**Lösung:** +**Datei:** `Linphone/view/Page/Layout/Settings/DisplaySettingsLayout.qml` + +```qml +color: DefaultStyle.main2_500_main // Korrigiert von main2_500main +``` + +### 3c. Anruffenster hell im Dark Mode + +**Problem:** Das Anruffenster hatte einen weißen Hintergrund im Dark Mode. + +**Ursache:** Die `color`-Eigenschaft wurde nicht gesetzt (fehlt im Gegensatz zu MainWindow.qml). + +**Lösung:** +**Datei:** `Linphone/view/Page/Window/Call/CallsWindow.qml` + +```qml +AbstractWindow { + id: mainWindow + flags: Qt.Window + color: DefaultStyle.grey_0 // Hinzugefügt + // ... +} +``` + +## Zusammenfassung der geänderten Dateien + +| Datei | Änderung | +|-------|----------| +| `ComboSetting.qml` | valueRole/textRole und korrekter Wertvergleich | +| `TextField.qml` | Binding nach Windows-Workaround wiederherstellen | +| `ComboBox.qml` | Popup-Hintergrundfarbe für Dark Mode | +| `DisplaySettingsLayout.qml` | Tippfehler bei Farbname korrigiert | +| `CallsWindow.qml` | Window-Hintergrundfarbe für Dark Mode | diff --git a/Linphone/data/languages/de.ts b/Linphone/data/languages/de.ts index 50e2ee17..0011c787 100644 --- a/Linphone/data/languages/de.ts +++ b/Linphone/data/languages/de.ts @@ -2033,6 +2033,18 @@ "Stocker ici les contacts nouvellement crées" Neu erstellte Kontakte hier speichern + + + settings_contacts_carddav_store_plain_password_title + "Passwort im Klartext speichern (für HTTP Basic Auth)" + Passwort im Klartext speichern (für HTTP Basic Auth) + + + + settings_contacts_carddav_store_plain_password_subtitle + "Für Nextcloud/WebDAV-Server erforderlich. Passwort wird nicht gehasht." + Für Nextcloud/WebDAV-Server erforderlich. Passwort wird nicht gehasht. + ChangeLayoutForm @@ -2712,13 +2724,13 @@ Error settings_chat_display_notification_content_title "Display notification content" - + Benachrichtigungsinhalt anzeigen settings_chat_display_notification_content_subtitle "Display the content of the received message" - + Inhalt der empfangenen Nachricht in Benachrichtigungen anzeigen diff --git a/Linphone/data/languages/en.ts b/Linphone/data/languages/en.ts index 98c7e27a..d7440e3a 100644 --- a/Linphone/data/languages/en.ts +++ b/Linphone/data/languages/en.ts @@ -2026,6 +2026,18 @@ "Stocker ici les contacts nouvellement crées" Store newly created contacts here + + + settings_contacts_carddav_store_plain_password_title + "Store password in plain text (for HTTP Basic Auth)" + Store password in plain text (for HTTP Basic Auth) + + + + settings_contacts_carddav_store_plain_password_subtitle + "Required for Nextcloud/WebDAV servers. Password is not hashed." + Required for Nextcloud/WebDAV servers. Password is not hashed. + ChangeLayoutForm @@ -2697,13 +2709,13 @@ Only your correspondent can decrypt them. settings_chat_display_notification_content_title "Display notification content" - + Display notification content settings_chat_display_notification_content_subtitle "Display the content of the received message" - + Display the content of the received message diff --git a/Linphone/view/Control/Button/ComboBox.qml b/Linphone/view/Control/Button/ComboBox.qml index 5175ffc3..6d09072d 100644 --- a/Linphone/view/Control/Button/ComboBox.qml +++ b/Linphone/view/Control/Button/ComboBox.qml @@ -256,6 +256,7 @@ Control.ComboBox { id: cboxBg anchors.fill: parent radius: Utils.getSizeWithScreenRatio(15) + color: DefaultStyle.grey_100 } MultiEffect { anchors.fill: cboxBg diff --git a/Linphone/view/Control/Button/LabelButton.qml b/Linphone/view/Control/Button/LabelButton.qml index 19d7296d..948c9745 100644 --- a/Linphone/view/Control/Button/LabelButton.qml +++ b/Linphone/view/Control/Button/LabelButton.qml @@ -13,6 +13,9 @@ ColumnLayout { property alias text: text property string label spacing: Utils.getSizeWithScreenRatio(8) + + Component.onCompleted: console.log("[LabelButton] Created:", label, "parent:", parent) + Component.onDestruction: console.log("[LabelButton] Destroyed:", label) Button { id: button Layout.alignment: Qt.AlignHCenter diff --git a/Linphone/view/Control/Button/Settings/ComboSetting.qml b/Linphone/view/Control/Button/Settings/ComboSetting.qml index 2e3b65cc..a602038c 100644 --- a/Linphone/view/Control/Button/Settings/ComboSetting.qml +++ b/Linphone/view/Control/Button/Settings/ComboSetting.qml @@ -49,18 +49,21 @@ RowLayout { Layout.preferredWidth: titleText.length > 0 ? Utils.getSizeWithScreenRatio(200) : undefined Layout.fillWidth: titleText.length === 0 oneLine: true + valueRole: "value" + textRole: "text" currentIndex: Utils.findIndex(model, function (entry) { - if(propertyOwnerGui) - return Utils.equalObject(entry, propertyOwnerGui.core[mainItem.propertyName]) - else - return Utils.equalObject(entry, propertyOwner[mainItem.propertyName]) + var currentVal = propertyOwnerGui + ? propertyOwnerGui.core[mainItem.propertyName] + : propertyOwner[mainItem.propertyName] + // Compare entry.value with the stored value (both are simple strings like "en", "orange") + return entry.value === currentVal }) onCurrentValueChanged: { - if(propertyOwnerGui) { - binding.when = !Utils.equalObject(currentValue, propertyOwnerGui.core[mainItem.propertyName]) - } else { - binding.when = !Utils.equalObject(currentValue, propertyOwner[mainItem.propertyName]) - } + var storedVal = propertyOwnerGui + ? propertyOwnerGui.core[mainItem.propertyName] + : propertyOwner[mainItem.propertyName] + // currentValue is now just the value string (e.g., "en", "orange") + binding.when = currentValue !== storedVal } Binding { id: binding diff --git a/Linphone/view/Control/Container/Call/CallHistoryLayout.qml b/Linphone/view/Control/Container/Call/CallHistoryLayout.qml index b2f84903..8cd3495a 100644 --- a/Linphone/view/Control/Container/Call/CallHistoryLayout.qml +++ b/Linphone/view/Control/Container/Call/CallHistoryLayout.qml @@ -12,6 +12,9 @@ ColumnLayout { id: mainItem spacing: Utils.getSizeWithScreenRatio(30) + Component.onCompleted: console.log("[CallHistoryLayout] Created, parent:", parent) + Component.onDestruction: console.log("[CallHistoryLayout] Destroyed") + property var callHistoryGui property FriendGui contact @@ -122,12 +125,9 @@ ColumnLayout { RowLayout { Layout.alignment: Qt.AlignHCenter spacing: Utils.getSizeWithScreenRatio(72) - Layout.fillWidth: true - Layout.preferredHeight: childrenRect.height visible: !mainItem.isConference LabelButton { - width: Utils.getSizeWithScreenRatio(56) - height: Utils.getSizeWithScreenRatio(56) + Layout.alignment: Qt.AlignTop button.icon.width: Utils.getSizeWithScreenRatio(24) button.icon.height: Utils.getSizeWithScreenRatio(24) button.icon.source: AppIcons.phone @@ -139,9 +139,8 @@ ColumnLayout { } } LabelButton { + Layout.alignment: Qt.AlignTop visible: !SettingsCpp.disableChatFeature - width: Utils.getSizeWithScreenRatio(56) - height: Utils.getSizeWithScreenRatio(56) button.icon.width: Utils.getSizeWithScreenRatio(24) button.icon.height: Utils.getSizeWithScreenRatio(24) button.icon.source: AppIcons.chatTeardropText @@ -159,9 +158,8 @@ ColumnLayout { } } LabelButton { + Layout.alignment: Qt.AlignTop visible: SettingsCpp.videoEnabled - width: Utils.getSizeWithScreenRatio(56) - height: Utils.getSizeWithScreenRatio(56) button.icon.width: Utils.getSizeWithScreenRatio(24) button.icon.height: Utils.getSizeWithScreenRatio(24) button.icon.source: AppIcons.videoCamera diff --git a/Linphone/view/Control/Input/TextField.qml b/Linphone/view/Control/Input/TextField.qml index d74079d8..d1d40c1b 100644 --- a/Linphone/view/Control/Input/TextField.qml +++ b/Linphone/view/Control/Input/TextField.qml @@ -21,7 +21,8 @@ Control.TextField { // due to Qt not initializing the Password echo mode before the first letter is typed Component.onCompleted: { text = "workaround" - resetText() + // Re-establish binding to initialText after workaround + text = Qt.binding(function() { return initialText }) } verticalAlignment: TextInput.AlignVCenter diff --git a/Linphone/view/Page/Layout/Settings/DisplaySettingsLayout.qml b/Linphone/view/Page/Layout/Settings/DisplaySettingsLayout.qml index e6e52a6d..ef8e6587 100644 --- a/Linphone/view/Page/Layout/Settings/DisplaySettingsLayout.qml +++ b/Linphone/view/Page/Layout/Settings/DisplaySettingsLayout.qml @@ -70,7 +70,7 @@ AbstractSettingsLayout { Layout.fillWidth: true //: Restart required for language change text: qsTr("settings_display_language_restart_hint") - color: DefaultStyle.main2_500main + color: DefaultStyle.main2_500_main font.pixelSize: Typography.p2.pixelSize wrapMode: Text.WordWrap } @@ -101,7 +101,7 @@ AbstractSettingsLayout { text: DefaultStyle.systemDarkMode ? qsTr("settings_display_system_dark_detected") : qsTr("settings_display_system_light_detected") - color: DefaultStyle.main2_500main + color: DefaultStyle.main2_500_main font.pixelSize: Typography.p2.pixelSize wrapMode: Text.WordWrap } diff --git a/Linphone/view/Page/Main/Call/CallPage.qml b/Linphone/view/Page/Main/Call/CallPage.qml index 58786d3a..f7827178 100644 --- a/Linphone/view/Page/Main/Call/CallPage.qml +++ b/Linphone/view/Page/Main/Call/CallPage.qml @@ -16,6 +16,13 @@ AbstractMainPage { emptyListText: qsTr("call_history_empty_title") newItemIconSource: AppIcons.newCall + Component.onCompleted: { + console.log("[CallPage] Created, rightPanelStackView.depth:", rightPanelStackView.depth) + // Ensure clean state on creation + rightPanelStackView.clear() + } + Component.onDestruction: console.log("[CallPage] Destroyed") + property var selectedRowHistoryGui signal listViewUpdated signal goToCallForwardSettings @@ -51,12 +58,14 @@ AbstractMainPage { } onSelectedRowHistoryGuiChanged: { + console.log("[CallPage] selectedRowHistoryGuiChanged:", selectedRowHistoryGui ? "has value" : "null/undefined", "depth before:", rightPanelStackView.depth) if (selectedRowHistoryGui) rightPanelStackView.replace(contactDetailComp, Control.StackView.Immediate) else rightPanelStackView.replace(emptySelection, Control.StackView.Immediate) + console.log("[CallPage] depth after:", rightPanelStackView.depth) } rightPanelStackView.initialItem: emptySelection rightPanelStackView.width: Utils.getSizeWithScreenRatio(360) diff --git a/Linphone/view/Page/Window/Call/CallsWindow.qml b/Linphone/view/Page/Window/Call/CallsWindow.qml index e59d8bb1..792ed297 100644 --- a/Linphone/view/Page/Window/Call/CallsWindow.qml +++ b/Linphone/view/Page/Window/Call/CallsWindow.qml @@ -13,6 +13,7 @@ import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle AbstractWindow { id: mainWindow flags: Qt.Window + color: DefaultStyle.grey_0 minimumWidth: Utils.getSizeWithScreenRatio(1020) minimumHeight: Utils.getSizeWithScreenRatio(700)