Add ringtones/wallpapers plugins, AT console, dialer USSD/*#06#, and SIM icon fix
This commit is contained in:
@@ -152,6 +152,19 @@ int dialer_run_main(int argc, char** argv) {
|
||||
bool zeroHeld = false;
|
||||
int64_t zeroPressMs = 0;
|
||||
|
||||
enum class DialerModal {
|
||||
Inactive = 0,
|
||||
Imei = 1,
|
||||
Ussd = 2,
|
||||
};
|
||||
DialerModal modal = DialerModal::Inactive;
|
||||
DeviceImeis deviceImeis;
|
||||
std::string ussdCode;
|
||||
std::string ussdResponse;
|
||||
std::string ussdReplyInput;
|
||||
bool ussdSessionActive = false;
|
||||
int ussdScrollLine = 0;
|
||||
|
||||
auto updateFilter = [&]() {
|
||||
filtered.clear();
|
||||
if (number.empty()) {
|
||||
@@ -256,15 +269,23 @@ int dialer_run_main(int argc, char** argv) {
|
||||
subText = "Dial: " + c.number;
|
||||
subCol = &colYellow;
|
||||
} else if (!number.empty()) {
|
||||
std::string exactName = book.resolveName(number);
|
||||
if (!exactName.empty()) {
|
||||
subText = exactName;
|
||||
subCol = &colGreen;
|
||||
} else if (!filtered.empty()) {
|
||||
subText = filtered[0].name + " (" + filtered[0].number + ")";
|
||||
subCol = &colBlue;
|
||||
if (number == "*#06#") {
|
||||
subText = "Show Device IMEI (1 & 2)";
|
||||
subCol = &colYellow;
|
||||
} else if (isUssdCode(number)) {
|
||||
subText = "USSD Code (Press Call/OK to send)";
|
||||
subCol = &colYellow;
|
||||
} else {
|
||||
subText = "Press Call to dial (Hold 0: +)";
|
||||
std::string exactName = book.resolveName(number);
|
||||
if (!exactName.empty()) {
|
||||
subText = exactName;
|
||||
subCol = &colGreen;
|
||||
} else if (!filtered.empty()) {
|
||||
subText = filtered[0].name + " (" + filtered[0].number + ")";
|
||||
subCol = &colBlue;
|
||||
} else {
|
||||
subText = "Press Call to dial (Hold 0: +)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
subText = "0-9/*/# Dial | Hold 0: +";
|
||||
@@ -339,9 +360,111 @@ int dialer_run_main(int argc, char** argv) {
|
||||
XFillRectangle(dpy, pix, gc, 0, sbY, kWinWidth, 1);
|
||||
|
||||
std::string leftLabel = number.empty() ? "Call Log" : "+Sign";
|
||||
std::string centerLabel = "CALL";
|
||||
std::string centerLabel =
|
||||
(selected < 0 && isUssdCode(number)) ? "SEND" : "CALL";
|
||||
std::string rightLabel = number.empty() ? "Close" : "Clear";
|
||||
|
||||
if (modal == DialerModal::Imei) {
|
||||
XSetForeground(dpy, gc, theme.spec.bgOverlay);
|
||||
XFillRectangle(dpy, pix, gc, 10, 22, kWinWidth - 20, kWinHeight - kSoftbarH - 34);
|
||||
XSetForeground(dpy, gc, theme.spec.accent);
|
||||
XDrawRectangle(dpy, pix, gc, 10, 22, kWinWidth - 21, kWinHeight - kSoftbarH - 35);
|
||||
|
||||
drawPango(layoutIcon, &colYellow, 18, 28, 24, kIconInfo);
|
||||
drawPango(layoutMain, &colYellow, 38, 28, 24, "Device IMEI (*#06#)", 184);
|
||||
|
||||
XSetForeground(dpy, gc, theme.spec.divider);
|
||||
XFillRectangle(dpy, pix, gc, 16, 54, kWinWidth - 32, 1);
|
||||
|
||||
// Slot 1 IMEI card
|
||||
XSetForeground(dpy, gc, theme.spec.bgAltEven);
|
||||
XFillRectangle(dpy, pix, gc, 16, 62, kWinWidth - 32, 54);
|
||||
XSetForeground(dpy, gc, theme.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 16, 62, kWinWidth - 33, 53);
|
||||
drawPango(layoutSmall, &colBlue, 22, 65, 18, "IMEI 1 (SIM Slot 1):");
|
||||
drawPango(layoutMain, &colWhite, 22, 85, 24,
|
||||
deviceImeis.imei1.empty() ? "Unavailable" : deviceImeis.imei1,
|
||||
kWinWidth - 44);
|
||||
|
||||
// Slot 2 IMEI card
|
||||
XSetForeground(dpy, gc, theme.spec.bgAltEven);
|
||||
XFillRectangle(dpy, pix, gc, 16, 124, kWinWidth - 32, 54);
|
||||
XSetForeground(dpy, gc, theme.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 16, 124, kWinWidth - 33, 53);
|
||||
drawPango(layoutSmall, &colGreen, 22, 127, 18, "IMEI 2 (SIM Slot 2):");
|
||||
drawPango(layoutMain, &colWhite, 22, 147, 24,
|
||||
deviceImeis.imei2.empty() ? "Unavailable" : deviceImeis.imei2,
|
||||
kWinWidth - 44);
|
||||
|
||||
std::string svLine = "IMEI SV: " +
|
||||
(deviceImeis.imeiSv.empty() ? "--" : deviceImeis.imeiSv);
|
||||
drawPango(layoutSmall, &colMuted, 22, 188, 20, svLine, kWinWidth - 44);
|
||||
|
||||
leftLabel = "";
|
||||
centerLabel = "OK";
|
||||
rightLabel = "Close";
|
||||
} else if (modal == DialerModal::Ussd) {
|
||||
XSetForeground(dpy, gc, theme.spec.bgOverlay);
|
||||
XFillRectangle(dpy, pix, gc, 8, 14, kWinWidth - 16, kWinHeight - kSoftbarH - 22);
|
||||
XSetForeground(dpy, gc, theme.spec.accent);
|
||||
XDrawRectangle(dpy, pix, gc, 8, 14, kWinWidth - 17, kWinHeight - kSoftbarH - 23);
|
||||
|
||||
std::string hdr = "USSD (" + ussdCode + ")";
|
||||
drawPango(layoutMain, &colYellow, 16, 18, 22, hdr, kWinWidth - 32);
|
||||
|
||||
// Response area
|
||||
XSetForeground(dpy, gc, theme.spec.bgAltEven);
|
||||
XFillRectangle(dpy, pix, gc, 14, 42, kWinWidth - 28, 152);
|
||||
XSetForeground(dpy, gc, theme.spec.border);
|
||||
XDrawRectangle(dpy, pix, gc, 14, 42, kWinWidth - 29, 151);
|
||||
|
||||
pango_layout_set_width(layoutSmall, (kWinWidth - 40) * PANGO_SCALE);
|
||||
pango_layout_set_wrap(layoutSmall, PANGO_WRAP_WORD_CHAR);
|
||||
pango_layout_set_ellipsize(layoutSmall, PANGO_ELLIPSIZE_NONE);
|
||||
pango_layout_set_text(layoutSmall, ussdResponse.c_str(),
|
||||
static_cast<int>(ussdResponse.size()));
|
||||
int lineCount = pango_layout_get_line_count(layoutSmall);
|
||||
int maxVisLines = 7;
|
||||
if (ussdScrollLine > std::max(0, lineCount - maxVisLines)) {
|
||||
ussdScrollLine = std::max(0, lineCount - maxVisLines);
|
||||
}
|
||||
int curY = 46;
|
||||
for (int li = ussdScrollLine;
|
||||
li < lineCount && (li - ussdScrollLine) < maxVisLines; ++li) {
|
||||
PangoLayoutLine* pl = pango_layout_get_line_readonly(layoutSmall, li);
|
||||
if (pl) {
|
||||
PangoRectangle ink{}, logical{};
|
||||
pango_layout_line_get_pixel_extents(pl, &ink, &logical);
|
||||
pango_xft_render_layout_line(
|
||||
xftDraw, &colWhite, pl, 20 * PANGO_SCALE,
|
||||
(curY - logical.y) * PANGO_SCALE);
|
||||
curY += std::max(18, logical.height + 2);
|
||||
}
|
||||
}
|
||||
pango_layout_set_width(layoutSmall, -1);
|
||||
|
||||
// Reply / Follow-up USSD input box
|
||||
drawPango(layoutSmall, ussdSessionActive ? &colGreen : &colMuted,
|
||||
16, 198, 18,
|
||||
ussdSessionActive ? "Session active - Reply:" : "Reply or dial USSD:");
|
||||
XSetForeground(dpy, gc, theme.spec.bgInputFocus);
|
||||
XFillRectangle(dpy, pix, gc, 14, 216, kWinWidth - 28, 26);
|
||||
XSetForeground(dpy, gc, theme.spec.selBg);
|
||||
XDrawRectangle(dpy, pix, gc, 14, 216, kWinWidth - 29, 25);
|
||||
drawPango(layoutMain, &colWhite, 20, 216, 26, ussdReplyInput + "_",
|
||||
kWinWidth - 40);
|
||||
|
||||
if (!ussdReplyInput.empty() || ussdSessionActive) {
|
||||
leftLabel = "Send";
|
||||
centerLabel = "SEND";
|
||||
rightLabel = "Close";
|
||||
} else {
|
||||
leftLabel = "Retry";
|
||||
centerLabel = "OK";
|
||||
rightLabel = "Close";
|
||||
}
|
||||
}
|
||||
|
||||
drawPango(layoutMain, &colLight, 6, sbY + 1, kSoftbarH - 1, leftLabel);
|
||||
int cw = pangoWidth(layoutMain, centerLabel);
|
||||
drawPango(layoutMain, &colGreen, (kWinWidth - cw) / 2, sbY + 1,
|
||||
@@ -367,8 +490,31 @@ int dialer_run_main(int argc, char** argv) {
|
||||
render();
|
||||
XSync(dpy, False);
|
||||
|
||||
auto openImeiModal = [&]() {
|
||||
deviceImeis = queryDeviceImeis();
|
||||
modal = DialerModal::Imei;
|
||||
number.clear();
|
||||
selected = allContacts.empty() ? -1 : 0;
|
||||
updateFilter();
|
||||
render();
|
||||
};
|
||||
|
||||
auto executeUssd = [&](const std::string& codeOrReply, bool isReply) {
|
||||
modal = DialerModal::Ussd;
|
||||
if (!isReply || isUssdCode(codeOrReply)) {
|
||||
ussdCode = codeOrReply;
|
||||
}
|
||||
ussdScrollLine = 0;
|
||||
ussdResponse = "Sending USSD " + codeOrReply + "...";
|
||||
ussdReplyInput.clear();
|
||||
render();
|
||||
ussdResponse = sendModemUssd(codeOrReply, isReply, &ussdSessionActive);
|
||||
render();
|
||||
};
|
||||
|
||||
auto showWindow = [&](const std::string& arg) {
|
||||
closeOtherPlugins("dialer");
|
||||
modal = DialerModal::Inactive;
|
||||
bool themeChanged = theme.checkAndReload(
|
||||
dpy, screen, visual, cmap, layoutMain, layoutSmall, layoutIcon,
|
||||
layoutNum, win);
|
||||
@@ -394,7 +540,9 @@ int dialer_run_main(int argc, char** argv) {
|
||||
usleep(2000);
|
||||
}
|
||||
bool reloaded = reloadContactsIfNeeded();
|
||||
if (!cleanArg.empty() || reloaded || themeChanged || number != cleanArg) {
|
||||
if (cleanArg == "*#06#") {
|
||||
openImeiModal();
|
||||
} else if (!cleanArg.empty() || reloaded || themeChanged || number != cleanArg) {
|
||||
number = cleanArg;
|
||||
selected = number.empty() ? (allContacts.empty() ? -1 : 0) : -1;
|
||||
updateFilter();
|
||||
@@ -408,8 +556,12 @@ int dialer_run_main(int argc, char** argv) {
|
||||
}
|
||||
number += cleanArg;
|
||||
selected = -1;
|
||||
updateFilter();
|
||||
render();
|
||||
if (number == "*#06#") {
|
||||
openImeiModal();
|
||||
} else {
|
||||
updateFilter();
|
||||
render();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -440,7 +592,13 @@ int dialer_run_main(int argc, char** argv) {
|
||||
softkeyPending = 0;
|
||||
softkeyDeadlineMs = 0;
|
||||
zeroHeld = false;
|
||||
if (!number.empty() || selected != (allContacts.empty() ? -1 : 0)) {
|
||||
if (modal == DialerModal::Ussd && ussdSessionActive) {
|
||||
cancelModemUssd();
|
||||
ussdSessionActive = false;
|
||||
}
|
||||
if (modal != DialerModal::Inactive || !number.empty() ||
|
||||
selected != (allContacts.empty() ? -1 : 0)) {
|
||||
modal = DialerModal::Inactive;
|
||||
number.clear();
|
||||
selected = allContacts.empty() ? -1 : 0;
|
||||
updateFilter();
|
||||
@@ -557,6 +715,79 @@ int dialer_run_main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
char dialCh = mapDialKey(sym, ev.xkey.keycode, ev.xkey.state);
|
||||
|
||||
if (modal == DialerModal::Imei) {
|
||||
if (sym == XK_Return || sym == XK_KP_Enter || sym == XK_Escape ||
|
||||
sym == XK_BackSpace || sym == XF86XK_Phone ||
|
||||
sym == XF86XK_PickupPhone) {
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (modal == DialerModal::Ussd) {
|
||||
if (dialCh != '\0') {
|
||||
if (ussdReplyInput.size() < 32) {
|
||||
ussdReplyInput.push_back(dialCh);
|
||||
render();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sym == XK_BackSpace || sym == XK_Left || sym == XK_KP_Left) {
|
||||
if (!ussdReplyInput.empty()) {
|
||||
ussdReplyInput.pop_back();
|
||||
render();
|
||||
} else if (sym == XK_BackSpace) {
|
||||
if (ussdSessionActive) {
|
||||
cancelModemUssd();
|
||||
ussdSessionActive = false;
|
||||
}
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sym == XK_Escape) {
|
||||
if (ussdSessionActive) {
|
||||
cancelModemUssd();
|
||||
ussdSessionActive = false;
|
||||
}
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
continue;
|
||||
}
|
||||
if (sym == XK_Up || sym == XK_KP_Up) {
|
||||
if (ussdScrollLine > 0) {
|
||||
--ussdScrollLine;
|
||||
render();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (sym == XK_Down || sym == XK_KP_Down) {
|
||||
++ussdScrollLine;
|
||||
render();
|
||||
continue;
|
||||
}
|
||||
if (sym == XK_Return || sym == XK_KP_Enter ||
|
||||
sym == XF86XK_Phone || sym == XF86XK_PickupPhone ||
|
||||
sym == XF86XK_Send) {
|
||||
if (!ussdReplyInput.empty()) {
|
||||
if (ussdReplyInput == "*#06#") {
|
||||
openImeiModal();
|
||||
} else {
|
||||
std::string req = ussdReplyInput;
|
||||
executeUssd(req, !isUssdCode(req));
|
||||
}
|
||||
} else if (!ussdSessionActive) {
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dialCh != '\0') {
|
||||
if (nowMs() - openStartMs < 40 && number.size() == 1 &&
|
||||
number[0] == dialCh) {
|
||||
@@ -570,6 +801,10 @@ int dialer_run_main(int argc, char** argv) {
|
||||
} else {
|
||||
zeroHeld = false;
|
||||
}
|
||||
if (number == "*#06#") {
|
||||
openImeiModal();
|
||||
continue;
|
||||
}
|
||||
updateFilter();
|
||||
render();
|
||||
continue;
|
||||
@@ -632,12 +867,22 @@ int dialer_run_main(int argc, char** argv) {
|
||||
case XK_Return:
|
||||
case XK_KP_Enter:
|
||||
case XF86XK_Phone:
|
||||
case XF86XK_PickupPhone: {
|
||||
case XF86XK_PickupPhone:
|
||||
case XF86XK_Send: {
|
||||
std::string target = selectActiveNumber();
|
||||
if (!target.empty()) {
|
||||
writeSoftkeySuppress(nowMs() + 350);
|
||||
hideWindow(true);
|
||||
placePhoneCall(target);
|
||||
if (target == "*#06#") {
|
||||
openImeiModal();
|
||||
} else if (isUssdCode(target)) {
|
||||
number.clear();
|
||||
selected = allContacts.empty() ? -1 : 0;
|
||||
updateFilter();
|
||||
executeUssd(target, false);
|
||||
} else {
|
||||
writeSoftkeySuppress(nowMs() + 350);
|
||||
hideWindow(true);
|
||||
placePhoneCall(target);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -658,7 +903,21 @@ int dialer_run_main(int argc, char** argv) {
|
||||
runAsyncArgv("xdrawer");
|
||||
}
|
||||
} else if (comb == 1) {
|
||||
if (number.empty()) {
|
||||
if (modal == DialerModal::Imei) {
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
} else if (modal == DialerModal::Ussd) {
|
||||
if (!ussdReplyInput.empty()) {
|
||||
if (ussdReplyInput == "*#06#") {
|
||||
openImeiModal();
|
||||
} else {
|
||||
std::string req = ussdReplyInput;
|
||||
executeUssd(req, !isUssdCode(req));
|
||||
}
|
||||
} else if (!ussdCode.empty()) {
|
||||
executeUssd(ussdCode, false);
|
||||
}
|
||||
} else if (number.empty()) {
|
||||
writeSoftkeySuppress(nowMs() + 250);
|
||||
hideWindow(false);
|
||||
if (!sendPluginCommand("calllog", "OPEN")) {
|
||||
@@ -675,7 +934,17 @@ int dialer_run_main(int argc, char** argv) {
|
||||
render();
|
||||
}
|
||||
} else if (comb == 2) {
|
||||
if (!number.empty()) {
|
||||
if (modal == DialerModal::Imei) {
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
} else if (modal == DialerModal::Ussd) {
|
||||
if (ussdSessionActive) {
|
||||
cancelModemUssd();
|
||||
ussdSessionActive = false;
|
||||
}
|
||||
modal = DialerModal::Inactive;
|
||||
render();
|
||||
} else if (!number.empty()) {
|
||||
number.pop_back();
|
||||
selected = -1;
|
||||
updateFilter();
|
||||
|
||||
Reference in New Issue
Block a user