Improve dashboard

This commit is contained in:
世界
2023-08-02 16:47:07 +08:00
parent b9a7ea4afa
commit 5e0573d15c
24 changed files with 619 additions and 257 deletions
@@ -1,6 +1,6 @@
{
"info": {
"author": "xcode",
"version": 1
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,15 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"symbol-rendering-intent" : "template"
},
"symbols" : [
{
"filename" : "singbox-menubar.svg",
"idiom" : "universal"
}
]
}
@@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 25.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 3300 2200" style="enable-background:new 0 0 3300 2200;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#000000;stroke-width:0.5;}
.st2{font-family:'Helvetica-Bold';}
.st3{font-size:13px;}
.st4{font-family:'Helvetica';}
.st5{fill:none;stroke:#00AEEF;stroke-width:0.5;}
.st6{fill:#27AAE1;}
.st7{fill:none;stroke:#27AAE1;stroke-width:0.5;}
</style>
<g id="Notes">
<rect id="artboard" class="st0" width="3300" height="2200"/>
<line class="st1" x1="263" y1="292" x2="3036" y2="292"/>
<text transform="matrix(1 0 0 1 263 322)" class="st2 st3">Weight/Scale Variations</text>
<text transform="matrix(1 0 0 1 534.0632935 322)" class="st4 st3">Ultralight</text>
<text transform="matrix(1 0 0 1 843.7774658 322)" class="st4 st3">Thin</text>
<text transform="matrix(1 0 0 1 1139.0350342 322)" class="st4 st3">Light</text>
<text transform="matrix(1 0 0 1 1427.0772705 322)" class="st4 st3">Regular</text>
<text transform="matrix(1 0 0 1 1723.4418945 322)" class="st4 st3">Medium</text>
<text transform="matrix(1 0 0 1 2016.171875 322)" class="st4 st3">Semibold</text>
<text transform="matrix(1 0 0 1 2326.970459 322)" class="st4 st3">Bold</text>
<text transform="matrix(1 0 0 1 2618.2658691 322)" class="st4 st3">Heavy</text>
<text transform="matrix(1 0 0 1 2917.5053711 322)" class="st4 st3">Black</text>
<line class="st1" x1="263" y1="1903" x2="3036" y2="1903"/>
<g transform="matrix(1 0 0 1 263 1933)">
<path d="M9.2480497,0.830078c4.3066502,0,7.8906507-3.5742178,7.8906507-7.8808579
c0-4.3066201-3.5938005-7.8808198-7.9004202-7.8808198c-4.2968702,0-7.8710904,3.5741997-7.8710904,7.8808198
C1.36719-2.7441399,4.95117,0.830078,9.2480497,0.830078z M9.2480497-0.654297
c-3.5449295,0-6.3769598-2.8417931-6.3769598-6.3964829c0-3.5547204,2.8222699-6.3965201,6.3671904-6.3965201
c3.5547199,0,6.4062195,2.8417997,6.4062195,6.3965201C15.6444998-3.4960899,12.8027-0.654297,9.2480497-0.654297z
M5.6543002-7.0507798c0,0.4296899,0.3027296,0.7226596,0.7519498,0.7226596h2.0996103v2.1191401
c0,0.43945,0.2929697,0.7421801,0.7226601,0.7421801c0.4492092,0,0.7421799-0.3027301,0.7421799-0.7421801v-2.1191401h2.1190996
c0.4394999,0,0.7421999-0.2929697,0.7421999-0.7226596c0-0.4394503-0.3027-0.7421904-0.7421999-0.7421904H9.9707003v-2.1093698
c0-0.4492598-0.2929707-0.7519598-0.7421799-0.7519598c-0.4296904,0-0.7226601,0.3027-0.7226601,0.7519598v2.1093698H6.40625
C5.9570298-7.7929702,5.6543002-7.4902301,5.6543002-7.0507798z"/>
</g>
<g transform="matrix(1 0 0 1 281.867 1933)">
<path d="M11.7089996,2.9101601c5.4491997,0,9.9609013-4.5214901,9.9609013-9.9609394
c0-5.4492207-4.5215015-9.9609203-9.9707012-9.9609203c-5.4394288,0-9.951149,4.5116997-9.951149,9.9609203
C1.7480507-1.61133,6.2695308,2.9101601,11.7089996,2.9101601z M11.7089996,1.25
c-4.6093888,0-8.291029-3.6914101-8.291029-8.3007793c0-4.6094208,3.6718702-8.3008194,8.281229-8.3008194
c4.6093998,0,8.3106003,3.6913996,8.3106003,8.3008194C20.0098-2.4414101,16.3183994,1.25,11.7089996,1.25z M7.177731-7.0507798
C7.177731-6.5722699,7.5097709-6.25,8.0078096-6.25h2.8710899v2.8808601c0,0.4882798,0.3320007,0.8300798,0.8106003,0.8300798
c0.4882002,0,0.8299999-0.3320298,0.8299999-0.8300798V-6.25h2.8809004c0.4882994,0,0.8300991-0.3222699,0.8300991-0.8007798
c0-0.4882803-0.3417997-0.83008-0.8300991-0.83008h-2.8809004v-2.87114c0-0.4980001-0.3417997-0.8397999-0.8299999-0.8397999
c-0.4785995,0-0.8106003,0.3417997-0.8106003,0.8397999v2.87114H8.0078096
C7.5097709-7.8808599,7.177731-7.5390601,7.177731-7.0507798z"/>
</g>
<g transform="matrix(1 0 0 1 305.646 1933)">
<path d="M14.9707003,5.6640601c6.9628992,0,12.7245989-5.7617164,12.7245989-12.7148399
c0-6.9629197-5.7714996-12.7246208-12.7343988-12.7246208c-6.9530907,0-12.70504,5.7617006-12.70504,12.7246208
C2.2558601-0.0976562,8.01758,5.6640601,14.9707003,5.6640601z M14.9707003,3.8476601
c-6.0351505,0-10.88867-4.8632803-10.88867-10.8984394c0-6.04492,4.843751-10.8984203,10.87887-10.8984203
c6.0449991,0,10.9082003,4.8534994,10.9082003,10.8984203C25.8691006-1.01562,21.0156002,3.8476601,14.9707003,3.8476601z
M9.1992197-7.0507798c0,0.51758,0.3710899,0.8789001,0.9179802,0.8789001H14.0625V-2.2168
c0,0.53711,0.3711004,0.9179699,0.8886995,0.9179699c0.5371008,0,0.9082003-0.3710899,0.9082003-0.9179699v-3.9550798h3.955101
c0.5370998,0,0.9179001-0.36132,0.9179001-0.8789001c0-0.5468802-0.3711014-0.9179702-0.9179001-0.9179702h-3.955101v-3.9453497
c0-0.5468006-0.3710995-0.9277-0.9082003-0.9277c-0.5175991,0-0.8886995,0.3808994-0.8886995,0.9277V-7.96875h-3.9453001
C9.5703096-7.96875,9.1992197-7.5976601,9.1992197-7.0507798z"/>
</g>
<text transform="matrix(1 0 0 1 263 1953)" class="st2 st3">Design Variations</text>
<text transform="matrix(1 0 0 1 263 1971)" class="st4 st3">Symbols are supported in up to nine weights and three scales.</text>
<text transform="matrix(1 0 0 1 263 1989)" class="st4 st3">For optimal layout with text and other symbols, vertically align</text>
<text transform="matrix(1 0 0 1 263 2007)" class="st4 st3">symbols with the adjacent text.</text>
<line class="st5" x1="776" y1="1919" x2="776" y2="1933"/>
<g transform="matrix(1 0 0 1 776 1933)">
<path d="M3.31055,0.15625c0.51757,0,0.7714798-0.1953125,0.9570301-0.742188l1.2597599-3.4472618h5.7617598l1.2597008,3.4472618
c0.1855993,0.5468755,0.4394999,0.742188,0.9473,0.742188c0.5175991,0,0.8495998-0.3125,0.8495998-0.800781
c0-0.166016-0.0293007-0.322266-0.1073999-0.527349L9.6582003-13.3690996c-0.2246103-0.5957003-0.625-0.8985004-1.25-0.8985004
c-0.6054702,0-1.0156202,0.2930002-1.2304702,0.8887005L2.5976601-1.16211c-0.07813,0.205079-0.10743,0.361329-0.10743,0.527344
C2.4902301-0.146484,2.8027301,0.15625,3.31055,0.15625z M6.0058599-5.51758l2.3730502-6.5722198h0.0488195L10.8008003-5.51758
H6.0058599z"/>
</g>
<line class="st5" x1="793.1970215" y1="1919" x2="793.1970215" y2="1933"/>
<text transform="matrix(1 0 0 1 776 1953)" class="st2 st3">Margins</text>
<text transform="matrix(1 0 0 1 776 1971)" class="st4 st3">Leading and trailing margins on the left and right side of each symbol</text>
<text transform="matrix(1 0 0 1 776 1989)" class="st4 st3">can be adjusted by modifying the x-location of the margin guidelines.</text>
<text transform="matrix(1 0 0 1 776 2007)" class="st4 st3">Modifications are automatically applied proportionally to all</text>
<text transform="matrix(1 0 0 1 776 2025)" class="st4 st3">scales and weights.</text>
<g transform="matrix(1 0 0 1 1289 1933)">
<path d="M2.8418,1.86523l1.6992199,1.70899c0.8593702,0.8691399,1.8457003,0.81055,2.7734299-0.2148399L18.0077991-8.4277296
l-0.9667988-0.9765701L6.4257798,2.2753899c-0.3515596,0.4003901-0.6835899,0.49805-1.1523399,0.0293L4.1015601,1.14258
c-0.46875-0.458986-0.36133-0.800783,0.0390601-1.1621113L15.6152-10.8203001l-0.9765005-0.9667997L3.04688-0.898438
C2.06055,0.0195312,1.98242,0.996094,2.8418,1.86523z M9.2578096-16.3281002
c-0.41992,0.4101-0.4492197,0.9863005-0.2148399,1.3769007c0.2343702,0.3613997,0.6933603,0.5956993,1.3379307,0.4296999
c1.4647999-0.3418007,2.9881992-0.4004002,4.4139996,0.5370998l-0.5859003,1.4551001
c-0.3417997,0.8301001-0.1659994,1.4159994,0.3711004,1.9629002L16.875-8.2519503
c0.4883003,0.4882803,0.8983994,0.5078101,1.4647999,0.4101501l1.0645008-0.1953101l0.6640987,0.6738305l-0.0390987,0.5566397
c-0.0391006,0.4980502,0.0879002,0.8789101,0.5761986,1.35742l0.7617016,0.7421904
c0.4784985,0.4785099,1.0936985,0.5078096,1.5625,0.0390596l2.910099-2.91992
c0.4687996-0.4687495,0.4493008-1.0644498-0.0293007-1.5429702L25.0391006-9.89258
c-0.4786015-0.4785204-0.8495998-0.6347198-1.3282013-0.5957203L23.1348-10.4394999L22.4902-11.0741997L22.7343998-12.1973
c0.1268997-0.5663996-0.0293007-1.0058002-0.6152992-1.5917997l-2.1972008-2.1875
C16.5820007-19.2968998,12.1484003-19.2187996,9.2578096-16.3281002z M10.7519999-15.9569998
c2.4316006-1.7774,5.7226-1.4746008,7.9492006,0.7518997l2.4315987,2.4120998
c0.2344017,0.2343998,0.2734013,0.4200001,0.205101,0.7617998l-0.3223,1.4843006L22.5195007-9.0625l0.9863987-0.0585899
C23.7598-9.1308603,23.8379002-9.11133,24.0331993-8.9160204l0.5762005,0.5761805l-2.4414005,2.4414001l-0.5761986-0.57617
c-0.1953011-0.1953101-0.2245998-0.2734404-0.2147999-0.5371103l0.0682983-0.9765596l-1.4940987-1.4843802L18.4277-9.21875
c-0.3222008,0.0683603-0.4687004,0.0390596-0.7129002-0.1953096l-2.0018997-2.0019407
c-0.2539005-0.2343998-0.2832003-0.4003992-0.1269999-0.7714996l0.8788996-2.0897999
c-1.5625-1.4551001-3.5936995-2.080101-5.625-1.4843998C10.6836004-15.7227001,10.625-15.8495998,10.7519999-15.9569998z"/>
</g>
<text transform="matrix(1 0 0 1 1289 1953)" class="st2 st3">Exporting</text>
<text transform="matrix(1 0 0 1 1289 1971)" class="st4 st3">Symbols should be outlined when exporting to ensure the</text>
<text transform="matrix(1 0 0 1 1289 1989)" class="st4 st3">design is preserved when submitting to Xcode.</text>
<text id="template-version" transform="matrix(1 0 0 1 2952.4140625 1933)" class="st4 st3">Template v.4.0</text>
<text transform="matrix(1 0 0 1 2865.4575195 1951)" class="st4 st3">Requires Xcode 14 or greater</text>
<text id="descriptive-name" transform="matrix(1 0 0 1 2826.4448242 1969)" class="st4 st3">Generated from custom.shippingbox</text>
<text transform="matrix(1 0 0 1 2912.4111328 1987)" class="st4 st3">Typeset at 100 points</text>
<text transform="matrix(1 0 0 1 263 726)" class="st4 st3">Small</text>
<text transform="matrix(1 0 0 1 263 1156)" class="st4 st3">Medium</text>
<text transform="matrix(1 0 0 1 263 1586)" class="st4 st3">Large</text>
</g>
<g id="Guides">
<g id="H-reference" transform="matrix(1 0 0 1 339 696)">
<path class="st6" d="M0.993654,0h2.6440959l25.6903496-67.1323013h0.7021999v-3.3266983h-1.9076996L0.993654,0z
M11.6885004-24.4799004h35.2929993l-0.75-2.2486H12.4385004L11.6885004-24.4799004z M55.1195984,0h2.6441002
L30.6382008-70.4589996H29.4326v3.3266983L55.1195984,0z"/>
</g>
<line id="Baseline-S" class="st7" x1="263" y1="696" x2="3036" y2="696"/>
<line id="Capline-S" class="st7" x1="263" y1="625.5410156" x2="3036" y2="625.5410156"/>
<g id="H-reference_1_" transform="matrix(1 0 0 1 339 1126)">
<path class="st6" d="M0.993654,0h2.6440959l25.6903496-67.1323013h0.7021999v-3.3266983h-1.9076996L0.993654,0z
M11.6885004-24.4799004h35.2929993l-0.75-2.2486H12.4385004L11.6885004-24.4799004z M55.1195984,0h2.6441002
L30.6382008-70.4589996H29.4326v3.3266983L55.1195984,0z"/>
</g>
<line id="Baseline-M" class="st7" x1="263" y1="1126" x2="3036" y2="1126"/>
<line id="Capline-M" class="st7" x1="263" y1="1055.5400391" x2="3036" y2="1055.5400391"/>
<g id="H-reference_2_" transform="matrix(1 0 0 1 339 1556)">
<path class="st6" d="M0.993654,0h2.6440959l25.6903496-67.1323013h0.7021999v-3.3266983h-1.9076996L0.993654,0z
M11.6885004-24.4799004h35.2929993l-0.75-2.2486H12.4385004L11.6885004-24.4799004z M55.1195984,0h2.6441002
L30.6382008-70.4589996H29.4326v3.3266983L55.1195984,0z"/>
</g>
<line id="Baseline-L" class="st7" x1="263" y1="1556" x2="3036" y2="1556"/>
<line id="Capline-L" class="st7" x1="263" y1="1485.5400391" x2="3036" y2="1485.5400391"/>
<line id="left-margin-Ultralight-S" class="st5" x1="512.4619751" y1="600.7849731" x2="512.4619751" y2="720.1209717"/>
<line id="right-margin-Ultralight-S" class="st5" x1="606.9609985" y1="600.7849731" x2="606.9609985" y2="720.1209717"/>
<line id="left-margin-Regular-S" class="st5" x1="1401.1899414" y1="600.7849731" x2="1401.1899414" y2="720.1209717"/>
<line id="right-margin-Regular-S" class="st5" x1="1498.5" y1="600.7849731" x2="1498.5" y2="720.1209717"/>
<line id="left-margin-Black-S" class="st5" x1="2883.0100098" y1="600.7849731" x2="2883.0100098" y2="720.1209717"/>
<line id="right-margin-Black-S" class="st5" x1="2983.7900391" y1="600.7849731" x2="2983.7900391" y2="720.1209717"/>
</g>
<g id="Symbols">
<g id="Black-S">
<path d="M2898.9768066,686.625l31.2011719,16.1621094c1.8554688,0.9765625,4.5898438,0.9765625,6.4453125,0L2967.8244629,686.625
c4.4921875-2.343811,6.2011719-5.1757812,6.2011719-10.156189v-34.1309204c0-4.5410156-1.7578125-7.6171875-6.1035156-9.8632812
l-26.0742188-13.6229858c-5.1757812-2.734436-11.71875-2.734436-16.8945312,0l-26.0742188,13.6229858
c-4.3457031,2.2460938-6.1035156,5.3222656-6.1035156,9.8632812v34.1309204
C2892.7756348,681.4492188,2894.4846191,684.281189,2898.9768066,686.625z M2906.5939941,676.6641235
c-1.5136719-0.8301392-2.0996094-1.7579346-2.0996094-3.2715454v-22.9980469l22.7539062,11.8163452v25.4883423
L2906.5939941,676.6641235z M2962.3068848,650.3945312v22.9980469c0,1.5136108-0.5859375,2.4414062-2.0996094,3.2715454
l-20.6542969,11.0350952v-25.4883423l4.2817383-2.2281494v1.9515991c0,3.9360962,3.1765137,7.1125488,7.1125488,7.1125488
c3.9016113-0.0345459,7.0778809-3.1419067,7.0778809-7.0779419v-9.3511353L2962.3068848,650.3945312z M2933.4006348,651.5175781
l-22.1679688-11.5722656l5.0292969-2.5878906l22.3144531,11.4746094L2933.4006348,651.5175781z M2951.1252441,642.2401733
l-22.0703125-11.5722046l1.3671875-0.6835938c1.9042969-0.9765625,4.0039062-0.9765625,5.9570312,0l19.1894531,9.9609375
L2951.1252441,642.2401733z"/>
</g>
<g id="Regular-S">
<path d="M1406.8195801,684.4480591l29.7851562,17.0410767c2.2949219,1.3183594,4.3945312,1.3183594,6.640625,0
l29.7851562-17.0410767c3.7109375-2.1483765,5.8105469-4.1991577,5.8105469-10.3026733v-29.4921875
c0-4.4434204-1.6113281-7.1777344-5.2246094-9.3262329l-26.1230469-14.9901733
c-5.1269531-2.8809204-9.9609375-2.8809204-15.0878906,0l-26.1230469,14.9901733
c-3.6621094,2.1484985-5.2246094,4.8828125-5.2246094,9.3262329v29.4921875
C1401.0578613,680.2489014,1403.1574707,682.2996826,1406.8195801,684.4480591z M1410.5793457,678.6375732
c-2.0996094-1.2695923-2.9296875-2.5390625-2.9296875-4.6875v-27.9296875l28.8574219,16.6992188v30.859375
L1410.5793457,678.6375732z M1472.2492676,646.0203857v27.9296875c0,2.1484375-0.8789062,3.4179077-2.9296875,4.6875
l-25.9277344,14.9414062v-30.859375l10.9072266-6.3255615v9.8839111c0,1.9334717,1.5882568,3.5217285,3.5217285,3.5217285
s3.5217285-1.5882568,3.5217285-3.5217285l-0.0345459-13.9328613L1472.2492676,646.0203857z M1439.9250488,656.6160889
l-28.4179688-16.2598267l10.8398438-6.2987671l28.3691406,16.3573608L1439.9250488,656.6160889z M1457.7473145,646.4110107
l-28.5644531-16.2598267l5.9571533-3.4179077c3.3201904-1.9042969,6.2987061-1.953064,9.5701904,0l23.6816406,13.6229858
L1457.7473145,646.4110107z"/>
</g>
<g id="Ultralight-S">
<path d="M525.7642822,682.3652954l31.465271,17.1317749c1.6592407,0.8643188,3.2139282,0.909729,4.9604492,0
l31.4653931-17.1317749c2.6210938-1.4672852,3.539978-3.0640259,3.539978-5.9434204v-33.8515625
c0-1.6733398-0.9755859-2.8184204-2.4091797-3.6499023l-31.2089233-17.2607422
c-2.4478149-1.3823853-5.2838135-1.3823853-7.7315063,0l-31.2089844,17.2607422
c-1.4370117,0.8314819-2.4091797,1.9765625-2.4091797,3.6499023v33.8515625
C522.2276001,679.3012695,523.1011963,680.8980103,525.7642822,682.3652954z M527.6621704,680.9141235
c-2.6898804-1.4512329-3.065918-2.4937134-3.065918-4.6875v-33.015625l33.9432983,18.4248047v35.8998413L527.6621704,680.9141235z
M578.9451904,651.8189087l15.8814697-8.6079102v33.015625c0,2.1937866-0.3793945,3.2362671-3.065918,4.6875
l-30.9227905,16.621521v-35.8998413l15.8883667-8.6142578l-0.0074463,15.2365112
c0.0320435,0.6169434,0.5285645,1.0493164,1.0813599,1.0812988c0.6491089,0,1.1455688-0.4963379,1.1455688-1.1455078
L578.9451904,651.8189087z M559.6870728,659.7098999l-34.4575195-18.6663818l16.3799438-9.0234985l34.6356812,18.71875
L559.6870728,659.7098999z M578.553772,649.5048828l-34.6494141-18.7572632l13.5405273-7.4595337
c1.4584961-0.8598633,3.074707-0.8632812,4.5297852,0l32.1732788,17.7554321L578.553772,649.5048828z"/>
</g>
</g>
<path d="M2282.9038086,649.5722046"/>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

@@ -1,6 +1,6 @@
import SwiftUI
public func NavigationStackCompat<T>(@ViewBuilder content: () -> T) -> some View where T: View{
public func NavigationStackCompat(@ViewBuilder content: () -> some View) -> some View {
viewBuilder {
if #available(iOS 17.0, *) {
// view not updating in iOS 16, but why?
@@ -4,82 +4,53 @@ import Library
import SwiftUI
public struct ActiveDashboardView: View {
public static let NotificationUpdateSelectedProfile = Notification.Name("update-selected-profile")
@Environment(\.scenePhase) var scenePhase
@Environment(\.selection) private var selection
@Environment(\.selection) private var parentSelection
@EnvironmentObject private var profile: ExtensionProfile
@State private var isLoading = true
@State private var profileList: [Profile] = []
@State private var selectedProfileID: Int64!
@State private var reasserting = false
@State private var observer: Any?
@State private var alert: Alert?
@State private var selection = DashboardPage.overview
public init() {}
public var body: some View {
viewBuilder {
if isLoading {
ProgressView().onAppear {
Task.detached {
await doReload()
}
}
} else {
if profileList.isEmpty {
Text("Empty profiles")
} else {
VStack {
#if os(iOS) || os(tvOS)
if ApplicationLibrary.inPreview || profile.status.isConnected {
ExtensionStatusView()
.listStyle(.automatic)
#if os(iOS)
.navigationBarTitleDisplayMode(.inline)
#endif
}
FormView {
StartStopButton()
Section("Profile") {
Picker(selection: $selectedProfileID) {
ForEach(profileList, id: \.id) { profile in
Text(profile.name).tag(profile.id)
}
} label: {}
.pickerStyle(.inline)
}
}
#elseif os(macOS)
if ApplicationLibrary.inPreview || profile.status.isConnected {
ExtensionStatusView()
}
FormView {
Section("Profile") {
ForEach(profileList, id: \.id) { profile in
Picker(profile.name, selection: $selectedProfileID) {
Text("").tag(profile.id)
}
}
.pickerStyle(.radioGroup)
}
}
#endif
}
.onChangeCompat(of: selectedProfileID) {
reasserting = true
Task.detached {
await switchProfile(selectedProfileID!)
}
}
.disabled(!ApplicationLibrary.inPreview && (!profile.status.isSwitchable || reasserting))
if isLoading {
ProgressView().onAppear {
Task.detached {
await doReload()
}
}
}
.alertBinding($alert)
#if os(iOS) || os(tvOS)
} else {
viewBuilder {
#if os(iOS) || os(tvOS)
if ApplicationLibrary.inPreview || profile.status.isConnectedStrict {
Picker("Page", selection: $selection) {
ForEach(DashboardPage.allCases) { page in
page.label
}
}
.pickerStyle(.segmented)
#if os(iOS)
.padding([.leading, .trailing])
.navigationBarTitleDisplayMode(.inline)
#endif
TabView(selection: $selection) {
ForEach(DashboardPage.allCases) { page in
page.contentView($profileList, $selectedProfileID)
.tag(page)
}
}
.tabViewStyle(.page(indexDisplayMode: .always))
} else {
OverviewView($profileList, $selectedProfileID)
}
#elseif os(macOS)
OverviewView($profileList, $selectedProfileID)
#endif
}
#if os(iOS) || os(tvOS)
.onChangeCompat(of: scenePhase) { newValue in
if newValue == .active {
Task.detached {
@@ -87,29 +58,16 @@ public struct ActiveDashboardView: View {
}
}
}
.onChangeCompat(of: selection.wrappedValue) { newValue in
.onChangeCompat(of: parentSelection.wrappedValue) { newValue in
if newValue == .dashboard {
Task.detached {
await doReload()
}
}
}
#elseif os(macOS)
.onAppear {
if observer == nil {
observer = NotificationCenter.default.addObserver(forName: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { _ in
Task.detached {
await doReload()
}
})
}
}
.onDisappear {
if let observer {
NotificationCenter.default.removeObserver(observer)
}
}
#endif
#endif
.alertBinding($alert)
}
}
private func doReload() {
@@ -143,28 +101,4 @@ public struct ActiveDashboardView: View {
}
}
}
private func switchProfile(_ newProfileID: Int64) {
SharedPreferences.selectedProfileID = newProfileID
NotificationCenter.default.post(name: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil)
if profile.status.isConnected {
do {
try LibboxNewStandaloneCommandClient()!.serviceReload()
} catch {
alert = Alert(error)
}
}
reasserting = false
}
private struct ServiceErrorReporter: View {
private let parent: ActiveDashboardView
init(_ parent: ActiveDashboardView) {
self.parent = parent
}
var body: some View {
EmptyView()
}
}
}
@@ -0,0 +1,43 @@
import Foundation
import Library
import SwiftUI
public enum DashboardPage: Int, CaseIterable, Identifiable {
public var id: Self {
self
}
case overview
case groups
}
public extension DashboardPage {
var title: String {
switch self {
case .overview:
return NSLocalizedString("Overview", comment: "")
case .groups:
return NSLocalizedString("Groups", comment: "")
}
}
var label: some View {
switch self {
case .overview:
return Label("Overview", systemImage: "text.and.command.macwindow")
case .groups:
return Label("Groups", systemImage: "rectangle.3.group.fill")
}
}
func contentView(_ profileList: Binding<[Profile]>, _ selectedProfileID: Binding<Int64?>) -> some View {
viewBuilder {
switch self {
case .overview:
OverviewView(profileList, selectedProfileID)
case .groups:
GroupListView()
}
}
}
}
@@ -40,7 +40,6 @@ public struct DashboardView: View {
}
}
#endif
.navigationTitle("Dashboard")
}
#if os(macOS)
@@ -18,28 +18,50 @@ public struct ExtensionStatusView: View {
VStack {
LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: columnCount), alignment: .leading) {
if ApplicationLibrary.inPreview {
StatusItem("Memory", "6.4 MiB")
StatusItem("Goroutines", "89")
StatusItem("Inbound Connections", "34")
StatusItem("Outbound Connections", "28")
StatusItem("Uplink", "38 B/s")
StatusItem("Downlink", "249 MiB/s")
StatusItem("Uplink Total", "52 MiB")
StatusItem("Downlink Total", "5.6 GiB")
StatusItem("Status") {
StatusLine("Memory", "6.4 MiB")
StatusLine("Goroutines", "89")
}
StatusItem("Connections") {
StatusLine("Inbound", "34")
StatusLine("Outbound", "28")
}
StatusItem("Traffic") {
StatusLine("Uplink", "38 B/s")
StatusLine("Downlink", "249 MiB/s")
}
StatusItem("TrafficTotal") {
StatusLine("Uplink", "52 MiB")
StatusLine("Downlink", "5.6 GiB")
}
} else if let message {
StatusItem("Memory", LibboxFormatBytes(message.memory))
StatusItem("Goroutines", "\(message.goroutines)")
StatusItem("Status") {
StatusLine("Memory", LibboxFormatBytes(message.memory))
StatusLine("Goroutines", "\(message.goroutines)")
}
StatusItem("Connections") {
StatusLine("Inbound", "\(message.connectionsIn)")
StatusLine("Outbound", "\(message.connectionsOut)")
}
if message.trafficAvailable {
StatusItem("Inbound Connections", "\(message.connectionsIn)")
StatusItem("Outbound Connections", "\(message.connectionsOut)")
StatusItem("Uplink", LibboxFormatBytes(message.uplink) + "/s")
StatusItem("Downlink", LibboxFormatBytes(message.downlink) + "/s")
StatusItem("Uplink Total", LibboxFormatBytes(message.uplinkTotal))
StatusItem("Downlink Total", LibboxFormatBytes(message.downlinkTotal))
StatusItem("Traffic") {
StatusLine("Uplink", "\(LibboxFormatBytes(message.uplink))/s")
StatusLine("Downlink", "\(LibboxFormatBytes(message.downlink))/s")
}
StatusItem("TrafficTotal") {
StatusLine("Uplink", LibboxFormatBytes(message.uplinkTotal))
StatusLine("Downlink", LibboxFormatBytes(message.downlinkTotal))
}
}
} else {
StatusItem("Memory", "Loading...")
StatusItem("Goroutines", "Loading...")
StatusItem("Status") {
StatusLine("Memory", "...")
StatusLine("Goroutines", "...")
}
StatusItem("Connections") {
StatusLine("Inbound", "...")
StatusLine("Outbound", "...")
}
}
}.background {
GeometryReader { geometry in
@@ -142,26 +164,25 @@ public struct ExtensionStatusView: View {
func writeGroups(_: LibboxOutboundGroupIteratorProtocol?) {}
}
private struct StatusItem: View {
private let name: String
private let value: String
init(_ name: String, _ value: String) {
self.name = name
self.value = value
private struct StatusItem<T>: View where T: View {
private let title: String
@ViewBuilder private let content: () -> T
init(_ title: String, @ViewBuilder content: @escaping () -> T) {
self.title = title
self.content = content
}
var body: some View {
VStack(alignment: .leading, spacing: 8) {
VStack(alignment: .leading) {
HStack {
Text(name)
.font(.subheadline)
.foregroundColor(.secondary)
Text(title)
.font(.headline)
Spacer()
}
Text(value)
.font(.system(size: 16))
}.padding(.bottom, 8)
content()
}
.frame(minWidth: 125)
.frame(minWidth: 125, alignment: .topLeading)
#if os(tvOS)
.padding(EdgeInsets(top: 20, leading: 26, bottom: 20, trailing: 26))
#else
@@ -181,4 +202,25 @@ public struct ExtensionStatusView: View {
#endif
}
}
private struct StatusLine: View {
private let name: String
private let value: String
init(_ name: String, _ value: String) {
self.name = name
self.value = value
}
var body: some View {
HStack {
Text(name)
.font(.subheadline)
.foregroundColor(.secondary)
Spacer()
Text(value)
.font(.subheadline)
}
}
}
}
@@ -0,0 +1,87 @@
import Foundation
import Libbox
import Library
import SwiftUI
public struct OverviewView: View {
public static let NotificationUpdateSelectedProfile = Notification.Name("update-selected-profile")
@Environment(\.scenePhase) var scenePhase
@Environment(\.selection) private var selection
@EnvironmentObject private var profile: ExtensionProfile
@Binding private var profileList: [Profile]
@Binding private var selectedProfileID: Int64!
@State private var alert: Alert?
@State private var reasserting = false
@State private var observer: Any?
public init(_ profileList: Binding<[Profile]>, _ selectedProfileID: Binding<Int64?>) {
_profileList = profileList
_selectedProfileID = selectedProfileID
}
public var body: some View {
VStack {
if ApplicationLibrary.inPreview || profile.status.isConnected {
ExtensionStatusView()
}
FormView {
#if os(iOS) || os(tvOS)
StartStopButton()
Section("Profile") {
Picker(selection: $selectedProfileID) {
ForEach(profileList, id: \.id) { profile in
Text(profile.name).tag(profile.id)
}
} label: {}
.pickerStyle(.inline)
}
#elseif os(macOS)
Section("Profile") {
ForEach(profileList, id: \.id) { profile in
Picker(profile.name, selection: $selectedProfileID) {
Text("").tag(profile.id)
}
}
.pickerStyle(.radioGroup)
}
#endif
}
}
.alertBinding($alert)
.onChangeCompat(of: selectedProfileID) {
reasserting = true
Task.detached {
await switchProfile(selectedProfileID!)
}
}
.disabled(!ApplicationLibrary.inPreview && (!profile.status.isSwitchable || reasserting))
#if os(macOS)
.onAppear {
if observer == nil {
observer = NotificationCenter.default.addObserver(forName: OverviewView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { newProfileID in
selectedProfileID = newProfileID.object as! Int64
})
}
}
.onDisappear {
if let observer {
NotificationCenter.default.removeObserver(observer)
}
}
#endif
}
private func switchProfile(_ newProfileID: Int64) {
SharedPreferences.selectedProfileID = newProfileID
NotificationCenter.default.post(name: OverviewView.NotificationUpdateSelectedProfile, object: newProfileID)
if profile.status.isConnected {
do {
try LibboxNewStandaloneCommandClient()!.serviceReload()
} catch {
alert = Alert(error)
}
}
reasserting = false
}
}
@@ -17,48 +17,54 @@ public struct GroupItemView: View {
@State private var alert: Alert?
public var body: some View {
HStack {
if group.selected == item.tag {
Rectangle()
.fill(Color.accentColor)
.frame(width: 6)
} else {
Rectangle()
.fill(.clear)
.frame(width: 6)
}
VStack {
HStack {
Text(item.tag)
.truncationMode(.tail)
.lineLimit(1)
.font(.system(size: 14))
Spacer(minLength: 6)
}
Spacer(minLength: 6)
HStack(alignment: .center) {
Text(item.type)
.foregroundColor(.secondary)
.font(.system(size: 12))
Spacer(minLength: 6)
if item.urlTestDelay > 0 {
Text(item.delayString)
.foregroundColor(item.delayColor)
.font(.system(size: 11))
}
}
}
.frame(height: 36)
.padding([.top, .bottom, .trailing], 12)
}
.background(backgroundColor)
.onTapGesture {
Button(action: {
if group.selectable, group.selected != item.tag {
Task.detached {
selectOutbound()
}
}
}
}, label: {
HStack {
VStack {
HStack {
Text(item.tag)
.font(.caption)
.foregroundStyle(.foreground)
.lineLimit(1)
.truncationMode(.tail)
Spacer(minLength: 0)
}
Spacer(minLength: 8)
HStack {
Text(item.type)
.font(.caption)
.foregroundColor(.secondary)
Spacer(minLength: 0)
}
}
Spacer(minLength: 0)
VStack {
if group.selected == item.tag {
Image(systemName: "checkmark.circle.fill")
.foregroundStyle(Color.accentColor)
}
Spacer(minLength: 0)
if item.urlTestDelay > 0 {
Text(item.delayString)
.font(.caption)
.foregroundColor(item.delayColor)
}
}
}
})
#if !os(tvOS)
.buttonStyle(.borderless)
.padding(EdgeInsets(top: 10, leading: 13, bottom: 10, trailing: 13))
.background(backgroundColor)
.cornerRadius(10)
#endif
.alertBinding($alert)
}
@@ -23,7 +23,6 @@ public struct GroupListView: View {
}, set: { newValue in
groupExpand[it.tag] = newValue
}))
Spacer()
}
}.padding()
}
@@ -40,7 +39,6 @@ public struct GroupListView: View {
}
commandClient = nil
}
.navigationTitle("Groups")
}
private func doReload() {
@@ -51,7 +49,7 @@ public struct GroupListView: View {
OutboundGroupItem(tag: "server2", type: "WireGuard", urlTestTime: .now, urlTestDelay: 34),
OutboundGroupItem(tag: "auto", type: "URLTest", urlTestTime: .now, urlTestDelay: 100),
]),
OutboundGroup(tag: "group2", type: "urltest", selected: "client", selectable: false, items:
OutboundGroup(tag: "group2", type: "urltest", selected: "client", selectable: true, items:
(0 ..< 234).map { index in
OutboundGroupItem(tag: "client\(index)", type: "Shadowsocks", urlTestTime: .now, urlTestDelay: UInt16(100 + index * 10))
}),
+23 -13
View File
@@ -15,12 +15,12 @@ public struct GroupView: View {
private var title: some View {
HStack {
Text(group.tag)
.font(.system(size: 17))
.font(.headline)
Text(group.displayType)
.font(.system(size: 13))
.font(.subheadline)
.foregroundColor(.secondary)
Text("\(group.items.count)")
.font(.system(size: 11))
.font(.subheadline)
.padding(EdgeInsets(top: 2, leading: 4, bottom: 2, trailing: 4))
.background(Color.gray.opacity(0.5))
.cornerRadius(4)
@@ -33,7 +33,7 @@ public struct GroupView: View {
Image(systemName: "arrow.up.to.line")
}
}
#if os(macOS)
#if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
Button {
@@ -43,11 +43,10 @@ public struct GroupView: View {
} label: {
Image(systemName: "bolt.fill")
}
#if os(macOS)
#if os(macOS) || os(tvOS)
.buttonStyle(.plain)
#endif
Spacer(minLength: 6)
}
}.padding([.top, .bottom], 8)
}
public var body: some View {
@@ -61,13 +60,17 @@ public struct GroupView: View {
}
}
} else {
VStack {
VStack(spacing: 5) {
ForEach(Array(itemGroups.enumerated()), id: \.offset) { items in
HStack {
HStack(spacing: 5) {
ForEach(items.element, id: \.tag) { it in
Rectangle()
.fill(it.delayColor)
#if !os(tvOS)
.frame(width: 10, height: 10)
#else
.frame(width: 30, height: 30)
#endif
}
}.frame(maxWidth: .infinity, alignment: .topLeading)
}
@@ -93,7 +96,12 @@ public struct GroupView: View {
}
private var itemGroups: [[OutboundGroupItem]] {
let count = Int(Int(geometryWidth) / 20)
let count: Int
#if os(tvOS)
count = Int(Int(geometryWidth) / 40)
#else
count = Int(Int(geometryWidth) / 20)
#endif
if count == 0 {
return [group.items]
} else {
@@ -104,11 +112,13 @@ public struct GroupView: View {
}
private func explandColumnCount() -> Int {
let count = Int(Int(geometryWidth) / 180)
let standardCount = Int(Int(geometryWidth) / 180)
#if os(iOS)
return count < 2 ? 2 : count
return standardCount < 2 ? 2 : standardCount
#elseif os(tvOS)
return Int(Int(geometryWidth) / 400)
#else
return count < 1 ? 1 : count
return standardCount < 1 ? 1 : standardCount
#endif
}
+1 -2
View File
@@ -13,7 +13,6 @@ public struct LogView: View {
Text("Service not started")
}
}
.navigationTitle("Logs")
}
private struct LogView0: View {
@@ -43,7 +42,7 @@ public struct LogView: View {
#if os(tvOS)
.focusable()
#endif
Spacer(minLength: 5)
Spacer(minLength: 8)
}
.onChangeCompat(of: logClient.logList.count) { newCount in
+27 -22
View File
@@ -8,13 +8,19 @@ public enum NavigationPage: Int, CaseIterable, Identifiable {
}
case dashboard
case groups
#if os(macOS)
case groups
#endif
case logs
case profiles
case settings
}
public extension NavigationPage {
static var macosDefaultPages: [NavigationPage] {
[.logs, .profiles, .settings]
}
var label: some View {
Label(title, systemImage: iconImage)
}
@@ -23,8 +29,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
return NSLocalizedString("Dashboard", comment: "")
case .groups:
return NSLocalizedString("Groups", comment: "")
#if os(macOS)
case .groups:
return NSLocalizedString("Groups", comment: "")
#endif
case .logs:
return NSLocalizedString("Logs", comment: "")
case .profiles:
@@ -38,8 +46,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
return "text.and.command.macwindow"
case .groups:
return "rectangle.3.group.fill"
#if os(macOS)
case .groups:
return "rectangle.3.group.fill"
#endif
case .logs:
return "doc.text.fill"
case .profiles:
@@ -54,9 +64,10 @@ public extension NavigationPage {
switch self {
case .dashboard:
DashboardView()
case .groups:
GroupListView()
#if os(macOS)
case .groups:
GroupListView()
#endif
case .logs:
LogView()
case .profiles:
@@ -70,20 +81,14 @@ public extension NavigationPage {
#endif
}
func visible(_ profile: ExtensionProfile?) -> Bool {
switch self {
case .groups:
#if os(tvOS)
// TODO: fix groups ui
return false
#else
if ApplicationLibrary.inPreview {
return true
}
#if os(macOS)
func visible(_ profile: ExtensionProfile?) -> Bool {
switch self {
case .groups:
return profile?.status.isConnectedStrict == true
#endif
default:
return true
default:
return true
}
}
}
#endif
}
@@ -115,7 +115,6 @@ public struct ProfileView: View {
}
}
.disabled(isUpdating)
.navigationTitle("Profiles")
.alertBinding($alert, $isLoading)
.onAppear {
if let profile = importProfile.wrappedValue {
@@ -129,7 +129,6 @@ public struct SettingView: View {
}
}
}
.navigationTitle("Settings")
.alertBinding($alert)
}
+1 -1
View File
@@ -53,7 +53,7 @@ public struct MacApplication: Scene {
MenuBarExtra(isInserted: $showMenuBarExtra) {
MenuView(isMenuPresented: $isMenuPresented)
} label: {
Image(systemName: "network.badge.shield.half.filled")
Image("MenuIcon")
}
.menuBarExtraStyle(.window)
.menuBarExtraAccess(isPresented: $isMenuPresented)
+2 -5
View File
@@ -17,11 +17,7 @@ public struct MainView: View {
public init() {}
public var body: some View {
NavigationSplitView {
VStack {
SidebarView()
}
.frame(minWidth: 150)
SidebarView()
} detail: {
if profileLoading {
ProgressView().onAppear {
@@ -32,6 +28,7 @@ public struct MainView: View {
}
} else {
selection.contentView
.navigationTitle(selection.title)
}
}
#if !DEBUG
+3 -3
View File
@@ -149,8 +149,8 @@ public struct MenuView: View {
}
.onAppear {
if observer == nil {
observer = NotificationCenter.default.addObserver(forName: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { _ in
doReload()
observer = NotificationCenter.default.addObserver(forName: OverviewView.NotificationUpdateSelectedProfile, object: nil, queue: nil, using: { notification in
selectedProfileID = notification.object as! Int64
})
}
}
@@ -188,7 +188,7 @@ public struct MenuView: View {
private func switchProfile(_ newProfileID: Int64) {
SharedPreferences.selectedProfileID = newProfileID
NotificationCenter.default.post(name: ActiveDashboardView.NotificationUpdateSelectedProfile, object: nil)
NotificationCenter.default.post(name: OverviewView.NotificationUpdateSelectedProfile, object: newProfileID)
if profile.status.isConnected {
do {
try LibboxNewStandaloneCommandClient()?.serviceReload()
+23 -7
View File
@@ -8,13 +8,13 @@ public struct SidebarView: View {
public init() {}
public var body: some View {
viewBuilder {
VStack {
if let profile = extensionProfile.wrappedValue {
SidebarView0().environmentObject(profile)
} else {
SidebarView1()
}
}
}.frame(minWidth: 150)
}
struct SidebarView0: View {
@@ -22,11 +22,27 @@ public struct SidebarView: View {
@EnvironmentObject private var extensionProfile: ExtensionProfile
var body: some View {
List(NavigationPage.allCases.filter { it in
it.visible(extensionProfile)
}, selection: selection) { it in
it.label
}.onChangeCompat(of: extensionProfile.status) {
VStack {
if extensionProfile.status.isConnectedStrict {
List(selection: selection) {
Section(NavigationPage.dashboard.title) {
Label("Overview", systemImage: "text.and.command.macwindow").tag(NavigationPage.dashboard)
NavigationPage.groups.label.tag(NavigationPage.groups)
}
Divider()
ForEach(NavigationPage.macosDefaultPages, id: \.self) { it in
it.label
}
}
} else {
List(NavigationPage.allCases.filter { it in
it.visible(extensionProfile)
}, selection: selection) { it in
it.label
}
}
}
.onChangeCompat(of: extensionProfile.status) {
if !selection.wrappedValue.visible(extensionProfile) {
selection.wrappedValue = NavigationPage.dashboard
}
+10 -1
View File
@@ -24,7 +24,16 @@ struct MainView: View {
}
}
} else {
ContentView()
TabView(selection: $selection) {
ForEach(NavigationPage.allCases, id: \.self) { page in
NavigationStackCompat {
page.contentView
.navigationTitle(page.title)
}
.tag(page)
.tabItem { page.label }
}
}
}
}
.alertBinding($alert)
+11 -1
View File
@@ -22,7 +22,17 @@ struct MainView: View {
}
}
} else {
ContentView()
TabView(selection: $selection) {
ForEach(NavigationPage.allCases, id: \.self) { page in
NavigationStackCompat {
page.contentView
.navigationTitle(page.title)
.focusSection()
}
.tag(page)
.tabItem { page.label }
}
}
}
}
.onChangeCompat(of: scenePhase) { newValue in
+14 -14
View File
@@ -9,6 +9,8 @@
/* Begin PBXBuildFile section */
3A017F922A4AB2E4009149FA /* GRDB in Frameworks */ = {isa = PBXBuildFile; productRef = 3A017F912A4AB2E4009149FA /* GRDB */; };
3A096F8F2A4ED3DE00D4A2ED /* Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3A096F862A4ED3DE00D4A2ED /* Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3A0C6D3C2A79D46500A4DF2B /* OverviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */; };
3A0C6D3E2A79D6A600A4DF2B /* DashboardPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */; };
3A1CF2F02A50E5EE000A8289 /* GroupListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2EF2A50E5EE000A8289 /* GroupListView.swift */; };
3A1CF2F22A50E613000A8289 /* OutboundGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F12A50E613000A8289 /* OutboundGroup.swift */; };
3A1CF2F62A50EE9C000A8289 /* GroupView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1CF2F52A50EE9C000A8289 /* GroupView.swift */; };
@@ -72,7 +74,6 @@
3A7E90352A46756300D53052 /* SharedPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7E90342A46756300D53052 /* SharedPreferences.swift */; };
3A7E90382A46778E00D53052 /* BinaryCodable in Frameworks */ = {isa = PBXBuildFile; productRef = 3A7E90372A46778E00D53052 /* BinaryCodable */; };
3A8655142A4FA26600B7181F /* IntentsExtension.appex in Embed ExtensionKit Extensions */ = {isa = PBXBuildFile; fileRef = 3A77016D2A4E6B34008F031F /* IntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3A9108E42A511AE70088B196 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9108E32A511AE70088B196 /* ContentView.swift */; };
3A9144D92A46AE370036E9AD /* ShadredPreferences+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */; };
3A9759202A4EB69C00E4404B /* Library.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; };
3A9759212A4EB69C00E4404B /* Library.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3AEC211D2A459B4700A63465 /* Library.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@@ -81,7 +82,6 @@
3A99B42E2A752ABB0010D4B0 /* NavigationDestinationCompat.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A99B42D2A752ABB0010D4B0 /* NavigationDestinationCompat.swift */; };
3AB1220B2A70FD500087CD55 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB1220A2A70FD500087CD55 /* Alert.swift */; };
3AC03B992A72BF3300B7946F /* Application.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC03B982A72BF3300B7946F /* Application.swift */; };
3AC03B9B2A72BF3300B7946F /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC03B9A2A72BF3300B7946F /* ContentView.swift */; };
3AC03B9D2A72BF3500B7946F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3AC03B9C2A72BF3500B7946F /* Assets.xcassets */; };
3AC194492A50013F00BD8CB9 /* IntentsExtension.appex in Embed ExtensionKit Extensions */ = {isa = PBXBuildFile; fileRef = 3A77016D2A4E6B34008F031F /* IntentsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3AC1944F2A50247300BD8CB9 /* ApplicationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */; };
@@ -413,6 +413,8 @@
3A096F892A4ED3DE00D4A2ED /* ExtensionProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionProvider.swift; sourceTree = "<group>"; };
3A096F8B2A4ED3DE00D4A2ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3A096F8C2A4ED3DE00D4A2ED /* Extension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Extension.entitlements; sourceTree = "<group>"; };
3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverviewView.swift; sourceTree = "<group>"; };
3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPage.swift; sourceTree = "<group>"; };
3A1CF2EF2A50E5EE000A8289 /* GroupListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupListView.swift; sourceTree = "<group>"; };
3A1CF2F12A50E613000A8289 /* OutboundGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutboundGroup.swift; sourceTree = "<group>"; };
3A1CF2F32A50E937000A8289 /* SidebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarView.swift; sourceTree = "<group>"; };
@@ -450,7 +452,6 @@
3A7701802A4E71F5008F031F /* IntentsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IntentsExtension.entitlements; sourceTree = "<group>"; };
3A7E90302A46745A00D53052 /* ViewBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewBuilder.swift; sourceTree = "<group>"; };
3A7E90342A46756300D53052 /* SharedPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedPreferences.swift; sourceTree = "<group>"; };
3A9108E32A511AE70088B196 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
3A9144D82A46AE370036E9AD /* ShadredPreferences+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ShadredPreferences+Database.swift"; sourceTree = "<group>"; };
3A99B4292A7526990010D4B0 /* NavigationStackCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationStackCompat.swift; sourceTree = "<group>"; };
3A99B42B2A75288C0010D4B0 /* ViewCompat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewCompat.swift; sourceTree = "<group>"; };
@@ -465,7 +466,6 @@
3ABA46D22A6A32A100D8366B /* Messages.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Messages.framework; path = Library/Frameworks/Messages.framework; sourceTree = DEVELOPER_DIR; };
3AC03B962A72BF3300B7946F /* sing-box.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sing-box.app"; sourceTree = BUILT_PRODUCTS_DIR; };
3AC03B982A72BF3300B7946F /* Application.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Application.swift; sourceTree = "<group>"; };
3AC03B9A2A72BF3300B7946F /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
3AC03B9C2A72BF3500B7946F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
3AC194512A50303300BD8CB9 /* ApplicationDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApplicationDelegate.swift; sourceTree = "<group>"; };
@@ -707,7 +707,6 @@
children = (
3A4FB1642A73568E007012B9 /* SFT.entitlements */,
3AC03B982A72BF3300B7946F /* Application.swift */,
3AC03B9A2A72BF3300B7946F /* ContentView.swift */,
3AC03B9C2A72BF3500B7946F /* Assets.xcassets */,
3A4FB1652A73574B007012B9 /* Info.plist */,
3A4FB1672A7358C9007012B9 /* ApplicationDelegate.swift */,
@@ -783,7 +782,6 @@
3AEC20F92A459AB500A63465 /* Assets.xcassets */,
3A44BB812A4DC28700E4C9F8 /* MainView.swift */,
3AC1944E2A50247300BD8CB9 /* ApplicationDelegate.swift */,
3A9108E32A511AE70088B196 /* ContentView.swift */,
);
path = SFI;
sourceTree = "<group>";
@@ -925,6 +923,8 @@
3AF342CC2A4AA88C002B34AC /* StartStopButton.swift */,
3ADF8DF32A4AF9B500900CC8 /* DashboardView.swift */,
3AE4D0C02A6E4852009FEA9E /* InstallSystemExtensionButton.swift */,
3A0C6D3B2A79D46500A4DF2B /* OverviewView.swift */,
3A0C6D3D2A79D6A600A4DF2B /* DashboardPage.swift */,
);
path = Dashboard;
sourceTree = "<group>";
@@ -1384,10 +1384,12 @@
3A99B42E2A752ABB0010D4B0 /* NavigationDestinationCompat.swift in Sources */,
3A4EAD332A4FEB7F005435B3 /* LogClient.swift in Sources */,
3AC729F22A76088E00FE8EC1 /* ShareButton.swift in Sources */,
3A0C6D3C2A79D46500A4DF2B /* OverviewView.swift in Sources */,
3A4EAD262A4FEB65005435B3 /* ExtensionStatusView.swift in Sources */,
3A4EAD252A4FEB65005435B3 /* StartStopButton.swift in Sources */,
3A4EAD2B2A4FEB6D005435B3 /* ViewBuilder.swift in Sources */,
3AC5EC082A6417470077AF34 /* DeviceCensorship.swift in Sources */,
3A0C6D3E2A79D6A600A4DF2B /* DashboardPage.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -1406,7 +1408,6 @@
files = (
3A4FB1682A7358C9007012B9 /* ApplicationDelegate.swift in Sources */,
3A4FB16A2A735AC9007012B9 /* MainView.swift in Sources */,
3AC03B9B2A72BF3300B7946F /* ContentView.swift in Sources */,
3AC03B992A72BF3300B7946F /* Application.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -1417,7 +1418,6 @@
files = (
3AC1944F2A50247300BD8CB9 /* ApplicationDelegate.swift in Sources */,
3AEC20F62A459AB400A63465 /* Application.swift in Sources */,
3A9108E42A511AE70088B196 /* ContentView.swift in Sources */,
3A44BB822A4DC28700E4C9F8 /* MainView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -2074,7 +2074,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3.5;
MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2115,7 +2115,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.3.5;
MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2139,7 +2139,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = Z56Z6NYZN2;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2155,7 +2155,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -2178,7 +2178,7 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 14;
CURRENT_PROJECT_VERSION = 21;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = Z56Z6NYZN2;
ENABLE_HARDENED_RUNTIME = YES;
@@ -2194,7 +2194,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 1.3.5;
MARKETING_VERSION = 1.3.6;
OTHER_CODE_SIGN_FLAGS = "";
OTHER_LDFLAGS = "-ld_classic";
PRODUCT_BUNDLE_IDENTIFIER = io.nekohasekai.sfa;
@@ -7,7 +7,7 @@
<key>ApplicationLibrary.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>8</integer>
<integer>2</integer>
</dict>
<key>Associations (Playground) 1.xcscheme</key>
<dict>
@@ -141,7 +141,7 @@
<key>SFT.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>7</integer>
<integer>5</integer>
</dict>
<key>ShareExtension.xcscheme_^#shared#^_</key>
<dict>
@@ -151,7 +151,7 @@
<key>SystemExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>5</integer>
<integer>4</integer>
</dict>
<key>Test.xcscheme_^#shared#^_</key>
<dict>