Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
Felix Foertsch
Luca Android
Commits
7e128df2
Commit
7e128df2
authored
Jul 27, 2021
by
Ulrich Scheller
Browse files
Release 1.11.1
parent
31fa1592
Changes
43
Hide whitespace changes
Inline
Side-by-side
Luca/app/build.gradle
View file @
7e128df2
...
...
@@ -10,8 +10,8 @@ android {
applicationId
"de.culture4life.luca"
minSdkVersion
21
targetSdkVersion
30
versionCode
7
7
versionName
"1.11.
0
"
versionCode
7
8
versionName
"1.11.
1
"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs
{
...
...
@@ -94,6 +94,9 @@ android {
buildConfigField
"String"
,
"API_BASE_URL"
,
'"https://app-preprod.luca-app.de"'
}
}
buildFeatures
{
viewBinding
=
true
}
compileOptions
{
sourceCompatibility
JavaVersion
.
VERSION_1_8
targetCompatibility
JavaVersion
.
VERSION_1_8
...
...
Luca/app/src/main/AndroidManifest.xml
View file @
7e128df2
...
...
@@ -62,6 +62,11 @@
</intent-filter>
</activity>
<activity
android:name=
".ui.terms.UpdatedTermsActivity"
android:screenOrientation=
"portrait"
>
</activity>
<activity
android:name=
"de.culture4life.luca.ui.registration.RegistrationActivity"
android:screenOrientation=
"portrait"
>
...
...
Luca/app/src/main/java/de/culture4life/luca/LucaApplication.java
View file @
7e128df2
...
...
@@ -20,6 +20,7 @@ import de.culture4life.luca.checkin.CheckInManager;
import
de.culture4life.luca.crypto.CryptoManager
;
import
de.culture4life.luca.dataaccess.DataAccessManager
;
import
de.culture4life.luca.document.DocumentManager
;
import
de.culture4life.luca.genuinity.GenuinityManager
;
import
de.culture4life.luca.history.HistoryManager
;
import
de.culture4life.luca.location.GeofenceManager
;
import
de.culture4life.luca.location.LocationManager
;
...
...
@@ -32,7 +33,6 @@ import de.culture4life.luca.registration.RegistrationManager;
import
de.culture4life.luca.service.LucaService
;
import
de.culture4life.luca.ui.ViewError
;
import
de.culture4life.luca.ui.dialog.BaseDialogFragment
;
import
de.culture4life.luca.util.TimeUtil
;
import
java.util.ArrayList
;
import
java.util.HashSet
;
...
...
@@ -68,6 +68,7 @@ public class LucaApplication extends MultiDexApplication {
private
final
PreferencesManager
preferencesManager
;
private
final
CryptoManager
cryptoManager
;
private
final
GenuinityManager
genuinityManager
;
private
final
NetworkManager
networkManager
;
private
final
LucaNotificationManager
notificationManager
;
private
final
LocationManager
locationManager
;
...
...
@@ -106,6 +107,7 @@ public class LucaApplication extends MultiDexApplication {
geofenceManager
=
new
GeofenceManager
();
historyManager
=
new
HistoryManager
(
preferencesManager
);
cryptoManager
=
new
CryptoManager
(
preferencesManager
,
networkManager
);
genuinityManager
=
new
GenuinityManager
(
preferencesManager
,
networkManager
);
registrationManager
=
new
RegistrationManager
(
preferencesManager
,
networkManager
,
cryptoManager
);
meetingManager
=
new
MeetingManager
(
preferencesManager
,
networkManager
,
locationManager
,
historyManager
,
cryptoManager
);
checkInManager
=
new
CheckInManager
(
preferencesManager
,
networkManager
,
geofenceManager
,
locationManager
,
historyManager
,
cryptoManager
,
notificationManager
);
...
...
@@ -175,6 +177,7 @@ public class LucaApplication extends MultiDexApplication {
notificationManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
networkManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
cryptoManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
genuinityManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
locationManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
registrationManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
checkInManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
...
...
@@ -183,7 +186,7 @@ public class LucaApplication extends MultiDexApplication {
documentManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
()),
geofenceManager
.
initialize
(
this
).
subscribeOn
(
Schedulers
.
io
())
).
andThen
(
Completable
.
mergeArray
(
invokeServerTimeCheck
(),
invokeServerTimeCheck
()
.
delaySubscription
(
5
,
TimeUnit
.
SECONDS
,
Schedulers
.
io
())
,
invokeRotatingBackendPublicKeyUpdate
(),
invokeAccessedDataUpdate
(),
startKeepingDataUpdated
()
...
...
@@ -191,16 +194,10 @@ public class LucaApplication extends MultiDexApplication {
}
private
Completable
invokeServerTimeCheck
()
{
return
Completable
.
fromAction
(()
->
applicationDisposable
.
add
(
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
LucaEndpointsV3:
:
getServerTime
)
.
map
(
jsonObject
->
jsonObject
.
get
(
"unix"
).
getAsInt
())
.
flatMap
(
TimeUtil:
:
convertFromUnixTimestamp
)
.
map
(
serverTimestamp
->
Math
.
abs
(
System
.
currentTimeMillis
()
-
serverTimestamp
))
return
Completable
.
fromAction
(()
->
applicationDisposable
.
add
(
genuinityManager
.
isGenuineTime
()
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
(
timestampOffset
->
{
Timber
.
d
(
"Timestamp offset: %d ms"
,
timestampOffset
);
if
(
timestampOffset
>
MAXIMUM_TIMESTAMP_OFFSET
)
{
.
subscribe
(
isGenuineTime
->
{
if
(!
isGenuineTime
)
{
showErrorAsDialog
(
new
ViewError
.
Builder
(
this
)
.
withTitle
(
R
.
string
.
error_timestamp_offset_title
)
.
withDescription
(
R
.
string
.
error_timestamp_offset_description
)
...
...
@@ -213,8 +210,7 @@ public class LucaApplication extends MultiDexApplication {
.
removeWhenShown
()
.
build
());
}
},
throwable
->
Timber
.
w
(
"Unable to get server time offset: %s"
,
throwable
.
toString
())
}
)));
}
...
...
@@ -241,7 +237,7 @@ public class LucaApplication extends MultiDexApplication {
return
Completable
.
fromAction
(()
->
applicationDisposable
.
add
(
dataAccessManager
.
update
()
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
(
()
->
Timber
.
i
(
"Updated accessed data"
),
()
->
Timber
.
d
(
"Updated accessed data"
),
throwable
->
Timber
.
w
(
"Unable to update accessed data: %s"
,
throwable
.
toString
())
)));
}
...
...
@@ -463,6 +459,10 @@ public class LucaApplication extends MultiDexApplication {
return
cryptoManager
;
}
public
GenuinityManager
getGenuinityManager
()
{
return
genuinityManager
;
}
public
NetworkManager
getNetworkManager
()
{
return
networkManager
;
}
...
...
Luca/app/src/main/java/de/culture4life/luca/checkin/CheckInManager.java
View file @
7e128df2
...
...
@@ -169,7 +169,8 @@ public class CheckInManager extends Manager {
public
Completable
checkIn
(
@NonNull
UUID
scannerId
,
@NonNull
QrCodeData
qrCodeData
)
{
return
assertNotCheckedIn
()
.
andThen
(
generateCheckInData
(
qrCodeData
,
scannerId
)
.
flatMapCompletable
(
checkInRequestData
->
networkManager
.
getLucaEndpoints
().
checkIn
(
checkInRequestData
)))
.
flatMapCompletable
(
checkInRequestData
->
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
checkIn
(
checkInRequestData
))))
.
andThen
(
getCheckInDataFromBackend
()
.
switchIfEmpty
(
Single
.
error
(
new
IllegalStateException
(
"No check-in data available at backend after checking in"
))))
.
flatMapCompletable
(
this
::
processCheckIn
);
...
...
@@ -201,7 +202,8 @@ public class CheckInManager extends Manager {
}
public
Single
<
ECPublicKey
>
getLocationPublicKey
(
@NonNull
UUID
scannerId
)
{
return
networkManager
.
getLucaEndpoints
().
getScanner
(
scannerId
.
toString
())
return
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
getScanner
(
scannerId
.
toString
()))
.
map
(
jsonObject
->
jsonObject
.
get
(
"publicKey"
).
getAsString
())
.
flatMap
(
SerializationUtil:
:
deserializeFromBase64
)
.
flatMap
(
AsymmetricCipherProvider:
:
decodePublicKey
);
...
...
@@ -365,7 +367,8 @@ public class CheckInManager extends Manager {
.
andThen
(
getCheckedInTraceId
())
.
toSingle
()
.
flatMap
(
traceId
->
generateAdditionalCheckInProperties
(
properties
,
traceId
,
locationPublicKey
))
.
flatMapCompletable
(
requestData
->
networkManager
.
getLucaEndpoints
().
addAdditionalCheckInProperties
(
requestData
))
.
flatMapCompletable
(
requestData
->
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
addAdditionalCheckInProperties
(
requestData
)))
.
andThen
(
persistAdditionalCheckInProperties
(
properties
));
}
...
...
@@ -431,8 +434,8 @@ public class CheckInManager extends Manager {
.
andThen
(
networkManager
.
assertNetworkConnected
())
.
andThen
(
generateCheckOutData
()
.
doOnSuccess
(
checkOutRequestData
->
Timber
.
i
(
"Generated checkout data: %s"
,
checkOutRequestData
))
.
flatMapCompletable
(
checkOutRequestData
->
networkManager
.
getLucaEndpoints
()
.
checkOut
(
checkOutRequestData
)
.
flatMapCompletable
(
checkOutRequestData
->
networkManager
.
getLucaEndpoints
V3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
checkOut
(
checkOutRequestData
)
)
.
onErrorResumeNext
(
throwable
->
{
if
(
NetworkManager
.
isHttpException
(
throwable
,
HttpURLConnection
.
HTTP_NOT_FOUND
))
{
// user is currently not checked-in
...
...
@@ -716,7 +719,8 @@ public class CheckInManager extends Manager {
if
(
traceData
.
isCheckedOut
())
{
return
Maybe
.
empty
();
}
return
networkManager
.
getLucaEndpoints
().
getLocation
(
traceData
.
getLocationId
())
return
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
getLocation
(
traceData
.
getLocationId
()))
.
map
(
location
->
{
Timber
.
d
(
"Creating check-in data for location: %s"
,
location
);
CheckInData
checkInData
=
new
CheckInData
();
...
...
@@ -815,7 +819,8 @@ public class CheckInManager extends Manager {
jsonObject
.
add
(
"traceIds"
,
jsonArray
);
return
jsonObject
;
})
.
flatMap
(
jsonObject
->
networkManager
.
getLucaEndpoints
().
getTraces
(
jsonObject
))
.
flatMap
(
jsonObject
->
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
getTraces
(
jsonObject
)))
.
flatMapObservable
(
Observable:
:
fromIterable
)
.
sorted
((
first
,
second
)
->
Long
.
compare
(
first
.
getCheckInTimestamp
(),
second
.
getCheckInTimestamp
()));
}
...
...
Luca/app/src/main/java/de/culture4life/luca/dataaccess/DataAccessManager.java
View file @
7e128df2
...
...
@@ -13,6 +13,7 @@ import de.culture4life.luca.crypto.CryptoManager;
import
de.culture4life.luca.history.HistoryItem
;
import
de.culture4life.luca.history.HistoryManager
;
import
de.culture4life.luca.network.NetworkManager
;
import
de.culture4life.luca.network.endpoints.LucaEndpointsV3
;
import
de.culture4life.luca.network.pojo.AccessedHashedTraceIdsData
;
import
de.culture4life.luca.notification.LucaNotificationManager
;
import
de.culture4life.luca.preference.PreferencesManager
;
...
...
@@ -240,7 +241,8 @@ public class DataAccessManager extends Manager {
}
public
Observable
<
AccessedHashedTraceIdsData
>
fetchAllRecentlyAccessedHashedTraceIdsData
()
{
return
networkManager
.
getLucaEndpoints
().
getAccessedTraces
()
return
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
LucaEndpointsV3:
:
getAccessedTraces
)
.
flatMapObservable
(
Observable:
:
fromIterable
);
}
...
...
Luca/app/src/main/java/de/culture4life/luca/genuinity/GenuinityManager.kt
0 → 100644
View file @
7e128df2
package
de.culture4life.luca.genuinity
import
android.content.Context
import
de.culture4life.luca.Manager
import
de.culture4life.luca.network.NetworkManager
import
de.culture4life.luca.preference.PreferencesManager
import
de.culture4life.luca.util.TimeUtil
import
io.reactivex.rxjava3.core.Completable
import
io.reactivex.rxjava3.core.Observable
import
io.reactivex.rxjava3.core.Single
import
io.reactivex.rxjava3.schedulers.Schedulers
import
timber.log.Timber
import
java.util.concurrent.TimeUnit
import
kotlin.math.abs
class
GenuinityManager
(
val
preferencesManager
:
PreferencesManager
,
val
networkManager
:
NetworkManager
)
:
Manager
()
{
companion
object
{
const
val
KEY_SERVER_TIME_OFFSET
=
"server_time_offset"
val
MAXIMUM_SERVER_TIME_OFFSET
=
TimeUnit
.
MINUTES
.
toMillis
(
5
)
}
var
timestampOffset
:
Long
?
=
null
override
fun
doInitialize
(
context
:
Context
):
Completable
{
return
Completable
.
mergeArray
(
preferencesManager
.
initialize
(
context
),
networkManager
.
initialize
(
context
)
).
andThen
(
invokeServerTimeOffsetUpdateIfRequired
().
delaySubscription
(
3
,
TimeUnit
.
SECONDS
))
}
private
fun
invokeServerTimeOffsetUpdateIfRequired
():
Completable
{
return
Completable
.
fromAction
{
if
(
timestampOffset
==
null
)
{
invokeServerTimeOffsetUpdate
()
}
}
}
fun
invokeServerTimeOffsetUpdate
():
Completable
{
return
Completable
.
fromAction
{
managerDisposable
.
add
(
fetchServerTimeOffset
()
.
subscribeOn
(
Schedulers
.
io
())
.
onErrorComplete
()
.
subscribe
())
}
}
fun
isGenuineTime
():
Single
<
Boolean
>
{
return
getOrFetchOrRestoreServerTimeOffset
()
.
map
{
it
<
MAXIMUM_SERVER_TIME_OFFSET
}
.
onErrorReturnItem
(
false
)
}
fun
getIsGenuineTimeChanges
():
Observable
<
Boolean
>
{
return
preferencesManager
.
getChanges
(
KEY_SERVER_TIME_OFFSET
,
Long
::
class
.
java
)
.
flatMapSingle
{
isGenuineTime
()
}
.
distinctUntilChanged
()
}
private
fun
getOrFetchOrRestoreServerTimeOffset
():
Single
<
Long
>
{
return
Single
.
defer
{
if
(
timestampOffset
!=
null
)
{
Single
.
just
(
timestampOffset
!!
)
}
else
{
fetchServerTimeOffset
()
}
}.
onErrorResumeWith
(
restoreLastKnownServerTimeOffset
())
.
onErrorResumeNext
{
Single
.
error
(
IllegalStateException
(
"Unable to get server time offset"
,
it
))
}
}
private
fun
restoreLastKnownServerTimeOffset
():
Single
<
Long
>
{
return
preferencesManager
.
restore
(
KEY_SERVER_TIME_OFFSET
,
Long
::
class
.
java
)
}
private
fun
fetchServerTimeOffset
():
Single
<
Long
>
{
return
networkManager
.
lucaEndpointsV3
.
flatMap
{
it
.
serverTime
}
.
map
{
it
[
"unix"
].
asLong
}
.
flatMap
{
TimeUtil
.
convertFromUnixTimestamp
(
it
)
}
.
map
{
abs
(
System
.
currentTimeMillis
()
-
it
)
}
.
doOnSuccess
{
timestampOffset
=
it
Timber
.
d
(
"Server timestamp offset updated: %d"
,
timestampOffset
)
}
.
doOnError
{
Timber
.
w
(
"Unable to update server timestamp offset: %s"
,
it
.
toString
())
}
.
flatMap
{
preferencesManager
.
persist
(
KEY_SERVER_TIME_OFFSET
,
it
).
andThen
(
Single
.
just
(
it
))
}
}
}
\ No newline at end of file
Luca/app/src/main/java/de/culture4life/luca/meeting/MeetingManager.java
View file @
7e128df2
...
...
@@ -124,7 +124,8 @@ public class MeetingManager extends Manager {
jsonObject
.
addProperty
(
"publicKey"
,
serializedPubKey
);
return
jsonObject
;
})
.
flatMap
(
requestData
->
networkManager
.
getLucaEndpoints
().
createPrivateLocation
(
requestData
))
.
flatMap
(
requestData
->
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
createPrivateLocation
(
requestData
)))
.
map
(
MeetingData:
:
new
);
}
...
...
@@ -134,8 +135,8 @@ public class MeetingManager extends Manager {
public
Completable
closePrivateLocation
()
{
return
restoreCurrentMeetingDataIfAvailable
()
.
flatMapCompletable
(
meetingData
->
networkManager
.
getLucaEndpoints
()
.
closePrivateLocation
(
meetingData
.
getAccessId
().
toString
())
.
flatMapCompletable
(
meetingData
->
networkManager
.
getLucaEndpoints
V3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
closePrivateLocation
(
meetingData
.
getAccessId
().
toString
())
)
.
onErrorResumeNext
(
throwable
->
{
if
(
NetworkManager
.
isHttpException
(
throwable
,
HttpURLConnection
.
HTTP_NOT_FOUND
))
{
// meeting has already ended
...
...
@@ -168,7 +169,8 @@ public class MeetingManager extends Manager {
public
Observable
<
TracesResponseData
>
fetchGuestData
()
{
return
restoreCurrentMeetingDataIfAvailable
()
.
map
(
MeetingData:
:
getAccessId
)
.
flatMapSingle
(
accessUuid
->
networkManager
.
getLucaEndpoints
().
fetchGuestList
(
accessUuid
.
toString
()))
.
flatMapSingle
(
accessUuid
->
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
fetchGuestList
(
accessUuid
.
toString
())))
.
doOnSuccess
(
tracesResponseData
->
Timber
.
d
(
"Location traces: %s"
,
tracesResponseData
))
.
flatMapObservable
(
Observable:
:
fromIterable
);
}
...
...
Luca/app/src/main/java/de/culture4life/luca/network/NetworkManager.java
View file @
7e128df2
...
...
@@ -112,16 +112,13 @@ public class NetworkManager extends Manager {
return
builder
.
build
();
}
@Deprecated
public
LucaEndpointsV3
getLucaEndpoints
()
{
if
(
lucaEndpointsV3
==
null
)
{
lucaEndpointsV3
=
createEndpoints
();
}
return
lucaEndpointsV3
;
}
public
Single
<
LucaEndpointsV3
>
getLucaEndpointsV3
()
{
return
Single
.
defer
(()
->
getInitializedField
(
getLucaEndpoints
()));
return
Single
.
fromCallable
(()
->
{
if
(
lucaEndpointsV3
==
null
)
{
lucaEndpointsV3
=
createEndpoints
();
}
return
lucaEndpointsV3
;
});
}
public
Completable
assertNetworkConnected
()
{
...
...
Luca/app/src/main/java/de/culture4life/luca/registration/RegistrationManager.java
View file @
7e128df2
...
...
@@ -163,7 +163,8 @@ public class RegistrationManager extends Manager {
return
Single
.
defer
(()
->
{
JsonObject
message
=
new
JsonObject
();
message
.
addProperty
(
"phone"
,
formattedPhoneNumber
);
return
networkManager
.
getLucaEndpoints
().
requestPhoneNumberVerificationTan
(
message
)
return
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
requestPhoneNumberVerificationTan
(
message
))
.
doOnSubscribe
(
disposable
->
Timber
.
i
(
"Requesting TAN for %s"
,
formattedPhoneNumber
))
.
map
(
jsonObject
->
jsonObject
.
get
(
"challengeId"
).
getAsString
());
});
...
...
@@ -182,7 +183,8 @@ public class RegistrationManager extends Manager {
}
jsonObject
.
add
(
"challengeIds"
,
challengeIdArray
);
jsonObject
.
addProperty
(
"tan"
,
verificationTan
);
return
networkManager
.
getLucaEndpoints
().
verifyPhoneNumberBulk
(
jsonObject
);
return
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
verifyPhoneNumberBulk
(
jsonObject
));
});
}
...
...
@@ -193,7 +195,8 @@ public class RegistrationManager extends Manager {
public
Completable
registerUser
()
{
return
createUserRegistrationRequestData
()
.
doOnSuccess
(
data
->
Timber
.
d
(
"User registration request data: %s"
,
data
))
.
flatMap
(
data
->
networkManager
.
getLucaEndpoints
().
registerUser
(
data
)
.
flatMap
(
data
->
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
registerUser
(
data
))
.
map
(
jsonObject
->
jsonObject
.
get
(
"userId"
).
getAsString
())
.
map
(
UUID:
:
fromString
))
.
doOnSuccess
(
userId
->
Timber
.
i
(
"Registered user for ID: %s"
,
userId
))
...
...
@@ -222,7 +225,8 @@ public class RegistrationManager extends Manager {
.
doOnSuccess
(
data
->
data
.
setGuestKeyPairPublicKey
(
null
))
// not part of update request
.
doOnSuccess
(
data
->
Timber
.
d
(
"User update request data: %s"
,
data
))
.
flatMapCompletable
(
data
->
getUserIdIfAvailable
()
.
flatMapCompletable
(
userId
->
networkManager
.
getLucaEndpoints
().
updateUser
(
userId
.
toString
(),
data
)))
.
flatMapCompletable
(
userId
->
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
lucaEndpointsV3
.
updateUser
(
userId
.
toString
(),
data
))))
.
doOnComplete
(()
->
Timber
.
i
(
"Updated user"
));
}
...
...
@@ -340,7 +344,8 @@ public class RegistrationManager extends Manager {
// TODO: 24.03.21 This doesn't seem to belong to the registration process
return
createDataTransferRequestData
(
days
)
.
doOnSuccess
(
data
->
Timber
.
d
(
"User data transfer request data: %s"
,
data
))
.
flatMap
(
data
->
networkManager
.
getLucaEndpoints
().
getTracingTan
(
data
))
.
flatMap
(
data
->
networkManager
.
getLucaEndpointsV3
()
.
flatMap
(
lucaEndpointsV3
->
lucaEndpointsV3
.
getTracingTan
(
data
)))
.
map
(
jsonObject
->
jsonObject
.
get
(
"tan"
).
getAsString
());
}
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/BaseFragment.java
View file @
7e128df2
...
...
@@ -5,7 +5,6 @@ import com.google.android.material.snackbar.Snackbar;
import
android.Manifest
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.os.Bundle
;
import
android.os.StrictMode
;
import
android.text.SpannedString
;
...
...
@@ -25,7 +24,6 @@ import de.culture4life.luca.BuildConfig;
import
de.culture4life.luca.LucaApplication
;
import
de.culture4life.luca.R
;
import
de.culture4life.luca.ui.dialog.BaseDialogFragment
;
import
de.culture4life.luca.ui.registration.RegistrationActivity
;
import
java.util.Set
;
import
java.util.concurrent.TimeUnit
;
...
...
@@ -285,12 +283,12 @@ public abstract class BaseFragment<ViewModelType extends BaseViewModel> extends
errorSnackbar
=
Snackbar
.
make
(
getView
(),
error
.
getTitle
(),
duration
);
errorSnackbar
.
addCallback
(
new
Snackbar
.
Callback
()
{
@Override
public
void
onShown
(
Snackbar
s
b
)
{
public
void
onShown
(
Snackbar
s
nackbar
)
{
viewModel
.
onErrorShown
(
error
);
}
@Override
public
void
onDismissed
(
Snackbar
transientBottomB
ar
,
int
event
)
{
public
void
onDismissed
(
Snackbar
snackb
ar
,
int
event
)
{
viewModel
.
onErrorDismissed
(
error
);
}
});
...
...
@@ -361,15 +359,6 @@ public abstract class BaseFragment<ViewModelType extends BaseViewModel> extends
.
show
();
}
private
void
showDeleteAccountDialog
()
{
new
BaseDialogFragment
(
new
MaterialAlertDialogBuilder
(
getContext
())
.
setTitle
(
R
.
string
.
delete_account_dialog_title
)
.
setMessage
(
R
.
string
.
delete_account_dialog_message
)
.
setPositiveButton
(
R
.
string
.
delete_account_dialog_action
,
(
dialog
,
which
)
->
viewModel
.
deleteAccount
())
.
setNegativeButton
(
R
.
string
.
action_cancel
,
(
dialog
,
which
)
->
dialog
.
dismiss
()))
.
show
();
}
protected
Completable
getCameraPermission
()
{
return
rxPermissions
.
request
(
Manifest
.
permission
.
CAMERA
)
.
flatMapCompletable
(
granted
->
{
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/MainActivity.java
View file @
7e128df2
...
...
@@ -14,11 +14,12 @@ import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent;
import
androidx.annotation.Nullable
;
import
androidx.navigation.NavController
;
import
androidx.navigation.
Navigation
;
import
androidx.navigation.
fragment.NavHostFragment
;
import
androidx.navigation.ui.AppBarConfiguration
;
import
androidx.navigation.ui.NavigationUI
;
import
five.star.me.FiveStarMe
;
import
io.reactivex.rxjava3.core.Completable
;
import
io.reactivex.rxjava3.core.Single
;
import
timber.log.Timber
;
public
class
MainActivity
extends
BaseActivity
{
...
...
@@ -43,13 +44,31 @@ public class MainActivity extends BaseActivity {
private
void
initializeNavigation
()
{
AppBarConfiguration
appBarConfiguration
=
new
AppBarConfiguration
.
Builder
(
R
.
id
.
qrCodeFragment
,
R
.
id
.
history
Fragment
R
.
id
.
qrCodeFragment
,
R
.
id
.
myLucaFragment
,
R
.
id
.
historyFragment
,
R
.
id
.
account
Fragment
).
build
();
navigationController
=
Navigation
.
findNavController
(
this
,
R
.
id
.
navigationHostFragment
);
NavHostFragment
navHostFragment
=
(
NavHostFragment
)
getSupportFragmentManager
()
.
findFragmentById
(
R
.
id
.
navigationHostFragment
);
navigationController
=
navHostFragment
.
getNavController
();
navigationController
.
setGraph
(
R
.
navigation
.
mobile_navigation
);
NavigationUI
.
setupActionBarWithNavController
(
this
,
navigationController
,
appBarConfiguration
);
bottomNavigationView
=
findViewById
(
R
.
id
.
bottomNavigationView
);
NavigationUI
.
setupWithNavController
(
bottomNavigationView
,
navigationController
);
bottomNavigationView
.
setOnNavigationItemSelectedListener
(
item
->
{
int
currentDestinationId
=
navigationController
.
getCurrentDestination
().
getId
();
if
(
currentDestinationId
!=
item
.
getItemId
())
{
if
(
item
.
getItemId
()
==
R
.
id
.
qrCodeFragment
)
{
int
destinationId
=
getCheckInScreenDestinationId
().
blockingGet
();
if
(
currentDestinationId
!=
destinationId
)
{
navigationController
.
navigate
(
destinationId
);
}
}
else
{
NavigationUI
.
onNavDestinationSelected
(
item
,
navigationController
);
}
}
return
true
;
});
if
(
application
.
isInDarkMode
())
{
// workaround for removing the elevation color overlay
// https://github.com/material-components/material-components-android/issues/1148
...
...
@@ -112,4 +131,24 @@ public class MainActivity extends BaseActivity {
}));
}
private
Single
<
Integer
>
getCheckInScreenDestinationId
()
{
Single
<
Boolean
>
checkedIn
=
application
.
getCheckInManager
()
.
initialize
(
application
)
.
andThen
(
application
.
getCheckInManager
().
isCheckedIn
());
Single
<
Boolean
>
hostingMeeting
=
application
.
getMeetingManager
()
.
initialize
(
application
)
.
andThen
(
application
.
getMeetingManager
().
isCurrentlyHostingMeeting
());
return
Single
.
zip
(
checkedIn
,
hostingMeeting
,
(
isCheckedIn
,
isHostingMeeting
)
->
{
if
(
isCheckedIn
)
{
return
R
.
id
.
venueDetailFragment
;
}
else
if
(
isHostingMeeting
)
{
return
R
.
id
.
meetingFragment
;
}
else
{
return
R
.
id
.
qrCodeFragment
;
}
});
}
}
\ No newline at end of file
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/MyLucaFragment.java
View file @
7e128df2
...
...
@@ -5,6 +5,7 @@ import com.google.android.material.card.MaterialCardView;
import
com.google.android.material.dialog.MaterialAlertDialogBuilder
;
import
com.google.common.util.concurrent.ListenableFuture
;
import
android.content.Intent
;
import
android.util.Size
;
import
android.view.View
;
import
android.widget.ImageView
;
...
...
@@ -70,7 +71,8 @@ public class MyLucaFragment extends BaseFragment<MyLucaViewModel> implements MyL
super
.
onResume
();
viewDisposable
.
add
(
Completable
.
mergeArray
(
viewModel
.
updateUserName
(),
viewModel
.
invokeListUpdate
()
viewModel
.
invokeListUpdate
(),
viewModel
.
invokeServerTimeOffsetUpdate
()
).
subscribe
());
}
...
...
@@ -81,6 +83,7 @@ public class MyLucaFragment extends BaseFragment<MyLucaViewModel> implements MyL
initializeMyLucaItemsViews
();
initializeEmptyStateViews
();
initializeImportViews
();
initializeTimeSyncErrorViews
();
}));
}
...
...
@@ -149,6 +152,22 @@ public class MyLucaFragment extends BaseFragment<MyLucaViewModel> implements MyL
});
}
private
void
initializeTimeSyncErrorViews
()
{
View
timeSyncErrorLayout
=
getView
().
findViewById
(
R
.
id
.
timeSyncErrorLayout
);
TextView
sheetDescriptionTextView
=
timeSyncErrorLayout
.
findViewById
(
R
.
id
.
sheetDescriptionTextView
);
sheetDescriptionTextView
.
setText
(
R
.
string
.
time_error_description
);
MaterialButton
sheetActionButton
=
timeSyncErrorLayout
.
findViewById
(
R
.
id
.
sheetActionButton
);
sheetActionButton
.
setText
(
R
.
string
.
time_error_action
);
sheetActionButton
.
setOnClickListener
(
v
->
{
Intent
intent
=
new
Intent
(
android
.
provider
.
Settings
.
ACTION_DATE_SETTINGS
);
intent
.
setFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
startActivity
(
intent
);
});
observe
(
viewModel
.
getIsGenuineTime
(),
isGenuineTime
->
{
timeSyncErrorLayout
.
setVisibility
(
isGenuineTime
?
View
.
GONE
:
View
.
VISIBLE
);
});
}
private
void
toggleCameraPreview
()
{
if
(
cameraPreviewDisposable
==
null
)
{
viewModel
.
isCameraConsentGiven
()
...
...