- Add type detection for three different model types:
- QStringList (video devices): plain strings
- Audio devices: objects with {id, display_name}
- Simple entries (language, color): objects with {text, value}
- Set textRole: "" for video devices ComboBox (QStringList)
- Fix ComboBox popup background color for dark mode
- Add window background color to CallsWindow for dark mode
- Update documentation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
274 lines
9.9 KiB
Markdown
274 lines
9.9 KiB
Markdown
# 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
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## 4. ComboSetting unterstützt verschiedene Model-Typen
|
|
|
|
### Problem
|
|
Die ComboSetting-Komponente konnte nur mit einem Model-Typ umgehen. Es gibt aber drei verschiedene Typen:
|
|
1. **Audio-Geräte**: `QVariantList` mit Objekten `{id: "...", display_name: "..."}`
|
|
2. **Einfache Einträge**: `QVariantList` mit Objekten `{text: "...", value: "..."}`
|
|
3. **Video-Geräte**: `QStringList` mit einfachen Strings
|
|
|
|
### Symptome
|
|
- Audio-Geräte (Lautsprecher, Mikrofon, Klingel) wurden nach Neustart nicht korrekt angezeigt
|
|
- Kamera-Dropdown zeigte keine Gerätenamen an (nur leere Einträge)
|
|
|
|
### Lösung
|
|
**Datei:** `Linphone/view/Control/Button/Settings/ComboSetting.qml`
|
|
|
|
Die `currentIndex`-Berechnung, `onCurrentIndexChanged` und `Binding.value` wurden erweitert, um alle drei Typen zu erkennen und korrekt zu verarbeiten:
|
|
|
|
```qml
|
|
currentIndex: Utils.findIndex(model, function (entry) {
|
|
var currentVal = propertyOwnerGui
|
|
? propertyOwnerGui.core[mainItem.propertyName]
|
|
: propertyOwner[mainItem.propertyName]
|
|
// Handle different entry types
|
|
if (typeof entry === 'string') {
|
|
// QStringList (video devices): compare strings directly
|
|
return entry === currentVal
|
|
} else if (entry.id !== undefined) {
|
|
// Audio devices: compare by id
|
|
return currentVal && entry.id === currentVal.id
|
|
} else if (entry.value !== undefined) {
|
|
// Simple entries (language, color): compare by value
|
|
return entry.value === currentVal
|
|
}
|
|
return false
|
|
})
|
|
```
|
|
|
|
**Datei:** `Linphone/view/Control/Form/Settings/MultimediaSettings.qml`
|
|
|
|
Für die Kamera-ComboBox wurde `textRole: ""` gesetzt, da QStringList-Models keine Properties haben:
|
|
|
|
```qml
|
|
ComboSetting {
|
|
id: videoDevicesCbox
|
|
entries: SettingsCpp.videoDevices
|
|
propertyName: "videoDevice"
|
|
propertyOwner: SettingsCpp
|
|
textRole: "" // Empty for QStringList models
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### Technischer Hintergrund
|
|
|
|
| Model-Typ | Beispiel | Vergleich | Rückgabewert |
|
|
|-----------|----------|-----------|--------------|
|
|
| QStringList | `"V4L2: /dev/video0"` | `entry === currentVal` | `entry` (String) |
|
|
| Audio-Geräte | `{id: "pulse:0", display_name: "Speaker"}` | `entry.id === currentVal.id` | `entry` (Objekt) |
|
|
| Einfache Einträge | `{text: "English", value: "en"}` | `entry.value === currentVal` | `entry.value` (String) |
|
|
|
|
## Zusammenfassung der geänderten Dateien
|
|
|
|
| Datei | Änderung |
|
|
|-------|----------|
|
|
| `ComboSetting.qml` | Unterstützung für drei Model-Typen (QStringList, Audio-Geräte, einfache Einträge) |
|
|
| `MultimediaSettings.qml` | `textRole: ""` für Kamera-ComboBox |
|
|
| `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 |
|