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)