implement album export, finish WinUI styles, cleanup code

This commit is contained in:
uncor3
2026-03-06 04:47:23 +03:00
parent 35c5985f47
commit 9043350731
67 changed files with 1340 additions and 587 deletions
+76 -11
View File
@@ -1,17 +1,38 @@
QWidget {
background: transparent;
color: rgb(255, 255, 255);
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
}
QMessageBox {
background-color: rgba(255, 255, 255, 16);
border: 1px solid rgba(255, 255, 255, 13);
border-radius: 8px;
}
QMessageBox QLabel {
background-color: transparent;
color: rgb(255, 255, 255);
}
QMessageBox QPushButton {
background-color: rgba(255, 255, 255, 18);
border: 1px solid rgba(255, 255, 255, 13);
border-radius: 7px;
min-height: 32px;
min-width: 80px;
padding: 5px 15px;
}
/*MENU*/
QMenuBar {
background-color: transparent;
color: white;
padding: 10px;
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
}
@@ -33,7 +54,7 @@ QMenuBar::item:pressed {
}
QMenu {
background-color: transparent;
background-color: rgba(0, 0, 0, 210);
padding-left: 1px;
padding-top: 1px;
border-radius: 5px;
@@ -173,7 +194,7 @@ QCheckBox::indicator:pressed {
QCheckBox::indicator:checked {
background-color: %1;
border: 2px solid %1;
image: url(:/CheckBox/img dark/CheckBox.png);
image: url(:/resources/win/dark/CheckBox.png);
}
QCheckBox::indicator:checked:pressed {
@@ -656,16 +677,47 @@ QComboBox::down-arrow:disabled {
image: url(:/resources/win/dark/ComboBoxDisabled.png);
}
/*COMBOBOX POPUP*/
QComboBox QAbstractItemView {
background-color: rgba(0, 0, 0, 210);
border: 1px solid rgba(255, 255, 255, 13);
border-radius: 5px;
padding: 3px;
outline: 0;
}
QComboBox QAbstractItemView::item {
background-color: transparent;
padding: 5px 10px;
min-height: 26px;
border-radius: 4px;
}
QComboBox QAbstractItemView::item:selected {
background-color: rgba(255, 255, 255, 16);
color: rgb(255, 255, 255);
}
QComboBox QAbstractItemView::item:!selected:hover {
background-color: rgba(255, 255, 255, 10);
color: rgb(255, 255, 255);
}
QComboBox QAbstractItemView::item:disabled {
color: rgb(150, 150, 150);
}
/*LINEEDIT*/
QLineEdit {
background-color: rgba(255, 255, 255, 16);
border: 1px solid rgba(255, 255, 255, 13);
font-size: 16px;
font-size: 14px;
font-family: "Segoe UI", serif;
font-weight: 500;
border-radius: 7px;
border-bottom: 1px solid rgba(255, 255, 255, 150);
padding: 5px;
min-height: 30px;
}
QLineEdit:hover {
@@ -790,7 +842,7 @@ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
QTextEdit {
background-color: rgba(255, 255, 255, 16);
border: 1px solid rgba(255, 255, 255, 13);
font-size: 16px;
font-size: 14px;
font-family: "Segoe UI", serif;
font-weight: 500;
border-radius: 7px;
@@ -824,7 +876,7 @@ QCalendarWidget {
QCalendarWidget QToolButton {
height: 36px;
font-size: 18px;
font-size: 14px;
background-color: rgba(255, 255, 255, 0);
margin: 5px;
}
@@ -1021,7 +1073,7 @@ QTreeView:disabled {
/*TOGGLESWITCH*/
#toggleSwitch {
color: rgb(255, 255, 255);
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
}
@@ -1083,7 +1135,7 @@ QTreeView:disabled {
/*HYPERLINKBUTTON*/
#hyperlinkButton {
color: %1;
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
border-radius: 5px;
background-color: rgba(255, 255, 255, 0);
@@ -1106,7 +1158,7 @@ QTreeView:disabled {
/*LISTVIEW*/
QListView {
background-color: transparent;
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
padding: 7px;
@@ -1123,4 +1175,17 @@ QListView::item:selected {
color: white;
border-radius: 5px;
padding-left: 0px;
}
}
QWidget#navWidget {
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 13);
background-color: rgba(255, 255, 255, 16);
padding-left: 10px;
padding-right: 10px;
}
QWidget#VirtualLocationWidget {
background-color: rgb(0, 0, 0);
}
+235 -167
View File
@@ -1,17 +1,37 @@
QWidget {
background: transparent;
color: rgb(0, 0, 0);
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
}
QMessageBox {
background-color: #f0f0f0;
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 8px;
}
QMessageBox QLabel {
background-color: transparent;
color: rgb(0, 0, 0);
}
QMessageBox QPushButton {
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 7px;
min-height: 32px;
min-width: 80px;
padding: 5px 15px;
}
/*MENU*/
QMenuBar {
background-color: transparent;
color: rgba(0, 0, 0);
background-color: transparent;
color: rgb(0, 0, 0);
padding: 10px;
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
}
@@ -24,20 +44,20 @@ QMenuBar::item {
}
QMenuBar::item:selected {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QMenuBar::item:pressed {
background-color: rgb(0, 0, 0, 7);
color: rgb(0, 0, 0, 150);
background-color: rgba(0, 0, 0, 7);
color: rgba(0, 0, 0, 150);
}
QMenu {
background-color: transparent;
background-color: rgba(0, 0, 0, 7);
padding-left: 1px;
padding-top: 1px;
border-radius: 5px;
border: 1px solid rgb(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
}
QMenu::item {
@@ -49,11 +69,11 @@ QMenu::item {
}
QMenu::item:selected {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QMenu::item:pressed {
background-color: rgb(0, 0, 0, 7);
background-color: rgba(0, 0, 0, 7);
}
QMenu::right-arrow {
@@ -63,36 +83,38 @@ QMenu::right-arrow {
}
QMenuBar:disabled {
color: rgb(0, 0, 0, 150);
color: rgba(0, 0, 0, 150);
}
QMenu::item:disabled {
color: rgb(0, 0, 0, 150);
color: rgba(0, 0, 0, 150);
background-color: transparent;
}
/*PUSHBUTTON*/
QPushButton {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 7px;
min-height: 38px;
max-height: 38px;
padding-left: 7px;
padding-right: 7px;
}
QPushButton:hover {
background-color: rgb(0, 0, 0, 10);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 10);
border: 1px solid rgba(0, 0, 0, 13);
}
QPushButton::pressed {
color: rgb(0, 0, 0, 150);
color: rgba(0, 0, 0, 150);
}
QPushButton::disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
/*RADIOBUTTON*/
@@ -106,16 +128,16 @@ QRadioButton::indicator {
height: 22px;
border-radius: 13px;
border: 2px solid #999999;
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
margin-right: 5px;
}
QRadioButton::indicator:hover {
background-color: rgb(0, 0, 0, 0);
background-color: rgba(0, 0, 0, 0);
}
QRadioButton::indicator:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
border: 2px solid #bbbbbb;
image: url(:/resources/win/light/RadioButton.png);
}
@@ -136,12 +158,12 @@ QRadioButton::indicator:checked:pressed {
}
QRadioButton:disabled {
color: rgb(0, 0, 0, 110);
color: rgba(0, 0, 0, 110);
}
QRadioButton::indicator:disabled {
border: 2px solid #bbbbbb;
background-color: rgb(0, 0, 0, 0);
background-color: rgba(0, 0, 0, 0);
}
/*CHECKBOX*/
@@ -155,16 +177,16 @@ QCheckBox::indicator {
height: 22px;
border-radius: 5px;
border: 2px solid #999999;
background-color: rgb(0, 0, 0, 0);
background-color: rgba(0, 0, 0, 0);
margin-right: 5px;
}
QCheckBox::indicator:hover {
background-color: rgb(0, 0, 0, 15);
background-color: rgba(0, 0, 0, 15);
}
QCheckBox::indicator:pressed {
background-color: rgb(0, 0, 0, 24);
background-color: rgba(0, 0, 0, 24);
border: 2px solid #bbbbbb;
}
@@ -180,33 +202,33 @@ QCheckBox::indicator:checked:pressed {
}
QCheckBox:disabled {
color: rgb(0, 0, 0, 110);
color: rgba(0, 0, 0, 110);
}
QCheckBox::indicator:disabled {
border: 2px solid #bbbbbb;
background-color: rgb(0, 0, 0, 0);
background-color: rgba(0, 0, 0, 0);
}
/*GROUPBOX*/
QGroupBox {
border-radius: 5px;
border: 1px solid rgb(0, 0, 0, 13);
margin-top: 36px;
border: 1px solid rgba(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 10);
margin-top: 30px;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top left;
background-color: rgb(0, 0, 0, 10);
padding: 7px 15px;
/* padding: 7px 15px;
margin-left: 5px;
border-top-left-radius: 5px;
border-top-right-radius: 5px;
border-top-right-radius: 5px; */
}
QGroupBox::title::disabled {
color: rgb(0, 0, 0, 150);
color: rgba(0, 0, 0, 150);
}
/*TABWIDGET*/
@@ -218,7 +240,7 @@ QWidget {
}
QTabWidget::pane {
border: 1px solid rgb(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
}
@@ -233,43 +255,43 @@ QTabBar::tab {
}
QTabBar::tab:hover {
background-color: rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 13);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
QTabBar::tab:selected {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
}
QTabBar::tab:disabled {
color: rgb(0, 0, 0, 150)
color: rgba(0, 0, 0, 150)
}
/*SPINBOX*/
QSpinBox {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
padding-left: 10px;
min-height: 38px;
max-height: 38px;
min-width: 100px;
border-bottom: 1px solid rgb(0, 0, 0, 100);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QSpinBox:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
border-bottom: 1px solid rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QSpinBox::focus {
background-color: rgb(0, 0, 0, 5);
border: 1px solid rgb(0, 0, 0, 10);
color: rgb(0, 0, 0, 200);
background-color: rgba(0, 0, 0, 5);
border: 1px solid rgba(0, 0, 0, 10);
color: rgba(0, 0, 0, 200);
border-bottom: 2px solid %1;
}
@@ -287,11 +309,11 @@ QSpinBox::up-button {
}
QSpinBox::up-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QSpinBox::up-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QSpinBox::down-button {
@@ -308,11 +330,11 @@ QSpinBox::down-button {
}
QSpinBox::down-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QSpinBox::down-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QSpinBox::drop-down {
@@ -321,9 +343,9 @@ QSpinBox::drop-down {
}
QSpinBox:disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
QSpinBox::up-button:disabled {
@@ -336,26 +358,26 @@ QSpinBox::down-button:disabled {
/*DOUBLESPINBOX*/
QDoubleSpinBox {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
padding-left: 10px;
min-height: 38px;
max-height: 38px;
min-width: 100px;
border-bottom: 1px solid rgb(0, 0, 0, 100);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QDoubleSpinBox:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
border-bottom: 1px solid rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QDoubleSpinBox::focus {
background-color: rgb(0, 0, 0, 5);
border: 1px solid rgb(0, 0, 0, 10);
color: rgb(0, 0, 0, 200);
background-color: rgba(0, 0, 0, 5);
border: 1px solid rgba(0, 0, 0, 10);
color: rgba(0, 0, 0, 200);
border-bottom: 2px solid %1;
}
@@ -373,11 +395,11 @@ QDoubleSpinBox::up-button {
}
QDoubleSpinBox::up-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QDoubleSpinBox::up-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QDoubleSpinBox::down-button {
@@ -394,11 +416,11 @@ QDoubleSpinBox::down-button {
}
QDoubleSpinBox::down-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QDoubleSpinBox::down-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QDoubleSpinBox::drop-down {
@@ -407,9 +429,9 @@ QDoubleSpinBox::drop-down {
}
QDoubleSpinBox:disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
QDoubleSpinBox::up-button:disabled {
@@ -422,26 +444,26 @@ QDoubleSpinBox::down-button:disabled {
/*DATETIMEEDIT*/
QDateTimeEdit {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
padding-left: 10px;
min-height: 38px;
max-height: 38px;
min-width: 100px;
border-bottom: 1px solid rgb(0, 0, 0, 100);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QDateTimeEdit:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
border-bottom: 1px solid rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QDateTimeEdit::focus {
background-color: rgb(0, 0, 0, 5);
border: 1px solid rgb(0, 0, 0, 10);
color: rgb(0, 0, 0, 200);
background-color: rgba(0, 0, 0, 5);
border: 1px solid rgba(0, 0, 0, 10);
color: rgba(0, 0, 0, 200);
border-bottom: 2px solid %1;
}
@@ -459,11 +481,11 @@ QDateTimeEdit::up-button {
}
QDateTimeEdit::up-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QDateTimeEdit::up-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QDateTimeEdit::down-button {
@@ -480,11 +502,11 @@ QDateTimeEdit::down-button {
}
QDateTimeEdit::down-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QDateTimeEdit::down-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QDateTimeEdit::drop-down {
@@ -493,9 +515,9 @@ QDateTimeEdit::drop-down {
}
QDateTimeEdit:disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
QDateTimeEdit::up-button:disabled {
@@ -514,7 +536,7 @@ QSlider:vertical {
QSlider::groove:vertical {
width: 5px;
background-color: rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 100);
border-radius: 2px;
}
@@ -546,7 +568,7 @@ QSlider::handle:vertical:pressed {
}
QSlider::groove:vertical:disabled {
background-color: rgb(0, 0, 0, 75);
background-color: rgba(0, 0, 0, 75);
}
QSlider::handle:vertical:disabled {
@@ -562,7 +584,7 @@ QSlider:horizontal {
QSlider::groove:horizontal {
height: 5px;
background-color: rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 100);
border-radius: 2px;
}
@@ -594,7 +616,7 @@ QSlider::handle:horizontal:pressed {
}
QSlider::groove:horizontal:disabled {
background-color: rgb(0, 0, 0, 75);
background-color: rgba(0, 0, 0, 75);
}
QSlider::handle:horizontal:disabled {
@@ -617,8 +639,8 @@ QProgressBar::chunk {
/*COMBOBOX*/
QComboBox {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
padding-left: 10px;
min-height: 38px;
@@ -626,12 +648,12 @@ QComboBox {
}
QComboBox:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
}
QComboBox::pressed {
border: 1px solid rgb(0, 0, 0, 10);
border: 1px solid rgba(0, 0, 0, 10);
}
QComboBox::down-arrow {
@@ -644,61 +666,94 @@ QComboBox::drop-down {
}
QComboBox:disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
QComboBox::down-arrow:disabled {
image: url(:/resources/win/light/ComboBoxDisabled.png);
}
/*COMBOBOX POPUP*/
QComboBox QAbstractItemView {
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
padding: 3px;
outline: 0;
}
QComboBox QAbstractItemView::item {
background-color: transparent;
padding: 5px 10px;
min-height: 26px;
border-radius: 4px;
color: rgb(0, 0, 0);
}
QComboBox QAbstractItemView::item:selected {
background-color: rgba(0, 0, 0, 13);
color: rgb(0, 0, 0);
}
QComboBox QAbstractItemView::item:!selected:hover {
background-color: rgba(0, 0, 0, 10);
color: rgb(0, 0, 0);
}
QComboBox QAbstractItemView::item:disabled {
color: rgba(0, 0, 0, 150);
}
/*LINEEDIT*/
QLineEdit {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
font-size: 16px;
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
font-size: 14px;
font-family: "Segoe UI", serif;
font-weight: 500;
border-radius: 7px;
border-bottom: 1px solid rgb(0, 0, 0, 100);
border-bottom: 1px solid rgba(0, 0, 0, 100);
padding-top: 0px;
padding-left: 5px;
min-height: 30px;
}
QLineEdit:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
border-bottom: 1px solid rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QLineEdit:focus {
border-bottom: 2px solid %1;
background-color: rgb(0, 0, 0, 5);
border-top: 1px solid rgb(0, 0, 0, 13);
border-left: 1px solid rgb(0, 0, 0, 13);
border-right: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 5);
border-top: 1px solid rgba(0, 0, 0, 13);
border-left: 1px solid rgba(0, 0, 0, 13);
border-right: 1px solid rgba(0, 0, 0, 13);
}
QLineEdit:disabled {
color: rgb(0, 0, 0, 150);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 150);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
/*SCROLLVERTICAL*/
QScrollBar:vertical {
border: 6px solid rgb(0, 0, 0, 0);
border: 6px solid rgba(0, 0, 0, 0);
margin: 14px 0px 14px 0px;
width: 16px;
}
QScrollBar:vertical:hover {
border: 5px solid rgb(0, 0, 0, 0);
border: 5px solid rgba(0, 0, 0, 0);
}
QScrollBar::handle:vertical {
background-color: rgb(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 110);
border-radius: 2px;
min-height: 25px;
}
@@ -737,17 +792,17 @@ QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
/*SCROLLHORIZONTAL*/
QScrollBar:horizontal {
border: 6px solid rgb(0, 0, 0, 0);
border: 6px solid rgba(0, 0, 0, 0);
margin: 0px 14px 0px 14px;
height: 16px;
}
QScrollBar:horizontal:hover {
border: 5px solid rgb(0, 0, 0, 0);
border: 5px solid rgba(0, 0, 0, 0);
}
QScrollBar::handle:horizontal {
background-color: rgb(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 110);
border-radius: 2px;
min-width: 25px;
}
@@ -786,34 +841,34 @@ QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
/*TEXTEDIT*/
QTextEdit {
background-color: rgb(0, 0, 0, 7);
border: 1px solid rgb(0, 0, 0, 13);
font-size: 16px;
background-color: rgba(0, 0, 0, 7);
border: 1px solid rgba(0, 0, 0, 13);
font-size: 14px;
font-family: "Segoe UI", serif;
font-weight: 500;
border-radius: 7px;
border-bottom: 1px solid rgb(0, 0, 0, 100);
border-bottom: 1px solid rgba(0, 0, 0, 100);
padding: 5px;
}
QTextEdit:hover {
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 13);
border-bottom: 1px solid rgb(0, 0, 0, 100);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-bottom: 1px solid rgba(0, 0, 0, 100);
}
QTextEdit:focus {
background-color: rgb(0, 0, 0, 5);
border-top: 1px solid rgb(0, 0, 0, 13);
border-left: 1px solid rgb(0, 0, 0, 13);
border-right: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 5);
border-top: 1px solid rgba(0, 0, 0, 13);
border-left: 1px solid rgba(0, 0, 0, 13);
border-right: 1px solid rgba(0, 0, 0, 13);
border-bottom: 2px solid %1;
}
QTextEdit:disabled {
color: rgb(0, 0, 0, 110);
background-color: rgb(0, 0, 0, 13);
border: 1px solid rgb(0, 0, 0, 5);
color: rgba(0, 0, 0, 110);
background-color: rgba(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 5);
}
/*CALENDAR*/
@@ -822,14 +877,14 @@ QCalendarWidget {
QCalendarWidget QToolButton {
height: 36px;
font-size: 18px;
background-color: rgb(0, 0, 0, 0);
font-size: 14px;
background-color: rgba(0, 0, 0, 0);
margin: 5px;
}
QCalendarWidget QWidget#qt_calendar_navigationbar {
background-color: rgb(0, 0, 0, 0);
border: 1px solid rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 0);
border: 1px solid rgba(0, 0, 0, 13);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
border-bottom-left-radius: 0px;
@@ -852,12 +907,12 @@ QCalendarWidget QMenu {
}
#qt_calendar_prevmonth:hover, #qt_calendar_nextmonth:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
border-radius: 5px;
}
#qt_calendar_prevmonth:pressed, #qt_calendar_nextmonth:pressed {
background-color: rgb(0, 0, 0, 7);
background-color: rgba(0, 0, 0, 7);
border-radius: 5px;
}
@@ -868,12 +923,12 @@ QCalendarWidget QMenu {
}
#qt_calendar_yearbutton:hover, #qt_calendar_monthbutton:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
border-radius: 5px;
}
#qt_calendar_yearbutton:pressed, #qt_calendar_monthbutton:pressed {
background-color: rgb(0, 0, 0, 7);
background-color: rgba(0, 0, 0, 7);
border-radius: 5px;
}
@@ -886,9 +941,9 @@ QCalendarWidget QSpinBox {
}
QCalendarWidget QSpinBox::focus {
background-color: rgb(0, 0, 0, 5);
border: 1px solid rgb(0, 0, 0, 10);
color: rgb(0, 0, 0, 200);
background-color: rgba(0, 0, 0, 5);
border: 1px solid rgba(0, 0, 0, 10);
color: rgba(0, 0, 0, 200);
border-bottom: 2px solid %1;
}
@@ -906,11 +961,11 @@ QCalendarWidget QSpinBox::up-button {
}
QCalendarWidget QSpinBox::up-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QCalendarWidget QSpinBox::up-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QCalendarWidget QSpinBox::down-button {
@@ -927,22 +982,22 @@ QCalendarWidget QSpinBox::down-button {
}
QCalendarWidget QSpinBox::down-button:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
QCalendarWidget QSpinBox::down-button:pressed {
background-color: rgb(0, 0, 0, 5);
background-color: rgba(0, 0, 0, 5);
}
QCalendarWidget QWidget {
alternate-background-color: rgb(0, 0, 0, 0);
alternate-background-color: rgba(0, 0, 0, 0);
}
QCalendarWidget QAbstractItemView:enabled {
color: rgb(0, 0, 0);
selection-background-color: %1;
selection-color: black;
border: 1px solid rgb(0, 0, 0, 10);
border: 1px solid rgba(0, 0, 0, 10);
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-bottom-left-radius: 5px;
@@ -954,7 +1009,7 @@ QCalendarWidget QAbstractItemView:disabled {
color: rgb(30, 30, 30);
selection-background-color: rgb(30, 30, 30);
selection-color: black;
border: 1px solid rgb(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-top-left-radius: 0px;
border-top-right-radius: 0px;
border-bottom-left-radius: 5px;
@@ -962,7 +1017,7 @@ QCalendarWidget QAbstractItemView:disabled {
}
#qt_calendar_yearbutton:disabled, #qt_calendar_monthbutton:disabled {
color: rgb(0, 0, 0, 110);
color: rgba(0, 0, 0, 110);
}
#qt_calendar_prevmonth:disabled {
@@ -976,7 +1031,7 @@ QCalendarWidget QAbstractItemView:disabled {
/*TREEWIDGET*/
QTreeView {
background-color: transparent;
border: 1px solid rgb(0, 0, 0, 13);
border: 1px solid rgba(0, 0, 0, 13);
border-radius: 5px;
outline: 0;
padding-right: 5px;
@@ -989,14 +1044,14 @@ QTreeView::item {
QTreeView::item:selected {
color: rgb(0, 0, 0);
background-color: rgb(0, 0, 0, 7);
background-color: rgba(0, 0, 0, 7);
border-radius: 5px;
margin-bottom: 3px;
padding-left: 0px;
}
QTreeView::item:!selected:hover {
background-color: rgb(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 13);
border-radius: 5px;
margin-bottom: 3px;
padding-left: 0px;
@@ -1013,7 +1068,7 @@ QTreeView::branch:open:has-children:has-siblings {
}
QTreeView:disabled {
color: rgb(0, 0, 0, 110);
color: rgba(0, 0, 0, 110);
}
/*TOGGLESWITCH*/
@@ -1029,7 +1084,7 @@ QTreeView:disabled {
height: 22px;
border-radius: 13px;
border: 2px solid #999999;
background-color: rgb(0, 0, 0, 0);
background-color: rgba(0, 0, 0, 0);
image: url(:/resources/win/light/ToggleSwitchOff.png);
margin-right: 5px;
padding-right: 25px;
@@ -1037,12 +1092,12 @@ QTreeView:disabled {
}
#toggleSwitch::indicator:hover {
background-color: rgb(0, 0, 0, 15);
background-color: rgba(0, 0, 0, 15);
image: url(:/resources/win/light/ToggleSwitchOffHover.png);
}
#toggleSwitch::indicator:pressed {
background-color: rgb(0, 0, 0, 24);
background-color: rgba(0, 0, 0, 24);
width: 26px;
padding-right: 21px;
image: url(:/resources/win/light/ToggleSwitchOffPressed.png);
@@ -1070,7 +1125,7 @@ QTreeView:disabled {
}
#toggleSwitch:disabled {
color: rgb(0, 0, 0, 110);
color: rgba(0, 0, 0, 110);
}
#toggleSwitch::indicator:disabled {
@@ -1089,22 +1144,22 @@ QTreeView:disabled {
}
#hyperlinkButton:hover {
background-color: rgb(0, 0, 0, 10);
background-color: rgba(0, 0, 0, 10);
}
#hyperlinkButton::pressed {
background-color: rgb(0, 0, 0, 7);
background-color: rgba(0, 0, 0, 7);
color: %1;
}
#hyperlinkButton:disabled {
color: rgb(0, 0, 0, 110)
color: rgba(0, 0, 0, 110);
}
/*LISTVIEW*/
QListView {
background-color: transparent;
font-size: 17px;
font-size: 14px;
font-family: "Segoe UI Variable Small", serif;
font-weight: 400;
padding: 7px;
@@ -1121,4 +1176,17 @@ QListView::item:selected {
color: black;
border-radius: 5px;
padding-left: 0px;
}
}
QWidget#navWidget {
border-radius: 20px;
border: 1px solid rgba(0, 0, 0, 13);
background-color: rgba(0, 0, 0, 10);
padding-left: 10px;
padding-right: 10px;
}
QWidget#VirtualLocationWidget {
background-color: rgb(255, 255, 255);
}
+25 -11
View File
@@ -593,14 +593,11 @@ void AfcExplorerWidget::setupFileExplorer()
navLayout->setContentsMargins(0, 0, 0, 0);
navLayout->setSpacing(0);
// Create navigation buttons using ClickableIconWidget
QWidget *explorerLeftSideNavButtons = new QWidget();
QHBoxLayout *leftNavLayout = new QHBoxLayout(explorerLeftSideNavButtons);
// explorerLeftSideNavButtons->setStyleSheet("border-right: 1px solid
// red;");
leftNavLayout->setContentsMargins(0, 0, 0, 0);
leftNavLayout->setSpacing(1);
// rename to ziconwidget
m_backButton = new ZIconWidget(
QIcon(":/resources/icons/MaterialSymbolsArrowLeftAlt.png"), "Go Back");
m_backButton->setEnabled(false);
@@ -654,9 +651,21 @@ void AfcExplorerWidget::setupFileExplorer()
// File list
m_fileList = new QListWidget();
m_fileList->setSelectionMode(QAbstractItemView::ExtendedSelection);
QScrollBar *vBar = m_fileList->QAbstractScrollArea::verticalScrollBar();
vBar->setStyleSheet(styleSheet());
#ifdef WIN32
m_fileList->setStyleSheet(R"(
QScrollBar:vertical {
border: 6px solid rgba(0, 0, 0, 0);
margin: 14px 0px 14px 0px;
width: 16px;
background-color: transparent;
}
QScrollBar::handle:vertical {
background-color: rgba(0, 0, 0, 110);
border-radius: 2px;
min-height: 25px;
}
)");
#endif
fileListLayout->addWidget(m_fileList);
// Create error widget
@@ -720,8 +729,10 @@ void AfcExplorerWidget::setupFileExplorer()
}
updateNavigationButtons();
updateButtonStates(); // Initialize button states
updateButtonStates();
#ifndef WIN32
updateNavStyles();
#endif
}
void AfcExplorerWidget::onAddToFavoritesClicked()
@@ -744,6 +755,7 @@ void AfcExplorerWidget::onAddToFavoritesClicked()
}
}
#ifndef WIN32
void AfcExplorerWidget::updateNavStyles()
{
if (!m_navWidget || !m_addressBar)
@@ -768,7 +780,8 @@ void AfcExplorerWidget::updateNavStyles()
.arg(bgColor.lighter().name())
.arg(accentColor.name());
m_navWidget->setStyleSheet(navStyles);
if (m_navWidget->styleSheet() != navStyles)
m_navWidget->setStyleSheet(navStyles);
// Update address bar styles to complement the nav widget
QString addressBarStyles =
@@ -779,9 +792,10 @@ void AfcExplorerWidget::updateNavStyles()
.arg(borderColor.lighter().name())
.arg(isDark ? QColor(Qt::black).name() : QColor(Qt::white).name())
.arg(COLOR_ACCENT_BLUE.name());
m_addressBar->setStyleSheet(addressBarStyles);
if (m_addressBar->styleSheet() != addressBarStyles)
m_addressBar->setStyleSheet(addressBarStyles);
}
#endif
void AfcExplorerWidget::updateButtonStates()
{
+3 -2
View File
@@ -114,9 +114,10 @@ private:
const char *local_path);
int importFileToDevice(AfcClientHandle *afc, const char *device_path,
const char *local_path);
void updateNavStyles();
void updateButtonStates();
void goUp();
#ifndef WIN32
void updateNavStyles();
protected:
void changeEvent(QEvent *event) override
@@ -126,6 +127,6 @@ protected:
}
QWidget::changeEvent(event);
}
#endif
};
#endif // AFCEXPLORER_H
+22 -20
View File
@@ -446,18 +446,8 @@ void AppContext::addDevice(iDescriptor::Uniq uniq,
}
qDebug() << "Device initialized: " << uniq;
/*
We need this because wireless devices get initialized
with Mac addresses. Even though a Mac address is unique, we
are better off using the "UDID" as the unique identifier.
This is only required for wireless devices, Usb devices
already use the UDID but it doesn't hurt to set it for them
as well
*/
uniq.set(initResult->deviceInfo.UniqueDeviceID, false);
iDescriptorDevice *device = new iDescriptorDevice{
.udid = uniq.get().toStdString(),
.udid = initResult->deviceInfo.UniqueDeviceID,
.conn_type = conn_type,
.provider = initResult->provider,
.deviceInfo = initResult->deviceInfo,
@@ -502,24 +492,36 @@ int AppContext::getConnectedDeviceCount() const
// #endif
}
void AppContext::removeDevice(QString _udid)
void AppContext::removeDevice(iDescriptor::Uniq uniq)
{
const std::string udid = _udid.toStdString();
qDebug() << "AppContext::removeDevice device with UUID:"
<< QString::fromStdString(udid);
qDebug() << "AppContext::removeDevice device with"
<< (uniq.isMac() ? "MAC" : "UDID") << uniq.get();
if (m_pendingDevices.contains(_udid)) {
m_pendingDevices.removeAll(_udid);
emit devicePairingExpired(_udid);
std::string udid = uniq.isUdid() ? uniq.get().toStdString() : "";
QString q_udid = QString::fromStdString(udid);
if (uniq.isMac()) {
const iDescriptorDevice *device = getDeviceByMacAddress(uniq.get());
if (device) {
udid = device->udid;
q_udid = QString::fromStdString(udid);
} else {
qDebug() << "Device with MAC " << uniq << " not found.";
}
}
if (m_pendingDevices.contains(q_udid)) {
m_pendingDevices.removeAll(q_udid);
emit devicePairingExpired(q_udid);
emit deviceChange();
return;
} else {
qDebug() << "Device with UUID " + _udid +
qDebug() << "Device with UUID " + q_udid +
" not found in pending devices.";
}
if (!m_devices.contains(udid)) {
qDebug() << "Device with UUID " + _udid +
qDebug() << "Device with UUID " + q_udid +
" not found in normal devices.";
return;
}
+1 -1
View File
@@ -90,7 +90,7 @@ signals:
void currentDeviceSelectionChanged(const DeviceSelection &selection);
void deviceHeartbeatFailed(const QString &macAddress, int tries);
public slots:
void removeDevice(QString udid);
void removeDevice(iDescriptor::Uniq uniq);
void addDevice(iDescriptor::Uniq udid,
DeviceMonitorThread::IdeviceConnectionType connType,
AddType addType, QString wifiMacAddress = QString(),
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef APPDOWNLOADDIALOG_H
#define APPDOWNLOADDIALOG_H
#include "appdownloadbasedialog.h"
#include "base/appdownload.h"
#include "iDescriptor-ui.h"
#include "zloadingwidget.h"
#include <QDialog>
-1
View File
@@ -19,7 +19,6 @@
#include "appinstalldialog.h"
#include "appcontext.h"
#include "appdownloadbasedialog.h"
#include "iDescriptor.h"
#include "servicemanager.h"
#include <QApplication>
+1 -1
View File
@@ -20,7 +20,7 @@
#ifndef APPINSTALLDIALOG_H
#define APPINSTALLDIALOG_H
#include "appdownloadbasedialog.h"
#include "base/appdownload.h"
#include "iDescriptor.h"
#include <QComboBox>
#include <QDialog>
+5 -3
View File
@@ -19,7 +19,6 @@
#include "appswidget.h"
#include "appcontext.h"
#include "appdownloadbasedialog.h"
#include "appdownloaddialog.h"
#include "appinstalldialog.h"
#include "appstoremanager.h"
@@ -87,8 +86,8 @@ void AppsWidget::setupUI()
QWidget *headerWidget = new QWidget();
headerWidget->setFixedHeight(60);
headerWidget->setStyleSheet(
"border-bottom: 1px solid #363d32; border-radius: 0px;");
// headerWidget->setStyleSheet(
// "border-bottom: 1px solid #363d32; border-radius: 0px;");
QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget);
headerLayout->setContentsMargins(20, 10, 20, 10);
@@ -210,11 +209,13 @@ void AppsWidget::handleInit()
m_statusLabel->setText("Failed to initialize");
m_loginButton->setText("Failed to initialize");
m_loginButton->setEnabled(false);
#ifndef WIN32
m_loginButton->setStyleSheet(
"background-color: #ccc; color: #666; "
"border: "
"none; border-radius: "
"4px; padding: 8px 16px; font-size: 14px;");
#endif
return;
}
/*
@@ -606,6 +607,7 @@ void AppsWidget::createAppCard(
// App name with sponsor indicator
QHBoxLayout *nameLayout = new QHBoxLayout();
QLabel *nameLabel = new QLabel(name);
// nameLabel->font().setSize(16);
nameLabel->setStyleSheet("font-size: 16px;");
nameLabel->setWordWrap(true);
nameLayout->addWidget(nameLabel);
@@ -17,8 +17,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "appdownloadbasedialog.h"
#include "appstoremanager.h"
#include "appdownload.h"
#include <QDesktopServices>
#include <QDir>
#include <QFutureWatcher>
@@ -59,6 +58,9 @@ AppDownloadBaseDialog::AppDownloadBaseDialog(const QString &appName,
{
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(20, 20, 20, 20);
#ifdef WIN32
setupWinWindow(this);
#endif
}
void AppDownloadBaseDialog::startDownloadProcess(const QString &bundleId,
@@ -20,6 +20,8 @@
#ifndef APPDOWNLOADBASEDIALOG_H
#define APPDOWNLOADBASEDIALOG_H
#include "../appstoremanager.h"
#include "../iDescriptor-ui.h"
#include <QDialog>
#include <QNetworkAccessManager>
#include <QProcess>
+6 -4
View File
@@ -23,13 +23,15 @@
#include "../platform/windows/win_common.h"
#endif
#ifdef WIN32
Tool::Tool(QWidget *parent) : WinToolWidget(parent)
#else
Tool::Tool(QWidget *parent) : QWidget(parent)
#endif
{
#ifdef __APPLE__
setupToolFrame(this);
#elif defined(WIN32)
setupWinWindow(this);
setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint |
Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
#else
#endif
}
-5
View File
@@ -30,12 +30,7 @@
#include "../platform/windows/widgets/wintoolwidget.h"
#endif
#ifdef WIN32
class Tool : public WinToolWidget
#else
class Tool : public QWidget
#endif
{
public:
explicit Tool(QWidget *parent = nullptr);
+5 -1
View File
@@ -137,9 +137,13 @@ void BatteryWidget::paintEvent(QPaintEvent *)
pen.setColor(palette().color(QPalette::Text));
painter.setPen(pen);
#ifndef WIN32
QFont textFont = QFont();
textFont.setPixelSize(widgetFrame.height() / 1.65);
textFont.setWeight(QFont::Bold);
#else
QFont textFont = QFont("Segoe UI Variable Small", 12);
#endif
textFont.setPixelSize(widgetFrame.height() / 1.65);
painter.setFont(textFont);
QFontMetrics fm(textFont);
QString percentageLevelString = QString("%1%").arg(m_value);
+8 -1
View File
@@ -26,6 +26,10 @@
#include <QScrollArea>
#include <QTimer>
#ifdef WIN32
#include "platform/windows/win_common.h"
#endif
CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent)
: Tool(parent), m_device(device), m_response(nullptr)
{
@@ -43,6 +47,9 @@ CableInfoWidget::CableInfoWidget(iDescriptorDevice *device, QWidget *parent)
void CableInfoWidget::setupUI()
{
setWindowTitle("Cable Information - iDescriptor");
setMinimumSize(500, 400);
m_mainLayout = new QVBoxLayout();
m_mainLayout->setSpacing(20);
m_mainLayout->setContentsMargins(20, 20, 20, 20);
@@ -81,7 +88,7 @@ void CableInfoWidget::setupUI()
m_loadingWidget = new ZLoadingWidget(true, this);
m_loadingWidget->setupContentWidget(m_mainLayout);
QVBoxLayout *layout = new QVBoxLayout(contentWidget());
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_loadingWidget);
+3 -2
View File
@@ -37,7 +37,7 @@ AFCFileTree get_file_tree(const iDescriptorDevice *device, bool checkDir,
// Use safe wrapper to read directory
IdeviceFfiError *err = ServiceManager::safeAfcReadDirectory(
device, path.c_str(), &dirs, count, altAfc);
device, path.c_str(), &dirs, &count, altAfc);
if (err) {
qDebug() << "Failed to read directory:" << path.c_str()
@@ -94,7 +94,8 @@ AFCFileTree get_file_tree(const iDescriptorDevice *device, bool checkDir,
// it's a dir
IdeviceFfiError *link_err =
ServiceManager::safeAfcReadDirectory(
device, fullPath.c_str(), &dir_contents, count, altAfc);
device, fullPath.c_str(), &dir_contents, &count,
altAfc);
if (!link_err) {
isDir = true;
+1 -4
View File
@@ -120,16 +120,13 @@ void parseOldDevice(PlistNavigator &ioreg, DeviceInfo &d)
parseOldDeviceBattery(ioreg, d);
}
// this is reused in the ui in deviceinfowidget
void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d)
{
d.batteryInfo.isCharging = ioreg["IsCharging"].getBool();
d.batteryInfo.fullyCharged = ioreg["FullyCharged"].getBool();
qDebug() << "Stalebatteryinfo:"
<< ioreg["BatteryData"]["StateOfCharge"].getUInt();
/* data is stale here so we need to calculate */
/* data is sometimes not accurate here so we need to calculate */
// d.batteryInfo.currentBatteryLevel =
// ioreg["BatteryData"]["StateOfCharge"].getUInt();
+3
View File
@@ -34,6 +34,9 @@ DevDiskImageHelper::DevDiskImageHelper(const iDescriptorDevice *device,
: QDialog(parent), m_device(device)
{
setAttribute(Qt::WA_DeleteOnClose);
#ifdef WIN32
setupWinWindow(this);
#endif
setWindowTitle("Developer Disk Image - iDescriptor");
setupUI();
+1
View File
@@ -20,6 +20,7 @@
#ifndef DEVDISKIMAGEHELPER_H
#define DEVDISKIMAGEHELPER_H
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include <QDialog>
#include <QLabel>
+4
View File
@@ -317,7 +317,11 @@ QPixmap DeviceImageWidget::createCompositeImage() const
QString currentTime = QDateTime::currentDateTime().toString("hh:mm");
QFont timeFont;
#ifndef WIN32
timeFont.setFamily("SF Pro Display, Helvetica, Arial");
#else
timeFont.setFamily("Segoe UI");
#endif
int fontSize = screenRect.width() / 5;
timeFont.setPointSize(fontSize);
timeFont.setWeight(QFont::Light);
+68 -60
View File
@@ -112,7 +112,6 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
// Right side: Info Table
QWidget *infoContainer = new QWidget();
// 2. Change the horizontal size policy from Expanding to Preferred
infoContainer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
QVBoxLayout *infoLayout = new QVBoxLayout(infoContainer);
@@ -127,7 +126,12 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
new QLabel(QString::fromStdString(device->deviceInfo.productType));
devProductType->setToolTip(
QString::fromStdString(device->deviceInfo.marketingName));
#ifndef WIN32
devProductType->setStyleSheet("font-size: 1rem; font-weight: bold;");
#else
devProductType->setStyleSheet(
mergeStyles(devProductType, "font-size: 18px; font-weight: 500;"));
#endif
QLabel *diskCapacityLabel = new QLabel(
QString::number(device->deviceInfo.diskInfo.totalDiskCapacity /
@@ -137,7 +141,6 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
diskCapacityLabel->setSizePolicy(QSizePolicy::Maximum,
QSizePolicy::Preferred);
diskCapacityLabel->setAttribute(Qt::WA_StyledBackground, true);
// background-color: rgba(0, 255, 30, 0.5);
diskCapacityLabel->setStyleSheet(QString("background-color: %1;"
"padding: 2px 4px;"
"color : white;"
@@ -151,9 +154,11 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
m_chargingStatusLabel->setStyleSheet(mergeStyles(
m_chargingStatusLabel,
(device->deviceInfo.batteryInfo.isCharging
? QString("QLabel#ChargingStatusLabel { color: %1; }")
? QString(
"QLabel#ChargingStatusLabel { color: %1; font-size: 14px; }")
.arg(COLOR_GREEN.name())
: QString("QLabel#ChargingStatusLabel { color: %1; }")
: QString(
"QLabel#ChargingStatusLabel { color: %1; font-size: 14px; }")
.arg(qApp->palette().color(QPalette::WindowText).name()))));
// Create the layout without a parent widget
QHBoxLayout *chargingLayout = new QHBoxLayout();
@@ -246,8 +251,6 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
infoItems.append({"Device Class:", createValueLabel(QString::fromStdString(
device->deviceInfo.deviceClass))});
infoItems.append({"Device Color:", createValueLabel(QString::fromStdString(
device->deviceInfo.deviceColor))});
infoItems.append(
{"Jailbroken:", createValueLabel(QString::fromStdString(
device->deviceInfo.jailbroken ? "Yes" : "No"))});
@@ -273,20 +276,22 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
{"Firmware Version:", createValueLabel(QString::fromStdString(
device->deviceInfo.firmwareVersion))});
// // FIXME: Battery Info
// // QWidget *batteryWidget = new QWidget();
// // QHBoxLayout *batteryLayout = new QHBoxLayout(batteryWidget);
// // batteryLayout->setContentsMargins(0, 0, 0, 0);
// // batteryLayout->setSpacing(5);
// // batteryLayout->addWidget(new
// // QLabel(device->deviceInfo.batteryInfo.health)); QPushButton
// *moreButton =
// // new QPushButton("More"); connect(moreButton, &QPushButton::clicked,
// this,
// // &DeviceInfoWidget::onBatteryMoreClicked);
// // batteryLayout->addWidget(moreButton);
// // batteryLayout->addStretch();
// // infoItems.append({"Battery Health:", batteryWidget});
// FIXME: Battery Info
QWidget *batteryWidget = new QWidget();
QHBoxLayout *batteryLayout = new QHBoxLayout(batteryWidget);
batteryLayout->setContentsMargins(0, 0, 0, 0);
batteryLayout->setSpacing(5);
batteryLayout->addWidget(new QLabel(device->deviceInfo.batteryInfo.health));
QPushButton *moreButton = new QPushButton("More");
moreButton->setStyleSheet(mergeStyles(
moreButton,
"QPushButton { height : 20px; min-height: 20px; padding: 2px "
"8px; font-size: 10px; }"));
connect(moreButton, &QPushButton::clicked, this,
&DeviceInfoWidget::onBatteryMoreClicked);
batteryLayout->addWidget(moreButton);
batteryLayout->addStretch();
infoItems.append({"Battery Health:", batteryWidget});
infoItems.append(
{"Production Device:",
@@ -362,10 +367,10 @@ DeviceInfoWidget::DeviceInfoWidget(const iDescriptorDevice *device,
mainLayout->addLayout(rightSideLayout);
mainLayout->addStretch();
// m_updateTimer = new QTimer(this);
// connect(m_updateTimer, &QTimer::timeout, this,
// &DeviceInfoWidget::updateBatteryInfo);
// m_updateTimer->start(30000); // Update every 30 seconds
m_updateTimer = new QTimer(this);
connect(m_updateTimer, &QTimer::timeout, this,
&DeviceInfoWidget::updateBatteryInfo);
m_updateTimer->start(30000); // Update every 30 seconds
}
DeviceInfoWidget::~DeviceInfoWidget() {}
@@ -385,47 +390,50 @@ void DeviceInfoWidget::onBatteryMoreClicked()
void DeviceInfoWidget::updateBatteryInfo()
{
// qDebug() << "Updating battery info...";
// plist_t diagnostics = nullptr;
// get_battery_info(m_device->deviceInfo.rawProductType, m_device->device,
// m_device->deviceInfo.is_iPhone, diagnostics);
qDebug() << "Updating battery info...";
plist_t diagnostics = nullptr;
// DONT BLOCK
get_battery_info(m_device->diagRelay.get(), diagnostics);
// if (!diagnostics) {
// qDebug() << "Failed to get diagnostics plist.";
// return;
// }
// /*DATA*/
// DeviceInfo &d = m_device->deviceInfo;
// qDebug() << "old device" << d.oldDevice;
// PlistNavigator ioreg = PlistNavigator(diagnostics)["IORegistry"];
// // if (d.oldDevice)
// // parseOldDeviceBattery(ioreg, d);
// // else
// // parseDeviceBattery(ioreg, d);
// /*UI*/
// updateChargingStatusIcon();
// m_chargingWattsWithCableTypeLabel->setText(
// QString::number(d.batteryInfo.watts) + "W" + "/" +
// (d.batteryInfo.usbConnectionType == BatteryInfo::ConnectionType::USB
// ? "USB"
// : "USB-C"));
if (!diagnostics) {
qDebug() << "Failed to get diagnostics plist.";
return;
}
/*DATA*/
DeviceInfo &d = const_cast<DeviceInfo &>(m_device->deviceInfo);
qDebug() << "old device" << d.oldDevice;
PlistNavigator ioreg = PlistNavigator(diagnostics);
if (d.oldDevice)
ServiceManager::safeParseOldDeviceBattery(m_device, ioreg, d);
else
ServiceManager::safeParseDeviceBattery(m_device, ioreg, d);
/*UI*/
updateChargingStatusIcon();
m_chargingWattsWithCableTypeLabel->setText(
QString::number(d.batteryInfo.watts) + "W" + "/" +
(d.batteryInfo.usbConnectionType == BatteryInfo::ConnectionType::USB
? "USB"
: "USB-C"));
// m_batteryWidget->updateContext(
// d.batteryInfo.isCharging,
// qBound<int>(1, d.batteryInfo.currentBatteryLevel, 100));
m_batteryWidget->updateContext(
d.batteryInfo.isCharging,
qBound<int>(1, d.batteryInfo.currentBatteryLevel, 100));
// FIXME: does diag c++ wrappers free this already ?
// plist_free(diagnostics);
}
void DeviceInfoWidget::updateChargingStatusIcon()
{
// if (m_device->deviceInfo.batteryInfo.isCharging) {
// m_chargingStatusLabel->setText("Charging");
// m_chargingStatusLabel->setStyleSheet(
// QString("color: %1;").arg(COLOR_GREEN.name()));
// m_lightningIconLabel->show();
if (m_device->deviceInfo.batteryInfo.isCharging) {
m_chargingStatusLabel->setText("Charging");
// FIXME
// m_chargingStatusLabel->setStyleSheet(
// QString("color: %1;").arg(COLOR_GREEN.name()));
m_lightningIconLabel->show();
// } else {
// m_chargingStatusLabel->setText("Not Charging");
// m_chargingStatusLabel->setStyleSheet("");
// m_lightningIconLabel->hide();
// }
} else {
m_chargingStatusLabel->setText("Not Charging");
// m_chargingStatusLabel->setStyleSheet("");
m_lightningIconLabel->hide();
}
}
+1
View File
@@ -23,6 +23,7 @@
#include "deviceimagewidget.h"
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "servicemanager.h"
#include <QLabel>
#include <QTimer>
#include <QWidget>
+23
View File
@@ -171,7 +171,9 @@ void DeviceSidebarItem::setupUI()
void DeviceSidebarItem::setSelected(bool selected)
{
m_selected = selected;
bool dark = isDarkMode();
#ifndef WIN32
if (selected) {
setStyleSheet(
"QFrame#DeviceSidebarItem { background-color: rgba(255, "
@@ -181,6 +183,27 @@ void DeviceSidebarItem::setSelected(bool selected)
"QFrame#DeviceSidebarItem { background-color: rgba(255, "
"255, 255, 16); }");
}
#else
if (selected) {
if (!dark) {
setStyleSheet("QFrame#DeviceSidebarItem { background-color: "
"rgba(0, 0, 0, 30); }");
} else {
setStyleSheet(
"QFrame#DeviceSidebarItem { background-color: rgba(255, "
"255, 255, 45); }");
}
} else {
if (!dark) {
setStyleSheet("QFrame#DeviceSidebarItem { background-color: "
"rgba(0, 0, 0, 10); }");
} else {
setStyleSheet(
"QFrame#DeviceSidebarItem { background-color: rgba(255, "
"255, 255, 16); }");
}
}
#endif
}
void DeviceSidebarItem::setCollapsed(bool collapsed)
+5 -2
View File
@@ -298,7 +298,9 @@ void DiagnoseWidget::checkDependencies(bool autoExpand)
QString("All dependencies are installed/activated (%1/%2)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: green; font-weight: bold;");
m_summaryLabel->setStyleSheet(
QString("color: %1; font-weight: bold;")
.arg(COLOR_GREEN.name()));
if (m_isExpanded && autoExpand) {
onToggleExpand();
}
@@ -307,7 +309,8 @@ void DiagnoseWidget::checkDependencies(bool autoExpand)
QString("Missing dependencies (%1/%2 installed)")
.arg(installedCount)
.arg(totalCount));
m_summaryLabel->setStyleSheet("color: red; font-weight: bold;");
m_summaryLabel->setStyleSheet(
QString("color: %1; font-weight: bold;").arg(COLOR_RED.name()));
if (!m_isExpanded && autoExpand) {
onToggleExpand();
}
+34
View File
@@ -0,0 +1,34 @@
#include "dirpickerlabel.h"
DirPickerLabel::DirPickerLabel(QWidget *parent, const QString &calloutString)
: QWidget{parent}
{
// Directory selection UI
QHBoxLayout *dirLayout = new QHBoxLayout();
QLabel *dirTextLabel = new QLabel(calloutString);
dirTextLabel->setStyleSheet("font-size: 14px;");
dirLayout->addWidget(dirTextLabel);
m_dirLabel = new ZLabel(this);
m_dirLabel->setText(m_outputDir);
m_dirLabel->setStyleSheet("font-size: 14px; color: #007AFF;");
connect(m_dirLabel, &ZLabel::clicked, this, [this]() {
QDesktopServices::openUrl(QUrl::fromLocalFile(m_outputDir));
});
m_dirLabel->setCursor(Qt::PointingHandCursor);
dirLayout->addWidget(m_dirLabel, 1);
m_dirButton = new QPushButton("Choose...");
// m_dirButton->setStyleSheet("font-size: 14px; padding: 4px 12px;");
connect(m_dirButton, &QPushButton::clicked, this, [this]() {
QString dir = QFileDialog::getExistingDirectory(
this, "Select Directory to Save IPA", m_outputDir);
if (!dir.isEmpty()) {
m_outputDir = dir;
m_dirLabel->setText(m_outputDir);
}
});
dirLayout->addWidget(m_dirButton);
setLayout(dirLayout);
}
+28
View File
@@ -0,0 +1,28 @@
#ifndef DIRPICKERLABEL_H
#define DIRPICKERLABEL_H
#include "iDescriptor-ui.h"
#include <QDesktopServices>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QLabel>
#include <QPushButton>
#include <QStandardPaths>
#include <QWidget>
class DirPickerLabel : public QWidget
{
public:
explicit DirPickerLabel(
QWidget *parent = nullptr,
const QString &calloutString = QString("Export to:"));
QString getOutputDir() const { return m_outputDir; }
private:
ZLabel *m_dirLabel;
QPushButton *m_dirButton;
QString m_outputDir =
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
};
#endif // DIRPICKERLABEL_H
+42 -8
View File
@@ -141,6 +141,8 @@ void DiskUsageWidget::setupUI()
m_othersBar->setObjectName("othersBar");
m_freeBar->setObjectName("freeBar");
bool dark = isDarkMode();
// Set colors
m_systemBar->setStyleSheet(
"QWidget#systemBar { background-color: #a1384d; border: 1px solid"
@@ -159,11 +161,12 @@ void DiskUsageWidget::setupUI()
"QWidget#othersBar { background-color: #a28729; border: 1px solid "
"#c4a32d; border-radius:0px; padding: 0; margin: 0; }");
m_freeBar->setStyleSheet(
"QWidget#freeBar { background-color: rgba(255, 255, 255, 10); border: "
"1px solid "
"#4f4f4f4f; padding: 0; margin: 0; border-radius:0px; "
"border-top-right-radius: 3px; "
"border-bottom-right-radius: 3px; }");
QString("QWidget#freeBar { background-color: %1; border: "
"1px solid "
"#4f4f4f4f; padding: 0; margin: 0; border-radius:0px; "
"border-top-right-radius: 3px; "
"border-bottom-right-radius: 3px; }")
.arg(dark ? "rgba(255, 255, 255, 10)" : "rgba(0, 0, 0, 25)"));
// remove padding margin from layout
m_systemBar->setContentsMargins(0, 0, 0, 0);
@@ -519,8 +522,8 @@ void DiskUsageWidget::fetchData()
size_t total_size = 0;
AfcFileHandle *afcHandle = nullptr;
err = ServiceManager::safeAfcFileOpen(
m_device, "/PhotoData/Photos.sqlite", AfcRdOnly, &afcHandle);
err = ServiceManager::safeAfcFileOpen(m_device, PHOTOS_SQLITE_DB_PATH,
AfcRdOnly, &afcHandle);
if (err != nullptr) {
qDebug() << "Failed to open Photos.sqlite on device:"
@@ -531,6 +534,20 @@ void DiskUsageWidget::fetchData()
return result;
}
AfcFileInfo fileInfo = {};
err = ServiceManager::safeAfcGetFileInfo(
m_device, PHOTOS_SQLITE_DB_PATH, &fileInfo);
if (err != nullptr) {
qDebug() << "Failed to get file info for Photos.sqlite:"
<< "Error Code:" << err->code
<< "Message:" << err->message;
idevice_error_free(err);
ServiceManager::safeAfcFileClose(m_device, afcHandle);
result["galleryUsage"] = QVariant::fromValue(uint64_t(0));
return result;
}
db_size = fileInfo.size;
while (true) {
uint8_t *chunk = nullptr;
size_t chunk_size = 0;
@@ -551,7 +568,24 @@ void DiskUsageWidget::fetchData()
memcpy(db_data + total_size, chunk, chunk_size);
total_size += chunk_size;
}
ServiceManager::safeAfcFileClose(m_device, afcHandle);
err = ServiceManager::safeAfcFileClose(m_device, afcHandle);
if (err != nullptr) {
qDebug() << "Failed to close Photos.sqlite on device:"
<< "Error Code:" << err->code
<< "Message:" << err->message;
idevice_error_free(err);
}
if (total_size != db_size) {
qDebug()
<< "Warning: Read size does not match expected file size for "
"Photos.sqlite. Read:"
<< total_size << "Expected:" << db_size;
result["galleryUsage"] = QVariant::fromValue(uint64_t(0));
return result;
}
qDebug() << "Total Photos.sqlite size read:" << total_size;
// HACK: File is in WAL mode (byte 18 == 0x02).
+213
View File
@@ -0,0 +1,213 @@
#include "exportalbum.h"
ExportAlbum::ExportAlbum(const iDescriptorDevice *device,
const QStringList &paths, QWidget *parent)
: QDialog(parent), m_device(device), m_listCount(paths.size())
{
setWindowTitle("Export Album");
setMaximumSize(600, 400);
#ifdef WIN32
setupWinWindow(this);
#endif
m_loadingWidget = new ZLoadingWidget(true, this);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(m_loadingWidget);
getTotalPhotoCount(paths);
connect(AppContext::sharedInstance(), &AppContext::deviceRemoved, this,
[this](const std::string &udid, const std::string &macAddress,
const std::string &ipAddress, bool wasWireless) {
if (udid == m_device->udid) {
m_exiting = true;
QTimer::singleShot(0, this, [this]() { close(); });
}
});
QWidget *contentWidget = new QWidget(this);
QVBoxLayout *contentLayout = new QVBoxLayout(contentWidget);
m_infoLabel = new QLabel(this);
contentLayout->addWidget(m_infoLabel);
QHBoxLayout *buttonLayout = new QHBoxLayout();
QPushButton *cancelButton = new QPushButton("Cancel", this);
QPushButton *exportButton = new QPushButton("Export", this);
buttonLayout->addWidget(exportButton);
buttonLayout->addWidget(cancelButton);
m_dirPickerLabel = new DirPickerLabel(this);
contentLayout->addWidget(m_dirPickerLabel);
QHBoxLayout *sizeLayout = new QHBoxLayout();
m_totalSizeExportLabel = new QLabel("Total size to export: 0 MB", this);
sizeLayout->addWidget(m_totalSizeExportLabel);
m_loadingIndicator = new QProcessIndicator(this);
m_loadingIndicator->setType(QProcessIndicator::line_rotate);
m_loadingIndicator->setFixedSize(32, 16);
sizeLayout->addWidget(m_loadingIndicator);
sizeLayout->addStretch();
contentLayout->addLayout(sizeLayout);
contentLayout->addLayout(buttonLayout);
connect(cancelButton, &QPushButton::clicked, this, [this]() {
m_exiting = true;
QTimer::singleShot(0, this, [this]() { close(); });
});
connect(exportButton, &QPushButton::clicked, this, [this, exportButton]() {
m_exiting = true;
exportButton->setEnabled(false);
QTimer::singleShot(0, this, [this]() {
startExport();
accept();
});
});
m_loadingWidget->setupContentWidget(contentWidget);
connect(this, &QDialog::finished, this, [this](int) {
m_exiting = true;
deleteLater();
});
}
void ExportAlbum::getTotalPhotoCount(const QStringList &paths)
{
QFutureWatcher<std::pair<bool, size_t>> *watcher =
new QFutureWatcher<std::pair<bool, size_t>>(this);
connect(watcher, &QFutureWatcher<std::pair<bool, size_t>>::finished, this,
[this, watcher]() {
std::pair<bool, size_t> result = watcher->result();
qDebug() << "Total photo count:" << result.second << "with"
<< (result.first ? 0 : 1) << "errors";
if (result.first) {
updateInfoLabel(result.second);
calculateTotalExportSize();
m_loadingWidget->stop();
} else {
QMessageBox::warning(
nullptr, "Error",
"Failed to read directory: cannot export album(s)");
reject();
}
});
watcher->setFuture(QtConcurrent::run([this, paths]() {
size_t count = 0;
bool errorOccurred = false;
for (const QString &path : paths) {
size_t innerCount = 0;
char **items = nullptr;
IdeviceFfiError *err = ServiceManager::safeAfcReadDirectory(
m_device, path.toStdString().c_str(), &items, &innerCount);
if (err) {
qDebug() << "Failed to read directory:"
<< path.toStdString().c_str()
<< "Error:" << err->message << "Code:" << err->code;
errorOccurred = true;
idevice_error_free(err);
} else {
int index = 0;
for (size_t i = 0; i < innerCount; ++i) {
const char *item = items[i];
if (!item) {
continue;
}
QString fileName = QString::fromUtf8(item);
if (fileName.endsWith(".") || fileName.endsWith("..")) {
continue;
}
QString filePath = path + "/" + QString::fromUtf8(item);
m_exportItems.append(
ExportItem(filePath, fileName, m_device->udid, index));
++index;
}
free_directory_listing(items, innerCount);
count += innerCount;
}
}
return std::make_pair(!errorOccurred, count);
}));
}
void ExportAlbum::updateInfoLabel(size_t photoCount)
{
m_infoLabel->setText(QString("Are you sure you want to export %1 album(s) "
"with %2 photo(s)/video(s) ?")
.arg(m_listCount)
.arg(photoCount));
}
void ExportAlbum::startExport()
{
// qDebug() << "Starting export of selected files:" << exportItems.size()
// << "items to" << exportDir;
ExportManager::sharedInstance()->startExport(
m_device, m_exportItems, m_dirPickerLabel->getOutputDir());
}
void ExportAlbum::calculateTotalExportSize()
{
m_totalExportSize = 0;
m_loadingIndicator->start();
auto timer = new QTimer(this);
timer->setInterval(500);
connect(timer, &QTimer::timeout, this, [this]() {
m_totalSizeExportLabel->setText(
QString("Total size to export: %1")
.arg(iDescriptor::Utils::formatSize(m_totalExportSize.load())));
});
timer->start();
QThreadPool::globalInstance()->start([this, timer]() {
for (const ExportItem &item : m_exportItems) {
if (m_exiting.load()) {
return;
}
AfcFileInfo info = {};
IdeviceFfiError *err = ServiceManager::safeAfcGetFileInfo(
m_device, item.sourcePathOnDevice.toStdString().c_str(), &info);
if (err) {
qDebug() << "Failed to get file info for:"
<< item.sourcePathOnDevice << "Error:" << err->message
<< "Code:" << err->code;
idevice_error_free(err);
} else {
this->m_totalExportSize += info.size;
afc_file_info_free(&info);
}
}
QMetaObject::invokeMethod(
this,
[this, timer]() {
if (m_exiting.load()) {
return;
}
timer->stop();
timer->deleteLater();
this->m_totalSizeExportLabel->setText(
QString("Total size to export: %1")
.arg(iDescriptor::Utils::formatSize(
this->m_totalExportSize.load())));
this->m_loadingIndicator->stop();
this->m_loadingIndicator->hide();
},
Qt::QueuedConnection);
});
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef EXPORTALBUM_H
#define EXPORTALBUM_H
#include "appcontext.h"
#include "dirpickerlabel.h"
#include "exportmanager.h"
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "qprocessindicator.h"
#include "servicemanager.h"
#include "zloadingwidget.h"
#include <QDialog>
#include <QMessageBox>
#include <QTimer>
#include <QWidget>
#include <QtConcurrent>
#include <atomic>
class ExportAlbum : public QDialog
{
Q_OBJECT
public:
explicit ExportAlbum(const iDescriptorDevice *device,
const QStringList &paths, QWidget *parent = nullptr);
private:
ZLoadingWidget *m_loadingWidget;
const iDescriptorDevice *m_device;
QLabel *m_infoLabel;
size_t m_listCount;
QList<ExportItem> m_exportItems;
DirPickerLabel *m_dirPickerLabel;
QLabel *m_totalSizeExportLabel;
QProcessIndicator *m_loadingIndicator = nullptr;
std::atomic<uint64_t> m_totalExportSize{0};
std::atomic<bool> m_exiting{false};
void getTotalPhotoCount(const QStringList &paths);
void updateInfoLabel(size_t photoCount);
// startExport(const QStringList &paths, const QString &exportDir);
void startExport();
void calculateTotalExportSize();
};
#endif // EXPORTALBUM_H
+94 -50
View File
@@ -19,6 +19,7 @@
#include "gallerywidget.h"
#include "exportmanager.h"
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "mediapreviewdialog.h"
#include "photomodel.h"
@@ -121,7 +122,7 @@ void GalleryWidget::setupControlsLayout()
// Sort order combo box
QLabel *sortLabel = new QLabel("Sort:");
sortLabel->setStyleSheet("font-weight: bold;");
sortLabel->setStyleSheet(mergeStyles(sortLabel, "font-weight: 600;"));
m_sortComboBox = new QComboBox();
m_sortComboBox->addItem("Newest First",
static_cast<int>(PhotoModel::NewestFirst));
@@ -133,7 +134,7 @@ void GalleryWidget::setupControlsLayout()
// Filter combo box
QLabel *filterLabel = new QLabel("Filter:");
filterLabel->setStyleSheet("font-weight: bold;");
filterLabel->setStyleSheet(mergeStyles(filterLabel, "font-weight: 600;"));
m_filterComboBox = new QComboBox();
m_filterComboBox->addItem("All Media", static_cast<int>(PhotoModel::All));
m_filterComboBox->addItem("Images Only",
@@ -147,14 +148,16 @@ void GalleryWidget::setupControlsLayout()
// Export buttons
m_exportSelectedButton = new QPushButton("Export Selected");
m_exportSelectedButton->setEnabled(false); // Initially disabled
m_exportSelectedButton->setEnabled(false);
m_exportSelectedButton->setSizePolicy(QSizePolicy::Preferred,
QSizePolicy::Fixed);
m_exportAllButton = new QPushButton("Export All");
m_exportAllButton->setEnabled(false);
// Back button
m_backButton = new QPushButton("");
m_backButton->setToolTip("Back to Albums");
m_backButton = new ZIconWidget(
QIcon(":/resources/icons/MaterialSymbolsArrowLeftAlt.png"),
"Back to Albums");
m_backButton->setMaximumWidth(30);
m_backButton->hide(); // Hidden initially
@@ -168,7 +171,7 @@ void GalleryWidget::setupControlsLayout()
&GalleryWidget::onExportSelected);
connect(m_exportAllButton, &QPushButton::clicked, this,
&GalleryWidget::onExportAll);
connect(m_backButton, &QPushButton::clicked, this,
connect(m_backButton, &ZIconWidget::clicked, this,
&GalleryWidget::onBackToAlbums);
// Add widgets to layout
@@ -226,6 +229,31 @@ void GalleryWidget::onFilterChanged()
void GalleryWidget::onExportSelected()
{
// if we are exporting from album selection view
if (m_loadingWidget->currentWidget() == m_albumSelectionWidget) {
QModelIndexList selectedIndexes =
m_albumListView->selectionModel()->selectedIndexes();
// QStringList filePaths =
// m_albumModel->getSelectedFilePaths(selectedIndexes);
QStringList paths;
for (const QModelIndex &index : selectedIndexes) {
if (index.isValid() &&
index.row() < m_albumListView->model()->rowCount()) {
paths.append(index.data(Qt::UserRole).toString());
} else {
qDebug() << "Invalid index in selection:" << index;
}
}
// /DCIM/100APPLE
qDebug() << "Selected file paths:" << paths;
auto *exportAlbum = new ExportAlbum(m_device, paths, this);
exportAlbum->show();
return;
}
if (!m_model || !m_listView->selectionModel()->hasSelection()) {
QMessageBox::information(this, "No Selection",
"Please select photos to export.");
@@ -247,7 +275,6 @@ void GalleryWidget::onExportSelected()
return;
}
// Convert QStringList to QList<ExportItem>
QList<ExportItem> exportItems;
// FIXME: index
int index = 0;
@@ -267,52 +294,64 @@ void GalleryWidget::onExportSelected()
void GalleryWidget::onExportAll()
{
// if we are exporting from album selection view
if (m_loadingWidget->currentWidget() == m_albumSelectionWidget) {
// gel all available albums
QStringList paths;
for (int row = 0; row < m_albumListView->model()->rowCount(); ++row) {
QModelIndex index = m_albumListView->model()->index(row, 0);
if (index.isValid()) {
paths.append(index.data(Qt::UserRole).toString());
}
}
auto *exportAlbum = new ExportAlbum(m_device, paths, this);
exportAlbum->show();
return;
}
if (!m_model)
return;
// if (ExportManager::sharedInstance()->isExporting()) {
// QMessageBox::information(this, "Export in Progress",
// "An export is already in progress.");
// return;
// }
QStringList filePaths = m_model->getFilteredFilePaths();
// QStringList filePaths = m_model->getFilteredFilePaths();
if (filePaths.isEmpty()) {
QMessageBox::information(this, "No Items", "No items to export.");
return;
}
// if (filePaths.isEmpty()) {
// QMessageBox::information(this, "No Items", "No items to export.");
// return;
// }
QString message =
QString("Export all %1 items currently shown?").arg(filePaths.size());
int reply = QMessageBox::question(this, "Export All", message,
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
// QString message =
// QString("Export all %1 items currently
// shown?").arg(filePaths.size());
// int reply = QMessageBox::question(this, "Export All", message,
// QMessageBox::Yes | QMessageBox::No,
// QMessageBox::No);
if (reply != QMessageBox::Yes) {
return;
}
// if (reply != QMessageBox::Yes) {
// return;
// }
QString exportDir = selectExportDirectory();
if (exportDir.isEmpty()) {
return;
}
// QString exportDir = selectExportDirectory();
// if (exportDir.isEmpty()) {
// return;
// }
// FIXME: index
int index = 0;
QList<ExportItem> exportItems;
for (const QString &filePath : filePaths) {
QString fileName = filePath.split('/').last();
exportItems.append(
ExportItem(filePath, fileName, m_device->udid, index));
++index;
}
// // Convert QStringList to QList<ExportItem>
// QList<ExportItem> exportItems;
// for (const QString &filePath : filePaths) {
// QString fileName = filePath.split('/').last();
// exportItems.append(ExportItem(filePath, fileName));
// }
qDebug() << "Starting export of:" << exportItems.size() << "items to"
<< exportDir;
// qDebug() << "Starting export of all filtered files:" <<
// exportItems.size()
// << "items to" << exportDir;
// // Start export and the manager will show its own dialog
// ExportManager::sharedInstance()->startExport(m_device, exportItems,
// exportDir);
// Start export and the manager will show its own dialog
ExportManager::sharedInstance()->startExport(m_device, exportItems,
exportDir);
}
QString GalleryWidget::selectExportDirectory()
@@ -440,12 +479,10 @@ void GalleryWidget::loadAlbumList(const AFCFileTree &dcimTree)
qDebug() << "DCIM directory read successfully, found"
<< dcimTree.entries.size() << "entries";
auto *albumModel = new QStandardItemModel(this);
m_albumModel = new QStandardItemModel(this);
for (const MediaEntry &entry : dcimTree.entries) {
QString albumName = QString::fromStdString(entry.name);
qDebug() << "DCIM entry:" << albumName << "(isDir:" << entry.isDir
<< ")";
// Check if it's a directory and matches common iOS photo album patterns
if (entry.isDir &&
@@ -459,15 +496,23 @@ void GalleryWidget::loadAlbumList(const AFCFileTree &dcimTree)
item->setData(fullPath, Qt::UserRole); // Store full path
item->setIcon(QIcon::fromTheme("folder"));
albumModel->appendRow(item);
m_albumModel->appendRow(item);
loadAlbumThumbnailAsync(fullPath, item);
}
}
m_albumListView->setModel(albumModel);
m_albumListView->setModel(m_albumModel);
m_loadingWidget->stop();
m_loadingWidget->switchToWidget(m_albumSelectionWidget);
m_exportAllButton->setEnabled(m_albumModel->rowCount() > 0);
connect(m_albumListView->selectionModel(),
&QItemSelectionModel::selectionChanged, this, [this]() {
bool hasSelection =
m_albumListView->selectionModel()->hasSelection();
m_exportSelectedButton->setEnabled(hasSelection);
});
}
void GalleryWidget::onAlbumSelected(const QString &albumPath)
@@ -528,7 +573,6 @@ void GalleryWidget::setControlsEnabled(bool enabled)
m_filterComboBox->setEnabled(enabled);
m_exportSelectedButton->setEnabled(
enabled && m_listView && m_listView->selectionModel()->hasSelection());
m_exportAllButton->setEnabled(enabled);
}
/*
@@ -667,4 +711,4 @@ void GalleryWidget::onPhotoContextMenu(const QPoint &pos)
GalleryWidget::~GalleryWidget()
{
qDebug() << "GalleryWidget destructor called";
}
}
+5 -1
View File
@@ -20,6 +20,8 @@
#ifndef GALLERYWIDGET_H
#define GALLERYWIDGET_H
#include "exportalbum.h"
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "photomodel.h"
#include "zloadingwidget.h"
@@ -34,6 +36,7 @@ class QVBoxLayout;
class QStackedWidget;
class QLabel;
class QStandardItem;
class QStandardItemModel;
QT_END_NAMESPACE
class ExportManager;
@@ -88,13 +91,14 @@ private:
QWidget *m_photoGalleryWidget;
QListView *m_listView;
PhotoModel *m_model;
QStandardItemModel *m_albumModel;
// Control widgets
QComboBox *m_sortComboBox;
QComboBox *m_filterComboBox;
QPushButton *m_exportSelectedButton;
QPushButton *m_exportAllButton;
QPushButton *m_backButton;
ZIconWidget *m_backButton;
// Export manager
ExportManager *m_exportManager;
+4 -4
View File
@@ -10,8 +10,8 @@ class HeartbeatThread : public QThread
{
Q_OBJECT
public:
HeartbeatThread(HeartbeatClientHandle *heartbeat, QString macAddress,
QObject *parent = nullptr)
HeartbeatThread(HeartbeatClientHandle *heartbeat,
iDescriptor::Uniq macAddress, QObject *parent = nullptr)
: QThread(parent), m_hb(Heartbeat::adopt(heartbeat)),
m_macAddress(macAddress)
{
@@ -88,11 +88,11 @@ public:
private:
Heartbeat m_hb;
bool m_initialCompleted = false;
QString m_macAddress;
iDescriptor::Uniq m_macAddress;
unsigned int m_tries = 0;
signals:
void heartbeatFailed(const QString &macAddress, unsigned int tries = 0);
void heartbeatThreadExited(const QString &macAddress);
void heartbeatThreadExited(const iDescriptor::Uniq &uniq);
};
#endif // HEARTBEATTHREAD_H
+1 -1
View File
@@ -237,7 +237,7 @@ QString HttpServer::generateJsonManifest() const
return doc.toJson();
}
QString HttpServer::getLocalIP() const
QString HttpServer::getLocalIP()
{
foreach (const QNetworkInterface &netIf,
QNetworkInterface::allInterfaces()) {
+2 -1
View File
@@ -39,6 +39,8 @@ public:
void stop();
int getPort() const;
QString getJsonFileName() const { return jsonFileName; }
static QString getLocalIP();
signals:
void serverStarted();
void serverError(const QString &error);
@@ -64,7 +66,6 @@ private:
void sendJsonManifest(QTcpSocket *socket);
QString generateJsonManifest() const;
QString getMimeType(const QString &filePath) const;
QString getLocalIP() const;
};
#endif // HTTPSERVER_H
+5 -1
View File
@@ -44,7 +44,11 @@
#include "./platform/windows/win_common.h"
#endif
#define COLOR_GREEN QColor(0, 180, 0) // Green
#ifndef WIN32
#define COLOR_GREEN QColor(0, 180, 0) // Green
#else
#define COLOR_GREEN QColor("#FF008000")
#endif
#define COLOR_ORANGE QColor(255, 140, 0) // Orange
#define COLOR_RED QColor(255, 0, 0) // Red
#define COLOR_BLUE QColor("#2b5693")
+4 -4
View File
@@ -36,7 +36,6 @@
#include <idevice++/heartbeat.hpp>
#include <idevice++/installation_proxy.hpp>
#include <idevice++/lockdown.hpp>
#include <idevice++/lockdown_location_simulation.hpp>
#include <idevice++/provider.hpp>
#include <idevice++/readwrite.hpp>
#include <idevice++/rsd.hpp>
@@ -81,6 +80,7 @@
#define TimeoutErrorCode -71
#define DISK_IMAGE_TYPE_DEVELOPER "Developer"
#define PHOTOS_SQLITE_DB_PATH "/PhotoData/Photos.sqlite"
#define HEARTBEAT_RETRY_LIMIT 2
@@ -480,8 +480,8 @@ struct ImageInfo {
void get_battery_info(DiagnosticsRelay *diagRelay, plist_t &diagnostics);
// void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);
// void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);
void parseOldDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);
void parseDeviceBattery(PlistNavigator &ioreg, DeviceInfo &d);
void fetchAppIconFromApple(
QNetworkAccessManager *manager, const QString &bundleId,
@@ -702,4 +702,4 @@ inline QString formatFileSize(qint64 bytes)
inline QString formatTransferRate(qint64 bytesPerSecond)
{
return formatFileSize(bytesPerSecond) + "/s";
}
}
+1 -1
View File
@@ -34,7 +34,7 @@
#endif
iFuseWidget::iFuseWidget(iDescriptorDevice *device, QWidget *parent)
: QWidget(parent), m_mainLayout(nullptr), m_ifuseProcess(nullptr),
: Tool(parent), m_mainLayout(nullptr), m_ifuseProcess(nullptr),
m_device(device)
{
setupUI();
+1 -1
View File
@@ -37,7 +37,7 @@
#include <QVBoxLayout>
#include <QWidget>
class iFuseWidget : public QWidget
class iFuseWidget : public Tool
{
Q_OBJECT
+20 -7
View File
@@ -39,13 +39,18 @@
AppTabWidget::AppTabWidget(const QString &appName, const QString &bundleId,
const QString &version, const QPixmap &icon,
QWidget *parent)
: QGroupBox(parent), m_appName(appName), m_bundleId(bundleId),
: QWidget(parent), m_appName(appName), m_bundleId(bundleId),
m_version(version), m_selected(false)
{
#ifndef WIN32
setFixedHeight(60);
#else
setMinimumHeight(60);
#endif
setMinimumWidth(100);
setCursor(Qt::PointingHandCursor);
setAttribute(Qt::WA_StyledBackground, true);
setObjectName("AppTabWidget");
setupUI(icon);
}
@@ -118,20 +123,28 @@ void AppTabWidget::mousePressEvent(QMouseEvent *event)
void AppTabWidget::updateStyles()
{
QString style;
#ifndef WIN32
QColor bgColor = isDarkMode() ? qApp->palette().color(QPalette::Light)
: qApp->palette().color(QPalette::Dark);
#else
QColor bgColor =
isDarkMode() ? QColor(255, 255, 255, 25) : QColor(0, 0, 0, 25);
#endif
if (m_selected) {
style = "QGroupBox { background-color: " + COLOR_ACCENT_BLUE.name() +
"; border-radius: "
"10px; border : 1px solid " +
bgColor.lighter().name() + "; }";
style =
"#AppTabWidget { background-color: " + COLOR_ACCENT_BLUE.name() +
"; border-radius: "
"10px; border : 1px solid " +
bgColor.lighter().name() + "; }";
} else {
style = "QGroupBox { background-color: " + bgColor.name() +
style = "#AppTabWidget { background-color: " +
bgColor.name(QColor::HexArgb) +
"; border-radius: 10px; border: 1px solid " +
bgColor.lighter().name() + "; }";
}
// prevent infinite loop
if (style != styleSheet()) {
qDebug() << "Style" << style;
setStyleSheet(style);
}
}
+2 -2
View File
@@ -43,7 +43,7 @@
#include <QVBoxLayout>
#include <QWidget>
class AppTabWidget : public QGroupBox
class AppTabWidget : public QWidget
{
Q_OBJECT
@@ -70,7 +70,7 @@ protected:
if (event->type() == QEvent::PaletteChange) {
updateStyles();
}
QGroupBox::changeEvent(event);
QWidget::changeEvent(event);
};
private:
+2 -2
View File
@@ -30,11 +30,11 @@
#include <QTimer>
#include <QVBoxLayout>
// todo add a retry button when failed
LiveScreenWidget::LiveScreenWidget(iDescriptorDevice *device, QWidget *parent)
: QWidget{parent}, m_device(device)
: Tool{parent}, m_device(device)
{
setWindowTitle("Live Screen - iDescriptor");
setAttribute(Qt::WA_DeleteOnClose);
unsigned int deviceMajorVersion =
m_device->deviceInfo.parsedDeviceVersion.major;
+2 -1
View File
@@ -20,6 +20,7 @@
#ifndef LIVESCREEN_H
#define LIVESCREEN_H
#include "iDescriptor-ui.h"
#include "iDescriptor.h"
#include "servicemanager.h"
#include <QLabel>
@@ -72,7 +73,7 @@ private:
iDescriptorDevice *m_device;
};
class LiveScreenWidget : public QWidget
class LiveScreenWidget : public Tool
{
Q_OBJECT
public:
+113 -95
View File
@@ -25,6 +25,7 @@
#include "ifusediskunmountbutton.h"
#include "ifusemanager.h"
#include "jailbrokenwidget.h"
#include "releasechangelogdialog.h"
#include "toolboxwidget.h"
#include "welcomewidget.h"
#include <QHBoxLayout>
@@ -155,19 +156,30 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
statusLayout->addWidget(statusBalloon->getButton());
ZIconWidget *welcomeMenu = new ZIconWidget(
ZIconWidget *welcomeMenuSwitch = new ZIconWidget(
QIcon(":/resources/icons/LetsIconsHorizontalDownLeftMainLight.png"),
"Switch to Welcome Menu");
connect(welcomeMenu, &ZIconWidget::clicked, this, [this, welcomeMenu]() {
if (m_mainStackedWidget->currentIndex() != 0) {
welcomeMenu->setToolTip("Switch to Connected Devices");
return m_mainStackedWidget->setCurrentIndex(0);
}
welcomeMenu->setToolTip("Switch to Welcome Menu");
m_mainStackedWidget->setCurrentIndex(1);
});
connect(welcomeMenuSwitch, &ZIconWidget::clicked, this,
[this, welcomeMenuSwitch]() {
if (m_mainStackedWidget->currentIndex() != 0) {
welcomeMenuSwitch->setToolTip(
"Switch to Connected Devices");
return m_mainStackedWidget->setCurrentIndex(0);
}
welcomeMenuSwitch->setToolTip("Switch to Welcome Menu");
m_mainStackedWidget->setCurrentIndex(1);
});
statusLayout->addWidget(welcomeMenu);
connect(m_ZTabWidget, &ZTabWidget::currentChanged, this,
[welcomeMenuSwitch](int index) {
if (index != 0) {
return welcomeMenuSwitch->hide();
}
welcomeMenuSwitch->show();
});
statusLayout->addWidget(welcomeMenuSwitch);
statusLayout->addStretch(1);
statusLayout->setContentsMargins(0, 0, 0, 0);
@@ -220,23 +232,16 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
qDebug() << "Subscribed to recovery device events successfully.";
#endif
// idevice_error_t res = idevice_event_subscribe(handleCallback,
// nullptr); if (res != IDEVICE_E_SUCCESS) {
// qDebug() << "ERROR: Unable to subscribe to device events. Error
// code:"
// << res;
// }
// qDebug() << "Subscribed to device events successfully.";
createMenus();
// UpdateProcedure updateProcedure;
// bool packageManagerManaged = false;
// bool isPortable = false;
// bool skipPrerelease = true;
// #ifdef WIN32
// isPortable = !is_iDescriptorInstalled();
// qDebug() << "isPortable=" << isPortable;
// #endif
UpdateProcedure updateProcedure;
bool packageManagerManaged = false;
bool isPortable = false;
bool skipPrerelease = true;
#ifdef WIN32
isPortable = !is_iDescriptorInstalled();
qDebug() << "isPortable=" << isPortable;
#endif
/*
struct UpdateProcedure {
@@ -247,75 +252,87 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
QString boxText;
};
*/
// switch (ZUpdater::detectPlatform()) {
// case Platform::Windows:
// updateProcedure = UpdateProcedure{
// !isPortable,
// isPortable,
// !isPortable,
// isPortable ? "New portable version downloaded, app location
// will "
// "be shown after this message"
// : "The application will now quit to install the
// update.",
// isPortable ? "New portable version downloaded"
// : "Do you want to install the downloaded update
// now?",
// };
// break;
// // todo: adjust for pkg managers
// case Platform::MacOS:
// updateProcedure = UpdateProcedure{
// true,
// false,
// true,
// "The application will now quit and open .dmg file downloaded
// to "
// "\"Downloads\" from there you can drag it to Applications to
// " "install.", "Update downloaded would you like to quit and
// install the update?",
// };
// break;
// case Platform::Linux:
// // currently only on linux (arch aur) is enabled
// #ifdef PACKAGE_MANAGER_MANAGED
// packageManagerManaged = true;
// #endif
// updateProcedure = UpdateProcedure{
// true,
// false,
// true,
// "AppImages we ship are not updateable. New version is
// downloaded " "to "
// "\"Downloads\". You can start using the new version by
// launching " "it " "from there. You can delete this AppImage
// version if you like.", "Update downloaded would you like to
// quit and open the new " "version?",
// };
// break;
// default:
// updateProcedure = UpdateProcedure{
// false, false, false, "", "",
// };
// }
switch (ZUpdater::detectPlatform()) {
case Platform::Windows:
updateProcedure = UpdateProcedure{
!isPortable,
isPortable,
!isPortable,
isPortable ? "New portable version downloaded, app location will "
"be shown after this message"
: "The application will now quit to install the update.",
isPortable ? "New portable version downloaded"
: "Do you want to install the downloaded update now?",
};
break;
// todo: adjust for pkg managers
case Platform::MacOS:
updateProcedure = UpdateProcedure{
true,
false,
true,
"The application will now quit and open .dmg file downloaded to "
"\"Downloads\" from there you can drag it to Applications to "
"install.",
"Update downloaded would you like to quit and install the update?",
};
break;
case Platform::Linux:
// currently only on linux (arch aur) is enabled
#ifdef PACKAGE_MANAGER_MANAGED
packageManagerManaged = true;
#endif
updateProcedure = UpdateProcedure{
true,
false,
true,
"AppImages we ship are not updateable. New version is downloaded "
"to "
"\"Downloads\". You can start using the new version by launching "
"it "
"from there. You can delete this AppImage version if you like.",
"Update downloaded would you like to quit and open the new "
"version?",
};
break;
default:
updateProcedure = UpdateProcedure{
false, false, false, "", "",
};
}
// m_updater = new ZUpdater("iDescriptor/iDescriptor", APP_VERSION,
// "iDescriptor", updateProcedure, isPortable,
// packageManagerManaged, skipPrerelease,
// this);
// #if defined(PACKAGE_MANAGER_MANAGED) && defined(__linux__)
// m_updater->setPackageManagerManagedMessage(
// QString(
// "You seem to have installed iDescriptor using a package
// manager. " "Please use %1 to update it.")
// .arg(PACKAGE_MANAGER_HINT));
// #endif
m_updater = new ZUpdater("iDescriptor/iDescriptor", APP_VERSION,
"iDescriptor", updateProcedure, isPortable,
packageManagerManaged, skipPrerelease, this);
#if defined(PACKAGE_MANAGER_MANAGED) && defined(__linux__)
m_updater->setPackageManagerManagedMessage(
QString(
"You seem to have installed iDescriptor using a package manager. "
"Please use %1 to update it.")
.arg(PACKAGE_MANAGER_HINT));
#endif
// SettingsManager::sharedInstance()->doIfEnabled(
// SettingsManager::Setting::AutoCheckUpdates, [this]() {
// qDebug() << "Checking for updates...";
// m_updater->checkForUpdates();
// });
QString lastAppVersion = SettingsManager::sharedInstance()->appVersion();
bool shouldShowReleaseChangelog = true;
SettingsManager::sharedInstance()->setAppVersion(APP_VERSION);
if (shouldShowReleaseChangelog) {
connect(
m_updater, &ZUpdater::dataAvailable, this,
[this](const QJsonDocument data, bool isUpdateAvailable) {
if (!isUpdateAvailable) {
ReleaseChangelogDialog dialog(data, this);
dialog.exec();
}
},
Qt::SingleShotConnection);
}
SettingsManager::sharedInstance()->doIfEnabled(
SettingsManager::Setting::AutoCheckUpdates, [this]() {
qDebug() << "Checking for updates...";
m_updater->checkForUpdates();
});
m_deviceMonitor = new DeviceMonitorThread(this);
connect(
@@ -343,9 +360,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
}
case DeviceMonitorThread::IDEVICE_DEVICE_REMOVE: {
QMetaObject::invokeMethod(AppContext::sharedInstance(),
"removeDevice", Qt::QueuedConnection,
Q_ARG(QString, udid));
QMetaObject::invokeMethod(
AppContext::sharedInstance(), "removeDevice",
Qt::QueuedConnection,
Q_ARG(iDescriptor::Uniq, iDescriptor::Uniq(udid)));
break;
}
+4
View File
@@ -55,6 +55,9 @@ MediaPreviewDialog::MediaPreviewDialog(const iDescriptorDevice *device,
m_afcClient(afcClient)
{
setWindowTitle(QFileInfo(filePath).fileName() + " - iDescriptor");
#ifdef WIN32
setupWinWindow(this);
#endif
// Make dialog fullscreen
setWindowState(Qt::WindowMaximized);
@@ -112,6 +115,7 @@ void MediaPreviewDialog::setupImageView()
// Controls layout
m_controlsLayout = new QHBoxLayout();
m_controlsLayout->setContentsMargins(10, 5, 10, 5);
m_controlsLayout->setSpacing(10);
m_zoomInBtn = new QPushButton("Zoom In", this);
m_zoomOutBtn = new QPushButton("Zoom Out", this);
+7 -8
View File
@@ -90,15 +90,14 @@ NetworkDeviceCard::NetworkDeviceCard(const NetworkDevice &device,
infoLayout->addWidget(m_connectButton);
infoLayout->addSpacing(5);
// Status indicator
QLabel *statusIndicator = new QLabel("");
QFont statusFont = statusIndicator->font();
statusFont.setPointSize(12);
statusIndicator->setFont(statusFont);
QPalette statusPalette = statusIndicator->palette();
statusPalette.setColor(QPalette::WindowText,
QColor(52, 199, 89)); // iOS green
statusIndicator->setPalette(statusPalette);
statusIndicator->setStyleSheet(
QString("QLabel { font-size: 14px; color: %1; }")
#ifdef WIN32
.arg(COLOR_ACCENT_BLUE.name()));
#else
.arg(COLOR_GREEN.name()));
#endif
infoLayout->addWidget(statusIndicator);
+9 -10
View File
@@ -33,8 +33,8 @@
NetworkDevicesWidget::NetworkDevicesWidget(QWidget *parent) : Tool(parent)
{
setWindowTitle("Network Devices - iDescriptor");
resize(500, 600);
setMinimumSize(400, 300);
setMinimumSize(300, 300);
setMaximumSize(500, 500);
setupUI();
#ifdef __linux__
m_networkProvider = new AvahiService(this);
@@ -162,15 +162,14 @@ void NetworkDevicesWidget::createDeviceCard(const NetworkDevice &device)
infoLayout->addWidget(portLabel);
infoLayout->addStretch();
// Status indicator
QLabel *statusIndicator = new QLabel("");
QFont statusFont = statusIndicator->font();
statusFont.setPointSize(12);
statusIndicator->setFont(statusFont);
QPalette statusPalette = statusIndicator->palette();
statusPalette.setColor(QPalette::WindowText,
QColor(52, 199, 89)); // iOS green
statusIndicator->setPalette(statusPalette);
statusIndicator->setStyleSheet(
QString("QLabel { font-size: 14px; color: %1; }")
#ifdef WIN32
.arg(COLOR_ACCENT_BLUE.name()));
#else
.arg(COLOR_GREEN.name()));
#endif
infoLayout->addWidget(statusIndicator);
+5 -19
View File
@@ -36,8 +36,11 @@ PhotoImportDialog::PhotoImportDialog(const QStringList &files, QWidget *parent)
{
setupUI();
setModal(true);
resize(600, 700);
resize(600, 600);
setWindowTitle("Import Photos to iDevice - iDescriptor");
#ifdef WIN32
setupWinWindow(this);
#endif
}
PhotoImportDialog::~PhotoImportDialog()
@@ -181,7 +184,7 @@ void PhotoImportDialog::init()
void PhotoImportDialog::onServerStarted()
{
QString localIP = getLocalIP();
QString localIP = HttpServer::getLocalIP();
int port = m_httpServer->getPort();
QString jsonFileName = m_httpServer->getJsonFileName();
QString url =
@@ -267,23 +270,6 @@ void PhotoImportDialog::generateQRCode(const QString &url)
QRcode_free(qrcode);
}
QString PhotoImportDialog::getLocalIP() const
{
foreach (const QNetworkInterface &interface,
QNetworkInterface::allInterfaces()) {
if (interface.flags().testFlag(QNetworkInterface::IsUp) &&
!interface.flags().testFlag(QNetworkInterface::IsLoopBack)) {
foreach (const QNetworkAddressEntry &entry,
interface.addressEntries()) {
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
return entry.ip().toString();
}
}
}
}
return "127.0.0.1";
}
void PhotoImportDialog::toggleInstructionMode()
{
if (m_instructionStack->currentIndex() == 0) {
+1 -1
View File
@@ -21,6 +21,7 @@
#define PHOTOIMPORTDIALOG_H
#include "httpserver.h"
#include "iDescriptor-ui.h"
#include <QDialog>
#include <QHBoxLayout>
#include <QLabel>
@@ -68,7 +69,6 @@ private:
void setupUI();
void generateQRCode(const QString &url);
QString getLocalIP() const;
};
#endif // PHOTOIMPORTDIALOG_H
+1 -1
View File
@@ -182,7 +182,7 @@ bool PhotoModel::populatePhotoPaths()
char **files = nullptr;
size_t count = 0;
err =
ServiceManager::safeAfcReadDirectory(m_device, photoDir, &files, count);
ServiceManager::safeAfcReadDirectory(m_device, photoDir, &files, &count);
if (err) {
qDebug() << "Failed to read photo directory:" << photoDir
<< "Error:" << err->message;
+17 -1
View File
@@ -104,4 +104,20 @@ inline void setupWinWindow(QWidget *window)
} else {
enableAcrylic(hwnd);
}
}
}
enum CornerPreference : int {
Corner_Default = DWMWCP_DEFAULT,
Corner_NoRound = DWMWCP_DONOTROUND,
Corner_Round = DWMWCP_ROUND,
Corner_RoundSmall = DWMWCP_ROUNDSMALL
};
inline void SetCorner(HWND hwnd, CornerPreference corner)
{
if (corner != Corner_Default) {
DWM_WINDOW_CORNER_PREFERENCE cp =
static_cast<DWM_WINDOW_CORNER_PREFERENCE>(corner);
DwmSetWindowAttribute(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, &cp,
sizeof(cp));
}
}
+45 -32
View File
@@ -130,41 +130,45 @@ void QBalloonTip::balloon(const QPoint &pos, int msecs)
if (!screen) {
screen = QGuiApplication::primaryScreen();
}
QRect scr = screen->availableGeometry();
const int border = 1;
const int ah = 18, ao = 18, aw = 18, rc = 7;
// bool arrowAtTop = (pos.y() + sh.height() + ah < scr.height());
// bool arrowAtLeft = (pos.x() + sh.width() - ao < scr.width());
// setContentsMargins(border + 3, border + (arrowAtTop ? ah : 0) + 2,
// border + 3, border + (arrowAtTop ? 0 : ah) + 2);
updateGeometry();
QSize sz = sizeHint();
QRect screenRect = screen->availableGeometry();
// Calculate the total required size for the balloon widget, including
// potential arrow space. Assuming the arrow takes up 'ah' height at either
// the top or bottom of the widget.
QSize sh_total = QSize(sz.width(), sz.height() + ah);
// Ensure layout is up to date so we get the correct size
ensurePolished();
adjustSize();
// Determine the desired X position: center the balloon horizontally on
// pos.x 'pos' is the global bottom-center of your button.
int targetX = pos.x() - sh_total.width() / 2;
// Clamp X position to screen bounds
targetX = qBound(screenRect.left(), targetX,
screenRect.right() - sh_total.width());
QSize balloonSize = size();
if (!balloonSize.isValid() || balloonSize.isEmpty()) {
balloonSize = sizeHint();
}
// Determine the desired Y position: Place the bottom of the balloon at
// pos.y() (button's bottom) This makes the balloon appear ABOVE the button.
int targetY = pos.y() - sh_total.height();
// Clamp Y position to screen bounds
targetY = qBound(screenRect.top(), targetY,
screenRect.bottom() - sh_total.height());
// Arrow dimensions
const int arrowGap = 40; // gap between balloon and anchor
const int margin = 5; // margin from screen edges
// Apply the calculated position
move(targetX, targetY);
// Calculate horizontal position - center on the anchor point
int balloonX = pos.x() - balloonSize.width() / 2;
// Clamp to screen bounds with margin
balloonX = qBound(screenRect.left() + margin, balloonX,
screenRect.right() - balloonSize.width() - margin);
// Calculate vertical position - prefer above the anchor point
int balloonY;
int spaceAbove = pos.y() - screenRect.top();
if (spaceAbove >= balloonSize.height() + arrowGap + margin) {
// Show above the anchor point (preferred)
balloonY = pos.y() - balloonSize.height() - arrowGap;
} else {
// Not enough space above, show below
balloonY = pos.y() + arrowGap;
}
balloonY = qBound(screenRect.top() + margin, balloonY,
screenRect.bottom() - balloonSize.height() - margin);
setGeometry(balloonX, balloonY, balloonSize.width(), balloonSize.height());
// if (msecs > 0)
// timer = startTimer(msecs);
show();
raise();
activateWindow();
@@ -192,11 +196,20 @@ bool QBalloonTip::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
// Check if click is outside the balloon
if (!geometry().contains(mouseEvent->globalPos())) {
if (m_button) {
if (QWidget *clickedWidget = qobject_cast<QWidget *>(obj)) {
if (clickedWidget == m_button ||
m_button->isAncestorOf(clickedWidget)) {
return false;
}
}
}
if (m_visible && !geometry().contains(mouseEvent->globalPos())) {
m_visible = false;
close();
return false;
return true;
}
} else if (event->type() == QEvent::WindowDeactivate) {
// Close when window loses focus
+4
View File
@@ -1,6 +1,7 @@
#ifndef QBALLOONTIP_H
#define QBALLOONTIP_H
#include "iDescriptor-ui.h"
#include <QBasicTimer>
#include <QIcon>
#include <QSystemTrayIcon>
@@ -16,6 +17,9 @@ public:
void updateBalloonPosition(const QPoint &pos);
void toggleBaloon(const QPoint &pos, int timeout, bool forceVisible);
void balloon(const QPoint &, int msecs);
ZIconWidget *getButton() { return m_button; }
ZIconWidget *m_button =
new ZIconWidget(QIcon(":/resources/icons/UimProcess.png"), "Processes");
signals:
void messageClicked();
+5 -1
View File
@@ -46,8 +46,12 @@ QueryMobileGestaltWidget::QueryMobileGestaltWidget(iDescriptorDevice *device,
void QueryMobileGestaltWidget::setupUI()
{
setWindowTitle("Query MobileGestalt - iDescriptor");
#ifdef WIN32
resize(600, 500);
setMaximumSize(800, 600);
#else
setMinimumSize(800, 600);
#endif
// Main layout
mainLayout = new QVBoxLayout(this);
+6 -3
View File
@@ -36,16 +36,19 @@ ReleaseChangelogDialog::ReleaseChangelogDialog(QJsonDocument data,
: QDialog(parent)
{
setupUI(data);
#ifdef WIN32
setupWinWindow(this);
#endif
}
ReleaseChangelogDialog::~ReleaseChangelogDialog() {}
void ReleaseChangelogDialog::setupUI(const QJsonDocument &data)
{
setWindowTitle("iDescriptor - Release Changelog");
setWindowTitle("Release Changelog");
setModal(true);
setMinimumSize(500, 250);
resize(600, 300);
setMinimumSize(400, 250);
resize(500, 400);
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(20, 20, 20, 20);
+26 -4
View File
@@ -23,12 +23,12 @@
IdeviceFfiError *ServiceManager::safeAfcReadDirectory(
const iDescriptorDevice *device, const char *path, char ***dirs,
size_t count, std::optional<AfcClientHandle *> altAfc)
size_t *count, std::optional<AfcClientHandle *> altAfc)
{
return executeAfcClientOperation(
device,
[path, dirs, &count, device](AfcClientHandle *client) {
return afc_list_directory(client, path, dirs, &count);
[path, dirs, count, device](AfcClientHandle *client) {
return afc_list_directory(client, path, dirs, count);
},
altAfc);
}
@@ -416,4 +416,26 @@ IdeviceFfiError *ServiceManager::enableDevMode(const iDescriptorDevice *device)
}
return err;
});
}
}
IdeviceFfiError *
ServiceManager::safeParseOldDeviceBattery(const iDescriptorDevice *device,
PlistNavigator &ioreg, DeviceInfo &d)
{
return executeOperation<IdeviceFfiError *>(
device, [device, &ioreg, &d]() -> IdeviceFfiError * {
parseOldDeviceBattery(ioreg, d);
return nullptr;
});
}
IdeviceFfiError *
ServiceManager::safeParseDeviceBattery(const iDescriptorDevice *device,
PlistNavigator &ioreg, DeviceInfo &d)
{
return executeOperation<IdeviceFfiError *>(
device, [device, &ioreg, &d]() -> IdeviceFfiError * {
parseDeviceBattery(ioreg, d);
return nullptr;
});
}
+7 -1
View File
@@ -241,7 +241,7 @@ public:
// Specific AFC operation wrappers
static IdeviceFfiError *safeAfcReadDirectory(
const iDescriptorDevice *device, const char *path, char ***dirs,
size_t count, std::optional<AfcClientHandle *> altAfc = std::nullopt);
size_t *count, std::optional<AfcClientHandle *> altAfc = std::nullopt);
static IdeviceFfiError *
safeAfcGetFileInfo(const iDescriptorDevice *device, const char *path,
@@ -307,6 +307,12 @@ public:
static IdeviceFfiError *
revealDeveloperModeOptionInUI(const iDescriptorDevice *device);
static IdeviceFfiError *enableDevMode(const iDescriptorDevice *device);
static IdeviceFfiError *
safeParseOldDeviceBattery(const iDescriptorDevice *device,
PlistNavigator &ioreg, DeviceInfo &d);
static IdeviceFfiError *
safeParseDeviceBattery(const iDescriptorDevice *device,
PlistNavigator &ioreg, DeviceInfo &d);
};
#endif // SERVICEMANAGER_H
+4 -1
View File
@@ -407,7 +407,10 @@ void SettingsWidget::connectSignals()
if (m_backDropTypeCombo) {
connect(m_backDropTypeCombo,
QOverload<int>::of(&QComboBox::currentIndexChanged), this,
&SettingsWidget::onSettingChanged);
[this]() {
m_restartRequired = true;
onSettingChanged();
});
}
#endif
}
+2 -6
View File
@@ -18,14 +18,10 @@
*/
#include "sponsorwidget.h"
#include "iDescriptor.h" // Include for REPO_URL
#include "sponsorappcard.h"
#include <QLabel>
#include <QUrl>
#include <QVBoxLayout>
SponsorWidget::SponsorWidget(QWidget *parent) : QWidget(parent)
SponsorWidget::SponsorWidget(QWidget *parent) : Tool(parent)
{
setMaximumSize(600, 400);
setLayout(new QVBoxLayout(this));
QLabel *sponsorTitle = new QLabel("Would you like to sponsor us?");
sponsorTitle->setStyleSheet("font-weight: bold; font-size: 16pt;");
+7 -1
View File
@@ -20,9 +20,15 @@
#ifndef SPONSORWIDGET_H
#define SPONSORWIDGET_H
#include "base/tool.h"
#include "iDescriptor.h"
#include "sponsorappcard.h"
#include <QLabel>
#include <QUrl>
#include <QVBoxLayout>
#include <QWidget>
class SponsorWidget : public QWidget
class SponsorWidget : public Tool
{
Q_OBJECT
public:
+44 -8
View File
@@ -19,6 +19,7 @@
#include <QPropertyAnimation>
#include <QPushButton>
#include <QScreen>
#include <QShowEvent>
#include <QStyle>
#include <QTimer>
#include <QTimerEvent>
@@ -35,7 +36,7 @@ BalloonProcess::BalloonProcess(ProcessItem *item, QWidget *parent)
{
auto *layout = new QVBoxLayout(this);
layout->setSpacing(6);
layout->setContentsMargins(0, 0, 0, 0);
layout->setContentsMargins(15, 15, 15, 15);
m_lastBytesTransferred = 0;
m_lastUpdateTime = QDateTime::currentDateTime();
@@ -152,16 +153,18 @@ StatusBalloon::StatusBalloon(QWidget *parent) : QBalloonTip(parent)
setMinimumHeight(300);
setMinimumWidth(300);
#ifdef WIN32
// FIXME: doesnt work the second time we call it
enableAcrylic((HWND)winId());
setAttribute(Qt::WA_TranslucentBackground);
#endif
// Create main layout
m_mainLayout = new QVBoxLayout();
m_mainLayout->setSpacing(8);
m_mainLayout->setContentsMargins(0, 0, 0, 0);
m_mainLayout->setContentsMargins(5, 5, 5, 5);
m_noProcesesLabel =
new QLabel("Export & Import processes will appear here", this);
// Header label
m_headerLabel = new QLabel("Processes");
m_headerLabel->hide();
QFont headerFont = m_headerLabel->font();
headerFont.setPointSize(headerFont.pointSize() + 2);
headerFont.setBold(true);
@@ -354,6 +357,7 @@ void StatusBalloon::updateHeader()
else if (item->status == ProcessStatus::Failed)
failed++;
}
int total = running + completed + failed;
QString headerText = QString("Processes: %1 running").arg(running);
if (completed > 0 || failed > 0) {
@@ -363,14 +367,23 @@ void StatusBalloon::updateHeader()
}
}
m_headerLabel->setText(headerText);
if (total == 0) {
m_headerLabel->hide();
m_noProcesesLabel->show();
return;
} else {
m_headerLabel->show();
m_noProcesesLabel->hide();
}
}
void StatusBalloon::handleShow(bool forceVisible)
{
QPoint pos = m_button->mapToGlobal(
QPoint buttonBottomCenter = m_button->mapToGlobal(
QPoint(m_button->width() / 2, m_button->height()));
toggleBaloon(pos, -1, forceVisible);
toggleBaloon(buttonBottomCenter, -1, forceVisible);
}
bool StatusBalloon::isProcessRunning(const QUuid &processId) const
@@ -491,4 +504,27 @@ void StatusBalloon::handleJobUpdate(ProcessItem *item)
item->processWidget->updateStats();
item->processWidget->updateButtons();
}
}
#ifdef WIN32
void StatusBalloon::showEvent(QShowEvent *event)
{
QBalloonTip::showEvent(event);
// HWND changes after hide/show, so have reapply acrylic here
enableMica((HWND)winId());
SetCorner((HWND)winId(), CornerPreference::Corner_Round);
}
#endif
void StatusBalloon::resizeEvent(QResizeEvent *event)
{
QBalloonTip::resizeEvent(event);
if (!m_noProcesesLabel)
return;
m_noProcesesLabel->adjustSize();
int x = (width() - m_noProcesesLabel->width()) / 2;
int y = (height() - m_noProcesesLabel->height()) / 2;
m_noProcesesLabel->move(x, y);
}
+8 -4
View File
@@ -81,10 +81,16 @@ public:
bool isProcessRunning(const QUuid &processId) const;
bool hasActiveProcesses() const;
bool isCancelRequested(const QUuid &processId) const;
ZIconWidget *getButton() { return m_button; }
void onCancelClicked();
void onOpenFolderClicked();
protected:
#ifdef WIN32
void showEvent(QShowEvent *event) override;
// void paintEvent(QPaintEvent *event) override;
#endif
void resizeEvent(QResizeEvent *event) override;
private:
void updateHeader();
void handleShow(bool forceVisible = false);
@@ -104,8 +110,6 @@ private:
QMap<QUuid, ProcessItem *> m_processes;
QUuid m_currentProcessId;
mutable QMutex m_processesMutex;
ZIconWidget *m_button =
new ZIconWidget(QIcon(":/resources/icons/UimProcess.png"), "Processes");
QLabel *m_noProcesesLabel;
};
#endif // STATUSBALLOON_H
-1
View File
@@ -452,7 +452,6 @@ void ToolboxWidget::onToolboxClicked(iDescriptorTool tool, bool requiresDevice)
case iDescriptorTool::LiveScreen: {
LiveScreenWidget *liveScreen = new LiveScreenWidget(device);
liveScreen->setAttribute(Qt::WA_DeleteOnClose);
liveScreen->show();
} break;
case iDescriptorTool::RecoveryMode: {
+6 -1
View File
@@ -45,12 +45,17 @@
// FIXME: on macOS setupToolFrame in Tool widget does nothing
// probably because we are using a QQuickWidget
VirtualLocation::VirtualLocation(iDescriptorDevice *device, QWidget *parent)
: Tool(parent), m_device(device)
: QWidget(parent), m_device(device)
{
setWindowTitle("Virtual Location - iDescriptor");
setMinimumSize(600, 400);
resize(800, 600);
#ifdef WIN32
setObjectName("VirtualLocationWidget");
setAttribute(Qt::WA_StyledBackground, true);
#endif
// Create the main layout
QHBoxLayout *mainLayout = new QHBoxLayout(this);
mainLayout->setContentsMargins(10, 10, 10, 10);
+1 -1
View File
@@ -31,7 +31,7 @@
#include <QVBoxLayout>
#include <QWidget>
class VirtualLocation : public Tool
class VirtualLocation : public QWidget
{
Q_OBJECT
+1 -1
View File
@@ -79,7 +79,7 @@ void WelcomeWidget::setupUI()
// GitHub link
m_githubLabel = createStyledLabel("Found an issue? Report it on GitHub", 12,
false, COLOR_HYPERLINK);
true, COLOR_HYPERLINK);
m_githubLabel->setWordWrap(false);
m_githubLabel->setMaximumWidth(m_imageLabel->sizeHint().width());
m_githubLabel->setCursor(Qt::PointingHandCursor);
+10 -4
View File
@@ -332,8 +332,11 @@ void ZTabWidget::updateTabStyles()
if (tab->isChecked()) {
tab->setStyleSheet(QString("ZTab {"
" color: %1;"
// " color: #d7e1f4ff;"
" font-weight: 700;"
// " color: #d7e1f4ff;"
#ifdef WIN32
"font-family : \"Segoe UI\", serif;"
#endif
" font-weight: 600;"
" font-size: 20px;"
" border: none;"
" outline: none;"
@@ -346,8 +349,11 @@ void ZTabWidget::updateTabStyles()
} else {
tab->setStyleSheet(QString("ZTab {"
" color: #666;"
// " color: #2b5693;"
" font-weight: 700;"
// " color: #2b5693;"
#ifdef WIN32
"font-family : \"Segoe UI\", serif;"
#endif
" font-weight: 600;"
" font-size: 20px;"
" border: none;"
" outline: none;"