Finishing payments.
This commit is contained in:
parent
59e7904721
commit
5dda40ca42
4
app_config.json
Normal file
4
app_config.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"licenser-server": "https://tnsoehasuhaons.beta.exd.sergiotarxz.me",
|
||||
"debug": true
|
||||
}
|
BIN
exd-logo.png
Normal file
BIN
exd-logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
417
exd.svg
417
exd.svg
@ -7,10 +7,11 @@
|
||||
viewBox="0 0 512 512"
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
|
||||
sodipodi:docname="exd.svg"
|
||||
sodipodi:docname="exd-final.svg"
|
||||
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<sodipodi:namedview
|
||||
@ -23,85 +24,367 @@
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#d1d1d1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:zoom="1.0131836"
|
||||
inkscape:cx="159.89205"
|
||||
inkscape:cy="321.75807"
|
||||
inkscape:window-width="1290"
|
||||
inkscape:window-height="1011"
|
||||
inkscape:window-x="20"
|
||||
inkscape:window-y="20"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:zoom="0.71972656"
|
||||
inkscape:cx="229.94844"
|
||||
inkscape:cy="249.40027"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1003"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1" />
|
||||
<defs
|
||||
id="defs1">
|
||||
<rect
|
||||
x="228.9812"
|
||||
y="200.35855"
|
||||
width="94.750843"
|
||||
height="31.583614"
|
||||
id="rect4" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient54"
|
||||
id="linearGradient146"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,3.1629448,-6.2364669)"
|
||||
x1="3.3060381"
|
||||
y1="26.921986"
|
||||
x2="30.560637"
|
||||
y2="26.921986" />
|
||||
<linearGradient
|
||||
id="linearGradient54"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#409172;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop54" />
|
||||
<stop
|
||||
style="stop-color:#50ba95;stop-opacity:1;"
|
||||
offset="0.03402343"
|
||||
id="stop59" />
|
||||
<stop
|
||||
style="stop-color:#378c6d;stop-opacity:1;"
|
||||
offset="0.07285479"
|
||||
id="stop56" />
|
||||
<stop
|
||||
style="stop-color:#378c6d;stop-opacity:1;"
|
||||
offset="0.92714483"
|
||||
id="stop57" />
|
||||
<stop
|
||||
style="stop-color:#50ba95;stop-opacity:1;"
|
||||
offset="0.96597624"
|
||||
id="stop58" />
|
||||
<stop
|
||||
style="stop-color:#409172;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop55" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4"
|
||||
id="linearGradient145"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,3.1629448,-6.2364669)"
|
||||
x1="16.933332"
|
||||
y1="3.1749997"
|
||||
x2="16.933332"
|
||||
y2="29.633331" />
|
||||
<linearGradient
|
||||
id="linearGradient4"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.7970323;"
|
||||
offset="0"
|
||||
id="stop4" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.3975068;"
|
||||
offset="0.24830961"
|
||||
id="stop6" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="0.50635862"
|
||||
id="stop8" />
|
||||
<stop
|
||||
style="stop-color:#378c6d;stop-opacity:0;"
|
||||
offset="0.57348305"
|
||||
id="stop9" />
|
||||
<stop
|
||||
style="stop-color:#378c6d;stop-opacity:0.54033399;"
|
||||
offset="0.73684102"
|
||||
id="stop7" />
|
||||
<stop
|
||||
style="stop-color:#1c8c63;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop5" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient62"
|
||||
id="linearGradient144"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="10.374425"
|
||||
y1="17.991667"
|
||||
x2="10.374561"
|
||||
y2="19.453598" />
|
||||
<linearGradient
|
||||
id="linearGradient62"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#9a9996;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop63" />
|
||||
<stop
|
||||
style="stop-color:#423f46;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop64" />
|
||||
</linearGradient>
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath29">
|
||||
<path
|
||||
id="path30"
|
||||
style="opacity:1;fill:#9141ac;fill-opacity:1;stroke-width:7.48075;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
d="m 9.5250001,16.557475 v 1.981445 c 0,0.283266 0.2278144,0.51108 0.5110799,0.51108 h 13.794507 c 0.283265,0 0.51108,-0.227814 0.51108,-0.51108 v -1.981445 z"
|
||||
sodipodi:nodetypes="csssscc" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient59"
|
||||
id="linearGradient143"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,3.1629448,-6.2364669)"
|
||||
x1="12.7"
|
||||
y1="19.049999"
|
||||
x2="12.7"
|
||||
y2="27.516665" />
|
||||
<linearGradient
|
||||
id="linearGradient59"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop60" />
|
||||
<stop
|
||||
style="stop-color:#e8e7e3;stop-opacity:1;"
|
||||
offset="0.375"
|
||||
id="stop62" />
|
||||
<stop
|
||||
style="stop-color:#deddda;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop61" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient170"
|
||||
id="linearGradient165"
|
||||
x1="14.287501"
|
||||
y1="87.312508"
|
||||
x2="14.287501"
|
||||
y2="85.195839"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,3.1629448,-1122.7502)" />
|
||||
<linearGradient
|
||||
id="linearGradient170"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
style="stop-color:#338265;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop169" />
|
||||
<stop
|
||||
style="stop-color:#5dbd9a;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop170" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient170"
|
||||
id="linearGradient167"
|
||||
x1="15.875001"
|
||||
y1="87.312508"
|
||||
x2="15.875001"
|
||||
y2="85.195839"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,1.118254,-1122.7502)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient170"
|
||||
id="linearGradient169"
|
||||
x1="17.991669"
|
||||
y1="87.312508"
|
||||
x2="17.991669"
|
||||
y2="85.195839"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(14.931319,0,0,15.662846,5.2076546,-1122.7502)" />
|
||||
</defs>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:url(#linearGradient146);fill-opacity:1;stroke-width:66.0493;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
id="rect129"
|
||||
width="406.94711"
|
||||
height="113.98333"
|
||||
x="52.526443"
|
||||
y="358.44681"
|
||||
ry="32.772198" />
|
||||
<rect
|
||||
style="fill:#75dfb9;fill-opacity:1;stroke-width:66.0493;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
id="rect130"
|
||||
width="406.94711"
|
||||
height="394.11246"
|
||||
x="52.526443"
|
||||
y="45.545456"
|
||||
ry="32.772198" />
|
||||
<rect
|
||||
style="opacity:0.962206;fill:url(#linearGradient145);fill-opacity:0.511007;stroke-width:66.0493;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
id="rect131"
|
||||
width="406.94711"
|
||||
height="394.11246"
|
||||
x="52.526443"
|
||||
y="45.545456"
|
||||
ry="32.772198" />
|
||||
<rect
|
||||
style="fill:#75dfb9;fill-opacity:1;stroke-width:58.5262;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
id="rect132"
|
||||
width="360.59457"
|
||||
height="349.22183"
|
||||
x="75.702713"
|
||||
y="77.017487"
|
||||
ry="17.691614" />
|
||||
<path
|
||||
style="fill:#75dfb9;fill-opacity:1;stroke:none;stroke-width:15.6084"
|
||||
d="M 418.19601,434.27472 108.73222,432.7412 C 87.30367,428.80108 66.39357,423.98239 61.80804,391.50124 L 62.19265,100.62701 C 61.50823,72.24757 76.96556,65.23751 89.35122,54.16097 l 323.90923,1.27354 c 23.94476,4.70727 33.02901,22.00536 39.99971,41.09419 l 3.06755,295.21917 c -3.23996,19.90715 -11.02317,37.06474 -38.1317,42.52685 z"
|
||||
id="path1"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
id="path132"
|
||||
style="fill:#378c6d;fill-opacity:1;stroke-width:114.401;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
d="m 161.18607,272.63285 -7.90117,8.87913 -5.7407,-6.45092 c -1.33434,1.44066 -2.16044,3.4001 -2.16044,5.57675 v 16.74012 c 0,4.43679 3.40156,8.00497 7.6311,8.00497 h 205.97018 c 4.22954,0 7.63109,-3.56818 7.63109,-8.00497 v -16.74012 c 0,-2.17665 -0.82615,-4.13609 -2.16049,-5.57675 l -5.74067,6.45092 -7.90114,-8.87913 -7.90116,8.87913 -7.90115,-8.87913 -7.90117,8.87913 -7.90114,-8.87913 -7.90117,8.87913 -7.90115,-8.87913 -7.90116,8.87913 -7.90115,-8.87913 -7.90116,8.87913 -7.90115,-8.87913 -7.90117,8.87913 -7.90114,-8.87913 -7.90117,8.87913 -7.90115,-8.87913 -7.90116,8.87913 -7.90115,-8.87913 -7.90117,8.87913 -7.90114,-8.87913 -7.90117,8.87913 -7.90114,-8.87913 -7.90117,8.87913 -7.90115,-8.87913 -7.90116,8.87913 z"
|
||||
sodipodi:nodetypes="cccssssssccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
style="fill:#d9d3d0;fill-opacity:1;stroke:#2b0000;stroke-width:7.95089;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 363.7621,284.44678 v -28.39463 l -207.73101,-2.98891 4.50879,27.40765 z"
|
||||
id="path3"
|
||||
sodipodi:nodetypes="ccccc" />
|
||||
id="path133"
|
||||
style="fill:#136246;fill-opacity:1;stroke-width:114.401;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
d="m 161.18607,276.74258 -7.90117,8.87912 -5.7407,-6.45091 c -1.33434,1.44067 -2.16044,3.40014 -2.16044,5.57676 v 15.96472 c 0,4.43673 3.40156,8.00496 7.6311,8.00496 h 205.97018 c 4.22954,0 7.63109,-3.56823 7.63109,-8.00496 v -15.96472 c 0,-2.17662 -0.82615,-4.13609 -2.16049,-5.57676 l -5.74067,6.45091 -7.90114,-8.87912 -7.90116,8.87912 -7.90115,-8.87912 -7.90117,8.87912 -7.90114,-8.87912 -7.90117,8.87912 -7.90115,-8.87912 -7.90116,8.87912 -7.90115,-8.87912 -7.90116,8.87912 -7.90115,-8.87912 -7.90117,8.87912 -7.90114,-8.87912 -7.90117,8.87912 -7.90115,-8.87912 -7.90116,8.87912 -7.90115,-8.87912 -7.90117,8.87912 -7.90114,-8.87912 -7.90117,8.87912 -7.90114,-8.87912 -7.90117,8.87912 -7.90115,-8.87912 -7.90116,8.87912 z"
|
||||
sodipodi:nodetypes="cccssssssccccccccccccccccccccccccccc" />
|
||||
<path
|
||||
style="fill:#371600;fill-opacity:1;stroke:#2b0000;stroke-width:7.95089;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 356.69643,305.36917 -206.31788,4.48336 1.41313,-46.32812 25.43646,13.45011 12.71821,-11.95565 32.50213,16.43901 16.95764,-13.45009 18.37078,13.45009 25.43643,-13.45009 29.67587,16.43899 22.61019,-13.45009 21.19704,13.45009 z"
|
||||
id="path2" />
|
||||
style="fill:url(#linearGradient144);fill-opacity:1;stroke:none;stroke-width:0.182682;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
d="m 9.5988037,20.108333 c 0,-1.286464 0.3197629,-2.116666 0.7756213,-2.116666 h 1.513594 v 2.116666 z"
|
||||
id="path134"
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:transform-center-x="1.4581046"
|
||||
inkscape:transform-center-y="-4.3858528"
|
||||
clip-path="url(#clipPath29)"
|
||||
transform="matrix(14.931319,0,0,15.662846,3.1629451,10.340015)" />
|
||||
<path
|
||||
style="fill:#fbfbec;fill-opacity:1;stroke:#2b0000;stroke-width:7.95089;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 336.95667,291.41161 c 39.95551,-15.89369 34.57135,66.53441 6.88683,93.24751 l -193.2618,-4.907 c 34.80282,-25.57481 50.68048,-107.3464 15.36715,-73.3849 -4.48827,4.31645 -7.28273,-10.99003 -11.75705,-17.35321 z"
|
||||
id="path4"
|
||||
sodipodi:nodetypes="cccscc" />
|
||||
id="path135"
|
||||
style="fill:url(#linearGradient143);fill-opacity:1;stroke:none;stroke-width:2.79371;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
inkscape:transform-center-x="-11.49783"
|
||||
inkscape:transform-center-y="-2.1929348"
|
||||
d="m 158.06883,292.14071 c 6.80652,0 11.01839,13.19126 11.01839,33.15303 v 99.45902 l 7.90116,-8.2882 7.90115,8.2882 7.90118,-8.2882 7.90114,8.2882 7.90117,-8.2882 7.90114,8.2882 7.90117,-8.2882 7.90115,8.2882 7.90116,-8.2882 7.90115,8.2882 7.90117,-8.2882 7.90114,8.2882 7.90117,-8.2882 7.90115,8.2882 7.90116,-8.2882 7.90114,8.2882 7.90116,-8.2882 7.90115,8.2882 7.90117,-8.2882 7.90114,8.2882 7.90117,-8.2882 7.90115,8.2882 7.90116,-8.2882 7.90115,8.2882 7.90116,-8.2882 7.90115,8.2882 v -99.45902 c 0,-19.96177 -4.21186,-33.15303 -11.0184,-33.15303 z"
|
||||
sodipodi:nodetypes="cscccccccccccccccccccccccccccssc" />
|
||||
<path
|
||||
id="path136"
|
||||
style="fill:#bab8b6;fill-opacity:1;stroke:none;stroke-width:2.79371;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
inkscape:transform-center-x="-11.49783"
|
||||
inkscape:transform-center-y="-2.1929298"
|
||||
d="m 181.64114,300.42901 c 0.83465,2.33144 1.5129,5.12621 2.037,8.28826 h 86.91272 c -0.52409,-3.16205 -1.20245,-5.95682 -2.03705,-8.28826 z m 126.41847,0 c 0.83467,2.33144 1.51293,5.12621 2.03702,8.28826 h 7.90116 c -0.52408,-3.16205 -1.20244,-5.95682 -2.03703,-8.28826 z m 15.8023,0 c 0.83468,2.33144 1.51295,5.12621 2.03704,8.28826 h 31.78981 c -0.52411,-3.16205 -1.20241,-5.95682 -2.03702,-8.28826 z m -139.25013,16.57651 c 0.17652,2.60968 0.27771,5.36511 0.27771,8.28826 h 86.91273 c 0,-2.92315 -0.10161,-5.67858 -0.27773,-8.28826 z m 126.41848,0 c 0.17615,2.60968 0.27773,5.36511 0.27773,8.28826 h 7.90117 c 0,-2.92315 -0.10161,-5.67858 -0.27773,-8.28826 z m 15.80231,0 c 0.17615,2.60968 0.27774,5.36511 0.27774,8.28826 h 31.78978 c 0,-2.92315 -0.10161,-5.67858 -0.27771,-8.28826 z" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
id="text4"
|
||||
style="text-align:start;writing-mode:lr-tb;direction:ltr;white-space:pre;shape-inside:url(#rect4);display:inline;fill:#5acea0;fill-opacity:1;stroke:none;stroke-width:5.4;stroke-dasharray:none;stroke-opacity:1"
|
||||
transform="matrix(1.4317665,0,0,1.5141573,-73.468577,22.490569)"><tspan
|
||||
x="228.98047"
|
||||
y="224.08681"
|
||||
id="tspan2"><tspan
|
||||
style="font-size:26.6667px;font-family:'Liberation Mono';-inkscape-font-specification:'Liberation Mono, Normal'"
|
||||
id="tspan1">EXD</tspan></tspan></text>
|
||||
<ellipse
|
||||
style="fill:#1bc9a2;fill-opacity:1;stroke:none;stroke-width:5.4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path7"
|
||||
cx="-153.44371"
|
||||
cy="-179.50844"
|
||||
rx="39.973011"
|
||||
ry="29.609638"
|
||||
transform="scale(-1)" />
|
||||
<ellipse
|
||||
style="fill:#beffe1;fill-opacity:1;stroke:none;stroke-width:3.7116;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path7-2"
|
||||
cx="-247.51122"
|
||||
cy="-211.81203"
|
||||
rx="27.635662"
|
||||
ry="20.233253"
|
||||
transform="scale(-1)" />
|
||||
<ellipse
|
||||
style="fill:#1bc9a2;fill-opacity:1;stroke:none;stroke-width:5.4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path7-7"
|
||||
cx="-346.70349"
|
||||
cy="-174.8"
|
||||
rx="39.973011"
|
||||
ry="29.609638"
|
||||
transform="scale(-1)" />
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:66.4819px;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold';text-align:justify;opacity:0.349358;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.66206;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
x="240.62625"
|
||||
y="390.69879"
|
||||
id="text136"
|
||||
transform="scale(0.97636847,1.0242035)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan136"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:Cantarell;-inkscape-font-specification:'Cantarell Bold';fill:#000000;stroke-width:1.66206"
|
||||
x="240.62625"
|
||||
y="390.69879">EXD</tspan></text>
|
||||
<path
|
||||
id="rect7"
|
||||
style="fill:none;stroke:#2b0000;stroke-width:4.7838"
|
||||
d="m 430.82675,373.76224 c -5.29241,24.3079 -20.35963,34.63148 -42.46611,34.88433 L 116.19612,408.06161 C 96.34024,401.6588 85.80851,388.5862 82.77241,370.15178 l 2.96251,-260.9134 c 4.8641,-15.18114 6.5647,-33.178351 32.18836,-29.87971 l 275.94999,-2.70784 c 20.77162,8.07608 33.36126,18.37634 35.15087,43.40105 z"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
style="opacity:0.962206;fill:#959492;fill-opacity:1;stroke:none;stroke-width:15.5961;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="m 319.2092,333.58203 v 8.28825 h 39.50577 v -8.28825 z"
|
||||
id="path137" />
|
||||
<path
|
||||
style="opacity:0.962206;fill:#bab8b6;fill-opacity:1;stroke:none;stroke-width:15.5961;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="m 303.40688,333.58203 v 8.28825 h 7.90115 v -8.28825 z"
|
||||
id="path138" />
|
||||
<path
|
||||
style="opacity:0.962206;fill:#bab8b6;fill-opacity:1;stroke:none;stroke-width:15.5961;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="m 184.88953,333.58203 v 8.28825 h 39.50579 v -8.28825 z"
|
||||
id="path139" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#338265;stroke-width:16.1847;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="path140"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="182.85791"
|
||||
sodipodi:cy="194.53314"
|
||||
sodipodi:rx="39.532063"
|
||||
sodipodi:ry="41.468849"
|
||||
sodipodi:start="3.4870691"
|
||||
sodipodi:end="5.9389792"
|
||||
sodipodi:arc-type="arc"
|
||||
d="m 145.66163,180.48992 a 39.532063,41.468849 0 0 1 37.22139,-27.42562 39.532063,41.468849 0 0 1 37.18815,27.4752"
|
||||
sodipodi:open="true" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#338265;stroke-width:16.1847;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="path141"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="334.94324"
|
||||
sodipodi:cy="194.53314"
|
||||
sodipodi:rx="39.532063"
|
||||
sodipodi:ry="41.468849"
|
||||
sodipodi:start="3.4870691"
|
||||
sodipodi:end="5.9389792"
|
||||
sodipodi:arc-type="arc"
|
||||
d="m 297.74696,180.48992 a 39.532063,41.468849 0 0 1 37.22139,-27.42562 39.532063,41.468849 0 0 1 37.18814,27.4752"
|
||||
sodipodi:open="true" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#136246;stroke-width:16.1847;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="path142"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="182.85791"
|
||||
sodipodi:cy="194.53314"
|
||||
sodipodi:rx="39.532063"
|
||||
sodipodi:ry="41.468849"
|
||||
sodipodi:start="3.4870691"
|
||||
sodipodi:end="5.9389792"
|
||||
sodipodi:arc-type="arc"
|
||||
d="m 145.66163,180.48992 a 39.532063,41.468849 0 0 1 37.22139,-27.42562 39.532063,41.468849 0 0 1 37.18815,27.4752"
|
||||
sodipodi:open="true" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:1;stroke:#136246;stroke-width:16.1847;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="path143"
|
||||
sodipodi:type="arc"
|
||||
sodipodi:cx="334.94324"
|
||||
sodipodi:cy="194.53314"
|
||||
sodipodi:rx="39.532063"
|
||||
sodipodi:ry="41.468849"
|
||||
sodipodi:start="3.4870691"
|
||||
sodipodi:end="5.9389792"
|
||||
sodipodi:arc-type="arc"
|
||||
d="m 297.74696,180.48992 a 39.532063,41.468849 0 0 1 37.22139,-27.42562 39.532063,41.468849 0 0 1 37.18814,27.4752"
|
||||
sodipodi:open="true" />
|
||||
<g
|
||||
id="rect170"
|
||||
transform="matrix(14.931319,0,0,15.662846,3.1629451,-1124.2224)">
|
||||
<path
|
||||
id="path171"
|
||||
style="color:#000000;fill:#136246;fill-opacity:1;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"
|
||||
d="m 13.226583,85.460934 c -0.655338,0 -1.187524,0.532187 -1.187524,1.187525 v 0.0057 c 0,0.655338 0.532186,1.187525 1.187524,1.187525 h 7.414018 c 0.655338,0 1.187524,-0.532187 1.187524,-1.187525 v -0.0057 c 0,-0.655338 -0.532186,-1.187525 -1.187524,-1.187525 z" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#75dfb9;fill-opacity:1;stroke:url(#linearGradient165);stroke-width:4.0462;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;paint-order:markers stroke fill"
|
||||
id="rect156"
|
||||
width="142.22083"
|
||||
height="33.153057"
|
||||
x="184.8895"
|
||||
y="211.65942"
|
||||
ry="16.520575" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient167);stroke:none;stroke-width:4.0462;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect160"
|
||||
width="4.089407"
|
||||
height="33.153057"
|
||||
x="228.20706"
|
||||
y="211.65942"
|
||||
ry="0" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient169);stroke:none;stroke-width:4.0462;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect161"
|
||||
width="4.089407"
|
||||
height="33.153057"
|
||||
x="279.70337"
|
||||
y="211.65942"
|
||||
ry="0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 18 KiB |
72
lib/Exd.pm
Normal file
72
lib/Exd.pm
Normal file
@ -0,0 +1,72 @@
|
||||
package Exd;
|
||||
|
||||
use v5.40.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Moo;
|
||||
use JSON;
|
||||
use Path::Tiny;
|
||||
use UUID::URandom qw/create_uuid_string/;
|
||||
|
||||
has config => ( is => 'lazy' );
|
||||
|
||||
sub _build_config($self) {
|
||||
return JSON::from_json( $self->_config_file_name->slurp_utf8 );
|
||||
}
|
||||
|
||||
sub _config_file_name($self) {
|
||||
return path(__FILE__)->parent->parent->child('app_config.json');
|
||||
}
|
||||
|
||||
sub licenser_server($self) {
|
||||
return $self->config->{'licenser-server'};
|
||||
}
|
||||
|
||||
sub debug($self) {
|
||||
return $self->config->{debug};
|
||||
}
|
||||
|
||||
sub uuid($self) {
|
||||
require Exd::DB;
|
||||
my $dbh = Exd::DB->connect;
|
||||
my $key = 'licenser-uuid';
|
||||
my $option =
|
||||
$dbh->selectrow_hashref( 'SELECT value FROM options WHERE name = ?;',
|
||||
{}, $key );
|
||||
my $uuid;
|
||||
if (defined $option) {
|
||||
$uuid = $option->{value};
|
||||
}
|
||||
if ( !defined $uuid ) {
|
||||
$uuid = create_uuid_string();
|
||||
$dbh->do( 'INSERT OR IGNORE INTO options (name, value) VALUES (?, ?);',
|
||||
{}, $key, $uuid );
|
||||
}
|
||||
return $uuid;
|
||||
}
|
||||
|
||||
{
|
||||
my $key = 'activated';
|
||||
sub is_activated_license($self) {
|
||||
require Exd::DB;
|
||||
my $dbh = Exd::DB->connect;
|
||||
my $option =
|
||||
$dbh->selectrow_hashref( 'SELECT value FROM options WHERE name = ?;',
|
||||
{}, $key );
|
||||
if (!defined $option) {
|
||||
return 0;
|
||||
}
|
||||
return $option->{value};
|
||||
}
|
||||
|
||||
sub activate_license($self) {
|
||||
require Exd::DB;
|
||||
my $dbh = Exd::DB->connect;
|
||||
$dbh->do( 'INSERT OR IGNORE INTO options (name, value) VALUES (?, ?);',
|
||||
{}, $key, 1 );
|
||||
}
|
||||
}
|
||||
1;
|
@ -56,7 +56,6 @@ sub _build__gatt($self) {
|
||||
|
||||
sub try_to_connect($self) {
|
||||
my $device_api = $self->_device;
|
||||
say $device_api->Connected;
|
||||
return if $device_api->Connected;
|
||||
$device_api->Connect;
|
||||
|
||||
|
105
lib/Exd/Gui.pm
105
lib/Exd/Gui.pm
@ -15,6 +15,7 @@ use Glib::IO;
|
||||
use Glib::Object::Introspection;
|
||||
use Path::Tiny;
|
||||
use GD::Image;
|
||||
use Mojo::UserAgent;
|
||||
|
||||
use IO::Select;
|
||||
use Capture::Tiny qw/capture/;
|
||||
@ -25,6 +26,7 @@ use Exd::FileFormat;
|
||||
use Exd::Gui::PrinterConfigure;
|
||||
use Exd::Gui::FontGallery;
|
||||
use Exd::Gui::Instance;
|
||||
use Exd;
|
||||
|
||||
use JSON;
|
||||
use Net::DBus;
|
||||
@ -53,6 +55,12 @@ Glib::Object::Introspection->setup(
|
||||
package => 'Gtk4::Source',
|
||||
);
|
||||
|
||||
Glib::Object::Introspection->setup(
|
||||
basename => 'Adw',
|
||||
version => '1',
|
||||
package => 'Adw',
|
||||
);
|
||||
|
||||
has _app => ( is => 'rw', );
|
||||
|
||||
has _select => ( is => 'lazy', );
|
||||
@ -74,9 +82,27 @@ has _first_time => ( is => 'rw', default => sub { 1 } );
|
||||
has _last_instance_id => ( is => 'rw', default => sub { 0 } );
|
||||
has parent_pid => ( is => 'rw' );
|
||||
has instances => ( is => 'rw', default => sub { return {} } );
|
||||
has _gresources_path => ( is => 'lazy', );
|
||||
has _exd => ( is => 'lazy' );
|
||||
|
||||
sub start( $self ) {
|
||||
my $app = Gtk4::Application->new( 'me.sergiotarxz.Exd', [qw/default-flags handles-command-line handles-open/] );
|
||||
sub _build__gresources_path($self) {
|
||||
my $root = path(__FILE__)->parent->parent->parent;
|
||||
my $gresources = $root->child('resources.gresource');
|
||||
0 == system( 'which', 'glib-compile-resources' )
|
||||
&& system( 'glib-compile-resources', $root->child('resources.xml') );
|
||||
if ( !-e $gresources ) {
|
||||
{
|
||||
die 'No gresources';
|
||||
}
|
||||
}
|
||||
return $gresources;
|
||||
}
|
||||
|
||||
sub start($self) {
|
||||
Glib::IO::resources_register(
|
||||
Glib::IO::Resource::load( $self->_gresources_path ) );
|
||||
my $app = Adw::Application->new( 'me.sergiotarxz.Exd',
|
||||
[qw/default-flags handles-command-line handles-open/] );
|
||||
my $bus = Net::DBus->session;
|
||||
my $started = 0;
|
||||
eval {
|
||||
@ -87,7 +113,7 @@ sub start( $self ) {
|
||||
$self->_app($app);
|
||||
my $arguments = [];
|
||||
$app->signal_connect(
|
||||
command_line => sub($app, $command_line) {
|
||||
command_line => sub( $app, $command_line ) {
|
||||
$arguments = $command_line->get_arguments;
|
||||
my $exd_file = shift @$arguments;
|
||||
$self->_activate($exd_file);
|
||||
@ -105,11 +131,9 @@ sub start( $self ) {
|
||||
}
|
||||
);
|
||||
say @ARGV;
|
||||
$app->run(\@ARGV);
|
||||
$app->run( \@ARGV );
|
||||
}
|
||||
|
||||
|
||||
|
||||
sub _startup($self) {
|
||||
my $app = $self->_app;
|
||||
}
|
||||
@ -120,6 +144,15 @@ sub send_packet_to_daemon( $self, $instance, $packet ) {
|
||||
$self->_write_to_script->flush;
|
||||
}
|
||||
|
||||
sub send_packet_check_if_activated( $self, $instance, $uuid) {
|
||||
$self->send_packet_to_daemon($instance, {
|
||||
type => 'check-activated',
|
||||
data => {
|
||||
uuid => $uuid,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sub _daemon_runner($self) {
|
||||
my ( $read_from_script, $write_to_parent );
|
||||
my ( $read_from_parent, $write_to_script );
|
||||
@ -165,12 +198,51 @@ sub _daemon_runner($self) {
|
||||
if ( $packet->{type} eq 'font-scan' ) {
|
||||
next;
|
||||
}
|
||||
if ( $packet->{type} eq 'check-activated') {
|
||||
$self->_on_check_activated($instance_id, $packet->{data});
|
||||
next;
|
||||
}
|
||||
warn 'Packet not recognized: '. Data::Dumper::Dumper $packet;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
close $read_from_parent;
|
||||
}
|
||||
|
||||
sub _build__exd($self) {
|
||||
require Exd;
|
||||
return Exd->new;
|
||||
}
|
||||
|
||||
sub _on_check_activated($self, $instance_id, $data) {
|
||||
my $pid = fork;
|
||||
if (!$pid) {
|
||||
while (1) {
|
||||
eval {
|
||||
my $url = $self->_exd->licenser_server.'/get_paid/'.$self->_exd->uuid;
|
||||
my $ua = Mojo::UserAgent->new;
|
||||
my $activated = $ua->get($url)->result->json;
|
||||
if ($activated) {
|
||||
say 'Program sucessfully activated, thank you!';
|
||||
$self->_exd->activate_license;
|
||||
$self->send_packet_to_window($instance_id, {
|
||||
type => 'activated!',
|
||||
});
|
||||
exit;
|
||||
}
|
||||
};
|
||||
if ($@) {
|
||||
warn $@;
|
||||
}
|
||||
sleep 5;
|
||||
if (!kill 0, $self->parent_pid) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub send_packet_to_window( $self, $instance_id, $packet ) {
|
||||
$packet->{instance_id} = $instance_id;
|
||||
$self->_write_to_parent->say( JSON::to_json($packet) );
|
||||
@ -196,8 +268,8 @@ sub _on_save_packet( $self, $instance_id, $json ) {
|
||||
$self->_save( $instance_id, $exd, $dest_file );
|
||||
};
|
||||
if ($@) {
|
||||
$self->_log($instance_id, $@);
|
||||
$self->_send_safe_to_exit($instance_id, 1);
|
||||
$self->_log( $instance_id, $@ );
|
||||
$self->_send_safe_to_exit( $instance_id, 1 );
|
||||
}
|
||||
exit;
|
||||
}
|
||||
@ -222,7 +294,7 @@ sub _on_run_script_packet( $self, $instance_id, $json ) {
|
||||
$json->@{ 'exd_dir', 'device', 'verbose' };
|
||||
$device = $self->device_hash_to_object($device);
|
||||
|
||||
my ($read, $write);
|
||||
my ( $read, $write );
|
||||
pipe $read, $write;
|
||||
|
||||
my $new_pid = fork;
|
||||
@ -239,12 +311,12 @@ sub _on_run_script_packet( $self, $instance_id, $json ) {
|
||||
close $write;
|
||||
if ($verbose) {
|
||||
my $log_getter_pid = fork;
|
||||
if (!$log_getter_pid) {
|
||||
$self->_log($instance_id, '### STARTED EXECUTION ###');
|
||||
while (my $line = <$read>) {
|
||||
$self->_log($instance_id, $line);
|
||||
if ( !$log_getter_pid ) {
|
||||
$self->_log( $instance_id, '### STARTED EXECUTION ###' );
|
||||
while ( my $line = <$read> ) {
|
||||
$self->_log( $instance_id, $line );
|
||||
}
|
||||
$self->_log($instance_id, '### TERMINATED EXECUTION ###');
|
||||
$self->_log( $instance_id, '### TERMINATED EXECUTION ###' );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@ -353,12 +425,13 @@ sub _log( $self, $instance_id, $message ) {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
sub _save( $self, $instance_id, $exd, $dest_file ) {
|
||||
$self->_log( $instance_id, "Pending save to $dest_file." );
|
||||
$self->_send_safe_to_exit($instance_id, 0);
|
||||
$self->_send_safe_to_exit( $instance_id, 0 );
|
||||
my $zip = $exd->to_zip;
|
||||
$zip->writeToFileNamed( '' . $dest_file );
|
||||
$self->_send_safe_to_exit($instance_id, 1);
|
||||
$self->_send_safe_to_exit( $instance_id, 1 );
|
||||
$self->_log( $instance_id, "Save completed to $dest_file." );
|
||||
}
|
||||
|
||||
|
@ -12,13 +12,18 @@ use Glib;
|
||||
use Glib::IO;
|
||||
use Glib::Object::Introspection;
|
||||
use Path::Tiny;
|
||||
use Mojo::UserAgent;
|
||||
|
||||
has app => ( is => 'rw', required => 1, weak_ref => 1 );
|
||||
has instance_id => ( is => 'rw', required => 1 );
|
||||
has window => ( is => 'rw' );
|
||||
has _editor => ( is => 'rw', );
|
||||
has _safe_to_exit => ( is => 'rw', default => sub { 1 } );
|
||||
has _transparent_avoid_input => ( is => 'rw' );
|
||||
has _paywall => ( is => 'rw' );
|
||||
has device => ( is => 'rw' );
|
||||
has _pay_url => ( is => 'lazy' );
|
||||
has _activated => ( is => 'rw' );
|
||||
has file_format => (
|
||||
is => 'rw',
|
||||
default => sub {
|
||||
@ -47,6 +52,12 @@ has _can_open_printer_configure => ( is => 'rw', default => sub { 1 } );
|
||||
has _preview_number => ( is => 'rw', default => sub { 0 } );
|
||||
has _save_path => ( is => 'rw' );
|
||||
has _want_to_close => ( is => 'rw' );
|
||||
has _exd => ( is => 'lazy' );
|
||||
has _overlay => ( is => 'rw' );
|
||||
|
||||
sub _build__exd($self) {
|
||||
return Exd->new;
|
||||
}
|
||||
|
||||
sub start( $self, $exd_file ) {
|
||||
my $win = $self->app->create_application_window;
|
||||
@ -116,7 +127,7 @@ sub start( $self, $exd_file ) {
|
||||
$execute_log->set_editable(0);
|
||||
$execute_log->set_cursor_visible(0);
|
||||
|
||||
$win->set_title('Exd (Thermal Printer)');
|
||||
$win->set_title('Hiperthermia (Thermal Printer) ' . ($self->_exd->debug ? 'DEBUG' : '') );
|
||||
$win->set_default_size( 1200, 900 );
|
||||
|
||||
$execute_log->set_hexpand(1);
|
||||
@ -150,20 +161,192 @@ sub start( $self, $exd_file ) {
|
||||
);
|
||||
$execute_log_window->set_child($execute_log);
|
||||
$box_vertical->append($execute_log_window);
|
||||
$win->set_child($box_vertical);
|
||||
my $overlay = Gtk4::Overlay->new;
|
||||
$self->_overlay($overlay);
|
||||
$overlay->set_child($box_vertical);
|
||||
$self->_activated( $self->_exd->is_activated_license );
|
||||
if ( !$self->_activated ) {
|
||||
my $uuid = $self->_exd->uuid;
|
||||
my $instance_id = $self->instance_id;
|
||||
$self->_add_timeout_paywall($overlay);
|
||||
$self->app->send_packet_check_if_activated( $self, $uuid );
|
||||
}
|
||||
$win->set_child($overlay);
|
||||
$win->present;
|
||||
}
|
||||
|
||||
sub _show_about_dialog($self) {
|
||||
my $window = Gtk4::Window->new;
|
||||
$window->set_default_size( 650, 650 );
|
||||
$window->set_transient_for( $self->window );
|
||||
$window->set_title('About Hiperthermia');
|
||||
my $picture = Gtk4::Picture->new;
|
||||
$picture->set_property('width-request', 256);
|
||||
$picture->set_property('height-request', 256);
|
||||
$picture->set_filename(path(__FILE__)->parent->parent->parent->parent->child('exd-logo.png').'');
|
||||
my $label = Gtk4::Label->new(undef);
|
||||
$label->set_markup(<<"EOF");
|
||||
Welcome to Hiperthermia.
|
||||
|
||||
This is a paid program but fully open source for everyone,
|
||||
have a copy of the source code at <a href="https://git.owlcode.tech/sergiotarxz/Exd">our source repo</a> under the AGPLv3 license.
|
||||
|
||||
NO WARRANTY TO THE EXTENT ALLOWED BY LAW, but fell free to drop
|
||||
\@sergiotarxz a message if you find bugs, issues or need support
|
||||
to use this program.
|
||||
|
||||
Our amazing contributors:
|
||||
|
||||
Sergiotarxz (Developer):
|
||||
<a href="https://git.owlcode.tech/sergiotarxz">Gitea</a>
|
||||
\@sergiotarxz in Telegram.
|
||||
\@sergiotarxz\@owlcode.tech in XMPP.
|
||||
(Open to freelance work and full time employement,
|
||||
accepts ETH, BTC and Bank transfers)
|
||||
|
||||
Lucidraws (Logo creator):
|
||||
<a href="https://linktr.ee/lucidraws">lintr.ee</a>
|
||||
(Open to graphic design comissions,
|
||||
accepts ETH, BTC and Mercado Pago payments)
|
||||
EOF
|
||||
my $box = Gtk4::Box->new( 'vertical', 10 );
|
||||
$box->set_hexpand(1);
|
||||
$box->set_vexpand(1);
|
||||
$box->set_halign('center');
|
||||
$box->set_valign('center');
|
||||
$box->append($picture);
|
||||
$box->append($label);
|
||||
my $scroll = Gtk4::ScrolledWindow->new;
|
||||
$scroll->set_vexpand(1);
|
||||
$scroll->set_hexpand(1);
|
||||
$scroll->set_child($box);
|
||||
$window->set_child($scroll);
|
||||
$window->present;
|
||||
}
|
||||
|
||||
sub _add_timeout_paywall( $self, $overlay ) {
|
||||
if ( $self->_activated ) {
|
||||
return 0;
|
||||
}
|
||||
if ( defined $self->_pay_url ) {
|
||||
Glib::Timeout->add(
|
||||
$self->_exd->debug ? 1_000 : 20_000,
|
||||
sub {
|
||||
my $box = Gtk4::Box->new( 'vertical', 10 );
|
||||
$self->_transparent_avoid_input($box);
|
||||
$box->set_opacity(0.7);
|
||||
$box->add_css_class('avoid-main-input');
|
||||
$box->set_halign('fill');
|
||||
$box->set_valign('fill');
|
||||
my $paywall = Gtk4::Box->new( 'vertical', 10 );
|
||||
$self->_paywall($paywall);
|
||||
|
||||
$paywall->set_property( 'width-request', 800 );
|
||||
$paywall->set_property( 'height-request', 800 );
|
||||
$paywall->add_css_class('paywall');
|
||||
my $inner_paywall_box = Gtk4::Box->new( 'vertical', 10 );
|
||||
my $title = Gtk4::Label->new('This program is not activated');
|
||||
my $activate = Gtk4::Button->new_with_label('Pay and activate');
|
||||
my $about = Gtk4::Button->new_with_label('More about the program');
|
||||
my $remind_me_later =
|
||||
Gtk4::Button->new_with_label('Remind me later');
|
||||
$about->signal_connect(
|
||||
clicked => sub {
|
||||
$self->_show_about_dialog;
|
||||
}
|
||||
);
|
||||
$activate->signal_connect(
|
||||
clicked => sub {
|
||||
my $launcher =
|
||||
Gtk4::UriLauncher->new( $self->_pay_url );
|
||||
$launcher->launch( $self->window, undef, undef );
|
||||
}
|
||||
);
|
||||
$remind_me_later->signal_connect(
|
||||
'clicked' => sub {
|
||||
$overlay->remove_overlay($paywall);
|
||||
$overlay->remove_overlay($box);
|
||||
$self->_paywall(undef);
|
||||
$self->_transparent_avoid_input(undef);
|
||||
$self->_add_timeout_paywall($overlay);
|
||||
}
|
||||
);
|
||||
my $picture = Gtk4::Image->new_from_file(path(__FILE__)->parent->parent->parent->parent->child('exd-logo.png').'');
|
||||
$picture->set_pixel_size(256);
|
||||
$inner_paywall_box->append($picture);
|
||||
$inner_paywall_box->append($title);
|
||||
if ($self->_exd->debug) {
|
||||
my $debug_message = Gtk4::Label->new('This is debug compilation, do not use your real payment data but a Stripe test card');
|
||||
$inner_paywall_box->append($debug_message);
|
||||
}
|
||||
$inner_paywall_box->append($activate);
|
||||
$inner_paywall_box->append($remind_me_later);
|
||||
$inner_paywall_box->append($about);
|
||||
$inner_paywall_box->set_valign('center');
|
||||
$inner_paywall_box->set_vexpand(1);
|
||||
$paywall->set_vexpand(1);
|
||||
$inner_paywall_box->set_halign('center');
|
||||
$paywall->set_halign('center');
|
||||
$paywall->set_valign('fill');
|
||||
$overlay->add_overlay($box);
|
||||
$overlay->add_overlay($paywall);
|
||||
$paywall->append($inner_paywall_box);
|
||||
Glib::Timeout->add(
|
||||
1_000,
|
||||
sub {
|
||||
return 0 if !defined $self->_transparent_avoid_input;
|
||||
if ($self->_activated) {
|
||||
if ( defined $self->_paywall ) {
|
||||
$self->_overlay->remove_overlay( $self->_paywall );
|
||||
}
|
||||
if ( defined $self->_transparent_avoid_input ) {
|
||||
$self->_overlay->remove_overlay(
|
||||
$self->_transparent_avoid_input );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub _build__pay_url($self) {
|
||||
my $url;
|
||||
eval {
|
||||
my $ua = Mojo::UserAgent->new;
|
||||
$url = $ua->get(
|
||||
$self->_exd->licenser_server . '/get_pay_url/' . $self->_exd->uuid )
|
||||
->result->json->{url};
|
||||
};
|
||||
if ($@) {
|
||||
warn $@;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
sub _create_popover_menu( $self, $box ) {
|
||||
my $menu_model = Glib::IO::Menu->new;
|
||||
my $file_menu = Glib::IO::Menu->new;
|
||||
my $help_menu = Glib::IO::Menu->new;
|
||||
my $open_action =
|
||||
Glib::IO::SimpleAction->new( 'open.' . $self->instance_id, undef );
|
||||
my $save_action =
|
||||
Glib::IO::SimpleAction->new( 'save.' . $self->instance_id, undef );
|
||||
my $save_as_action =
|
||||
Glib::IO::SimpleAction->new( 'save-as.' . $self->instance_id, undef );
|
||||
my $about_action =
|
||||
Glib::IO::SimpleAction->new( 'about.' . $self->instance_id, undef );
|
||||
my $app = $self->app->_app;
|
||||
$about_action->signal_connect(
|
||||
'activate',
|
||||
sub {
|
||||
$self->_show_about_dialog;
|
||||
}
|
||||
);
|
||||
$open_action->signal_connect(
|
||||
'activate',
|
||||
sub {
|
||||
@ -185,10 +368,13 @@ sub _create_popover_menu( $self, $box ) {
|
||||
$app->add_action($open_action);
|
||||
$app->add_action($save_action);
|
||||
$app->add_action($save_as_action);
|
||||
$app->add_action($about_action);
|
||||
$file_menu->append( 'Open', 'app.open.' . $self->instance_id );
|
||||
$file_menu->append( 'Save', 'app.save.' . $self->instance_id );
|
||||
$file_menu->append( 'Save as', 'app.save-as.' . $self->instance_id );
|
||||
$help_menu->append( 'About', 'app.about.' . $self->instance_id);
|
||||
$menu_model->append_submenu( 'File', $file_menu );
|
||||
$menu_model->append_submenu( 'Help', $help_menu );
|
||||
my $popover = Gtk4::PopoverMenuBar->new_from_model($menu_model);
|
||||
$box->append($popover);
|
||||
}
|
||||
@ -243,7 +429,7 @@ sub _populate_editor_and_preview( $self, $box_vertical ) {
|
||||
|
||||
sub _update_editor_buffer($self) {
|
||||
my $editor = $self->_editor;
|
||||
if (defined $editor) {
|
||||
if ( defined $editor ) {
|
||||
my $buffer = $editor->get_buffer();
|
||||
$buffer->set_text( $self->file_format->get_script, -1 );
|
||||
}
|
||||
@ -324,6 +510,15 @@ sub receive_packet( $self, $packet ) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ( $packet->{type} eq 'activated!' ) {
|
||||
$self->mark_activated;
|
||||
return;
|
||||
}
|
||||
warn 'Packet not recognized ' . Data::Dumper::Dumper $packet;
|
||||
}
|
||||
|
||||
sub mark_activated($self) {
|
||||
$self->_activated(1);
|
||||
}
|
||||
|
||||
sub _add_to_log( $self, $text ) {
|
||||
@ -562,7 +757,7 @@ sub _open_file( $self, $file ) {
|
||||
$self->_save_path($file);
|
||||
my $window = $self->window;
|
||||
$window->set_title(
|
||||
"Exd (Thermal Printer) " . path( $self->_save_path )->basename );
|
||||
"Hiperthermia (Thermal Printer) " . ($self->_exd->debug ? 'DEBUG' : '') . path( $self->_save_path )->basename );
|
||||
$self->file_format( Exd::FileFormat->from_zip_file($file) );
|
||||
$self->_update_editor_buffer;
|
||||
}
|
||||
|
@ -17,17 +17,17 @@ use Exd::DeviceToBluetooth;
|
||||
use Exd::DeviceToRawFile;
|
||||
use Exd::DeviceToCatPrinter;
|
||||
|
||||
has app => (is => 'ro', required => 1);
|
||||
has instance => (is => 'ro', required => 1);
|
||||
has app => ( is => 'ro', required => 1 );
|
||||
has instance => ( is => 'ro', required => 1 );
|
||||
has on_close => ( is => 'ro', required => 1 );
|
||||
has _pid_daemon => (is => 'rw');
|
||||
has _read_from_daemon => (is => 'rw');
|
||||
has _write_to_app => (is => 'rw');
|
||||
has _pid_daemon => ( is => 'rw' );
|
||||
has _read_from_daemon => ( is => 'rw' );
|
||||
has _write_to_app => ( is => 'rw' );
|
||||
has _select => ( is => 'lazy', );
|
||||
has _window => ( is => 'rw' );
|
||||
has _bluetooth_printers => ( is => 'rw', default => sub { [] } );
|
||||
has _usb_printers => ( is => 'rw', default => sub { [] });
|
||||
has _cat_printers => ( is => 'rw', default => sub { [] });
|
||||
has _usb_printers => ( is => 'rw', default => sub { [] } );
|
||||
has _cat_printers => ( is => 'rw', default => sub { [] } );
|
||||
has _stop_timeout => ( is => 'rw' );
|
||||
|
||||
sub _build__select($self) {
|
||||
@ -38,67 +38,146 @@ sub _read_bluetooth_printers($self) {
|
||||
my @fhs = $self->_select->can_read(0);
|
||||
for my $fh (@fhs) {
|
||||
$fh->blocking(0);
|
||||
while (defined(my $line = <$fh>)) {
|
||||
my @return = map {$self->app->device_hash_to_object($_)} @{JSON::from_json($line)};
|
||||
$self->_bluetooth_printers(\@return);
|
||||
Exd::DeviceToBluetooth->cache_printers($self->_bluetooth_printers);
|
||||
while ( defined( my $line = <$fh> ) ) {
|
||||
my @return = map { $self->app->device_hash_to_object($_) }
|
||||
@{ JSON::from_json($line) };
|
||||
$self->_bluetooth_printers( \@return );
|
||||
Exd::DeviceToBluetooth->cache_printers(
|
||||
$self->_bluetooth_printers );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _usb_printer_print_to_box($self, $device, $box) {
|
||||
sub _usb_printer_print_to_box( $self, $device, $box ) {
|
||||
my $window = $self->_window;
|
||||
my $button = Gtk4::Button->new_with_label($device->output_file);
|
||||
$button->signal_connect('clicked', sub {
|
||||
my $button = Gtk4::Button->new_with_label( $device->output_file );
|
||||
$button->signal_connect(
|
||||
'clicked',
|
||||
sub {
|
||||
$self->instance->device($device);
|
||||
$window->close;
|
||||
});
|
||||
}
|
||||
);
|
||||
$box->append($button);
|
||||
}
|
||||
|
||||
sub _cat_printer_print_to_box($self, $device, $box) {
|
||||
sub _cat_printer_print_to_box( $self, $device, $box ) {
|
||||
my $window = $self->_window;
|
||||
my $button = Gtk4::Button->new_with_label($device->path);
|
||||
$button->signal_connect('clicked', sub {
|
||||
my $button = Gtk4::Button->new_with_label( $device->path );
|
||||
$button->signal_connect(
|
||||
'clicked',
|
||||
sub {
|
||||
$self->instance->device($device);
|
||||
$window->close;
|
||||
});
|
||||
}
|
||||
);
|
||||
$box->append($button);
|
||||
}
|
||||
|
||||
sub _bluetoth_printer_print_to_box($self, $device, $box) {
|
||||
sub _bluetoth_printer_print_to_box( $self, $device, $box ) {
|
||||
my $window = $self->_window;
|
||||
my $button = Gtk4::Button->new_with_label($device->name.':'.$device->address);
|
||||
$button->signal_connect('clicked', sub {
|
||||
my $button =
|
||||
Gtk4::Button->new_with_label( $device->name . ':' . $device->address );
|
||||
$button->signal_connect(
|
||||
'clicked',
|
||||
sub {
|
||||
$self->instance->device($device);
|
||||
$window->close;
|
||||
});
|
||||
}
|
||||
);
|
||||
$box->append($button);
|
||||
}
|
||||
|
||||
sub _read_usb_printers($self) {
|
||||
my @printers = map { Exd::DeviceToRawFile->new(output_file => $_) } glob '/dev/usb/lp*';
|
||||
$self->_usb_printers(\@printers);
|
||||
my @printers = map { Exd::DeviceToRawFile->new( output_file => $_ ) }
|
||||
glob '/dev/usb/lp*';
|
||||
$self->_usb_printers( \@printers );
|
||||
}
|
||||
|
||||
sub _device_api( $self, $path ) {
|
||||
my $session = Net::DBus->system( private => 1 );
|
||||
my $service = $session->get_service('org.bluez');
|
||||
return $service->get_object( $path, 'org.bluez.Device1' );
|
||||
}
|
||||
|
||||
has _pid_read_special_cat_printer => ( is => 'rw' );
|
||||
|
||||
sub _try_to_connect_difficult_cat_printer_devices( $self, $key, $device ) {
|
||||
if ( defined $device && $device->{Name} eq 'SC05-6F4C' ) {
|
||||
my $device_api = $self->_device_api($key);
|
||||
if ( $device_api->Connected ) {
|
||||
return;
|
||||
}
|
||||
$device_api->get_service->get_bus->get_connection->disconnect;
|
||||
if ( defined $self->_pid_read_special_cat_printer && kill 0,
|
||||
$self->_pid_read_special_cat_printer )
|
||||
{
|
||||
# Ignoring if there is a fork running.
|
||||
return;
|
||||
}
|
||||
$self->_pid_read_special_cat_printer(fork);
|
||||
if ( !$self->_pid_read_special_cat_printer ) {
|
||||
my $device_api = $self->_device_api($key);
|
||||
eval {
|
||||
$device_api->CancelPairing;
|
||||
sleep 1;
|
||||
};
|
||||
if ($@) {
|
||||
warn $@;
|
||||
}
|
||||
eval {
|
||||
$device_api->Pair;
|
||||
sleep 1;
|
||||
};
|
||||
if ($@) {
|
||||
warn $@;
|
||||
}
|
||||
eval {
|
||||
$device_api->Connect;
|
||||
sleep 1;
|
||||
};
|
||||
if ($@) {
|
||||
warn $@;
|
||||
}
|
||||
$device_api->get_service->get_bus->get_connection->disconnect;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub _read_cat_printers($self) {
|
||||
my $session = Net::DBus->system;
|
||||
my $session = Net::DBus->system( private => 1 );
|
||||
my $service = $session->get_service('org.bluez');
|
||||
my $path = '/';
|
||||
my $object_manager_interface = 'org.freedesktop.DBus.ObjectManager';
|
||||
my $object = $service->get_object($path, $object_manager_interface);
|
||||
my $object = $service->get_object( $path, $object_manager_interface );
|
||||
use Data::Dumper;
|
||||
my $items = $object->GetManagedObjects;
|
||||
$object->get_service->get_bus->get_connection->disconnect;
|
||||
my @paths_tx;
|
||||
for my $key (keys %$items) {
|
||||
|
||||
for my $key ( keys %$items ) {
|
||||
my $device = $items->{$key}{'org.bluez.Device1'};
|
||||
my $item = $items->{$key}{'org.bluez.GattCharacteristic1'};
|
||||
if (!defined $item) {
|
||||
|
||||
{
|
||||
next if defined $item;
|
||||
$self->_try_to_connect_difficult_cat_printer_devices( $key,
|
||||
$device );
|
||||
}
|
||||
if ( !defined $item ) {
|
||||
next;
|
||||
}
|
||||
if ($item->{UUID} eq '0000ae01-0000-1000-8000-00805f9b34fb') {
|
||||
if ( $item->{UUID} eq '0000ae01-0000-1000-8000-00805f9b34fb' ) {
|
||||
push @paths_tx, $key;
|
||||
}
|
||||
}
|
||||
$self->_cat_printers([map { Exd::DeviceToCatPrinter->new(path => $_) } sort {$a cmp $b} @paths_tx]);
|
||||
$self->_cat_printers(
|
||||
[
|
||||
map { Exd::DeviceToCatPrinter->new( path => $_ ) }
|
||||
sort { $a cmp $b } @paths_tx
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
sub start($self) {
|
||||
@ -107,15 +186,20 @@ sub start($self) {
|
||||
my $window = Gtk4::Window->new;
|
||||
$self->_window($window);
|
||||
$window->set_default_size( 600, 600 );
|
||||
$window->signal_connect('close-request', sub{
|
||||
$window->signal_connect(
|
||||
'close-request',
|
||||
sub {
|
||||
$self->_on_close;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
);
|
||||
$window->set_title('Printer Selection');
|
||||
$window->set_child(Gtk4::Label->new('Searching for printers...'));
|
||||
$self->_select->add($self->_read_from_daemon);
|
||||
$self->_bluetooth_printers(Exd::DeviceToBluetooth->devices_from_cache);
|
||||
Glib::Timeout->add(1000, sub {
|
||||
$window->set_child( Gtk4::Label->new('Searching for printers...') );
|
||||
$self->_select->add( $self->_read_from_daemon );
|
||||
$self->_bluetooth_printers( Exd::DeviceToBluetooth->devices_from_cache );
|
||||
Glib::Timeout->add(
|
||||
1000,
|
||||
sub {
|
||||
return 0 if $self->_stop_timeout;
|
||||
eval {
|
||||
$self->_read_usb_printers;
|
||||
@ -124,37 +208,38 @@ sub start($self) {
|
||||
$self->_update_box;
|
||||
};
|
||||
if ($@) {
|
||||
die $@;
|
||||
warn $@;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
);
|
||||
$window->present;
|
||||
$window->set_transient_for($self->instance->window);
|
||||
$window->set_transient_for( $self->instance->window );
|
||||
}
|
||||
|
||||
sub _update_box($self) {
|
||||
my $window = $self->_window;
|
||||
my $box = Gtk4::Box->new( 'vertical', 10 );
|
||||
my $bluetooth_printers = $self->_bluetooth_printers;
|
||||
for my $device ($bluetooth_printers->@*) {
|
||||
$self->_bluetoth_printer_print_to_box($device, $box);
|
||||
for my $device ( $bluetooth_printers->@* ) {
|
||||
$self->_bluetoth_printer_print_to_box( $device, $box );
|
||||
}
|
||||
for my $device ($self->_usb_printers->@*) {
|
||||
$self->_usb_printer_print_to_box($device, $box);
|
||||
for my $device ( $self->_usb_printers->@* ) {
|
||||
$self->_usb_printer_print_to_box( $device, $box );
|
||||
}
|
||||
for my $device ($self->_cat_printers->@*) {
|
||||
$self->_cat_printer_print_to_box($device, $box);
|
||||
for my $device ( $self->_cat_printers->@* ) {
|
||||
$self->_cat_printer_print_to_box( $device, $box );
|
||||
}
|
||||
$window->set_child($box);
|
||||
}
|
||||
|
||||
sub _start_daemon_bluetooth_search($self) {
|
||||
my ($read, $write);
|
||||
my ( $read, $write );
|
||||
pipe $read, $write;
|
||||
$self->_read_from_daemon($read);
|
||||
$self->_write_to_app($write);
|
||||
my $pid = fork;
|
||||
if (!$pid) {
|
||||
if ( !$pid ) {
|
||||
close $read;
|
||||
while (1) {
|
||||
$self->_daemon_bluetooth_search_iteration;
|
||||
@ -166,25 +251,35 @@ sub _start_daemon_bluetooth_search($self) {
|
||||
}
|
||||
|
||||
sub _daemon_bluetooth_search_iteration($self) {
|
||||
# say 'Listing bluetooth devices';
|
||||
if (!kill 0, $self->app->parent_pid) {
|
||||
|
||||
# say 'Listing bluetooth devices';
|
||||
if ( !kill 0, $self->app->parent_pid ) {
|
||||
say 'Parent died at bluetooth search iteration, exiting...';
|
||||
exit 1;
|
||||
}
|
||||
my $devices = Net::Bluetooth::get_remote_devices;
|
||||
my @return;
|
||||
for my $address (keys %$devices) {
|
||||
say "Detected $devices->{$address}:$address, looking if it supports Serial Port...";
|
||||
my $search = Net::Bluetooth::sdp_search($address, "1101", "");
|
||||
if (defined $search && defined $search->{RFCOMM}) {
|
||||
say "$devices->{$address}:$address supports Serial Port and may be a printer, the port is: $search->{RFCOMM}";
|
||||
for my $address ( keys %$devices ) {
|
||||
next if $devices->{$address} eq 'SC05-6F4C';
|
||||
say
|
||||
"Detected $devices->{$address}:$address, looking if it supports Serial Port...";
|
||||
my $search = Net::Bluetooth::sdp_search( $address, "1101", "" );
|
||||
if ( defined $search && defined $search->{RFCOMM} ) {
|
||||
say
|
||||
"$devices->{$address}:$address supports Serial Port and may be a printer, the port is: $search->{RFCOMM}";
|
||||
say $devices->{$address};
|
||||
push @return, Exd::DeviceToBluetooth->new(name => $devices->{$address}, address => $address, port => $search->{RFCOMM});
|
||||
push @return,
|
||||
Exd::DeviceToBluetooth->new(
|
||||
name => $devices->{$address},
|
||||
address => $address,
|
||||
port => $search->{RFCOMM}
|
||||
);
|
||||
}
|
||||
}
|
||||
# say 'Finishing listing bluetooth devices';
|
||||
|
||||
# say 'Finishing listing bluetooth devices';
|
||||
@return = map { $_->serialize } sort { $a->name cmp $b->name } @return;
|
||||
$self->_write_to_app->say(JSON::to_json(\@return));
|
||||
$self->_write_to_app->say( JSON::to_json( \@return ) );
|
||||
$self->_write_to_app->flush;
|
||||
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ sub print($self) {
|
||||
if system(
|
||||
qw/convert/,
|
||||
$image_file_in,
|
||||
qw/-resize 384x -brightness-contrast +10 -dither FloydSteinberg -remap pattern:gray50/,
|
||||
qw/-resize 384x -brightness-contrast +0.8 -dither FloydSteinberg -remap pattern:gray50/,
|
||||
$image_file_out
|
||||
);
|
||||
$image_final = Exd::Utils::get_gd_image( $image_file_out . '' );
|
||||
|
7
style-dark.css
Normal file
7
style-dark.css
Normal file
@ -0,0 +1,7 @@
|
||||
headerbar box {
|
||||
background: #015544;
|
||||
}
|
||||
|
||||
box.paywall {
|
||||
background: #010F0C;
|
||||
}
|
Loading…
Reference in New Issue
Block a user