mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
implement album export, finish WinUI styles, cleanup code
This commit is contained in:
+76
-11
@@ -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
@@ -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
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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
@@ -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
@@ -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(),
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "appinstalldialog.h"
|
||||
#include "appcontext.h"
|
||||
#include "appdownloadbasedialog.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "servicemanager.h"
|
||||
#include <QApplication>
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#ifndef DEVDISKIMAGEHELPER_H
|
||||
#define DEVDISKIMAGEHELPER_H
|
||||
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QDialog>
|
||||
#include <QLabel>
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "deviceimagewidget.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include "servicemanager.h"
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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).
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -37,7 +37,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class iFuseWidget : public QWidget
|
||||
class iFuseWidget : public Tool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
|
||||
class VirtualLocation : public Tool
|
||||
class VirtualLocation : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
@@ -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
@@ -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;"
|
||||
|
||||
Reference in New Issue
Block a user