Version 3.0.360

This commit is contained in:
Anja 2023-02-22 14:03:35 +01:00
parent 5c0b2e70c9
commit faf68061f4
160 changed files with 2114 additions and 1932 deletions

View file

@ -11,25 +11,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItShared", "..\LockItSh
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItShared", "..\TestLockItShared\TestLockItShared.csproj", "{7E25F58E-62E3-48D7-8115-E33DA67C511E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestShareeLib", "..\TestShareeLib\TestShareeLib.csproj", "{38F340AD-EC12-4BB2-8633-AC5B55C32B77}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItBLE", "..\TestLockItBLE\TestLockItBLE.csproj", "{2581E9AD-4F56-431A-AB87-1B6D80D546AA}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "LastenradBayern", "TINK\LastenradBayern.shproj", "{8D4F2CDD-32C6-4AA1-A9E1-7B27BDCEB3A5}" Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "LastenradBayern", "TINK\LastenradBayern.shproj", "{8D4F2CDD-32C6-4AA1-A9E1-7B27BDCEB3A5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LastenradBayern.iOS", "TINK.iOS\LastenradBayern.iOS.csproj", "{3A0EF953-1501-4155-B0A0-265EB5FB2975}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LastenradBayern.iOS", "TINK.iOS\LastenradBayern.iOS.csproj", "{3A0EF953-1501-4155-B0A0-265EB5FB2975}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSharee", "..\TestSharee\TestSharee.csproj", "{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
TINK\LastenradBayern.projitems*{3a0ef953-1501-4155-b0a0-265eb5fb2975}*SharedItemsImports = 4
TINK\LastenradBayern.projitems*{8d4f2cdd-32c6-4aa1-a9e1-7b27bdceb3a5}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|ARM = Ad-Hoc|ARM Ad-Hoc|ARM = Ad-Hoc|ARM
@ -249,150 +237,6 @@ Global
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.Build.0 = Release|Any CPU
{3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhoneSimulator {3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhoneSimulator
{3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhoneSimulator {3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhoneSimulator
{3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone {3A0EF953-1501-4155-B0A0-265EB5FB2975}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
@ -473,54 +317,6 @@ Global
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -528,6 +324,11 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C6529CD7-C3F7-4E80-89B5-002E2B8E3EB5} SolutionGuid = {C6529CD7-C3F7-4E80-89B5-002E2B8E3EB5}
EndGlobalSection EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
TINK\LastenradBayern.projitems*{3a0ef953-1501-4155-b0a0-265eb5fb2975}*SharedItemsImports = 4
..\ShareeSharedGuiLib\ShareeSharedGuiLib.projitems*{3a0ef953-1501-4155-b0a0-265eb5fb2975}*SharedItemsImports = 4
TINK\LastenradBayern.projitems*{8d4f2cdd-32c6-4aa1-a9e1-7b27bdceb3a5}*SharedItemsImports = 13
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0 Policies = $0
$0.DotNetNamingPolicy = $1 $0.DotNetNamingPolicy = $1

View file

@ -57,7 +57,7 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>None</AndroidLinkMode>
<AotAssemblies>false</AotAssemblies> <AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM> <EnableLLVM>false</EnableLLVM>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
@ -176,16 +176,16 @@
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.AndroidX.Core"> <PackageReference Include="Xamarin.AndroidX.Core">
<Version>1.9.0.1</Version> <Version>1.9.0.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.MediaRouter"> <PackageReference Include="Xamarin.AndroidX.MediaRouter">
<Version>1.3.1.1</Version> <Version>1.3.1.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.Palette"> <PackageReference Include="Xamarin.AndroidX.Palette">
<Version>1.0.0.15</Version> <Version>1.0.0.16</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView"> <PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.8</Version> <Version>1.2.1.9</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" /> <PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" /> <PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -193,7 +193,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms.AppLinks"> <PackageReference Include="Xamarin.Forms.AppLinks">
@ -203,10 +203,10 @@
<Version>5.0.0</Version> <Version>5.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" /> <PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0.2" />
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2" /> <PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.357" android:versionCode="357"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.LastenradBayern" android:versionName="3.0.360" android:versionCode="360">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions --> <!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services --> <!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>LastenradBayern</string> <string>LastenradBayern</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>357</string> <string>360</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.357</string> <string>3.0.360</string>
</dict> </dict>
</plist> </plist>

View file

@ -25,7 +25,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<MtouchArch>x86_64</MtouchArch> <MtouchArch>x86_64</MtouchArch>
<MtouchLink>None</MtouchLink> <MtouchLink>SdkOnly</MtouchLink>
<MtouchDebug>true</MtouchDebug> <MtouchDebug>true</MtouchDebug>
<CodesignProvision>VS: com.TeilRad.LastenradBayern Development</CodesignProvision> <CodesignProvision>VS: com.TeilRad.LastenradBayern Development</CodesignProvision>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey> <CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
@ -200,7 +200,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps"> <PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version> <Version>5.0.0</Version>

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@ -126,6 +126,8 @@ namespace TINK
Log.Debug("Get auth cookie."); Log.Debug("Get auth cookie.");
IStore store = null; IStore store = null;
// Version of last version used or null for initial installation.
// Used for updating purposes.
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON); var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (new Version(3, 0, 290) <= lastVersion) if (new Version(3, 0, 290) <= lastVersion)
{ {
@ -139,9 +141,11 @@ namespace TINK
Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
// Get main thread synchronization context to be able to update gui elements from worker threads.
var context = SynchronizationContext.Current; var context = SynchronizationContext.Current;
var appInfoService = DependencyService.Get<IAppInfo>(); var appInfoService = DependencyService.Get<IAppInfo>();
var smartDevice = DependencyService.Get<ISmartDevice>();
const string MERCHANTID = "0000000000"; const string MERCHANTID = "0000000000";
@ -158,13 +162,14 @@ namespace TINK
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
sessionCookie, sessionCookie,
mail, mail,
smartDevice,
expiresAfter), expiresAfter),
merchantId: MERCHANTID, merchantId: MERCHANTID,
bluetoothService: BluetoothService, /* locksService */ bluetoothService: BluetoothService, /* locksService */
locationPermissionsService: PermissionsService, locationPermissionsService: PermissionsService,
locationServicesContainer: LocationServicesContainer, locationServicesContainer: LocationServicesContainer,
locksService: null, locksService: null,
device: DependencyService.Get<ISmartDevice>(), device: smartDevice,
specialFolder: specialFolders, specialFolder: specialFolders,
cipher: new Cipher(), cipher: new Cipher(),
new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries), new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries),

View file

@ -199,8 +199,8 @@
Grid.Row="13" Grid.Row="13"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="2"/>
<Label <Label
Text= "{Binding TariffDescription.InfoEntry5}" Text= "{Binding TariffDescription.TrackingInfoText}"
IsVisible="{Binding TariffDescription.InfoEntry5, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}"
Grid.Row="14" Grid.Row="14"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="2"/>
</Grid> </Grid>

View file

@ -79,7 +79,7 @@ namespace TINK.View.BikesAtStation
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -88,9 +88,6 @@ namespace TINK.View.BikesAtStation
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new BikesAtStationPageViewModel( m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -103,7 +100,7 @@ namespace TINK.View.BikesAtStation
model.LocksServices.Active, model.LocksServices.Active,
model.Polling, model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url), (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this) this)
{ {
@ -128,7 +125,7 @@ namespace TINK.View.BikesAtStation
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
BikesAtStationListView.ItemsSource = m_oViewModel; BikesAtStationListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }

View file

@ -35,7 +35,7 @@ namespace TINK.View.FindBike
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
return; return;
} }
@ -43,9 +43,6 @@ namespace TINK.View.FindBike
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new FindBikePageViewModel( m_oViewModel = new FindBikePageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -57,7 +54,7 @@ namespace TINK.View.FindBike
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -78,7 +75,7 @@ namespace TINK.View.FindBike
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
FindBikeListView.ItemsSource = m_oViewModel; FindBikeListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
} }
/// <summary> /// <summary>

View file

@ -1,4 +1,4 @@
using Plugin.Connectivity; using Plugin.Connectivity;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,7 +47,7 @@ namespace TINK.View.MyBikes
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -56,9 +56,6 @@ namespace TINK.View.MyBikes
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new MyBikesPageViewModel( m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -70,7 +67,7 @@ namespace TINK.View.MyBikes
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -91,7 +88,7 @@ namespace TINK.View.MyBikes
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
MyBikesListView.ItemsSource = m_oViewModel; MyBikesListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }
@ -183,4 +180,4 @@ namespace TINK.View.MyBikes
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving)); public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif #endif
} }
} }

View file

@ -11,7 +11,7 @@
<PackageReference Include="Plugin.BLE" Version="2.1.3" /> <PackageReference Include="Plugin.BLE" Version="2.1.3" />
<PackageReference Include="Polly" Version="7.2.3" /> <PackageReference Include="Polly" Version="7.2.3" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.4" /> <PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -154,8 +154,8 @@ namespace TINK.Services.BluetoothLock.BLE
case LockitLockingState.Unknown: case LockitLockingState.Unknown:
// Expected error. ILockIt count not be opened (Spoke has blocked/ blocks lock, ....) // Expected error. ILockIt count not be opened (Spoke has blocked/ blocks lock, ....)
Log.ForContext<LockItEventBased>().Debug($"Opening lock failed. Bold was blocked."); Log.ForContext<LockItEventBased>().Debug($"Opening lock failed. Bold status is unknown");
throw new CouldntOpenBoldWasBlockedException(); throw new CouldntOpenBoldStatusIsUnknownException();
default: default:
// Comprises values // Comprises values
@ -270,6 +270,11 @@ namespace TINK.Services.BluetoothLock.BLE
Log.ForContext<LockItEventBased>().Information($"Lock was closed successfully."); Log.ForContext<LockItEventBased>().Information($"Lock was closed successfully.");
return lockingState; return lockingState;
case LockitLockingState.Open:
// Expected error. ILockIt could not be closed. Bolt was blocked but was opened again.
Log.ForContext<LockItPolling>().Debug($"Closing lock failed. Bold is blocked but was reopened again.");
throw new CouldntCloseBoldBlockedException(LockingState.Open);
default: default:
// Comprises values // Comprises values
// - LockitLockingState.Open // - LockitLockingState.Open

View file

@ -120,8 +120,8 @@ namespace TINK.Services.BluetoothLock.BLE
case LockitLockingState.Unknown: case LockitLockingState.Unknown:
// Expected error. ILockIt count not be opened (Spoke has blocked/ blocks lock, ....) // Expected error. ILockIt count not be opened (Spoke has blocked/ blocks lock, ....)
Log.ForContext<LockItPolling>().Debug($"Opening lock failed. Bold was blocked."); Log.ForContext<LockItPolling>().Debug($"Opening lock failed. Bold status is unknown.");
throw new CouldntOpenBoldWasBlockedException(); throw new CouldntOpenBoldStatusIsUnknownException();
default: default:
// Comprises values // Comprises values
@ -181,13 +181,29 @@ namespace TINK.Services.BluetoothLock.BLE
var watch = new Stopwatch(); var watch = new Stopwatch();
watch.Start(); watch.Start();
var hasBeenLocked = false;
while (info.State != null while (info.State != null
&& info.State.Value != LockitLockingState.CouldntCloseBoldBlocked
&& info.State.Value != LockitLockingState.CouldntCloseMoving && info.State.Value != LockitLockingState.CouldntCloseMoving
&& info.State.Value != LockitLockingState.Closed && info.State.Value != LockitLockingState.Closed
&& watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS)) && watch.Elapsed < TimeSpan.FromMilliseconds(OPEN_CLOSE_TIMEOUT_MS))
{ {
info = await GetLockStateAsync(true); ; // While closing lock seems not always respond to reading operations. info = await GetLockStateAsync(true); ; // While closing lock seems not always respond to reading operations.
if (info.State.Value == LockitLockingState.CouldntCloseBoldBlocked)
{
// Lock reported a blocked bold.
hasBeenLocked = true;
Log.ForContext<LockItPolling>().Debug($"Waiting for lock to close. Bold is blocked.");
continue;
}
if (hasBeenLocked && info.State.Value == LockitLockingState.Open)
{
// ILockIt could not be closed. Bolt was blocked but was opened again.
Log.ForContext<LockItPolling>().Debug($"Closing lock failed. Bold was blocked and lock was reopened.");
throw new CouldntCloseBoldBlockedException(LockingState.Open);
}
Log.ForContext<LockItPolling>().Debug($"Waiting for lock to close. Current lock state is {info?.State.Value}."); Log.ForContext<LockItPolling>().Debug($"Waiting for lock to close. Current lock state is {info?.State.Value}.");
} }

View file

@ -1,4 +1,4 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// <auto-generated> // <auto-generated>
// This code was generated by a tool. // This code was generated by a tool.
// Runtime Version:4.0.30319.42000 // Runtime Version:4.0.30319.42000
@ -144,18 +144,18 @@ namespace TINK.MultilingualResources {
/// <summary> /// <summary>
/// Looks up a localized string similar to Bold is blocked.. /// Looks up a localized string similar to Bold is blocked..
/// </summary> /// </summary>
internal static string ErrorOpenLockBoldBlocked { internal static string ErrorOpenLockBoldIsBlocked {
get { get {
return ResourceManager.GetString("ErrorOpenLockBoldBlocked", resourceCulture); return ResourceManager.GetString("ErrorOpenLockBoldIsBlocked", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Bold was or is blocked.. /// Looks up a localized string similar to Bold status is unknown..
/// </summary> /// </summary>
internal static string ErrorOpenLockBoldWasBlocked { internal static string ErrorOpenLockBoldStatusIsUnknown {
get { get {
return ResourceManager.GetString("ErrorOpenLockBoldWasBlocked", resourceCulture); return ResourceManager.GetString("ErrorOpenLockBoldStatusIsUnknown", resourceCulture);
} }
} }

View file

@ -1,11 +1,20 @@
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
namespace TINK.Services.BluetoothLock.Exception namespace TINK.Services.BluetoothLock.Exception
{ {
public class CouldntCloseBoldBlockedException : StateAwareException public class CouldntCloseBoldBlockedException : StateAwareException
{ {
public CouldntCloseBoldBlockedException() : base( /// <summary>
LockingState.UnknownFromHardwareError, // Lock is closed in most cases, but this is not guaranteed according to haveltec. /// Constructs a bold blocked exception.
/// </summary>
/// <remarks>
/// Lock is closed in most cases, but this is not guaranteed according to haveltec.
/// </remarks>
/// <param name="state">State of the lock while/ after bold blocked event.</param>
/// <remarks>
/// </remarks>
public CouldntCloseBoldBlockedException(LockingState state = LockingState.UnknownFromHardwareError) : base(
state,
MultilingualResources.Resources.ErrorCloseLockBoldBlocked) MultilingualResources.Resources.ErrorCloseLockBoldBlocked)
{ {
} }

View file

@ -1,4 +1,4 @@
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
namespace TINK.Services.BluetoothLock.Exception namespace TINK.Services.BluetoothLock.Exception
{ {
@ -9,7 +9,7 @@ namespace TINK.Services.BluetoothLock.Exception
{ {
public CouldntOpenBoldIsBlockedException() : base( public CouldntOpenBoldIsBlockedException() : base(
LockingState.UnknownFromHardwareError, LockingState.UnknownFromHardwareError,
MultilingualResources.Resources.ErrorOpenLockBoldBlocked) MultilingualResources.Resources.ErrorOpenLockBoldIsBlocked)
{ {
} }
} }

View file

@ -1,15 +1,15 @@
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
namespace TINK.Services.BluetoothLock.Exception namespace TINK.Services.BluetoothLock.Exception
{ {
/// <summary> /// <summary>
/// Lock can not be opened, because bold is/ was blocked. Obstacle might no more block but lock could not be opened completely to obstacle. /// Lock can not be opened, because bold is/ was blocked. Obstacle might no more block but lock could not be opened completely to obstacle.
/// </summary> /// </summary>
public class CouldntOpenBoldWasBlockedException : StateAwareException public class CouldntOpenBoldStatusIsUnknownException : StateAwareException
{ {
public CouldntOpenBoldWasBlockedException() : base( public CouldntOpenBoldStatusIsUnknownException() : base(
LockingState.UnknownFromHardwareError, LockingState.UnknownFromHardwareError,
MultilingualResources.Resources.ErrorOpenLockBoldWasBlocked) MultilingualResources.Resources.ErrorOpenLockBoldStatusIsUnknown)
{ {
} }
} }

View file

@ -11,20 +11,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItShared", "..\LockItSh
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItShared", "..\TestLockItShared\TestLockItShared.csproj", "{7E25F58E-62E3-48D7-8115-E33DA67C511E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestShareeLib", "..\TestShareeLib\TestShareeLib.csproj", "{38F340AD-EC12-4BB2-8633-AC5B55C32B77}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItBLE", "..\TestLockItBLE\TestLockItBLE.csproj", "{2581E9AD-4F56-431A-AB87-1B6D80D546AA}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Meinkonrad", "TINK\Meinkonrad.shproj", "{5CF95CB1-AD37-4DBA-8B9D-651CFB9EB903}" Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Meinkonrad", "TINK\Meinkonrad.shproj", "{5CF95CB1-AD37-4DBA-8B9D-651CFB9EB903}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meinkonrad.iOS", "TINK.iOS\Meinkonrad.iOS.csproj", "{CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meinkonrad.iOS", "TINK.iOS\Meinkonrad.iOS.csproj", "{CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSharee", "..\TestSharee\TestSharee.csproj", "{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
@ -245,150 +237,6 @@ Global
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.Build.0 = Release|Any CPU
{CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhoneSimulator {CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|Any CPU.ActiveCfg = Ad-Hoc|iPhoneSimulator
{CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhoneSimulator {CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|ARM.ActiveCfg = Ad-Hoc|iPhoneSimulator
{CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone {CF1B848A-D1DF-40AB-BA6F-B1E1746A1161}.Ad-Hoc|iPhone.ActiveCfg = Ad-Hoc|iPhone
@ -469,54 +317,6 @@ Global
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -527,6 +327,7 @@ Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution GlobalSection(SharedMSBuildProjectFiles) = preSolution
TINK\Meinkonrad.projitems*{5cf95cb1-ad37-4dba-8b9d-651cfb9eb903}*SharedItemsImports = 13 TINK\Meinkonrad.projitems*{5cf95cb1-ad37-4dba-8b9d-651cfb9eb903}*SharedItemsImports = 13
TINK\Meinkonrad.projitems*{cf1b848a-d1df-40ab-ba6f-b1e1746a1161}*SharedItemsImports = 4 TINK\Meinkonrad.projitems*{cf1b848a-d1df-40ab-ba6f-b1e1746a1161}*SharedItemsImports = 4
..\ShareeSharedGuiLib\ShareeSharedGuiLib.projitems*{cf1b848a-d1df-40ab-ba6f-b1e1746a1161}*SharedItemsImports = 4
EndGlobalSection EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0 Policies = $0

View file

@ -57,7 +57,7 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>None</AndroidLinkMode>
<AotAssemblies>false</AotAssemblies> <AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM> <EnableLLVM>false</EnableLLVM>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
@ -176,16 +176,16 @@
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.AndroidX.Core"> <PackageReference Include="Xamarin.AndroidX.Core">
<Version>1.9.0.1</Version> <Version>1.9.0.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.MediaRouter"> <PackageReference Include="Xamarin.AndroidX.MediaRouter">
<Version>1.3.1.1</Version> <Version>1.3.1.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.Palette"> <PackageReference Include="Xamarin.AndroidX.Palette">
<Version>1.0.0.15</Version> <Version>1.0.0.16</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView"> <PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.8</Version> <Version>1.2.1.9</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" /> <PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" /> <PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -193,7 +193,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms.AppLinks"> <PackageReference Include="Xamarin.Forms.AppLinks">
@ -203,10 +203,10 @@
<Version>5.0.0</Version> <Version>5.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" /> <PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0.2" />
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2" /> <PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.357" android:versionCode="357"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.TeilRad.Meinkonrad" android:versionName="3.0.360" android:versionCode="360">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions --> <!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services --> <!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Mein konrad</string> <string>Mein konrad</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>357</string> <string>360</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.357</string> <string>3.0.360</string>
</dict> </dict>
</plist> </plist>

View file

@ -25,7 +25,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<MtouchArch>x86_64</MtouchArch> <MtouchArch>x86_64</MtouchArch>
<MtouchLink>None</MtouchLink> <MtouchLink>SdkOnly</MtouchLink>
<MtouchDebug>true</MtouchDebug> <MtouchDebug>true</MtouchDebug>
<CodesignProvision>Automatic</CodesignProvision> <CodesignProvision>Automatic</CodesignProvision>
<CodesignKey>Apple Development: Oliver Hauff (947JH7MS9L)</CodesignKey> <CodesignKey>Apple Development: Oliver Hauff (947JH7MS9L)</CodesignKey>
@ -201,7 +201,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps"> <PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version> <Version>5.0.0</Version>

View file

@ -27,10 +27,10 @@
<x:String x:Key="EyeOpen">&#xf06e;</x:String> <x:String x:Key="EyeOpen">&#xf06e;</x:String>
<x:String x:Key="EyeClose">&#xf070;</x:String> <x:String x:Key="EyeClose">&#xf070;</x:String>
<!--Triangle exclamation--> <!--Arrow down from line-->
<x:String x:Key="Attention">&#xf071;</x:String> <x:String x:Key="ArrowDown">&#xf063;</x:String>
<!-- Add more resources here --> <!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<!-- Add more resource dictionaries here --> <!-- Add more resource dictionaries here -->
<themes:Konrad/> <themes:Konrad/>

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@ -125,6 +125,8 @@ namespace TINK
Log.Debug("Get auth cookie."); Log.Debug("Get auth cookie.");
IStore store = null; IStore store = null;
// Version of last version used or null for initial installation.
// Used for updating purposes.
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON); var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (new Version(3, 0, 290) <= lastVersion) if (new Version(3, 0, 290) <= lastVersion)
{ {
@ -138,9 +140,11 @@ namespace TINK
Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
// Get main thread synchronization context to be able to update gui elements from worker threads.
var context = SynchronizationContext.Current; var context = SynchronizationContext.Current;
var appInfoService = DependencyService.Get<IAppInfo>(); var appInfoService = DependencyService.Get<IAppInfo>();
var smartDevice = DependencyService.Get<ISmartDevice>();
const string MERCHANTID = "0000000000"; const string MERCHANTID = "0000000000";
@ -157,13 +161,14 @@ namespace TINK
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
sessionCookie, sessionCookie,
mail, mail,
smartDevice,
expiresAfter), expiresAfter),
merchantId: MERCHANTID, merchantId: MERCHANTID,
bluetoothService: BluetoothService, /* locksService */ bluetoothService: BluetoothService, /* locksService */
locationPermissionsService: PermissionsService, locationPermissionsService: PermissionsService,
locationServicesContainer: LocationServicesContainer, locationServicesContainer: LocationServicesContainer,
locksService: null, locksService: null,
device: DependencyService.Get<ISmartDevice>(), device: smartDevice,
specialFolder: specialFolders, specialFolder: specialFolders,
cipher: new Cipher(), cipher: new Cipher(),
new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries), new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries),

View file

@ -69,32 +69,13 @@
IsVisible="{Binding IsButtonVisible}" IsVisible="{Binding IsButtonVisible}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
Command="{Binding OnButtonClicked}"/> Command="{Binding OnButtonClicked}"/>
<Button <Button
Style="{StaticResource SecondaryButton}" Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}" Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}" IsVisible="{Binding IsLockitButtonVisible}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
Command="{Binding OnLockitButtonClicked}"/> Command="{Binding OnLockitButtonClicked}"/>
<!--Hint for Cache Daten.--> <!-- Rental description (tarif name, options and rental info -->
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding IsDataFromCache}">
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource Attention}"
Color="Red"
FontFamily="FA-S"
Size="Small"/>
</Image.Source>
</Image>
<Label
TextColor="Red"
FontSize="Small"
Text="{x:Static resources:AppResources.MarkingDataIsFromCache}"/>
</StackLayout>
<!-- Rental description (tarif name, options and rental info -->
<Grid <Grid
RowSpacing="0" RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"> IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
@ -237,8 +218,8 @@
Grid.Row="13" Grid.Row="13"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="2"/>
<Label <Label
Text= "{Binding TariffDescription.InfoEntry5}" Text= "{Binding TariffDescription.TrackingInfoText}"
IsVisible="{Binding TariffDescription.InfoEntry5, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}"
Grid.Row="14" Grid.Row="14"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="2"/>
</Grid> </Grid>

View file

@ -27,93 +27,108 @@
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<Frame <StackLayout Grid.Row="0" Spacing="0">
Grid.Row="0">
<!-- Grid for Content --> <!--No Network Connection-->
<Grid <sharedGui:NotConnectedToNetView/>
RowDefinitions="Auto,1*,Auto,Auto">
<!--Station--> <Frame>
<StackLayout
Grid.Row="0"
Orientation="Vertical">
<!--Title--> <!-- Grid for Content -->
<Label <Grid
HorizontalOptions="Center" RowDefinitions="Auto,1*,Auto,Auto">
FontAttributes="Bold"
TextColor="{DynamicResource primary-back-title-color}"
Text="{Binding StationDetailText}"/>
<!--Line--> <!--Station-->
<BoxView <StackLayout
HeightRequest="1" Orientation="Vertical">
Color="{DynamicResource primary-back-title-color}"/>
</StackLayout> <!--Title-->
<Label
HorizontalOptions="Center"
FontAttributes="Bold"
TextColor="{DynamicResource primary-back-title-color}"
Text="{Binding StationDetailText}"/>
<!--Bike(s)--> <!--Line-->
<ListView Grid.Row="1" <BoxView
x:Name="BikesAtStationListView" HeightRequest="1"
SelectionMode="None" Color="{DynamicResource primary-back-title-color}"/>
SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True"
ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/>
<!--No Bikes--> </StackLayout>
<Label Grid.Row="1"
IsVisible="{Binding IsNoBikesAtStationVisible}"
Text="{Binding NoBikesAtStationText}"/>
<!--Info text--> <!--Bike(s)-->
<Label <StackLayout
Grid.Row="2" Spacing="0"
Text="{Binding StatusInfoText}" Grid.Row="1"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding IsBikesListVisible}"
FontSize="Small" Orientation="Vertical">
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/>
<!-- Contact and Login at end of page--> <!--Hint for Outdated Data.-->
<StackLayout <sharedGui:HintForRefreshingPageView/>
Grid.Row="3"
Orientation="Vertical">
<!--Line--> <ListView
<BoxView x:Name="BikesAtStationListView"
HeightRequest="1" SelectionMode="None"
Color="{DynamicResource primary-back-title-color}"/> SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}"
HasUnevenRows="True"
ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/>
<!--Contact to operator--> </StackLayout>
<Label
TextType="Html"
Text="{Binding ContactSupportHintText}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ContactSupportClickedCommand}"/>
</Label.GestureRecognizers>
</Label>
<!--Login required--> <!--No Bikes-->
<Label <Label
IsVisible="{Binding IsLoginRequiredHintVisible}" IsVisible="{Binding IsNoBikesAtStationVisible}"
TextType="Html" Text="{Binding NoBikesAtStationText}"/>
Text="{Binding LoginRequiredHintText}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LoginRequiredHintClickedCommand}"/>
</Label.GestureRecognizers>
</Label>
</StackLayout> <!--Info text-->
<Label
Grid.Row="2"
Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
FontSize="Small"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/>
</Grid> <!-- Contact and Login at end of page-->
<StackLayout
Grid.Row="3"
Orientation="Vertical">
</Frame> <!--Line-->
<BoxView
HeightRequest="1"
Color="{DynamicResource primary-back-title-color}"/>
<!--Contact to operator-->
<Label
TextType="Html"
Text="{Binding ContactSupportHintText}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ContactSupportClickedCommand}"/>
</Label.GestureRecognizers>
</Label>
<!--Login required-->
<Label
IsVisible="{Binding IsLoginRequiredHintVisible}"
TextType="Html"
Text="{Binding LoginRequiredHintText}">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LoginRequiredHintClickedCommand}"/>
</Label.GestureRecognizers>
</Label>
</StackLayout>
</Grid>
</Frame>
</StackLayout>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -80,7 +80,7 @@ namespace TINK.View.BikesAtStation
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -89,9 +89,6 @@ namespace TINK.View.BikesAtStation
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new BikesAtStationPageViewModel( m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -104,7 +101,7 @@ namespace TINK.View.BikesAtStation
model.LocksServices.Active, model.LocksServices.Active,
model.Polling, model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url), (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this) this)
{ {
@ -129,7 +126,7 @@ namespace TINK.View.BikesAtStation
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
BikesAtStationListView.ItemsSource = m_oViewModel; BikesAtStationListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }

View file

@ -23,44 +23,56 @@
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<StackLayout Grid.Row="0">
<Frame <!--No Network Connection-->
Grid.Row="0"> <sharedGui:NotConnectedToNetView/>
<Grid <Frame>
<Grid
RowDefinitions="1*,32"> RowDefinitions="1*,32">
<!--Search bike--> <!--Search bike-->
<StackLayout Grid.Row="0"> <StackLayout>
<Entry <Entry
Placeholder="{x:Static resources:AppResources.PlaceholderFindBike}" Placeholder="{x:Static resources:AppResources.PlaceholderFindBike}"
IsVisible="{Binding IsSelectBikeVisible}" IsVisible="{Binding IsSelectBikeVisible}"
MaxLength="10" MaxLength="10"
CursorPosition="0" CursorPosition="0"
Text="{Binding BikeIdUserInput}"/> Text="{Binding BikeIdUserInput}"/>
<Button <Button
Text="{x:Static resources:AppResources.MarkingFindBike}" Text="{x:Static resources:AppResources.MarkingFindBike}"
IsEnabled="{Binding IsSelectBikeEnabled}" IsEnabled="{Binding IsSelectBikeEnabled}"
IsVisible="{Binding IsSelectBikeVisible}" IsVisible="{Binding IsSelectBikeVisible}"
Command="{Binding OnSelectBikeRequest}"/> Command="{Binding OnSelectBikeRequest}"/>
<ListView <StackLayout
Spacing="0"
IsVisible="{Binding IsBikesListVisible}"
Orientation="Vertical">
<!--Hint for Outdated Data.-->
<sharedGui:HintForRefreshingPageView/>
<ListView
x:Name="FindBikeListView" x:Name="FindBikeListView"
SelectionMode="None" SelectionMode="None"
SelectedItem="{Binding SelectedBike}" SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True" HasUnevenRows="True"
ItemTemplate="{StaticResource bikeTemplateSelector}" ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True" IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}" RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/> IsRefreshing="{Binding IsRefreshing}"/>
</StackLayout> </StackLayout>
<!--Info text--> </StackLayout>
<Label
<!--Info text-->
<Label
Grid.Row="1" Grid.Row="1"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
@ -68,9 +80,11 @@
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid> </Grid>
</Frame> </Frame>
</StackLayout>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -34,7 +34,7 @@ namespace TINK.View.FindBike
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
return; return;
} }
@ -42,9 +42,6 @@ namespace TINK.View.FindBike
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new FindBikePageViewModel( m_oViewModel = new FindBikePageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -56,7 +53,7 @@ namespace TINK.View.FindBike
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -77,7 +74,7 @@ namespace TINK.View.FindBike
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
FindBikeListView.ItemsSource = m_oViewModel; FindBikeListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
} }
/// <summary> /// <summary>

View file

@ -20,14 +20,22 @@
<ContentPage.Content> <ContentPage.Content>
<!--Grid for Map with Buttons and Running process--> <!--Grid for Map with Buttons and Running process-->
<Grid <Grid>
<StackLayout
Spacing="0"
Grid.Row="0">
<sharedGui:NotConnectedToNetView/>
<Grid Grid.Row="1"
RowDefinitions="3,46,1*,32" RowDefinitions="3,46,1*,32"
ColumnDefinitions="1*,Auto,1*" ColumnDefinitions="1*,Auto,1*"
IsEnabled="{Binding IsMapPageEnabled}" IsEnabled="{Binding IsMapPageEnabled}"
VerticalOptions="FillAndExpand"> VerticalOptions="FillAndExpand">
<!--Map--> <!--Map-->
<maps:Map <maps:Map
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
WidthRequest="320" WidthRequest="320"
@ -35,14 +43,14 @@
x:Name="MyMap" x:Name="MyMap"
MyLocationEnabled="True" MyLocationEnabled="True"
MapType="Street"> MapType="Street">
<maps:Map.Behaviors> <maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}"/> <bindings:BindingPinsBehavior Value="{Binding Pins}"/>
<bindings:PinClickedToCommandBehavior Command="{Binding PinClickedCommand}"/> <bindings:PinClickedToCommandBehavior Command="{Binding PinClickedCommand}"/>
</maps:Map.Behaviors> </maps:Map.Behaviors>
</maps:Map> </maps:Map>
<!--Buttons for choosing bike type--> <!--Buttons for choosing bike type-->
<Frame <Frame
CornerRadius="13" CornerRadius="13"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
@ -50,11 +58,11 @@
Padding="0" Padding="0"
IsVisible="{Binding IsNavBarVisible}" IsVisible="{Binding IsNavBarVisible}"
BackgroundColor="{DynamicResource secondary-back-title-color}"> BackgroundColor="{DynamicResource secondary-back-title-color}">
<StackLayout <StackLayout
Orientation="Horizontal" Orientation="Horizontal"
Margin="0" Margin="0"
Padding="0"> Padding="0">
<Button <Button
x:Name="KonradButton" x:Name="KonradButton"
AutomationId ="FilterKonrad_button" AutomationId ="FilterKonrad_button"
Text="{x:Static resources:AppResources.MarkingCityBike}" Text="{x:Static resources:AppResources.MarkingCityBike}"
@ -72,8 +80,8 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold" FontAttributes="Bold"
TextColor="{Binding NoKonradColor}"> TextColor="{Binding NoKonradColor}">
</Button> </Button>
<Button <Button
x:Name="TINKButton" x:Name="TINKButton"
AutomationId ="FilterTINK_button" AutomationId ="FilterTINK_button"
Text="{x:Static resources:AppResources.MarkingCargoBike}" Text="{x:Static resources:AppResources.MarkingCargoBike}"
@ -91,12 +99,12 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold" FontAttributes="Bold"
TextColor="{Binding NoTinkColor}"> TextColor="{Binding NoTinkColor}">
</Button> </Button>
</StackLayout> </StackLayout>
</Frame> </Frame>
<!--Info text--> <!--Info text-->
<Label <Label
Grid.Row="3" Grid.Row="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
@ -106,11 +114,14 @@
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid>
</StackLayout>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView
IsVisible="{Binding IsProcessWithRunningProcessView}" IsVisible="{Binding IsProcessWithRunningProcessView}"
Grid.RowSpan="4" Grid.Row="0"/>
Grid.ColumnSpan="3"/>
</Grid> </Grid>

View file

@ -27,35 +27,47 @@
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<Frame <StackLayout Grid.Row="0">
Grid.Row="0">
<!--Bike(s) view--> <!--No Network Connection-->
<Grid <sharedGui:NotConnectedToNetView/>
<Frame>
<!--Bike(s) view-->
<Grid
RowDefinitions="1*,32"> RowDefinitions="1*,32">
<!--Bike(s)--> <!--Bike(s)-->
<ListView <StackLayout
Grid.Row="0" Spacing="0"
IsVisible="{Binding IsBikesListVisible}"
Orientation="Vertical">
<!--Hint for Outdated Data.-->
<sharedGui:HintForRefreshingPageView/>
<ListView
x:Name="MyBikesListView" x:Name="MyBikesListView"
SelectionMode="None" SelectionMode="None"
SelectedItem="{Binding SelectedBike}" SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True" HasUnevenRows="True"
ItemTemplate="{StaticResource bikeTemplateSelector}" ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True" IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}" RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/> IsRefreshing="{Binding IsRefreshing}"/>
<!--No Bikes--> </StackLayout>
<Label
<!--No Bikes-->
<Label
Grid.Row="0" Grid.Row="0"
IsVisible="{Binding IsNoBikesOccupiedVisible}" IsVisible="{Binding IsNoBikesOccupiedVisible}"
Text="{Binding NoBikesOccupiedText}"/> Text="{Binding NoBikesOccupiedText}"/>
<!--Info text--> <!--Info text-->
<Label <Label
Grid.Row="1" Grid.Row="1"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
@ -63,9 +75,11 @@
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid> </Grid>
</Frame> </Frame>
</StackLayout>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -1,4 +1,4 @@
using Plugin.Connectivity; using Plugin.Connectivity;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,7 +47,7 @@ namespace TINK.View.MyBikes
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -56,9 +56,6 @@ namespace TINK.View.MyBikes
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new MyBikesPageViewModel( m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -70,7 +67,7 @@ namespace TINK.View.MyBikes
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -91,7 +88,7 @@ namespace TINK.View.MyBikes
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
MyBikesListView.ItemsSource = m_oViewModel; MyBikesListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }
@ -183,4 +180,4 @@ namespace TINK.View.MyBikes
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving)); public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif #endif
} }
} }

View file

@ -21,6 +21,7 @@
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\Bar.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModel\Bar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\BarLevelInputViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModel\BarLevelInputViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\BarLevelViewModel.cs" /> <Compile Include="$(MSBuildThisFileDirectory)ViewModel\BarLevelViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ViewModel\NotConnectedToNetViewModel.cs" />
<Compile Include="$(MSBuildThisFileDirectory)View\BarLevelInputView.xaml.cs"> <Compile Include="$(MSBuildThisFileDirectory)View\BarLevelInputView.xaml.cs">
<DependentUpon>BarLevelInputView.xaml</DependentUpon> <DependentUpon>BarLevelInputView.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
@ -29,6 +30,12 @@
<DependentUpon>BarLevelView.xaml</DependentUpon> <DependentUpon>BarLevelView.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="$(MSBuildThisFileDirectory)View\HintForRefreshingPageView.xaml.cs">
<DependentUpon>HintForRefreshingPageView.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)View\NotConnectedToNetView.xaml.cs">
<DependentUpon>NotConnectedToNetView.xaml</DependentUpon>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)View\RunningProcessView.xaml.cs"> <Compile Include="$(MSBuildThisFileDirectory)View\RunningProcessView.xaml.cs">
<DependentUpon>RunningProcessView.xaml</DependentUpon> <DependentUpon>RunningProcessView.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
@ -67,4 +74,16 @@
<Generator>MSBuild:UpdateDesignTimeXaml</Generator> <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)View\NotConnectedToNetView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="$(MSBuildThisFileDirectory)View\HintForRefreshingPageView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project> </Project>

View file

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib"
x:Class="ShareeSharedGuiLib.View.HintForRefreshingPageView">
<StackLayout
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding IsBikesDataOutdatedLabelVisible}"
Padding="0"
Spacing="0"
Margin="0">
<StackLayout.Triggers>
<DataTrigger TargetType="StackLayout"
Binding="{Binding IsBikesDataOutdatedLabelVisible}"
Value="false">
<Setter Property="HeightRequest" Value="0" />
</DataTrigger>
</StackLayout.Triggers>
<Image>
<Image.Source>
<FontImageSource
Glyph="{StaticResource ArrowDown}"
Color="DimGray"
FontFamily="FA-S"
Size="Small"/>
</Image.Source>
</Image>
<Label
TextColor="DimGray"
FontSize="Small"
Padding="5"
Text="{x:Static resources:AppResources.MarkingDataIsFromCache}"/>
</StackLayout>
</ContentView>

View file

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ShareeSharedGuiLib.ViewModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ShareeSharedGuiLib.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HintForRefreshingPageView : ContentView
{
public HintForRefreshingPageView()
{
InitializeComponent();
this.BindingContext = new NotConnectedToNetViewModel();
}
}
}

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib"
x:Class="ShareeSharedGuiLib.View.NotConnectedToNetView">
<StackLayout
BackgroundColor="{x:DynamicResource attention-color}"
IsVisible="{Binding IsNotConnectedToNet}"
Padding="0"
Spacing="0"
Margin="0">
<StackLayout.Triggers>
<DataTrigger TargetType="StackLayout"
Binding="{Binding IsNotConnectedToNet}"
Value="false">
<Setter Property="HeightRequest" Value="0" />
</DataTrigger>
</StackLayout.Triggers>
<Label Text="{x:Static resources:AppResources.MarkingNoNetworkConnection}"
TextColor="White"
FontSize="Small"
Padding="5"
HorizontalTextAlignment="Center"
HorizontalOptions="CenterAndExpand"/>
</StackLayout>
</ContentView>

View file

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ShareeSharedGuiLib.ViewModel;
using Xamarin.Essentials;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ShareeSharedGuiLib.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NotConnectedToNetView : ContentView, INotifyPropertyChanged
{
public NotConnectedToNetView()
{
InitializeComponent();
this.BindingContext = new NotConnectedToNetViewModel();
}
}
}

View file

@ -0,0 +1,54 @@
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using TINK.MultilingualResources;
using Xamarin.Essentials;
namespace ShareeSharedGuiLib.ViewModel
{
public class NotConnectedToNetViewModel : INotifyPropertyChanged
{
public bool IsNotConnectedToNet { get; set; }
private bool _isBikesDataOutdatedLabelVisible = false;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsBikesDataOutdatedLabelVisible
{
get { return _isBikesDataOutdatedLabelVisible; }
set
{
_isBikesDataOutdatedLabelVisible = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBikesDataOutdatedLabelVisible)));
}
}
public NotConnectedToNetViewModel()
{
IsNotConnectedToNet = Connectivity.NetworkAccess != NetworkAccess.Internet;
// Register for connectivity changes, be sure to unsubscribe when finished
Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
}
public async void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
IsNotConnectedToNet = e.NetworkAccess != NetworkAccess.Internet;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsNotConnectedToNet)));
if (IsNotConnectedToNet)
{
IsBikesDataOutdatedLabelVisible = false;
}
else
{
IsBikesDataOutdatedLabelVisible = true;
await Task.Delay(TimeSpan.FromSeconds(5));
IsBikesDataOutdatedLabelVisible = false;
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsBikesDataOutdatedLabelVisible)));
}
}
}

View file

@ -15,21 +15,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItShared", "..\LockItSh
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LockItBLE", "..\LockItBLE\LockItBLE.csproj", "{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItShared", "..\TestLockItShared\TestLockItShared.csproj", "{7E25F58E-62E3-48D7-8115-E33DA67C511E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestShareeLib", "..\TestShareeLib\TestShareeLib.csproj", "{38F340AD-EC12-4BB2-8633-AC5B55C32B77}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestLockItBLE", "..\TestLockItBLE\TestLockItBLE.csproj", "{2581E9AD-4F56-431A-AB87-1B6D80D546AA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestFramework", "..\TestFramework\TestFramework.csproj", "{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestSharee", "..\TestSharee\TestSharee.csproj", "{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}"
EndProject
Global Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
TINK\TINK.projitems*{5297504f-603f-4e1a-98aa-57c4a0d9d833}*SharedItemsImports = 13
TINK\TINK.projitems*{f2d8208f-a8bf-4403-b0ae-2a1d270e4dc9}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Ad-Hoc|Any CPU = Ad-Hoc|Any CPU Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
Ad-Hoc|ARM = Ad-Hoc|ARM Ad-Hoc|ARM = Ad-Hoc|ARM
@ -282,150 +270,6 @@ Global
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x64.Build.0 = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.ActiveCfg = Release|Any CPU
{BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU {BDE9CE26-15CF-47DA-A4F6-B6956D02D0FC}.Release|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.AppStore|x86.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|ARM.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhone.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x64.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.ActiveCfg = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Debug|x86.Build.0 = Debug|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|Any CPU.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|ARM.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhone.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x64.Build.0 = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.ActiveCfg = Release|Any CPU
{7E25F58E-62E3-48D7-8115-E33DA67C511E}.Release|x86.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.AppStore|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|ARM.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhone.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x64.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.ActiveCfg = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Debug|x86.Build.0 = Debug|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|Any CPU.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|ARM.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhone.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x64.Build.0 = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.ActiveCfg = Release|Any CPU
{38F340AD-EC12-4BB2-8633-AC5B55C32B77}.Release|x86.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.AppStore|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|ARM.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhone.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x64.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.ActiveCfg = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Debug|x86.Build.0 = Debug|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|Any CPU.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|ARM.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhone.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x64.Build.0 = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.ActiveCfg = Release|Any CPU
{2581E9AD-4F56-431A-AB87-1B6D80D546AA}.Release|x86.Build.0 = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
@ -474,54 +318,6 @@ Global
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x64.Build.0 = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.ActiveCfg = Release|Any CPU
{9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU {9EA4ED8C-C4C3-48DC-8CBE-9281E0A7CA8D}.Release|x86.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Ad-Hoc|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.AppStore|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|ARM.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhone.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x64.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.ActiveCfg = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Debug|x86.Build.0 = Debug|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|Any CPU.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|ARM.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhone.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x64.Build.0 = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.ActiveCfg = Release|Any CPU
{9C80A989-4BBB-4F00-AB5D-45B1F99D5A08}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -529,6 +325,11 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C6529CD7-C3F7-4E80-89B5-002E2B8E3EB5} SolutionGuid = {C6529CD7-C3F7-4E80-89B5-002E2B8E3EB5}
EndGlobalSection EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
TINK\TINK.projitems*{5297504f-603f-4e1a-98aa-57c4a0d9d833}*SharedItemsImports = 13
..\ShareeSharedGuiLib\ShareeSharedGuiLib.projitems*{f2d8208f-a8bf-4403-b0ae-2a1d270e4dc9}*SharedItemsImports = 4
TINK\TINK.projitems*{f2d8208f-a8bf-4403-b0ae-2a1d270e4dc9}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0 Policies = $0
$0.DotNetNamingPolicy = $1 $0.DotNetNamingPolicy = $1

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.hauffware.sharee" android:versionName="3.0.357" android:versionCode="357"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:installLocation="internalOnly" package="com.hauffware.sharee" android:versionName="3.0.360" android:versionCode="360">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" /> <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="31" />
<!-- Google Maps related permissions --> <!-- Google Maps related permissions -->
<!-- Permission to receive remote notifications from Google Play Services --> <!-- Permission to receive remote notifications from Google Play Services -->

View file

@ -57,7 +57,7 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<AndroidUseSharedRuntime>False</AndroidUseSharedRuntime> <AndroidUseSharedRuntime>False</AndroidUseSharedRuntime>
<AndroidLinkMode>SdkOnly</AndroidLinkMode> <AndroidLinkMode>None</AndroidLinkMode>
<AotAssemblies>false</AotAssemblies> <AotAssemblies>false</AotAssemblies>
<EnableLLVM>false</EnableLLVM> <EnableLLVM>false</EnableLLVM>
<AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot>
@ -176,16 +176,16 @@
<PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.v7.RecyclerView" Version="28.0.0.3" />
<PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" /> <PackageReference Include="Xamarin.Android.Support.Vector.Drawable" Version="28.0.0.3" />
<PackageReference Include="Xamarin.AndroidX.Core"> <PackageReference Include="Xamarin.AndroidX.Core">
<Version>1.9.0.1</Version> <Version>1.9.0.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.MediaRouter"> <PackageReference Include="Xamarin.AndroidX.MediaRouter">
<Version>1.3.1.1</Version> <Version>1.3.1.2</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.Palette"> <PackageReference Include="Xamarin.AndroidX.Palette">
<Version>1.0.0.15</Version> <Version>1.0.0.16</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.AndroidX.RecyclerView"> <PackageReference Include="Xamarin.AndroidX.RecyclerView">
<Version>1.2.1.8</Version> <Version>1.2.1.9</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Auth" Version="1.7.0" /> <PackageReference Include="Xamarin.Auth" Version="1.7.0" />
<PackageReference Include="Xamarin.Build.Download" Version="0.11.4" /> <PackageReference Include="Xamarin.Build.Download" Version="0.11.4" />
@ -193,7 +193,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms.AppLinks"> <PackageReference Include="Xamarin.Forms.AppLinks">
@ -203,10 +203,10 @@
<Version>5.0.0</Version> <Version>5.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" /> <PackageReference Include="Xamarin.Forms.GoogleMaps.Bindings" Version="3.0.0" />
<PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Base" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Basement" Version="118.1.0.2" />
<PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0" /> <PackageReference Include="Xamarin.GooglePlayServices.Maps" Version="118.1.0.1" />
<PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2" /> <PackageReference Include="Xamarin.GooglePlayServices.Tasks" Version="118.0.2.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Mono.Android" /> <Reference Include="Mono.Android" />

View file

@ -56,8 +56,8 @@
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>sharee.bike</string> <string>sharee.bike</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>357</string> <string>360</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>3.0.357</string> <string>3.0.360</string>
</dict> </dict>
</plist> </plist>

View file

@ -25,7 +25,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause> <ConsolePause>false</ConsolePause>
<MtouchArch>x86_64</MtouchArch> <MtouchArch>x86_64</MtouchArch>
<MtouchLink>None</MtouchLink> <MtouchLink>SdkOnly</MtouchLink>
<MtouchDebug>true</MtouchDebug> <MtouchDebug>true</MtouchDebug>
<CodesignProvision>VS: com.TeilRad.sharee.bike Development</CodesignProvision> <CodesignProvision>VS: com.TeilRad.sharee.bike Development</CodesignProvision>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey> <CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
@ -94,7 +94,7 @@
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchNoSymbolStrip> <MtouchNoSymbolStrip>
</MtouchNoSymbolStrip> </MtouchNoSymbolStrip>
<MtouchLink>SdkOnly</MtouchLink> <MtouchLink>None</MtouchLink>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
<DebugType>none</DebugType> <DebugType>none</DebugType>
@ -107,7 +107,7 @@
<CodesignProvision>VS: com.TeilRad.sharee.bike Development</CodesignProvision> <CodesignProvision>VS: com.TeilRad.sharee.bike Development</CodesignProvision>
<CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey> <CodesignKey>Apple Development: Oliver Hauff (8SZ7J9P24J)</CodesignKey>
<CodesignEntitlements>Entitlements.plist</CodesignEntitlements> <CodesignEntitlements>Entitlements.plist</CodesignEntitlements>
<MtouchLink>SdkOnly</MtouchLink> <MtouchLink>None</MtouchLink>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(RunConfiguration)' == 'Default' "> <PropertyGroup Condition=" '$(RunConfiguration)' == 'Default' ">
<AppExtensionDebugBundleId /> <AppExtensionDebugBundleId />
@ -201,7 +201,7 @@
<Version>2.0.5</Version> <Version>2.0.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Essentials"> <PackageReference Include="Xamarin.Essentials">
<Version>1.7.4</Version> <Version>1.7.5</Version>
</PackageReference> </PackageReference>
<PackageReference Include="Xamarin.Forms.GoogleMaps"> <PackageReference Include="Xamarin.Forms.GoogleMaps">
<Version>5.0.0</Version> <Version>5.0.0</Version>

View file

@ -21,14 +21,17 @@
<x:String x:Key="IconContact">&#xf0e0;</x:String> <x:String x:Key="IconContact">&#xf0e0;</x:String>
<x:String x:Key="IconInfo">&#xf05a;</x:String> <x:String x:Key="IconInfo">&#xf05a;</x:String>
<!--<x:String x:Key="IconClose">&#xf00d;</x:String>--> <!--<x:String x:Key="IconClose">&#xf00d;</x:String>-->
<x:String x:Key="IconClose">&#xf410;</x:String> <x:String x:Key="IconClose">&#xf00d;</x:String>
<!--TogglePasswortEntry--> <!--TogglePasswortEntry-->
<x:String x:Key="EyeOpen">&#xf06e;</x:String> <x:String x:Key="EyeOpen">&#xf06e;</x:String>
<x:String x:Key="EyeClose">&#xf070;</x:String> <x:String x:Key="EyeClose">&#xf070;</x:String>
<!--Triangle exclamation--> <!--Arrow down from line-->
<x:String x:Key="Attention">&#xf071;</x:String> <x:String x:Key="ArrowDown">&#xf063;</x:String>
<!--Info in Circle-->
<x:String x:Key="InfoCircle">&#xf05a;</x:String>
<!-- Add more resources here --> <!-- Add more resources here -->
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
@ -125,6 +125,8 @@ namespace TINK
Log.Debug("Get auth cookie."); Log.Debug("Get auth cookie.");
IStore store = null; IStore store = null;
// Version of last version used or null for initial installation.
// Used for updating purposes.
var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON); var lastVersion = JsonSettingsDictionary.GetAppVersion(settingsJSON);
if (new Version(3, 0, 290) <= lastVersion) if (new Version(3, 0, 290) <= lastVersion)
{ {
@ -138,9 +140,11 @@ namespace TINK
Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name; Barrel.ApplicationId = System.Reflection.Assembly.GetExecutingAssembly().GetName().Name;
// Get main thread synchronization context to be able to update gui elements from worker threads.
var context = SynchronizationContext.Current; var context = SynchronizationContext.Current;
var appInfoService = DependencyService.Get<IAppInfo>(); var appInfoService = DependencyService.Get<IAppInfo>();
var smartDevice = DependencyService.Get<ISmartDevice>();
const string MERCHANTID = "0000000000"; const string MERCHANTID = "0000000000";
@ -157,13 +161,14 @@ namespace TINK
CultureInfo.CurrentUICulture.TwoLetterISOLanguageName, CultureInfo.CurrentUICulture.TwoLetterISOLanguageName,
sessionCookie, sessionCookie,
mail, mail,
smartDevice,
expiresAfter), expiresAfter),
merchantId: MERCHANTID, merchantId: MERCHANTID,
bluetoothService: BluetoothService, /* locksService */ bluetoothService: BluetoothService, /* locksService */
locationPermissionsService: PermissionsService, locationPermissionsService: PermissionsService,
locationServicesContainer: LocationServicesContainer, locationServicesContainer: LocationServicesContainer,
locksService: null, locksService: null,
device: DependencyService.Get<ISmartDevice>(), device: smartDevice,
specialFolder: specialFolders, specialFolder: specialFolders,
cipher: new Cipher(), cipher: new Cipher(),
new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries), new TINK.Services.ThemeNS.Theme(Application.Current.Resources.MergedDictionaries),

View file

@ -9,231 +9,275 @@
mc:Ignorable="d" mc:Ignorable="d"
x:Class="TINK.View.Bike.ILockItBike"> x:Class="TINK.View.Bike.ILockItBike">
<ContentView> <ContentView>
<ContentView.Resources>
<conv:StringNotNullOrEmptyToVisibleConverter x:Key="Label_Converter"/> <ContentView.Resources>
</ContentView.Resources> <conv:StringNotNullOrEmptyToVisibleConverter x:Key="Label_Converter"/>
<StackLayout </ContentView.Resources>
Padding="10">
<Grid Padding="0,0,5,10"> <Frame
<Grid.ColumnDefinitions> Padding="10"
<ColumnDefinition Width="Auto" /> Margin="0,5,0,5"
<ColumnDefinition Width="Auto" /> HorizontalOptions="FillAndExpand"
<ColumnDefinition Width="*" /> VerticalOptions="FillAndExpand"
</Grid.ColumnDefinitions> BackgroundColor="White">
<!-- Icon of the bike -->
<Image <StackLayout
Source="{Binding DisplayedBikeImageSourceString}" Orientation="Vertical"
HeightRequest="60" Padding="10">
Aspect="AspectFit"
HorizontalOptions="Start" <!-- Icons, Name, ID -->
VerticalOptions="End" <Grid Padding="0,0,5,10"
Grid.Column="0"/> ColumnDefinitions="Auto,Auto,*"
<!-- Battery level --> RowDefinitions="Auto,Auto">
<sharedGui:BarLevelView
Current="{Binding CurrentChargeBars}" <!-- Icon of the bike -->
Maximum="{Binding MaxChargeBars}" <Image
Grid.Column="1" Grid.Column="0"
VerticalOptions="End" Grid.Row="0"
IsVisible="{Binding IsBatteryChargeVisible}"/> Grid.RowSpan="2"
<!-- Name of the bike --> Source="{Binding DisplayedBikeImageSourceString}"
<StackLayout Grid.Column="1" Grid.ColumnSpan="2"> HeightRequest="60"
<Label Aspect="AspectFit"
FontAttributes="Bold" HorizontalOptions="Start"
FontSize="Large" VerticalOptions="End"/>
HorizontalTextAlignment="Right"
Text="{Binding Name}"/> <!-- Battery level -->
<!-- Id of the bike --> <sharedGui:BarLevelView
<Label Grid.Column="1"
FontAttributes="Bold" Grid.Row="1"
HorizontalTextAlignment="Right" Current="{Binding CurrentChargeBars}"
IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}" Maximum="{Binding MaxChargeBars}"
Text="{Binding DisplayId}"/> VerticalOptions="End"
</StackLayout> IsVisible="{Binding IsBatteryChargeVisible}"/>
</Grid>
<!-- Rental state --> <!-- Name of the bike -->
<Label <Label
Text="{Binding StateText}" Grid.Column="1"
TextColor="{Binding StateColor}"/> Grid.ColumnSpan="2"
<Label Grid.Row="0"
Text="{Binding ErrorText}" FontAttributes="Bold"
IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}" FontSize="Large"
TextColor="Red"/> HorizontalTextAlignment="Right"
<Button Text="{Binding Name}"/>
Text="{Binding ButtonText}"
IsVisible="{Binding IsButtonVisible}" <!-- Id of the bike -->
Command="{Binding OnButtonClicked}"/> <Label
<Button Grid.Column="2"
Style="{StaticResource SecondaryButton}" Grid.Row="1"
Text="{Binding LockitButtonText}" FontAttributes="Bold"
IsVisible="{Binding IsLockitButtonVisible}" HorizontalTextAlignment="Right"
Command="{Binding OnLockitButtonClicked}"/> IsVisible="{Binding DisplayId, Converter={StaticResource Label_Converter}}"
<!--Hint for Cache Daten.--> Text="{Binding DisplayId}"/>
<StackLayout
Orientation="Horizontal" </Grid>
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding IsDataFromCache}"> <!-- Rental state -->
<Image> <Label
<Image.Source> Text="{Binding StateText}"
<FontImageSource TextColor="{Binding StateColor}"/>
Glyph="{StaticResource Attention}" <Label
Color="Red" Text="{Binding ErrorText}"
FontFamily="FA-S" IsVisible="{Binding ErrorText, Converter={StaticResource Label_Converter}}"
Size="Small"/> TextColor="Red"/>
</Image.Source>
</Image> <!-- Buttons -->
<Label <Button
TextColor="Red" Text="{Binding ButtonText}"
FontSize="Small" IsVisible="{Binding IsButtonVisible}"
Text="{x:Static resources:AppResources.MarkingDataIsFromCache}"/> Command="{Binding OnButtonClicked}"/>
</StackLayout> <Button
Style="{StaticResource SecondaryButton}"
Text="{Binding LockitButtonText}"
IsVisible="{Binding IsLockitButtonVisible}"
Command="{Binding OnLockitButtonClicked}"/>
<!-- Rental description (tarif name, options and rental info --> <!-- Rental description (tarif name, options and rental info -->
<Grid <Grid
RowSpacing="0" RowSpacing="0"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"> IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<!-- start tarif- entries --> <!-- start tarif- entries -->
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<!-- start rental info --> <!-- start rental info -->
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" />
<!-- start tarif- entries (should be a CollectionView) --> </Grid.ColumnDefinitions>
<Label
<!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}" Text= "{x:Static resources:AppResources.MessageBikesManagementTariffDescriptionTariffHeader}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0" Grid.Row="0"
FontAttributes="Bold"/> FontAttributes="Bold"/>
<Label <Label
Text="{Binding TariffDescription.Header}" Text="{Binding TariffDescription.Header}"
IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.Header, Converter={StaticResource Label_Converter}}"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
FontAttributes="Bold"/> FontAttributes="Bold"/>
<Label
<!--Tracking-->
<Grid
Grid.Row="0"
Grid.Column="1"
Grid.ColumnSpan="2"
ColumnDefinitions="*,Auto"
IsVisible="{Binding TariffDescription.TrackingInfoText, Converter={StaticResource Label_Converter}}">
<Label
Text= "Tracking"
FontAttributes="Bold"
Grid.Column="0"
HorizontalOptions="End"/>
<Button
Command="{Binding ShowTrackingInfoCommand}"
WidthRequest="24"
HeightRequest="24"
BackgroundColor="Transparent"
BorderWidth="0"
Grid.Column="1"
Padding="0"
Margin="0">
<Button.ImageSource>
<FontImageSource
Glyph="{StaticResource InfoCircle}"
Color="DimGray"
FontFamily="FA-S"
Size="20"/>
</Button.ImageSource>
</Button>
</Grid>
<Label
Text= "{Binding TariffDescription.TarifEntry1.Description}" Text= "{Binding TariffDescription.TarifEntry1.Description}"
IsVisible="{Binding TariffDescription.TarifEntry1.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry1.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="1"/> Grid.Row="1"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry1.Value}" Text="{Binding TariffDescription.TarifEntry1.Value}"
IsVisible="{Binding TariffDescription.TarifEntry1.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry1.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="1" Grid.Row="1"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry2.Description}" Text= "{Binding TariffDescription.TarifEntry2.Description}"
IsVisible="{Binding TariffDescription.TarifEntry2.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry2.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="2"/> Grid.Row="2"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry2.Value}" Text="{Binding TariffDescription.TarifEntry2.Value}"
IsVisible="{Binding TariffDescription.TarifEntry2.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry2.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="2" Grid.Row="2"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry3.Description}" Text= "{Binding TariffDescription.TarifEntry3.Description}"
IsVisible="{Binding TariffDescription.TarifEntry3.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry3.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="3"/> Grid.Row="3"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry3.Value}" Text="{Binding TariffDescription.TarifEntry3.Value}"
IsVisible="{Binding TariffDescription.TarifEntry3.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry3.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="3" Grid.Row="3"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry4.Description}" Text= "{Binding TariffDescription.TarifEntry4.Description}"
IsVisible="{Binding TariffDescription.TarifEntry4.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry4.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="4"/> Grid.Row="4"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry4.Value}" Text="{Binding TariffDescription.TarifEntry4.Value}"
IsVisible="{Binding TariffDescription.TarifEntry4.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry4.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="4" Grid.Row="4"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry5.Description}" Text= "{Binding TariffDescription.TarifEntry5.Description}"
IsVisible="{Binding TariffDescription.TarifEntry5.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry5.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="5"/> Grid.Row="5"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry5.Value}" Text="{Binding TariffDescription.TarifEntry5.Value}"
IsVisible="{Binding TariffDescription.TarifEntry5.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry5.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="5" Grid.Row="5"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry6.Description}" Text= "{Binding TariffDescription.TarifEntry6.Description}"
IsVisible="{Binding TariffDescription.TarifEntry6.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry6.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="6"/> Grid.Row="6"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry6.Value}" Text="{Binding TariffDescription.TarifEntry6.Value}"
IsVisible="{Binding TariffDescription.TarifEntry6.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry6.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="6" Grid.Row="6"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry7.Description}" Text= "{Binding TariffDescription.TarifEntry7.Description}"
IsVisible="{Binding TariffDescription.TarifEntry7.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry7.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="7"/> Grid.Row="7"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry7.Value}" Text="{Binding TariffDescription.TarifEntry7.Value}"
IsVisible="{Binding TariffDescription.TarifEntry7.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry7.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="7" Grid.Row="7"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry8.Description}" Text= "{Binding TariffDescription.TarifEntry8.Description}"
IsVisible="{Binding TariffDescription.TarifEntry8.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry8.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="8"/> Grid.Row="8"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry8.Value}" Text="{Binding TariffDescription.TarifEntry8.Value}"
IsVisible="{Binding TariffDescription.TarifEntry8.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry8.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="8" Grid.Row="8"
Grid.Column="1"/> Grid.Column="1"
<Label Grid.ColumnSpan="2"/>
<Label
Text= "{Binding TariffDescription.TarifEntry9.Description}" Text= "{Binding TariffDescription.TarifEntry9.Description}"
IsVisible="{Binding TariffDescription.TarifEntry9.Description, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry9.Description, Converter={StaticResource Label_Converter}}"
Grid.Row="9"/> Grid.Row="9"/>
<Label <Label
Text="{Binding TariffDescription.TarifEntry9.Value}" Text="{Binding TariffDescription.TarifEntry9.Value}"
IsVisible="{Binding TariffDescription.TarifEntry9.Value, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.TarifEntry9.Value, Converter={StaticResource Label_Converter}}"
Grid.Row="9" Grid.Row="9"
Grid.Column="1"/> Grid.Column="1"
<!-- start tarif- entries (should be a CollectionView) --> Grid.ColumnSpan="2"/>
<Label <!-- start tarif- entries (should be a CollectionView) -->
<Label
Text= "{Binding TariffDescription.InfoEntry1}" Text= "{Binding TariffDescription.InfoEntry1}"
IsVisible="{Binding TariffDescription.InfoEntry1, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.InfoEntry1, Converter={StaticResource Label_Converter}}"
Grid.Row="10" Grid.Row="10"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="3"/>
<Label <Label
Text= "{Binding TariffDescription.InfoEntry2}" Text= "{Binding TariffDescription.InfoEntry2}"
IsVisible="{Binding TariffDescription.InfoEntry2, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.InfoEntry2, Converter={StaticResource Label_Converter}}"
Grid.Row="11" Grid.Row="11"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="3"/>
<Label <Label
Text= "{Binding TariffDescription.InfoEntry3}" Text= "{Binding TariffDescription.InfoEntry3}"
IsVisible="{Binding TariffDescription.InfoEntry3, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.InfoEntry3, Converter={StaticResource Label_Converter}}"
Grid.Row="12" Grid.Row="12"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="3"/>
<Label <Label
Text= "{Binding TariffDescription.InfoEntry4}" Text= "{Binding TariffDescription.InfoEntry4}"
IsVisible="{Binding TariffDescription.InfoEntry4, Converter={StaticResource Label_Converter}}" IsVisible="{Binding TariffDescription.InfoEntry4, Converter={StaticResource Label_Converter}}"
Grid.Row="13" Grid.Row="13"
Grid.ColumnSpan="2"/> Grid.ColumnSpan="3"/>
<Label </Grid>
Text= "{Binding TariffDescription.InfoEntry5}" </StackLayout>
IsVisible="{Binding TariffDescription.InfoEntry5, Converter={StaticResource Label_Converter}}" </Frame>
Grid.Row="14" </ContentView>
Grid.ColumnSpan="2"/>
</Grid>
</StackLayout>
</ContentView>
</ViewCell> </ViewCell>

View file

@ -7,6 +7,7 @@
xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib" xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib"
xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View" xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View"
Shell.FlyoutBehavior="Disabled" Shell.FlyoutBehavior="Disabled"
BackgroundColor="#f6f6f6"
Shell.NavBarIsVisible="{Binding IsIdle}"> Shell.NavBarIsVisible="{Binding IsIdle}">
<Shell.TitleView> <Shell.TitleView>
@ -26,94 +27,118 @@
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<!-- Grid for Content -->
<Grid Grid.Row="0"
RowDefinitions="Auto,1*,Auto">
<Frame <StackLayout
Grid.Row="0"> Grid.Row="0"
Spacing="0"
<!-- Grid for Content --> Orientation="Vertical">
<Grid
RowDefinitions="Auto,1*,Auto,Auto">
<!--Station--> <!--Station-->
<StackLayout <StackLayout
Grid.Row="0" BackgroundColor="{DynamicResource primary-back-title-color}">
Orientation="Vertical">
<!--Title-->
<Label
HorizontalOptions="Center"
FontAttributes="Bold"
TextColor="{DynamicResource primary-back-title-color}"
Text="{Binding StationDetailText}"/>
<!--Line--> <!--Line-->
<BoxView <BoxView
HeightRequest="1" HeightRequest="1"
Color="{DynamicResource primary-back-title-color}"/> WidthRequest="260"
HorizontalOptions="Center"
Color="White"/>
<!--Title-->
<Label
HorizontalOptions="Center"
FontAttributes="Bold"
Padding="10,0,10,10"
TextColor="White"
Text="{Binding StationDetailText}"/>
</StackLayout> </StackLayout>
<!--No Network Connection-->
<sharedGui:NotConnectedToNetView/>
<!--Bike(s)--> <!--Bike(s)-->
<ListView Grid.Row="1" <StackLayout
IsVisible="{Binding IsBikesListVisible}"
Spacing="0">
<!--Hint for Outdated Data.-->
<sharedGui:HintForRefreshingPageView/>
<ListView Grid.Row="1"
x:Name="BikesAtStationListView" x:Name="BikesAtStationListView"
SelectionMode="None" SelectionMode="None"
SelectedItem="{Binding SelectedBike}" SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True" HasUnevenRows="True"
SeparatorVisibility="None"
ItemTemplate="{StaticResource bikeTemplateSelector}" ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True" IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}" RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/> IsRefreshing="{Binding IsRefreshing}"/>
<!--No Bikes--> </StackLayout>
<Label Grid.Row="1"
</StackLayout>
<!--No Bikes-->
<Label Grid.Row="1" Padding="10"
IsVisible="{Binding IsNoBikesAtStationVisible}" IsVisible="{Binding IsNoBikesAtStationVisible}"
Text="{Binding NoBikesAtStationText}"/> Text="{Binding NoBikesAtStationText}"/>
<StackLayout
Grid.Row="2"
Orientation="Vertical"
BackgroundColor="{DynamicResource primary-back-title-color}"
Padding="0,0,0,10">
<!--Info text--> <!--Info text-->
<Label <Label
Grid.Row="2"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
FontSize="Small" FontSize="Small"
Padding="10,5,10,0"
TextColor="White"
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
<!-- Contact and Login at end of page--> <!-- Contact and Login at end of page-->
<StackLayout <!--Line-->
Grid.Row="3" <BoxView
Orientation="Vertical">
<!--Line-->
<BoxView
HeightRequest="1" HeightRequest="1"
Color="{DynamicResource primary-back-title-color}"/> WidthRequest="260"
HorizontalOptions="Center"
Color="White"/>
<!--Contact to operator--> <!--Contact to operator-->
<Label <Label
TextType="Html" TextType="Html"
Padding="10,5,10,0"
TextColor="White"
Text="{Binding ContactSupportHintText}"> Text="{Binding ContactSupportHintText}">
<Label.GestureRecognizers> <Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ContactSupportClickedCommand}"/> <TapGestureRecognizer Command="{Binding ContactSupportClickedCommand}"/>
</Label.GestureRecognizers> </Label.GestureRecognizers>
</Label> </Label>
<!--Login required--> <!--Login required-->
<Label <Label
IsVisible="{Binding IsLoginRequiredHintVisible}" IsVisible="{Binding IsLoginRequiredHintVisible}"
TextType="Html" TextType="Html"
Padding="10,5,10,0"
TextColor="White"
Text="{Binding LoginRequiredHintText}"> Text="{Binding LoginRequiredHintText}">
<Label.GestureRecognizers> <Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LoginRequiredHintClickedCommand}"/> <TapGestureRecognizer Command="{Binding LoginRequiredHintClickedCommand}"/>
</Label.GestureRecognizers> </Label.GestureRecognizers>
</Label> </Label>
</StackLayout> </StackLayout>
</Grid> </Grid>
</Frame>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -80,7 +80,7 @@ namespace TINK.View.BikesAtStation
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -89,9 +89,6 @@ namespace TINK.View.BikesAtStation
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new BikesAtStationPageViewModel( m_oViewModel = new BikesAtStationPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -104,7 +101,7 @@ namespace TINK.View.BikesAtStation
model.LocksServices.Active, model.LocksServices.Active,
model.Polling, model.Polling,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url), (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url),
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this) this)
{ {
@ -129,7 +126,7 @@ namespace TINK.View.BikesAtStation
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
BikesAtStationListView.ItemsSource = m_oViewModel; BikesAtStationListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }

View file

@ -5,7 +5,8 @@
x:Class="TINK.View.FindBike.FindBikePage" x:Class="TINK.View.FindBike.FindBikePage"
xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib" xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib"
xmlns:local_bike="clr-namespace:TINK.View.Bike" xmlns:local_bike="clr-namespace:TINK.View.Bike"
xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View"> xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View"
BackgroundColor="#f6f6f6">
<Shell.TitleView> <Shell.TitleView>
<Grid ColumnDefinitions="Auto, 1*"> <Grid ColumnDefinitions="Auto, 1*">
@ -23,19 +24,28 @@
<ContentPage.Content> <ContentPage.Content>
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<Frame <Grid
Grid.Row="0"> RowDefinitions="1*,Auto"
Grid.Row="0">
<Grid <StackLayout
RowDefinitions="1*,32"> Grid.Row="0"
Spacing="0"
Orientation="Vertical">
<!--No Network Connection-->
<sharedGui:NotConnectedToNetView/>
<!--Search bike--> <!--Search bike-->
<StackLayout Grid.Row="0"> <StackLayout
BackgroundColor="White"
IsVisible="{Binding IsSelectBikeVisible}"
Padding="10">
<Entry <Entry
Placeholder="{x:Static resources:AppResources.PlaceholderFindBike}" Placeholder="{x:Static resources:AppResources.PlaceholderFindBike}"
IsVisible="{Binding IsSelectBikeVisible}"
MaxLength="10" MaxLength="10"
CursorPosition="0" CursorPosition="0"
Text="{Binding BikeIdUserInput}"/> Text="{Binding BikeIdUserInput}"/>
@ -43,35 +53,51 @@
<Button <Button
Text="{x:Static resources:AppResources.MarkingFindBike}" Text="{x:Static resources:AppResources.MarkingFindBike}"
IsEnabled="{Binding IsSelectBikeEnabled}" IsEnabled="{Binding IsSelectBikeEnabled}"
IsVisible="{Binding IsSelectBikeVisible}"
Command="{Binding OnSelectBikeRequest}"/> Command="{Binding OnSelectBikeRequest}"/>
<ListView
x:Name="FindBikeListView"
SelectionMode="None"
SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True"
ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/>
</StackLayout> </StackLayout>
<!--Info text--> <!-- Bike -->
<StackLayout
Spacing="0"
IsVisible="{Binding IsBikesListVisible}"
Orientation="Vertical">
<!--Hint for Outdated Data.-->
<sharedGui:HintForRefreshingPageView/>
<ListView
x:Name="FindBikeListView"
SelectionMode="None"
SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}"
HasUnevenRows="True"
SeparatorVisibility="None"
ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/>
</StackLayout>
</StackLayout>
<!--Info text-->
<StackLayout
BackgroundColor="#f6f6f6"
Padding="10,5,10,10"
Grid.Row="1">
<Label <Label
Grid.Row="1"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
FontSize="Small" FontSize="Small"
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid> </StackLayout>
</Frame> </Grid>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -34,7 +34,7 @@ namespace TINK.View.FindBike
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
return; return;
} }
@ -42,9 +42,6 @@ namespace TINK.View.FindBike
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new FindBikePageViewModel( m_oViewModel = new FindBikePageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -56,7 +53,7 @@ namespace TINK.View.FindBike
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -79,7 +76,7 @@ namespace TINK.View.FindBike
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
FindBikeListView.ItemsSource = m_oViewModel; FindBikeListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
} }
/// <summary> /// <summary>

View file

@ -19,14 +19,22 @@
<ContentPage.Content> <ContentPage.Content>
<!--Grid for Map with Buttons and Running process--> <!--Grid for Map with Buttons and Running process-->
<Grid <Grid>
<StackLayout
Spacing="0"
Grid.Row="0">
<sharedGui:NotConnectedToNetView/>
<Grid
RowDefinitions="3,46,1*,32" RowDefinitions="3,46,1*,32"
ColumnDefinitions="1*,Auto,1*" ColumnDefinitions="1*,Auto,1*"
IsEnabled="{Binding IsMapPageEnabled}" IsEnabled="{Binding IsMapPageEnabled}"
VerticalOptions="FillAndExpand"> VerticalOptions="FillAndExpand">
<!--Map--> <!--Map-->
<maps:Map <maps:Map
Grid.RowSpan="3" Grid.RowSpan="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
WidthRequest="320" WidthRequest="320"
@ -34,14 +42,14 @@
x:Name="MyMap" x:Name="MyMap"
MyLocationEnabled="True" MyLocationEnabled="True"
MapType="Street"> MapType="Street">
<maps:Map.Behaviors> <maps:Map.Behaviors>
<bindings:BindingPinsBehavior Value="{Binding Pins}"/> <bindings:BindingPinsBehavior Value="{Binding Pins}"/>
<bindings:PinClickedToCommandBehavior Command="{Binding PinClickedCommand}"/> <bindings:PinClickedToCommandBehavior Command="{Binding PinClickedCommand}"/>
</maps:Map.Behaviors> </maps:Map.Behaviors>
</maps:Map> </maps:Map>
<!--Buttons for choosing bike type--> <!--Buttons for choosing bike type-->
<Frame <Frame
CornerRadius="13" CornerRadius="13"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
@ -49,11 +57,11 @@
Padding="0" Padding="0"
IsVisible="{Binding IsNavBarVisible}" IsVisible="{Binding IsNavBarVisible}"
BackgroundColor="{DynamicResource secondary-back-title-color}"> BackgroundColor="{DynamicResource secondary-back-title-color}">
<StackLayout <StackLayout
Orientation="Horizontal" Orientation="Horizontal"
Margin="0" Margin="0"
Padding="0"> Padding="0">
<Button <Button
x:Name="KonradButton" x:Name="KonradButton"
AutomationId ="FilterKonrad_button" AutomationId ="FilterKonrad_button"
Text="{x:Static resources:AppResources.MarkingCityBike}" Text="{x:Static resources:AppResources.MarkingCityBike}"
@ -71,8 +79,8 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold" FontAttributes="Bold"
TextColor="{Binding NoKonradColor}"> TextColor="{Binding NoKonradColor}">
</Button> </Button>
<Button <Button
x:Name="TINKButton" x:Name="TINKButton"
AutomationId ="FilterTINK_button" AutomationId ="FilterTINK_button"
Text="{x:Static resources:AppResources.MarkingCargoBike}" Text="{x:Static resources:AppResources.MarkingCargoBike}"
@ -90,12 +98,12 @@
FontSize="Small" FontSize="Small"
FontAttributes="Bold" FontAttributes="Bold"
TextColor="{Binding NoTinkColor}"> TextColor="{Binding NoTinkColor}">
</Button> </Button>
</StackLayout> </StackLayout>
</Frame> </Frame>
<!--Info text--> <!--Info text-->
<Label <Label
Grid.Row="3" Grid.Row="3"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
@ -105,12 +113,14 @@
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid>
</StackLayout>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView
IsVisible="{Binding IsProcessWithRunningProcessView}" IsVisible="{Binding IsProcessWithRunningProcessView}"
Grid.RowSpan="4" Grid.Row="0"/>
Grid.ColumnSpan="3"/>
</Grid> </Grid>
</ContentPage.Content> </ContentPage.Content>

View file

@ -6,6 +6,7 @@
xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib" xmlns:resources="clr-namespace:TINK.MultilingualResources;assembly=TINKLib"
xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View" xmlns:sharedGui="clr-namespace:ShareeSharedGuiLib.View"
xmlns:local_bike="clr-namespace:TINK.View.Bike" xmlns:local_bike="clr-namespace:TINK.View.Bike"
BackgroundColor="#f6f6f6"
Shell.FlyoutBehavior="{Binding FlyoutBehavior}"> Shell.FlyoutBehavior="{Binding FlyoutBehavior}">
<Shell.TitleView> <Shell.TitleView>
@ -26,45 +27,66 @@
<!--Grid for Bike(s) view and Running process in same row--> <!--Grid for Bike(s) view and Running process in same row-->
<Grid> <Grid>
<Frame <!--Bike(s) view-->
Grid.Row="0"> <Grid
RowDefinitions="1*,Auto"
Grid.Row="0">
<!--Bike(s) view--> <StackLayout
<Grid Grid.Row="0"
RowDefinitions="1*,32"> Spacing="0"
Orientation="Vertical">
<!--No Network Connection-->
<sharedGui:NotConnectedToNetView/>
<!--Bike(s)--> <!--Bike(s)-->
<ListView <StackLayout
Grid.Row="0" Spacing="0"
IsVisible="{Binding IsBikesListVisible}"
Orientation="Vertical">
<!--Hint for Outdated Data.-->
<sharedGui:HintForRefreshingPageView/>
<ListView
x:Name="MyBikesListView" x:Name="MyBikesListView"
SelectionMode="None" SelectionMode="None"
SelectedItem="{Binding SelectedBike}" SelectedItem="{Binding SelectedBike}"
IsEnabled="{Binding IsIdle}" IsEnabled="{Binding IsIdle}"
IsVisible="{Binding IsBikesListVisible}"
HasUnevenRows="True" HasUnevenRows="True"
SeparatorVisibility="None"
ItemTemplate="{StaticResource bikeTemplateSelector}" ItemTemplate="{StaticResource bikeTemplateSelector}"
IsPullToRefreshEnabled="True" IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}" RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"/> IsRefreshing="{Binding IsRefreshing}"/>
</StackLayout>
<!--No Bikes--> <!--No Bikes-->
<Label <Label
Grid.Row="0" Padding="10"
IsVisible="{Binding IsNoBikesOccupiedVisible}" IsVisible="{Binding IsNoBikesOccupiedVisible}"
Text="{Binding NoBikesOccupiedText}"/> Text="{Binding NoBikesOccupiedText}"/>
</StackLayout>
<!--Info text-->
<StackLayout
BackgroundColor="#f6f6f6"
Padding="10,5,10,10"
Grid.Row="1">
<!--Info text-->
<Label <Label
Grid.Row="1"
Text="{Binding StatusInfoText}" Text="{Binding StatusInfoText}"
IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}" IsVisible="{Binding Path=IsProcessWithRunningProcessView, Converter={StaticResource InvertedBoolConverter}}"
FontSize="Small" FontSize="Small"
HorizontalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"/> VerticalOptions="CenterAndExpand"/>
</Grid> </StackLayout>
</Frame> </Grid>
<!--While process is running--> <!--While process is running-->
<sharedGui:RunningProcessView <sharedGui:RunningProcessView

View file

@ -1,4 +1,4 @@
using Plugin.Connectivity; using Plugin.Connectivity;
using System; using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -47,7 +47,7 @@ namespace TINK.View.MyBikes
{ {
// No need to create view model, set binding context an items source if already done. // No need to create view model, set binding context an items source if already done.
// If done twice tap events are fired multiple times (when hiding page using home button). // If done twice tap events are fired multiple times (when hiding page using home button).
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
return; return;
} }
@ -56,9 +56,6 @@ namespace TINK.View.MyBikes
{ {
var model = App.ModelRoot; var model = App.ModelRoot;
// Backup synchronization context when called from GUI-thread.
var synchronizationContext = SynchronizationContext.Current;
m_oViewModel = new MyBikesPageViewModel( m_oViewModel = new MyBikesPageViewModel(
model.ActiveUser, model.ActiveUser,
App.PermissionsService, App.PermissionsService,
@ -70,7 +67,7 @@ namespace TINK.View.MyBikes
model.LocksServices.Active, model.LocksServices.Active,
model.Stations, model.Stations,
model.Polling, model.Polling,
(d, obj) => synchronizationContext.Post(d, obj), model.PostAction,
model.SmartDevice, model.SmartDevice,
this, this,
(url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url)) (url) => DependencyService.Get<IExternalBrowserService>().OpenUrl(url))
@ -91,7 +88,7 @@ namespace TINK.View.MyBikes
BindingContext = m_oViewModel; BindingContext = m_oViewModel;
MyBikesListView.ItemsSource = m_oViewModel; MyBikesListView.ItemsSource = m_oViewModel;
await m_oViewModel.OnAppearing(); await m_oViewModel.OnAppearingOrRefresh();
isInitializationStarted = false; isInitializationStarted = false;
} }
@ -183,4 +180,4 @@ namespace TINK.View.MyBikes
public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving)); public async Task<IUserFeedback> DisplayUserFeedbackPopup(IBattery battery = null, string co2Saving = null) => await Navigation.ShowPopupAsync<FeedbackPopup.Result>(new FeedbackPopup(battery, co2Saving));
#endif #endif
} }
} }

View file

@ -35,7 +35,7 @@ namespace TINK.Model.Bikes.BikeInfoNS.BluetoothLock
public new string ToString() public new string ToString()
{ {
return $"Id={Id}{(TypeOfBike != null ? $";type={TypeOfBike}" : "")};state={State}"; return $"Id={Id}{(TypeOfBike != null ? $";type={TypeOfBike}" : "")};state={State.ToString()}";
} }
} }
} }

View file

@ -1,4 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace TINK.Model.Bikes.BikeInfoNS namespace TINK.Model.Bikes.BikeInfoNS
{ {
@ -24,9 +24,19 @@ namespace TINK.Model.Bikes.BikeInfoNS
public string Value { get; set; } = string.Empty; public string Value { get; set; } = string.Empty;
} }
/// <summary>
/// Info element of general purpose (AGB, tracking info, ...)
/// </summary>
public class InfoElement public class InfoElement
{ {
/// <summary>
/// Key which identyfies the value (required for special processing)
/// </summary>
public string Key { get; set; } public string Key { get; set; }
/// <summary>
/// Text to be displayed to user.
/// </summary>
public string Value { get; set; } public string Value { get; set; }
} }

View file

@ -286,7 +286,7 @@ namespace TINK.Model.Connector
} }
DoReturnResponse response DoReturnResponse response
= (await CopriServer.DoReturn(bike.Id, location, smartDevice, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id); = (await CopriServer.DoReturn(bike.Id, location, bike.OperatorUri)).GetIsReturnBikeResponseOk(bike.Id);
bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None); bike.Load(Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);
return response?.Create() ?? new BookingFinishedModel(); return response?.Create() ?? new BookingFinishedModel();

View file

@ -1,4 +1,5 @@
using System; using System;
using TINK.Model.Device;
using TINK.Model.Services.CopriApi; using TINK.Model.Services.CopriApi;
using TINK.Repository; using TINK.Repository;
@ -9,12 +10,13 @@ namespace TINK.Model.Connector
/// </summary> /// </summary>
public class Connector : IConnector public class Connector : IConnector
{ {
/// <summary>Constructs a copri connector object.</summary> /// <summary>Constructs a copri connector object to connect to copri by https with cache fallback.</summary>
/// <param name="activeUri"> Uri to connect to.</param> /// <param name="activeUri"> Uri to connect to.</param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param> /// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param> /// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param> /// <param name="mail">Mail of user.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="expiresAfter">Timespan which holds value after which cache expires.</param> /// <param name="expiresAfter">Timespan which holds value after which cache expires.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param> /// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public Connector( public Connector(
@ -23,25 +25,28 @@ namespace TINK.Model.Connector
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie, string sessionCookie,
string mail, string mail,
ISmartDevice smartDevice = null,
TimeSpan? expiresAfter = null, TimeSpan? expiresAfter = null,
ICachedCopriServer server = null) ICachedCopriServer server = null)
{ {
Command = GetCommand( Command = CreateCommand(
server ?? new CopriProviderHttps( server ?? new CopriProviderHttps(
activeUri, activeUri,
appContextInfo.MerchantId, appContextInfo.MerchantId,
appContextInfo, appContextInfo,
uiIsoLangugageName, uiIsoLangugageName,
smartDevice,
sessionCookie), sessionCookie),
sessionCookie, sessionCookie,
mail); mail);
Query = GetQuery( Query = CreateQuery(
server ?? new CopriProviderHttps( server ?? new CopriProviderHttps(
activeUri, activeUri,
appContextInfo.MerchantId, appContextInfo.MerchantId,
appContextInfo, appContextInfo,
uiIsoLangugageName, uiIsoLangugageName,
smartDevice,
sessionCookie, sessionCookie,
expiresAfter), expiresAfter),
sessionCookie, sessionCookie,
@ -57,13 +62,13 @@ namespace TINK.Model.Connector
/// <summary> True if connector has access to copri server, false if cached values are used. </summary> /// <summary> True if connector has access to copri server, false if cached values are used. </summary>
public bool IsConnected => Command.IsConnected; public bool IsConnected => Command.IsConnected;
/// <summary> Gets a command object to perform copri commands. </summary> /// <summary> Creates a command object to perform copri commands. </summary>
public static ICommand GetCommand(ICopriServerBase copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie) public static ICommand CreateCommand(ICopriServerBase copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new Command(copri) ? new Command(copri)
: new CommandLoggedIn(copri, sessioncookie, mail, () => DateTime.Now) as ICommand; : new CommandLoggedIn(copri, sessioncookie, mail, () => DateTime.Now) as ICommand;
/// <summary> Gets a command object to perform copri queries. </summary> /// <summary> Creates a command object to perform copri queries. </summary>
private static IQuery GetQuery(ICachedCopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie) private static IQuery CreateQuery(ICachedCopriServer copri, string sessioncookie, string mail) => string.IsNullOrEmpty(sessioncookie)
? new CachedQuery(copri) as IQuery ? new CachedQuery(copri) as IQuery
: new CachedQueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now); : new CachedQueryLoggedIn(copri, sessioncookie, mail, () => DateTime.Now);
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using TINK.Model.Device;
using TINK.Model.Services.CopriApi; using TINK.Model.Services.CopriApi;
using TINK.Repository; using TINK.Repository;
@ -9,26 +10,28 @@ namespace TINK.Model.Connector
/// </summary> /// </summary>
public class ConnectorCache : IConnector public class ConnectorCache : IConnector
{ {
/// <summary>Constructs a copri connector object.</summary> /// <summary>Constructs a copri connector object to connect to cache.</summary>
/// <remarks>Used for offline szenario to ensure responsiveness of app by preventing hopeless tries to communicate with COPRI. </remarks>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie"> Holds the session cookie.</param> /// <param name="sessionCookie"> Holds the session cookie.</param>
/// <param name="mail">Mail of user.</param> /// <param name="mail">Mail of user.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="server"> Is null in production and migh be a mock in testing context.</param> /// <param name="server"> Is null in production and migh be a mock in testing context.</param>
public ConnectorCache( public ConnectorCache(
AppContextInfo appContextInfo, AppContextInfo appContextInfo,
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie, string sessionCookie,
string mail, string mail,
ISmartDevice smartDevice = null,
ICopriServer server = null) ICopriServer server = null)
{ {
Command = Connector.CreateCommand(
Command = Connector.GetCommand( server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie, smartDevice),
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie),
sessionCookie, sessionCookie,
mail); mail);
Query = GetQuery( Query = GetQuery(
server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie), server ?? new CopriProviderMonkeyStore(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie, smartDevice),
sessionCookie, sessionCookie,
mail); mail);
} }

View file

@ -1,4 +1,5 @@
using System; using System;
using TINK.Model.Device;
using TINK.Repository; using TINK.Repository;
namespace TINK.Model.Connector namespace TINK.Model.Connector
@ -8,10 +9,13 @@ namespace TINK.Model.Connector
/// <summary> /// <summary>
/// Gets a connector object depending on whether beein onlin or offline. /// Gets a connector object depending on whether beein onlin or offline.
/// </summary> /// </summary>
/// <param name="isConnected">True if online, false if offline. If offline cache connector is returned.</param> /// <param name="isConnected">
/// True if online, false if offline.
/// If offline cache connector is returned to avoid performance penalty which would happen when trying to communicate with backend in offline scenario.
/// </param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param> /// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <returns></returns> /// <param name="smartDevice">Holds info about smart device.</param>
public static IConnector Create( public static IConnector Create(
bool isConnected, bool isConnected,
Uri activeUri, Uri activeUri,
@ -19,11 +23,12 @@ namespace TINK.Model.Connector
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie, string sessionCookie,
string mail, string mail,
ISmartDevice smartDevice = null,
TimeSpan? expiresAfter = null) TimeSpan? expiresAfter = null)
{ {
return isConnected return isConnected
? new Connector(activeUri, appContextInfo, uiIsoLangugageName, sessionCookie, mail, expiresAfter: expiresAfter) as IConnector ? new Connector(activeUri, appContextInfo, uiIsoLangugageName, sessionCookie, mail, smartDevice, expiresAfter: expiresAfter) as IConnector
: new ConnectorCache(appContextInfo, uiIsoLangugageName, sessionCookie, mail); : new ConnectorCache(appContextInfo, uiIsoLangugageName, sessionCookie, mail, smartDevice);
} }
} }
} }

View file

@ -118,12 +118,12 @@ namespace TINK.Model.Settings
} }
/// <summary> Sets the uri of the active copri host. </summary> /// <summary> Sets the uri of the active copri host. </summary>
/// <param name="settingsJSON">Dictionary holding parameters from JSON.</param> /// <param name="settingsJSON">Dictionary holding parameters from JSON.</param>
public static Dictionary<string, string> SetCopriHostUri(this IDictionary<string, string> p_oTargetDictionary, string p_strNextActiveUriText) public static Dictionary<string, string> SetCopriHostUri(this IDictionary<string, string> targetDictionary, string p_strNextActiveUriText)
{ {
if (p_oTargetDictionary == null) if (targetDictionary == null)
throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null."); throw new Exception("Writing copri host uri to dictionary failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string> return targetDictionary.Union(new Dictionary<string, string>
{ {
{ typeof(CopriServerUriList).ToString(), JsonConvert.SerializeObject(p_strNextActiveUriText) }, { typeof(CopriServerUriList).ToString(), JsonConvert.SerializeObject(p_strNextActiveUriText) },
}).ToDictionary(key => key.Key, value => value.Value); }).ToDictionary(key => key.Key, value => value.Value);
@ -196,15 +196,17 @@ namespace TINK.Model.Settings
/// <summary> Sets whether polling is on or off and the periode if polling is on. </summary> /// <summary> Sets whether polling is on or off and the periode if polling is on. </summary>
/// <param name="settingsJSON">Dictionary to write entries to.</param> /// <param name="settingsJSON">Dictionary to write entries to.</param>
public static Dictionary<string, string> SetPollingParameters(this IDictionary<string, string> p_oTargetDictionary, PollingParameters p_oPollingParameter) public static Dictionary<string, string> SetPollingParameters(
this IDictionary<string, string> targetDictionary,
PollingParameters pollingParameter)
{ {
if (p_oTargetDictionary == null) if (targetDictionary == null)
throw new Exception("Writing polling parameters to dictionary failed. Dictionary must not be null."); throw new Exception("Writing polling parameters to dictionary failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string> return targetDictionary.Union(new Dictionary<string, string>
{ {
{ $"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", JsonConvert.SerializeObject(p_oPollingParameter.Periode) }, { $"{typeof(PollingParameters).Name}_{typeof(TimeSpan).Name}", JsonConvert.SerializeObject(pollingParameter.Periode) },
{ $"{typeof(PollingParameters).Name}_{typeof(bool).Name}", JsonConvert.SerializeObject(p_oPollingParameter.IsActivated) }, { $"{typeof(PollingParameters).Name}_{typeof(bool).Name}", JsonConvert.SerializeObject(pollingParameter.IsActivated) },
}).ToDictionary(key => key.Key, value => value.Value); }).ToDictionary(key => key.Key, value => value.Value);
} }
@ -242,24 +244,24 @@ namespace TINK.Model.Settings
/// <returns>Dictionary of settings.</returns> /// <returns>Dictionary of settings.</returns>
public static Dictionary<string, string> Deserialize(string settingsDirectory) public static Dictionary<string, string> Deserialize(string settingsDirectory)
{ {
var l_oFileName = $"{settingsDirectory}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}"; var fileName = $"{settingsDirectory}{System.IO.Path.DirectorySeparatorChar}{SETTINGSFILETITLE}";
if (!System.IO.File.Exists(l_oFileName)) if (!System.IO.File.Exists(fileName))
{ {
// File is empty. Nothing to read. // File is empty. Nothing to read.
return new Dictionary<string, string>(); ; return new Dictionary<string, string>(); ;
} }
var l_oJSONFile = System.IO.File.ReadAllText(l_oFileName); var jsonFile = System.IO.File.ReadAllText(fileName);
if (string.IsNullOrEmpty(l_oJSONFile)) if (string.IsNullOrEmpty(jsonFile))
{ {
// File is empty. Nothing to read. // File is empty. Nothing to read.
return new Dictionary<string, string>(); return new Dictionary<string, string>();
} }
// Load setting file. // Load setting file.
return JsonConvert.DeserializeObject<Dictionary<string, string>>(l_oJSONFile); return JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonFile);
} }
/// <summary> Gets the logging level.</summary> /// <summary> Gets the logging level.</summary>
@ -291,15 +293,15 @@ namespace TINK.Model.Settings
/// <summary> Sets the logging level.</summary> /// <summary> Sets the logging level.</summary>
/// <param name="settingsJSON">Dictionary to get logging level from.</param> /// <param name="settingsJSON">Dictionary to get logging level from.</param>
public static Dictionary<string, string> SetMinimumLoggingLevel(this IDictionary<string, string> p_oTargetDictionary, LogEventLevel p_oLevel) public static Dictionary<string, string> SetMinimumLoggingLevel(this IDictionary<string, string> targetDictionary, LogEventLevel level)
{ {
// Set logging level. // Set logging level.
if (p_oTargetDictionary == null) if (targetDictionary == null)
throw new Exception("Writing logging level to dictionary failed. Dictionary must not be null."); throw new Exception("Writing logging level to dictionary failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string> return targetDictionary.Union(new Dictionary<string, string>
{ {
{ MINLOGGINGLEVELKEY, JsonConvert.SerializeObject((int)p_oLevel) } { MINLOGGINGLEVELKEY, JsonConvert.SerializeObject((int)level) }
}).ToDictionary(key => key.Key, value => value.Value); }).ToDictionary(key => key.Key, value => value.Value);
} }
@ -321,15 +323,15 @@ namespace TINK.Model.Settings
/// <summary> Sets the version of app when whats new was shown.</summary> /// <summary> Sets the version of app when whats new was shown.</summary>
/// <param name="settingsJSON">Dictionary to get information from.</param> /// <param name="settingsJSON">Dictionary to get information from.</param>
public static Dictionary<string, string> SetWhatsNew(this IDictionary<string, string> p_oTargetDictionary, Version p_oAppVersion) public static Dictionary<string, string> SetWhatsNew(this IDictionary<string, string> targetDictionary, Version appVersion)
{ {
// Set logging level. // Set logging level.
if (p_oTargetDictionary == null) if (targetDictionary == null)
throw new Exception("Writing WhatsNew info failed. Dictionary must not be null."); throw new Exception("Writing WhatsNew info failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string> return targetDictionary.Union(new Dictionary<string, string>
{ {
{ SHOWWHATSNEWKEY, JsonConvert.SerializeObject(p_oAppVersion, new VersionConverter()) } { SHOWWHATSNEWKEY, JsonConvert.SerializeObject(appVersion, new VersionConverter()) }
}).ToDictionary(key => key.Key, value => value.Value); }).ToDictionary(key => key.Key, value => value.Value);
} }
@ -350,12 +352,12 @@ namespace TINK.Model.Settings
/// <summary> Sets the the expiration time.</summary> /// <summary> Sets the the expiration time.</summary>
/// <param name="settingsJSON">Dictionary to write information to.</param> /// <param name="settingsJSON">Dictionary to write information to.</param>
public static Dictionary<string, string> SetExpiresAfter(this IDictionary<string, string> p_oTargetDictionary, TimeSpan expiresAfter) public static Dictionary<string, string> SetExpiresAfter(this IDictionary<string, string> targetDictionary, TimeSpan expiresAfter)
{ {
if (p_oTargetDictionary == null) if (targetDictionary == null)
throw new Exception("Writing ExpiresAfter info failed. Dictionary must not be null."); throw new Exception("Writing ExpiresAfter info failed. Dictionary must not be null.");
return p_oTargetDictionary.Union(new Dictionary<string, string> return targetDictionary.Union(new Dictionary<string, string>
{ {
{ EXPIRESAFTER, JsonConvert.SerializeObject(expiresAfter, new JavaScriptDateTimeConverter()) } { EXPIRESAFTER, JsonConvert.SerializeObject(expiresAfter, new JavaScriptDateTimeConverter()) }
}).ToDictionary(key => key.Key, value => value.Value); }).ToDictionary(key => key.Key, value => value.Value);
@ -497,16 +499,16 @@ namespace TINK.Model.Settings
public static IDictionary<string, string> SetGroupFilterMapPage( public static IDictionary<string, string> SetGroupFilterMapPage(
this IDictionary<string, string> settings, this IDictionary<string, string> settings,
IDictionary<string, FilterState> p_oFilterCollection) IDictionary<string, FilterState> filterCollection)
{ {
if (settings == null if (settings == null
|| p_oFilterCollection == null || filterCollection == null
|| p_oFilterCollection.Count < 1) || filterCollection.Count < 1)
{ {
return settings; return settings;
} }
settings["FilterCollection_MapPageFilter"] = JsonConvert.SerializeObject(p_oFilterCollection); settings["FilterCollection_MapPageFilter"] = JsonConvert.SerializeObject(filterCollection);
return settings; return settings;
} }
@ -541,16 +543,16 @@ namespace TINK.Model.Settings
public static IDictionary<string, string> SetGroupFilterSettings( public static IDictionary<string, string> SetGroupFilterSettings(
this IDictionary<string, string> settings, this IDictionary<string, string> settings,
IDictionary<string, FilterState> p_oFilterCollection) IDictionary<string, FilterState> filterCollection)
{ {
if (settings == null if (settings == null
|| p_oFilterCollection == null || filterCollection == null
|| p_oFilterCollection.Count < 1) || filterCollection.Count < 1)
{ {
return settings; return settings;
} }
settings["FilterCollection"] = JsonConvert.SerializeObject(p_oFilterCollection); settings["FilterCollection"] = JsonConvert.SerializeObject(filterCollection);
return settings; return settings;
} }

View file

@ -1,4 +1,4 @@
using System; using System;
namespace TINK.Settings namespace TINK.Settings
{ {
@ -7,7 +7,7 @@ namespace TINK.Settings
{ {
/// <summary> Holds default polling parameters. </summary> /// <summary> Holds default polling parameters. </summary>
public static PollingParameters Default { get; } = new PollingParameters( public static PollingParameters Default { get; } = new PollingParameters(
new TimeSpan(0, 0, 0, 10 /*secs*/, 0),// Default polling interval. new TimeSpan(0, 0, 0, 60 /*secs*/, 0), // Default polling interval. Was 10 secs up to 3.0.357.
true); true);
/// <summary> Holds polling parameters which represent polling off (empty polling object). </summary> /// <summary> Holds polling parameters which represent polling off (empty polling object). </summary>
@ -16,12 +16,12 @@ namespace TINK.Settings
false); false);
/// <summary> Constructs a polling parameter object. </summary> /// <summary> Constructs a polling parameter object. </summary>
/// <param name="p_oPeriode">Polling periode.</param> /// <param name="periode">Polling periode.</param>
/// <param name="p_bIsActivated">True if polling is activated.</param> /// <param name="activated">True if polling is activated.</param>
public PollingParameters(TimeSpan p_oPeriode, bool p_bIsActivated) public PollingParameters(TimeSpan periode, bool activated)
{ {
Periode = p_oPeriode; // Can not be null because is a struct. Periode = periode; // Can not be null because is a struct.
IsActivated = p_bIsActivated; IsActivated = activated;
} }
/// <summary>Holds the polling periode.</summary> /// <summary>Holds the polling periode.</summary>

View file

@ -193,10 +193,13 @@ namespace TINK.Model
?? ((d, obj) => d(obj)); ?? ((d, obj) => d(obj));
ConnectorFactory = connectorFactory ConnectorFactory = connectorFactory
?? throw new ArgumentException("Can not instantiate TinkApp- object. No connector factory object available."); ?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No connector factory object available.");
MerchantId = merchantId MerchantId = merchantId
?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}. No merchant id available."); ?? throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. No merchant id available.");
if (settings == null)
throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. Settings must not be null.");
Cipher = cipher ?? new Cipher(); Cipher = cipher ?? new Cipher();
@ -296,8 +299,12 @@ namespace TINK.Model
NextActiveUri = Uris.ActiveUri; NextActiveUri = Uris.ActiveUri;
Polling = settings.PollingParameters ?? if (settings.PollingParameters == null)
throw new ArgumentException("Can not instantiate TinkApp- object. Polling parameters must never be null."); throw new ArgumentException($"Can not instantiate {nameof(TinkApp)}- object. Polling parameters must never be null.");
Polling = (lastVersion != null && lastVersion < new Version(3, 0, 358))
? PollingParameters.Default // Default polling periode was 10s up to 3.0.357. Is 60s for later versions.
: settings.PollingParameters;
AppVersion = currentVersion ?? new Version(3, 0, 122); AppVersion = currentVersion ?? new Version(3, 0, 122);

View file

@ -673,8 +673,8 @@ namespace TINK.Model
AppResources.ChangeLog3_0_231 AppResources.ChangeLog3_0_231
}, },
{ {
new Version(3, 0, 357), new Version(3, 0, 360),
AppResources.ChangeLog_3_0_357_MK_SB, AppResources.ChangeLog_3_0_358_MK_SB,
new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike } new List<AppFlavor> { AppFlavor.MeinKonrad, AppFlavor.ShareeBike }
}, },
}; };

View file

@ -748,11 +748,12 @@ namespace TINK.MultilingualResources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to You can only start or end a rent with network reception. Turn on mobile data or wifi and drag the page downward with the finger to refresh the page.. /// Looks up a localized string similar to New functions:&lt;ul&gt;&lt;li&gt;If your device is not connected to the Internet, this is now displayed at the top.&lt;/li&gt;&lt;li&gt;You can now update your bike view by dragging from top to bottom. Especially useful after you reconnect to the Internet.&lt;/li&gt;&lt;/ul&gt;
///&lt;br/&gt;In addition:&lt;ul&gt;&lt;li&gt;Software packages were updated.&lt;/li&gt;&lt;li&gt;Minor bug fixes.&lt;/li&gt;&lt;/ul&gt;.
/// </summary> /// </summary>
public static string ChangeLog_3_0_357_MK_SB { public static string ChangeLog_3_0_358_MK_SB {
get { get {
return ResourceManager.GetString("ChangeLog_3_0_357_MK_SB", resourceCulture); return ResourceManager.GetString("ChangeLog_3_0_358_MK_SB", resourceCulture);
} }
} }
@ -1592,20 +1593,24 @@ namespace TINK.MultilingualResources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Lock is blocked. Please ensure that no obstacle prevents lock from opening and try again.. /// Looks up a localized string similar to Ensure that no obstacle prevents lock from opening and try again..
/// </summary> /// </summary>
public static string ErrorOpenLockBoldBlockedMessage { public static string ErrorOpenLockBoldIsBlockedMessage {
get { get {
return ResourceManager.GetString("ErrorOpenLockBoldBlockedMessage", resourceCulture); return ResourceManager.GetString("ErrorOpenLockBoldIsBlockedMessage", resourceCulture);
} }
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to Lock was blocked and might still be. Please ensure that no obstacle prevents lock from opening and try again.. /// Looks up a localized string similar to The lock could not be opened correctly. Please try again.
///
///Attention! Your rental has already started.
///
///If the lock still won&apos;t open, make sure the lock is closed and return the bike. Please report it to the support!.
/// </summary> /// </summary>
public static string ErrorOpenLockBoldWasBlockedMessage { public static string ErrorOpenLockBoldStatusIsUnknownMessage {
get { get {
return ResourceManager.GetString("ErrorOpenLockBoldWasBlockedMessage", resourceCulture); return ResourceManager.GetString("ErrorOpenLockBoldStatusIsUnknownMessage", resourceCulture);
} }
} }
@ -1630,9 +1635,9 @@ namespace TINK.MultilingualResources {
/// <summary> /// <summary>
/// Looks up a localized string similar to Lock can not be opened!. /// Looks up a localized string similar to Lock can not be opened!.
/// </summary> /// </summary>
public static string ErrorOpenLockStillOpenTitle { public static string ErrorOpenLockStillClosedTitle {
get { get {
return ResourceManager.GetString("ErrorOpenLockStillOpenTitle", resourceCulture); return ResourceManager.GetString("ErrorOpenLockStillClosedTitle", resourceCulture);
} }
} }
@ -1958,7 +1963,7 @@ namespace TINK.MultilingualResources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to No network, data is outdated.. /// Looks up a localized string similar to Pull to refresh..
/// </summary> /// </summary>
public static string MarkingDataIsFromCache { public static string MarkingDataIsFromCache {
get { get {
@ -2192,6 +2197,15 @@ namespace TINK.MultilingualResources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Oops, there is no internet connection..
/// </summary>
public static string MarkingNoNetworkConnection {
get {
return ResourceManager.GetString("MarkingNoNetworkConnection", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Bike is ok. /// Looks up a localized string similar to Bike is ok.
/// </summary> /// </summary>

View file

@ -572,17 +572,8 @@ Fehlerhandling verbessert.</value>
<data name="ChangeLog3_0_235" xml:space="preserve"> <data name="ChangeLog3_0_235" xml:space="preserve">
<value>Veraltetes Objekt durch aktuelles ersetzt.</value> <value>Veraltetes Objekt durch aktuelles ersetzt.</value>
</data> </data>
<data name="ErrorOpenLockBoldBlockedMessage" xml:space="preserve">
<value>Schloss ist blockiert. Bitte Ursache von Blockierung beheben und Vorgang wiederholen.</value>
</data>
<data name="ErrorOpenLockBoldWasBlockedMessage" xml:space="preserve">
<value>Schloss war oder ist blockiert. Bitte Ursache von Blockierung beheben und Vorgang wiederholen.</value>
</data>
<data name="ErrorOpenLockTitle" xml:space="preserve"> <data name="ErrorOpenLockTitle" xml:space="preserve">
<value>Fehler beim Schlossöffnen!</value> <value>Fehler beim Schloss Öffnen!</value>
</data>
<data name="ErrorOpenLockStillOpenTitle" xml:space="preserve">
<value>Schloss kann nicht geöffnet werden!</value>
</data> </data>
<data name="ChangeLog3_0_236" xml:space="preserve"> <data name="ChangeLog3_0_236" xml:space="preserve">
<value>Anzeige von Stationsnamen statt Nummern. <value>Anzeige von Stationsnamen statt Nummern.
@ -1115,7 +1106,7 @@ Probieren Sie es aus!</value>
<value>Bluetooth-Kommunikation verbessert.</value> <value>Bluetooth-Kommunikation verbessert.</value>
</data> </data>
<data name="MarkingDataIsFromCache" xml:space="preserve"> <data name="MarkingDataIsFromCache" xml:space="preserve">
<value>Kein Netz, Daten sind veraltet.</value> <value>Zum Aktualisieren ziehen.</value>
</data> </data>
<data name="MarkingBikesAtStationNoBikesAvailable" xml:space="preserve"> <data name="MarkingBikesAtStationNoBikesAvailable" xml:space="preserve">
<value>Momentan sind keine Fahrräder an dieser Station verfügbar.</value> <value>Momentan sind keine Fahrräder an dieser Station verfügbar.</value>
@ -1126,10 +1117,27 @@ Probieren Sie es aus!</value>
<data name="MessageTitleInformation" xml:space="preserve"> <data name="MessageTitleInformation" xml:space="preserve">
<value>Information</value> <value>Information</value>
</data> </data>
<data name="ChangeLog_3_0_357_MK_SB" xml:space="preserve">
<value>Sie können eine Miete nur bei Netzempfang beginnen oder beenden. Schalten Sie mobile Daten oder WLAN ein und ziehen Sie die Seite mit dem Finger nach unten, um Ihre Ansicht zu aktualisieren.</value>
</data>
<data name="ChangeLog_MinorImprovements" xml:space="preserve"> <data name="ChangeLog_MinorImprovements" xml:space="preserve">
<value>Kleine Verbesserungen.</value> <value>Kleine Verbesserungen.</value>
</data> </data>
<data name="ErrorOpenLockBoldStatusIsUnknownMessage" xml:space="preserve">
<value>Das Schloss konnte nicht korrekt geöffnet werden. Bitte versuchen Sie es erneut.
Achtung! Ihre Miete hat bereits begonnen.
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück. Bitte melden Sie es dem Support!</value>
</data>
<data name="ErrorOpenLockStillClosedTitle" xml:space="preserve">
<value>Schloss kann nicht geöffnet werden!</value>
</data>
<data name="ErrorOpenLockBoldIsBlockedMessage" xml:space="preserve">
<value>Stellen Sie sicher, dass kein Hindernis das Öffnen des Schlosses verhindert und versuchen Sie es erneut.</value>
</data>
<data name="MarkingNoNetworkConnection" xml:space="preserve">
<value>Ups, es ist keine Internetverbindung vorhanden.</value>
</data>
<data name="ChangeLog_3_0_358_MK_SB" xml:space="preserve">
<value>Neue Funktionen:&lt;ul&gt;&lt;li&gt;Wenn Ihr Gerät nicht mit dem Internet verbunden ist, wird dies nun oben angezeigt.&lt;/li&gt;&lt;li&gt;Sie können jetzt Ihre Fahrradansicht aktualisieren, indem Sie von oben nach unten ziehen. Das ist besonders nützlich, wenn Sie sich wieder mit dem Internet verbunden haben.&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;Außerdem:&lt;ul&gt;&lt;li&gt;Software Pakete wurde aktualisiert.&lt;/li&gt;&lt;li&gt;Kleinere Fehlerbehebungen.&lt;/li&gt;&lt;/ul&gt;</value>
</data>
</root> </root>

View file

@ -677,13 +677,17 @@ Error handling improved.</value>
<data name="ChangeLog3_0_235" xml:space="preserve"> <data name="ChangeLog3_0_235" xml:space="preserve">
<value>Obsolete object replaced with up-to-date one.</value> <value>Obsolete object replaced with up-to-date one.</value>
</data> </data>
<data name="ErrorOpenLockBoldBlockedMessage" xml:space="preserve"> <data name="ErrorOpenLockBoldIsBlockedMessage" xml:space="preserve">
<value>Lock is blocked. Please ensure that no obstacle prevents lock from opening and try again.</value> <value>Ensure that no obstacle prevents lock from opening and try again.</value>
</data> </data>
<data name="ErrorOpenLockBoldWasBlockedMessage" xml:space="preserve"> <data name="ErrorOpenLockBoldStatusIsUnknownMessage" xml:space="preserve">
<value>Lock was blocked and might still be. Please ensure that no obstacle prevents lock from opening and try again.</value> <value>The lock could not be opened correctly. Please try again.
Attention! Your rental has already started.
If the lock still won't open, make sure the lock is closed and return the bike. Please report it to the support!</value>
</data> </data>
<data name="ErrorOpenLockStillOpenTitle" xml:space="preserve"> <data name="ErrorOpenLockStillClosedTitle" xml:space="preserve">
<value>Lock can not be opened!</value> <value>Lock can not be opened!</value>
</data> </data>
<data name="ChangeLog3_0_236" xml:space="preserve"> <data name="ChangeLog3_0_236" xml:space="preserve">
@ -1205,7 +1209,7 @@ Try it out!</value>
<value>Bluetooth communication improved.</value> <value>Bluetooth communication improved.</value>
</data> </data>
<data name="MarkingDataIsFromCache" xml:space="preserve"> <data name="MarkingDataIsFromCache" xml:space="preserve">
<value>No network, data is outdated.</value> <value>Pull to refresh.</value>
</data> </data>
<data name="MarkingBikesAtStationNoBikesAvailable" xml:space="preserve"> <data name="MarkingBikesAtStationNoBikesAvailable" xml:space="preserve">
<value>There are currently no bicycles available at this station.</value> <value>There are currently no bicycles available at this station.</value>
@ -1216,10 +1220,14 @@ Try it out!</value>
<data name="MessageTitleInformation" xml:space="preserve"> <data name="MessageTitleInformation" xml:space="preserve">
<value>Information</value> <value>Information</value>
</data> </data>
<data name="ChangeLog_3_0_357_MK_SB" xml:space="preserve"> <data name="ChangeLog_3_0_358_MK_SB" xml:space="preserve">
<value>You can only start or end a rent with network reception. Turn on mobile data or wifi and drag the page downward with the finger to refresh the page.</value> <value>New functions:&lt;ul&gt;&lt;li&gt;If your device is not connected to the Internet, this is now displayed at the top.&lt;/li&gt;&lt;li&gt;You can now update your bike view by dragging from top to bottom. Especially useful after you reconnect to the Internet.&lt;/li&gt;&lt;/ul&gt;
&lt;br/&gt;In addition:&lt;ul&gt;&lt;li&gt;Software packages were updated.&lt;/li&gt;&lt;li&gt;Minor bug fixes.&lt;/li&gt;&lt;/ul&gt;</value>
</data> </data>
<data name="ChangeLog_MinorImprovements" xml:space="preserve"> <data name="ChangeLog_MinorImprovements" xml:space="preserve">
<value>Minor improvements.</value> <value>Minor improvements.</value>
</data> </data>
<data name="MarkingNoNetworkConnection" xml:space="preserve">
<value>Oops, there is no internet connection.</value>
</data>
</root> </root>

View file

@ -765,21 +765,9 @@ Fehlerhandling verbessert.</target>
<source>Obsolete object replaced with up-to-date one.</source> <source>Obsolete object replaced with up-to-date one.</source>
<target state="translated">Veraltetes Objekt durch aktuelles ersetzt.</target> <target state="translated">Veraltetes Objekt durch aktuelles ersetzt.</target>
</trans-unit> </trans-unit>
<trans-unit id="ErrorOpenLockBoldBlockedMessage" translate="yes" xml:space="preserve">
<source>Lock is blocked. Please ensure that no obstacle prevents lock from opening and try again.</source>
<target state="translated">Schloss ist blockiert. Bitte Ursache von Blockierung beheben und Vorgang wiederholen.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockBoldWasBlockedMessage" translate="yes" xml:space="preserve">
<source>Lock was blocked and might still be. Please ensure that no obstacle prevents lock from opening and try again.</source>
<target state="translated">Schloss war oder ist blockiert. Bitte Ursache von Blockierung beheben und Vorgang wiederholen.</target>
</trans-unit>
<trans-unit id="ErrorOpenLockTitle" translate="yes" xml:space="preserve"> <trans-unit id="ErrorOpenLockTitle" translate="yes" xml:space="preserve">
<source>Error while opening lock!</source> <source>Error while opening lock!</source>
<target state="translated">Fehler beim Schlossöffnen!</target> <target state="translated">Fehler beim Schloss Öffnen!</target>
</trans-unit>
<trans-unit id="ErrorOpenLockStillOpenTitle" translate="yes" xml:space="preserve">
<source>Lock can not be opened!</source>
<target state="translated">Schloss kann nicht geöffnet werden!</target>
</trans-unit> </trans-unit>
<trans-unit id="ChangeLog3_0_236" translate="yes" xml:space="preserve"> <trans-unit id="ChangeLog3_0_236" translate="yes" xml:space="preserve">
<source>Stations names instead descriptions shown on page title. <source>Stations names instead descriptions shown on page title.
@ -1525,8 +1513,8 @@ Probieren Sie es aus!</target>
<target state="translated">Bluetooth-Kommunikation verbessert.</target> <target state="translated">Bluetooth-Kommunikation verbessert.</target>
</trans-unit> </trans-unit>
<trans-unit id="MarkingDataIsFromCache" translate="yes" xml:space="preserve"> <trans-unit id="MarkingDataIsFromCache" translate="yes" xml:space="preserve">
<source>No network, data is outdated.</source> <source>Pull to refresh.</source>
<target state="translated">Kein Netz, Daten sind veraltet.</target> <target state="translated">Zum Aktualisieren ziehen.</target>
</trans-unit> </trans-unit>
<trans-unit id="MarkingBikesAtStationNoBikesAvailable" translate="yes" xml:space="preserve"> <trans-unit id="MarkingBikesAtStationNoBikesAvailable" translate="yes" xml:space="preserve">
<source>There are currently no bicycles available at this station.</source> <source>There are currently no bicycles available at this station.</source>
@ -1540,14 +1528,40 @@ Probieren Sie es aus!</target>
<source>Information</source> <source>Information</source>
<target state="translated">Information</target> <target state="translated">Information</target>
</trans-unit> </trans-unit>
<trans-unit id="ChangeLog_3_0_357_MK_SB" translate="yes" xml:space="preserve">
<source>You can only start or end a rent with network reception. Turn on mobile data or wifi and drag the page downward with the finger to refresh the page.</source>
<target state="translated">Sie können eine Miete nur bei Netzempfang beginnen oder beenden. Schalten Sie mobile Daten oder WLAN ein und ziehen Sie die Seite mit dem Finger nach unten, um Ihre Ansicht zu aktualisieren.</target>
</trans-unit>
<trans-unit id="ChangeLog_MinorImprovements" translate="yes" xml:space="preserve"> <trans-unit id="ChangeLog_MinorImprovements" translate="yes" xml:space="preserve">
<source>Minor improvements.</source> <source>Minor improvements.</source>
<target state="translated">Kleine Verbesserungen.</target> <target state="translated">Kleine Verbesserungen.</target>
</trans-unit> </trans-unit>
<trans-unit id="ErrorOpenLockBoldStatusIsUnknownMessage" translate="yes" xml:space="preserve">
<source>The lock could not be opened correctly. Please try again.
Attention! Your rental has already started.
If the lock still won't open, make sure the lock is closed and return the bike. Please report it to the support!</source>
<target state="translated">Das Schloss konnte nicht korrekt geöffnet werden. Bitte versuchen Sie es erneut.
Achtung! Ihre Miete hat bereits begonnen.
Wenn sich das Schloss weiterhin nicht öffnen lässt, vergewissern Sie sich, dass das Schloss geschlossen ist und geben Sie das Rad zurück. Bitte melden Sie es dem Support!</target>
</trans-unit>
<trans-unit id="ErrorOpenLockStillClosedTitle" translate="yes" xml:space="preserve">
<source>Lock can not be opened!</source>
<target state="translated">Schloss kann nicht geöffnet werden!</target>
</trans-unit>
<trans-unit id="ErrorOpenLockBoldIsBlockedMessage" translate="yes" xml:space="preserve">
<source>Ensure that no obstacle prevents lock from opening and try again.</source>
<target state="translated">Stellen Sie sicher, dass kein Hindernis das Öffnen des Schlosses verhindert und versuchen Sie es erneut.</target>
</trans-unit>
<trans-unit id="MarkingNoNetworkConnection" translate="yes" xml:space="preserve">
<source>Oops, there is no internet connection.</source>
<target state="translated">Ups, es ist keine Internetverbindung vorhanden.</target>
</trans-unit>
<trans-unit id="ChangeLog_3_0_358_MK_SB" translate="yes" xml:space="preserve">
<source>New functions:<bpt id="1">&lt;ul&gt;</bpt><bpt id="2">&lt;li&gt;</bpt>If your device is not connected to the Internet, this is now displayed at the top.<ept id="2">&lt;/li&gt;</ept><bpt id="3">&lt;li&gt;</bpt>You can now update your bike view by dragging from top to bottom. Especially useful after you reconnect to the Internet.<ept id="3">&lt;/li&gt;</ept><ept id="1">&lt;/ul&gt;</ept>
&lt;br/&gt;In addition:<bpt id="4">&lt;ul&gt;</bpt><bpt id="5">&lt;li&gt;</bpt>Software packages were updated.<ept id="5">&lt;/li&gt;</ept><bpt id="6">&lt;li&gt;</bpt>Minor bug fixes.<ept id="6">&lt;/li&gt;</ept><ept id="4">&lt;/ul&gt;</ept></source>
<target state="translated">Neue Funktionen:<bpt id="1">&lt;ul&gt;</bpt><bpt id="2">&lt;li&gt;</bpt>Wenn Ihr Gerät nicht mit dem Internet verbunden ist, wird dies nun oben angezeigt.<ept id="2">&lt;/li&gt;</ept><bpt id="3">&lt;li&gt;</bpt>Sie können jetzt Ihre Fahrradansicht aktualisieren, indem Sie von oben nach unten ziehen. Das ist besonders nützlich, wenn Sie sich wieder mit dem Internet verbunden haben.<ept id="3">&lt;/li&gt;</ept><ept id="1">&lt;/ul&gt;</ept>
&lt;br/&gt;Außerdem:<bpt id="4">&lt;ul&gt;</bpt><bpt id="5">&lt;li&gt;</bpt>Software Pakete wurde aktualisiert.<ept id="5">&lt;/li&gt;</ept><bpt id="6">&lt;li&gt;</bpt>Kleinere Fehlerbehebungen.<ept id="6">&lt;/li&gt;</ept><ept id="4">&lt;/ul&gt;</ept></target>
</trans-unit>
</group> </group>
</body> </body>
</file> </file>

View file

@ -26,12 +26,14 @@ namespace TINK.Repository
/// <param name="copriHost">Host to connect to. </param> /// <param name="copriHost">Host to connect to. </param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param> /// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param> /// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param>
public CopriCallsHttps( public CopriCallsHttps(
Uri copriHost, Uri copriHost,
AppContextInfo appContextInfo, AppContextInfo appContextInfo,
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie = null) string sessionCookie = null,
ISmartDevice smartDevice = null)
{ {
m_oCopriHost = copriHost m_oCopriHost = copriHost
?? throw new System.Exception($"Can not construct {GetType()}- object. Uri of copri host must not be null."); ?? throw new System.Exception($"Can not construct {GetType()}- object. Uri of copri host must not be null.");
@ -41,8 +43,8 @@ namespace TINK.Repository
: throw new System.Exception($"Can not construct {GetType()}- object. User agent must not be null or empty."); : throw new System.Exception($"Can not construct {GetType()}- object. User agent must not be null or empty.");
requestBuilder = string.IsNullOrEmpty(sessionCookie) requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(appContextInfo.MerchantId, uiIsoLangugageName) as IRequestBuilder ? new RequestBuilder(appContextInfo.MerchantId, uiIsoLangugageName, smartDevice) as IRequestBuilder
: new RequestBuilderLoggedIn(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie); : new RequestBuilderLoggedIn(appContextInfo.MerchantId, uiIsoLangugageName, sessionCookie, smartDevice);
} }
/// <summary> Holds the URL for rest calls.</summary> /// <summary> Holds the URL for rest calls.</summary>
@ -226,31 +228,27 @@ namespace TINK.Repository
/// <summary> Returns a bike. </summary> /// <summary> Returns a bike. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="location">Geolocation of lock.</param> /// <param name="location">Geolocation of lock.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param> /// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
public async Task<DoReturnResponse> DoReturn( public async Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto location, LocationDto location,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await DoReturn( => await DoReturn(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri, operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.DoReturn(bikeId, location, smartDevice), requestBuilder.DoReturn(bikeId, location),
UserAgent); UserAgent);
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param> /// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
public async Task<DoReturnResponse> ReturnAndStartClosingAsync( public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await DoReturn( => await DoReturn(
operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri, operatorUri?.AbsoluteUri ?? m_oCopriHost.AbsoluteUri,
requestBuilder.ReturnAndStartClosing(bikeId, smartDevice), requestBuilder.ReturnAndStartClosing(bikeId),
UserAgent); UserAgent);
/// <summary> Submits feedback to copri server. </summary> /// <summary> Submits feedback to copri server. </summary>
@ -325,15 +323,15 @@ namespace TINK.Repository
/// <param name="copriHost">Host to connect to. </param> /// <param name="copriHost">Host to connect to. </param>
/// <param name="command">Command to log user out.</param> /// <param name="command">Command to log user out.</param>
public static async Task<AuthorizationoutResponse> DoAuthoutAsync( public static async Task<AuthorizationoutResponse> DoAuthoutAsync(
string p_strCopriHost, string copriHost,
string p_oCommand, string command,
string userAgent = null) string userAgent = null)
{ {
#if !WINDOWS_UWP #if !WINDOWS_UWP
string l_oLogoutResponse; string logoutResponse;
try try
{ {
l_oLogoutResponse = await PostAsync(p_strCopriHost, p_oCommand, userAgent); logoutResponse = await PostAsync(copriHost, command, userAgent);
} }
catch (System.Exception l_oException) catch (System.Exception l_oException)
@ -352,7 +350,7 @@ namespace TINK.Repository
} }
/// Extract session cookie from response. /// Extract session cookie from response.
return CopriCallsStatic.DeserializeResponse<AuthorizationoutResponse>(l_oLogoutResponse, (version) => new UnsupportedCopriVersionDetectedException()); return CopriCallsStatic.DeserializeResponse<AuthorizationoutResponse>(logoutResponse, (version) => new UnsupportedCopriVersionDetectedException());
#else #else
return null; return null;
#endif #endif
@ -361,19 +359,19 @@ namespace TINK.Repository
/// <summary> /// <summary>
/// Get list of stations from file. /// Get list of stations from file.
/// </summary> /// </summary>
/// <param name="p_strCopriHost">URL of the copri host to connect to.</param> /// <param name="copriHost">URL of the copri host to connect to.</param>
/// <param name="p_oCommand">Command to get stations.</param> /// <param name="command">Command to get stations.</param>
/// <returns>List of files.</returns> /// <returns>List of files.</returns>
public static async Task<StationsAvailableResponse> GetStationsAsync( public static async Task<StationsAvailableResponse> GetStationsAsync(
string p_strCopriHost, string copriHost,
string p_oCommand, string command,
string userAgent = null) string userAgent = null)
{ {
#if !WINDOWS_UWP #if !WINDOWS_UWP
string response; string response;
try try
{ {
response = await PostAsync(p_strCopriHost, p_oCommand, userAgent); response = await PostAsync(copriHost, command, userAgent);
} }
catch (System.Exception l_oException) catch (System.Exception l_oException)
{ {
@ -401,7 +399,7 @@ namespace TINK.Repository
/// <summary> Gets a list of bikes from Copri. </summary> /// <summary> Gets a list of bikes from Copri. </summary>
/// <param name="copriHost">URL of the copri host to connect to.</param> /// <param name="copriHost">URL of the copri host to connect to.</param>
/// <param name="p_oCommand">Command to get bikes.</param> /// <param name="command">Command to get bikes.</param>
/// <returns>Response holding list of bikes.</returns> /// <returns>Response holding list of bikes.</returns>
public static async Task<BikesAvailableResponse> GetBikesAvailableAsync( public static async Task<BikesAvailableResponse> GetBikesAvailableAsync(
string copriHost, string copriHost,
@ -440,19 +438,19 @@ namespace TINK.Repository
} }
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary> /// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
/// <param name="p_strCopriHost">URL of the copri host to connect to.</param> /// <param name="copriHost">URL of the copri host to connect to.</param>
/// <param name="p_oCommand">Command to post.</param> /// <param name="command">Command to post.</param>
/// <returns>Response holding list of bikes.</returns> /// <returns>Response holding list of bikes.</returns>
public static async Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync( public static async Task<BikesReservedOccupiedResponse> GetBikesOccupiedAsync(
string p_strCopriHost, string copriHost,
string p_oCommand, string command,
string userAgent = null) string userAgent = null)
{ {
#if !WINDOWS_UWP #if !WINDOWS_UWP
string response; string response;
try try
{ {
response = await PostAsync(p_strCopriHost, p_oCommand, userAgent); response = await PostAsync(copriHost, command, userAgent);
} }
catch (System.Exception l_oException) catch (System.Exception l_oException)
{ {

View file

@ -1296,8 +1296,8 @@ namespace TINK.Repository
SessionCookie = sessionCookie; SessionCookie = sessionCookie;
requestBuilder = string.IsNullOrEmpty(sessionCookie) requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(MerchantId, null /*UI language */) as IRequestBuilder ? new RequestBuilder(MerchantId, null /*UI language */, null /* smart device */) as IRequestBuilder
: new RequestBuilderLoggedIn(MerchantId, null /*UI language */, sessionCookie); : new RequestBuilderLoggedIn(MerchantId, null /*UI language */, sessionCookie, null /* smart device */);
} }
@ -1358,7 +1358,7 @@ namespace TINK.Repository
/// <summary> /// <summary>
/// Get list of stations from file. /// Get list of stations from file.
/// </summary> /// </summary>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param> /// <param name="cookie">Auto cookie of user if user is logged in.</param>
/// <returns>List of files.</returns> /// <returns>List of files.</returns>
public async Task<StationsAvailableResponse> GetStationsAsync() public async Task<StationsAvailableResponse> GetStationsAsync()
{ {
@ -1379,7 +1379,7 @@ namespace TINK.Repository
/// Gets canel booking request response. /// Gets canel booking request response.
/// </summary> /// </summary>
/// <param name="bikeId">Id of the bike to book.</param> /// <param name="bikeId">Id of the bike to book.</param>
/// <param name="p_strCookie">Cookie of the logged in user.</param> /// <param name="cookie">Cookie of the logged in user.</param>
/// <returns>Response on cancel booking request.</returns> /// <returns>Response on cancel booking request.</returns>
public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri) public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri)
{ {
@ -1546,14 +1546,14 @@ namespace TINK.Repository
/// <summary> /// <summary>
/// Gets stations response. /// Gets stations response.
/// </summary> /// </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param> /// <param name="merchantId">Id of the merchant.</param>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param> /// <param name="cookie">Auto cookie of user if user is logged in.</param>
/// <param name="p_eSampleSet"></param> /// <param name="p_eSampleSet"></param>
/// <param name="p_lStageIndex"></param> /// <param name="p_lStageIndex"></param>
/// <returns></returns> /// <returns></returns>
public static StationsAvailableResponse GetStationsAll( public static StationsAvailableResponse GetStationsAll(
string p_strMerchantId, string merchantId,
string p_strCookie = null, string cookie = null,
SampleSets p_eSampleSet = DEFAULT_SAMPLE_SET, SampleSets p_eSampleSet = DEFAULT_SAMPLE_SET,
long p_lStageIndex = DEFAULT_STAGE_INDEX) long p_lStageIndex = DEFAULT_STAGE_INDEX)
{ {
@ -1657,13 +1657,11 @@ namespace TINK.Repository
public Task<DoReturnResponse> DoReturn( public Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto geolocation, LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> null; => null;
public Task<DoReturnResponse> ReturnAndStartClosingAsync( public Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();

View file

@ -117,20 +117,22 @@ namespace TINK.Repository
public string SessionCookie => requestBuilder.SessionCookie; public string SessionCookie => requestBuilder.SessionCookie;
/// <summary> Initializes a instance of the copri monkey store object. </summary> /// <summary> Initializes a instance of the copri monkey store object. </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param> /// <param name="merchantId">Id of the merchant.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param> /// <param name="sessionCookie">Session cookie if user is logged in, null otherwise.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
public CopriCallsMonkeyStore( public CopriCallsMonkeyStore(
string merchantId, string merchantId,
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie = null, string sessionCookie = null,
ISmartDevice smartDevice = null,
TimeSpan? expiresAfter = null) TimeSpan? expiresAfter = null)
{ {
ExpiresAfter = expiresAfter ?? TimeSpan.FromSeconds(1); ExpiresAfter = expiresAfter ?? TimeSpan.FromSeconds(1);
requestBuilder = string.IsNullOrEmpty(sessionCookie) requestBuilder = string.IsNullOrEmpty(sessionCookie)
? new RequestBuilder(merchantId, uiIsoLangugageName) as IRequestBuilder ? new RequestBuilder(merchantId, uiIsoLangugageName, smartDevice) as IRequestBuilder
: new RequestBuilderLoggedIn(merchantId, uiIsoLangugageName, sessionCookie); : new RequestBuilderLoggedIn(merchantId, uiIsoLangugageName, sessionCookie, smartDevice);
// Ensure that store holds valid entries. // Ensure that store holds valid entries.
if (!Barrel.Current.Exists(requestBuilder.GetBikesAvailable())) if (!Barrel.Current.Exists(requestBuilder.GetBikesAvailable()))
@ -201,18 +203,15 @@ namespace TINK.Repository
public Task<DoReturnResponse> DoReturn( public Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto geolocation, LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!"); => throw new System.Exception("Rückgabe im Offlinemodus nicht möglich!");
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param> /// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
public Task<DoReturnResponse> ReturnAndStartClosingAsync( public Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> throw new System.Exception("Rückgabe mit Schloss schließen Befehl im Offlinemodus nicht möglich!"); => throw new System.Exception("Rückgabe mit Schloss schließen Befehl im Offlinemodus nicht möglich!");

View file

@ -107,13 +107,11 @@ namespace TINK.Repository
/// <summary> Returns a bike. </summary> /// <summary> Returns a bike. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="location">Geolocation of lock.</param> /// <param name="location">Geolocation of lock.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param> /// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
Task<DoReturnResponse> DoReturn( Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto location, LocationDto location,
ISmartDevice smartDevice,
Uri operatorUri); Uri operatorUri);
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
@ -123,7 +121,6 @@ namespace TINK.Repository
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
Task<DoReturnResponse> ReturnAndStartClosingAsync( Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri); Uri operatorUri);
/// <summary> /// <summary>

View file

@ -2,7 +2,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Connector; using TINK.Model.Connector;
using TINK.Model.Device;
namespace TINK.Repository.Request namespace TINK.Repository.Request
{ {
@ -26,7 +25,7 @@ namespace TINK.Repository.Request
string deviceId); string deviceId);
/// <summary> Logs user out. </summary> /// <summary> Logs user out. </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param> /// <param name="merchantId">Id of the merchant.</param>
/// <param name="p_strSessionCookie"> Cookie which identifies user.</param> /// <param name="p_strSessionCookie"> Cookie which identifies user.</param>
string DoAuthout(); string DoAuthout();
@ -98,13 +97,13 @@ namespace TINK.Repository.Request
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="location">Geolocation of lock when returning bike.</param> /// <param name="location">Geolocation of lock when returning bike.</param>
/// <returns>Requst on returning request.</returns> /// <returns>Requst on returning request.</returns>
string DoReturn(string bikeId, LocationDto location, ISmartDevice smartDevice); string DoReturn(string bikeId, LocationDto location);
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param> /// <param name="smartDevice">Provides info about hard and software.</param>
/// <returns>Response to send to corpi.</returns> /// <returns>Response to send to corpi.</returns>
string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice); string ReturnAndStartClosing(string bikeId);
/// <summary> /// <summary>
/// Gets request for submiting feedback to copri server. /// Gets request for submiting feedback to copri server.

View file

@ -14,9 +14,11 @@ namespace TINK.Repository.Request
/// <summary> Constructs a object for building requests. </summary> /// <summary> Constructs a object for building requests. </summary>
/// <param name="merchantId">Holds the id denoting the merchant.</param> /// <param name="merchantId">Holds the id denoting the merchant.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
public RequestBuilder( public RequestBuilder(
string merchantId, string merchantId,
string uiIsoLangugageName) string uiIsoLangugageName,
ISmartDevice smartDevice = null)
{ {
MerchantId = !string.IsNullOrEmpty(merchantId) MerchantId = !string.IsNullOrEmpty(merchantId)
? merchantId ? merchantId
@ -25,6 +27,8 @@ namespace TINK.Repository.Request
UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(WebUtility.UrlEncode(uiIsoLangugageName)); UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(WebUtility.UrlEncode(uiIsoLangugageName));
AuthCookieParameter = $"&authcookie={WebUtility.UrlEncode(MerchantId)}"; AuthCookieParameter = $"&authcookie={WebUtility.UrlEncode(MerchantId)}";
SmartDevice = smartDevice;
} }
/// <summary>Holds the id denoting the merchant.</summary> /// <summary>Holds the id denoting the merchant.</summary>
@ -39,6 +43,9 @@ namespace TINK.Repository.Request
/// <summary> Auth cookie parameter. </summary> /// <summary> Auth cookie parameter. </summary>
private string AuthCookieParameter { get; } private string AuthCookieParameter { get; }
/// <summary>Holds info about smart device.</summary>
private ISmartDevice SmartDevice { get; }
/// <summary> Gets request to log user in. </summary> /// <summary> Gets request to log user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param> /// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="password">Password to log in.</param> /// <param name="password">Password to log in.</param>
@ -71,6 +78,7 @@ namespace TINK.Repository.Request
public string GetStations() public string GetStations()
=> "request=stations_available" + => "request=stations_available" +
AuthCookieParameter + AuthCookieParameter +
SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
/// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary> /// <summary> Gets a list of bikes reserved/ booked by acctive user from Copri.</summary>
@ -125,14 +133,14 @@ namespace TINK.Repository.Request
public string BookReservedAndStartOpening(string bikeId) public string BookReservedAndStartOpening(string bikeId)
=> throw new NotSupportedException(); => throw new NotSupportedException();
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) public string DoReturn(string bikeId, LocationDto geolocation)
=> throw new NotSupportedException(); => throw new NotSupportedException();
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param> /// <param name="smartDevice">Provides info about hard and software.</param>
/// <returns>Response to send to corpi.</returns> /// <returns>Response to send to corpi.</returns>
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice) public string ReturnAndStartClosing(string bikeId)
=> throw new NotSupportedException(); => throw new NotSupportedException();
/// <summary> Gets submit feedback request. </summary> /// <summary> Gets submit feedback request. </summary>

View file

@ -1,5 +1,7 @@
using System.Net;
using TINK.Model.Connector; using TINK.Model.Connector;
using TINK.Model.Device;
namespace TINK.Repository.Request namespace TINK.Repository.Request
{ {
@ -29,5 +31,16 @@ namespace TINK.Repository.Request
return null; return null;
} }
} }
/// <summary> Gets the smart device parameters. </summary>
/// <returns>in a format which is urlencode invariant.</returns>
public static string GetSmartDeviceParameters(this ISmartDevice smartDevice)
=> smartDevice != null
? $"{(!string.IsNullOrEmpty(smartDevice.Manufacturer) ? $"&user_device_manufacturer={WebUtility.UrlEncode(smartDevice.Manufacturer)}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Model) ? $"&user_device_model={WebUtility.UrlEncode(smartDevice.Model)}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Platform.ToString()) ? $"&user_device_platform={WebUtility.UrlEncode(smartDevice.Platform.ToString())}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.VersionText) ? $"&user_device_version={WebUtility.UrlEncode(smartDevice.VersionText)}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Identifier) ? $"&user_device_id={WebUtility.UrlEncode(smartDevice.Identifier)}" : string.Empty)}"
: string.Empty;
} }
} }

View file

@ -17,10 +17,12 @@ namespace TINK.Repository.Request
/// <summary> Constructs a object for building requests. </summary> /// <summary> Constructs a object for building requests. </summary>
/// <param name="merchantId">Holds the id denoting the merchant.</param> /// <param name="merchantId">Holds the id denoting the merchant.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
public RequestBuilderLoggedIn( public RequestBuilderLoggedIn(
string merchantId, string merchantId,
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie) string sessionCookie,
ISmartDevice smartDevice = null)
{ {
MerchantId = !string.IsNullOrEmpty(merchantId) MerchantId = !string.IsNullOrEmpty(merchantId)
? merchantId ? merchantId
@ -33,6 +35,8 @@ namespace TINK.Repository.Request
UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(WebUtility.UrlEncode(uiIsoLangugageName)); UiIsoLanguageNameParameter = RequestBuilderHelper.GetLanguageParameter(WebUtility.UrlEncode(uiIsoLangugageName));
AuthCookieParameter = $"&authcookie={WebUtility.UrlEncode(SessionCookie)}{WebUtility.UrlEncode(MerchantId)}"; AuthCookieParameter = $"&authcookie={WebUtility.UrlEncode(SessionCookie)}{WebUtility.UrlEncode(MerchantId)}";
SmartDevice = smartDevice;
} }
/// <summary> Holds the id denoting the merchant. </summary> /// <summary> Holds the id denoting the merchant. </summary>
@ -47,6 +51,9 @@ namespace TINK.Repository.Request
/// <summary> Auth cookie parameter. </summary> /// <summary> Auth cookie parameter. </summary>
private string AuthCookieParameter { get; } private string AuthCookieParameter { get; }
/// <summary>Holds info about smart device.</summary>
private ISmartDevice SmartDevice { get; }
/// <summary> Gets request to log user in. </summary> /// <summary> Gets request to log user in. </summary>
/// <param name="mailAddress">Mailaddress of user to log in.</param> /// <param name="mailAddress">Mailaddress of user to log in.</param>
/// <param name="password">Password to log in.</param> /// <param name="password">Password to log in.</param>
@ -83,6 +90,7 @@ namespace TINK.Repository.Request
public string GetStations() public string GetStations()
=> "request=stations_available" + => "request=stations_available" +
AuthCookieParameter + AuthCookieParameter +
SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
/// <summary> Gets reservation request (synonym: reservation == request == reservieren). </summary> /// <summary> Gets reservation request (synonym: reservation == request == reservieren). </summary>
@ -93,6 +101,7 @@ namespace TINK.Repository.Request
=> "request=booking_request" + => "request=booking_request" +
GetBikeIdParameter(bikeId) + GetBikeIdParameter(bikeId) +
AuthCookieParameter + AuthCookieParameter +
SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
/// <summary> Gets request to cancel reservation. </summary> /// <summary> Gets request to cancel reservation. </summary>
@ -175,6 +184,7 @@ namespace TINK.Repository.Request
AuthCookieParameter + AuthCookieParameter +
"&state=occupied" + "&state=occupied" +
GetLockStateParameter(lock_state.unlocking) + GetLockStateParameter(lock_state.unlocking) +
SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
/// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary> /// <summary> Gets the request to book and start opening the bike (synonym: booking == renting == mieten). </summary>
@ -193,14 +203,14 @@ namespace TINK.Repository.Request
/// <param name="bikeId">Id of bike to return.</param> /// <param name="bikeId">Id of bike to return.</param>
/// <param name="geolocation">Geolocation of lock when returning bike.</param> /// <param name="geolocation">Geolocation of lock when returning bike.</param>
/// <returns>Requst on returning request.</returns> /// <returns>Requst on returning request.</returns>
public string DoReturn(string bikeId, LocationDto geolocation, ISmartDevice smartDevice) public string DoReturn(string bikeId, LocationDto geolocation)
=> "request=booking_update" + => "request=booking_update" +
GetBikeIdParameter(bikeId) + GetBikeIdParameter(bikeId) +
AuthCookieParameter + AuthCookieParameter +
"&state=available" + "&state=available" +
GetLocationParameters(geolocation) + GetLocationParameters(geolocation) +
GetLockStateParameter(lock_state.locked) + GetLockStateParameter(lock_state.locked) +
GetSmartDeviceParameters(smartDevice) + SmartDevice.GetSmartDeviceParameters() +
GetLog() + GetLog() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
@ -209,13 +219,13 @@ namespace TINK.Repository.Request
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param> /// <param name="smartDevice">Provides info about hard and software.</param>
/// <returns>Response to send to corpi.</returns> /// <returns>Response to send to corpi.</returns>
public string ReturnAndStartClosing(string bikeId, ISmartDevice smartDevice) public string ReturnAndStartClosing(string bikeId)
=> "request=booking_update" + => "request=booking_update" +
GetBikeIdParameter(bikeId) + GetBikeIdParameter(bikeId) +
AuthCookieParameter + AuthCookieParameter +
"&state=available" + "&state=available" +
GetLockStateParameter(lock_state.locking) + GetLockStateParameter(lock_state.locking) +
GetSmartDeviceParameters(smartDevice) + SmartDevice.GetSmartDeviceParameters() +
UiIsoLanguageNameParameter; UiIsoLanguageNameParameter;
/// <summary> Gets submit feedback request. </summary> /// <summary> Gets submit feedback request. </summary>
@ -315,17 +325,6 @@ namespace TINK.Repository.Request
return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_accuracy={geolocation.Accuracy.Value.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}"; return $"&gps={geolocation.Latitude.ToString(CultureInfo.InvariantCulture)},{geolocation.Longitude.ToString(CultureInfo.InvariantCulture)}&gps_accuracy={geolocation.Accuracy.Value.ToString(CultureInfo.InvariantCulture)}&gps_age={geolocation.Age.TotalSeconds}";
} }
/// <summary> Gets the geolocation parameter. </summary>
/// <returns>in a format which is urlencode invariant.</returns>
private static string GetSmartDeviceParameters(ISmartDevice smartDevice)
=> smartDevice != null
? $"{(!string.IsNullOrEmpty(smartDevice.Manufacturer) ? $"&user_device_manufaturer={WebUtility.UrlEncode(smartDevice.Manufacturer)})" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Model) ? $"&user_device_model={WebUtility.UrlEncode(smartDevice.Model)}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Platform.ToString()) ? $"&user_device_platform={WebUtility.UrlEncode(smartDevice.Platform.ToString())}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.VersionText) ? $"&user_device_version={WebUtility.UrlEncode(smartDevice.VersionText)}" : string.Empty)}" +
$"{(!string.IsNullOrEmpty(smartDevice.Identifier) ? $"&user_device_id={WebUtility.UrlEncode(smartDevice.Identifier)}" : string.Empty)}"
: string.Empty;
/// <summary> /// <summary>
/// Gets logging entries from serilog. /// Gets logging entries from serilog.
/// </summary> /// </summary>

View file

@ -12,7 +12,7 @@ using TINK.Repository.Response;
namespace TINK.Model.Services.CopriApi namespace TINK.Model.Services.CopriApi
{ {
/// <summary> Object which manages calls to copri in a thread safe way inclding cache functionality. </summary> /// <summary> Object which manages calls to copri in a thread safe way including cache functionality. </summary>
public class CopriProviderHttps : ICachedCopriServer public class CopriProviderHttps : ICachedCopriServer
{ {
/// <summary> Object which manages stored copri answers. </summary> /// <summary> Object which manages stored copri answers. </summary>
@ -34,6 +34,7 @@ namespace TINK.Model.Services.CopriApi
/// <param name="copriHost"></param> /// <param name="copriHost"></param>
/// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param> /// <param name="appContextInfo">Provides app related info (app name and version, merchantid) to pass to COPRI.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
/// <param name="sessionCookie">Cookie of user if a user is logged in, false otherwise.</param> /// <param name="sessionCookie">Cookie of user if a user is logged in, false otherwise.</param>
/// <param name="expiresAfter">Timespan which holds value after which cache expires.</param> /// <param name="expiresAfter">Timespan which holds value after which cache expires.</param>
public CopriProviderHttps( public CopriProviderHttps(
@ -41,13 +42,14 @@ namespace TINK.Model.Services.CopriApi
string merchantId, string merchantId,
AppContextInfo appContextInfo, AppContextInfo appContextInfo,
string uiIsoLangugageName, string uiIsoLangugageName,
ISmartDevice smartDevice = null,
string sessionCookie = null, string sessionCookie = null,
TimeSpan? expiresAfter = null, TimeSpan? expiresAfter = null,
ICopriCache cacheServer = null, ICopriCache cacheServer = null,
ICopriServer httpsServer = null) ICopriServer httpsServer = null)
{ {
CacheServer = cacheServer ?? new CopriCallsMonkeyStore(merchantId, uiIsoLangugageName, sessionCookie, expiresAfter); CacheServer = cacheServer ?? new CopriCallsMonkeyStore(merchantId, uiIsoLangugageName, sessionCookie, smartDevice, expiresAfter);
HttpsServer = httpsServer ?? new CopriCallsHttps(copriHost, appContextInfo, uiIsoLangugageName, sessionCookie); HttpsServer = httpsServer ?? new CopriCallsHttps(copriHost, appContextInfo, uiIsoLangugageName, sessionCookie, smartDevice);
} }
/// <summary>Gets bikes available.</summary> /// <summary>Gets bikes available.</summary>
@ -275,20 +277,17 @@ namespace TINK.Model.Services.CopriApi
public async Task<DoReturnResponse> DoReturn( public async Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto location, LocationDto location,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await HttpsServer.DoReturn(bikeId, location, smartDevice, operatorUri); => await HttpsServer.DoReturn(bikeId, location, operatorUri);
/// <summary> Returns a bike and starts closing. </summary> /// <summary> Returns a bike and starts closing. </summary>
/// <param name="bikeId">Id of the bike to return.</param> /// <param name="bikeId">Id of the bike to return.</param>
/// <param name="smartDevice">Provides info about hard and software.</param>
/// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param> /// <param name="operatorUri">Holds the uri of the operator or null, in case of single operator setup.</param>
/// <returns>Response on returning request.</returns> /// <returns>Response on returning request.</returns>
public async Task<DoReturnResponse> ReturnAndStartClosingAsync( public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await HttpsServer.ReturnAndStartClosingAsync(bikeId, smartDevice, operatorUri); => await HttpsServer.ReturnAndStartClosingAsync(bikeId, operatorUri);
/// <summary> /// <summary>
/// Submits feedback to copri server. /// Submits feedback to copri server.

View file

@ -11,6 +11,7 @@ using TINK.Services.CopriApi.Exception;
namespace TINK.Model.Services.CopriApi namespace TINK.Model.Services.CopriApi
{ {
/// <summary> Object which manages calls to cache. </summary>
public class CopriProviderMonkeyStore : ICopriServer public class CopriProviderMonkeyStore : ICopriServer
{ {
/// <summary> Object which manages stored copri answers. </summary> /// <summary> Object which manages stored copri answers. </summary>
@ -25,12 +26,14 @@ namespace TINK.Model.Services.CopriApi
/// <summary> Constructs object which Object which manages stored copri answers in a thread save way. </summary> /// <summary> Constructs object which Object which manages stored copri answers in a thread save way. </summary>
/// <param name="merchantId">Id of the merchant TINK-App.</param> /// <param name="merchantId">Id of the merchant TINK-App.</param>
/// <param name="uiIsoLangugageName">Two letter ISO language name.</param> /// <param name="uiIsoLangugageName">Two letter ISO language name.</param>
/// <param name="smartDevice">Holds info about smart device.</param>
public CopriProviderMonkeyStore( public CopriProviderMonkeyStore(
string merchantId, string merchantId,
string uiIsoLangugageName, string uiIsoLangugageName,
string sessionCookie) string sessionCookie,
ISmartDevice smartDevice = null)
{ {
monkeyStore = new CopriCallsMonkeyStore(merchantId, uiIsoLangugageName, sessionCookie); monkeyStore = new CopriCallsMonkeyStore(merchantId, uiIsoLangugageName, sessionCookie, smartDevice);
} }
/// <summary> Gets the merchant id.</summary> /// <summary> Gets the merchant id.</summary>
@ -82,15 +85,13 @@ namespace TINK.Model.Services.CopriApi
public async Task<DoReturnResponse> DoReturn( public async Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto geolocation, LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await monkeyStore.DoReturn(bikeId, geolocation, smartDevice, operatorUri); => await monkeyStore.DoReturn(bikeId, geolocation, operatorUri);
public async Task<DoReturnResponse> ReturnAndStartClosingAsync( public async Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> await monkeyStore.ReturnAndStartClosingAsync(bikeId, smartDevice, operatorUri); => await monkeyStore.ReturnAndStartClosingAsync(bikeId, operatorUri);
public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, int? currentChargeBars, string messge, bool bIsBikeBroke, Uri operatorUri) public Task<SubmitFeedbackResponse> DoSubmitFeedback(string bikeId, int? currentChargeBars, string messge, bool bIsBikeBroke, Uri operatorUri)
=> throw new RequestNotCachableException(nameof(DoSubmitFeedback)); => throw new RequestNotCachableException(nameof(DoSubmitFeedback));

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -20,18 +20,28 @@ namespace TINK.Services.CopriApi
/// <summary> Timeout for open/ close operations.</summary> /// <summary> Timeout for open/ close operations.</summary>
private const int OPEN_CLOSE_TIMEOUT_MS = 50000; private const int OPEN_CLOSE_TIMEOUT_MS = 50000;
/// <summary> Opens lock.</summary>
/// <param name="copriServer"> Instance to communicate with backend.</param>
/// <param name="bike">Bike object holding id of bike to open. Lock state of object is updated after open request.</param>
public static async Task OpenAync(
this ICopriServerBase copriServer,
IBikeInfoMutable bike)
{
if (!(copriServer is ICachedCopriServer cachedServer))
throw new ArgumentNullException(nameof(copriServer));
await cachedServer.OpenAync(bike);
}
/// <summary> Opens lock.</summary> /// <summary> Opens lock.</summary>
/// <param name="corpiServer"> Instance to communicate with backend.</param> /// <param name="corpiServer"> Instance to communicate with backend.</param>
/// <param name="bike">Bike object holding id of bike to open. Lock state of object is updated after open request.</param> /// <param name="bike">Bike object holding id of bike to open. Lock state of object is updated after open request.</param>
public static async Task OpenAync( public static async Task OpenAync(
this ICopriServerBase corpiServer, this ICachedCopriServer cachedServer,
IBikeInfoMutable bike) IBikeInfoMutable bike)
{ {
if (!(corpiServer is ICachedCopriServer cachedServer))
throw new ArgumentNullException(nameof(corpiServer));
// Send command to close lock // Send command to close lock
await corpiServer.UpdateLockingStateAsync( await cachedServer.UpdateLockingStateAsync(
bike.Id, bike.Id,
Repository.Request.lock_state.unlocking, Repository.Request.lock_state.unlocking,
bike.OperatorUri); bike.OperatorUri);
@ -169,7 +179,7 @@ namespace TINK.Services.CopriApi
// Send command to open lock // Send command to open lock
DoReturnResponse response = DoReturnResponse response =
await corpiServer.ReturnAndStartClosingAsync(bike.Id, smartDevice, bike.OperatorUri); await corpiServer.ReturnAndStartClosingAsync(bike.Id, bike.OperatorUri);
// Upate booking state // Upate booking state
bike.Load(Model.Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None); bike.Load(Model.Bikes.BikeInfoNS.BC.NotifyPropertyChangedLevel.None);

View file

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Label="MultilingualAppToolkit"> <PropertyGroup Label="MultilingualAppToolkit">
<MultilingualAppToolkitVersion>4.0</MultilingualAppToolkitVersion> <MultilingualAppToolkitVersion>4.0</MultilingualAppToolkitVersion>
@ -44,7 +44,7 @@
<PackageReference Include="System.Xml.XDocument" Version="4.3.0" /> <PackageReference Include="System.Xml.XDocument" Version="4.3.0" />
<PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" /> <PackageReference Include="Xam.Plugin.Connectivity" Version="3.2.0" />
<PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" /> <PackageReference Include="Xam.Plugins.Messaging" Version="5.2.0" />
<PackageReference Include="Xamarin.Essentials" Version="1.7.4" /> <PackageReference Include="Xamarin.Essentials" Version="1.7.5" />
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" /> <PackageReference Include="Xamarin.Forms" Version="5.0.0.2545" />
<PackageReference Include="Xamarin.Forms.GoogleMaps" Version="5.0.0" /> <PackageReference Include="Xamarin.Forms.GoogleMaps" Version="5.0.0" />
</ItemGroup> </ItemGroup>

View file

@ -9,6 +9,9 @@
<!--Secondary color--> <!--Secondary color-->
<Color x:Key="secondary-back-title-color">#FF0020</Color> <Color x:Key="secondary-back-title-color">#FF0020</Color>
<!--Attention color-->
<Color x:Key="attention-color">#06D1B1</Color>
<!--Primary Button--> <!--Primary Button-->
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="WidthRequest" Value="400" /> <Setter Property="WidthRequest" Value="400" />

View file

@ -6,6 +6,9 @@
<!--Main color--> <!--Main color-->
<Color x:Key="primary-back-title-color">#009899</Color> <Color x:Key="primary-back-title-color">#009899</Color>
<!--Attention color-->
<Color x:Key="attention-color">#FC870D</Color>
<!--Primary Button--> <!--Primary Button-->
<Style TargetType="Button"> <Style TargetType="Button">
<Setter Property="WidthRequest" Value="400" /> <Setter Property="WidthRequest" Value="400" />

View file

@ -2,9 +2,11 @@ using System;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using Plugin.Connectivity;
using TINK.Model.Connector; using TINK.Model.Connector;
using TINK.Model.Device; using TINK.Model.Device;
using TINK.Model.User; using TINK.Model.User;
using TINK.MultilingualResources;
using TINK.Services.BluetoothLock; using TINK.Services.BluetoothLock;
using TINK.Services.Geolocation; using TINK.Services.Geolocation;
using TINK.View; using TINK.View;
@ -20,6 +22,8 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// </summary> /// </summary>
public class BikeViewModel : BikeViewModelBase, INotifyPropertyChanged public class BikeViewModel : BikeViewModelBase, INotifyPropertyChanged
{ {
public Xamarin.Forms.Command ShowTrackingInfoCommand { get; private set; }
/// <summary> Notifies GUI about changes. </summary> /// <summary> Notifies GUI about changes. </summary>
public override event PropertyChangedEventHandler PropertyChanged; public override event PropertyChangedEventHandler PropertyChanged;
@ -39,12 +43,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
string lastStateText = null, string lastStateText = null,
Xamarin.Forms.Color? lastStateColor = null) Xamarin.Forms.Color? lastStateColor = null)
{ {
if (IsDataFromCache != IsDataFromCache)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsDataFromCache)));
}
if (lastHandler.ButtonText != ButtonText) if (lastHandler.ButtonText != ButtonText)
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ButtonText)));
@ -105,6 +103,15 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
IBikesViewModel bikesViewModel, IBikesViewModel bikesViewModel,
Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, stateInfoProvider, bikesViewModel, openUrlInBrowser) Action<string> openUrlInBrowser) : base(isConnectedDelegate, connectorFactory, bikeRemoveDelegate, viewUpdateManager, smartDevice, viewService, selectedBike, user, stateInfoProvider, bikesViewModel, openUrlInBrowser)
{ {
ShowTrackingInfoCommand = new Xamarin.Forms.Command(async () => {
await ViewService.DisplayAlert(
"Tracking",
TariffDescription.TrackingInfoText,
AppResources.MessageAnswerOk);
});
RequestHandler = user.IsLoggedIn RequestHandler = user.IsLoggedIn
? RequestHandlerFactory.Create( ? RequestHandlerFactory.Create(
selectedBike, selectedBike,
@ -132,7 +139,6 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
{ {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsButtonVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLockitButtonVisible))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsLockitButtonVisible)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsDataFromCache)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnButtonClicked))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnButtonClicked)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnLockitButtonClicked))); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(OnLockitButtonClicked)));
}; };
@ -175,15 +181,13 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock
/// <summary> Gets the text of the ILockIt command button. </summary> /// <summary> Gets the text of the ILockIt command button. </summary>
public string LockitButtonText => RequestHandler.LockitButtonText; public string LockitButtonText => RequestHandler.LockitButtonText;
/// <summary> True if Data is from Cache. </summary> /// <summary> Processes request to perform a copri action (reserve bike and cancel reservation).
public bool IsDataFromCache /// Button only enabled if data is up to date = not from cache. </summary>
=> Bike.DataSource == Model.Bikes.BikeInfoNS.BC.DataSource.Cache; public System.Windows.Input.ICommand OnButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption1()));
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary> /// <summary> Processes request to perform a ILockIt action (unlock bike and lock bike).
public System.Windows.Input.ICommand OnButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption1()), () => !IsDataFromCache); /// Button only enabled if data is up to date = not from cache. </summary>
public System.Windows.Input.ICommand OnLockitButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption2()));
/// <summary> Processes request to perform a ILockIt action (unlock bike and lock bike). </summary>
public System.Windows.Input.ICommand OnLockitButtonClicked => new Xamarin.Forms.Command(async () => await ClickButton(RequestHandler.HandleRequestOption2()), () => !IsDataFromCache);
/// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary> /// <summary> Processes request to perform a copri action (reserve bike and cancel reservation). </summary>
private async Task ClickButton(Task<IRequestHandler> handleRequest) private async Task ClickButton(Task<IRequestHandler> handleRequest)

View file

@ -342,16 +342,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<BookedClosed>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<BookedClosed>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
"OK"); "OK");
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -94,16 +94,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<BookedUnknown>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -283,16 +283,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<DisposableDisconnected>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<DisposableDisconnected>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -248,16 +248,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<ReservedClosed>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -411,16 +411,16 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<ReservedDisconnected>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<ReservedDisconnected>().Debug("Lock can not be opened. Bold status is unknown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -86,20 +86,20 @@ namespace TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
} }
else if (exception is CouldntOpenBoldIsBlockedException) else if (exception is CouldntOpenBoldIsBlockedException)
{ {
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. Bold is blocked. {Exception}", exception); Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. bold is blocked. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockTitle, AppResources.ErrorOpenLockTitle,
AppResources.ErrorOpenLockBoldBlockedMessage, AppResources.ErrorOpenLockBoldIsBlockedMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenBoldWasBlockedException) else if (exception is CouldntOpenBoldStatusIsUnknownException)
{ {
Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. Bold was or is blocked. {Exception}", exception); Log.ForContext<ReservedUnknown>().Debug("Lock can not be opened. lock reports state unkwnown. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
AppResources.ErrorOpenLockStillOpenTitle, AppResources.ErrorOpenLockStillClosedTitle,
AppResources.ErrorOpenLockBoldWasBlockedMessage, AppResources.ErrorOpenLockBoldStatusIsUnknownMessage,
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
else if (exception is CouldntOpenInconsistentStateExecption inconsistentState else if (exception is CouldntOpenInconsistentStateExecption inconsistentState

View file

@ -9,6 +9,8 @@ namespace TINK.ViewModel.Bikes.Bike
/// </summary> /// </summary>
public class TariffDescriptionViewModel public class TariffDescriptionViewModel
{ {
private const string TRACKINGKEY = "TRACKING";
public TariffDescriptionViewModel(RentalDescription tariff) public TariffDescriptionViewModel(RentalDescription tariff)
{ {
Name = tariff?.Name ?? string.Empty; Name = tariff?.Name ?? string.Empty;
@ -18,8 +20,13 @@ namespace TINK.ViewModel.Bikes.Bike
: new ObservableCollection<RentalDescription.TariffElement>(); : new ObservableCollection<RentalDescription.TariffElement>();
InfoEntries = tariff != null && tariff?.InfoEntries != null InfoEntries = tariff != null && tariff?.InfoEntries != null
? new ObservableCollection<string>(tariff.InfoEntries.OrderBy(x => x.Key).Select(x => x.Value.Value)) ? new ObservableCollection<string>(tariff.InfoEntries
.Where(x => x.Value.Key.ToUpper() != TRACKINGKEY)
.OrderBy(x => x.Key)
.Select(x => x.Value.Value))
: new ObservableCollection<string>(); : new ObservableCollection<string>();
TrackingInfoText = tariff?.InfoEntries != null ? tariff?.InfoEntries?.FirstOrDefault(x => x.Value.Key.ToUpper() == TRACKINGKEY).Value?.Value ?? string.Empty : string.Empty;
} }
/// <summary> /// <summary>
@ -37,11 +44,15 @@ namespace TINK.ViewModel.Bikes.Bike
/// </summary> /// </summary>
public ObservableCollection<string> InfoEntries { get; private set; } public ObservableCollection<string> InfoEntries { get; private set; }
/// <summary>
/// Holds the tracking info text or empty if not applicable.
/// </summary>
public string TrackingInfoText { get; private set; }
public RentalDescription.TariffElement TarifEntry1 => TariffEntries.Count > 0 ? TariffEntries[0] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry1 => TariffEntries.Count > 0 ? TariffEntries[0] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry2 => TariffEntries.Count > 1 ? TariffEntries[1] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry2 => TariffEntries.Count > 1 ? TariffEntries[1] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry3 => TariffEntries.Count > 2 ? TariffEntries[2] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry3 => TariffEntries.Count > 2 ? TariffEntries[2] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry4 => TariffEntries.Count > 3 ? TariffEntries[3] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry4 => TariffEntries.Count > 3 ? TariffEntries[3] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry5 => TariffEntries.Count > 4 ? TariffEntries[4] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry5 => TariffEntries.Count > 4 ? TariffEntries[4] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry6 => TariffEntries.Count > 5 ? TariffEntries[5] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry6 => TariffEntries.Count > 5 ? TariffEntries[5] : new RentalDescription.TariffElement();
public RentalDescription.TariffElement TarifEntry7 => TariffEntries.Count > 6 ? TariffEntries[6] : new RentalDescription.TariffElement(); public RentalDescription.TariffElement TarifEntry7 => TariffEntries.Count > 6 ? TariffEntries[6] : new RentalDescription.TariffElement();

View file

@ -152,8 +152,6 @@ namespace TINK.ViewModel.Bikes
m_oPolling = polling; m_oPolling = polling;
isConnected = IsConnectedDelegate();
OpenUrlInBrowser = openUrlInBrowser; OpenUrlInBrowser = openUrlInBrowser;
CollectionChanged += (sender, eventargs) => CollectionChanged += (sender, eventargs) =>
@ -389,11 +387,6 @@ namespace TINK.ViewModel.Bikes
return Exception.GetShortErrorInfoText(IsReportLevelVerbose); return Exception.GetShortErrorInfoText(IsReportLevelVerbose);
} }
if (!IsConnected)
{
return AppResources.ActivityTextConnectionStateOffline;
}
return ActionText ?? string.Empty; return ActionText ?? string.Empty;
} }
} }

View file

@ -51,6 +51,9 @@ namespace TINK.ViewModel.BikesAtStation
} }
} }
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
public Command RefreshCommand { get; } public Command RefreshCommand { get; }
/// <summary> /// <summary>
@ -92,14 +95,10 @@ namespace TINK.ViewModel.BikesAtStation
? string.Format(AppResources.MarkingBikesAtStationStationId, Station.Id) ? string.Format(AppResources.MarkingBikesAtStationStationId, Station.Id)
: string.Empty; : string.Empty;
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
RefreshCommand = new Command(async () => { RefreshCommand = new Command(async () => {
IsRefreshing = true;
await OnAppearing();
IsRefreshing = false; IsRefreshing = false;
await OnAppearingOrRefresh();
}); });
@ -242,10 +241,12 @@ namespace TINK.ViewModel.BikesAtStation
/// Invoked when page is shown. /// Invoked when page is shown.
/// Starts update process. /// Starts update process.
/// </summary> /// </summary>
public async Task OnAppearing() public async Task OnAppearingOrRefresh()
{ {
IsIdle = false; IsIdle = false;
IsConnected = IsConnectedDelegate();
Log.ForContext<BikesAtStationPageViewModel>().Information($"Bikes at station {Station.StationName} is appearing, either due to tap on a station or to app being shown again."); Log.ForContext<BikesAtStationPageViewModel>().Information($"Bikes at station {Station.StationName} is appearing, either due to tap on a station or to app being shown again.");
ActionText = AppResources.ActivityTextOneMomentPlease; ActionText = AppResources.ActivityTextOneMomentPlease;
@ -294,7 +295,7 @@ namespace TINK.ViewModel.BikesAtStation
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -316,7 +317,7 @@ namespace TINK.ViewModel.BikesAtStation
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
} }
@ -332,7 +333,7 @@ namespace TINK.ViewModel.BikesAtStation
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -360,7 +361,7 @@ namespace TINK.ViewModel.BikesAtStation
// Backup GUI synchronization context. // Backup GUI synchronization context.
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
} }

View file

@ -299,7 +299,7 @@ namespace TINK.ViewModel.Contact
{ {
// User decided to give access to locations permissions. // User decided to give access to locations permissions.
PermissionsService.OpenAppSettings(); PermissionsService.OpenAppSettings();
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsMapPageEnabled = true; IsMapPageEnabled = true;
return; return;
@ -405,7 +405,7 @@ namespace TINK.ViewModel.Contact
Log.ForContext<SelectStationPageViewModel>().Verbose("Update pins color done."); Log.ForContext<SelectStationPageViewModel>().Verbose("Update pins color done.");
Exception = resultStationsAndBikes.Exception; Exception = resultStationsAndBikes.Exception;
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsMapPageEnabled = true; IsMapPageEnabled = true;
} }
@ -472,12 +472,12 @@ namespace TINK.ViewModel.Contact
await ViewService.ShowPage("//ContactPage"); await ViewService.ShowPage("//ContactPage");
#endif #endif
IsMapPageEnabled = true; IsMapPageEnabled = true;
ActionText = ""; ActionText = string.Empty;
} }
catch (Exception exception) catch (Exception exception)
{ {
IsMapPageEnabled = true; IsMapPageEnabled = true;
ActionText = ""; ActionText = string.Empty;
Log.ForContext<SelectStationPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception); Log.ForContext<SelectStationPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(

View file

@ -25,6 +25,7 @@ using TINK.Services.Permissions;
using TINK.Settings; using TINK.Settings;
using TINK.View; using TINK.View;
using TINK.ViewModel.Bikes; using TINK.ViewModel.Bikes;
using Xamarin.Essentials;
using Xamarin.Forms; using Xamarin.Forms;
using Command = Xamarin.Forms.Command; using Command = Xamarin.Forms.Command;
@ -94,6 +95,9 @@ namespace TINK.ViewModel.FindBike
} }
} }
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
public Command RefreshCommand { get; } public Command RefreshCommand { get; }
/// <summary> /// <summary>
@ -136,14 +140,10 @@ namespace TINK.ViewModel.FindBike
Stations = stations ?? throw new ArgumentException(nameof(stations)); Stations = stations ?? throw new ArgumentException(nameof(stations));
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
RefreshCommand = new Command(async () => { RefreshCommand = new Command(async () => {
IsRefreshing = true;
await OnAppearing();
IsRefreshing = false; IsRefreshing = false;
await SelectBike();
}); });
} }
@ -152,12 +152,17 @@ namespace TINK.ViewModel.FindBike
/// Invoked when page is shown. /// Invoked when page is shown.
/// Starts update process. /// Starts update process.
/// </summary> /// </summary>
public async Task OnAppearing() public async Task OnAppearingOrRefresh()
{ {
IsIdle = false; IsIdle = false;
Log.ForContext<FindBikePageViewModel>().Information("User request to show page FindBike- page re-appearing"); Log.ForContext<FindBikePageViewModel>().Information("User request to show page FindBike- page re-appearing");
IsConnected = IsConnectedDelegate();
// Stop polling before getting bikes info.
await m_oViewUpdateManager.StopUpdatePeridically();
if (string.IsNullOrEmpty(BikeIdUserInput) /* Find bike page flyout was taped */ if (string.IsNullOrEmpty(BikeIdUserInput) /* Find bike page flyout was taped */
&& BikeCollection.Count > 0 /* Bike was successfully selected */) && BikeCollection.Count > 0 /* Bike was successfully selected */)
{ {
@ -173,12 +178,12 @@ namespace TINK.ViewModel.FindBike
// Restart update. // Restart update.
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
} }
@ -192,6 +197,8 @@ namespace TINK.ViewModel.FindBike
ActionText = AppResources.ActivityTextFindBikeLoadingBikes; ActionText = AppResources.ActivityTextFindBikeLoadingBikes;
IsIdle = false; IsIdle = false;
IsConnected = IsConnectedDelegate();
Result<BikeCollection> bikes = null; Result<BikeCollection> bikes = null;
try try
{ {
@ -220,7 +227,7 @@ namespace TINK.ViewModel.FindBike
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
} }
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -241,7 +248,7 @@ namespace TINK.ViewModel.FindBike
string.Format(AppResources.MessageErrorSelectBikeNoBikeFound, BikeIdUserInput), string.Format(AppResources.MessageErrorSelectBikeNoBikeFound, BikeIdUserInput),
AppResources.MessageAnswerOk); AppResources.MessageAnswerOk);
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -289,7 +296,7 @@ namespace TINK.ViewModel.FindBike
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -313,7 +320,7 @@ namespace TINK.ViewModel.FindBike
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -335,7 +342,7 @@ namespace TINK.ViewModel.FindBike
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -352,7 +359,7 @@ namespace TINK.ViewModel.FindBike
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -379,7 +386,7 @@ namespace TINK.ViewModel.FindBike
await StartUpdateTask(() => UpdateTask()); await StartUpdateTask(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
} }
catch (Exception exception) catch (Exception exception)
@ -391,7 +398,7 @@ namespace TINK.ViewModel.FindBike
Log.ForContext<FindBikePageViewModel>().Error("Running command to select bike failed. {Exception}", exception); Log.ForContext<FindBikePageViewModel>().Error("Running command to select bike failed. {Exception}", exception);
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }

View file

@ -26,6 +26,8 @@ using TINK.Services.BluetoothLock;
using TINK.Repository; using TINK.Repository;
using TINK.Services.Geolocation; using TINK.Services.Geolocation;
using TINK.Model.State; using TINK.Model.State;
using TINK.ViewModel.Bikes;
#if !TRYNOTBACKSTYLE #if !TRYNOTBACKSTYLE
@ -308,7 +310,7 @@ namespace TINK.ViewModel.Map
try try
{ {
//Request Location Permission on iOS //Request Location Permission on iOS
if(DeviceInfo.Platform == DevicePlatform.iOS) if (DeviceInfo.Platform == DevicePlatform.iOS)
{ {
var status = await PermissionsService.RequestAsync(); var status = await PermissionsService.RequestAsync();
} }
@ -336,11 +338,17 @@ namespace TINK.ViewModel.Map
if (!string.IsNullOrEmpty(resultStationsAndBikes?.GeneralData?.MerchantMessage) if (!string.IsNullOrEmpty(resultStationsAndBikes?.GeneralData?.MerchantMessage)
&& !WasMerchantMessageAlreadyShown) && !WasMerchantMessageAlreadyShown)
{ {
// Show COPRI message once. // Context switch should not be required because code is called from GUI thread
await ViewService.DisplayAlert( // but a xf-issue requires call (see issue #594).
AppResources.MessageTitleInformation, TinkApp.PostAction( async (x) =>
resultStationsAndBikes.GeneralData.MerchantMessage, {
AppResources.MessageAnswerOk); // Show COPRI message once.
await ViewService.DisplayAlert(
AppResources.MessageTitleInformation,
resultStationsAndBikes.GeneralData.MerchantMessage,
AppResources.MessageAnswerOk);
}, null);
WasMerchantMessageAlreadyShown = true; WasMerchantMessageAlreadyShown = true;
} }
@ -405,7 +413,7 @@ namespace TINK.ViewModel.Map
} }
Exception = resultStationsAndBikes.Exception; Exception = resultStationsAndBikes.Exception;
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsNavBarVisible = true; IsNavBarVisible = true;
IsMapPageEnabled = true; IsMapPageEnabled = true;
@ -542,7 +550,7 @@ namespace TINK.ViewModel.Map
{ {
// User decided to give access to locations permissions. // User decided to give access to locations permissions.
PermissionsService.OpenAppSettings(); PermissionsService.OpenAppSettings();
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsNavBarVisible = true; IsNavBarVisible = true;
IsMapPageEnabled = true; IsMapPageEnabled = true;
@ -655,7 +663,7 @@ namespace TINK.ViewModel.Map
{ {
try try
{ {
Log.ForContext<MapPageViewModel>().Information($"User taped station {selectedStationId}."); Log.ForContext<MapPageViewModel>().Information($"User taped station {selectedStationId}.");
// Lock action to prevent multiple instances of "BikeAtStation" being opened. // Lock action to prevent multiple instances of "BikeAtStation" being opened.
IsMapPageEnabled = false; IsMapPageEnabled = false;
@ -673,13 +681,13 @@ namespace TINK.ViewModel.Map
await ViewService.PushAsync(ViewTypes.BikesAtStation); await ViewService.PushAsync(ViewTypes.BikesAtStation);
IsMapPageEnabled = true; IsMapPageEnabled = true;
ActionText = ""; ActionText = string.Empty;
} }
} }
catch (Exception exception) catch (Exception exception)
{ {
IsMapPageEnabled = true; IsMapPageEnabled = true;
ActionText = ""; ActionText = string.Empty;
Log.ForContext<MapPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception); Log.ForContext<MapPageViewModel>().Error("Fehler beim Öffnen der Ansicht \"Fahrräder an Station\" aufgetreten. {Exception}", exception);
await ViewService.DisplayAlert( await ViewService.DisplayAlert(
@ -851,11 +859,6 @@ namespace TINK.ViewModel.Map
return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose); return Exception.GetShortErrorInfoText(TinkApp.IsReportLevelVerbose);
} }
if (!IsConnected)
{
return AppResources.ActivityTextConnectionStateOffline;
}
return ActionText ?? string.Empty; return ActionText ?? string.Empty;
} }
} }
@ -955,7 +958,7 @@ namespace TINK.ViewModel.Map
// Excpetions are handled insde update task; // Excpetions are handled insde update task;
} }
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsNavBarVisible = true; IsNavBarVisible = true;
IsMapPageEnabled = true; IsMapPageEnabled = true;
@ -964,7 +967,7 @@ namespace TINK.ViewModel.Map
catch (Exception l_oException) catch (Exception l_oException)
{ {
Log.ForContext<MapPageViewModel>().Error("An error occurred switching view Cargobike/ Citybike.{}"); Log.ForContext<MapPageViewModel>().Error("An error occurred switching view Cargobike/ Citybike.{}");
ActionText = ""; ActionText = string.Empty;
IsProcessWithRunningProcessView = false; IsProcessWithRunningProcessView = false;
IsNavBarVisible = true; IsNavBarVisible = true;

View file

@ -22,6 +22,7 @@ using TINK.Services.Permissions;
using TINK.Settings; using TINK.Settings;
using TINK.View; using TINK.View;
using TINK.ViewModel.Bikes; using TINK.ViewModel.Bikes;
using Xamarin.Essentials;
using Xamarin.Forms; using Xamarin.Forms;
using Command = Xamarin.Forms.Command; using Command = Xamarin.Forms.Command;
@ -46,6 +47,11 @@ namespace TINK.ViewModel.MyBikes
} }
} }
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
public Command RefreshCommand { get; }
/// <summary> /// <summary>
/// Constructs bike collection view model in case information about occupied bikes is available. /// Constructs bike collection view model in case information about occupied bikes is available.
/// </summary> /// </summary>
@ -87,20 +93,14 @@ namespace TINK.ViewModel.MyBikes
Stations = stations ?? throw new ArgumentException(nameof(stations)); Stations = stations ?? throw new ArgumentException(nameof(stations));
/// <summary>
/// Holds what should be executed on pull to refresh
/// </summary>
RefreshCommand = new Command(async () => { RefreshCommand = new Command(async () => {
IsRefreshing = true;
await OnAppearing();
IsRefreshing = false; IsRefreshing = false;
await OnAppearingOrRefresh();
}); });
} }
public Command RefreshCommand { get; }
/// <summary> Returns if info about the fact that user did not request or book any bikes is visible or not.<summary> /// <summary> Returns if info about the fact that user did not request or book any bikes is visible or not.<summary>
/// Gets message that logged in user has not booked any bikes. /// Gets message that logged in user has not booked any bikes.
/// </summary> /// </summary>
@ -127,15 +127,20 @@ namespace TINK.ViewModel.MyBikes
/// Invoked when page is shown. /// Invoked when page is shown.
/// Starts update process. /// Starts update process.
/// </summary> /// </summary>
public async Task OnAppearing() public async Task OnAppearingOrRefresh()
{ {
IsIdle = false; IsIdle = false;
IsConnected = IsConnectedDelegate();
// Get my bikes from COPRI // Get my bikes from COPRI
Log.ForContext<MyBikesPageViewModel>().Information("User request to show page MyBikes/ page re-appearing"); Log.ForContext<MyBikesPageViewModel>().Information("User request to show page MyBikes/ page re-appearing");
ActionText = AppResources.ActivityTextMyBikesLoadingBikes; ActionText = AppResources.ActivityTextMyBikesLoadingBikes;
// Stop polling before getting bikes info.
await m_oViewUpdateManager.StopUpdatePeridically();
var bikesOccupied = await ConnectorFactory(IsConnected).Query.GetBikesOccupiedAsync(); var bikesOccupied = await ConnectorFactory(IsConnected).Query.GetBikesOccupiedAsync();
Exception = bikesOccupied.Exception; // Update communication error from query for bikes occupied. Exception = bikesOccupied.Exception; // Update communication error from query for bikes occupied.
@ -178,7 +183,7 @@ namespace TINK.ViewModel.MyBikes
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -200,7 +205,7 @@ namespace TINK.ViewModel.MyBikes
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -217,7 +222,7 @@ namespace TINK.ViewModel.MyBikes
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
return; return;
} }
@ -244,7 +249,7 @@ namespace TINK.ViewModel.MyBikes
await OnAppearing(() => UpdateTask()); await OnAppearing(() => UpdateTask());
ActionText = ""; ActionText = string.Empty;
IsIdle = true; IsIdle = true;
} }

View file

@ -130,7 +130,7 @@ namespace TestFramework.Repository
/// <summary> /// <summary>
/// Get list of stations from file. /// Get list of stations from file.
/// </summary> /// </summary>
/// <param name="p_strCookie">Auto cookie of user if user is logged in.</param> /// <param name="cookie">Auto cookie of user if user is logged in.</param>
/// <returns>List of files.</returns> /// <returns>List of files.</returns>
public async Task<StationsAvailableResponse> GetStationsAsync() public async Task<StationsAvailableResponse> GetStationsAsync()
=> await Task.Run(() => GetStationsAll(Stations, null, SessionCookie)); => await Task.Run(() => GetStationsAll(Stations, null, SessionCookie));
@ -147,7 +147,7 @@ namespace TestFramework.Repository
/// Gets canel booking request response. /// Gets canel booking request response.
/// </summary> /// </summary>
/// <param name="bikeId">Id of the bike to book.</param> /// <param name="bikeId">Id of the bike to book.</param>
/// <param name="p_strCookie">Cookie of the logged in user.</param> /// <param name="cookie">Cookie of the logged in user.</param>
/// <returns>Response on cancel booking request.</returns> /// <returns>Response on cancel booking request.</returns>
public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri) public async Task<ReservationCancelReturnResponse> DoCancelReservationAsync(string bikeId, Uri operatorUri)
=> await Task.Run(() => DoCancelReservation(CancelBookingRequestResponse, bikeId, SessionCookie)); => await Task.Run(() => DoCancelReservation(CancelBookingRequestResponse, bikeId, SessionCookie));
@ -196,14 +196,14 @@ namespace TestFramework.Repository
/// <summary> /// <summary>
/// Gets list of bikes from memory. /// Gets list of bikes from memory.
/// </summary> /// </summary>
/// <param name="p_strMerchantId">Id of the merchant.</param> /// <param name="merchantId">Id of the merchant.</param>
/// <param name="p_strSessionCookie">Auto cookie of user if user is logged in.</param> /// <param name="p_strSessionCookie">Auto cookie of user if user is logged in.</param>
/// <param name="p_eSampleSet">Set of samples.</param> /// <param name="p_eSampleSet">Set of samples.</param>
/// <param name="p_lStageIndex">Index of the stage.</param> /// <param name="p_lStageIndex">Index of the stage.</param>
/// <returns></returns> /// <returns></returns>
public static BikesAvailableResponse GetBikesAvailable( public static BikesAvailableResponse GetBikesAvailable(
string BikesAvailableResponse, string BikesAvailableResponse,
string p_strMerchantId, string merchantId,
string p_strSessionCookie = null) => string p_strSessionCookie = null) =>
CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BikesAvailableResponse); CopriCallsStatic.DeserializeResponse<BikesAvailableResponse>(BikesAvailableResponse);
@ -275,13 +275,11 @@ namespace TestFramework.Repository
public Task<DoReturnResponse> DoReturn( public Task<DoReturnResponse> DoReturn(
string bikeId, string bikeId,
LocationDto geolocation, LocationDto geolocation,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> null; => null;
public Task<DoReturnResponse> ReturnAndStartClosingAsync( public Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> null; => null;

View file

@ -74,11 +74,11 @@ namespace TestFramework.Repository
public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(string bikeId, Uri operatorUri) public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(string bikeId, Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();
public Task<DoReturnResponse> DoReturn(string bikeId, LocationDto location, ISmartDevice smartDevice, Uri operatorUri) public Task<DoReturnResponse> DoReturn(string bikeId, LocationDto location, Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();
public Task<DoReturnResponse> ReturnAndStartClosingAsync( public Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();

View file

@ -94,12 +94,11 @@ namespace TestFramework.Services.CopriApi.Connector
public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(string bikeId, Uri operatorUri) public Task<ReservationBookingResponse> BookReservedAndStartOpeningAsync(string bikeId, Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();
public Task<DoReturnResponse> DoReturn(string bikeId, LocationDto location, ISmartDevice smartDevice, Uri operatorUri) public Task<DoReturnResponse> DoReturn(string bikeId, LocationDto location, Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();
public Task<DoReturnResponse> ReturnAndStartClosingAsync( public Task<DoReturnResponse> ReturnAndStartClosingAsync(
string bikeId, string bikeId,
ISmartDevice smartDevice,
Uri operatorUri) Uri operatorUri)
=> throw new NotImplementedException(); => throw new NotImplementedException();

View file

@ -245,7 +245,7 @@ namespace TestLockItBLE
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[] { 0 /* opened */})); controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[] { 0 /* opened */}));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true)); activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Open /* State passed as event argument after closing. */}); stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Unknown /* State passed as event argument after closing. */}); /* changed from .Open to .Unknown (20.02.23, AMM) after bug fix #657. */
// Use factory to create LockIt-object. // Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result; var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
@ -294,7 +294,8 @@ namespace TestLockItBLE
// Calls related to Close functionality. // Calls related to Close functionality.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic)); lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[] { 0 /* open */})); controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult(new byte[] { 0 /* open */
}));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true)); activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(true));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.CouldntCloseBoldBlocked /* State passed as event argument after opening. */}); stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.CouldntCloseBoldBlocked /* State passed as event argument after opening. */});
@ -312,4 +313,4 @@ namespace TestLockItBLE
Throws.InstanceOf<CouldntCloseBoldBlockedException>()); Throws.InstanceOf<CouldntCloseBoldBlockedException>());
} }
} }
} }

View file

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
@ -10,10 +10,10 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="NSubstitute" Version="4.4.0" /> <PackageReference Include="NSubstitute" Version="5.0.0" />
<PackageReference Include="NUnit" Version="3.13.3" /> <PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.3.1" /> <PackageReference Include="NUnit3TestAdapter" Version="4.3.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

Some files were not shown because too many files have changed in this diff Show more