diff options
Diffstat (limited to 'iosApp/iosApp')
28 files changed, 854 insertions, 58 deletions
diff --git a/iosApp/iosApp/Assets.xcassets/Angle0.imageset/0 2.svg b/iosApp/iosApp/Assets.xcassets/Angle0.imageset/0 2.svg new file mode 100644 index 0000000..efe814f --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle0.imageset/0 2.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="0.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="15.12" + inkscape:cx="13.85582" + inkscape:cy="17.195767" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(90,3.1749477,3.17515)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 5.8618164,3.1756595 2.9355056,1.4857149 V 2.5830814 L 0.24432832,2.5826243 c 0,0 -2e-8,0.395052 -2e-8,0.592578 0,0.1972212 0,0.5916636 0,0.5916636 l 2.6911773,4.572e-4 v 1.0973665 z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle0.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle0.imageset/Contents.json new file mode 100644 index 0000000..be69468 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle0.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "0 2.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle135.imageset/135.svg b/iosApp/iosApp/Assets.xcassets/Angle135.imageset/135.svg new file mode 100644 index 0000000..a7c625b --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle135.imageset/135.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="135.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="21.382909" + inkscape:cx="8.6283863" + inkscape:cy="10.896553" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(-45,3.175293,3.1743164)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 1.2760955,1.2748867 2.1503383,4.5390721 2.9262936,3.7631168 4.82892,5.6663897 c 0,0 0.279344,-0.279344 0.419016,-0.4190159 C 5.3873924,5.1079173 5.6663053,4.8290044 5.6663053,4.8290044 L 3.763679,2.9257315 4.5396343,2.1497762 Z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle135.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle135.imageset/Contents.json new file mode 100644 index 0000000..1e01d4c --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle135.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "135.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle180.imageset/180.svg b/iosApp/iosApp/Assets.xcassets/Angle180.imageset/180.svg new file mode 100644 index 0000000..4df8b75 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle180.imageset/180.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="180.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="21.382909" + inkscape:cx="8.6283863" + inkscape:cy="10.896553" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(-90,3.17515,3.1746617)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 0.4887696,3.1743545 3.4150803,4.8642991 V 3.7669326 l 2.6911772,4.571e-4 c 0,0 0,-0.395052 0,-0.592578 0,-0.1972212 0,-0.5916636 0,-0.5916636 L 3.4150803,2.5826909 V 1.4853244 Z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle180.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle180.imageset/Contents.json new file mode 100644 index 0000000..cca2175 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle180.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "180.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle225.imageset/225.svg b/iosApp/iosApp/Assets.xcassets/Angle225.imageset/225.svg new file mode 100644 index 0000000..35d4080 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle225.imageset/225.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="225.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="21.382909" + inkscape:cx="8.6283863" + inkscape:cy="10.896553" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(-135,3.175579,3.175007)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 1.2758633,5.074895 4.5400487,4.2006522 3.7640934,3.4246969 5.6673663,1.5220705 c 0,0 -0.279344,-0.279344 -0.4190159,-0.419016 C 5.1088939,0.96359809 4.829981,0.68468519 4.829981,0.68468519 L 2.9267081,2.5873115 2.1507528,1.8113562 Z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle225.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle225.imageset/Contents.json new file mode 100644 index 0000000..1b49b8a --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle225.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "225.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle270.imageset/270.svg b/iosApp/iosApp/Assets.xcassets/Angle270.imageset/270.svg new file mode 100644 index 0000000..23562a0 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle270.imageset/270.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="270.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="21.382909" + inkscape:cx="8.6283863" + inkscape:cy="10.896553" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(-180,3.1756382,3.17515)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="m 3.1758193,5.8620185 1.6899446,-2.9263106 -1.0973665,0 4.571e-4,-2.6911772 c 0,0 -0.395052,0 -0.592578,-7e-8 -0.1972212,7e-8 -0.5916636,7e-8 -0.5916636,7e-8 l -4.572e-4,2.6911771 -1.0973665,0 z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle270.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle270.imageset/Contents.json new file mode 100644 index 0000000..9eab5a3 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle270.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "270.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle315.imageset/315.svg b/iosApp/iosApp/Assets.xcassets/Angle315.imageset/315.svg new file mode 100644 index 0000000..a501605 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle315.imageset/315.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="315.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="21.382909" + inkscape:cx="8.6283863" + inkscape:cy="11.972178" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(135,3.1754952,3.1754952)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 5.0756692,5.0756154 4.2014264,1.81143 3.4254711,2.5873853 1.5228447,0.68411246 c 0,0 -0.279344,0.27934395 -0.419016,0.41901584 C 0.96437228,1.2425848 0.68545938,1.5214977 0.68545938,1.5214977 L 2.5880857,3.4247706 1.8121304,4.2007259 Z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle315.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle315.imageset/Contents.json new file mode 100644 index 0000000..fed8257 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle315.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "315.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle45.imageset/45.svg b/iosApp/iosApp/Assets.xcassets/Angle45.imageset/45.svg new file mode 100644 index 0000000..1ce060e --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle45.imageset/45.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + sodipodi:docname="45.svg" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="15.12" + inkscape:cx="13.062169" + inkscape:cy="10.780423" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012;stroke-dasharray:none" + transform="rotate(45,3.1743164,3.1743164)"> + <path + style="color:#000000;fill:#008000;stroke-width:1.00012;stroke-linecap:square;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 5.0744368,1.2758094 1.8102513,2.1500524 2.5862066,2.9260077 0.80607031,4.7066972 1.2250863,5.1257132 1.6434556,5.5440825 3.4235919,3.7633929 4.1995472,4.5393483 Z" + sodipodi:nodetypes="ccccccccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle45.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle45.imageset/Contents.json new file mode 100644 index 0000000..a785b47 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle45.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "45.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Assets.xcassets/Angle90.imageset/90.svg b/iosApp/iosApp/Assets.xcassets/Angle90.imageset/90.svg new file mode 100644 index 0000000..de994b5 --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle90.imageset/90.svg @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + width="24" + height="24" + viewBox="0 0 6.3499999 6.35" + version="1.1" + id="svg1" + inkscape:version="1.3 (0e150ed6c4, 2023-07-21)" + sodipodi:docname="90.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <sodipodi:namedview + id="namedview1" + pagecolor="#ffffff" + bordercolor="#000000" + borderopacity="0.25" + inkscape:showpageshadow="2" + inkscape:pageopacity="0.0" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" + inkscape:document-units="px" + inkscape:zoom="15.12" + inkscape:cx="17.956349" + inkscape:cy="11.177249" + inkscape:window-width="1920" + inkscape:window-height="1008" + inkscape:window-x="0" + inkscape:window-y="0" + inkscape:window-maximized="1" + inkscape:current-layer="layer1" /> + <defs + id="defs1" /> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1"> + <g + id="path1" + style="stroke-width:1.00012499;stroke-dasharray:none"> + <path + style="color:#000000;fill:#008000;stroke-linecap:square;stroke-width:1.00012499;stroke-dasharray:none" + d="M 6.1057692,3.175 A 2.9307692,2.9307692 0 0 1 3.175,6.1057692 2.9307692,2.9307692 0 0 1 0.24423075,3.175 2.9307692,2.9307692 0 0 1 3.175,0.24423075 2.9307692,2.9307692 0 0 1 6.1057692,3.175 Z" + id="path6" /> + <path + style="color:#000000;fill:#1a1a1a;stroke-linecap:square;stroke-width:0;stroke-dasharray:none" + d="M 3.1757813,0 C 1.4251716,0 0,1.4251716 0,3.1757813 c 0,1.7506096 1.4251716,3.1738281 3.1757813,3.1738281 1.7506096,0 3.1738281,-1.4232185 3.1738281,-3.1738281 C 6.3496094,1.4251716 4.9263909,0 3.1757813,0 Z m 0,0.48828125 c 1.4866254,0 2.6855468,1.20087455 2.6855468,2.68750005 0,1.4866254 -1.1989214,2.6855468 -2.6855468,2.6855468 -1.4866255,0 -2.68750005,-1.1989214 -2.68750005,-2.6855468 0,-1.4866255 1.20087455,-2.68750005 2.68750005,-2.68750005 z" + id="path7" /> + </g> + <path + id="path5" + style="fill:#1a1a1a;fill-opacity:1;stroke:#1a1a1a;stroke-width:0;stroke-linecap:square;stroke-dasharray:none" + d="M 3.1754573,0.48828127 1.4855127,3.414592 H 2.5828792 V 5.9667127 H 3.1754573 3.7671208 V 3.414592 h 1.0973665 z" + sodipodi:nodetypes="ccccscccc" /> + </g> +</svg> diff --git a/iosApp/iosApp/Assets.xcassets/Angle90.imageset/Contents.json b/iosApp/iosApp/Assets.xcassets/Angle90.imageset/Contents.json new file mode 100644 index 0000000..c84e36d --- /dev/null +++ b/iosApp/iosApp/Assets.xcassets/Angle90.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "90.svg", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift index 7e2ba81..4e0d39e 100644 --- a/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift +++ b/iosApp/iosApp/Details/Reports/UnitReportsViewModel.swift @@ -19,6 +19,7 @@ import Foundation import Combine import shared +@MainActor class UnitReportsViewModel: ObservableObject { @Inject var reportController: ReportController @Inject var geofencesController: GeofencesController @@ -38,25 +39,27 @@ class UnitReportsViewModel: ObservableObject { } @Published var periodType: ReportDates.PeriodTypes = .today { didSet { - switch periodType { - case .today: - reportPeriod = ReportDates.ReportPeriodToday() - case .last24: - reportPeriod = ReportDates.ReportPeriodLast24() - case .yesterday: - reportPeriod = ReportDates.ReportPeriodYesterday() - case .thisWeek: - reportPeriod = ReportDates.ReportPeriodThisWeek() - case .last7: - reportPeriod = ReportDates.ReportPeriodLast7() - case .thisMonth: - reportPeriod = ReportDates.ReportPeriodThisMonth() - case .last30: - reportPeriod = ReportDates.ReportPeriodLast30() - case .custom: - reportPeriod = ReportDates.ReportPeriodCustom(from: nil, to: nil) - default: - reportPeriod = ReportDates.ReportPeriodToday() + Task { @MainActor in + switch periodType { + case .today: + reportPeriod = ReportDates.ReportPeriodToday() + case .last24: + reportPeriod = ReportDates.ReportPeriodLast24() + case .yesterday: + reportPeriod = ReportDates.ReportPeriodYesterday() + case .thisWeek: + reportPeriod = ReportDates.ReportPeriodThisWeek() + case .last7: + reportPeriod = ReportDates.ReportPeriodLast7() + case .thisMonth: + reportPeriod = ReportDates.ReportPeriodThisMonth() + case .last30: + reportPeriod = ReportDates.ReportPeriodLast30() + case .custom: + reportPeriod = ReportDates.ReportPeriodCustom(from: nil, to: nil) + default: + reportPeriod = ReportDates.ReportPeriodToday() + } } } } @@ -136,11 +139,15 @@ class UnitReportsViewModel: ObservableObject { } func setReport (report: ReportController.Report) { - self.report = report + Task { @MainActor in + self.report = report + } } private func setGeofences(geofences: [Int: Geofence]) { - self.geofences = geofences + Task { @MainActor in + self.geofences = geofences + } } func fetchReport(xlsx: Bool = false) { diff --git a/iosApp/iosApp/Map/MapViewController.swift b/iosApp/iosApp/Map/MapViewController.swift index c7bc91d..f424389 100644 --- a/iosApp/iosApp/Map/MapViewController.swift +++ b/iosApp/iosApp/Map/MapViewController.swift @@ -224,14 +224,14 @@ class OurMaplyViewController: MaplyViewController { Float(marker.latitude)) } - let fontSize = 11.0 + let fontSize = Constants.markerLabelTextSize let colorReport = UIColor(red: 0.0, green: 0.5, blue: 0.0, alpha: 1.0) let colorLabel = UIColor.darkGray let colorLabelOutline = UIColor.white let vectorDesc: [AnyHashable : Any] = [ kMaplyColor: colorReport, - kMaplyVecWidth: 12.0, + kMaplyVecWidth: Constants.reportLineWidth, kMaplyWideVecImpl: kMaplyWideVecImplPerf ] @@ -248,26 +248,26 @@ class OurMaplyViewController: MaplyViewController { screenMarker.layoutImportance = .greatestFiniteMagnitude screenMarker.loc = MaplyCoordinateMakeWithDegrees(Float(marker.longitude), Float(marker.latitude)) - var type: Marker.Type_ = .default_ + var image: UIImage if isReport { // For reports, position, start and end icons must be different switch i { - case markers.startIndex: type = .reportStart - case markers.endIndex - 1: type = .reportEnd - default: type = .reportPosition + case markers.startIndex: image = getIcon(markerType: .reportStart) + case markers.endIndex - 1: image = getIcon(markerType: .reportEnd) + default: image = getIcon(forDirection: points[i], to: points[i + 1]) } } else { - type = marker.type + image = getIcon(markerType: marker.type) } - screenMarker.image = getIcon(markerType: type) + screenMarker.image = image - var size = 50.0 + var size = Constants.markerSize if isReport { // For reports, position, start and end sizes must be different switch i { - case markers.startIndex: size = 40.0 - case markers.endIndex - 1: size = 40.0 - default: size = 22.0 + case markers.startIndex: size = Constants.markerSize + case markers.endIndex - 1: size = Constants.markerSize + default: size = Constants.vertexsize } } screenMarker.size = CGSize(width: size, height: size) @@ -311,14 +311,14 @@ class OurMaplyViewController: MaplyViewController { "features": [ [ "type": "Feature", - "properties": [], + "properties": [] as [Any], "geometry": [ "type": "LineString", "coordinates": markers.map({ marker in [marker.longitude, marker.latitude] }) - ] - ] + ] as [String : Any] + ] as [String : Any] ] ] if let vector = MaplyVectorObject(fromGeoJSONDictionary: geoJSON) { @@ -342,14 +342,14 @@ class OurMaplyViewController: MaplyViewController { func display(geofences: [Geofence]) { clear(geofences: true) - let fontSize = 11.0 + let fontSize = Constants.geofenceLabelTextSize let colorFill = UIColor(red: 0.10, green: 0.46, blue: 0.82, alpha: 1.00) let colorLabel = UIColor(red: 0.10, green: 0.46, blue: 0.82, alpha: 1.00) let colorLabelOutline = UIColor.white let vectorDesc: [AnyHashable : Any] = [ kMaplyColor: colorFill, - kMaplyVecWidth: 12.0, + kMaplyVecWidth: Constants.geofenceLineWidth, kMaplyWideVecImpl: kMaplyWideVecImplPerf ] @@ -375,7 +375,7 @@ class OurMaplyViewController: MaplyViewController { "features": [ [ "type": "Feature", - "properties": [], + "properties": [] as [Any], "geometry": [ "type": "Polygon", "coordinates": [ @@ -383,8 +383,8 @@ class OurMaplyViewController: MaplyViewController { [coordinate.y, coordinate.x] } ] - ] - ] + ] as [String : Any] + ] as [String : Any] ] ] if let vector = MaplyVectorObject(fromGeoJSONDictionary: geoJSON) { @@ -439,4 +439,12 @@ class OurMaplyViewController: MaplyViewController { return UIImage(named: MarkerTransformations .markerTypeToImageName(markerType: markerType))! } + + private func getIcon(forDirection a: MaplyCoordinate, to b: MaplyCoordinate) -> UIImage { + let vectorX = b.x - a.x + let vectorY = b.y - a.y + let angleRad = atan2(vectorY, vectorX) + return UIImage(named: MarkerTransformations + .angleToImageName(rad: angleRad))! + } } diff --git a/iosApp/iosApp/Map/UnitMapView.swift b/iosApp/iosApp/Map/UnitMapView.swift index 5a1e2f0..8444e36 100644 --- a/iosApp/iosApp/Map/UnitMapView.swift +++ b/iosApp/iosApp/Map/UnitMapView.swift @@ -27,7 +27,9 @@ struct UnitMapView: View { markers: $unitsViewModel.markers, geofences: $unitsViewModel.flatGeofences, selected: $unitsViewModel.selectedMarker, - markerCallback: unitsViewModel.selectUnitWith) + markerCallback: { p1, p2 in + unitsViewModel.selectUnitWith(position: p1, switchToMap: p2) + }) if let unit = unitsViewModel.selectedUnit { VStack { DeviceRow(unit: unit, callback: { action in diff --git a/iosApp/iosApp/Session/RootView.swift b/iosApp/iosApp/Session/RootView.swift index 960187a..10498b2 100644 --- a/iosApp/iosApp/Session/RootView.swift +++ b/iosApp/iosApp/Session/RootView.swift @@ -35,16 +35,34 @@ struct RootView: View { var body: some View { Group { - switch rootViewModel.loginState { - case is SessionController.LoginStateLoading: - LoadingView() - case is SessionController.LoginStateSuccess: - UnitsView() - default: - LoginContentView(username: $username, - password: $password, - server: $server, - onLogin: rootViewModel.login) + VStack { + if (rootViewModel.networkAvailable != true) { + OfflineBanner() + } + + if rootViewModel.showLoadingView { + LoadingView() + .frame(minHeight: 0, maxHeight: .infinity) + } else { + switch rootViewModel.loginState { + case is SessionController.LoginStateSuccess: + UnitsView() + case is SessionController.LoginStateLoading: + LoadingView() + .frame(minHeight: 0, maxHeight: .infinity) + default: + LoginContentView(username: $username, + password: $password, + server: $server, + onLogin: { username, password, server in + rootViewModel.login( + username: username, + password: password, + url: server + ) + }) + } + } } }.environmentObject(rootViewModel) } diff --git a/iosApp/iosApp/Session/RootViewModel.swift b/iosApp/iosApp/Session/RootViewModel.swift index ec103ba..16f21f3 100644 --- a/iosApp/iosApp/Session/RootViewModel.swift +++ b/iosApp/iosApp/Session/RootViewModel.swift @@ -20,14 +20,42 @@ import shared @MainActor class RootViewModel: ObservableObject { + @Inject private var networkController: NetworkController @Inject private var sessionController: SessionController + @Published var networkAvailable: Bool? = nil @Published var loginState: SessionController.LoginState = SessionController.LoginStateNothing() + @Published var showLoadingView: Bool = false + + var hasSession: Bool{ + get { return sessionController.hasSession } + } init() { - let collector = Collector<SessionController.LoginState?>(callback: setLoginState) - sessionController.loginStateFlow.collect(collector: collector) { _ in } - restoreSession() + let networkCollector = Collector<Bool?>(callback: setNetworkState) + networkController.networkAvailable.collect(collector: networkCollector) { _ in } + let sessionCollector = Collector<SessionController.LoginState?>(callback: setLoginState) + sessionController.loginStateFlow.collect(collector: sessionCollector) { _ in } + } + + func setNetworkState(state: Bool?) { + print("Network state is: \(state?.description ?? "")") + Task { @MainActor in + self.networkAvailable = state + + // Wait for internet to restore session + if (state == true && sessionController.hasSession) { + showLoadingView = false + restoreSession() + return + } + + if (state == nil) { + showLoadingView = true + } else { + showLoadingView = hasSession + } + } } func setLoginState(state: SessionController.LoginState?) { @@ -38,7 +66,7 @@ class RootViewModel: ObservableObject { } func restoreSession() { - sessionController.restoreSession() + sessionController.getSession() } private func getFcmToken() -> String? { diff --git a/iosApp/iosApp/Shared/Constants.swift b/iosApp/iosApp/Shared/Constants.swift new file mode 100644 index 0000000..de82b0b --- /dev/null +++ b/iosApp/iosApp/Shared/Constants.swift @@ -0,0 +1,19 @@ +// +// Constants.swift +// iosApp +// +// Created by Ivan Avalos on 21/09/23. +// Copyright © 2023 orgName. All rights reserved. +// + +import Foundation +import UIKit + +struct Constants { + static var markerSize = 14.0 * UIScreen.main.scale + static var vertexsize = 8.0 * UIScreen.main.scale + static var markerLabelTextSize = UIFont.smallSystemFontSize + static var geofenceLabelTextSize = UIFont.smallSystemFontSize + static var geofenceLineWidth = 4.0 * UIScreen.main.scale + static var reportLineWidth = 4.0 * UIScreen.main.scale +} diff --git a/iosApp/iosApp/Shared/MarkerTransformations.swift b/iosApp/iosApp/Shared/MarkerTransformations.swift index 7291a58..57aa36e 100644 --- a/iosApp/iosApp/Shared/MarkerTransformations.swift +++ b/iosApp/iosApp/Shared/MarkerTransformations.swift @@ -51,4 +51,23 @@ class MarkerTransformations { } return imageName } + + static let STEP = Float.pi / 8 + + static func angleToImageName(rad: Float) -> String { + var imageName: String + switch rad { + case 0.0 ..< STEP: imageName = "Angle0" + case STEP ..< STEP * 3: imageName = "Angle45" + case STEP * 3 ..< STEP * 5: imageName = "Angle90" + case STEP * 5 ..< STEP * 7: imageName = "Angle135" + case STEP * 7 ..< STEP * 9: imageName = "Angle180" + case STEP * 9 ..< STEP * 11: imageName = "Angle225" + case STEP * 11 ..< STEP * 13: imageName = "Angle270" + case STEP * 13 ..< STEP * 15: imageName = "Angle315" + case STEP * 15 ..< STEP * 16: imageName = "Angle0" + default: imageName = angleToImageName(rad: Float.pi * 2 + rad) + } + return imageName + } } diff --git a/iosApp/iosApp/Shared/OfflineBanner.swift b/iosApp/iosApp/Shared/OfflineBanner.swift new file mode 100644 index 0000000..f29ab7d --- /dev/null +++ b/iosApp/iosApp/Shared/OfflineBanner.swift @@ -0,0 +1,27 @@ +// +// OfflineBanner.swift +// iosApp +// +// Created by Ivan Avalos on 17/09/23. +// Copyright © 2023 orgName. All rights reserved. +// + +import SwiftUI + +struct OfflineBanner: View { + var body: some View { + Group { + Text("offline") + .foregroundColor(.white) + .padding(5) + } + .frame(minWidth: 0, maxWidth: .infinity) + .background(Color.red) + } +} + +struct OfflineBanner_Previews: PreviewProvider { + static var previews: some View { + OfflineBanner() + } +} diff --git a/iosApp/iosApp/Units/UnitsViewModel.swift b/iosApp/iosApp/Units/UnitsViewModel.swift index 7fcc80e..52e0c39 100644 --- a/iosApp/iosApp/Units/UnitsViewModel.swift +++ b/iosApp/iosApp/Units/UnitsViewModel.swift @@ -21,6 +21,7 @@ import shared @MainActor class UnitsViewModel: ObservableObject { + @Inject var networkController: NetworkController @Inject var unitsController: UnitsController @Inject var geofenceController: GeofencesController @@ -34,6 +35,7 @@ class UnitsViewModel: ObservableObject { var detailsUnit: UnitInformation? = nil var detailsAction = DeviceRow.Action.details + @Published var networkAvailable: Bool? = nil @Published var searchQuery = "" { didSet { unitsDisplayMode = .list @@ -83,6 +85,9 @@ class UnitsViewModel: ObservableObject { } private func setupObservers() { + let networkCollector = Collector<Bool?>(callback: setNetworkState) + networkController.networkAvailable.collect(collector: networkCollector) { _ in } + let unitsCollector = Collector<[UnitInformation]>(callback: setUnits) unitsController.displayedUnitsFlow.collect(collector: unitsCollector) { _ in } @@ -90,12 +95,19 @@ class UnitsViewModel: ObservableObject { geofenceController.geofencesFlow.collect(collector: geofencesCollector) { _ in } } + private func setNetworkState(state: Bool?) { + print("Network state is: \(state?.description ?? "")") + Task { @MainActor in + self.networkAvailable = state + } + } + private func setUnits(units: [UnitInformation]) { print("Positions") Task { @MainActor in self.units = units + updateSelectedUnit() } - updateSelectedUnit() } private func setGeofences(geofences: [Int: Geofence]) { diff --git a/iosApp/iosApp/en.lproj/Localizable.strings b/iosApp/iosApp/en.lproj/Localizable.strings index 0959a1f..58d1ba5 100644 --- a/iosApp/iosApp/en.lproj/Localizable.strings +++ b/iosApp/iosApp/en.lproj/Localizable.strings @@ -22,6 +22,7 @@ "loading" = "Loading"; "done" = "Done"; +"offline" = "No internet access"; "username" = "Username"; "password" = "Password"; diff --git a/iosApp/iosApp/es-419.lproj/Localizable.strings b/iosApp/iosApp/es-419.lproj/Localizable.strings index 52267cc..8fc5d45 100644 --- a/iosApp/iosApp/es-419.lproj/Localizable.strings +++ b/iosApp/iosApp/es-419.lproj/Localizable.strings @@ -22,6 +22,7 @@ "loading" = "Cargando"; "done" = "Hecho"; +"offline" = "No hay acceso a internet"; "username" = "Usuario"; "password" = "Contraseña"; diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift index 763e0e2..46848ae 100644 --- a/iosApp/iosApp/iOSApp.swift +++ b/iosApp/iosApp/iOSApp.swift @@ -53,8 +53,15 @@ struct iOSApp: App { Resolver.shared.add(CommandsApi.self) { resolver in return CommandsApi(sessionManager: resolver.resolve()) } + Resolver.shared.add(NetworkController.self) { resolver in + return NetworkController() + } Resolver.shared.add(SessionController.self) { resolver in - return SessionController(sessionApi: resolver.resolve(), usersApi: resolver.resolve()) + return SessionController( + sessionManager: resolver.resolve(), + sessionApi: resolver.resolve(), + usersApi: resolver.resolve() + ) } Resolver.shared.add(UnitsController.self) { resolver in return UnitsController(devicesApi: resolver.resolve(), positionsApi: resolver.resolve()) |