paradigm shift
This commit is contained in:
@@ -37,8 +37,8 @@ android {
|
|||||||
applicationId "com.imbenji.bus_infotainment"
|
applicationId "com.imbenji.bus_infotainment"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
||||||
minSdkVersion flutter.minSdkVersion
|
minSdkVersion 21
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdkVersion 33
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
multiDexEnabled = true
|
multiDexEnabled = true
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
android:resource="@style/NormalTheme"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
@@ -32,6 +34,9 @@
|
|||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.mlkit.vision.DEPENDENCIES"
|
||||||
|
android:value="barcode_ui"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
5,"Upton Park, Boleyn",51.5305005,0.0384915
|
5,"Upton Park, Boleyn",51.5305005,0.0384915
|
||||||
5,"Plaistow, Balaam Street",51.5226426,0.0223686
|
5,"Plaistow, Balaam Street",51.5226426,0.0223686
|
||||||
5,"Canning Town, Barking Road",51.53044569999999,0.038323
|
5,"Canning Town, Barking Road",51.53044569999999,0.038323
|
||||||
5,Canning Town,51.5189494,0.0132
|
5,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
6,"Willesden, Bus Garage",51.5474482,-0.2394372
|
6,"Willesden, Bus Garage",51.5474482,-0.2394372
|
||||||
6,Kensal Rise,51.5345071,-0.2250186
|
6,Kensal Rise,51.5345071,-0.2250186
|
||||||
6,Queen's Park,51.5345448,-0.2043853
|
6,Queen's Park,51.5345448,-0.2043853
|
||||||
@@ -216,8 +216,8 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
20,Whipps Cross,51.581499,0.0001219
|
20,Whipps Cross,51.581499,0.0001219
|
||||||
20,Woodford Green,51.6092549,0.0405521
|
20,Woodford Green,51.6092549,0.0405521
|
||||||
20,Woodford Wells,51.6148287,0.0282889
|
20,Woodford Wells,51.6148287,0.0282889
|
||||||
20,Loughton,51.655942,0.068161
|
20,Loughton,51.64195093723499, 0.05498357119784937
|
||||||
20,Debden,51.6042352,0.04159529999999999
|
20,Debden,51.645776846753535, 0.08200009471482733
|
||||||
21,"Lewisham, Shopping Centre",51.46115090000001,-0.0073177
|
21,"Lewisham, Shopping Centre",51.46115090000001,-0.0073177
|
||||||
21,"Lewisham, Jerrard Street",51.4650045,-0.0164722
|
21,"Lewisham, Jerrard Street",51.4650045,-0.0164722
|
||||||
21,New Cross Gate,51.4749904,-0.0403466
|
21,New Cross Gate,51.4749904,-0.0403466
|
||||||
@@ -719,7 +719,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
69,Stratford,51.5426313,-0.0010369
|
69,Stratford,51.5426313,-0.0010369
|
||||||
69,Plaistow,51.5268317,0.0308143
|
69,Plaistow,51.5268317,0.0308143
|
||||||
69,"Canning Town, Hermit Road",51.5209368,0.0125057
|
69,"Canning Town, Hermit Road",51.5209368,0.0125057
|
||||||
69,Canning Town,51.5189494,0.0132
|
69,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
70,"Chiswick, Business Park",51.4930604,-0.2748696
|
70,"Chiswick, Business Park",51.4930604,-0.2748696
|
||||||
70,"Acton, High Street",51.5068505,-0.2673267
|
70,"Acton, High Street",51.5068505,-0.2673267
|
||||||
70,East Acton Lane,51.5123715,-0.2543317
|
70,East Acton Lane,51.5123715,-0.2543317
|
||||||
@@ -1066,7 +1066,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
108,Stratford International Bus Station,51.5453665,-0.0099022
|
108,Stratford International Bus Station,51.5453665,-0.0099022
|
||||||
108,Bow Church,51.5287753,-0.0167013
|
108,Bow Church,51.5287753,-0.0167013
|
||||||
108,"Poplar, All Saints",51.5105521,-0.0118612
|
108,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
108,Canning Town,51.5189494,0.0132
|
108,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
108,North Greenwich,51.4859576,0.007494900000000001
|
108,North Greenwich,51.4859576,0.007494900000000001
|
||||||
108,East Greenwich,51.4309209,-0.0936496
|
108,East Greenwich,51.4309209,-0.0936496
|
||||||
108,"Blackheath, Royal Standard",51.4779946,0.0202001
|
108,"Blackheath, Royal Standard",51.4779946,0.0202001
|
||||||
@@ -1128,7 +1128,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
115,"Upton Park, Boleyn",51.5305005,0.0384915
|
115,"Upton Park, Boleyn",51.5305005,0.0384915
|
||||||
115,"Plaistow, Balaam street",51.5260131,0.0238468
|
115,"Plaistow, Balaam street",51.5260131,0.0238468
|
||||||
115,"Canning Town, Barking Road",51.5175196,0.0115068
|
115,"Canning Town, Barking Road",51.5175196,0.0115068
|
||||||
115,Canning Town,51.5189494,0.0132
|
115,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
115,"Poplar, All Saints",51.5105521,-0.0118612
|
115,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
115,"Limehouse, Burdett Road",51.5209123,-0.0327503
|
115,"Limehouse, Burdett Road",51.5209123,-0.0327503
|
||||||
115,"Stepney, Arbour Square",51.5140186,-0.0481747
|
115,"Stepney, Arbour Square",51.5140186,-0.0481747
|
||||||
@@ -1412,7 +1412,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
147,"East Ham, Newham Town Hall",51.53280239999999,0.0551608
|
147,"East Ham, Newham Town Hall",51.53280239999999,0.0551608
|
||||||
147,"Upton Park, Boleyn",51.5305005,0.0384915
|
147,"Upton Park, Boleyn",51.5305005,0.0384915
|
||||||
147,Prince Regent,51.5178274,0.0321034
|
147,Prince Regent,51.5178274,0.0321034
|
||||||
147,Canning Town,51.5189494,0.0132
|
147,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
148,Camberwell Green,51.4756016,-0.0928896
|
148,Camberwell Green,51.4756016,-0.0928896
|
||||||
148,Elephant & Castle,51.4938058,-0.0977932
|
148,Elephant & Castle,51.4938058,-0.0977932
|
||||||
148,Parliament Square,51.5010421,-0.1268514
|
148,Parliament Square,51.5010421,-0.1268514
|
||||||
@@ -1580,7 +1580,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
167,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999
|
167,"Barkingside, Fullwell Cross",51.59451199999999,0.08571999999999999
|
||||||
167,Gants Hill,51.5767812,0.0661732
|
167,Gants Hill,51.5767812,0.0661732
|
||||||
167,Buckhurst Hill,51.627572,0.034513
|
167,Buckhurst Hill,51.627572,0.034513
|
||||||
167,Loughton,51.655942,0.068161
|
167,Loughton,51.64195093723499, 0.05498357119784937
|
||||||
168,Hampstead Heath,51.5608294,-0.1629416
|
168,Hampstead Heath,51.5608294,-0.1629416
|
||||||
168,Chalk Farm,51.5422732,-0.1466907
|
168,Chalk Farm,51.5422732,-0.1466907
|
||||||
168,Camden Town,51.5390261,-0.1425516
|
168,Camden Town,51.5390261,-0.1425516
|
||||||
@@ -1984,7 +1984,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
212,Highams Park,51.6083754,0.0014712
|
212,Highams Park,51.6083754,0.0014712
|
||||||
212,"Walthamstow, Beacontree Avenue",51.595736,0.0045318
|
212,"Walthamstow, Beacontree Avenue",51.595736,0.0045318
|
||||||
212,Walthamstow Central,51.5830128,-0.019886
|
212,Walthamstow Central,51.5830128,-0.019886
|
||||||
212,St James Street,51.5064993,-0.1393328
|
212,St James Street,51.581118791593234, -0.0328839757764101
|
||||||
213,Kingston,51.4116616,-0.2080648
|
213,Kingston,51.4116616,-0.2080648
|
||||||
213,Kingston,51.4116616,-0.2080648
|
213,Kingston,51.4116616,-0.2080648
|
||||||
213,"New Malden, Coombe Road",51.4094312,-0.2586718
|
213,"New Malden, Coombe Road",51.4094312,-0.2586718
|
||||||
@@ -2202,7 +2202,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
241,Plaistow,51.5268317,0.0308143
|
241,Plaistow,51.5268317,0.0308143
|
||||||
241,Plaistow Abbey Arms,51.5222296,0.0225853
|
241,Plaistow Abbey Arms,51.5222296,0.0225853
|
||||||
241,Keir Hardie Estate,51.5678758,-0.0607466
|
241,Keir Hardie Estate,51.5678758,-0.0607466
|
||||||
241,Canning Town,51.5189494,0.0132
|
241,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
241,"Canning Town, Barking Road",51.5198077,0.0168462
|
241,"Canning Town, Barking Road",51.5198077,0.0168462
|
||||||
242,Homerton Hospital,51.5478609,-0.0425903
|
242,Homerton Hospital,51.5478609,-0.0425903
|
||||||
242,"Clapton Park, Millfields",51.5575011,-0.0424329
|
242,"Clapton Park, Millfields",51.5575011,-0.0424329
|
||||||
@@ -2483,7 +2483,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
274,Baker Street Station,51.5231548,-0.156863
|
274,Baker Street Station,51.5231548,-0.156863
|
||||||
274,Portman Square,51.5161534,-0.1560125
|
274,Portman Square,51.5161534,-0.1560125
|
||||||
274,Marble Arch,51.5132225,-0.1588937
|
274,Marble Arch,51.5132225,-0.1588937
|
||||||
275,St James Street,51.5064993,-0.1393328
|
275,St James Street,51.581118791593234, -0.0328839757764101
|
||||||
275,Walthamstow Central,51.5830128,-0.019886
|
275,Walthamstow Central,51.5830128,-0.019886
|
||||||
275,"Walthamstow, Beacontree Avenue",51.595736,0.0045318
|
275,"Walthamstow, Beacontree Avenue",51.595736,0.0045318
|
||||||
275,Mill lane,51.5521985,-0.1932197
|
275,Mill lane,51.5521985,-0.1932197
|
||||||
@@ -2685,7 +2685,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
300,"Plaistow, Greengate Street",51.527444,0.027621
|
300,"Plaistow, Greengate Street",51.527444,0.027621
|
||||||
300,"Plaistow, Balaam Street",51.529212,0.0243676
|
300,"Plaistow, Balaam Street",51.529212,0.0243676
|
||||||
300,"Canning Town, Barking Road",51.5208364,0.0191093
|
300,"Canning Town, Barking Road",51.5208364,0.0191093
|
||||||
300,Canning Town,51.5189494,0.0132
|
300,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
302,Mill Hill Broadway,51.6129292,-0.2487871
|
302,Mill Hill Broadway,51.6129292,-0.2487871
|
||||||
302,Burnt Oak,51.602809,-0.266965
|
302,Burnt Oak,51.602809,-0.266965
|
||||||
302,Burnt Oak,51.602809,-0.266965
|
302,Burnt Oak,51.602809,-0.266965
|
||||||
@@ -2716,7 +2716,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
308,Stratford City,51.5440354,-0.0053088
|
308,Stratford City,51.5440354,-0.0053088
|
||||||
308,Homerton Hospital,51.5478609,-0.0425903
|
308,Homerton Hospital,51.5478609,-0.0425903
|
||||||
308,Clapton Pond,51.5561061,-0.05490830000000001
|
308,Clapton Pond,51.5561061,-0.05490830000000001
|
||||||
309,Canning Town,51.5189494,0.0132
|
309,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
309,Aberfeldy Estate,51.4309209,-0.0936496
|
309,Aberfeldy Estate,51.4309209,-0.0936496
|
||||||
309,"Poplar, All Saints",51.5105521,-0.0118612
|
309,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
309,"Poplar, Cordelia Street",51.5137347,-0.0174897
|
309,"Poplar, Cordelia Street",51.5137347,-0.0174897
|
||||||
@@ -2805,7 +2805,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
322,Brixton,51.4612794,-0.1156148
|
322,Brixton,51.4612794,-0.1156148
|
||||||
322,Clapham North,51.4658813,-0.1413263
|
322,Clapham North,51.4658813,-0.1413263
|
||||||
322,Clapham Common,51.4589252,-0.1493071
|
322,Clapham Common,51.4589252,-0.1493071
|
||||||
323,Canning Town,51.5189494,0.0132
|
323,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
323,East London Mail Centre,51.55633,0.0655092
|
323,East London Mail Centre,51.55633,0.0655092
|
||||||
323,Mile End,51.52354529999999,-0.0330122
|
323,Mile End,51.52354529999999,-0.0330122
|
||||||
324,Stanmore Station,51.617676,-0.311451
|
324,Stanmore Station,51.617676,-0.311451
|
||||||
@@ -2862,7 +2862,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
330,"Upton Park, Boleyn",51.5305005,0.0384915
|
330,"Upton Park, Boleyn",51.5305005,0.0384915
|
||||||
330,"Plaistow, Balaam Street",51.529212,0.0243676
|
330,"Plaistow, Balaam Street",51.529212,0.0243676
|
||||||
330,"Canning Town, Barking Road",51.521274,0.0207211
|
330,"Canning Town, Barking Road",51.521274,0.0207211
|
||||||
330,Canning Town,51.5189494,0.0132
|
330,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
331,Ruislip,51.5758719,-0.421236
|
331,Ruislip,51.5758719,-0.421236
|
||||||
331,Ruislip Lido,51.59114049999999,-0.4304918
|
331,Ruislip Lido,51.59114049999999,-0.4304918
|
||||||
331,Northwood Station,51.6112297,-0.423889
|
331,Northwood Station,51.6112297,-0.423889
|
||||||
@@ -3206,8 +3206,8 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
397,"Crooked Billet, Sainsbury's",51.601088,-0.0159737
|
397,"Crooked Billet, Sainsbury's",51.601088,-0.0159737
|
||||||
397,Chingford Mount,51.6185735,-0.0180318
|
397,Chingford Mount,51.6185735,-0.0180318
|
||||||
397,Chingford Station,51.6331421,0.0098588
|
397,Chingford Station,51.6331421,0.0098588
|
||||||
397,Loughton,51.655942,0.068161
|
397,Loughton,51.64195093723499, 0.05498357119784937
|
||||||
397,Debden,51.5417031,0.2034589
|
397,Debden,51.645776846753535, 0.08200009471482733
|
||||||
398,Ruislip,51.5758719,-0.421236
|
398,Ruislip,51.5758719,-0.421236
|
||||||
398,Rayners Lane Station,51.5751034,-0.3708618
|
398,Rayners Lane Station,51.5751034,-0.3708618
|
||||||
398,South Harrow,51.5683717,-0.3553483
|
398,South Harrow,51.5683717,-0.3553483
|
||||||
@@ -3521,7 +3521,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
473,Plaistow,51.5268317,0.0308143
|
473,Plaistow,51.5268317,0.0308143
|
||||||
473,Stratford,51.5426313,-0.0010369
|
473,Stratford,51.5426313,-0.0010369
|
||||||
474,"Canning Town, Barking Road",51.52364720000001,0.0258453
|
474,"Canning Town, Barking Road",51.52364720000001,0.0258453
|
||||||
474,Canning Town,51.5189494,0.0132
|
474,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
474,London City Airport,51.5048437,0.049518
|
474,London City Airport,51.5048437,0.049518
|
||||||
474,North Woolwich,51.5008658,0.0626916
|
474,North Woolwich,51.5008658,0.0626916
|
||||||
474,Cyprus,51.5091192,0.0633823
|
474,Cyprus,51.5091192,0.0633823
|
||||||
@@ -3658,7 +3658,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
541,Prince Regent,51.4309209,-0.0936496
|
541,Prince Regent,51.4309209,-0.0936496
|
||||||
549,South Woodford,51.5912671,0.0264721
|
549,South Woodford,51.5912671,0.0264721
|
||||||
549,Buckhurst Hill,51.627572,0.034513
|
549,Buckhurst Hill,51.627572,0.034513
|
||||||
549,Loughton,51.655942,0.068161
|
549,Loughton,51.64195093723499, 0.05498357119784937
|
||||||
601,Thamesmead,51.50575809999999,0.1100586
|
601,Thamesmead,51.50575809999999,0.1100586
|
||||||
601,Bexley,51.439933,0.154327
|
601,Bexley,51.439933,0.154327
|
||||||
601,Wilmington Schools,51.4309209,-0.0936496
|
601,Wilmington Schools,51.4309209,-0.0936496
|
||||||
@@ -3803,7 +3803,7 @@ Route,Blind,51.4309209,-0.0936496
|
|||||||
673,Beckton Station,51.5144016,0.06153319999999999
|
673,Beckton Station,51.5144016,0.06153319999999999
|
||||||
674,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527
|
674,"Harold Hill, Dagnam Park Square",51.6049149,0.2445527
|
||||||
674,Romford Station,51.57472449999999,0.1826519
|
674,Romford Station,51.57472449999999,0.1826519
|
||||||
675,St James Street,51.5064993,-0.1393328
|
675,St James Street,51.581118791593234, -0.0328839757764101
|
||||||
675,Woodbridge School,51.4309209,-0.0936496
|
675,Woodbridge School,51.4309209,-0.0936496
|
||||||
678,Stratford,51.5426313,-0.0010369
|
678,Stratford,51.5426313,-0.0010369
|
||||||
678,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496
|
678,NO BLIND DESCRIPTION (Departs only),51.4309209,-0.0936496
|
||||||
@@ -4016,7 +4016,7 @@ EL1,Barking,51.536563,0.075766
|
|||||||
EL1,Barking,51.536563,0.075766
|
EL1,Barking,51.536563,0.075766
|
||||||
EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878
|
EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878
|
||||||
EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878
|
EL1,"River Road, Waverley Gardens",51.5343317,-0.2891878
|
||||||
EL1,Barking Riverside,51.536563,0.075766
|
EL1,Barking Riverside,51.519303731473705, 0.11590257503355633
|
||||||
EL2,Becontree Heath,51.5609465,0.1488995
|
EL2,Becontree Heath,51.5609465,0.1488995
|
||||||
EL2,Five Elms,51.3697855,0.0259964
|
EL2,Five Elms,51.3697855,0.0259964
|
||||||
EL2,Bennett's Castle Lane,51.5562949,0.1276031
|
EL2,Bennett's Castle Lane,51.5562949,0.1276031
|
||||||
@@ -4031,7 +4031,7 @@ EL3,"Goodmayes, Goodmayes Lane",51.5620979,0.1095257
|
|||||||
EL3,Barking,51.536563,0.075766
|
EL3,Barking,51.536563,0.075766
|
||||||
EL3,Creekmouth,51.517381,0.102234
|
EL3,Creekmouth,51.517381,0.102234
|
||||||
EL3,Barking,51.536563,0.075766
|
EL3,Barking,51.536563,0.075766
|
||||||
EL3,Barking Riverside,51.536563,0.075766
|
EL3,Barking Riverside,51.519303731473705, 0.11590257503355633
|
||||||
G1,"Streatham, Green Lane",51.4147104,-0.1158693
|
G1,"Streatham, Green Lane",51.4147104,-0.1158693
|
||||||
G1,"Streatham, St Leonard's Church",51.4307467,-0.1294977
|
G1,"Streatham, St Leonard's Church",51.4307467,-0.1294977
|
||||||
G1,Tooting Broadway,51.427867,-0.1678142
|
G1,Tooting Broadway,51.427867,-0.1678142
|
||||||
@@ -4411,7 +4411,7 @@ UL10,Hackney Downs,51.5553095,-0.06908249999999999
|
|||||||
UL10,Liverpool Street,51.5175001,-0.0826966
|
UL10,Liverpool Street,51.5175001,-0.0826966
|
||||||
UL11,Canary Wharf,51.5054306,-0.0235333
|
UL11,Canary Wharf,51.5054306,-0.0235333
|
||||||
UL11,Stratford,51.5426313,-0.0010369
|
UL11,Stratford,51.5426313,-0.0010369
|
||||||
UL12,Loughton,51.655942,0.068161
|
UL12,Loughton,51.64195093723499, 0.05498357119784937
|
||||||
UL12,Snaresbrook,51.58567859999999,0.0084531
|
UL12,Snaresbrook,51.58567859999999,0.0084531
|
||||||
UL12,Leyton,51.5702225,-0.0146938
|
UL12,Leyton,51.5702225,-0.0146938
|
||||||
UL12,Stratford,51.5426313,-0.0010369
|
UL12,Stratford,51.5426313,-0.0010369
|
||||||
@@ -4438,7 +4438,7 @@ UL19,Wembley Central,51.550501,-0.3048409
|
|||||||
UL19,Stonebridge Park,51.5445824,-0.2608244
|
UL19,Stonebridge Park,51.5445824,-0.2608244
|
||||||
UL19,Queen's Park,51.5345448,-0.2043853
|
UL19,Queen's Park,51.5345448,-0.2043853
|
||||||
UL20,Tower Hill,51.5095757,-0.0760083
|
UL20,Tower Hill,51.5095757,-0.0760083
|
||||||
UL20,Canning Town,51.5189494,0.0132
|
UL20,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
UL20,Stratford,51.5426313,-0.0010369
|
UL20,Stratford,51.5426313,-0.0010369
|
||||||
UL20,Stratford,51.5426313,-0.0010369
|
UL20,Stratford,51.5426313,-0.0010369
|
||||||
UL20,East Ham,51.5333972,0.04991139999999999
|
UL20,East Ham,51.5333972,0.04991139999999999
|
||||||
@@ -4540,7 +4540,7 @@ W11,"Walthamstow, Crooked Billet",51.601088,-0.0159737
|
|||||||
W11,Walthamstow Central,51.5830128,-0.019886
|
W11,Walthamstow Central,51.5830128,-0.019886
|
||||||
W12,"Walthamstow, Coppermill Lane",51.5803038,-0.0403725
|
W12,"Walthamstow, Coppermill Lane",51.5803038,-0.0403725
|
||||||
W12,Walthamstow Central,51.5830128,-0.019886
|
W12,Walthamstow Central,51.5830128,-0.019886
|
||||||
W12,St James Street,51.5064993,-0.1393328
|
W12,St James Street,51.581118791593234, -0.0328839757764101
|
||||||
W12,Whipps Cross,51.5095281,-0.229236
|
W12,Whipps Cross,51.5095281,-0.229236
|
||||||
W12,South Woodford,51.5095281,-0.229236
|
W12,South Woodford,51.5095281,-0.229236
|
||||||
W12,Wanstead,51.5767971,0.0249881
|
W12,Wanstead,51.5767971,0.0249881
|
||||||
@@ -4559,7 +4559,7 @@ W14,"Leytonstone, Harrow Green",51.5582955,0.007356
|
|||||||
W14,Leyton,51.4964278,-0.2085211
|
W14,Leyton,51.4964278,-0.2085211
|
||||||
W14,"Leyton, Superstores",51.5558965,-0.0093311
|
W14,"Leyton, Superstores",51.5558965,-0.0093311
|
||||||
W15,"Higham Hill, Cogan Avenue",51.6012336,-0.0363719
|
W15,"Higham Hill, Cogan Avenue",51.6012336,-0.0363719
|
||||||
W15,"Forest Road, Palmerston Road",51.5858953,-0.0292291
|
W15,"Forest Road, Palmerston Road",51.588898351903815, -0.030623848707334166
|
||||||
W15,Walthamstow Central,51.5830128,-0.019886
|
W15,Walthamstow Central,51.5830128,-0.019886
|
||||||
W15,"Leyton, Bakers Arms",51.5749185,-0.013549
|
W15,"Leyton, Bakers Arms",51.5749185,-0.013549
|
||||||
W15,Whipps Cross,51.581499,0.0001219
|
W15,Whipps Cross,51.581499,0.0001219
|
||||||
@@ -4576,7 +4576,7 @@ W16,"Walthamstow, Wood Street",51.5864747,-0.0026968
|
|||||||
W16,"Leyton, Bakers Arms",51.5749185,-0.013549
|
W16,"Leyton, Bakers Arms",51.5749185,-0.013549
|
||||||
W16,Leytonstone,51.5649624,0.0088141
|
W16,Leytonstone,51.5649624,0.0088141
|
||||||
W19,"Walthamstow, Argall Avenue",51.5701165,-0.0387872
|
W19,"Walthamstow, Argall Avenue",51.5701165,-0.0387872
|
||||||
W19,St James Street,51.5064993,-0.1393328
|
W19,St James Street,51.581118791593234, -0.0328839757764101
|
||||||
W19,Walthamstow Central,51.5830128,-0.019886
|
W19,Walthamstow Central,51.5830128,-0.019886
|
||||||
W19,Whipps Cross,51.4255297,-0.2050566
|
W19,Whipps Cross,51.4255297,-0.2050566
|
||||||
W19,Leytonstone,51.5649624,0.0088141
|
W19,Leytonstone,51.5649624,0.0088141
|
||||||
@@ -4704,7 +4704,7 @@ N15,Barking,51.5833519,-0.07649299999999999
|
|||||||
N15,"East Ham, Newham Town Hall",51.53280239999999,0.0551608
|
N15,"East Ham, Newham Town Hall",51.53280239999999,0.0551608
|
||||||
N15,Upton Park,51.53471750000001,0.0337596
|
N15,Upton Park,51.53471750000001,0.0337596
|
||||||
N15,"Canning Town, Barking Road",51.5180017,0.0130984
|
N15,"Canning Town, Barking Road",51.5180017,0.0130984
|
||||||
N15,Canning Town,51.5189494,0.0132
|
N15,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
N15,"Poplar, All Saints",51.5105521,-0.0118612
|
N15,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
N15,"Limehouse, Burdett Road",51.5150014,-0.0285662
|
N15,"Limehouse, Burdett Road",51.5150014,-0.0285662
|
||||||
N15,Aldgate,51.5134365,-0.0772463
|
N15,Aldgate,51.5134365,-0.0772463
|
||||||
@@ -5151,13 +5151,13 @@ N550,Aldgate,51.5134365,-0.0772463
|
|||||||
N550,Cannon Street,51.5119949,-0.091962
|
N550,Cannon Street,51.5119949,-0.091962
|
||||||
N550,"Limehouse, Burdett Road",51.5150014,-0.0285662
|
N550,"Limehouse, Burdett Road",51.5150014,-0.0285662
|
||||||
N550,"Poplar, All Saints",51.5105521,-0.0118612
|
N550,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
N550,Canning Town,51.5189494,0.0132
|
N550,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
N551,Trafalgar Square,51.508039,-0.128069
|
N551,Trafalgar Square,51.508039,-0.128069
|
||||||
N551,Aldwych,51.5132441,-0.1172819
|
N551,Aldwych,51.5132441,-0.1172819
|
||||||
N551,Aldgate,51.5134365,-0.0772463
|
N551,Aldgate,51.5134365,-0.0772463
|
||||||
N551,Limehouse,51.5110598,-0.0366652
|
N551,Limehouse,51.5110598,-0.0366652
|
||||||
N551,"Poplar, All Saints",51.5105521,-0.0118612
|
N551,"Poplar, All Saints",51.5105521,-0.0118612
|
||||||
N551,Canning Town,51.5189494,0.0132
|
N551,Canning Town,51.51395705923875, 0.00827546234713445
|
||||||
N551,Keir Hardie Estate,51.5678758,-0.0607466
|
N551,Keir Hardie Estate,51.5678758,-0.0607466
|
||||||
N551,Prince Regent,51.4309209,-0.0936496
|
N551,Prince Regent,51.4309209,-0.0936496
|
||||||
N551,Beckton Station,51.5144016,0.06153319999999999
|
N551,Beckton Station,51.5144016,0.06153319999999999
|
||||||
|
|||||||
|
@@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
class ApiConstants {
|
class ApiConstants {
|
||||||
|
|
||||||
static const String APPWRITE_ENDPOINT = "https://cloud.imbenji.net/v1";
|
static const String APPWRITE_ENDPOINT = "https://cloud.appwrite.io/v1";
|
||||||
static const String APPWRITE_PROJECT_ID = "65de530c1c0a7ffc0c3f";
|
static const String APPWRITE_PROJECT_ID = "6633d0e00023502890ed";
|
||||||
|
|
||||||
static const String INFO_Q_DATABASE_ID = "65de5cab16717444527b";
|
static const String INFO_Q_DATABASE_ID = "65de5cab16717444527b";
|
||||||
static const String MANUAL_Q_COLLECTION_ID = "65de9f2f925562a2eda8";
|
static const String MANUAL_Q_COLLECTION_ID = "65de9f2f925562a2eda8";
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class AuthAPI extends ChangeNotifier {
|
|||||||
late final appwrite.Account account;
|
late final appwrite.Account account;
|
||||||
|
|
||||||
late models.User _currentUser;
|
late models.User _currentUser;
|
||||||
|
late models.Session _currentSession;
|
||||||
|
|
||||||
AuthStatus _status = AuthStatus.UNINITIALIZED;
|
AuthStatus _status = AuthStatus.UNINITIALIZED;
|
||||||
|
|
||||||
@@ -32,11 +33,16 @@ class AuthAPI extends ChangeNotifier {
|
|||||||
AuthStatus get status => _status;
|
AuthStatus get status => _status;
|
||||||
String? get username => _currentUser.name;
|
String? get username => _currentUser.name;
|
||||||
String? get email => _currentUser.email;
|
String? get email => _currentUser.email;
|
||||||
String? get userID => _currentUser.$id;
|
String? get userID {
|
||||||
|
try {
|
||||||
|
return _currentUser.$id;
|
||||||
|
} catch (e) {
|
||||||
|
return _currentSession.$id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
AuthAPI() {
|
AuthAPI({bool autoLoad = true}) {
|
||||||
init();
|
init();
|
||||||
loadUser();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@@ -45,6 +51,29 @@ class AuthAPI extends ChangeNotifier {
|
|||||||
.setProject(ApiConstants.APPWRITE_PROJECT_ID)
|
.setProject(ApiConstants.APPWRITE_PROJECT_ID)
|
||||||
.setSelfSigned();
|
.setSelfSigned();
|
||||||
account = appwrite.Account(client);
|
account = appwrite.Account(client);
|
||||||
|
try {
|
||||||
|
account.get().then((value) {
|
||||||
|
_currentUser = value;
|
||||||
|
_status = AuthStatus.AUTHENTICATED;
|
||||||
|
print("Auto loaded user: ${_currentUser.name}");
|
||||||
|
print("Auth status: $_status");
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAnonymousUser() async {
|
||||||
|
try {
|
||||||
|
final user = await account.createAnonymousSession();
|
||||||
|
_currentSession = user;
|
||||||
|
_status = AuthStatus.AUTHENTICATED;
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
_status = AuthStatus.UNAUTHENTICATED;
|
||||||
|
} finally {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUser() async {
|
loadUser() async {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import 'package:bus_infotainment/backend/modules/tube_info.dart';
|
|||||||
import 'package:bus_infotainment/tfl_datasets.dart';
|
import 'package:bus_infotainment/tfl_datasets.dart';
|
||||||
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
import 'package:bus_infotainment/utils/audio%20wrapper.dart';
|
||||||
import 'package:bus_infotainment/utils/delegates.dart';
|
import 'package:bus_infotainment/utils/delegates.dart';
|
||||||
|
import 'package:bus_infotainment/workaround/keepalive_realtime.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
@@ -62,12 +63,6 @@ class LiveInformation {
|
|||||||
print("Loading tube stations from assets");
|
print("Loading tube stations from assets");
|
||||||
tubeStations = TubeStations.fromJson(json.decode(await rootBundle.loadString("assets/datasets/tube_stations.json")));
|
tubeStations = TubeStations.fromJson(json.decode(await rootBundle.loadString("assets/datasets/tube_stations.json")));
|
||||||
print("Loaded tube stations from assets");
|
print("Loaded tube stations from assets");
|
||||||
|
|
||||||
|
|
||||||
String sessionID = "test";
|
|
||||||
|
|
||||||
commandModule = CommandModule(sessionID);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialise modules
|
// Initialise modules
|
||||||
@@ -77,6 +72,9 @@ class LiveInformation {
|
|||||||
initTrackerModule();
|
initTrackerModule();
|
||||||
|
|
||||||
print("Initialised LiveInformation");
|
print("Initialised LiveInformation");
|
||||||
|
if (!auth.isAuthenticated()) {
|
||||||
|
auth.loadAnonymousUser();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initTrackerModule() async {
|
Future<void> initTrackerModule() async {
|
||||||
@@ -86,10 +84,18 @@ class LiveInformation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Auth
|
// Auth
|
||||||
AuthAPI auth = AuthAPI();
|
AuthAPI auth = AuthAPI(
|
||||||
|
autoLoad: false,
|
||||||
|
);
|
||||||
|
String? roomCode;
|
||||||
|
String? roomDocumentID;
|
||||||
|
bool isHost = false;
|
||||||
|
appwrite.RealtimeSubscription? _subscription;
|
||||||
|
RealtimeKeepAliveConnection? _keepAliveConnection; // This is a workaround for a bug in the appwrite SDK
|
||||||
|
|
||||||
|
|
||||||
// Modules
|
// Modules
|
||||||
late CommandModule commandModule;
|
// late CommandModule commandModule; This needs to be deprecated
|
||||||
late BusSequences busSequences;
|
late BusSequences busSequences;
|
||||||
late AnnouncementModule announcementModule;
|
late AnnouncementModule announcementModule;
|
||||||
late SyncedTimeModule syncedTimeModule;
|
late SyncedTimeModule syncedTimeModule;
|
||||||
@@ -100,7 +106,7 @@ class LiveInformation {
|
|||||||
BusRouteVariant? _currentRouteVariant;
|
BusRouteVariant? _currentRouteVariant;
|
||||||
|
|
||||||
// Events
|
// Events
|
||||||
EventDelegate<BusRouteVariant> routeVariantDelegate = EventDelegate();
|
EventDelegate<BusRouteVariant?> routeVariantDelegate = EventDelegate();
|
||||||
|
|
||||||
// Internal methods
|
// Internal methods
|
||||||
|
|
||||||
@@ -108,7 +114,54 @@ class LiveInformation {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
Future<void> setRouteVariant_Internal(BusRouteVariant routeVariant) async {
|
Future<void> setRouteVariant(BusRouteVariant? routeVariant) async {
|
||||||
|
|
||||||
|
if (routeVariant == null) {
|
||||||
|
_currentRouteVariant = null;
|
||||||
|
|
||||||
|
await announcementModule.queueAnnounceByAudioName(
|
||||||
|
displayText: "*** NO MESSAGE ***",
|
||||||
|
);
|
||||||
|
|
||||||
|
routeVariantDelegate.trigger(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roomCode != null) {
|
||||||
|
try {
|
||||||
|
final client = auth.client;
|
||||||
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
|
final response = await databases.listDocuments(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", roomCode!)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
final document = response.documents.first;
|
||||||
|
|
||||||
|
// Check if the route is not the same
|
||||||
|
if (document.data["CurrentRoute"] != routeVariant.busRoute.routeNumber || document.data["CurrentRouteVariant"] != routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)) {
|
||||||
|
final updatedDocument = await databases.updateDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: document.$id,
|
||||||
|
data: {
|
||||||
|
"CurrentRoute": routeVariant.busRoute.routeNumber,
|
||||||
|
"CurrentRouteVariant": routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant),
|
||||||
|
"LastUpdater": auth.userID,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
print("Updated route on server");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to update route on server");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
Continuation:
|
||||||
|
|
||||||
// Set the current route variant
|
// Set the current route variant
|
||||||
_currentRouteVariant = routeVariant;
|
_currentRouteVariant = routeVariant;
|
||||||
@@ -135,6 +188,10 @@ class LiveInformation {
|
|||||||
|
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Display the route variant
|
||||||
|
announcementModule.queueAnnouncementByRouteVariant(routeVariant: routeVariant);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public methods
|
// Public methods
|
||||||
@@ -143,16 +200,329 @@ class LiveInformation {
|
|||||||
return _currentRouteVariant;
|
return _currentRouteVariant;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setRouteVariant(BusRouteVariant routeVariant) async {
|
Future<void> setRouteVariantQuery(String routeNumber, int routeVariantIndex) async {
|
||||||
await commandModule.executeCommand(
|
BusRoute route = busSequences.routes[routeNumber]!;
|
||||||
"setroute ${routeVariant.busRoute.routeNumber} ${routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)}"
|
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
|
||||||
|
|
||||||
|
await setRouteVariant(
|
||||||
|
routeVariant
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Multi device support
|
||||||
|
|
||||||
|
Future<void> createRoom(String roomCode) async {
|
||||||
|
print("Creating room with code $roomCode");
|
||||||
|
|
||||||
|
// Update the room code
|
||||||
|
this.roomCode = roomCode;
|
||||||
|
|
||||||
|
// Enable host mode
|
||||||
|
isHost = true;
|
||||||
|
|
||||||
|
// Access the database
|
||||||
|
final client = auth.client;
|
||||||
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
|
// Remove any existing documents
|
||||||
|
final existingDocuments = await databases.listDocuments(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", roomCode)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
for (var document in existingDocuments.documents) {
|
||||||
|
await databases.deleteDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: document.$id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the document
|
||||||
|
final document = await databases.createDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: appwrite.ID.unique(),
|
||||||
|
data: {
|
||||||
|
"SessionID": roomCode,
|
||||||
|
"LastUpdater": auth.userID,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Listen for changes
|
||||||
|
// { Breaks due to bug in appwrite
|
||||||
|
// final realtime = appwrite.Realtime(client);
|
||||||
|
//
|
||||||
|
// if (_subscription != null) {
|
||||||
|
// _subscription!.close();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// _subscription = realtime.subscribe(
|
||||||
|
// ['databases.6633e85400036415ab0f.collections.6633e85d0020f52f3771.documents.${document.$id}']
|
||||||
|
// );
|
||||||
|
// _subscription!.stream.listen(ServerListener);
|
||||||
|
// }
|
||||||
|
// Listen for changes
|
||||||
|
if (_keepAliveConnection != null) {
|
||||||
|
try {
|
||||||
|
_keepAliveConnection!.close();
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to close connection... oh well");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String APPWRITE_ENDPOINT_URL = "https://cloud.appwrite.io/v1";
|
||||||
|
String domain = APPWRITE_ENDPOINT_URL.replaceAll("https://", "").trim();
|
||||||
|
_keepAliveConnection = RealtimeKeepAliveConnection(
|
||||||
|
channels: ['databases.6633e85400036415ab0f.collections.6633e85d0020f52f3771.documents.${document.$id}'],
|
||||||
|
onData: ServerListener,
|
||||||
|
domain: domain,
|
||||||
|
client: auth.client,
|
||||||
|
onError: (e) {
|
||||||
|
print("Workarround Error: $e");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_keepAliveConnection!.initialize();
|
||||||
|
|
||||||
|
|
||||||
|
// Update the room document ID
|
||||||
|
roomDocumentID = document.$id;
|
||||||
|
|
||||||
|
print("Created room with code $roomCode");
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> JoinRoom(String roomCode) async {
|
||||||
|
print("Joining room with code $roomCode");
|
||||||
|
|
||||||
|
// Disable host mode
|
||||||
|
isHost = false;
|
||||||
|
|
||||||
|
// Update the room code
|
||||||
|
this.roomCode = roomCode;
|
||||||
|
|
||||||
|
// Access the database
|
||||||
|
final client = auth.client;
|
||||||
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
|
// Get the document
|
||||||
|
final response = await databases.listDocuments(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", roomCode)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.documents.isEmpty) {
|
||||||
|
throw Exception("Room not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
final document = response.documents.first;
|
||||||
|
|
||||||
|
// Listen for changes
|
||||||
|
// {
|
||||||
|
// final realtime = appwrite.Realtime(client);
|
||||||
|
//
|
||||||
|
// if (_subscription != null) {
|
||||||
|
// _subscription!.close();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// _subscription = realtime.subscribe([
|
||||||
|
// 'databases.6633e85400036415ab0f.collections.6633e85d0020f52f3771.documents.${document.$id}'
|
||||||
|
// ]);
|
||||||
|
//
|
||||||
|
// _subscription!.stream.listen(ServerListener);
|
||||||
|
// }
|
||||||
|
// Listen for changes
|
||||||
|
if (_keepAliveConnection != null) {
|
||||||
|
try {
|
||||||
|
_keepAliveConnection!.close();
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to close connection... oh well");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String APPWRITE_ENDPOINT_URL = "https://cloud.appwrite.io/v1";
|
||||||
|
String domain = APPWRITE_ENDPOINT_URL.replaceAll("https://", "").trim();
|
||||||
|
_keepAliveConnection = RealtimeKeepAliveConnection(
|
||||||
|
channels: ['databases.6633e85400036415ab0f.collections.6633e85d0020f52f3771.documents.${document.$id}'],
|
||||||
|
onData: ServerListener,
|
||||||
|
domain: domain,
|
||||||
|
client: auth.client,
|
||||||
|
onError: (e) {
|
||||||
|
print("Workarround Error: $e");
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_keepAliveConnection!.initialize();
|
||||||
|
|
||||||
|
// Update the room document ID
|
||||||
|
roomDocumentID = document.$id;
|
||||||
|
|
||||||
|
// Get the current route
|
||||||
|
try {
|
||||||
|
String routeNumber = document.data["CurrentRoute"];
|
||||||
|
int routeVariantIndex = document.data["CurrentRouteVariant"];
|
||||||
|
|
||||||
|
await setRouteVariantQuery(routeNumber, routeVariantIndex);
|
||||||
|
print("Set route to $routeNumber $routeVariantIndex");
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to set route");
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Joined room with code $roomCode");
|
||||||
|
}
|
||||||
|
|
||||||
|
String? lastCommand;
|
||||||
|
Future<void> ServerListener(appwrite.RealtimeMessage response) async {
|
||||||
|
print("Session update");
|
||||||
|
|
||||||
|
// Only do something if the document was created or updated
|
||||||
|
if (!(response.events.first.contains("create") || response.events.first.contains("update"))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the user that caused the event
|
||||||
|
|
||||||
|
String senderID = response.payload["LastUpdater"];
|
||||||
|
// If the sender is the same as the client, then ignore the event
|
||||||
|
if (senderID == auth.userID) {
|
||||||
|
print("Ignoring event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if the commands are updated
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get the new route
|
||||||
|
String routeNumber = response.payload["CurrentRoute"];
|
||||||
|
int routeVariantIndex = response.payload["CurrentRouteVariant"];
|
||||||
|
|
||||||
|
// If the route arent the same, then update the route
|
||||||
|
if (routeNumber != _currentRouteVariant!.busRoute.routeNumber || routeVariantIndex != _currentRouteVariant!.busRoute.routeVariants.values.toList().indexOf(_currentRouteVariant!)) {
|
||||||
|
// Set the route
|
||||||
|
await setRouteVariantQuery(routeNumber, routeVariantIndex);
|
||||||
|
|
||||||
|
// announce the route
|
||||||
|
// announcementModule.queueAnnouncementByRouteVariant(routeVariant: _currentRouteVariant!);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to set route");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command
|
||||||
|
List<String> commands = response.payload["Commands"].cast<String>();
|
||||||
|
|
||||||
|
String? command = commands.last;
|
||||||
|
|
||||||
|
if (command == lastCommand) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastCommand = command;
|
||||||
|
|
||||||
|
List<String> commandParts = _splitCommand(command);
|
||||||
|
String commandName = commandParts[0];
|
||||||
|
|
||||||
|
if (commandName == "announce") {
|
||||||
|
print("Announce command received");
|
||||||
|
String mode = commandParts[1];
|
||||||
|
|
||||||
|
print ("Command: $command");
|
||||||
|
|
||||||
|
if (mode == "info") {
|
||||||
|
print("Announce info command received");
|
||||||
|
announcementModule.queueAnnounementByInfoIndex(
|
||||||
|
sendToServer: false,
|
||||||
|
infoIndex: int.parse(commandParts[2]),
|
||||||
|
scheduledTime: DateTime.fromMillisecondsSinceEpoch(int.parse(commandParts[3])),
|
||||||
|
);
|
||||||
|
} else if (mode == "dest") {
|
||||||
|
print("Announce dest command received");
|
||||||
|
|
||||||
|
String routeNumber = commandParts[2];
|
||||||
|
int routeVariantIndex = int.parse(commandParts[3]);
|
||||||
|
|
||||||
|
announcementModule.queueAnnouncementByRouteVariant(
|
||||||
|
sendToServer: false,
|
||||||
|
routeVariant: busSequences.routes[routeNumber]!.routeVariants.values.toList()[routeVariantIndex],
|
||||||
|
scheduledTime: DateTime.fromMillisecondsSinceEpoch(int.parse(commandParts[4])),
|
||||||
|
);
|
||||||
|
|
||||||
|
} else if (mode == "manual") {
|
||||||
|
print("Announce manual command received");
|
||||||
|
|
||||||
|
final displayText = commandParts[2];
|
||||||
|
|
||||||
|
List<String> audioFileNames = commandParts.sublist(3);
|
||||||
|
try {
|
||||||
|
if (int.parse(audioFileNames.last) != null) {
|
||||||
|
audioFileNames.removeLast();
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
DateTime scheduledTime = LiveInformation().syncedTimeModule.Now().add(Duration(seconds: 1));
|
||||||
|
try {
|
||||||
|
if (int.parse(commandParts.last) != null) {
|
||||||
|
scheduledTime = DateTime.fromMillisecondsSinceEpoch(int.parse(commandParts.last));
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
announcementModule.queueAnnounceByAudioName(
|
||||||
|
displayText: displayText,
|
||||||
|
audioNames: audioFileNames,
|
||||||
|
scheduledTime: scheduledTime,
|
||||||
|
sendToServer: false
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String _extractId(String input) {
|
||||||
|
RegExp regExp = RegExp(r'\("user:(.*)"\)');
|
||||||
|
Match match = regExp.firstMatch(input)!;
|
||||||
|
return match.group(1)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> SendCommand(String command) async {
|
||||||
|
|
||||||
|
final client = auth.client;
|
||||||
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
|
final response = await databases.listDocuments(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", roomCode!)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
List<String> pastCommands = [];
|
||||||
|
|
||||||
|
response.documents.first.data["Commands"].forEach((element) {
|
||||||
|
pastCommands.add(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
pastCommands.add(command);
|
||||||
|
|
||||||
|
final document = await databases.updateDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: roomDocumentID!,
|
||||||
|
data: {
|
||||||
|
"Commands": pastCommands,
|
||||||
|
"LastUpdater": auth.userID,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> _splitCommand(String command) {
|
||||||
|
var regex = RegExp(r'([^\s"]+)|"([^"]*)"');
|
||||||
|
var matches = regex.allMatches(command);
|
||||||
|
return matches.map((match) => match.group(0)!.replaceAll('"', '')).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -162,8 +532,6 @@ class LiveInformation {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AnnouncementQueueEntry {
|
class AnnouncementQueueEntry {
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class AnnouncementModule extends InfoModule {
|
|||||||
final EventDelegate<AnnouncementQueueEntry> onAnnouncement = EventDelegate();
|
final EventDelegate<AnnouncementQueueEntry> onAnnouncement = EventDelegate();
|
||||||
|
|
||||||
// Timer
|
// Timer
|
||||||
Timer refreshTimer() => Timer.periodic(const Duration(milliseconds: 200), (timer) async {
|
Timer refreshTimer() => Timer.periodic(const Duration(milliseconds: 10), (timer) async {
|
||||||
|
|
||||||
if (!isPlaying) {
|
if (!isPlaying) {
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class AnnouncementModule extends InfoModule {
|
|||||||
|
|
||||||
bool proceeding = await _internalAccountForInconsistentTime(
|
bool proceeding = await _internalAccountForInconsistentTime(
|
||||||
announcement: nextAnnouncement,
|
announcement: nextAnnouncement,
|
||||||
timerInterval: const Duration(milliseconds: 200),
|
timerInterval: const Duration(milliseconds: 10),
|
||||||
callback: () {
|
callback: () {
|
||||||
queue.removeAt(0);
|
queue.removeAt(0);
|
||||||
print("Announcement proceeding");
|
print("Announcement proceeding");
|
||||||
@@ -105,35 +105,21 @@ class AnnouncementModule extends InfoModule {
|
|||||||
|
|
||||||
if (currentAnnouncement!.audioSources.isNotEmpty) {
|
if (currentAnnouncement!.audioSources.isNotEmpty) {
|
||||||
|
|
||||||
// audioPlayer.loadSource(AudioWrapperAssetSource("assets/audio/5-seconds-of-silence.mp3"));
|
// Prime all of the audio sources to be ready to play
|
||||||
// audioPlayer.play();
|
|
||||||
// await Future.delayed(const Duration(milliseconds: 300));
|
|
||||||
// audioPlayer.stop();
|
|
||||||
|
|
||||||
// try {
|
|
||||||
for (AudioWrapperSource source in currentAnnouncement!.audioSources) {
|
for (AudioWrapperSource source in currentAnnouncement!.audioSources) {
|
||||||
try {
|
try {
|
||||||
await audioPlayer.loadSource(source);
|
await audioPlayer.loadSource(source);
|
||||||
|
await Future.delayed((await audioPlayer.play())!);
|
||||||
Duration? duration = await audioPlayer.play();
|
|
||||||
await Future.delayed(duration!);
|
|
||||||
audioPlayer.stop();
|
audioPlayer.stop();
|
||||||
// await Future.delayed(const Duration(milliseconds: 100));
|
|
||||||
if (currentAnnouncement?.audioSources.last != source) {
|
if (currentAnnouncement?.audioSources.last != source) {
|
||||||
await Future.delayed(const Duration(milliseconds: 100));
|
await Future.delayed(const Duration(milliseconds: 100));
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Do nothing
|
|
||||||
// print("Error playing announcement: $e on ${currentAnnouncement?.displayText}");
|
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// audioPlayer.stop();
|
|
||||||
|
|
||||||
// } catch (e) {
|
|
||||||
// // Do nothing
|
|
||||||
// print("Error playing announcement: $e on ${currentAnnouncement?.displayTex}");
|
|
||||||
// }
|
|
||||||
} else {
|
} else {
|
||||||
if (queue.isNotEmpty) {
|
if (queue.isNotEmpty) {
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
await Future.delayed(const Duration(seconds: 5));
|
||||||
@@ -179,7 +165,7 @@ class AnnouncementModule extends InfoModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
int get defaultAnnouncementDelay => liveInformation.auth.isAuthenticated() ? 2 : 0;
|
int get defaultAnnouncementDelay => liveInformation.auth.isAuthenticated() ? 1 : 0;
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
Future<void> queueAnnounceByAudioName({
|
Future<void> queueAnnounceByAudioName({
|
||||||
@@ -199,8 +185,12 @@ class AnnouncementModule extends InfoModule {
|
|||||||
audioNamesString += "\"$audioName\" ";
|
audioNamesString += "\"$audioName\" ";
|
||||||
}
|
}
|
||||||
|
|
||||||
liveInformation.commandModule.executeCommand(
|
liveInformation.SendCommand("announce manual \"$displayText\" $audioNamesString ${scheduledTime.millisecondsSinceEpoch}");
|
||||||
"announce manual \"$displayText\" ${audioNamesString} ${scheduledTime?.millisecondsSinceEpoch ?? ""}"
|
queueAnnounceByAudioName(
|
||||||
|
displayText: displayText,
|
||||||
|
audioNames: audioNames,
|
||||||
|
scheduledTime: scheduledTime,
|
||||||
|
sendToServer: false
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -244,9 +234,13 @@ class AnnouncementModule extends InfoModule {
|
|||||||
|
|
||||||
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
|
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
|
||||||
|
|
||||||
liveInformation.commandModule.executeCommand(
|
liveInformation.SendCommand("announce info $infoIndex ${scheduledTime.millisecondsSinceEpoch}");
|
||||||
"announce info $infoIndex ${scheduledTime?.millisecondsSinceEpoch ?? ""}"
|
queueAnnounementByInfoIndex(
|
||||||
|
infoIndex: infoIndex,
|
||||||
|
scheduledTime: scheduledTime,
|
||||||
|
sendToServer: false
|
||||||
);
|
);
|
||||||
|
print("Announcement sent to server");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,9 +264,16 @@ class AnnouncementModule extends InfoModule {
|
|||||||
|
|
||||||
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
|
scheduledTime ??= liveInformation.syncedTimeModule.Now().add(Duration(seconds: defaultAnnouncementDelay));
|
||||||
|
|
||||||
liveInformation.commandModule.executeCommand(
|
String routeNumber = routeVariant.busRoute.routeNumber;
|
||||||
"announce dest \"${routeVariant.busRoute.routeNumber}\" ${routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant)} ${scheduledTime?.millisecondsSinceEpoch ?? ""}"
|
int routeVariantIndex = routeVariant.busRoute.routeVariants.values.toList().indexOf(routeVariant);
|
||||||
|
|
||||||
|
liveInformation.SendCommand("announce dest ${routeNumber} ${routeVariantIndex} ${scheduledTime.millisecondsSinceEpoch}");
|
||||||
|
queueAnnouncementByRouteVariant(
|
||||||
|
routeVariant: routeVariant,
|
||||||
|
scheduledTime: scheduledTime,
|
||||||
|
sendToServer: false
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
print("Checkpoint 4");
|
print("Checkpoint 4");
|
||||||
|
|||||||
@@ -47,17 +47,37 @@ class CommandModule extends InfoModule {
|
|||||||
|
|
||||||
final databases = appwrite.Databases(client);
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
if (liveInformation.auth.status == AuthStatus.AUTHENTICATED) {
|
if (true) {
|
||||||
final document = await databases.createDocument(
|
try {
|
||||||
databaseId: ApiConstants.INFO_Q_DATABASE_ID,
|
final response = await databases.listDocuments(
|
||||||
collectionId: ApiConstants.COMMANDS_COLLECTION_ID,
|
databaseId: "6633e85400036415ab0f",
|
||||||
documentId: appwrite.ID.unique(),
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", liveInformation.roomCode!)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
List<String> pastCommands = [];
|
||||||
|
|
||||||
|
response.documents.first.data["Commands"].forEach((element) {
|
||||||
|
pastCommands.add(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
pastCommands.add(command);
|
||||||
|
|
||||||
|
final document = await databases.updateDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: liveInformation.roomDocumentID!,
|
||||||
data: {
|
data: {
|
||||||
"session_id": sessionID,
|
"Commands": pastCommands,
|
||||||
"command": command,
|
"LastUpdater": clientID,
|
||||||
"client_id": clientID,
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to send command");
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCommandReceived(CommandInfo(command, clientID));
|
_onCommandReceived(CommandInfo(command, clientID));
|
||||||
@@ -78,6 +98,10 @@ class CommandModule extends InfoModule {
|
|||||||
|
|
||||||
if (command == "Response:") {
|
if (command == "Response:") {
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (command == "initroom") {
|
||||||
|
// initroom <roomCode>
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (command == "announce") {
|
else if (command == "announce") {
|
||||||
|
|
||||||
@@ -166,10 +190,41 @@ class CommandModule extends InfoModule {
|
|||||||
BusRoute route = liveInformation.busSequences.routes[routeNumber]!;
|
BusRoute route = liveInformation.busSequences.routes[routeNumber]!;
|
||||||
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
|
BusRouteVariant routeVariant = route.routeVariants.values.toList()[routeVariantIndex];
|
||||||
|
|
||||||
liveInformation.setRouteVariant_Internal(
|
liveInformation.setRouteVariant(
|
||||||
routeVariant
|
routeVariant
|
||||||
);
|
);
|
||||||
executeCommand("Response: v \"Client $clientID set its route to ($routeNumber to ${routeVariant.busStops.last.formattedStopName})\"");
|
|
||||||
|
|
||||||
|
// Update the server
|
||||||
|
if (liveInformation.isHost) {
|
||||||
|
print("Updating server");
|
||||||
|
final client = liveInformation.auth.client;
|
||||||
|
final databases = appwrite.Databases(client);
|
||||||
|
|
||||||
|
final response = await databases.listDocuments(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
queries: [
|
||||||
|
appwrite.Query.search("SessionID", liveInformation.roomCode!)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
final document = await databases.updateDocument(
|
||||||
|
databaseId: "6633e85400036415ab0f",
|
||||||
|
collectionId: "6633e85d0020f52f3771",
|
||||||
|
documentId: response.documents.first.$id,
|
||||||
|
data: {
|
||||||
|
"CurrentRoute": routeNumber,
|
||||||
|
"CurrentRouteVariant": routeVariantIndex,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
|
||||||
|
print("Updated server");
|
||||||
|
} catch (e) {
|
||||||
|
print("Failed to update server");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,26 +236,26 @@ class CommandModule extends InfoModule {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final realtime = appwrite.Realtime(LiveInformation().auth.client);
|
// final realtime = appwrite.Realtime(LiveInformation().auth.client);
|
||||||
|
//
|
||||||
_subscription = realtime.subscribe(
|
// _subscription = realtime.subscribe(
|
||||||
['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.COMMANDS_COLLECTION_ID}.documents']
|
// ['databases.${ApiConstants.INFO_Q_DATABASE_ID}.collections.${ApiConstants.COMMANDS_COLLECTION_ID}.documents']
|
||||||
);
|
// );
|
||||||
_subscription!.stream.listen((event) {
|
// _subscription!.stream.listen((event) {
|
||||||
print(jsonEncode(event.payload));
|
// print(jsonEncode(event.payload));
|
||||||
|
//
|
||||||
// Only do something if the document was created or updated
|
// // Only do something if the document was created or updated
|
||||||
if (!(event.events.first.contains("create") || event.events.first.contains("update"))) {
|
// if (!(event.events.first.contains("create") || event.events.first.contains("update"))) {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
final commandInfo = CommandInfo(event.payload['command'], event.payload['client_id']);
|
// final commandInfo = CommandInfo(event.payload['command'], event.payload['client_id']);
|
||||||
|
//
|
||||||
if (commandInfo.clientID != clientID) {
|
// if (commandInfo.clientID != clientID) {
|
||||||
_onCommandReceived(commandInfo);
|
// _onCommandReceived(commandInfo);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
});
|
// });
|
||||||
|
|
||||||
print("Listening for commands");
|
print("Listening for commands");
|
||||||
|
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ class TrackerModule extends InfoModule {
|
|||||||
print("Closest stop: ${closestStop.formattedStopName} in ${closestDistance.round()} meters");
|
print("Closest stop: ${closestStop.formattedStopName} in ${closestDistance.round()} meters");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double _calculateRelativeDistance(BusRouteStop stop, double latitude, double longitude) {
|
double _calculateRelativeDistance(BusRouteStop stop, double latitude, double longitude) {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class TubeStations {
|
|||||||
double distance = Vector2(stop.easting.toDouble(), stop.northing.toDouble()).distanceTo(OSGrid.toNorthingEasting(station.latitude, station.longitude));
|
double distance = Vector2(stop.easting.toDouble(), stop.northing.toDouble()).distanceTo(OSGrid.toNorthingEasting(station.latitude, station.longitude));
|
||||||
|
|
||||||
// if the distance is less than 100m, then we can assume that the bus stop is near the tube station
|
// if the distance is less than 100m, then we can assume that the bus stop is near the tube station
|
||||||
if (distance < 200) {
|
if (distance < 400) {
|
||||||
for (TubeLine line in station.lines) {
|
for (TubeLine line in station.lines) {
|
||||||
lineMatches[line] = lineMatches[line]! + 1;
|
lineMatches[line] = lineMatches[line]! + 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'package:bus_infotainment/utils/delegates.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:geolocator/geolocator.dart';
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:shadcn_ui/shadcn_ui.dart';
|
||||||
|
|
||||||
class pages_Home extends StatelessWidget {
|
class pages_Home extends StatelessWidget {
|
||||||
const pages_Home({super.key});
|
const pages_Home({super.key});
|
||||||
@@ -60,7 +61,7 @@ class pages_Home extends StatelessWidget {
|
|||||||
outlineColor: Colors.white70,
|
outlineColor: Colors.white70,
|
||||||
announcements: [
|
announcements: [
|
||||||
for (NamedAnnouncementQueueEntry announcement in LiveInformation().announcementModule.manualAnnouncements)
|
for (NamedAnnouncementQueueEntry announcement in LiveInformation().announcementModule.manualAnnouncements)
|
||||||
_AnnouncementEntry(
|
AnnouncementEntry(
|
||||||
label: announcement.shortName,
|
label: announcement.shortName,
|
||||||
index: LiveInformation().announcementModule.manualAnnouncements.indexOf(announcement),
|
index: LiveInformation().announcementModule.manualAnnouncements.indexOf(announcement),
|
||||||
outlineColor: Colors.white70,
|
outlineColor: Colors.white70,
|
||||||
@@ -92,12 +93,12 @@ class pages_Home extends StatelessWidget {
|
|||||||
color: Colors.grey.shade900,
|
color: Colors.grey.shade900,
|
||||||
),
|
),
|
||||||
|
|
||||||
child: DelegateBuilder<BusRouteVariant>(
|
child: DelegateBuilder<BusRouteVariant?>(
|
||||||
delegate: LiveInformation().routeVariantDelegate,
|
delegate: LiveInformation().routeVariantDelegate,
|
||||||
builder: (context, routeVariant) {
|
builder: (context, routeVariant) {
|
||||||
print("rebuilt stop announcement picker");
|
print("rebuilt stop announcement picker");
|
||||||
return StopAnnouncementPicker(
|
return StopAnnouncementPicker(
|
||||||
routeVariant: routeVariant,
|
routeVariant: routeVariant!,
|
||||||
backgroundColor: Colors.grey.shade900,
|
backgroundColor: Colors.grey.shade900,
|
||||||
outlineColor: Colors.white70,
|
outlineColor: Colors.white70,
|
||||||
);
|
);
|
||||||
@@ -133,11 +134,6 @@ class pages_Home extends StatelessWidget {
|
|||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
LiveInformation liveInformation = LiveInformation();
|
LiveInformation liveInformation = LiveInformation();
|
||||||
final commandModule = liveInformation.commandModule;
|
|
||||||
|
|
||||||
// commandModule.executeCommand(
|
|
||||||
// "announce dest"
|
|
||||||
// );
|
|
||||||
|
|
||||||
liveInformation.announcementModule.queueAnnouncementByRouteVariant(
|
liveInformation.announcementModule.queueAnnouncementByRouteVariant(
|
||||||
routeVariant: liveInformation.getRouteVariant()!
|
routeVariant: liveInformation.getRouteVariant()!
|
||||||
@@ -148,74 +144,6 @@ class pages_Home extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
// Container(
|
|
||||||
//
|
|
||||||
// margin: EdgeInsets.all(20),
|
|
||||||
//
|
|
||||||
// height: 300-45,
|
|
||||||
//
|
|
||||||
// child: ListView(
|
|
||||||
//
|
|
||||||
// scrollDirection: Axis.vertical,
|
|
||||||
//
|
|
||||||
// children: [
|
|
||||||
//
|
|
||||||
// ElevatedButton(
|
|
||||||
// onPressed: () async {
|
|
||||||
// LiveInformation liveInformation = LiveInformation();
|
|
||||||
// liveInformation.queueAnnouncement(await liveInformation.getDestinationAnnouncement(liveInformation.getRouteVariant()!, sendToServer: false));
|
|
||||||
// },
|
|
||||||
// child: Text("Test announcement"),
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// ElevatedButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// LiveInformation liveInformation = LiveInformation();
|
|
||||||
// liveInformation.updateServer();
|
|
||||||
// },
|
|
||||||
// child: Text("Update server"),
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// SizedBox(
|
|
||||||
//
|
|
||||||
// width: 100,
|
|
||||||
//
|
|
||||||
// child: TextField(
|
|
||||||
// onChanged: (String value) {
|
|
||||||
// LiveInformation liveInformation = LiveInformation();
|
|
||||||
// // liveInformation.documentID = value;
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// SizedBox(
|
|
||||||
//
|
|
||||||
// width: 200,
|
|
||||||
//
|
|
||||||
// child: TextField(
|
|
||||||
// onSubmitted: (String value) {
|
|
||||||
// LiveInformation liveInformation = LiveInformation();
|
|
||||||
// liveInformation.queueAnnouncement(AnnouncementQueueEntry(
|
|
||||||
// displayText: value,
|
|
||||||
// audioSources: []
|
|
||||||
// ));
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// ElevatedButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// LiveInformation liveInformation = LiveInformation();
|
|
||||||
// liveInformation.pullServer();
|
|
||||||
// },
|
|
||||||
// child: Text("Pull server"),
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// ],
|
|
||||||
//
|
|
||||||
// ),
|
|
||||||
//
|
|
||||||
// ),
|
|
||||||
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -366,8 +294,9 @@ class AnnouncementPicker extends StatefulWidget {
|
|||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
final Color outlineColor;
|
final Color outlineColor;
|
||||||
final List<Widget> announcements;
|
final List<Widget> announcements;
|
||||||
|
final String label;
|
||||||
|
|
||||||
const AnnouncementPicker({super.key, required this.backgroundColor, required this.outlineColor, required this.announcements});
|
const AnnouncementPicker({super.key, required this.backgroundColor, required this.outlineColor, required this.announcements, this.label = ""});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AnnouncementPicker> createState() => _AnnouncementPickerState();
|
State<AnnouncementPicker> createState() => _AnnouncementPickerState();
|
||||||
@@ -411,9 +340,9 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
color: widget.backgroundColor,
|
color: widget.backgroundColor,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
width: 2
|
width: 1
|
||||||
),
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8)
|
||||||
|
|
||||||
|
|
||||||
),
|
),
|
||||||
@@ -428,10 +357,20 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 2,
|
decoration: BoxDecoration(
|
||||||
|
color: widget.backgroundColor,
|
||||||
|
border: Border.all(
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
|
width: 1
|
||||||
),
|
),
|
||||||
|
borderRadius: BorderRadius.circular(4)
|
||||||
|
),
|
||||||
|
// height: 100,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
|
||||||
|
|
||||||
if (_currentIndex < announcementWidgets.length)
|
if (_currentIndex < announcementWidgets.length)
|
||||||
announcementWidgets[_currentIndex + 0]
|
announcementWidgets[_currentIndex + 0]
|
||||||
@@ -450,7 +389,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 2,
|
height: 1,
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -471,7 +410,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 2,
|
height: 1,
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -492,7 +431,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 2,
|
height: 1,
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -513,7 +452,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
height: 2,
|
height: 1,
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -521,15 +460,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
height: 40,
|
height: 40,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: widget.backgroundColor,
|
color: widget.backgroundColor,
|
||||||
border: Border.symmetric(
|
|
||||||
vertical: BorderSide(
|
|
||||||
color: widget.outlineColor,
|
|
||||||
width: 2
|
|
||||||
)
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
|
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
||||||
@@ -537,6 +468,26 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
|
|
||||||
children: [
|
children: [
|
||||||
|
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
widget.label,
|
||||||
|
style: ShadTheme.of(context).textTheme.h4.copyWith(
|
||||||
|
shadows: [
|
||||||
|
Shadow(
|
||||||
|
color: Colors.blueAccent.shade700,
|
||||||
|
blurRadius: 8
|
||||||
|
)
|
||||||
|
],
|
||||||
|
color: Colors.blueAccent.shade700
|
||||||
|
)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Expanded(child: Container()),
|
||||||
|
|
||||||
Container(
|
Container(
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
@@ -545,7 +496,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
border: Border.symmetric(
|
border: Border.symmetric(
|
||||||
vertical: BorderSide(
|
vertical: BorderSide(
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
width: 2
|
width: 1
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -598,7 +549,7 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
border: Border.symmetric(
|
border: Border.symmetric(
|
||||||
vertical: BorderSide(
|
vertical: BorderSide(
|
||||||
color: widget.outlineColor,
|
color: widget.outlineColor,
|
||||||
width: 2
|
width: 1
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -648,9 +599,8 @@ class _AnnouncementPickerState extends State<AnnouncementPicker> {
|
|||||||
),
|
),
|
||||||
|
|
||||||
),
|
),
|
||||||
Container(
|
],
|
||||||
height: 2,
|
),
|
||||||
color: widget.outlineColor,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -669,13 +619,14 @@ class StopAnnouncementPicker extends AnnouncementPicker {
|
|||||||
required this.routeVariant,
|
required this.routeVariant,
|
||||||
required Color backgroundColor,
|
required Color backgroundColor,
|
||||||
required Color outlineColor,
|
required Color outlineColor,
|
||||||
|
String label = "Stops"
|
||||||
}) : super(
|
}) : super(
|
||||||
key: key,
|
key: key,
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
outlineColor: outlineColor,
|
outlineColor: outlineColor,
|
||||||
announcements: [
|
announcements: [
|
||||||
for (BusRouteStop stop in routeVariant.busStops)
|
for (BusRouteStop stop in routeVariant.busStops)
|
||||||
_AnnouncementEntry(
|
AnnouncementEntry(
|
||||||
label: stop.formattedStopName,
|
label: stop.formattedStopName,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
LiveInformation liveInformation = LiveInformation();
|
LiveInformation liveInformation = LiveInformation();
|
||||||
@@ -688,7 +639,8 @@ class StopAnnouncementPicker extends AnnouncementPicker {
|
|||||||
outlineColor: outlineColor,
|
outlineColor: outlineColor,
|
||||||
alert: LiveInformation().announcementModule.announcementCache[stop.getAudioFileName()] == null,
|
alert: LiveInformation().announcementModule.announcementCache[stop.getAudioFileName()] == null,
|
||||||
)
|
)
|
||||||
]
|
],
|
||||||
|
label: label
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +661,7 @@ int wrap(int i, int j, int length, {int increment = -1}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AnnouncementEntry extends StatelessWidget {
|
class AnnouncementEntry extends StatelessWidget {
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
|
|
||||||
@@ -719,7 +671,7 @@ class _AnnouncementEntry extends StatelessWidget {
|
|||||||
|
|
||||||
bool alert = false;
|
bool alert = false;
|
||||||
|
|
||||||
_AnnouncementEntry({super.key, required this.label, required this.onPressed, required this.index, required this.outlineColor, this.alert = false});
|
AnnouncementEntry({super.key, required this.label, required this.onPressed, required this.index, required this.outlineColor, this.alert = false});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -730,12 +682,6 @@ class _AnnouncementEntry extends StatelessWidget {
|
|||||||
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
border: Border.symmetric(
|
|
||||||
vertical: BorderSide(
|
|
||||||
color: outlineColor,
|
|
||||||
width: 2
|
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@@ -760,7 +706,7 @@ class _AnnouncementEntry extends StatelessWidget {
|
|||||||
label,
|
label,
|
||||||
style: GoogleFonts.teko(
|
style: GoogleFonts.teko(
|
||||||
fontSize: 25,
|
fontSize: 25,
|
||||||
color: outlineColor,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1228,11 +1228,11 @@ class _ConsoleState extends State<Console> {
|
|||||||
// TODO: implement initState
|
// TODO: implement initState
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_listenerReceipt = LiveInformation().commandModule.onCommandReceived.addListener((p0) {
|
/*_listenerReceipt = LiveInformation().commandModule.onCommandReceived.addListener((p0) {
|
||||||
print("Command received, updating console");
|
print("Command received, updating console");
|
||||||
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1253,7 +1253,7 @@ class _ConsoleState extends State<Console> {
|
|||||||
Text("Command History:")
|
Text("Command History:")
|
||||||
);
|
);
|
||||||
|
|
||||||
for (int i = 0; i < LiveInformation().commandModule.commandHistory.length; i++){
|
/*for (int i = 0; i < LiveInformation().commandModule.commandHistory.length; i++){
|
||||||
CommandInfo command = LiveInformation().commandModule.commandHistory[i];
|
CommandInfo command = LiveInformation().commandModule.commandHistory[i];
|
||||||
|
|
||||||
commands.add(
|
commands.add(
|
||||||
@@ -1271,7 +1271,7 @@ class _ConsoleState extends State<Console> {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return Container(
|
return Container(
|
||||||
|
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@@ -1299,7 +1299,7 @@ class _ConsoleState extends State<Console> {
|
|||||||
color: Colors.white70,
|
color: Colors.white70,
|
||||||
),
|
),
|
||||||
|
|
||||||
Container(
|
/*Container(
|
||||||
height: 50,
|
height: 50,
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@@ -1315,7 +1315,7 @@ class _ConsoleState extends State<Console> {
|
|||||||
LiveInformation().commandModule.executeCommand(value);
|
LiveInformation().commandModule.executeCommand(value);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
)
|
)*/
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:bus_infotainment/pages/tfl_dataset_test.dart';
|
||||||
import 'package:bus_infotainment/remaster/InitialStartup.dart';
|
import 'package:bus_infotainment/remaster/InitialStartup.dart';
|
||||||
import 'package:bus_infotainment/remaster/dashboard.dart';
|
import 'package:bus_infotainment/remaster/dashboard.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -15,13 +16,22 @@ class RemasteredApp extends StatelessWidget {
|
|||||||
darkTheme: ShadThemeData(
|
darkTheme: ShadThemeData(
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
colorScheme: ShadSlateColorScheme.dark(),
|
colorScheme: ShadSlateColorScheme.dark(),
|
||||||
|
// force dark mode
|
||||||
),
|
),
|
||||||
|
themeMode: ThemeMode.dark,
|
||||||
|
|
||||||
routes: {
|
routes: {
|
||||||
'/setup': (context) => InitialStartup(),
|
'/setup': (context) => InitialStartup(),
|
||||||
'/': (context) => HomePage_Re(),
|
'/': (context) => HomePage_Re(),
|
||||||
'/routes': (context) => RoutePage(),
|
'/routes': (context) => RoutePage(),
|
||||||
'/enroute': (context) => EnRoutePage(),
|
'/enroute': (context) => EnRoutePage(),
|
||||||
|
'/legacy': (context) => TfL_Dataset_Test(),
|
||||||
|
'/multi': (context) => MultiModeSetup(),
|
||||||
|
'/multi/enroute': (context) => MultiModeEnroute(),
|
||||||
|
'/multi/login': (context) => MultiModeLogin(),
|
||||||
|
'/multi/register': (context) => MultiModeRegister(),
|
||||||
|
'/display': (context) => FullscreenDisplay(),
|
||||||
|
'/multi/join': (context) => MultiModeJoin(),
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
112
lib/workaround/keepalive_realtime.dart
Normal file
112
lib/workaround/keepalive_realtime.dart
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:appwrite/appwrite.dart';
|
||||||
|
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||||
|
// import this package https://pub.dev/packages/web_socket_channel
|
||||||
|
|
||||||
|
class RealtimeKeepAliveConnection {
|
||||||
|
RealtimeKeepAliveConnection({
|
||||||
|
required this.channels,
|
||||||
|
required this.domain,
|
||||||
|
required this.client,
|
||||||
|
this.keepAlivePingDuration = const Duration(seconds: 90),
|
||||||
|
required this.onData,
|
||||||
|
required this.onError,
|
||||||
|
});
|
||||||
|
|
||||||
|
final List<String> channels;
|
||||||
|
final String domain;
|
||||||
|
final Duration keepAlivePingDuration;
|
||||||
|
final Client client;
|
||||||
|
final Function(RealtimeMessage) onData;
|
||||||
|
final Function(dynamic) onError;
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
StreamSubscription<dynamic>? _subscription;
|
||||||
|
WebSocketChannel? _webSocket;
|
||||||
|
final Stopwatch _stopwatch = Stopwatch();
|
||||||
|
bool _keepAlive = true;
|
||||||
|
bool _sentKeepAlivePing = false;
|
||||||
|
int reconnectCount = 0;
|
||||||
|
|
||||||
|
Future initialize() async {
|
||||||
|
await _initRealtime(
|
||||||
|
onData: _realtimeOnData,
|
||||||
|
onDone: _realtimeOnDone,
|
||||||
|
onError: _realtimeOnError,
|
||||||
|
);
|
||||||
|
_heartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
_keepAlive = false;
|
||||||
|
_subscription!.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _heartbeat() async {
|
||||||
|
while (_keepAlive) {
|
||||||
|
await Future.delayed(keepAlivePingDuration);
|
||||||
|
if (_webSocket != null) {
|
||||||
|
_sentKeepAlivePing = true;
|
||||||
|
_webSocket!.sink.add("ping");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _realtimeOnData(RealtimeMessage data) {
|
||||||
|
log("[$reconnectCount][${_stopwatch.elapsed}] onData");
|
||||||
|
onData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _realtimeOnDone() async {
|
||||||
|
reconnectCount++;
|
||||||
|
log("[$reconnectCount][${_stopwatch.elapsed}] onDone");
|
||||||
|
if (_keepAlive) {
|
||||||
|
if (_subscription != null) _subscription!.cancel();
|
||||||
|
|
||||||
|
_subscription = _subscription = await _initRealtime(
|
||||||
|
onData: _realtimeOnData,
|
||||||
|
onDone: _realtimeOnDone,
|
||||||
|
onError: _realtimeOnError,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _realtimeOnError(dynamic e) {
|
||||||
|
log("[$reconnectCount][${_stopwatch.elapsed}] onError:$e");
|
||||||
|
onError(onError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _initRealtime({
|
||||||
|
required Function(RealtimeMessage) onData,
|
||||||
|
required Function() onDone,
|
||||||
|
required Function(dynamic) onError,
|
||||||
|
}) async {
|
||||||
|
_stopwatch.reset();
|
||||||
|
_stopwatch.start();
|
||||||
|
String channelParams = channels.map((c) => "channels[]=$c").join('&');
|
||||||
|
|
||||||
|
String? projectId = client.config['project'];
|
||||||
|
|
||||||
|
final wssUrl = Uri.parse('wss://$domain/realtime?project=$projectId&$channelParams');
|
||||||
|
_webSocket = WebSocketChannel.connect(wssUrl);
|
||||||
|
|
||||||
|
Realtime realtime = Realtime(client);
|
||||||
|
RealtimeSubscription subscriptionRealTime = realtime.subscribe(channels);
|
||||||
|
|
||||||
|
subscriptionRealTime.stream.listen(onData, onDone: onDone, onError: onError);
|
||||||
|
_subscription = _webSocket!.stream.listen(_handlePingMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handlePingMsg(dynamic response) {
|
||||||
|
var json = jsonDecode(response);
|
||||||
|
|
||||||
|
if (json["type"] == "error" && _sentKeepAlivePing) {
|
||||||
|
_sentKeepAlivePing = false;
|
||||||
|
log("Web socket keep-alive heartbeat successful (Reconnect Count: $reconnectCount, Time alive: ${_stopwatch.elapsed})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
pubspec.lock
32
pubspec.lock
@@ -185,6 +185,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.8"
|
version: "1.0.8"
|
||||||
|
dart_ping:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dart_ping
|
||||||
|
sha256: "2f5418d0a5c64e53486caaac78677b25725b1e13c33c5be834ce874ea18bd24f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "9.0.1"
|
||||||
device_info_plus:
|
device_info_plus:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -565,6 +573,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
native_qr:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: native_qr
|
||||||
|
sha256: "0928754b92305eb101a3359014a60ac5e90126534406b4dd6fb7550433978420"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
ntp:
|
ntp:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -741,6 +757,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.0"
|
version: "2.1.0"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
qr_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: qr_flutter
|
||||||
|
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
rive:
|
rive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -52,6 +52,9 @@ dependencies:
|
|||||||
file_picker: ^8.0.0+1
|
file_picker: ^8.0.0+1
|
||||||
shadcn_ui: ^0.4.1
|
shadcn_ui: ^0.4.1
|
||||||
flutter_carousel_widget: ^2.2.0
|
flutter_carousel_widget: ^2.2.0
|
||||||
|
dart_ping: ^9.0.1
|
||||||
|
native_qr: ^0.0.3
|
||||||
|
qr_flutter: ^4.1.0
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
|||||||
Reference in New Issue
Block a user