mirror of https://github.com/MISP/misp-bump
commit
32fa6a919f
|
@ -0,0 +1,116 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -3,11 +3,11 @@ apply plugin: 'kotlin-android-extensions'
|
|||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
compileSdkVersion 29
|
||||
defaultConfig {
|
||||
applicationId "lu.circl.mispbump"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 28
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
@ -26,6 +26,10 @@ android {
|
|||
buildToolsVersion = '29.0.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// android
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
|
@ -37,9 +41,9 @@ dependencies {
|
|||
implementation 'androidx.preference:preference:1.1.0-rc01'
|
||||
|
||||
// retrofit
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.1.0'
|
||||
|
||||
// barcode reading
|
||||
implementation 'com.google.android.gms:play-services-vision:18.0.0'
|
||||
|
@ -53,7 +57,5 @@ dependencies {
|
|||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
implementation project(path: ':expandablecardview')
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="lu.circl.mispbump">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:hardwareAccelerated="true"
|
||||
|
@ -16,43 +12,43 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".activities.StartUpActivity">
|
||||
<activity android:name=".activities.UploadActivity" />
|
||||
<activity android:name=".activities.LauncherActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.LoginActivity"
|
||||
android:label="@string/login"/>
|
||||
android:label="@string/login" />
|
||||
<activity
|
||||
android:name=".activities.HomeActivity"
|
||||
android:label="@string/app_name"/>
|
||||
android:label="@string/app_name" />
|
||||
<activity
|
||||
android:name=".activities.ExchangeActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:parentActivityName=".activities.HomeActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.Translucent"/>
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
<activity
|
||||
android:name=".activities.UploadInfoActivity"
|
||||
android:name=".activities.SyncInfoDetailActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:parentActivityName=".activities.HomeActivity"/>
|
||||
<activity
|
||||
android:name=".activities.UploadActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="Upload"
|
||||
android:parentActivityName=".activities.HomeActivity"/>
|
||||
android:label="@string/sync_details_activity_label"
|
||||
android:parentActivityName=".activities.HomeActivity" />
|
||||
<activity
|
||||
android:name=".activities.PreferenceActivity"
|
||||
android:label="@string/settings"
|
||||
android:parentActivityName=".activities.HomeActivity"/>
|
||||
android:parentActivityName=".activities.HomeActivity" />
|
||||
<activity
|
||||
android:name=".activities.ProfileActivity"
|
||||
android:label="Profile"
|
||||
android:parentActivityName=".activities.HomeActivity"
|
||||
android:theme="@style/AppTheme.Translucent"/>
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -22,16 +22,14 @@ import com.google.gson.JsonSyntaxException;
|
|||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.DialogManager;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.auxiliary.QrCodeGenerator;
|
||||
import lu.circl.mispbump.auxiliary.RandomString;
|
||||
import lu.circl.mispbump.fragments.CameraFragment;
|
||||
import lu.circl.mispbump.models.ExchangeInformation;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.security.DiffieHellman;
|
||||
|
||||
|
||||
|
@ -40,7 +38,6 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
private PreferenceManager preferenceManager;
|
||||
private QrCodeGenerator qrCodeGenerator;
|
||||
private DiffieHellman diffieHellman;
|
||||
private UploadInformation uploadInformation;
|
||||
|
||||
private CameraFragment cameraFragment;
|
||||
|
||||
|
@ -50,6 +47,8 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
private ImageView qrCode;
|
||||
private ImageButton prevButton, nextButton;
|
||||
|
||||
private SyncInformation syncInformation;
|
||||
|
||||
private Bitmap publicKeyQr, dataQr;
|
||||
|
||||
private SyncState currentSyncState;
|
||||
|
@ -67,9 +66,11 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
initViews();
|
||||
initCamera();
|
||||
|
||||
uploadInformation = new UploadInformation();
|
||||
publicKeyQr = generatePublicKeyBitmap();
|
||||
|
||||
syncInformation = new SyncInformation();
|
||||
syncInformation.setLocal(generateSyncExchangeInformation());
|
||||
|
||||
setSyncState(SyncState.KEY_EXCHANGE);
|
||||
}
|
||||
|
||||
|
@ -105,95 +106,86 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private ExchangeInformation generateSyncExchangeInformation() {
|
||||
ExchangeInformation exchangeInformation = new ExchangeInformation();
|
||||
exchangeInformation.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
|
||||
exchangeInformation.setSyncUser(preferenceManager.getUserInfo().toSyncUser());
|
||||
exchangeInformation.setServer(new Server(preferenceManager.getUserCredentials().first));
|
||||
return exchangeInformation;
|
||||
}
|
||||
|
||||
|
||||
private Bitmap generatePublicKeyBitmap() {
|
||||
return qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
|
||||
}
|
||||
|
||||
private Bitmap generateLocalSyncInfoBitmap() {
|
||||
uploadInformation.setLocal(generateLocalSyncInfo());
|
||||
return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(uploadInformation.getLocal())));
|
||||
}
|
||||
|
||||
private SyncInformation generateLocalSyncInfo() {
|
||||
SyncInformation syncInformation = new SyncInformation();
|
||||
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
|
||||
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
|
||||
syncInformation.baseUrl = preferenceManager.getUserCredentials().first;
|
||||
syncInformation.syncUserPassword = new RandomString(16).nextString();
|
||||
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
|
||||
return syncInformation;
|
||||
return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(syncInformation.getLocal())));
|
||||
}
|
||||
|
||||
|
||||
private void showQrCode(final Bitmap bitmap) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
qrCode.setImageBitmap(bitmap);
|
||||
qrFrame.setVisibility(View.VISIBLE);
|
||||
}
|
||||
runOnUiThread(() -> {
|
||||
qrCode.setImageBitmap(bitmap);
|
||||
qrFrame.setVisibility(View.VISIBLE);
|
||||
});
|
||||
}
|
||||
|
||||
private void setSyncState(SyncState state) {
|
||||
currentSyncState = state;
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setVisibility(View.GONE);
|
||||
runOnUiThread(() -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setVisibility(View.GONE);
|
||||
|
||||
setCameraPreviewEnabled(true);
|
||||
showQrCode(publicKeyQr);
|
||||
setCameraPreviewEnabled(true);
|
||||
showQrCode(publicKeyQr);
|
||||
|
||||
setReadQrStatus(ReadQrStatus.PENDING);
|
||||
scanFeedbackText.setText(R.string.scan_qr_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
case KEY_EXCHANGE_DONE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
|
||||
nextButton.setVisibility(View.VISIBLE);
|
||||
setReadQrStatus(ReadQrStatus.PENDING);
|
||||
scanFeedbackText.setText(R.string.scan_qr_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
case KEY_EXCHANGE_DONE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_forward));
|
||||
nextButton.setVisibility(View.VISIBLE);
|
||||
|
||||
setCameraPreviewEnabled(false);
|
||||
showQrCode(publicKeyQr);
|
||||
setCameraPreviewEnabled(false);
|
||||
showQrCode(publicKeyQr);
|
||||
|
||||
setReadQrStatus(ReadQrStatus.SUCCESS);
|
||||
scanFeedbackText.setText(R.string.public_key_received_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setVisibility(View.GONE);
|
||||
setReadQrStatus(ReadQrStatus.SUCCESS);
|
||||
scanFeedbackText.setText(R.string.public_key_received_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setVisibility(View.GONE);
|
||||
|
||||
setCameraPreviewEnabled(true);
|
||||
showQrCode(dataQr);
|
||||
setCameraPreviewEnabled(true);
|
||||
showQrCode(dataQr);
|
||||
|
||||
setReadQrStatus(ReadQrStatus.PENDING);
|
||||
scanFeedbackText.setText(R.string.scan_qr_hint);
|
||||
qrContentInfo.setText(R.string.sync_information);
|
||||
break;
|
||||
case DATA_EXCHANGE_DONE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setImageDrawable(getDrawable(R.drawable.ic_check));
|
||||
nextButton.setVisibility(View.VISIBLE);
|
||||
setReadQrStatus(ReadQrStatus.PENDING);
|
||||
scanFeedbackText.setText(R.string.scan_qr_hint);
|
||||
qrContentInfo.setText(R.string.sync_information);
|
||||
break;
|
||||
case DATA_EXCHANGE_DONE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
|
||||
prevButton.setVisibility(View.VISIBLE);
|
||||
nextButton.setImageDrawable(getDrawable(R.drawable.ic_check));
|
||||
nextButton.setVisibility(View.VISIBLE);
|
||||
|
||||
setCameraPreviewEnabled(false);
|
||||
showQrCode(dataQr);
|
||||
setCameraPreviewEnabled(false);
|
||||
showQrCode(dataQr);
|
||||
|
||||
setReadQrStatus(ReadQrStatus.SUCCESS);
|
||||
scanFeedbackText.setText(R.string.sync_info_received_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
}
|
||||
setReadQrStatus(ReadQrStatus.SUCCESS);
|
||||
scanFeedbackText.setText(R.string.sync_info_received_hint);
|
||||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -261,107 +253,70 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
|
||||
|
||||
private CameraFragment.QrScanCallback onQrScanned() {
|
||||
return new CameraFragment.QrScanCallback() {
|
||||
@Override
|
||||
public void qrScanResult(String qrData) {
|
||||
cameraFragment.setReadQrEnabled(false);
|
||||
return qrData -> {
|
||||
cameraFragment.setReadQrEnabled(false);
|
||||
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
try {
|
||||
diffieHellman.setForeignPublicKey(DiffieHellman.publicKeyFromString(qrData));
|
||||
setSyncState(SyncState.KEY_EXCHANGE_DONE);
|
||||
dataQr = generateLocalSyncInfoBitmap();
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||
if (currentReadQrStatus == ReadQrStatus.PENDING) {
|
||||
setReadQrStatus(ReadQrStatus.FAILURE);
|
||||
Snackbar.make(rootLayout, "Public key not parsable", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
cameraFragment.setReadQrEnabled(true);
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
try {
|
||||
diffieHellman.setForeignPublicKey(DiffieHellman.publicKeyFromString(qrData));
|
||||
setSyncState(SyncState.KEY_EXCHANGE_DONE);
|
||||
dataQr = generateLocalSyncInfoBitmap();
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||
if (currentReadQrStatus == ReadQrStatus.PENDING) {
|
||||
setReadQrStatus(ReadQrStatus.FAILURE);
|
||||
Snackbar.make(rootLayout, "Public key not parsable", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
try {
|
||||
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
|
||||
|
||||
final List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
|
||||
|
||||
for (final UploadInformation ui : uploadInformationList) {
|
||||
if (ui.getRemote().organisation.getUuid().equals(remoteSyncInfo.organisation.getUuid())) {
|
||||
DialogManager.syncAlreadyExistsDialog(ui.getRemote(), remoteSyncInfo, ExchangeActivity.this, new DialogManager.IDialogFeedback() {
|
||||
@Override
|
||||
public void positive() {
|
||||
// update remote info only
|
||||
uploadInformation.setUuid(ui.getUuid());
|
||||
uploadInformation.setDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void negative() {
|
||||
// replace credentials too
|
||||
uploadInformationList.remove(ui);
|
||||
preferenceManager.setUploadInformationList(uploadInformationList);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uploadInformation.setRemote(remoteSyncInfo);
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
setSyncState(SyncState.DATA_EXCHANGE_DONE);
|
||||
} catch (JsonSyntaxException e) {
|
||||
if (currentReadQrStatus == ReadQrStatus.PENDING) {
|
||||
setReadQrStatus(ReadQrStatus.FAILURE);
|
||||
Snackbar.make(rootLayout, "Sync information not parsable", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
cameraFragment.setReadQrEnabled(true);
|
||||
cameraFragment.setReadQrEnabled(true);
|
||||
}
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
try {
|
||||
syncInformation.setRemote(new Gson().fromJson(diffieHellman.decrypt(qrData), ExchangeInformation.class));
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
setSyncState(SyncState.DATA_EXCHANGE_DONE);
|
||||
} catch (JsonSyntaxException e) {
|
||||
if (currentReadQrStatus == ReadQrStatus.PENDING) {
|
||||
setReadQrStatus(ReadQrStatus.FAILURE);
|
||||
Snackbar.make(rootLayout, "Sync information not parsable", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cameraFragment.setReadQrEnabled(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private View.OnClickListener onPrevClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
case KEY_EXCHANGE_DONE:
|
||||
// TODO warning that sync will be lost
|
||||
finish();
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
case DATA_EXCHANGE_DONE:
|
||||
setSyncState(SyncState.KEY_EXCHANGE_DONE);
|
||||
break;
|
||||
}
|
||||
return v -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
case KEY_EXCHANGE_DONE:
|
||||
// TODO warning that sync will be lost
|
||||
finish();
|
||||
break;
|
||||
case DATA_EXCHANGE:
|
||||
case DATA_EXCHANGE_DONE:
|
||||
setSyncState(SyncState.KEY_EXCHANGE_DONE);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private View.OnClickListener onNextClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE_DONE:
|
||||
setSyncState(SyncState.DATA_EXCHANGE);
|
||||
break;
|
||||
case DATA_EXCHANGE_DONE:
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.PENDING);
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
Intent i = new Intent(ExchangeActivity.this, UploadInfoActivity.class);
|
||||
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformation.getUuid());
|
||||
startActivity(i);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
return v -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE_DONE:
|
||||
setSyncState(SyncState.DATA_EXCHANGE);
|
||||
break;
|
||||
case DATA_EXCHANGE_DONE:
|
||||
Intent i = new Intent(ExchangeActivity.this, SyncInfoDetailActivity.class);
|
||||
i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid());
|
||||
startActivity(i);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,37 +11,56 @@ import android.widget.TextView;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.adapters.UploadInfoAdapter;
|
||||
import lu.circl.mispbump.adapters.SyncInfoAdapter;
|
||||
import lu.circl.mispbump.auxiliary.MispRestClient;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.models.ExchangeInformation;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.restModels.MispServer;
|
||||
import lu.circl.mispbump.models.restModels.MispUser;
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
private List<UploadInformation> uploadInformationList;
|
||||
private List<SyncInformation> syncInformationList;
|
||||
private PreferenceManager preferenceManager;
|
||||
private MispRestClient restClient;
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private UploadInfoAdapter uploadInfoAdapter;
|
||||
private SyncInfoAdapter syncInfoAdapter;
|
||||
private TextView emptyRecyclerView;
|
||||
|
||||
private SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_home);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(this);
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
initViews();
|
||||
initRecyclerView();
|
||||
checkRequiredInformationAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -62,7 +81,6 @@ public class HomeActivity extends AppCompatActivity {
|
|||
return true;
|
||||
}
|
||||
|
||||
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
|
@ -80,46 +98,187 @@ public class HomeActivity extends AppCompatActivity {
|
|||
setSupportActionBar(myToolbar);
|
||||
|
||||
FloatingActionButton syncFab = findViewById(R.id.home_fab);
|
||||
syncFab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startActivity(new Intent(HomeActivity.this, ExchangeActivity.class));
|
||||
}
|
||||
syncFab.setOnClickListener(v -> startActivity(new Intent(HomeActivity.this, ExchangeActivity.class)));
|
||||
|
||||
swipeRefreshLayout = findViewById(R.id.swipeRefresh);
|
||||
swipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
checkUnimportedSyncs();
|
||||
|
||||
syncInfoAdapter.setItems(syncInformationList);
|
||||
});
|
||||
}
|
||||
|
||||
private void initRecyclerView() {
|
||||
recyclerView = findViewById(R.id.recyclerView);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(HomeActivity.this));
|
||||
uploadInfoAdapter = new UploadInfoAdapter(HomeActivity.this);
|
||||
uploadInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
|
||||
recyclerView.setAdapter(uploadInfoAdapter);
|
||||
syncInfoAdapter = new SyncInfoAdapter();
|
||||
syncInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
|
||||
recyclerView.setAdapter(syncInfoAdapter);
|
||||
}
|
||||
|
||||
private void refreshRecyclerView() {
|
||||
uploadInformationList = preferenceManager.getUploadInformationList();
|
||||
syncInformationList = preferenceManager.getSyncInformationList();
|
||||
|
||||
if (uploadInformationList.isEmpty()) {
|
||||
if (syncInformationList.isEmpty()) {
|
||||
emptyRecyclerView.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emptyRecyclerView.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
uploadInfoAdapter.setItems(uploadInformationList);
|
||||
syncInfoAdapter.setItems(syncInformationList);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRequiredInformationAvailable() {
|
||||
if (preferenceManager.getRoles() == null || preferenceManager.getUserInfo() == null || preferenceManager.getUserOrganisation() == null) {
|
||||
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
MispRestClient client = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
// get roles
|
||||
client.getRoles(new MispRestClient.AllRolesCallback() {
|
||||
@Override
|
||||
public void success(Role[] roles) {
|
||||
preferenceManager.setRoles(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
|
||||
// get user and organisation
|
||||
client.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(User user) {
|
||||
preferenceManager.setMyUser(user);
|
||||
|
||||
client.getOrganisation(user.getOrgId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
}
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUnimportedSyncs() {
|
||||
restClient.getAllServers(new MispRestClient.AllRawServersCallback() {
|
||||
@Override
|
||||
public void success(List<MispServer> mispServers) {
|
||||
if (mispServers.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SyncInformation> syncInformationList = preferenceManager.getSyncInformationList();
|
||||
|
||||
for (MispServer mispServer : mispServers) {
|
||||
|
||||
boolean existsOffline = false;
|
||||
|
||||
for (SyncInformation syncInformation : syncInformationList) {
|
||||
int localServerId = syncInformation.getRemote().getServer().getId();
|
||||
int remoteServerId = mispServer.getServer().getId();
|
||||
|
||||
if (remoteServerId == localServerId) {
|
||||
existsOffline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!existsOffline) {
|
||||
// mispServer is not locally available
|
||||
SyncInformation syncInformation = new SyncInformation();
|
||||
|
||||
ExchangeInformation local = new ExchangeInformation();
|
||||
local.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
|
||||
User syncUser = preferenceManager.getUserInfo().toSyncUser();
|
||||
syncUser.setAuthkey("Could not be recovered");
|
||||
syncUser.setPassword("Could not be recovered");
|
||||
local.setSyncUser(syncUser);
|
||||
local.setServer(new Server(preferenceManager.getUserCredentials().first));
|
||||
|
||||
ExchangeInformation remote = new ExchangeInformation();
|
||||
remote.setServer(mispServer.getServer());
|
||||
|
||||
restClient.getOrganisation(mispServer.getRemoteOrganisation().getId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
remote.setOrganisation(organisation);
|
||||
|
||||
restClient.getAllUsers(new MispRestClient.AllMispUsersCallback() {
|
||||
@Override
|
||||
public void success(List<MispUser> users) {
|
||||
for (MispUser mispUser : users) {
|
||||
|
||||
boolean isSyncUserRole = false;
|
||||
|
||||
Role[] roles = preferenceManager.getRoles();
|
||||
|
||||
for (Role role : roles) {
|
||||
if (role.getId().equals(mispUser.getRole().getId())) {
|
||||
isSyncUserRole = role.isSyncUserRole();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mispUser.getOrganisation().getId().equals(organisation.getId()) && isSyncUserRole) {
|
||||
remote.setSyncUser(mispUser.getUser());
|
||||
|
||||
syncInformation.setLocal(local);
|
||||
syncInformation.setRemote(remote);
|
||||
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
refreshRecyclerView();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerItemClickListener() {
|
||||
return new OnRecyclerItemClickListener<Integer>() {
|
||||
@Override
|
||||
public void onClick(View v, Integer index) {
|
||||
Intent i = new Intent(HomeActivity.this, UploadInfoActivity.class);
|
||||
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformationList.get(index).getUuid());
|
||||
return (v, index) -> {
|
||||
Intent i = new Intent(HomeActivity.this, SyncInfoDetailActivity.class);
|
||||
i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformationList.get(index).getUuid());
|
||||
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(v.findViewById(R.id.rootLayout), (int) v.getX(), (int) v.getY(), v.getWidth(), v.getHeight());
|
||||
startActivity(i, options.toBundle());
|
||||
}
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(v.findViewById(R.id.rootLayout), (int) v.getX(), (int) v.getY(), v.getWidth(), v.getHeight());
|
||||
startActivity(i, options.toBundle());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ import lu.circl.mispbump.auxiliary.PreferenceManager;
|
|||
/**
|
||||
* Starts either the login or home activity.
|
||||
*/
|
||||
public class StartUpActivity extends AppCompatActivity {
|
||||
public class LauncherActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
|
@ -131,9 +131,9 @@ public class LoginActivity extends AppCompatActivity {
|
|||
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(final User user) {
|
||||
preferenceManager.setUserInfo(user);
|
||||
preferenceManager.setMyUser(user);
|
||||
for (Role role : roles) {
|
||||
if (role.getId().equals(user.role_id)) {
|
||||
if (role.getId().equals(user.getRoleId())) {
|
||||
if (!role.getPermAdmin()) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
Snackbar.make(constraintLayout, "No admin is associated with this authkey.", Snackbar.LENGTH_LONG).show();
|
||||
|
@ -142,10 +142,10 @@ public class LoginActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
||||
mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
preferenceManager.setUserOrgInfo(organisation);
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
preferenceManager.setUserCredentials(url, authkey);
|
||||
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
|
|
@ -8,17 +8,24 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
|
||||
|
||||
public class PreferenceActivity extends AppCompatActivity {
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_preference);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(PreferenceActivity.this);
|
||||
|
||||
initializeViews();
|
||||
}
|
||||
|
||||
|
@ -32,15 +39,27 @@ public class PreferenceActivity extends AppCompatActivity {
|
|||
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
fragmentTransaction.add(R.id.fragmentContainer, new PreferencesFragment(), PreferencesFragment.class.getSimpleName());
|
||||
PreferencesFragment preferencesFragment = new PreferencesFragment();
|
||||
preferencesFragment.onDeleteAllSyncsListener = preference -> {
|
||||
preferenceManager.clearUploadInformation();
|
||||
return true;
|
||||
};
|
||||
|
||||
fragmentTransaction.add(R.id.fragmentContainer, preferencesFragment, PreferencesFragment.class.getSimpleName());
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
public static class PreferencesFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private Preference.OnPreferenceClickListener onDeleteAllSyncsListener;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.preference_screen_main, rootKey);
|
||||
findPreference("PREF_DELETE_ALL_SYNCS").setOnPreferenceClickListener(preference -> true);
|
||||
|
||||
Preference deleteAllSyncInfo = findPreference("PREF_DELETE_ALL_SYNCS");
|
||||
assert deleteAllSyncInfo != null;
|
||||
deleteAllSyncInfo.setOnPreferenceClickListener(onDeleteAllSyncsListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
|
@ -45,6 +44,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
private FloatingActionButton fab;
|
||||
private AnimatedVectorDrawable fabLoadingDrawable;
|
||||
|
||||
private View.OnClickListener onFabClicked = view -> {
|
||||
fab.setImageDrawable(fabLoadingDrawable);
|
||||
fabLoadingDrawable.start();
|
||||
updateProfileInformation();
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -54,55 +59,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
init();
|
||||
initToolbar();
|
||||
initViews();
|
||||
|
||||
populateInformationViews();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
rootLayout = findViewById(R.id.rootLayout);
|
||||
|
||||
ImageView headerBg = findViewById(R.id.headerBg);
|
||||
headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
|
||||
|
||||
// populate Toolbar (Actionbar)
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(onFabClicked());
|
||||
|
||||
fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
|
||||
}
|
||||
|
||||
private void populateInformationViews() {
|
||||
Organisation organisation = preferenceManager.getUserOrganisation();
|
||||
|
||||
TextView name = findViewById(R.id.orgName);
|
||||
name.setText(organisation.getName());
|
||||
|
||||
final MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(organisation.getUuid());
|
||||
|
||||
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
||||
nationality.setSubtitle(organisation.getNationality());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
if (organisation.getSector() == null) {
|
||||
sector.setVisibility(View.GONE);
|
||||
} else {
|
||||
sector.setSubtitle(organisation.getSector());
|
||||
}
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(organisation.getDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_profile, menu);
|
||||
|
@ -119,23 +81,51 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private View.OnClickListener onFabClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
fab.setImageDrawable(fabLoadingDrawable);
|
||||
fabLoadingDrawable.start();
|
||||
updateProfile();
|
||||
}
|
||||
};
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getRandomHeader() {
|
||||
int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
|
||||
return getDrawable(ids[new Random().nextInt(ids.length)]);
|
||||
private void initViews() {
|
||||
rootLayout = findViewById(R.id.rootLayout);
|
||||
|
||||
ImageView headerBg = findViewById(R.id.headerBg);
|
||||
headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(onFabClicked);
|
||||
|
||||
fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
|
||||
}
|
||||
|
||||
public void updateProfile() {
|
||||
private void populateInformationViews() {
|
||||
Organisation organisation = preferenceManager.getUserOrganisation();
|
||||
|
||||
TextView name = findViewById(R.id.orgName);
|
||||
name.setText(organisation.getName());
|
||||
|
||||
final MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(organisation.getUuid());
|
||||
|
||||
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
||||
nationality.setSubtitle(organisation.getNationality());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
sector.setSubtitle(organisation.getSector());
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(organisation.getDescription());
|
||||
}
|
||||
|
||||
|
||||
public void updateProfileInformation() {
|
||||
mispRestClient.getRoles(new MispRestClient.AllRolesCallback() {
|
||||
@Override
|
||||
public void success(Role[] roles) {
|
||||
|
@ -151,12 +141,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(final User user) {
|
||||
preferenceManager.setUserInfo(user);
|
||||
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
||||
preferenceManager.setMyUser(user);
|
||||
mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
fabLoadingDrawable.stop();
|
||||
preferenceManager.setUserOrgInfo(organisation);
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
Snackbar.make(rootLayout, "Successfully update profile", Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
|
@ -181,25 +171,23 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
|
||||
builder.setTitle("Clear all saved data and logout");
|
||||
builder.setMessage("Do you really want to delete all data and logout?");
|
||||
builder.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton("Discard", (dialog, which) -> dialog.cancel());
|
||||
|
||||
builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
preferenceManager.clearAllData();
|
||||
KeyStoreWrapper.deleteAllStoredKeys();
|
||||
builder.setPositiveButton("Delete & Logout", (dialog, which) -> {
|
||||
preferenceManager.clearAllData();
|
||||
KeyStoreWrapper.deleteAllStoredKeys();
|
||||
|
||||
Intent login = new Intent(getApplicationContext(), LoginActivity.class);
|
||||
startActivity(login);
|
||||
finish();
|
||||
}
|
||||
Intent login = new Intent(getApplicationContext(), LoginActivity.class);
|
||||
startActivity(login);
|
||||
finish();
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
|
||||
private Drawable getRandomHeader() {
|
||||
int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
|
||||
return getDrawable(ids[new Random().nextInt(ids.length)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroupOverlay;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.customViews.MaterialPasswordView;
|
||||
import lu.circl.mispbump.customViews.MaterialPreferenceText;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
|
||||
|
||||
public class SyncInfoDetailActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_SYNC_INFO_UUID = "EXTRA_SYNC_INFO_UUID";
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private SyncInformation syncInformation;
|
||||
|
||||
private boolean fabMenuExpanded;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_sync_info_detail);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(SyncInfoDetailActivity.this);
|
||||
syncInformation = preferenceManager.getSyncInformation(getExtraUuid());
|
||||
|
||||
if (syncInformation == null) {
|
||||
throw new RuntimeException("Could not find UploadInformation with UUID {" + getExtraUuid().toString() + "}");
|
||||
}
|
||||
|
||||
initToolbar();
|
||||
initFabMenu();
|
||||
populateContent();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
}
|
||||
|
||||
|
||||
private UUID getExtraUuid() {
|
||||
return (UUID) getIntent().getSerializableExtra(EXTRA_SYNC_INFO_UUID);
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void initFabMenu() {
|
||||
FloatingActionButton fab = findViewById(R.id.fab_main);
|
||||
FloatingActionButton fabUpload = findViewById(R.id.fab_upload);
|
||||
FloatingActionButton fabDownload = findViewById(R.id.fab_download);
|
||||
|
||||
LinearLayout uploadLayout = findViewById(R.id.layout_upload);
|
||||
LinearLayout downloadLayout = findViewById(R.id.layout_download);
|
||||
|
||||
uploadLayout.setVisibility(View.GONE);
|
||||
downloadLayout.setVisibility(View.GONE);
|
||||
|
||||
fab.setOnClickListener(view -> {
|
||||
if (fabMenuExpanded) {
|
||||
uploadLayout.setVisibility(View.GONE);
|
||||
downloadLayout.setVisibility(View.GONE);
|
||||
|
||||
fabMenuExpanded = false;
|
||||
} else {
|
||||
uploadLayout.setVisibility(View.VISIBLE);
|
||||
downloadLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
fabMenuExpanded = true;
|
||||
}
|
||||
});
|
||||
|
||||
fabUpload.setOnClickListener(view -> {
|
||||
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
|
||||
Intent upload = new Intent(SyncInfoDetailActivity.this, UploadActivity.class);
|
||||
upload.putExtra(UploadActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid().toString());
|
||||
startActivity(upload);
|
||||
});
|
||||
|
||||
fabDownload.setOnClickListener(view -> {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void populateContent() {
|
||||
|
||||
// information
|
||||
|
||||
MaterialPreferenceText name = findViewById(R.id.name);
|
||||
name.setSubtitle(syncInformation.getRemote().getOrganisation().getName());
|
||||
|
||||
MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(syncInformation.getRemote().getOrganisation().getUuid());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
sector.setSubtitle(syncInformation.getRemote().getOrganisation().getSector());
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(syncInformation.getRemote().getOrganisation().getDescription());
|
||||
|
||||
// settings
|
||||
|
||||
CheckBox allowSelfSigned = findViewById(R.id.checkbox_self_signed);
|
||||
allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned());
|
||||
allowSelfSigned.setOnCheckedChangeListener((compoundButton, b) -> {
|
||||
syncInformation.getRemote().getServer().setSelfSigned(b);
|
||||
|
||||
});
|
||||
|
||||
CheckBox push = findViewById(R.id.checkbox_push);
|
||||
push.setChecked(syncInformation.getRemote().getServer().getPush());
|
||||
push.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setPush(b));
|
||||
|
||||
CheckBox pull = findViewById(R.id.checkbox_pull);
|
||||
pull.setChecked(syncInformation.getRemote().getServer().getPull());
|
||||
pull.setOnCheckedChangeListener((compundButton, b) -> syncInformation.getRemote().getServer().setPull(b));
|
||||
|
||||
CheckBox cache = findViewById(R.id.checkbox_cache);
|
||||
cache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
cache.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setCachingEnabled(b));
|
||||
|
||||
// credentials
|
||||
|
||||
MaterialPreferenceText email = findViewById(R.id.email);
|
||||
email.setSubtitle(syncInformation.getLocal().getSyncUser().getEmail());
|
||||
|
||||
MaterialPasswordView password = findViewById(R.id.password);
|
||||
password.setPassword(syncInformation.getLocal().getSyncUser().getPassword());
|
||||
|
||||
MaterialPasswordView authkey = findViewById(R.id.authkey);
|
||||
authkey.setPassword(syncInformation.getLocal().getSyncUser().getAuthkey());
|
||||
}
|
||||
|
||||
|
||||
public static void applyDim(@NonNull ViewGroup parent, float dimAmount) {
|
||||
// ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView();
|
||||
Drawable dim = new ColorDrawable(Color.BLACK);
|
||||
dim.setBounds(0, 0, parent.getWidth(), parent.getHeight());
|
||||
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(dimAmount);
|
||||
|
||||
valueAnimator.addUpdateListener(valueAnim -> {
|
||||
float value = (float) valueAnim.getAnimatedValue();
|
||||
dim.setAlpha((int) (255 * value));
|
||||
ViewGroupOverlay overlay = parent.getOverlay();
|
||||
overlay.add(dim);
|
||||
});
|
||||
|
||||
valueAnimator.start();
|
||||
}
|
||||
|
||||
public static void clearDim(@NonNull ViewGroup parent) {
|
||||
ViewGroupOverlay overlay = parent.getOverlay();
|
||||
overlay.clear();
|
||||
}
|
||||
}
|
|
@ -4,37 +4,92 @@ package lu.circl.mispbump.activities;
|
|||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.MispRestClient;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.customViews.UploadAction;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.customViews.ProgressActionView;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class UploadActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_UPLOAD_INFO = "uploadInformation";
|
||||
public static final String EXTRA_SYNC_INFO_UUID = "EXTRA_SYNC_INFO_UUID";
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private UploadInformation uploadInformation;
|
||||
private MispRestClient mispRest;
|
||||
private SyncInformation syncInformation;
|
||||
|
||||
private ProgressActionView availableAction, organisationAction, userAction, serverAction;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
|
||||
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
mispRest = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
parseExtra();
|
||||
initToolbar();
|
||||
initProgressActionViews();
|
||||
startUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
String syncInfoUuid = i.getStringExtra(EXTRA_SYNC_INFO_UUID);
|
||||
syncInformation = preferenceManager.getSyncInformation(UUID.fromString(syncInfoUuid));
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initProgressActionViews() {
|
||||
availableAction = findViewById(R.id.availableProgressAction);
|
||||
organisationAction = findViewById(R.id.organisationProgressAction);
|
||||
userAction = findViewById(R.id.userProgressAction);
|
||||
serverAction = findViewById(R.id.serverProgressAction);
|
||||
|
||||
availableAction.pending();
|
||||
organisationAction.pending();
|
||||
userAction.pending();
|
||||
serverAction.pending();
|
||||
}
|
||||
|
||||
private MispRestClient restClient;
|
||||
private UploadAction availableAction, orgAction, userAction, serverAction;
|
||||
|
||||
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
|
||||
@Override
|
||||
|
@ -92,187 +147,70 @@ public class UploadActivity extends AppCompatActivity {
|
|||
}
|
||||
};
|
||||
|
||||
private FloatingActionButton fab;
|
||||
|
||||
private boolean errorWhileUpload;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
parseExtra();
|
||||
initViews();
|
||||
startUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
saveCurrentState();
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
saveCurrentState();
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
|
||||
UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO);
|
||||
|
||||
for (UploadInformation ui : preferenceManager.getUploadInformationList()) {
|
||||
if (ui.getUuid().compareTo(currentUUID) == 0) {
|
||||
uploadInformation = ui;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadInformation == null) {
|
||||
throw new RuntimeException("Could not find UploadInfo with UUID {" + currentUUID.toString() + "}");
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.hide();
|
||||
|
||||
// toolbar
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
|
||||
ab.setDisplayShowTitleEnabled(false);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
|
||||
availableAction = findViewById(R.id.availableAction);
|
||||
orgAction = findViewById(R.id.orgAction);
|
||||
userAction = findViewById(R.id.userAction);
|
||||
serverAction = findViewById(R.id.serverAction);
|
||||
}
|
||||
|
||||
private void saveCurrentState() {
|
||||
if (errorWhileUpload) {
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||
}
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
}
|
||||
|
||||
private void setUploadActionState(UploadAction uploadAction, UploadAction.UploadState state, @Nullable String error) {
|
||||
uploadAction.setCurrentUploadState(state);
|
||||
uploadAction.setError(error);
|
||||
|
||||
switch (state) {
|
||||
case PENDING:
|
||||
if (fab.isShown()) {
|
||||
fab.hide();
|
||||
}
|
||||
break;
|
||||
case LOADING:
|
||||
errorWhileUpload = false;
|
||||
if (fab.isShown()) {
|
||||
fab.hide();
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
errorWhileUpload = false;
|
||||
break;
|
||||
case ERROR:
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||
|
||||
fab.setImageResource(R.drawable.ic_autorenew);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.LOADING, null);
|
||||
startUpload();
|
||||
}
|
||||
});
|
||||
if (!fab.isShown()) {
|
||||
fab.show();
|
||||
}
|
||||
errorWhileUpload = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private User generateSyncUser(Organisation organisation) {
|
||||
User syncUser = new User();
|
||||
syncUser.org_id = organisation.getId();
|
||||
syncUser.role_id = User.ROLE_SYNC_USER;
|
||||
syncUser.email = uploadInformation.getRemote().syncUserEmail;
|
||||
syncUser.password = uploadInformation.getRemote().syncUserPassword;
|
||||
syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
|
||||
syncUser.termsaccepted = true;
|
||||
User syncUser = syncInformation.getRemote().getSyncUser();
|
||||
|
||||
syncUser.setOrgId(organisation.getId());
|
||||
syncUser.setTermsAccepted(true);
|
||||
|
||||
Role[] roles = preferenceManager.getRoles();
|
||||
for (Role role : roles) {
|
||||
if (role.isSyncUserRole()) {
|
||||
syncUser.setRoleId(role.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return syncUser;
|
||||
}
|
||||
|
||||
private Server generateSyncServer() {
|
||||
Server server = new Server();
|
||||
server.name = uploadInformation.getRemote().organisation.getName() + "'s Sync Server";
|
||||
server.url = uploadInformation.getRemote().baseUrl;
|
||||
server.remote_org_id = uploadInformation.getRemote().organisation.getId();
|
||||
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
|
||||
server.pull = uploadInformation.isPull();
|
||||
server.push = uploadInformation.isPush();
|
||||
server.caching_enabled = uploadInformation.isCached();
|
||||
server.self_signed = uploadInformation.isAllowSelfSigned();
|
||||
Server server = syncInformation.getRemote().getServer();
|
||||
server.setName(syncInformation.getRemote().getOrganisation().getName() + "'s Sync Server");
|
||||
server.setRemoteOrgId(syncInformation.getRemote().getOrganisation().getId());
|
||||
server.setAuthkey(syncInformation.getRemote().getSyncUser().getAuthkey());
|
||||
server.setPull(syncInformation.getRemote().getServer().getPull());
|
||||
server.setPush(syncInformation.getRemote().getServer().getPush());
|
||||
server.setCachingEnabled(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
server.setSelfSigned(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start upload to misp instance.
|
||||
*/
|
||||
private void startUpload() {
|
||||
availableAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||
restClient.isAvailable(availableCallback);
|
||||
availableAction.start();
|
||||
mispRest.isAvailable(availableCallback);
|
||||
}
|
||||
|
||||
private void mispAvailable(boolean available, String error) {
|
||||
if (available) {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.DONE, null);
|
||||
restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
|
||||
availableAction.done();
|
||||
organisationAction.start();
|
||||
|
||||
mispRest.addOrganisation(syncInformation.getRemote().getOrganisation(), organisationCallback);
|
||||
} else {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.ERROR, error);
|
||||
availableAction.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
private void organisationAdded(Organisation organisation) {
|
||||
if (organisation != null) {
|
||||
setUploadActionState(orgAction, UploadAction.UploadState.DONE, null);
|
||||
uploadInformation.getRemote().organisation.setId(organisation.getId());
|
||||
restClient.addUser(generateSyncUser(organisation), userCallback);
|
||||
organisationAction.done();
|
||||
userAction.start();
|
||||
|
||||
syncInformation.getRemote().getOrganisation().setId(organisation.getId());
|
||||
mispRest.addUser(generateSyncUser(organisation), userCallback);
|
||||
} else {
|
||||
// search by UUID because the error does not give the actual ID
|
||||
restClient.getOrganisation(uploadInformation.getRemote().organisation.getUuid(), new MispRestClient.OrganisationCallback() {
|
||||
mispRest.getOrganisation(syncInformation.getRemote().getOrganisation().getUuid(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
organisationAdded(organisation);
|
||||
organisationAction.done("Organisation already on MISP instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
setUploadActionState(orgAction, UploadAction.UploadState.ERROR, error);
|
||||
organisationAction.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -280,18 +218,21 @@ public class UploadActivity extends AppCompatActivity {
|
|||
|
||||
private void userAdded(User user) {
|
||||
if (user != null) {
|
||||
setUploadActionState(userAction, UploadAction.UploadState.DONE, null);
|
||||
restClient.getAllServers(allServersCallback);
|
||||
userAction.done();
|
||||
serverAction.start();
|
||||
|
||||
mispRest.getAllServers(allServersCallback);
|
||||
} else {
|
||||
restClient.getUser(uploadInformation.getRemote().syncUserEmail, new MispRestClient.UserCallback() {
|
||||
mispRest.getUser(syncInformation.getLocal().getSyncUser().getEmail(), new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(User user) {
|
||||
userAdded(user);
|
||||
userAction.done("User already on MISP instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
setUploadActionState(userAction, UploadAction.UploadState.ERROR, error);
|
||||
userAction.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -302,35 +243,25 @@ public class UploadActivity extends AppCompatActivity {
|
|||
Server serverToUpload = generateSyncServer();
|
||||
|
||||
for (Server server : servers) {
|
||||
if (server.remote_org_id.equals(serverToUpload.remote_org_id)) {
|
||||
if (server.getRemoteOrgId().equals(serverToUpload.getRemoteOrgId())) {
|
||||
// server already exists: override id to update instead
|
||||
serverToUpload.id = server.id;
|
||||
serverToUpload.setId(server.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
restClient.addServer(serverToUpload, serverCallback);
|
||||
mispRest.addServer(serverToUpload, serverCallback);
|
||||
} else {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not retrieve server information");
|
||||
serverAction.error("Unknown error while creating the Sync Server");
|
||||
}
|
||||
}
|
||||
|
||||
private void serverAdded(Server server) {
|
||||
if (server != null) {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.DONE, null);
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
|
||||
saveCurrentState();
|
||||
|
||||
fab.setImageResource(R.drawable.ic_check);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
fab.show();
|
||||
serverAction.done();
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
} else {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not add server");
|
||||
serverAction.error("Could not create Sync Server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,269 +0,0 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.DialogManager;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.fragments.UploadCredentialsFragment;
|
||||
import lu.circl.mispbump.fragments.UploadSettingsFragment;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
|
||||
public class UploadInfoActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_UPLOAD_INFO_UUID = "uploadInformationUuid";
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private UploadInformation uploadInformation;
|
||||
private ViewPagerAdapter viewPagerAdapter;
|
||||
|
||||
private FloatingActionButton fab;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload_information);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadInfoActivity.this);
|
||||
|
||||
// tint statusBar
|
||||
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
|
||||
// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
|
||||
parseExtra();
|
||||
initToolbar();
|
||||
initViewPager();
|
||||
initViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// refresh current uploadInformation
|
||||
if (uploadInformation != null) {
|
||||
uploadInformation = preferenceManager.getUploadInformation(uploadInformation.getUuid());
|
||||
initContent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
saveCurrentSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_upload_info, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete:
|
||||
DialogManager.deleteSyncInformationDialog(UploadInfoActivity.this, new DialogManager.IDialogFeedback() {
|
||||
@Override
|
||||
public void positive() {
|
||||
preferenceManager.removeUploadInformation(uploadInformation.getUuid());
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void negative() {
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
case android.R.id.home:
|
||||
saveCurrentSettings();
|
||||
finish();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
|
||||
UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO_UUID);
|
||||
uploadInformation = preferenceManager.getUploadInformation(currentUUID);
|
||||
|
||||
if (uploadInformation == null) {
|
||||
throw new RuntimeException("Could not find UploadInformation with UUID {" + currentUUID.toString() + "}");
|
||||
}
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
|
||||
TextView toolbarTitle = findViewById(R.id.toolbarTitle);
|
||||
toolbarTitle.setText(uploadInformation.getRemote().organisation.getName());
|
||||
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
|
||||
ab.setDisplayShowTitleEnabled(false);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void initViewPager() {
|
||||
ViewPager viewPager = findViewById(R.id.viewPager);
|
||||
TabLayout tabLayout = findViewById(R.id.tabLayout);
|
||||
|
||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), uploadInformation);
|
||||
viewPager.setAdapter(viewPagerAdapter);
|
||||
|
||||
viewPager.addOnPageChangeListener(onPageChangeListener());
|
||||
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// for the UploadActivity to have the latest settings of this UploadInfoObject
|
||||
saveCurrentSettings();
|
||||
|
||||
Intent i = new Intent(UploadInfoActivity.this, UploadActivity.class);
|
||||
i.putExtra(UploadActivity.EXTRA_UPLOAD_INFO, uploadInformation.getUuid());
|
||||
startActivity(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initContent() {
|
||||
switch (uploadInformation.getCurrentSyncStatus()) {
|
||||
case COMPLETE:
|
||||
|
||||
break;
|
||||
|
||||
case FAILURE:
|
||||
|
||||
break;
|
||||
|
||||
case PENDING:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCurrentSettings() {
|
||||
uploadInformation.setAllowSelfSigned(viewPagerAdapter.uploadSettingsFragment.getAllowSelfSigned());
|
||||
uploadInformation.setPull(viewPagerAdapter.uploadSettingsFragment.getPull());
|
||||
uploadInformation.setPush(viewPagerAdapter.uploadSettingsFragment.getPush());
|
||||
uploadInformation.setCached(viewPagerAdapter.uploadSettingsFragment.getCache());
|
||||
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
}
|
||||
|
||||
|
||||
private ViewPager.OnPageChangeListener onPageChangeListener() {
|
||||
return new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (position == 0) {
|
||||
float scale = (1 - positionOffset);
|
||||
fab.setScaleX(scale);
|
||||
fab.setScaleY(scale);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class ViewPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
private UploadSettingsFragment uploadSettingsFragment;
|
||||
private UploadCredentialsFragment uploadCredentialsFragment;
|
||||
|
||||
ViewPagerAdapter(@NonNull FragmentManager fm, UploadInformation uploadInformation) {
|
||||
super(fm, ViewPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
uploadSettingsFragment = new UploadSettingsFragment(uploadInformation);
|
||||
uploadCredentialsFragment = new UploadCredentialsFragment(uploadInformation);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return uploadSettingsFragment;
|
||||
|
||||
case 1:
|
||||
return uploadCredentialsFragment;
|
||||
|
||||
default:
|
||||
uploadSettingsFragment = new UploadSettingsFragment();
|
||||
return uploadSettingsFragment;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return getString(R.string.settings);
|
||||
|
||||
case 1:
|
||||
return getString(R.string.credentials);
|
||||
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package lu.circl.mispbump.adapters;
|
||||
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
|
||||
|
||||
public class SyncInfoAdapter extends RecyclerView.Adapter<SyncInfoAdapter.ViewHolder> {
|
||||
|
||||
private List<SyncInformation> items;
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener;
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SyncInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
|
||||
return new SyncInfoAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final SyncInfoAdapter.ViewHolder holder, final int position) {
|
||||
final SyncInformation item = items.get(position);
|
||||
|
||||
SimpleDateFormat monthFormatter = new SimpleDateFormat("MMM", Locale.getDefault());
|
||||
SimpleDateFormat dayFormatter = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
|
||||
holder.dateMonth.setText(monthFormatter.format(item.getSyncDate()));
|
||||
holder.dateDay.setText(dayFormatter.format(item.getSyncDate()));
|
||||
|
||||
holder.orgName.setText(item.getRemote().getOrganisation().getName());
|
||||
|
||||
// switch (item.getCurrentSyncStatus()) {
|
||||
// case COMPLETE:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
|
||||
// break;
|
||||
// case FAILURE:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||
// break;
|
||||
// case PENDING:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_pending);
|
||||
// break;
|
||||
// }
|
||||
|
||||
holder.rootView.setOnClickListener(view -> onRecyclerPositionClickListener.onClick(view, position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (items == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return items.size();
|
||||
}
|
||||
|
||||
|
||||
public void setItems(List<SyncInformation> items) {
|
||||
this.items = items;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener) {
|
||||
this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
|
||||
}
|
||||
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
View rootView;
|
||||
ImageView syncStatus;
|
||||
TextView orgName, dateMonth, dateDay;
|
||||
|
||||
ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
rootView = itemView;
|
||||
|
||||
orgName = itemView.findViewById(R.id.orgName);
|
||||
|
||||
dateMonth = itemView.findViewById(R.id.date_month);
|
||||
dateDay = itemView.findViewById(R.id.date_day);
|
||||
|
||||
syncStatus = itemView.findViewById(R.id.syncStatus);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
package lu.circl.mispbump.adapters;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
|
||||
public class UploadInfoAdapter extends RecyclerView.Adapter<UploadInfoAdapter.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<UploadInformation> items;
|
||||
|
||||
private OnRecyclerItemClickListener<UploadInformation> onRecyclerItemClickListener;
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener;
|
||||
|
||||
|
||||
public UploadInfoAdapter(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UploadInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
|
||||
return new UploadInfoAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final UploadInfoAdapter.ViewHolder holder, final int position) {
|
||||
|
||||
final UploadInformation item = items.get(position);
|
||||
|
||||
holder.date.setText(item.getDateString());
|
||||
holder.orgName.setText(item.getRemote().organisation.getName());
|
||||
|
||||
switch (item.getCurrentSyncStatus()) {
|
||||
case COMPLETE:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
|
||||
break;
|
||||
case FAILURE:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||
break;
|
||||
case PENDING:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_pending);
|
||||
break;
|
||||
}
|
||||
|
||||
holder.rootView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onRecyclerItemClickListener.onClick(view, item);
|
||||
}
|
||||
});
|
||||
|
||||
holder.rootView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onRecyclerPositionClickListener.onClick(view, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
|
||||
public void setItems(List<UploadInformation> items) {
|
||||
this.items = items;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
// callbacks
|
||||
|
||||
public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener<UploadInformation> onRecyclerItemClickListener) {
|
||||
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
|
||||
}
|
||||
|
||||
public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener) {
|
||||
this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
|
||||
}
|
||||
|
||||
// viewHolder
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
View rootView;
|
||||
ImageView syncStatus;
|
||||
TextView orgName, date;
|
||||
|
||||
ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
rootView = itemView;
|
||||
orgName = itemView.findViewById(R.id.orgName);
|
||||
date = itemView.findViewById(R.id.date);
|
||||
syncStatus = itemView.findViewById(R.id.syncStatus);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,11 +27,11 @@ public class DialogManager {
|
|||
// this dialog needs definite user feedback
|
||||
adb.setCancelable(false);
|
||||
|
||||
if (oldSync.organisation.getName().equals(newSync.organisation.getName())) {
|
||||
adb.setTitle("Already Synced with " + oldSync.organisation.getName());
|
||||
} else {
|
||||
adb.setTitle("Already Synced with " + oldSync.organisation.getName() + "(Now:" + newSync.organisation.getName() + ")");
|
||||
}
|
||||
// if (oldSync.organisation.getName().equals(newSync.organisation.getName())) {
|
||||
// adb.setTitle("Already Synced with " + oldSync.organisation.getName());
|
||||
// } else {
|
||||
// adb.setTitle("Already Synced with " + oldSync.organisation.getName() + "(Now:" + newSync.organisation.getName() + ")");
|
||||
// }
|
||||
|
||||
adb.setMessage("");
|
||||
|
||||
|
@ -143,33 +143,22 @@ public class DialogManager {
|
|||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||
|
||||
adb.setTitle("Sync information received");
|
||||
adb.setMessage(syncInformation.organisation.getName());
|
||||
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
adb.setMessage(syncInformation.getRemote().getOrganisation().getName());
|
||||
adb.setPositiveButton("Accept", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Reject", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
adb.setNegativeButton("Reject", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -183,31 +172,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("Continue?");
|
||||
adb.setMessage("Only continue if your partner already scanned this QR code");
|
||||
adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
adb.setPositiveButton("Continue", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Show QR code again", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
adb.setNegativeButton("Show QR code again", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,21 +196,11 @@ public class DialogManager {
|
|||
public static void loginHelpDialog(Context context) {
|
||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||
adb.setMessage(R.string.login_help_text);
|
||||
adb.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
adb.setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
Activity act = (Activity) context;
|
||||
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
public static void instanceNotAvailableDialog(Context context, final IDialogFeedback callback) {
|
||||
|
@ -240,31 +208,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("MISP not available");
|
||||
adb.setMessage("Your MISP instance is not available. Would you like to save?");
|
||||
adb.setPositiveButton("Retry now", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
adb.setPositiveButton("Retry now", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Save & retry later", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
adb.setNegativeButton("Save & retry later", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
public static void deleteSyncInformationDialog(Context context, final IDialogFeedback callback) {
|
||||
|
@ -272,31 +229,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("Delete Sync Information?");
|
||||
adb.setMessage("This sync information will be deleted permanently");
|
||||
adb.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
adb.setPositiveButton("Delete", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
adb.setNegativeButton("Discard", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -307,6 +253,4 @@ public class DialogManager {
|
|||
|
||||
void negative();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -5,20 +5,17 @@ import android.annotation.SuppressLint;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import lu.circl.mispbump.interfaces.MispRestInterface;
|
||||
import lu.circl.mispbump.interfaces.MispService;
|
||||
import lu.circl.mispbump.models.restModels.MispOrganisation;
|
||||
import lu.circl.mispbump.models.restModels.MispRole;
|
||||
import lu.circl.mispbump.models.restModels.MispServer;
|
||||
|
@ -28,7 +25,6 @@ import lu.circl.mispbump.models.restModels.Role;
|
|||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
import lu.circl.mispbump.models.restModels.Version;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
@ -47,7 +43,7 @@ public class MispRestClient {
|
|||
|
||||
|
||||
private static MispRestClient instance;
|
||||
private MispRestInterface mispRestInterface;
|
||||
private MispService mispService;
|
||||
|
||||
public static MispRestClient getInstance(String url, String authkey) {
|
||||
if (instance == null) {
|
||||
|
@ -67,13 +63,18 @@ public class MispRestClient {
|
|||
.client(getCustomClient(true, true, authkey))
|
||||
.build();
|
||||
|
||||
mispRestInterface = retrofit.create(MispRestInterface.class);
|
||||
mispService = retrofit.create(MispService.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public MispService getService() {
|
||||
return mispService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param unsafe whether to accept all certificates or only trusted ones
|
||||
* @param logging whether to log Retrofit calls (for debugging)
|
||||
|
@ -90,12 +91,14 @@ public class MispRestClient {
|
|||
new X509TrustManager() {
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
@Override
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
@Override
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,12 +116,7 @@ public class MispRestClient {
|
|||
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
|
||||
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
|
||||
builder.hostnameVerifier(new HostnameVerifier() {
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
builder.hostnameVerifier((hostname, session) -> true);
|
||||
}
|
||||
|
||||
if (logging) {
|
||||
|
@ -127,16 +125,13 @@ public class MispRestClient {
|
|||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// create authorization interceptor
|
||||
builder.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public okhttp3.Response intercept(Chain chain) throws IOException {
|
||||
Request.Builder ongoing = chain.request().newBuilder();
|
||||
ongoing.addHeader("Accept", "application/json");
|
||||
ongoing.addHeader("Content-Type", "application/json");
|
||||
ongoing.addHeader("Authorization", authkey);
|
||||
return chain.proceed(ongoing.build());
|
||||
}
|
||||
// create interceptor
|
||||
builder.addInterceptor(chain -> {
|
||||
Request.Builder ongoing = chain.request().newBuilder();
|
||||
ongoing.addHeader("Accept", "application/json");
|
||||
ongoing.addHeader("Content-Type", "application/json");
|
||||
ongoing.addHeader("Authorization", authkey);
|
||||
return chain.proceed(ongoing.build());
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
|
@ -153,7 +148,7 @@ public class MispRestClient {
|
|||
* @param callback {@link AvailableCallback}
|
||||
*/
|
||||
public void isAvailable(final AvailableCallback callback) {
|
||||
Call<Version> call = mispRestInterface.pyMispVersion();
|
||||
Call<Version> call = mispService.pyMispVersion();
|
||||
call.enqueue(new Callback<Version>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Version> call, @NonNull Response<Version> response) {
|
||||
|
@ -177,10 +172,10 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
public void getRoles(final AllRolesCallback callback) {
|
||||
Call<List<MispRole>> call = mispRestInterface.getRoles();
|
||||
Call<List<MispRole>> call = mispService.getRoles();
|
||||
call.enqueue(new Callback<List<MispRole>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<MispRole>> call, Response<List<MispRole>> response) {
|
||||
public void onResponse(@NonNull Call<List<MispRole>> call, @NonNull Response<List<MispRole>> response) {
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
|
@ -200,7 +195,7 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<MispRole>> call, Throwable t) {
|
||||
public void onFailure(@NonNull Call<List<MispRole>> call, @NonNull Throwable t) {
|
||||
callback.failure(extractError(t));
|
||||
}
|
||||
});
|
||||
|
@ -213,7 +208,7 @@ public class MispRestClient {
|
|||
* @param callback {@link UserCallback} wrapper to return user directly
|
||||
*/
|
||||
public void getMyUser(final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.getMyUserInformation();
|
||||
Call<MispUser> call = mispService.getMyUserInformation();
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -222,7 +217,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
if (response.body() != null) {
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
} else {
|
||||
callback.failure("response body was null");
|
||||
}
|
||||
|
@ -243,9 +238,8 @@ public class MispRestClient {
|
|||
* @param userId user identifier
|
||||
* @param callback {@link UserCallback} wrapper to return user directly
|
||||
*/
|
||||
|
||||
public void getUser(int userId, final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.getUser(userId);
|
||||
Call<MispUser> call = mispService.getUser(userId);
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -254,7 +248,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
if (response.body() != null) {
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
} else {
|
||||
callback.failure("response body was null");
|
||||
}
|
||||
|
@ -274,7 +268,7 @@ public class MispRestClient {
|
|||
@Override
|
||||
public void success(User[] users) {
|
||||
for (User user : users) {
|
||||
if (user.email.equals(emailAddress)) {
|
||||
if (user.getEmail().equals(emailAddress)) {
|
||||
callback.success(user);
|
||||
return;
|
||||
}
|
||||
|
@ -290,8 +284,29 @@ public class MispRestClient {
|
|||
});
|
||||
}
|
||||
|
||||
public void getAllUsers(final AllMispUsersCallback callback) {
|
||||
Call<List<MispUser>> call = mispService.getAllUsers();
|
||||
|
||||
call.enqueue(new Callback<List<MispUser>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List<MispUser>> call, @NonNull Response<List<MispUser>> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure("Failed onResponse");
|
||||
return;
|
||||
}
|
||||
|
||||
callback.success(response.body());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<MispUser>> call, @NonNull Throwable t) {
|
||||
callback.failure(extractError(t));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getAllUsers(final AllUsersCallback callback) {
|
||||
Call<List<MispUser>> call = mispRestInterface.getAllUsers();
|
||||
Call<List<MispUser>> call = mispService.getAllUsers();
|
||||
|
||||
call.enqueue(new Callback<List<MispUser>>() {
|
||||
@Override
|
||||
|
@ -307,7 +322,7 @@ public class MispRestClient {
|
|||
User[] users = new User[mispUsers.size()];
|
||||
|
||||
for (int i = 0; i < users.length; i++) {
|
||||
users[i] = mispUsers.get(i).user;
|
||||
users[i] = mispUsers.get(i).getUser();
|
||||
}
|
||||
|
||||
callback.success(users);
|
||||
|
@ -327,7 +342,7 @@ public class MispRestClient {
|
|||
* @param callback {@link UserCallback} wrapper to return the created user directly
|
||||
*/
|
||||
public void addUser(User user, final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.addUser(user);
|
||||
Call<MispUser> call = mispService.addUser(user);
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -336,7 +351,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
assert response.body() != null;
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -357,7 +372,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
|
||||
*/
|
||||
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
||||
Call<MispOrganisation> call = mispRestInterface.getOrganisation(orgId);
|
||||
Call<MispOrganisation> call = mispService.getOrganisation(orgId);
|
||||
|
||||
call.enqueue(new Callback<MispOrganisation>() {
|
||||
@Override
|
||||
|
@ -402,7 +417,7 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
public void getAllOrganisations(final AllOrganisationsCallback callback) {
|
||||
Call<List<MispOrganisation>> call = mispRestInterface.getAllOrganisations();
|
||||
Call<List<MispOrganisation>> call = mispService.getAllOrganisations();
|
||||
|
||||
call.enqueue(new Callback<List<MispOrganisation>>() {
|
||||
@Override
|
||||
|
@ -438,7 +453,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
|
||||
*/
|
||||
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
||||
Call<MispOrganisation> call = mispRestInterface.addOrganisation(organisation);
|
||||
Call<MispOrganisation> call = mispService.addOrganisation(organisation);
|
||||
|
||||
call.enqueue(new Callback<MispOrganisation>() {
|
||||
@Override
|
||||
|
@ -466,7 +481,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
|
||||
*/
|
||||
public void getAllServers(final AllServersCallback callback) {
|
||||
Call<List<MispServer>> call = mispRestInterface.getAllServers();
|
||||
Call<List<MispServer>> call = mispService.getAllServers();
|
||||
|
||||
call.enqueue(new Callback<List<MispServer>>() {
|
||||
@Override
|
||||
|
@ -474,16 +489,14 @@ public class MispRestClient {
|
|||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
} else {
|
||||
|
||||
List<MispServer> mispServers = response.body();
|
||||
assert mispServers != null;
|
||||
|
||||
Server[] servers = new Server[mispServers.size()];
|
||||
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
servers[i] = mispServers.get(i).server;
|
||||
servers[i] = mispServers.get(i).getServer();
|
||||
}
|
||||
|
||||
callback.success(servers);
|
||||
}
|
||||
}
|
||||
|
@ -495,6 +508,26 @@ public class MispRestClient {
|
|||
});
|
||||
}
|
||||
|
||||
public void getAllServers(final AllRawServersCallback callback) {
|
||||
Call<List<MispServer>> call = mispService.getAllServers();
|
||||
|
||||
call.enqueue(new Callback<List<MispServer>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List<MispServer>> call, @NonNull Response<List<MispServer>> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
} else {
|
||||
callback.success(response.body());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<MispServer>> call, @NonNull Throwable t) {
|
||||
callback.failure(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a server to the MISP instance
|
||||
*
|
||||
|
@ -502,7 +535,7 @@ public class MispRestClient {
|
|||
* @param callback {@link ServerCallback} wrapper to return the created server directly
|
||||
*/
|
||||
public void addServer(Server server, final ServerCallback callback) {
|
||||
Call<Server> call = mispRestInterface.addServer(server);
|
||||
Call<Server> call = mispService.addServer(server);
|
||||
|
||||
call.enqueue(new Callback<Server>() {
|
||||
@Override
|
||||
|
@ -588,7 +621,6 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
// interfaces
|
||||
|
||||
public interface AvailableCallback {
|
||||
void available();
|
||||
|
||||
|
@ -607,6 +639,12 @@ public class MispRestClient {
|
|||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllMispUsersCallback {
|
||||
void success(List<MispUser> users);
|
||||
|
||||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface OrganisationCallback {
|
||||
void success(Organisation organisation);
|
||||
|
||||
|
@ -631,6 +669,12 @@ public class MispRestClient {
|
|||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllRawServersCallback {
|
||||
void success(List<MispServer> mispServers);
|
||||
|
||||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllRolesCallback {
|
||||
void success(Role[] roles);
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ import javax.crypto.BadPaddingException;
|
|||
import javax.crypto.IllegalBlockSizeException;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
@ -36,7 +36,7 @@ public class PreferenceManager {
|
|||
private static final String USER_INFOS = "user_infos";
|
||||
private static final String USER_ORG_INFOS = "user_org_infos";
|
||||
|
||||
private static final String UPLOAD_INFO = "upload_info";
|
||||
private static final String SYNC_INFO = "sync_info";
|
||||
|
||||
private static final String MISP_ROLES = "misp_roles";
|
||||
|
||||
|
@ -83,10 +83,10 @@ public class PreferenceManager {
|
|||
public Role[] getRoles() {
|
||||
Type type = new TypeToken<Role[]>() {
|
||||
}.getType();
|
||||
String rolesString = preferences.getString(MISP_ROLES, "");
|
||||
|
||||
assert rolesString != null;
|
||||
if (rolesString.isEmpty()) {
|
||||
String rolesString = preferences.getString(MISP_ROLES, null);
|
||||
|
||||
if (rolesString == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new Gson().fromJson(rolesString, type);
|
||||
|
@ -99,23 +99,13 @@ public class PreferenceManager {
|
|||
*
|
||||
* @param user {@link User}
|
||||
*/
|
||||
public void setUserInfo(User user) {
|
||||
public void setMyUser(User user) {
|
||||
try {
|
||||
String userStr = new Gson().toJson(user);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
||||
String encryptedUserInfo = keyStoreWrapper.encrypt(userStr);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(USER_INFOS, encryptedUserInfo);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
||||
editor.putString(USER_INFOS, keyStoreWrapper.encrypt(new Gson().toJson(user)));
|
||||
editor.apply();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
} catch (BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -135,17 +125,7 @@ public class PreferenceManager {
|
|||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
||||
String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_INFOS, ""));
|
||||
return new Gson().fromJson(decrypted, User.class);
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidAlgorithmParameterException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
} catch (BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
@ -158,7 +138,7 @@ public class PreferenceManager {
|
|||
*
|
||||
* @param organisation Object representation of json organisation information
|
||||
*/
|
||||
public void setUserOrgInfo(Organisation organisation) {
|
||||
public void setMyOrganisation(Organisation organisation) {
|
||||
try {
|
||||
String orgStr = new Gson().toJson(organisation);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
|
||||
|
@ -243,58 +223,57 @@ public class PreferenceManager {
|
|||
}
|
||||
|
||||
|
||||
private List<UploadInformation> cachedUploadInformationList;
|
||||
private List<SyncInformation> cachedSyncInformationList;
|
||||
|
||||
private void loadUploadInformationList() {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
|
||||
private void loadSyncInformationList() {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
|
||||
String storedSyncInfoString = preferences.getString(SYNC_INFO, null);
|
||||
|
||||
Type type = new TypeToken<List<UploadInformation>>() {
|
||||
}.getType();
|
||||
Type type = new TypeToken<List<SyncInformation>>() {}.getType();
|
||||
|
||||
if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
|
||||
cachedUploadInformationList = new ArrayList<>();
|
||||
if (storedSyncInfoString == null || storedSyncInfoString.isEmpty()) {
|
||||
cachedSyncInformationList = new ArrayList<>();
|
||||
} else {
|
||||
try {
|
||||
storedUploadInfoString = ksw.decrypt(storedUploadInfoString);
|
||||
cachedUploadInformationList = new Gson().fromJson(storedUploadInfoString, type);
|
||||
storedSyncInfoString = ksw.decrypt(storedSyncInfoString);
|
||||
cachedSyncInformationList = new Gson().fromJson(storedSyncInfoString, type);
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveUploadInformationList() {
|
||||
private void saveSyncInformationList() {
|
||||
try {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||
String cipherText = ksw.encrypt(new Gson().toJson(cachedUploadInformationList));
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
|
||||
String cipherText = ksw.encrypt(new Gson().toJson(cachedSyncInformationList));
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(UPLOAD_INFO, cipherText);
|
||||
editor.putString(SYNC_INFO, cipherText);
|
||||
editor.apply();
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public List<UploadInformation> getUploadInformationList() {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
public List<SyncInformation> getSyncInformationList() {
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
return cachedUploadInformationList;
|
||||
return cachedSyncInformationList;
|
||||
}
|
||||
|
||||
public void setUploadInformationList(List<UploadInformation> uploadInformationList) {
|
||||
cachedUploadInformationList = uploadInformationList;
|
||||
saveUploadInformationList();
|
||||
public void setSyncInformationList(List<SyncInformation> uploadInformationList) {
|
||||
cachedSyncInformationList = uploadInformationList;
|
||||
saveSyncInformationList();
|
||||
}
|
||||
|
||||
public UploadInformation getUploadInformation(UUID uuid) {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
public SyncInformation getSyncInformation(UUID uuid) {
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
for (UploadInformation ui : cachedUploadInformationList) {
|
||||
for (SyncInformation ui : cachedSyncInformationList) {
|
||||
if (ui.getUuid().compareTo(uuid) == 0) {
|
||||
return ui;
|
||||
}
|
||||
|
@ -303,51 +282,50 @@ public class PreferenceManager {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void addUploadInformation(UploadInformation uploadInformation) {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
public void addSyncInformation(SyncInformation syncInformation) {
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
// update if exists
|
||||
for (int i = 0; i < cachedUploadInformationList.size(); i++) {
|
||||
if (cachedUploadInformationList.get(i).getUuid().compareTo(uploadInformation.getUuid()) == 0) {
|
||||
cachedUploadInformationList.set(i, uploadInformation);
|
||||
saveUploadInformationList();
|
||||
for (int i = 0; i < cachedSyncInformationList.size(); i++) {
|
||||
if (cachedSyncInformationList.get(i).getUuid().compareTo(syncInformation.getUuid()) == 0) {
|
||||
cachedSyncInformationList.set(i, syncInformation);
|
||||
saveSyncInformationList();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// else: add
|
||||
cachedUploadInformationList.add(uploadInformation);
|
||||
saveUploadInformationList();
|
||||
cachedSyncInformationList.add(syncInformation);
|
||||
saveSyncInformationList();
|
||||
}
|
||||
|
||||
public void removeUploadInformation(UUID uuid) {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
for (UploadInformation ui : cachedUploadInformationList) {
|
||||
for (SyncInformation ui : cachedSyncInformationList) {
|
||||
if (ui.getUuid().compareTo(uuid) == 0) {
|
||||
// if is last element, then clear everything including IV and key in KeyStore
|
||||
if (cachedUploadInformationList.size() == 1) {
|
||||
if (cachedSyncInformationList.size() == 1) {
|
||||
clearUploadInformation();
|
||||
} else {
|
||||
cachedUploadInformationList.remove(ui);
|
||||
saveUploadInformationList();
|
||||
cachedSyncInformationList.remove(ui);
|
||||
saveSyncInformationList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearUploadInformation() {
|
||||
cachedUploadInformationList.clear();
|
||||
cachedSyncInformationList.clear();
|
||||
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
|
||||
keyStoreWrapper.deleteStoredKey();
|
||||
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.remove(UPLOAD_INFO);
|
||||
editor.remove(SYNC_INFO);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import lu.circl.mispbump.R;
|
|||
public class MaterialPasswordView extends ConstraintLayout {
|
||||
|
||||
private TextView titleView, passwordView;
|
||||
private OnCopyClickListener onCopyClickListener;
|
||||
|
||||
|
||||
public MaterialPasswordView(Context context, AttributeSet attrs) {
|
||||
|
@ -31,14 +30,6 @@ public class MaterialPasswordView extends ConstraintLayout {
|
|||
final String password = a.getString(R.styleable.MaterialPasswordView_password);
|
||||
a.recycle();
|
||||
|
||||
ImageButton copyButton = view.findViewById(R.id.copy);
|
||||
copyButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onCopyClickListener.onClick(title, getPassword());
|
||||
}
|
||||
});
|
||||
|
||||
titleView = view.findViewById(R.id.material_password_title);
|
||||
titleView.setText(title);
|
||||
|
||||
|
@ -47,14 +38,11 @@ public class MaterialPasswordView extends ConstraintLayout {
|
|||
passwordView.setText(password);
|
||||
|
||||
ImageButton visibleToggle = findViewById(R.id.visibleToggle);
|
||||
visibleToggle.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (passwordView.getTransformationMethod() == null) {
|
||||
passwordView.setTransformationMethod(new PasswordTransformationMethod());
|
||||
} else {
|
||||
passwordView.setTransformationMethod(null);
|
||||
}
|
||||
visibleToggle.setOnClickListener(v -> {
|
||||
if (passwordView.getTransformationMethod() == null) {
|
||||
passwordView.setTransformationMethod(new PasswordTransformationMethod());
|
||||
} else {
|
||||
passwordView.setTransformationMethod(null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -84,13 +72,4 @@ public class MaterialPasswordView extends ConstraintLayout {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void addOnCopyClickedListener(OnCopyClickListener listener) {
|
||||
onCopyClickListener = listener;
|
||||
}
|
||||
|
||||
|
||||
public interface OnCopyClickListener {
|
||||
void onClick(String title, String password);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
|
||||
public class ProgressActionView extends LinearLayout {
|
||||
|
||||
private Context context;
|
||||
|
||||
private ImageView icon;
|
||||
private ProgressBar progressBar;
|
||||
private TextView title, feedback;
|
||||
|
||||
private Drawable pendingIcon, doneIcon, errorIcon;
|
||||
|
||||
public ProgressActionView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
public ProgressActionView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
public ProgressActionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
public ProgressActionView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
this.context = context;
|
||||
initViews(attrs);
|
||||
}
|
||||
|
||||
|
||||
private void initViews(AttributeSet attrs) {
|
||||
View v = LayoutInflater.from(context).inflate(R.layout.view_upload_action, this, true);
|
||||
|
||||
icon = v.findViewById(R.id.progressIcon);
|
||||
progressBar = v.findViewById(R.id.progressBar);
|
||||
title = v.findViewById(R.id.title);
|
||||
feedback = v.findViewById(R.id.error);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProgressActionView);
|
||||
title.setText(a.getString(R.styleable.ProgressActionView_action_title));
|
||||
pendingIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_pending_icon, 0));
|
||||
doneIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_done_icon, 0));
|
||||
errorIcon = context.getDrawable(a.getResourceId(R.styleable.ProgressActionView_action_error_icon, 0));
|
||||
a.recycle();
|
||||
|
||||
pendingIcon.setTint(context.getColor(R.color.status_amber));
|
||||
doneIcon.setTint(context.getColor(R.color.status_green));
|
||||
errorIcon.setTint(context.getColor(R.color.status_red));
|
||||
|
||||
pending();
|
||||
icon.setImageTintList(ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
}
|
||||
|
||||
|
||||
public void pending() {
|
||||
progressBar.setVisibility(GONE);
|
||||
switchIcon(pendingIcon, R.color.status_amber);
|
||||
icon.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
progressBar.setVisibility(VISIBLE);
|
||||
|
||||
icon.setVisibility(GONE);
|
||||
feedback.setVisibility(GONE);
|
||||
}
|
||||
|
||||
public void done() {
|
||||
done("");
|
||||
}
|
||||
|
||||
public void done(String message) {
|
||||
progressBar.setVisibility(GONE);
|
||||
|
||||
switchIcon(doneIcon, R.color.status_green);
|
||||
icon.setVisibility(VISIBLE);
|
||||
|
||||
if (message.isEmpty()) {
|
||||
feedback.setVisibility(GONE);
|
||||
} else {
|
||||
feedback.setTextColor(context.getColor(R.color.status_amber));
|
||||
feedback.setText(message);
|
||||
feedback.setVisibility(VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
public void error(String error) {
|
||||
progressBar.setVisibility(GONE);
|
||||
|
||||
switchIcon(errorIcon, R.color.status_red);
|
||||
icon.setVisibility(VISIBLE);
|
||||
|
||||
feedback.setTextColor(context.getColor(R.color.status_red));
|
||||
feedback.setText(error);
|
||||
feedback.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
public void info(String info) {
|
||||
progressBar.setVisibility(GONE);
|
||||
|
||||
switchIcon(errorIcon, R.color.status_amber);
|
||||
icon.setVisibility(VISIBLE);
|
||||
|
||||
this.feedback.setTextColor(context.getColor(R.color.status_amber));
|
||||
this.feedback.setText(info);
|
||||
this.feedback.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
private void switchIcon(Drawable d, int color) {
|
||||
icon.setImageDrawable(d);
|
||||
icon.setImageTintList(ColorStateList.valueOf(context.getColor(color)));
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title.setText(title);
|
||||
}
|
||||
|
||||
public void setErrorIconDrawable(Drawable d) {
|
||||
errorIcon = d;
|
||||
}
|
||||
|
||||
public void setPendingIconDrawable(Drawable d) {
|
||||
pendingIcon = d;
|
||||
}
|
||||
|
||||
public void setDoneIconDrawable(Drawable d) {
|
||||
doneIcon = d;
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ package lu.circl.mispbump.customViews;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -45,15 +44,15 @@ public class UploadAction extends ConstraintLayout {
|
|||
|
||||
View baseView = LayoutInflater.from(context).inflate(R.layout.view_upload_action, this);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);
|
||||
// TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.UploadAction);
|
||||
//
|
||||
// titleView = baseView.findViewById(R.id.title);
|
||||
// titleView.setText(a.getString(R.styleable.UploadAction_description));
|
||||
|
||||
titleView = baseView.findViewById(R.id.title);
|
||||
titleView.setText(a.getString(R.styleable.UploadAction_description));
|
||||
|
||||
a.recycle();
|
||||
// a.recycle();
|
||||
|
||||
errorView = baseView.findViewById(R.id.error);
|
||||
stateView = baseView.findViewById(R.id.stateView);
|
||||
stateView = baseView.findViewById(R.id.progressIcon);
|
||||
progressBar = baseView.findViewById(R.id.progressBar);
|
||||
|
||||
setCurrentUploadState(UploadState.PENDING);
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.customViews.MaterialPasswordView;
|
||||
import lu.circl.mispbump.customViews.MaterialPreferenceText;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
|
||||
public class UploadCredentialsFragment extends Fragment {
|
||||
|
||||
private View rootLayout;
|
||||
private UploadInformation uploadInformation;
|
||||
|
||||
public UploadCredentialsFragment() {
|
||||
}
|
||||
|
||||
public UploadCredentialsFragment(UploadInformation uploadInformation) {
|
||||
this.uploadInformation = uploadInformation;
|
||||
}
|
||||
|
||||
private MaterialPasswordView.OnCopyClickListener onCopyClickListener = new MaterialPasswordView.OnCopyClickListener() {
|
||||
@Override
|
||||
public void onClick(String title, String password) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(title, password);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Snackbar.make(rootLayout, "Copied to clipboard", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_upload_credentials, container, false);
|
||||
|
||||
rootLayout = v.findViewById(R.id.rootLayout);
|
||||
|
||||
MaterialPreferenceText baseUrl = v.findViewById(R.id.baseUrl);
|
||||
baseUrl.setSubtitle(uploadInformation.getRemote().baseUrl);
|
||||
|
||||
MaterialPreferenceText email = v.findViewById(R.id.email);
|
||||
email.setSubtitle(uploadInformation.getLocal().syncUserEmail);
|
||||
|
||||
MaterialPasswordView authkey = v.findViewById(R.id.authkey);
|
||||
authkey.setPassword(uploadInformation.getRemote().syncUserAuthkey);
|
||||
authkey.addOnCopyClickedListener(onCopyClickListener);
|
||||
|
||||
MaterialPasswordView password = v.findViewById(R.id.password);
|
||||
password.setPassword(uploadInformation.getRemote().syncUserPassword);
|
||||
password.addOnCopyClickedListener(onCopyClickListener);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.customViews.MaterialPreferenceSwitch;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
|
||||
public class UploadSettingsFragment extends Fragment {
|
||||
|
||||
private MaterialPreferenceSwitch allowSelfSigned, push, pull, cache;
|
||||
private UploadInformation uploadInformation;
|
||||
|
||||
public UploadSettingsFragment() {
|
||||
}
|
||||
|
||||
public UploadSettingsFragment(UploadInformation uploadInformation) {
|
||||
this.uploadInformation = uploadInformation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_upload_settings, container, false);
|
||||
|
||||
allowSelfSigned = v.findViewById(R.id.self_signed_switch);
|
||||
push = v.findViewById(R.id.push_switch);
|
||||
pull = v.findViewById(R.id.pull_switch);
|
||||
cache = v.findViewById(R.id.cache_switch);
|
||||
|
||||
populateContent();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
private void populateContent() {
|
||||
if (uploadInformation == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
allowSelfSigned.setChecked(uploadInformation.isAllowSelfSigned());
|
||||
push.setChecked(uploadInformation.isPush());
|
||||
pull.setChecked(uploadInformation.isPull());
|
||||
cache.setChecked(uploadInformation.isCached());
|
||||
}
|
||||
|
||||
public void setUploadInfo(UploadInformation uploadInfo) {
|
||||
this.uploadInformation = uploadInfo;
|
||||
}
|
||||
|
||||
public boolean getAllowSelfSigned() {
|
||||
return allowSelfSigned.isChecked();
|
||||
}
|
||||
|
||||
public void setAllowSelfSigned(boolean allowSelfSigned) {
|
||||
this.allowSelfSigned.setChecked(allowSelfSigned);
|
||||
}
|
||||
|
||||
public boolean getPush() {
|
||||
return push.isChecked();
|
||||
}
|
||||
|
||||
public void setPush(boolean push) {
|
||||
this.push.setChecked(push);
|
||||
}
|
||||
|
||||
public boolean getPull() {
|
||||
return pull.isChecked();
|
||||
}
|
||||
|
||||
public void setPull(boolean pull) {
|
||||
this.pull.setChecked(pull);
|
||||
}
|
||||
|
||||
public boolean getCache() {
|
||||
return cache.isChecked();
|
||||
}
|
||||
|
||||
public void setCache(boolean cache) {
|
||||
this.cache.setChecked(cache);
|
||||
}
|
||||
}
|
|
@ -21,7 +21,7 @@ import retrofit2.http.Path;
|
|||
/**
|
||||
* RetroFit2 interface for communication with misp instances
|
||||
*/
|
||||
public interface MispRestInterface {
|
||||
public interface MispService {
|
||||
|
||||
// settings routes
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class ExchangeInformation {
|
||||
|
||||
private Organisation organisation;
|
||||
private User syncUser;
|
||||
private Server server;
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
public User getSyncUser() {
|
||||
return syncUser;
|
||||
}
|
||||
public void setSyncUser(User syncUser) {
|
||||
this.syncUser = syncUser;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Exchange Information: \n" + organisation.toString() + "\n" + syncUser.toString() + "\n" + server.toString();
|
||||
}
|
||||
}
|
|
@ -1,32 +1,88 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* A Class that holds the information needed synchronize two misp instances.
|
||||
* This class can be serialized and passed via QR code.
|
||||
* Class that holds the information needed synchronize two misp instances.
|
||||
*/
|
||||
public class SyncInformation {
|
||||
|
||||
public Organisation organisation;
|
||||
public String syncUserEmail;
|
||||
public String syncUserPassword;
|
||||
public String syncUserAuthkey;
|
||||
public String baseUrl;
|
||||
private UUID uuid;
|
||||
private Date date, lastModified;
|
||||
|
||||
private ExchangeInformation remote;
|
||||
private ExchangeInformation local;
|
||||
|
||||
|
||||
public SyncInformation() {
|
||||
uuid = UUID.randomUUID();
|
||||
setSyncDate();
|
||||
}
|
||||
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public Date getLastModified() {
|
||||
return lastModified;
|
||||
}
|
||||
public void setLastModified() {
|
||||
setLastModified(Calendar.getInstance().getTime());
|
||||
}
|
||||
public void setLastModified(Date date) {
|
||||
lastModified = date;
|
||||
}
|
||||
|
||||
public void setSyncDate() {
|
||||
setSyncDate(Calendar.getInstance().getTime());
|
||||
}
|
||||
public void setSyncDate(Date date) {
|
||||
this.date = date;
|
||||
this.lastModified = date;
|
||||
}
|
||||
public Date getSyncDate() {
|
||||
return date;
|
||||
}
|
||||
private String getSyncDateString() {
|
||||
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
|
||||
public ExchangeInformation getRemote() {
|
||||
return remote;
|
||||
}
|
||||
public void setRemote(ExchangeInformation remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
public ExchangeInformation getLocal() {
|
||||
return local;
|
||||
}
|
||||
public void setLocal(ExchangeInformation local) {
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SyncInformation{" +
|
||||
"organisation=" + organisation +
|
||||
", syncUserEmail='" + syncUserEmail + '\'' +
|
||||
", syncUserPassword='" + syncUserPassword + '\'' +
|
||||
", syncUserAuthkey='" + syncUserAuthkey + '\'' +
|
||||
", baseUrl='" + baseUrl + '\'' +
|
||||
'}';
|
||||
return "Sync Information: \n" +
|
||||
"UUID = " + uuid + "\n" +
|
||||
"Sync Date = " + getSyncDateString() + "\n" +
|
||||
remote.toString() +
|
||||
local.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,130 +0,0 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
public class UploadInformation {
|
||||
|
||||
public enum SyncStatus {
|
||||
COMPLETE,
|
||||
FAILURE,
|
||||
PENDING
|
||||
}
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
private SyncStatus currentSyncStatus = SyncStatus.PENDING;
|
||||
|
||||
private boolean allowSelfSigned, pull, push, cached;
|
||||
|
||||
private SyncInformation local;
|
||||
private SyncInformation remote;
|
||||
|
||||
private Date date;
|
||||
|
||||
public UploadInformation() {
|
||||
uuid = UUID.randomUUID();
|
||||
date = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
// getter and setter
|
||||
|
||||
public void setCurrentSyncStatus(SyncStatus status) {
|
||||
currentSyncStatus = status;
|
||||
}
|
||||
|
||||
public SyncStatus getCurrentSyncStatus() {
|
||||
return currentSyncStatus;
|
||||
}
|
||||
|
||||
public void setLocal(SyncInformation local) {
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
public SyncInformation getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setRemote(SyncInformation remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
public SyncInformation getRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setDate() {
|
||||
setDate(Calendar.getInstance().getTime());
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public String getDateString() {
|
||||
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
public boolean isAllowSelfSigned() {
|
||||
return allowSelfSigned;
|
||||
}
|
||||
|
||||
public void setAllowSelfSigned(boolean allowSelfSigned) {
|
||||
this.allowSelfSigned = allowSelfSigned;
|
||||
}
|
||||
|
||||
public boolean isPull() {
|
||||
return pull;
|
||||
}
|
||||
|
||||
public void setPull(boolean pull) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
public boolean isPush() {
|
||||
return push;
|
||||
}
|
||||
|
||||
public void setPush(boolean push) {
|
||||
this.push = push;
|
||||
}
|
||||
|
||||
public boolean isCached() {
|
||||
return cached;
|
||||
}
|
||||
|
||||
public void setCached(boolean cached) {
|
||||
this.cached = cached;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UploadInformation{" +
|
||||
"currentSyncStatus=" + currentSyncStatus +
|
||||
", local=" + local.toString() +
|
||||
", remote=" + remote.toString() +
|
||||
", date=" + date +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -9,26 +10,50 @@ import java.util.List;
|
|||
|
||||
public class MispServer {
|
||||
|
||||
public MispServer() {
|
||||
}
|
||||
|
||||
public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
|
||||
this.server = server;
|
||||
this.organisation = organisation;
|
||||
this.remoteOrg = remoteOrganisation;
|
||||
}
|
||||
|
||||
@SerializedName("Server")
|
||||
@Expose
|
||||
public Server server;
|
||||
@SerializedName("Organisation")
|
||||
@Expose
|
||||
public Organisation organisation;
|
||||
@SerializedName("RemoteOrg")
|
||||
@Expose
|
||||
public Organisation remoteOrg;
|
||||
@SerializedName("User")
|
||||
@Expose
|
||||
public List<User> user;
|
||||
private Server server;
|
||||
|
||||
@SerializedName("Organisation")
|
||||
private Organisation organisation;
|
||||
|
||||
@SerializedName("RemoteOrg")
|
||||
private Organisation remoteOrganisation;
|
||||
|
||||
@SerializedName("User")
|
||||
private List<User> user;
|
||||
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
public Organisation getRemoteOrganisation() {
|
||||
return remoteOrganisation;
|
||||
}
|
||||
public void setRemoteOrganisation(Organisation remoteOrganisation) {
|
||||
this.remoteOrganisation = remoteOrganisation;
|
||||
}
|
||||
|
||||
public List<User> getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(List<User> user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return server.toString() + "\n" + organisation.toString() + "\n" + remoteOrganisation.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,40 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class MispUser {
|
||||
|
||||
@SerializedName("User")
|
||||
@Expose
|
||||
public User user;
|
||||
private User user;
|
||||
|
||||
public MispUser(User user) {
|
||||
@SerializedName("Role")
|
||||
private Role role;
|
||||
|
||||
@SerializedName("Organisation")
|
||||
private Organisation organisation;
|
||||
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
public void setRole(Role role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Information gathered from Misp API about a organisation.
|
||||
*/
|
||||
|
@ -21,27 +26,14 @@ public class Organisation {
|
|||
private String created_by;
|
||||
private Integer user_count;
|
||||
|
||||
public Organisation() {
|
||||
}
|
||||
|
||||
public Organisation(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Organisation(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Organisation toSyncOrganisation() {
|
||||
Organisation organisation = new Organisation();
|
||||
organisation.local = true;
|
||||
organisation.name = name;
|
||||
organisation.uuid = uuid;
|
||||
organisation.description = description;
|
||||
organisation.nationality = nationality;
|
||||
organisation.sector = sector;
|
||||
organisation.type = "Sync organisation";
|
||||
organisation.contacts = contacts;
|
||||
|
||||
return organisation;
|
||||
|
@ -64,19 +56,19 @@ public class Organisation {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDate_created() {
|
||||
public String getDateCreated() {
|
||||
return date_created;
|
||||
}
|
||||
|
||||
public void setDate_created(String date_created) {
|
||||
public void setDateCreated(String date_created) {
|
||||
this.date_created = date_created;
|
||||
}
|
||||
|
||||
public String getDate_modified() {
|
||||
public String getDateModified() {
|
||||
return date_modified;
|
||||
}
|
||||
|
||||
public void setDate_modified(String date_modified) {
|
||||
public void setDateModified(String date_modified) {
|
||||
this.date_modified = date_modified;
|
||||
}
|
||||
|
||||
|
@ -136,47 +128,47 @@ public class Organisation {
|
|||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String[] getRestricted_to_domain() {
|
||||
public String[] getRestrictedToDomain() {
|
||||
return restricted_to_domain;
|
||||
}
|
||||
|
||||
public void setRestricted_to_domain(String[] restricted_to_domain) {
|
||||
public void setRestrictedToDomain(String[] restricted_to_domain) {
|
||||
this.restricted_to_domain = restricted_to_domain;
|
||||
}
|
||||
|
||||
public String getCreated_by() {
|
||||
public String getCreatedBy() {
|
||||
return created_by;
|
||||
}
|
||||
|
||||
public void setCreated_by(String created_by) {
|
||||
public void setCreatedBy(String created_by) {
|
||||
this.created_by = created_by;
|
||||
}
|
||||
|
||||
public Integer getUser_count() {
|
||||
public Integer getUserCount() {
|
||||
return user_count;
|
||||
}
|
||||
|
||||
public void setUser_count(Integer user_count) {
|
||||
public void setUserCount(Integer user_count) {
|
||||
this.user_count = user_count;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Organisation{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", date_created='" + date_created + '\'' +
|
||||
", date_modified='" + date_modified + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", nationality='" + nationality + '\'' +
|
||||
", sector='" + sector + '\'' +
|
||||
", contacts='" + contacts + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", local=" + local +
|
||||
", uuid='" + uuid + '\'' +
|
||||
", restricted_to_domain='" + restricted_to_domain + '\'' +
|
||||
", created_by='" + created_by + '\'' +
|
||||
", user_count=" + user_count +
|
||||
'}';
|
||||
return "Organisation: \n" +
|
||||
"\t id = " + id + "\n" +
|
||||
"\t name = " + name + '\n' +
|
||||
"\t date_created = " + date_created + '\n' +
|
||||
"\t date_modified = " + date_modified + '\n' +
|
||||
"\t type = " + type + '\n' +
|
||||
"\t nationality = " + nationality + '\n' +
|
||||
"\t sector = " + sector + '\n' +
|
||||
"\t contacts = " + contacts + '\n' +
|
||||
"\t description = " + description + '\n' +
|
||||
"\t local = " + local + '\n' +
|
||||
"\t uuid = " + uuid + '\n' +
|
||||
"\t restricted_to_domain = " + Arrays.toString(restricted_to_domain) + '\n' +
|
||||
"\t created_by = " + created_by + '\n' +
|
||||
"\t user_count = " + user_count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,13 @@ public class Role {
|
|||
@SerializedName("permission_description")
|
||||
private String permissionDescription;
|
||||
|
||||
|
||||
public boolean isSyncUserRole() {
|
||||
return permSync && permAuth && permTagger && permTagEditor && permSharingGroup
|
||||
&& permDelegate && permSighting && permPublishZmq && permPublishKafka;
|
||||
}
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -1,112 +1,241 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
||||
public class Server {
|
||||
|
||||
public Server() {
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String url;
|
||||
private String authkey;
|
||||
private Integer org_id;
|
||||
private Boolean push = false;
|
||||
private Boolean pull = false;
|
||||
private Object lastpulledid;
|
||||
private Object lastpushedid;
|
||||
private Object organization;
|
||||
private Integer remote_org_id;
|
||||
private Boolean publish_without_email = false;
|
||||
private Boolean unpublish_event = false;
|
||||
private Boolean self_signed = false;
|
||||
private String pull_rules;
|
||||
private String push_rules;
|
||||
private Object cert_file;
|
||||
private Object client_cert_file;
|
||||
private Boolean internal;
|
||||
private Boolean skip_proxy;
|
||||
private Boolean caching_enabled = false;
|
||||
private Boolean cache_timestamp;
|
||||
|
||||
|
||||
public Server(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public Server(String name, String url, String authkey, Integer remote_org_id) {
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getAuthkey() {
|
||||
return authkey;
|
||||
}
|
||||
|
||||
public void setAuthkey(String authkey) {
|
||||
this.authkey = authkey;
|
||||
}
|
||||
|
||||
public Integer getOrgId() {
|
||||
return org_id;
|
||||
}
|
||||
|
||||
public void setOrgId(Integer org_id) {
|
||||
this.org_id = org_id;
|
||||
}
|
||||
|
||||
public Boolean getPush() {
|
||||
return push;
|
||||
}
|
||||
|
||||
public void setPush(Boolean push) {
|
||||
this.push = push;
|
||||
}
|
||||
|
||||
public Boolean getPull() {
|
||||
return pull;
|
||||
}
|
||||
|
||||
public void setPull(Boolean pull) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
public Object getLastpulledId() {
|
||||
return lastpulledid;
|
||||
}
|
||||
|
||||
public void setLastpulledId(Object lastpulledid) {
|
||||
this.lastpulledid = lastpulledid;
|
||||
}
|
||||
|
||||
public Object getLastpushedId() {
|
||||
return lastpushedid;
|
||||
}
|
||||
|
||||
public void setLastpushedId(Object lastpushedid) {
|
||||
this.lastpushedid = lastpushedid;
|
||||
}
|
||||
|
||||
public Object getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(Object organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public Integer getRemoteOrgId() {
|
||||
return remote_org_id;
|
||||
}
|
||||
|
||||
public void setRemoteOrgId(Integer remote_org_id) {
|
||||
this.remote_org_id = remote_org_id;
|
||||
}
|
||||
|
||||
@SerializedName("id")
|
||||
public Integer id;
|
||||
public Boolean getPublishWithoutEmail() {
|
||||
return publish_without_email;
|
||||
}
|
||||
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
public void setPublishWithoutEmail(Boolean publish_without_email) {
|
||||
this.publish_without_email = publish_without_email;
|
||||
}
|
||||
|
||||
@SerializedName("url")
|
||||
public String url;
|
||||
public Boolean getUnpublishEvent() {
|
||||
return unpublish_event;
|
||||
}
|
||||
|
||||
@SerializedName("authkey")
|
||||
public String authkey;
|
||||
public void setUnpublishEvent(Boolean unpublish_event) {
|
||||
this.unpublish_event = unpublish_event;
|
||||
}
|
||||
|
||||
@SerializedName("org_id")
|
||||
public Integer org_id;
|
||||
public Boolean getSelfSigned() {
|
||||
return self_signed;
|
||||
}
|
||||
|
||||
@SerializedName("push")
|
||||
public Boolean push;
|
||||
public void setSelfSigned(Boolean self_signed) {
|
||||
this.self_signed = self_signed;
|
||||
}
|
||||
|
||||
@SerializedName("pull")
|
||||
public Boolean pull;
|
||||
public String getPullRules() {
|
||||
return pull_rules;
|
||||
}
|
||||
|
||||
@SerializedName("lastpulledid")
|
||||
public Object lastpulledid;
|
||||
public void setPullRules(String pull_rules) {
|
||||
this.pull_rules = pull_rules;
|
||||
}
|
||||
|
||||
@SerializedName("lastpushedid")
|
||||
public Object lastpushedid;
|
||||
public String getPushRules() {
|
||||
return push_rules;
|
||||
}
|
||||
|
||||
@SerializedName("organization")
|
||||
public Object organization;
|
||||
public void setPushRules(String push_rules) {
|
||||
this.push_rules = push_rules;
|
||||
}
|
||||
|
||||
@SerializedName("remote_org_id")
|
||||
public Integer remote_org_id;
|
||||
public Object getCertFile() {
|
||||
return cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("publish_without_email")
|
||||
public Boolean publish_without_email = false;
|
||||
public void setCertFile(Object cert_file) {
|
||||
this.cert_file = cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("unpublish_event")
|
||||
public Boolean unpublish_event;
|
||||
public Object getClientCertFile() {
|
||||
return client_cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("self_signed")
|
||||
public Boolean self_signed = false;
|
||||
public void setClientCertFile(Object client_cert_file) {
|
||||
this.client_cert_file = client_cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("pull_rules")
|
||||
public String pull_rules;
|
||||
public Boolean getInternal() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
@SerializedName("push_rules")
|
||||
public String push_rules;
|
||||
public void setInternal(Boolean internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
@SerializedName("cert_file")
|
||||
public Object cert_file;
|
||||
public Boolean getSkipProxy() {
|
||||
return skip_proxy;
|
||||
}
|
||||
|
||||
@SerializedName("client_cert_file")
|
||||
public Object client_cert_file;
|
||||
public void setSkipProxy(Boolean skip_proxy) {
|
||||
this.skip_proxy = skip_proxy;
|
||||
}
|
||||
|
||||
@SerializedName("internal")
|
||||
public Boolean internal;
|
||||
public Boolean getCachingEnabled() {
|
||||
return caching_enabled;
|
||||
}
|
||||
|
||||
@SerializedName("skip_proxy")
|
||||
public Boolean skip_proxy = false;
|
||||
public void setCachingEnabled(Boolean caching_enabled) {
|
||||
this.caching_enabled = caching_enabled;
|
||||
}
|
||||
|
||||
@SerializedName("caching_enabled")
|
||||
public Boolean caching_enabled;
|
||||
public Boolean getCacheTimestamp() {
|
||||
return cache_timestamp;
|
||||
}
|
||||
|
||||
@SerializedName("cache_timestamp")
|
||||
public Boolean cache_timestamp;
|
||||
public void setCacheTimestamp(Boolean cache_timestamp) {
|
||||
this.cache_timestamp = cache_timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Server{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", authkey='" + authkey + '\'' +
|
||||
", org_id=" + org_id +
|
||||
", push=" + push +
|
||||
", pull=" + pull +
|
||||
", lastpulledid=" + lastpulledid +
|
||||
", lastpushedid=" + lastpushedid +
|
||||
", organization=" + organization +
|
||||
", remote_org_id=" + remote_org_id +
|
||||
", publish_without_email=" + publish_without_email +
|
||||
", unpublish_event=" + unpublish_event +
|
||||
", self_signed=" + self_signed +
|
||||
", pull_rules='" + pull_rules + '\'' +
|
||||
", push_rules='" + push_rules + '\'' +
|
||||
", cert_file=" + cert_file +
|
||||
", client_cert_file=" + client_cert_file +
|
||||
", internal=" + internal +
|
||||
", skip_proxy=" + skip_proxy +
|
||||
", caching_enabled=" + caching_enabled +
|
||||
", cache_timestamp=" + cache_timestamp +
|
||||
'}';
|
||||
return "Server: \n" +
|
||||
"\t id = " + id + '\n' +
|
||||
"\t name = " + name + '\n' +
|
||||
"\t url = " + url + '\n' +
|
||||
"\t authkey = " + authkey + '\n' +
|
||||
"\t org_id = " + org_id + '\n' +
|
||||
"\t push = " + push + '\n' +
|
||||
"\t pull = " + pull + '\n' +
|
||||
"\t lastpulledid = " + lastpulledid + '\n' +
|
||||
"\t lastpushedid = " + lastpushedid + '\n' +
|
||||
"\t organization = " + organization + '\n' +
|
||||
"\t remote_org_id = " + remote_org_id + '\n' +
|
||||
"\t publish_without_email = " + publish_without_email + '\n' +
|
||||
"\t unpublish_event = " + unpublish_event + '\n' +
|
||||
"\t self_signed = " + self_signed + '\n' +
|
||||
"\t pull_rules = " + pull_rules + '\n' +
|
||||
"\t push_rules = " + push_rules + '\n' +
|
||||
"\t cert_file = " + cert_file + '\n' +
|
||||
"\t client_cert_file = " + client_cert_file + '\n' +
|
||||
"\t internal = " + internal + '\n' +
|
||||
"\t skip_proxy = " + skip_proxy + '\n' +
|
||||
"\t caching_enabled = " + caching_enabled + '\n' +
|
||||
"\t cache_timestamp = " + cache_timestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,127 +1,249 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lu.circl.mispbump.auxiliary.RandomString;
|
||||
|
||||
|
||||
public class User {
|
||||
|
||||
public static final int ROLE_ADMIN = 1;
|
||||
public static final int ROLE_ORG_ADMIN = 2;
|
||||
public static final int ROLE_USER = 3;
|
||||
public static final int ROLE_PUBLISHER = 4;
|
||||
public static final int ROLE_SYNC_USER = 5;
|
||||
public static final int ROLE_READ_ONLY = 6;
|
||||
private Integer id;
|
||||
private String password;
|
||||
private Integer org_id;
|
||||
private String email;
|
||||
private Boolean autoalert;
|
||||
private String authkey;
|
||||
private String invited_by;
|
||||
private Object gpgkey;
|
||||
private String certif_public;
|
||||
private String nids_sid;
|
||||
private Boolean termsaccepted;
|
||||
private String newsread;
|
||||
private Integer role_id;
|
||||
private String change_pw;
|
||||
private Boolean contactalert;
|
||||
private Boolean disabled;
|
||||
private Object expiration;
|
||||
private String current_login;
|
||||
private String last_login;
|
||||
private Boolean force_logout;
|
||||
private Object date_created;
|
||||
private String date_modified;
|
||||
|
||||
public User() {
|
||||
|
||||
public User toSyncUser() {
|
||||
User user = new User();
|
||||
user.email = email;
|
||||
user.authkey = new RandomString(40).nextString();
|
||||
user.password = new RandomString(16).nextString();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public User(Integer org_id, String email, Integer role_id) {
|
||||
this.org_id = org_id;
|
||||
this.email = email;
|
||||
this.role_id = role_id;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public User(Integer org_id, String email, Integer role_id, String password) {
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Integer getOrgId() {
|
||||
return org_id;
|
||||
}
|
||||
|
||||
public void setOrgId(Integer org_id) {
|
||||
this.org_id = org_id;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean getAutoalert() {
|
||||
return autoalert;
|
||||
}
|
||||
|
||||
public void setAutoalert(Boolean autoalert) {
|
||||
this.autoalert = autoalert;
|
||||
}
|
||||
|
||||
public String getAuthkey() {
|
||||
return authkey;
|
||||
}
|
||||
|
||||
public void setAuthkey(String authkey) {
|
||||
this.authkey = authkey;
|
||||
}
|
||||
|
||||
public String getInvitedBy() {
|
||||
return invited_by;
|
||||
}
|
||||
|
||||
public void setInvitedBy(String invited_by) {
|
||||
this.invited_by = invited_by;
|
||||
}
|
||||
|
||||
public Object getGpgKey() {
|
||||
return gpgkey;
|
||||
}
|
||||
|
||||
public void setGpgKey(Object gpgkey) {
|
||||
this.gpgkey = gpgkey;
|
||||
}
|
||||
|
||||
public String getCertIfPublic() {
|
||||
return certif_public;
|
||||
}
|
||||
|
||||
public void setCertIfPublic(String certif_public) {
|
||||
this.certif_public = certif_public;
|
||||
}
|
||||
|
||||
public String getNidsSid() {
|
||||
return nids_sid;
|
||||
}
|
||||
|
||||
public void setNidsSid(String nids_sid) {
|
||||
this.nids_sid = nids_sid;
|
||||
}
|
||||
|
||||
public Boolean getTermsAccepted() {
|
||||
return termsaccepted;
|
||||
}
|
||||
|
||||
public void setTermsAccepted(Boolean termsaccepted) {
|
||||
this.termsaccepted = termsaccepted;
|
||||
}
|
||||
|
||||
public String getNewsRead() {
|
||||
return newsread;
|
||||
}
|
||||
|
||||
public void setNewsRead(String newsread) {
|
||||
this.newsread = newsread;
|
||||
}
|
||||
|
||||
public Integer getRoleId() {
|
||||
return role_id;
|
||||
}
|
||||
|
||||
public void setRoleId(Integer role_id) {
|
||||
this.role_id = role_id;
|
||||
}
|
||||
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
public Integer id;
|
||||
@SerializedName("password")
|
||||
@Expose
|
||||
public String password;
|
||||
@SerializedName("org_id")
|
||||
@Expose
|
||||
public Integer org_id;
|
||||
@SerializedName("email")
|
||||
@Expose
|
||||
public String email;
|
||||
@SerializedName("autoalert")
|
||||
@Expose
|
||||
public Boolean autoalert;
|
||||
@SerializedName("authkey")
|
||||
@Expose
|
||||
public String authkey;
|
||||
@SerializedName("invited_by")
|
||||
@Expose
|
||||
public String invited_by;
|
||||
@SerializedName("gpgkey")
|
||||
@Expose
|
||||
public Object gpgkey;
|
||||
@SerializedName("certif_public")
|
||||
@Expose
|
||||
public String certif_public;
|
||||
@SerializedName("nids_sid")
|
||||
@Expose
|
||||
public String nids_sid;
|
||||
@SerializedName("termsaccepted")
|
||||
@Expose
|
||||
public Boolean termsaccepted;
|
||||
@SerializedName("newsread")
|
||||
@Expose
|
||||
public String newsread;
|
||||
@SerializedName("role_id")
|
||||
@Expose
|
||||
public Integer role_id;
|
||||
@SerializedName("change_pw")
|
||||
@Expose
|
||||
public String change_pw;
|
||||
@SerializedName("contactalert")
|
||||
@Expose
|
||||
public Boolean contactalert;
|
||||
@SerializedName("disabled")
|
||||
@Expose
|
||||
public Boolean disabled;
|
||||
@SerializedName("expiration")
|
||||
@Expose
|
||||
public Object expiration;
|
||||
@SerializedName("current_login")
|
||||
@Expose
|
||||
public String current_login;
|
||||
@SerializedName("last_login")
|
||||
@Expose
|
||||
public String last_login;
|
||||
@SerializedName("force_logout")
|
||||
@Expose
|
||||
public Boolean force_logout;
|
||||
@SerializedName("date_created")
|
||||
@Expose
|
||||
public Object date_created;
|
||||
@SerializedName("date_modified")
|
||||
@Expose
|
||||
public String date_modified;
|
||||
public String getChangePw() {
|
||||
return change_pw;
|
||||
}
|
||||
|
||||
public void setChangePw(String change_pw) {
|
||||
this.change_pw = change_pw;
|
||||
}
|
||||
|
||||
public Boolean getContactalert() {
|
||||
return contactalert;
|
||||
}
|
||||
|
||||
public void setContactalert(Boolean contactalert) {
|
||||
this.contactalert = contactalert;
|
||||
}
|
||||
|
||||
public Boolean getDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(Boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public Object getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Object expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getCurrentLogin() {
|
||||
return current_login;
|
||||
}
|
||||
|
||||
public void setCurrentLogin(String current_login) {
|
||||
this.current_login = current_login;
|
||||
}
|
||||
|
||||
public String getLastLogin() {
|
||||
return last_login;
|
||||
}
|
||||
|
||||
public void setLastLogin(String last_login) {
|
||||
this.last_login = last_login;
|
||||
}
|
||||
|
||||
public Boolean getForceLogout() {
|
||||
return force_logout;
|
||||
}
|
||||
|
||||
public void setForceLogout(Boolean force_logout) {
|
||||
this.force_logout = force_logout;
|
||||
}
|
||||
|
||||
public Object getDateCreated() {
|
||||
return date_created;
|
||||
}
|
||||
|
||||
public void setDateCreated(Object date_created) {
|
||||
this.date_created = date_created;
|
||||
}
|
||||
|
||||
public String getDateModified() {
|
||||
return date_modified;
|
||||
}
|
||||
|
||||
public void setDateModified(String date_modified) {
|
||||
this.date_modified = date_modified;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"id='" + id + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", org_id='" + org_id + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", autoalert=" + autoalert +
|
||||
", authkey='" + authkey + '\'' +
|
||||
", invited_by='" + invited_by + '\'' +
|
||||
", gpgkey=" + gpgkey +
|
||||
", certif_public='" + certif_public + '\'' +
|
||||
", nids_sid='" + nids_sid + '\'' +
|
||||
", termsaccepted=" + termsaccepted +
|
||||
", newsread='" + newsread + '\'' +
|
||||
", role_id='" + role_id + '\'' +
|
||||
", change_pw='" + change_pw + '\'' +
|
||||
", contactalert=" + contactalert +
|
||||
", disabled=" + disabled +
|
||||
", expiration=" + expiration +
|
||||
", current_login='" + current_login + '\'' +
|
||||
", last_login='" + last_login + '\'' +
|
||||
", force_logout=" + force_logout +
|
||||
", date_created=" + date_created +
|
||||
", date_modified='" + date_modified + '\'' +
|
||||
'}';
|
||||
return "User: \n" +
|
||||
"\t id = " + id + '\n' +
|
||||
"\t password = " + password + '\n' +
|
||||
"\t org_id = " + org_id + '\n' +
|
||||
"\t email = " + email + '\n' +
|
||||
"\t autoalert = " + autoalert + '\n' +
|
||||
"\t authkey = " + authkey + '\n' +
|
||||
"\t invited_by = " + invited_by + '\n' +
|
||||
"\t gpgkey = " + gpgkey + '\n' +
|
||||
"\t certif_public = " + certif_public + '\n' +
|
||||
"\t nids_sid = " + nids_sid + '\n' +
|
||||
"\t termsaccepted = " + termsaccepted + '\n' +
|
||||
"\t newsread = " + newsread + '\n' +
|
||||
"\t role_id = " + role_id + '\n' +
|
||||
"\t change_pw = " + change_pw + '\n' +
|
||||
"\t contactalert = " + contactalert + '\n' +
|
||||
"\t disabled = " + disabled + '\n' +
|
||||
"\t expiration = " + expiration + '\n' +
|
||||
"\t current_login = " + current_login + '\n' +
|
||||
"\t last_login = " + last_login + '\n' +
|
||||
"\t force_logout = " + force_logout + '\n' +
|
||||
"\t date_created = " + date_created + '\n' +
|
||||
"\t date_modified = " + date_modified;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ public class KeyStoreWrapper {
|
|||
public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
|
||||
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
|
||||
public static final String USER_CREDENTIALS_ALIAS = "ALIAS_USER_CREDENTIALS";
|
||||
public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
|
||||
public static final String SYNC_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
|
||||
|
||||
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
|
||||
private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.12,9.29L12,13.17l3.88,-3.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0L6.7,10.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.38 1.03,-0.39 1.42,0z"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M38.71,20.07C37.35,13.19 31.28,8 24,8c-5.78,0 -10.79,3.28 -13.3,8.07C4.69,16.72 0,21.81 0,28c0,6.63 5.37,12 12,12h26c5.52,0 10,-4.48 10,-10 0,-5.28 -4.11,-9.56 -9.29,-9.93zM34,26L24,36 14,26h6v-8h8v8h6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/white"/>
|
||||
<corners android:radius="4dp"/>
|
||||
</shape>
|
|
@ -18,11 +18,18 @@
|
|||
app:popupTheme="@style/PopupTheme"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefresh"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty"
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activities.SyncInfoDetailActivity"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:theme="@style/ToolbarTheme"
|
||||
app:popupTheme="@style/PopupTheme" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<ScrollView
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<lu.circl.expandablecardview.ExpandableCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:card_header_background_color="@color/colorPrimary"
|
||||
app:card_header_foreground_color="@color/white"
|
||||
app:card_icon="@drawable/ic_info_outline"
|
||||
app:card_title="Information">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:title="Name"
|
||||
app:subtitle="No name" />
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/uuid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/name"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:title="UUID"
|
||||
app:subtitle="No UUID" />
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/sector"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/uuid"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:title="Sector"
|
||||
app:subtitle="No sector" />
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/uuid"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:title="@string/description"
|
||||
app:subtitle="No description" />
|
||||
</LinearLayout>
|
||||
|
||||
</lu.circl.expandablecardview.ExpandableCardView>
|
||||
|
||||
|
||||
<lu.circl.expandablecardview.ExpandableCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:card_header_background_color="@color/colorPrimary"
|
||||
app:card_header_foreground_color="@color/white"
|
||||
app:card_icon="@drawable/ic_settings"
|
||||
app:card_title="@string/settings">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_self_signed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/settings_self_signed_title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_push"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/settings_push_title"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkbox_self_signed" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_pull"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:text="@string/settings_pull_title"
|
||||
app:layout_constraintStart_toEndOf="@+id/checkbox_push"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkbox_self_signed" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkbox_cache"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:text="@string/settings_cache_title"
|
||||
app:layout_constraintTop_toBottomOf="@id/checkbox_push"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</lu.circl.expandablecardview.ExpandableCardView>
|
||||
|
||||
|
||||
<lu.circl.expandablecardview.ExpandableCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
app:card_header_background_color="@color/colorPrimary"
|
||||
app:card_header_foreground_color="@color/white"
|
||||
app:card_icon="@drawable/ic_verified_user"
|
||||
app:card_title="@string/credentials">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:title="Email"
|
||||
app:subtitle="Keine Ahnung" />
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPasswordView
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="Password"
|
||||
app:password="Weiß ich leider auch nicht" />
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPasswordView
|
||||
android:id="@+id/authkey"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:title="Authkey"
|
||||
app:password="Den erst recht nicht ..." />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</lu.circl.expandablecardview.ExpandableCardView>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="86dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<!-- <FrameLayout-->
|
||||
<!-- android:layout_width="match_parent"-->
|
||||
<!-- android:layout_height="match_parent"-->
|
||||
<!-- android:background="@color/black_50"/>-->
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_main"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_keyboard_arrow_down"
|
||||
android:tint="@color/white"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_upload"
|
||||
android:visibility="visible"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="8dp"
|
||||
android:clipToPadding="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/fab_main">
|
||||
|
||||
<TextView
|
||||
android:text="Upload to MISP instance"
|
||||
android:textColor="@color/white"
|
||||
android:padding="8dp"
|
||||
android:background="@drawable/tooltip_background"
|
||||
android:backgroundTint="@color/black_70"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_upload"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_cloud_upload"
|
||||
app:fabSize="mini"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:visibility="visible"
|
||||
android:id="@+id/layout_download"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:padding="8dp"
|
||||
android:clipToPadding="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/layout_upload">
|
||||
|
||||
<TextView
|
||||
android:text="Download changes from MISP instance"
|
||||
android:textColor="@color/white"
|
||||
android:padding="8dp"
|
||||
android:background="@drawable/tooltip_background"
|
||||
android:backgroundTint="@color/black_70"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab_download"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_cloud_download"
|
||||
app:fabSize="mini"/>
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -6,7 +6,6 @@
|
|||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:context=".activities.UploadActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
|
@ -17,78 +16,78 @@
|
|||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||
android:background="@color/colorPrimary">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbarTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
|
||||
android:text="@string/upload"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
android:theme="@style/ToolbarTheme"
|
||||
app:popupTheme="@style/PopupTheme"/>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
|
||||
<LinearLayout
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true">
|
||||
|
||||
<lu.circl.mispbump.customViews.UploadAction
|
||||
android:id="@+id/availableAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:description="@string/upload_action_available"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.UploadAction
|
||||
android:id="@+id/orgAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:description="@string/upload_action_add_org"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.UploadAction
|
||||
android:id="@+id/userAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:description="@string/upload_action_add_user"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.UploadAction
|
||||
android:id="@+id/serverAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/white"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:description="@string/upload_action_add_server"/>
|
||||
</androidx.appcompat.widget.LinearLayoutCompat>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp"
|
||||
android:src="@drawable/ic_check"/>
|
||||
android:orientation="vertical">
|
||||
|
||||
<lu.circl.mispbump.customViews.ProgressActionView
|
||||
android:layout_marginTop="8dp"
|
||||
android:id="@+id/availableProgressAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:action_title="Instance available"
|
||||
app:action_done_icon="@drawable/ic_check_outline"
|
||||
app:action_error_icon="@drawable/ic_error_outline"
|
||||
app:action_pending_icon="@drawable/ic_pending"/>
|
||||
|
||||
<View
|
||||
android:background="@color/black_10"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.ProgressActionView
|
||||
android:id="@+id/organisationProgressAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:action_title="Add Organisation"
|
||||
app:action_done_icon="@drawable/ic_check_outline"
|
||||
app:action_error_icon="@drawable/ic_error_outline"
|
||||
app:action_pending_icon="@drawable/ic_pending"/>
|
||||
|
||||
<View
|
||||
android:background="@color/black_10"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.ProgressActionView
|
||||
android:id="@+id/userProgressAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:action_title="Add Sync User"
|
||||
app:action_done_icon="@drawable/ic_check_outline"
|
||||
app:action_error_icon="@drawable/ic_error_outline"
|
||||
app:action_pending_icon="@drawable/ic_pending"/>
|
||||
|
||||
<View
|
||||
android:background="@color/black_10"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.ProgressActionView
|
||||
android:id="@+id/serverProgressAction"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:action_title="Add Sync Server"
|
||||
app:action_done_icon="@drawable/ic_check_outline"
|
||||
app:action_error_icon="@drawable/ic_error_outline"
|
||||
app:action_pending_icon="@drawable/ic_pending"/>
|
||||
|
||||
<View
|
||||
android:background="@color/black_10"
|
||||
android:layout_margin="8dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false">
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/baseUrl"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/white"
|
||||
app:subtitle="www.google.de"
|
||||
app:title="@string/url"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceText
|
||||
android:id="@+id/email"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/white"
|
||||
app:subtitle="syncuser_orga@mispx.yz"
|
||||
app:title="@string/email"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPasswordView
|
||||
android:id="@+id/password"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/white"
|
||||
app:title="@string/password"
|
||||
app:password="abc"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPasswordView
|
||||
android:id="@+id/authkey"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:background="@color/white"
|
||||
app:title="@string/authkey"
|
||||
app:password="abc"/>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
|
@ -1,75 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fragment_upload_settings_title"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceSwitch
|
||||
android:id="@+id/self_signed_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/text"
|
||||
app:onText="@string/settings_self_signed_on"
|
||||
app:offText="@string/settings_self_signed_off"
|
||||
app:title="@string/settings_self_signed_title"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceSwitch
|
||||
android:id="@+id/push_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/self_signed_switch"
|
||||
app:onText="@string/settings_push_on"
|
||||
app:offText="@string/settings_push_off"
|
||||
app:title="@string/settings_push_title"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceSwitch
|
||||
android:id="@+id/pull_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/push_switch"
|
||||
app:onText="@string/settings_pull_on"
|
||||
app:offText="@string/settings_pull_off"
|
||||
app:title="@string/settings_pull_title"/>
|
||||
|
||||
<lu.circl.mispbump.customViews.MaterialPreferenceSwitch
|
||||
android:id="@+id/cache_switch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/pull_switch"
|
||||
app:onText="@string/settings_cache_on"
|
||||
app:offText="@string/settings_cache_off"
|
||||
app:title="@string/settings_cache_title"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -24,25 +24,13 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/copy"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_file_copy"
|
||||
android:tint="@color/colorIconDark"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/material_password"
|
||||
app:layout_constraintEnd_toStartOf="@id/visibleToggle"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/material_password_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
|
||||
app:layout_constraintEnd_toStartOf="@+id/copy"
|
||||
app:layout_constraintEnd_toStartOf="@+id/visibleToggle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Title"/>
|
||||
|
@ -54,7 +42,7 @@
|
|||
android:layout_marginEnd="8dp"
|
||||
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintEnd_toStartOf="@+id/copy"
|
||||
app:layout_constraintEnd_toStartOf="@+id/visibleToggle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/material_password_title"
|
||||
tools:ignore="TextViewEdits"
|
||||
|
|
|
@ -7,54 +7,65 @@
|
|||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:padding="8dp">
|
||||
android:foreground="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/syncStatus"
|
||||
android:transitionName="icon"
|
||||
android:transformPivotX="12dp"
|
||||
android:transformPivotY="12dp"
|
||||
<TextView
|
||||
android:id="@+id/date_month"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:tint="@color/status_red"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:layout_margin="16dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_error_outline"/>
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
android:textSize="14sp"
|
||||
tools:text="Aug"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date_day"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/date_month"
|
||||
app:layout_constraintStart_toStartOf="@id/date_month"
|
||||
app:layout_constraintEnd_toEndOf="@id/date_month"
|
||||
tools:text="16"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/orgName"
|
||||
android:transitionName="title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/date"
|
||||
app:layout_constraintStart_toEndOf="@+id/syncStatus"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/date_month"
|
||||
tools:text="Organisation A"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
<ImageView
|
||||
android:id="@+id/syncStatus"
|
||||
android:src="@drawable/ic_check_outline"
|
||||
android:tint="@color/status_green"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="20.3.2019"/>
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<View
|
||||
android:background="@color/black_10"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintStart_toEndOf="@id/date_month"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
android:animateLayoutChanges="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/stateView"
|
||||
android:id="@+id/progressIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_error_outline"
|
||||
|
@ -19,8 +19,8 @@
|
|||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<ProgressBar
|
||||
android:visibility="gone"
|
||||
android:id="@+id/progressBar"
|
||||
android:visibility="gone"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -33,18 +33,19 @@
|
|||
android:layout_marginTop="2dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAppearance="@style/AppTheme.TextAppearance.ListTitle"
|
||||
app:layout_constraintEnd_toStartOf="@+id/stateView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/progressIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Add Organisation"/>
|
||||
|
||||
<TextView
|
||||
android:visibility="gone"
|
||||
android:id="@+id/error"
|
||||
android:visibility="gone"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:textAppearance="@style/AppTheme.TextAppearance.ListSubtitle"
|
||||
android:textColor="@color/status_red"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||
tools:text="Organisation B added successfully"/>
|
||||
|
|
|
@ -49,4 +49,5 @@
|
|||
<string name="preference_category_general">Allgemein</string>
|
||||
<string name="preference_github_summary">Besuchen Sie das Github Projekt</string>
|
||||
<string name="preference_category_information">App Informationen</string>
|
||||
<string name="sync_details_activity_label">Synchronisations Details</string>
|
||||
</resources>
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
<attr name="password"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="UploadAction">
|
||||
<attr name="description" format="string"/>
|
||||
<declare-styleable name="ProgressActionView">
|
||||
<attr name="action_title" format="string"/>
|
||||
<attr name="action_pending_icon" format="reference"/>
|
||||
<attr name="action_done_icon" format="reference"/>
|
||||
<attr name="action_error_icon" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="FixedAspectRatioFrameLayout">
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
<color name="grey_light">#F0F0F0</color>
|
||||
|
||||
<color name="black">#000</color>
|
||||
<color name="black_70">#B3000000</color>
|
||||
<color name="black_50">#80000000</color>
|
||||
<color name="black_30">#4D000000</color>
|
||||
<color name="black_10">#1A000000</color>
|
||||
|
||||
<color name="status_green">#4CAF50</color>
|
||||
<color name="status_amber">#FB8C00</color>
|
||||
|
|
|
@ -55,4 +55,5 @@
|
|||
<string name="preference_category_general">General</string>
|
||||
<string name="preference_category_information">App information</string>
|
||||
<string name="preference_github_summary">Visit the Github project</string>
|
||||
<string name="sync_details_activity_label">Synchronisation details</string>
|
||||
</resources>
|
||||
|
|
|
@ -13,7 +13,7 @@ import static org.junit.Assert.assertEquals;
|
|||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
public void additionIsCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.31'
|
||||
ext.kotlin_version = '1.3.41'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
/build
|
|
@ -0,0 +1,34 @@
|
|||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.1"
|
||||
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
|
@ -0,0 +1,29 @@
|
|||
package lu.circl.expandablecardview;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class ExampleInstrumentedTest {
|
||||
@Test
|
||||
public void useAppContext() {
|
||||
// Context of the app under test.
|
||||
Context appContext = InstrumentationRegistry.getTargetContext();
|
||||
|
||||
assertEquals("lu.circl.expandablecardview.test", appContext.getPackageName());
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<manifest package="lu.circl.expandablecardview" />
|
|
@ -0,0 +1,177 @@
|
|||
package lu.circl.expandablecardview;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
||||
public class ExpandableCardView extends LinearLayout {
|
||||
|
||||
private Context context;
|
||||
|
||||
private FrameLayout contentLayout;
|
||||
private int cardContentPadding;
|
||||
|
||||
private boolean isExpanded = true;
|
||||
private int animationSpeed = 200;
|
||||
|
||||
|
||||
public ExpandableCardView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ExpandableCardView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.context = context;
|
||||
|
||||
setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
|
||||
setOrientation(VERTICAL);
|
||||
setClipToOutline(true);
|
||||
|
||||
TypedArray customAttributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, defStyleAttr, 0);
|
||||
|
||||
// general
|
||||
int cornerRadius = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_corner_radius, 12);
|
||||
|
||||
// header
|
||||
String cardTitle = customAttributes.getString(R.styleable.ExpandableCardView_card_title);
|
||||
int iconRes = customAttributes.getResourceId(R.styleable.ExpandableCardView_card_icon, 0x0);
|
||||
int headerForegroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_foreground_color, 0xFF000000);
|
||||
int headerBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_background_color, 0xFFFFFFFF);
|
||||
|
||||
// content
|
||||
cardContentPadding = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_content_padding, 0);
|
||||
int cardContentBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_content_background_color, 0xFFFFFFFF);
|
||||
|
||||
customAttributes.recycle();
|
||||
|
||||
GradientDrawable cardBackground = new GradientDrawable();
|
||||
cardBackground.setCornerRadius(cornerRadius);
|
||||
cardBackground.setColor(cardContentBackgroundColor);
|
||||
|
||||
setBackground(cardBackground);
|
||||
setElevation(10);
|
||||
|
||||
initHeader(cardTitle, iconRes, headerBackgroundColor, headerForegroundColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index, ViewGroup.LayoutParams params) {
|
||||
if (getChildCount() == 0) {
|
||||
super.addView(child, index, params); // add header
|
||||
} else {
|
||||
if (contentLayout == null) {
|
||||
contentLayout = new FrameLayout(context);
|
||||
contentLayout.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
|
||||
contentLayout.setPadding(cardContentPadding, cardContentPadding, cardContentPadding, cardContentPadding);
|
||||
|
||||
super.addView(contentLayout, index, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
|
||||
contentLayout.addView(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void initHeader(String title, int iconRes, int backgroundColor, int foregroundColor) {
|
||||
View header = LayoutInflater.from(context).inflate(R.layout.expandable_card_view_header, this, true);
|
||||
LinearLayout ll = header.findViewById(R.id.llRoot);
|
||||
ll.setBackgroundColor(backgroundColor);
|
||||
|
||||
TextView titleTextView = header.findViewById(R.id.expandable_card_view_header_title);
|
||||
titleTextView.setText(title);
|
||||
titleTextView.setTextColor(foregroundColor);
|
||||
|
||||
ImageView iconView = header.findViewById(R.id.expandable_card_view_header_icon);
|
||||
if (iconRes == 0x0) {
|
||||
iconView.setVisibility(GONE);
|
||||
} else {
|
||||
iconView.setImageResource(iconRes);
|
||||
iconView.setColorFilter(foregroundColor);
|
||||
}
|
||||
|
||||
final ImageButton expandToggle = header.findViewById(R.id.expandable_card_view_header_toggle);
|
||||
expandToggle.setColorFilter(foregroundColor);
|
||||
expandToggle.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (isExpanded) {
|
||||
collapse(contentLayout);
|
||||
expandToggle.animate().rotation(0).setDuration(animationSpeed);
|
||||
} else {
|
||||
expand(contentLayout);
|
||||
expandToggle.animate().rotation(180).setDuration(animationSpeed);
|
||||
}
|
||||
|
||||
isExpanded = !isExpanded;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void expand(final View v) {
|
||||
int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY);
|
||||
int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
v.measure(matchParentMeasureSpec, wrapContentMeasureSpec);
|
||||
final int targetHeight = v.getMeasuredHeight();
|
||||
|
||||
v.getLayoutParams().height = 1;
|
||||
v.setVisibility(View.VISIBLE);
|
||||
Animation a = new Animation() {
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
v.getLayoutParams().height = interpolatedTime == 1
|
||||
? LayoutParams.WRAP_CONTENT
|
||||
: (int) (targetHeight * interpolatedTime);
|
||||
v.requestLayout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willChangeBounds() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
a.setDuration(animationSpeed);
|
||||
v.startAnimation(a);
|
||||
}
|
||||
|
||||
private void collapse(final View v) {
|
||||
final int initialHeight = v.getMeasuredHeight();
|
||||
|
||||
Animation a = new Animation() {
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
if (interpolatedTime == 1) {
|
||||
v.setVisibility(View.GONE);
|
||||
} else {
|
||||
v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime);
|
||||
v.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willChangeBounds() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
a.setDuration(animationSpeed);
|
||||
v.startAnimation(a);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/llRoot"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/expandable_card_view_header_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
tools:src="@drawable/ic_info_outline"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/expandable_card_view_header_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
tools:text="Card Title"/>
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/expandable_card_view_header_toggle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_keyboard_arrow_down"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<declare-styleable name="ExpandableCardView">
|
||||
// general
|
||||
<attr name="card_corner_radius" format="dimension"/>
|
||||
|
||||
// header
|
||||
<attr name="card_title" format="string"/>
|
||||
<attr name="card_icon" format="reference"/>
|
||||
<attr name="card_header_background_color" format="color"/>
|
||||
<attr name="card_header_foreground_color" format="color"/>
|
||||
|
||||
// content
|
||||
<attr name="card_content_padding" format="dimension"/>
|
||||
<attr name="card_content_background_color" format="color"/>
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -0,0 +1,3 @@
|
|||
<resources>
|
||||
<string name="app_name">ExpandableCardView</string>
|
||||
</resources>
|
|
@ -0,0 +1,19 @@
|
|||
package lu.circl.expandablecardview;
|
||||
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||
*/
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
#Wed May 08 12:00:08 CEST 2019
|
||||
#Wed Aug 21 13:50:22 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
|
|
|
@ -1 +1 @@
|
|||
include ':app'
|
||||
include ':app', ':expandablecardview'
|
||||
|
|
Loading…
Reference in New Issue