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
31fa1592
Commit
31fa1592
authored
Jul 16, 2021
by
Daniel Beckmann
Browse files
Release 1.11.0
parent
22451438
Changes
64
Hide whitespace changes
Inline
Side-by-side
Luca/.idea/misc.xml
View file @
31fa1592
<?xml version="1.0" encoding="UTF-8"?>
<project
version=
"4"
>
<component
name=
"ProjectRootManager"
version=
"2"
languageLevel=
"JDK_1
_8
"
default=
"true"
project-jdk-name=
"1.8"
project-jdk-type=
"JavaSDK"
>
<component
name=
"ProjectRootManager"
version=
"2"
languageLevel=
"JDK_1
1
"
default=
"true"
project-jdk-name=
"1.8"
project-jdk-type=
"JavaSDK"
>
<output
url=
"file://$PROJECT_DIR$/build/classes"
/>
</component>
<component
name=
"ProjectType"
>
...
...
Luca/app/build.gradle
View file @
31fa1592
...
...
@@ -10,8 +10,8 @@ android {
applicationId
"de.culture4life.luca"
minSdkVersion
21
targetSdkVersion
30
versionCode
7
6
versionName
"1.1
0
.0"
versionCode
7
7
versionName
"1.1
1
.0"
testInstrumentationRunner
"androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs
{
...
...
@@ -97,6 +97,7 @@ android {
compileOptions
{
sourceCompatibility
JavaVersion
.
VERSION_1_8
targetCompatibility
JavaVersion
.
VERSION_1_8
coreLibraryDesugaringEnabled
true
}
testOptions
{
animationsDisabled
true
...
...
@@ -119,6 +120,7 @@ play {
}
dependencies
{
coreLibraryDesugaring
'com.android.tools:desugar_jdk_libs:1.1.5'
implementation
project
(
':decoder'
)
implementation
'androidx.annotation:annotation:1.2.0'
...
...
Luca/app/src/main/java/de/culture4life/luca/LucaApplication.java
View file @
31fa1592
...
...
@@ -495,7 +495,7 @@ public class LucaApplication extends MultiDexApplication {
return
dataAccessManager
;
}
public
DocumentManager
get
Testing
Manager
()
{
public
DocumentManager
get
Document
Manager
()
{
return
documentManager
;
}
...
...
Luca/app/src/main/java/de/culture4life/luca/dataaccess/DataAccessManager.java
View file @
31fa1592
...
...
@@ -160,7 +160,7 @@ public class DataAccessManager extends Manager {
.
map
(
durationSinceLastUpdate
->
UPDATE_INTERVAL
-
durationSinceLastUpdate
)
.
map
(
recommendedDelay
->
Math
.
max
(
0
,
recommendedDelay
))
.
doOnSuccess
(
recommendedDelay
->
{
String
readableDelay
=
TimeUtil
.
getReadable
ApproximateDuration
(
recommendedDelay
,
context
).
blockingGet
();
String
readableDelay
=
TimeUtil
.
getReadable
DurationWithPlural
(
recommendedDelay
,
context
).
blockingGet
();
Timber
.
v
(
"Recommended update delay: %s"
,
readableDelay
);
});
}
...
...
Luca/app/src/main/java/de/culture4life/luca/document/Document.java
View file @
31fa1592
...
...
@@ -68,13 +68,14 @@ public class Document {
}
public
static
final
long
MAXIMUM_
FAST_TEST
_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
2
);
public
static
final
long
MAXIMUM_
PCR_TES
T_VALIDITY
=
TimeUnit
.
DAY
S
.
toMillis
(
3
);
public
static
final
long
MAXIMUM_
RECOVERY
_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
30
*
6
);
public
static
final
long
MAXIMUM_
APPOINTMEN
T_VALIDITY
=
TimeUnit
.
HOUR
S
.
toMillis
(
2
);
public
static
final
long
TIME_UNTIL_VACCINATION_IS_VALID
=
TimeUnit
.
DAYS
.
toMillis
(
15
);
public
static
final
long
MAXIMUM_VACCINATION_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
365
);
public
static
final
long
TIME_UNTIL_RECOVERY_IS_VALID
=
TimeUnit
.
DAYS
.
toMillis
(
15
);
public
static
final
long
MAXIMUM_RECOVERY_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
30
*
6
);
public
static
final
long
MAXIMUM_APPOINTMENT_VALIDITY
=
TimeUnit
.
HOURS
.
toMillis
(
2
);
public
static
final
long
MAXIMUM_FAST_TEST_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
2
);
public
static
final
long
MAXIMUM_NEGATIVE_PCR_TEST_VALIDITY
=
TimeUnit
.
DAYS
.
toMillis
(
3
);
public
static
final
long
MAXIMUM_POSITIVE_PCR_TEST_VALIDITY
=
MAXIMUM_RECOVERY_VALIDITY
;
@IntDef
({
TYPE_UNKNOWN
,
TYPE_FAST
,
TYPE_PCR
,
TYPE_VACCINATION
,
TYPE_APPOINTMENT
,
TYPE_GREEN_PASS
,
TYPE_RECOVERY
})
@Retention
(
SOURCE
)
...
...
@@ -87,6 +88,7 @@ public class Document {
public
static
final
int
TYPE_PCR
=
2
;
public
static
final
int
TYPE_VACCINATION
=
3
;
public
static
final
int
TYPE_APPOINTMENT
=
4
;
@Deprecated
public
static
final
int
TYPE_GREEN_PASS
=
5
;
public
static
final
int
TYPE_RECOVERY
=
6
;
...
...
@@ -160,6 +162,10 @@ public class Document {
@SerializedName
(
"provider"
)
private
String
provider
;
@Expose
@SerializedName
(
"verified"
)
private
boolean
verified
=
false
;
@Expose
@SerializedName
(
"encodedData"
)
private
String
encodedData
;
...
...
@@ -270,6 +276,14 @@ public class Document {
this
.
provider
=
provider
;
}
public
boolean
isVerified
()
{
return
verified
;
}
public
void
setVerified
(
boolean
verified
)
{
this
.
verified
=
verified
;
}
public
String
getEncodedData
()
{
return
encodedData
;
}
...
...
@@ -313,6 +327,8 @@ public class Document {
return
getTestingTimestamp
()
+
TIME_UNTIL_VACCINATION_IS_VALID
;
}
else
if
(
type
==
TYPE_RECOVERY
&&
outcome
==
OUTCOME_FULLY_IMMUNE
)
{
return
getTestingTimestamp
()
+
TIME_UNTIL_RECOVERY_IS_VALID
;
}
else
if
(
type
==
TYPE_PCR
&&
outcome
==
OUTCOME_POSITIVE
)
{
return
getTestingTimestamp
()
+
TIME_UNTIL_RECOVERY_IS_VALID
;
}
else
{
return
getTestingTimestamp
();
}
...
...
@@ -333,12 +349,16 @@ public class Document {
* The duration in milliseconds after which a document with the specified {@link Type} should be
* treated as invalid.
*/
public
static
long
getExpirationDuration
(
@Type
int
type
)
{
public
long
getExpirationDuration
(
@Type
int
type
)
{
switch
(
type
)
{
case
TYPE_FAST:
return
MAXIMUM_FAST_TEST_VALIDITY
;
case
TYPE_PCR:
return
MAXIMUM_PCR_TEST_VALIDITY
;
if
(
outcome
==
OUTCOME_POSITIVE
)
{
return
MAXIMUM_POSITIVE_PCR_TEST_VALIDITY
;
}
else
{
return
MAXIMUM_NEGATIVE_PCR_TEST_VALIDITY
;
}
case
TYPE_VACCINATION:
return
MAXIMUM_VACCINATION_VALIDITY
;
case
TYPE_RECOVERY:
...
...
@@ -350,6 +370,18 @@ public class Document {
}
}
/**
* @return true if this document is a valid recovery certificate. This is the case when it is a
* positive PCR test older than 14 days but no more than 6 months.
*/
public
boolean
isValidRecovery
()
{
if
(
type
==
TYPE_RECOVERY
||
(
type
==
TYPE_PCR
&&
outcome
==
OUTCOME_POSITIVE
))
{
long
now
=
System
.
currentTimeMillis
();
return
now
>
getValidityStartTimestamp
()
&&
now
<
getExpirationTimestamp
();
}
return
false
;
}
@Override
public
String
toString
()
{
return
"Document{"
+
...
...
Luca/app/src/main/java/de/culture4life/luca/document/DocumentManager.java
View file @
31fa1592
...
...
@@ -123,7 +123,9 @@ public class DocumentManager extends Manager {
}
if
(
document
.
getOutcome
()
==
Document
.
OUTCOME_POSITIVE
&&
document
.
getType
()
!=
Document
.
TYPE_GREEN_PASS
)
{
return
Completable
.
error
(
new
TestResultPositiveException
());
if
(!
document
.
isValidRecovery
())
{
return
Completable
.
error
(
new
TestResultPositiveException
());
}
}
if
(
document
.
getOutcome
()
==
Document
.
OUTCOME_UNKNOWN
&&
document
.
getType
()
!=
Document
.
TYPE_GREEN_PASS
...
...
@@ -154,15 +156,18 @@ public class DocumentManager extends Manager {
);
// TODO: 07.05.21 add ubirch
}
/**
* Redeem a document so that it can not be imported on another device
*
* @param document document object to redeem
*/
public
Completable
redeemDocument
(
@NonNull
Document
document
)
{
if
(
BuildConfig
.
DEBUG
)
{
return
Completable
.
complete
();
}
return
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
Single
.
zip
(
generateEncodedDocumentHash
(
document
),
generateOrRestoreDocumentTag
(
document
),
(
hash
,
tag
)
->
{
JsonObject
jsonObject
=
new
JsonObject
();
jsonObject
.
addProperty
(
"hash"
,
hash
);
jsonObject
.
addProperty
(
"tag"
,
tag
);
JsonObject
jsonObject
=
jsonObjectWith
(
hash
,
tag
);
jsonObject
.
addProperty
(
"expireAt"
,
TimeUtil
.
convertToUnixTimestamp
(
document
.
getExpirationTimestamp
()).
blockingGet
());
return
jsonObject
;
}).
flatMapCompletable
(
lucaEndpointsV3:
:
redeemDocument
))
...
...
@@ -175,6 +180,43 @@ public class DocumentManager extends Manager {
});
}
/**
* Unredeem the given document so it can be imported again on another device
*
* @param document document object to unredeem
*/
public
Completable
unredeemDocument
(
@NonNull
Document
document
)
{
return
networkManager
.
getLucaEndpointsV3
()
.
flatMapCompletable
(
lucaEndpointsV3
->
Single
.
zip
(
generateEncodedDocumentHash
(
document
),
generateOrRestoreDocumentTag
(
document
),
(
hash
,
tag
)
->
jsonObjectWith
(
hash
,
tag
)
).
flatMapCompletable
(
body
->
lucaEndpointsV3
.
unredeemDocument
(
body
)
.
onErrorResumeNext
(
throwable
->
{
if
(
NetworkManager
.
isHttpException
(
throwable
,
HttpURLConnection
.
HTTP_NOT_FOUND
))
{
// The route is not yet available on backend or the document was already unredeemed
return
Completable
.
complete
();
}
return
Completable
.
error
(
throwable
);
})
));
}
/**
* Unredeem and delete all documents stored so they can be imported again on another device
*/
public
Completable
unredeemAndDeleteAllDocuments
()
{
return
getOrRestoreDocuments
()
.
flatMapCompletable
(
document
->
unredeemDocument
(
document
)
.
andThen
(
deleteDocument
(
document
.
getId
())));
}
private
JsonObject
jsonObjectWith
(
String
hash
,
String
tag
)
{
JsonObject
jsonObject
=
new
JsonObject
();
jsonObject
.
addProperty
(
"hash"
,
hash
);
jsonObject
.
addProperty
(
"tag"
,
tag
);
return
jsonObject
;
}
protected
Single
<
String
>
generateEncodedDocumentHash
(
@NonNull
Document
document
)
{
return
Single
.
fromCallable
(
document:
:
getHashableEncodedData
)
.
map
(
hashableEncodedData
->
hashableEncodedData
.
getBytes
(
StandardCharsets
.
UTF_8
))
...
...
Luca/app/src/main/java/de/culture4life/luca/document/provider/baercode/BaercodeDocumentProvider.java
View file @
31fa1592
...
...
@@ -75,6 +75,7 @@ public class BaercodeDocumentProvider extends DocumentProvider<BaercodeDocument>
.
map
(
bytes
->
{
BaercodeDocument
document
=
new
BaercodeDocument
(
bytes
);
decryptPersonalData
(
document
);
document
.
getDocument
().
setVerified
(
true
);
return
document
;
}).
onErrorResumeNext
(
throwable
->
{
if
(
throwable
instanceof
DocumentParsingException
||
throwable
instanceof
DocumentImportException
)
{
...
...
Luca/app/src/main/java/de/culture4life/luca/document/provider/eudcc/EudccDocumentProvider.kt
View file @
31fa1592
...
...
@@ -15,30 +15,27 @@ import io.reactivex.rxjava3.core.Single
* Provider for the EU Digital COVID Certificate (EUDCC)
*/
class
EudccDocumentProvider
(
val
context
:
Context
)
:
DocumentProvider
<
EudccResult
>()
{
private
val
base45Decoder
=
Base45Decoder
()
private
val
decoder
=
DefaultCertificateDecoder
(
base45Decoder
)
override
fun
canParse
(
encodedData
:
String
):
Single
<
Boolean
>
{
return
Single
.
fromCallable
{
try
{
val
withoutPrefix
=
if
(
encodedData
.
startsWith
(
PREFIX
))
encodedData
.
drop
(
PREFIX
.
length
)
else
encodedData
val
decompressed
=
base45Decoder
.
decode
(
withoutPrefix
).
decompressBase45DecodedData
()
val
cbor
=
decompressed
.
decodeCose
().
cbor
EudccSchemaValidator
().
validate
(
cbor
)
}
catch
(
t
:
Throwable
)
{
false
}
}
val
withoutPrefix
=
if
(
encodedData
.
startsWith
(
PREFIX
))
encodedData
.
drop
(
PREFIX
.
length
)
else
encodedData
val
decompressed
=
base45Decoder
.
decode
(
withoutPrefix
).
decompressBase45DecodedData
()
val
cbor
=
decompressed
.
decodeCose
().
cbor
EudccSchemaValidator
().
validate
(
cbor
)
}.
onErrorReturn
{
false
}
}
override
fun
parse
(
encodedData
:
String
):
Single
<
EudccResult
>
{
return
Single
.
just
(
EudccResult
(
encodedData
,
decoder
.
decodeCertificate
(
encodedData
)))
.
map
{
it
.
document
.
provider
=
context
.
getString
(
R
.
string
.
provider_name_eu_dcc
);
it
}
.
onErrorResumeNext
{
throwable
->
if
(
throwable
is
DocumentParsingException
)
{
Single
.
error
<
DocumentParsingException
>(
throwable
)
return
Single
.
fromCallable
{
EudccResult
(
encodedData
,
decoder
.
decodeCertificate
(
encodedData
))
}
.
map
{
it
.
document
.
provider
=
context
.
getString
(
R
.
string
.
provider_name_eu_dcc
);
it
}
.
onErrorResumeNext
{
throwable
->
if
(
throwable
is
DocumentParsingException
)
{
Single
.
error
<
DocumentParsingException
>(
throwable
)
}
Single
.
error
(
DocumentParsingException
(
throwable
))
}
Single
.
error
(
DocumentParsingException
(
throwable
))
}
}
}
\ No newline at end of file
Luca/app/src/main/java/de/culture4life/luca/document/provider/eudcc/EudccResult.kt
View file @
31fa1592
...
...
@@ -52,7 +52,7 @@ class EudccResult(encodedData: String, result: CertificateDecodingResult) : Prov
}
}
}
throw
DocumentParsingException
(
"Could not parse EUDCC: ${error.error}"
)
throw
DocumentParsingException
(
"Could not parse EUDCC: ${error.error}"
,
error
.
error
.
error
)
}
}
...
...
Luca/app/src/main/java/de/culture4life/luca/document/provider/opentestcheck/OpenTestCheckDocument.java
View file @
31fa1592
...
...
@@ -85,9 +85,6 @@ public class OpenTestCheckDocument extends ProvidedDocument {
}
l
=
l
.
trim
().
replaceAll
(
" {2,}"
,
System
.
lineSeparator
());
document
.
setLabName
(
l
);
if
(
l
.
startsWith
(
"DFB"
)
&&
document
.
getType
()
==
Document
.
TYPE_UNKNOWN
)
{
document
.
setType
(
Document
.
TYPE_GREEN_PASS
);
}
document
.
setProvider
(
l
);
// will be replaced with test software provider if available
// lab doctor name
...
...
Luca/app/src/main/java/de/culture4life/luca/document/provider/opentestcheck/OpenTestCheckDocumentProvider.java
View file @
31fa1592
...
...
@@ -62,6 +62,7 @@ public class OpenTestCheckDocumentProvider extends DocumentProvider<OpenTestChec
.
flatMap
(
openTestCheckDocument
->
getProviderName
(
openTestCheckDocument
)
.
map
(
providerName
->
{
openTestCheckDocument
.
getDocument
().
setProvider
(
providerName
);
openTestCheckDocument
.
getDocument
().
setVerified
(
true
);
return
openTestCheckDocument
;
}))
.
onErrorResumeNext
(
throwable
->
Single
.
error
(
new
DocumentParsingException
(
throwable
)));
...
...
Luca/app/src/main/java/de/culture4life/luca/network/endpoints/LucaEndpointsV3.java
View file @
31fa1592
...
...
@@ -154,6 +154,9 @@ public interface LucaEndpointsV3 {
@POST
(
"tests/redeem"
)
Completable
redeemDocument
(
@Body
JsonObject
message
);
@HTTP
(
method
=
"DELETE"
,
path
=
"tests/redeem"
,
hasBody
=
true
)
Completable
unredeemDocument
(
@Body
JsonObject
message
);
@GET
(
"testProviders"
)
Single
<
DocumentProviderDataList
>
getDocumentProviders
();
...
...
Luca/app/src/main/java/de/culture4life/luca/registration/RegistrationManager.java
View file @
31fa1592
...
...
@@ -204,7 +204,6 @@ public class RegistrationManager extends Manager {
.
doOnSuccess
(
registrationData
->
registrationData
.
setId
(
userId
))
.
flatMapCompletable
(
this
::
persistRegistrationData
)
));
}
/**
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/BaseViewModel.java
View file @
31fa1592
...
...
@@ -282,7 +282,8 @@ public abstract class BaseViewModel extends AndroidViewModel {
* successful, show error dialog when an error occurred.
*/
public
void
deleteAccount
()
{
modelDisposable
.
add
(
application
.
getRegistrationManager
().
deleteRegistrationOnBackend
()
modelDisposable
.
add
(
application
.
getDocumentManager
().
unredeemAndDeleteAllDocuments
()
.
andThen
(
application
.
getRegistrationManager
().
deleteRegistrationOnBackend
())
.
doOnSubscribe
(
disposable
->
{
updateAsSideEffect
(
isLoading
,
true
);
removeError
(
deleteAccountError
);
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/AppointmentItem.java
View file @
31fa1592
...
...
@@ -13,7 +13,7 @@ public class AppointmentItem extends TestResultItem {
public
AppointmentItem
(
@NonNull
Context
context
,
@NonNull
Document
document
)
{
super
(
context
,
document
);
this
.
title
=
context
.
getString
(
R
.
string
.
appointment_title
);
this
.
title
=
context
.
getString
(
R
.
string
.
appointment_title
,
document
.
getFirstName
()
);
this
.
color
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
appointment
);
this
.
deleteButtonText
=
context
.
getString
(
R
.
string
.
delete_appointment_action
);
this
.
provider
=
null
;
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/GreenPassItem.java
deleted
100644 → 0
View file @
22451438
package
de.culture4life.luca.ui.myluca
;
import
android.content.Context
;
import
de.culture4life.luca.R
;
import
de.culture4life.luca.document.Document
;
import
androidx.annotation.NonNull
;
import
androidx.core.content.ContextCompat
;
public
class
GreenPassItem
extends
MyLucaListItem
{
protected
final
Document
document
;
public
GreenPassItem
(
@NonNull
Context
context
,
@NonNull
Document
document
)
{
super
(
TYPE_GREEN_PASS
);
this
.
document
=
document
;
this
.
title
=
context
.
getString
(
R
.
string
.
em_green_pass
);
this
.
provider
=
getReadableProvider
(
context
,
document
.
getProvider
());
this
.
timestamp
=
document
.
getImportTimestamp
();
this
.
barcode
=
generateQrCode
(
document
.
getEncodedData
()).
blockingGet
();
this
.
color
=
ContextCompat
.
getColor
(
context
,
R
.
color
.
green_pass
);
this
.
imageResource
=
R
.
drawable
.
ic_dfb
;
this
.
deleteButtonText
=
context
.
getString
(
R
.
string
.
item_delete_action
);
String
time
=
context
.
getString
(
R
.
string
.
document_result_time
,
getReadableDate
(
context
,
document
.
getResultTimestamp
()));
addTopContent
(
document
.
getLabDoctorName
(),
""
);
addTopContent
(
context
.
getString
(
R
.
string
.
em_green_pass_valid
),
time
);
addCollapsedContent
(
context
.
getString
(
R
.
string
.
document_issued_by
),
document
.
getLabName
());
}
public
Document
getDocument
()
{
return
document
;
}
}
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/MyLucaFragment.java
View file @
31fa1592
package
de.culture4life.luca.ui.myluca
;
import
com.google.android.material.button.MaterialButton
;
import
com.google.android.material.card.MaterialCardView
;
import
com.google.android.material.dialog.MaterialAlertDialogBuilder
;
import
com.google.common.util.concurrent.ListenableFuture
;
import
android.util.Size
;
import
android.view.View
;
import
android.widget.ImageView
;
...
...
@@ -7,6 +12,14 @@ import android.widget.ScrollView;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
de.culture4life.luca.R
;
import
de.culture4life.luca.document.Document
;
import
de.culture4life.luca.ui.BaseFragment
;
import
de.culture4life.luca.ui.dialog.BaseDialogFragment
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.Executors
;
import
androidx.annotation.NonNull
;
import
androidx.camera.core.Camera
;
import
androidx.camera.core.CameraSelector
;
...
...
@@ -18,19 +31,6 @@ import androidx.core.content.ContextCompat;
import
androidx.lifecycle.LifecycleOwner
;
import
androidx.recyclerview.widget.LinearLayoutManager
;
import
androidx.recyclerview.widget.RecyclerView
;
import
com.google.android.material.button.MaterialButton
;
import
com.google.android.material.card.MaterialCardView
;
import
com.google.android.material.dialog.MaterialAlertDialogBuilder
;
import
com.google.common.util.concurrent.ListenableFuture
;
import
java.util.concurrent.ExecutionException
;
import
java.util.concurrent.Executors
;
import
de.culture4life.luca.R
;
import
de.culture4life.luca.document.Document
;
import
de.culture4life.luca.ui.BaseFragment
;
import
de.culture4life.luca.ui.dialog.BaseDialogFragment
;
import
io.reactivex.rxjava3.core.Completable
;
import
io.reactivex.rxjava3.core.Maybe
;
import
io.reactivex.rxjava3.core.Single
;
...
...
@@ -260,6 +260,7 @@ public class MyLucaFragment extends BaseFragment<MyLucaViewModel> implements MyL
})
.
setPositiveButton
(
R
.
string
.
action_confirm
,
(
dialog
,
which
)
->
viewDisposable
.
add
(
viewModel
.
deleteListItem
(
myLucaListItem
)
.
onErrorComplete
()
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
()));
new
BaseDialogFragment
(
builder
).
show
();
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/MyLucaListAdapter.java
View file @
31fa1592
...
...
@@ -9,8 +9,6 @@ import androidx.fragment.app.Fragment;
import
androidx.recyclerview.widget.RecyclerView
;
import
androidx.viewpager2.widget.ViewPager2
;
import
org.jetbrains.annotations.NotNull
;
import
java.util.ArrayList
;
import
java.util.Collections
;
import
java.util.HashMap
;
...
...
@@ -50,7 +48,7 @@ public class MyLucaListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
}
@Override
public
RecyclerView
.
@NotNull
ViewHolder
onCreateViewHolder
(
@NonNull
ViewGroup
parent
,
int
viewType
)
{
public
@NonNull
RecyclerView
.
ViewHolder
onCreateViewHolder
(
@NonNull
ViewGroup
parent
,
int
viewType
)
{
if
(
viewType
==
SINGLE_ITEM_VIEW_HOLDER
)
{
ViewGroup
view
=
(
ViewGroup
)
LayoutInflater
.
from
(
parent
.
getContext
()).
inflate
(
R
.
layout
.
my_luca_list_item_container
,
parent
,
false
);
return
new
SingleMyLucaItemViewHolder
(
view
);
...
...
@@ -80,16 +78,12 @@ public class MyLucaListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
holder
.
getConstraintLayoutContainer
().
addView
(
singleLucaItemView
);
singleLucaItemView
.
setListeners
(
expandClickListener
,
deleteClickListener
);
}
else
{
MyLucaListItemExpandListener
expandClickListener
=
new
MyLucaListItemExpandListener
()
{
@Override
public
void
onExpand
()
{
for
(
int
i
=
0
;
i
<
items
.
size
();
i
++)
{
MyLucaListItem
item
=
items
.
get
(
i
);
item
.
toggleExpanded
();
}
notifyItemChanged
(
position
);
MyLucaListItemExpandListener
expandClickListener
=
()
->
{
for
(
int
i
=
0
;
i
<
items
.
size
();
i
++)
{
MyLucaListItem
item
=
items
.
get
(
i
);
item
.
toggleExpanded
();
}
notifyItemChanged
(
position
);
};
Integer
hashCode
=
items
.
hashCode
();
MyLucaItemViewPager
viewPagerAdapter
=
new
MyLucaItemViewPager
(
this
.
fragment
,
items
,
expandClickListener
,
clickListener
,
position
);
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/MyLucaListItem.java
View file @
31fa1592
package
de.culture4life.luca.ui.myluca
;
import
com.google.zxing.EncodeHintType
;
import
android.content.Context
;
import
android.graphics.Bitmap
;
import
android.text.TextUtils
;
import
android.util.Pair
;
import
androidx.annotation.ColorInt
;
import
androidx.annotation.DrawableRes
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
com.google.zxing.EncodeHintType
;
import
de.culture4life.luca.R
;
import
net.glxn.qrgen.android.QRCode
;
import
java.io.Serializable
;
import
java.lang.annotation.Retention
;
import
java.text.SimpleDateFormat
;
import
java.util.ArrayList
;
...
...
@@ -23,7 +18,11 @@ import java.util.Date;
import
java.util.List
;
import
java.util.Locale
;
import
de.culture4life.luca.R
;
import
androidx.annotation.ColorInt
;
import
androidx.annotation.DrawableRes
;
import
androidx.annotation.IntDef
;
import
androidx.annotation.NonNull
;
import
androidx.annotation.Nullable
;
import
io.reactivex.rxjava3.core.Single
;
import
static
java
.
lang
.
annotation
.
RetentionPolicy
.
SOURCE
;
...
...
@@ -33,6 +32,7 @@ public abstract class MyLucaListItem {
public
static
final
int
TYPE_UNKNOWN
=
0
;
public
static
final
int
TYPE_TEST_RESULT
=
1
;
public
static
final
int
TYPE_APPOINTMENT
=
2
;
@Deprecated
public
static
final
int
TYPE_GREEN_PASS
=
3
;
@IntDef
({
TYPE_UNKNOWN
,
TYPE_TEST_RESULT
,
TYPE_APPOINTMENT
,
TYPE_GREEN_PASS
})
...
...
Luca/app/src/main/java/de/culture4life/luca/ui/myluca/MyLucaViewModel.java
View file @
31fa1592
...
...
@@ -57,10 +57,11 @@ public class MyLucaViewModel extends BaseViewModel implements ImageAnalysis.Anal
private
Disposable
imageProcessingDisposable
;
private
ViewError
importError
;
private
ViewError
deleteError
;
public
MyLucaViewModel
(
@NonNull
Application
application
)
{
super
(
application
);
this
.
documentManager
=
this
.
application
.
get
Testing
Manager
();
this
.
documentManager
=
this
.
application
.
get
Document
Manager
();
this
.
notificationManager
=
this
.
application
.
getNotificationManager
();
this
.
registrationManager
=
this
.
application
.
getRegistrationManager
();
this
.
scanner
=
BarcodeScanning
.
getClient
();
...
...
@@ -110,9 +111,7 @@ public class MyLucaViewModel extends BaseViewModel implements ImageAnalysis.Anal
private
Maybe
<
MyLucaListItem
>
createListItem
(
@NonNull
Document
document
)
{
return
Maybe
.
fromCallable
(()
->
{
if
(
document
.
getType
()
==
Document
.
TYPE_GREEN_PASS
)
{
return
new
GreenPassItem
(
application
,
document
);
}
else
if
(
document
.
getType
()
==
Document
.
TYPE_APPOINTMENT
)
{
if
(
document
.
getType
()
==
Document
.
TYPE_APPOINTMENT
)
{
return
new
AppointmentItem
(
application
,
document
);
}
else
if
(
document
.
getType
()
==
Document
.
TYPE_VACCINATION
)
{
return
new
VaccinationItem
(
application
,
document
);
...
...
@@ -126,15 +125,27 @@ public class MyLucaViewModel extends BaseViewModel implements ImageAnalysis.Anal
public
Completable
deleteListItem
(
@NonNull
MyLucaListItem
myLucaListItem
)
{
return
Completable
.
defer
(()
->
{
Document
document
;
if
(
myLucaListItem
instanceof
TestResultItem
)
{
return
documentManager
.
deleteDocument
(((
TestResultItem
)
myLucaListItem
).
getDocument
().
getId
())
.
andThen
(
invokeListUpdate
());
}
else
if
(
myLucaListItem
instanceof
GreenPassItem
)
{
return
documentManager
.
deleteDocument
(((
GreenPassItem
)
myLucaListItem
).
getDocument
().
getId
())
.
andThen
(
invokeListUpdate
());
document
=
((
TestResultItem
)
myLucaListItem
).
getDocument
();
}
else
{