diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..681f41a
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ xmlns:android
+
+ ^$
+
+
+
+
+
+
+
+
+ xmlns:.*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*:id
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ .*:name
+
+ http://schemas.android.com/apk/res/android
+
+
+
+
+
+
+
+
+ name
+
+ ^$
+
+
+
+
+
+
+
+
+ style
+
+ ^$
+
+
+
+
+
+
+
+
+ .*
+
+ ^$
+
+
+ BY_NAME
+
+
+
+
+
+
+ .*
+
+ http://schemas.android.com/apk/res/android
+
+
+ ANDROID_ATTRIBUTE_ORDER
+
+
+
+
+
+
+ .*
+
+ .*
+
+
+ BY_NAME
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 3e34bb9..f7bd235 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -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')
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index abd7c7c..169716e 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,12 +1,8 @@
-
-
-
-
-
+
+
+
-
+
-
+
+ android:label="@string/login" />
+ android:label="@string/app_name" />
+ android:theme="@style/AppTheme.Translucent" />
-
+ android:label="@string/sync_details_activity_label"
+ android:parentActivityName=".activities.HomeActivity" />
+ android:parentActivityName=".activities.HomeActivity" />
+ android:theme="@style/AppTheme.Translucent" />
+
+
+
diff --git a/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java b/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
index 007bb8e..17a7300 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/ExchangeActivity.java
@@ -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,10 @@ public class ExchangeActivity extends AppCompatActivity {
initViews();
initCamera();
- uploadInformation = new UploadInformation();
publicKeyQr = generatePublicKeyBitmap();
+ syncInformation = new SyncInformation();
+
setSyncState(SyncState.KEY_EXCHANGE);
}
@@ -105,24 +105,23 @@ 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().getEmail();
- return syncInformation;
+ ExchangeInformation exchangeInformation = generateSyncExchangeInformation();
+ syncInformation.setLocal(exchangeInformation);
+ return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(exchangeInformation)));
}
@@ -275,34 +274,9 @@ public class ExchangeActivity extends AppCompatActivity {
break;
case DATA_EXCHANGE:
try {
- final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
-
- final List 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);
+ ExchangeInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), ExchangeInformation.class);
+ syncInformation.populateRemoteExchangeInformation(remoteSyncInfo);
+ preferenceManager.addSyncInformation(syncInformation);
setSyncState(SyncState.DATA_EXCHANGE_DONE);
} catch (JsonSyntaxException e) {
if (currentReadQrStatus == ReadQrStatus.PENDING) {
@@ -340,10 +314,8 @@ public class ExchangeActivity extends AppCompatActivity {
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());
+ Intent i = new Intent(ExchangeActivity.this, SyncInfoDetailActivity.class);
+ i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid());
startActivity(i);
finish();
break;
diff --git a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
index 6a2ffc6..90a388b 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java
@@ -12,7 +12,6 @@ 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;
@@ -21,21 +20,18 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
import java.util.List;
import lu.circl.mispbump.R;
-import lu.circl.mispbump.adapters.UploadInfoAdapter;
-import lu.circl.mispbump.auxiliary.MispRestClient;
+import lu.circl.mispbump.adapters.SyncInfoAdapter;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
-import lu.circl.mispbump.models.SyncModel;
-import lu.circl.mispbump.models.UploadInformation;
-import lu.circl.mispbump.models.restModels.Server;
+import lu.circl.mispbump.models.SyncInformation;
public class HomeActivity extends AppCompatActivity {
- private List uploadInformationList;
+ private List syncInformationList;
private PreferenceManager preferenceManager;
private RecyclerView recyclerView;
- private UploadInfoAdapter uploadInfoAdapter;
+ private SyncInfoAdapter syncInfoAdapter;
private TextView emptyRecyclerView;
@Override
@@ -90,55 +86,33 @@ public class HomeActivity extends AppCompatActivity {
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() {
+ syncInformationList = preferenceManager.getSyncInformationList();
- Pair credentials = preferenceManager.getUserCredentials();
- MispRestClient mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
-
- mispRestClient.getAllServers(new MispRestClient.AllServersCallback() {
- @Override
- public void success(Server[] servers) {
- SyncModel.createFromServer(mispRestClient, servers[0], new SyncModel.InitializeWithServerObject() {
- @Override
- public void success(SyncModel syncModel) {
- Log.d("DEBUG", syncModel.toString());
- }
-
- @Override
- public void failure(String error) {
-
- }
- });
- }
-
- @Override
- public void failure(String error) {
-
- }
- });
-
- uploadInformationList = preferenceManager.getUploadInformationList();
-
- 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);
+
+ for (SyncInformation si : syncInformationList) {
+ Log.d("DEBUG", si.toString());
+ }
}
}
private OnRecyclerItemClickListener onRecyclerItemClickListener() {
return (v, index) -> {
- Intent i = new Intent(HomeActivity.this, UploadInfoActivity.class);
- i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformationList.get(index).getUuid());
+ 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());
diff --git a/app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
similarity index 87%
rename from app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java
rename to app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
index 2f29d5b..bc3ed30 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/StartUpActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java
@@ -12,14 +12,14 @@ 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) {
super.onCreate(savedInstanceState);
if (isUserLoggedIn()) {
- Intent home = new Intent(this, HomeActivity.class);
+ Intent home = new Intent(this, NetworkTestActivity.class);
startActivity(home);
} else {
Intent login = new Intent(this, LoginActivity.class);
diff --git a/app/src/main/java/lu/circl/mispbump/activities/NetworkTestActivity.java b/app/src/main/java/lu/circl/mispbump/activities/NetworkTestActivity.java
new file mode 100644
index 0000000..4921bdc
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/activities/NetworkTestActivity.java
@@ -0,0 +1,99 @@
+package lu.circl.mispbump.activities;
+
+
+import android.os.Bundle;
+import android.util.Log;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.util.Pair;
+
+import java.util.List;
+
+import lu.circl.mispbump.R;
+import lu.circl.mispbump.auxiliary.MispRestClient;
+import lu.circl.mispbump.auxiliary.PreferenceManager;
+import lu.circl.mispbump.interfaces.MispService;
+import lu.circl.mispbump.models.SyncInformation;
+import lu.circl.mispbump.models.restModels.MispOrganisation;
+import lu.circl.mispbump.models.restModels.MispServer;
+import lu.circl.mispbump.models.restModels.Organisation;
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+
+
+public class NetworkTestActivity extends AppCompatActivity {
+
+ private PreferenceManager preferenceManager;
+ private MispService service;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_network_test);
+
+ preferenceManager = PreferenceManager.getInstance(NetworkTestActivity.this);
+ Pair credentials = preferenceManager.getUserCredentials();
+ MispRestClient restClient = MispRestClient.getInstance(credentials.first, credentials.second);
+ service = restClient.getService();
+
+ loadAllSyncs();
+ }
+
+ private void boundSyncInfoToServer() {
+ List syncInformationList = preferenceManager.getSyncInformationList();
+
+ for (SyncInformation syncInfo : syncInformationList) {
+ String authkey = syncInfo.getSyncServer().getAuthkey();
+ String localUUID = syncInfo.getLocal().getOrganisation().getUuid();
+ String foreignUUID = syncInfo.getRemoteOrganisation().getUuid();
+
+
+ }
+ }
+
+ private void loadAllSyncs() {
+ Call> allServersCall = service.getAllServers();
+
+ allServersCall.enqueue(new Callback>() {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (!response.isSuccessful()) {
+ return;
+ }
+
+ List allServers = response.body();
+
+ assert allServers != null;
+
+ for (MispServer mispServer : allServers) {
+ loadOrganisation(mispServer.getRemoteOrganisation().getId());
+ }
+ }
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+
+ }
+ });
+ }
+
+ private void loadOrganisation(int id) {
+ Call organisationCall = service.getOrganisation(id);
+ organisationCall.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ return;
+ }
+
+ Organisation org = response.body().organisation;
+ Log.d("DEBUG", org.toString());
+
+ }
+ @Override
+ public void onFailure(Call call, Throwable t) {
+
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java b/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
index 3ffb150..67d04df 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/ProfileActivity.java
@@ -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;
@@ -120,13 +119,10 @@ public class ProfileActivity extends AppCompatActivity {
}
private View.OnClickListener onFabClicked() {
- return new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- fab.setImageDrawable(fabLoadingDrawable);
- fabLoadingDrawable.start();
- updateProfile();
- }
+ return v -> {
+ fab.setImageDrawable(fabLoadingDrawable);
+ fabLoadingDrawable.start();
+ updateProfile();
};
}
@@ -181,23 +177,15 @@ 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();
diff --git a/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java
new file mode 100644
index 0000000..d19fc37
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java
@@ -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.getRemoteOrganisation().getName());
+
+ MaterialPreferenceText uuid = findViewById(R.id.uuid);
+ uuid.setSubtitle(syncInformation.getRemoteOrganisation().getUuid());
+
+ MaterialPreferenceText sector = findViewById(R.id.sector);
+ sector.setSubtitle(syncInformation.getRemoteOrganisation().getSector());
+
+ MaterialPreferenceText description = findViewById(R.id.description);
+ description.setSubtitle(syncInformation.getRemoteOrganisation().getDescription());
+
+ // settings
+
+ CheckBox allowSelfSigned = findViewById(R.id.checkbox_self_signed);
+ allowSelfSigned.setChecked(syncInformation.getSyncServer().getSelf_signed());
+ allowSelfSigned.setOnCheckedChangeListener((compoundButton, b) -> {
+ syncInformation.getSyncServer().setSelf_signed(b);
+
+ });
+
+ CheckBox push = findViewById(R.id.checkbox_push);
+ push.setChecked(syncInformation.getSyncServer().getPush());
+ push.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getSyncServer().setPush(b));
+
+ CheckBox pull = findViewById(R.id.checkbox_pull);
+ pull.setChecked(syncInformation.getSyncServer().getPull());
+ pull.setOnCheckedChangeListener((compundButton, b) -> syncInformation.getSyncServer().setPull(b));
+
+ CheckBox cache = findViewById(R.id.checkbox_cache);
+ cache.setChecked(syncInformation.getSyncServer().getCaching_enabled());
+ cache.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getSyncServer().setCaching_enabled(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();
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java b/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
index b396970..c4b05f5 100644
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
+++ b/app/src/main/java/lu/circl/mispbump/activities/UploadActivity.java
@@ -6,21 +6,19 @@ 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.Server;
import lu.circl.mispbump.models.restModels.User;
@@ -28,13 +26,74 @@ 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 View rootLayout;
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);
+
+ rootLayout = findViewById(R.id.rootLayout);
+
+ preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
+
+ Pair 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 +151,64 @@ 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 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();
+ User syncUser = syncInformation.getSyncUser();
+
syncUser.setOrg_id(organisation.getId());
-// syncUser.role_id = User.ROLE_SYNC_USER;
- syncUser.setEmail(uploadInformation.getRemote().syncUserEmail);
- syncUser.setPassword(uploadInformation.getRemote().syncUserPassword);
- syncUser.setAuthkey(uploadInformation.getRemote().syncUserAuthkey);
+ syncUser.setRole_id(6);
syncUser.setTermsaccepted(true);
return syncUser;
}
private Server generateSyncServer() {
- Server server = new Server();
- server.setName(uploadInformation.getRemote().organisation.getName() + "'s Sync Server");
- server.setUrl(uploadInformation.getRemote().baseUrl);
- server.setRemote_org_id(uploadInformation.getRemote().organisation.getId());
- server.setAuthkey(uploadInformation.getLocal().syncUserAuthkey);
- server.setPull(uploadInformation.isPull());
- server.setPush(uploadInformation.isPush());
- server.setCaching_enabled(uploadInformation.isCached());
- server.setSelf_signed(uploadInformation.isAllowSelfSigned());
+ Server server = syncInformation.getSyncServer();
+ server.setName(syncInformation.getRemoteOrganisation().getName() + "'s Sync Server");
+ server.setRemote_org_id(syncInformation.getRemoteOrganisation().getId());
+ server.setAuthkey(syncInformation.getLocal().getSyncUser().getAuthkey());
+ server.setPull(syncInformation.getSyncServer().getPull());
+ server.setPush(syncInformation.getSyncServer().getPush());
+ server.setCaching_enabled(syncInformation.getSyncServer().getCaching_enabled());
+ server.setSelf_signed(syncInformation.getSyncServer().getCaching_enabled());
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.getRemoteOrganisation(), 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.getRemoteOrganisation().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.getRemoteOrganisation().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 +216,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) {
+ userAction.done("User already on MISP instance");
userAdded(user);
}
@Override
public void failure(String error) {
- setUploadActionState(userAction, UploadAction.UploadState.ERROR, error);
+ userAction.error(error);
}
});
}
@@ -309,28 +248,16 @@ public class UploadActivity extends AppCompatActivity {
}
}
- 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();
- } else {
- setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not add server");
+ serverAction.done();
+ preferenceManager.addSyncInformation(syncInformation);
}
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java b/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java
deleted file mode 100644
index 66067cb..0000000
--- a/app/src/main/java/lu/circl/mispbump/activities/UploadInfoActivity.java
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java
new file mode 100644
index 0000000..5661b30
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java
@@ -0,0 +1,99 @@
+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 {
+
+ private List items;
+ private OnRecyclerItemClickListener 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.getRemoteOrganisation().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() {
+ return items.size();
+ }
+
+
+ public void setItems(List items) {
+ this.items = items;
+ notifyDataSetChanged();
+ }
+
+ public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener 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);
+ }
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java
deleted file mode 100644
index 9e1594e..0000000
--- a/app/src/main/java/lu/circl/mispbump/adapters/UploadInfoAdapter.java
+++ /dev/null
@@ -1,98 +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 {
-
- private Context context;
- private List items;
-
- private OnRecyclerItemClickListener 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(view -> onRecyclerPositionClickListener.onClick(view, position));
- }
-
- @Override
- public int getItemCount() {
- return items.size();
- }
-
-
- public void setItems(List items) {
- this.items = items;
- notifyDataSetChanged();
- }
-
- public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener onRecyclerPositionClickListener) {
- this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
- }
-
-
- 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);
- }
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java b/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
index 9ded4b4..161aa51 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/DialogManager.java
@@ -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,7 +143,7 @@ public class DialogManager {
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
adb.setTitle("Sync information received");
- adb.setMessage(syncInformation.organisation.getName());
+ adb.setMessage(syncInformation.getRemoteOrganisation().getName());
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java b/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
index 621fc4e..d4cbfe6 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/MispRestClient.java
@@ -18,7 +18,7 @@ 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;
@@ -47,7 +47,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 +67,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)
@@ -153,7 +158,7 @@ public class MispRestClient {
* @param callback {@link AvailableCallback}
*/
public void isAvailable(final AvailableCallback callback) {
- Call call = mispRestInterface.pyMispVersion();
+ Call call = mispService.pyMispVersion();
call.enqueue(new Callback() {
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) {
@@ -177,7 +182,7 @@ public class MispRestClient {
}
public void getRoles(final AllRolesCallback callback) {
- Call> call = mispRestInterface.getRoles();
+ Call> call = mispService.getRoles();
call.enqueue(new Callback>() {
@Override
public void onResponse(Call> call, Response> response) {
@@ -213,7 +218,7 @@ public class MispRestClient {
* @param callback {@link UserCallback} wrapper to return user directly
*/
public void getMyUser(final UserCallback callback) {
- Call call = mispRestInterface.getMyUserInformation();
+ Call call = mispService.getMyUserInformation();
call.enqueue(new Callback() {
@Override
@@ -245,7 +250,7 @@ public class MispRestClient {
*/
public void getUser(int userId, final UserCallback callback) {
- Call call = mispRestInterface.getUser(userId);
+ Call call = mispService.getUser(userId);
call.enqueue(new Callback() {
@Override
@@ -291,7 +296,7 @@ public class MispRestClient {
}
public void getAllUsers(final AllUsersCallback callback) {
- Call> call = mispRestInterface.getAllUsers();
+ Call> call = mispService.getAllUsers();
call.enqueue(new Callback>() {
@Override
@@ -327,7 +332,7 @@ public class MispRestClient {
* @param callback {@link UserCallback} wrapper to return the created user directly
*/
public void addUser(User user, final UserCallback callback) {
- Call call = mispRestInterface.addUser(user);
+ Call call = mispService.addUser(user);
call.enqueue(new Callback() {
@Override
@@ -357,7 +362,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
*/
public void getOrganisation(int orgId, final OrganisationCallback callback) {
- Call call = mispRestInterface.getOrganisation(orgId);
+ Call call = mispService.getOrganisation(orgId);
call.enqueue(new Callback() {
@Override
@@ -402,7 +407,7 @@ public class MispRestClient {
}
public void getAllOrganisations(final AllOrganisationsCallback callback) {
- Call> call = mispRestInterface.getAllOrganisations();
+ Call> call = mispService.getAllOrganisations();
call.enqueue(new Callback>() {
@Override
@@ -438,7 +443,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
*/
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
- Call call = mispRestInterface.addOrganisation(organisation);
+ Call call = mispService.addOrganisation(organisation);
call.enqueue(new Callback() {
@Override
@@ -466,7 +471,7 @@ public class MispRestClient {
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
*/
public void getAllServers(final AllServersCallback callback) {
- Call> call = mispRestInterface.getAllServers();
+ Call> call = mispService.getAllServers();
call.enqueue(new Callback>() {
@Override
@@ -494,7 +499,7 @@ public class MispRestClient {
}
public void getAllServers(final AllRawServersCallback callback) {
- Call> call = mispRestInterface.getAllServers();
+ Call> call = mispService.getAllServers();
call.enqueue(new Callback>() {
@Override
@@ -520,7 +525,7 @@ public class MispRestClient {
* @param callback {@link ServerCallback} wrapper to return the created server directly
*/
public void addServer(Server server, final ServerCallback callback) {
- Call call = mispRestInterface.addServer(server);
+ Call call = mispService.addServer(server);
call.enqueue(new Callback() {
@Override
diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
index 6bde257..6dada16 100644
--- a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
+++ b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java
@@ -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";
@@ -101,21 +101,11 @@ public class PreferenceManager {
*/
public void setUserInfo(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();
}
@@ -243,58 +223,57 @@ public class PreferenceManager {
}
- private List cachedUploadInformationList;
+ private List 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>() {
- }.getType();
+ Type type = new TypeToken>() {}.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 getUploadInformationList() {
- if (cachedUploadInformationList == null) {
- loadUploadInformationList();
+ public List getSyncInformationList() {
+ if (cachedSyncInformationList == null) {
+ loadSyncInformationList();
}
- return cachedUploadInformationList;
+ return cachedSyncInformationList;
}
- public void setUploadInformationList(List uploadInformationList) {
- cachedUploadInformationList = uploadInformationList;
- saveUploadInformationList();
+ public void setSyncInformationList(List 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();
}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
index ae6c3d7..9e90a9b 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/MaterialPasswordView.java
@@ -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);
- }
}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java b/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java
new file mode 100644
index 0000000..daa9171
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/customViews/ProgressActionView.java
@@ -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;
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java b/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
index 4b53dba..a821ca7 100644
--- a/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
+++ b/app/src/main/java/lu/circl/mispbump/customViews/UploadAction.java
@@ -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);
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java b/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java
deleted file mode 100644
index d19029c..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadCredentialsFragment.java
+++ /dev/null
@@ -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;
- }
-
-}
diff --git a/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java b/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java
deleted file mode 100644
index 021c44a..0000000
--- a/app/src/main/java/lu/circl/mispbump/fragments/UploadSettingsFragment.java
+++ /dev/null
@@ -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);
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java b/app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
similarity index 97%
rename from app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java
rename to app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
index 68ce5e6..cc8852a 100644
--- a/app/src/main/java/lu/circl/mispbump/interfaces/MispRestInterface.java
+++ b/app/src/main/java/lu/circl/mispbump/interfaces/MispService.java
@@ -21,7 +21,7 @@ import retrofit2.http.Path;
/**
* RetroFit2 interface for communication with misp instances
*/
-public interface MispRestInterface {
+public interface MispService {
// settings routes
diff --git a/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java b/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java
new file mode 100644
index 0000000..0a31f2e
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/models/ExchangeInformation.java
@@ -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();
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
index ccbf113..0c8d42f 100644
--- a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java
@@ -3,29 +3,118 @@ package lu.circl.mispbump.models;
import androidx.annotation.NonNull;
+import com.google.gson.annotations.SerializedName;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.UUID;
+
import lu.circl.mispbump.models.restModels.Organisation;
+import lu.circl.mispbump.models.restModels.Server;
+import lu.circl.mispbump.models.restModels.User;
/**
- * A Class that holds the information needed synchronize two misp instances.
+ * 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;
+
+ @SerializedName("organisation")
+ private Organisation remoteOrganisation;
+ private User syncUser;
+ private Server syncServer;
+ 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 Organisation getRemoteOrganisation() {
+ return remoteOrganisation;
+ }
+ public void setRemoteOrganisation(Organisation organisation) {
+ this.remoteOrganisation = organisation;
+ }
+
+ public User getSyncUser() {
+ return syncUser;
+ }
+ public void setSyncUser(User syncUser) {
+ this.syncUser = syncUser;
+ }
+
+ public Server getSyncServer() {
+ return syncServer;
+ }
+ public void setSyncServer(Server syncServer) {
+ this.syncServer = syncServer;
+ }
+
+ public ExchangeInformation getLocal() {
+ return local;
+ }
+ public void setLocal(ExchangeInformation local) {
+ this.local = local;
+ }
+
+
+ public void populateRemoteExchangeInformation(ExchangeInformation exchangeInformation) {
+ this.remoteOrganisation = exchangeInformation.getOrganisation();
+ this.syncUser = exchangeInformation.getSyncUser();
+ this.syncServer = exchangeInformation.getServer();
+ }
+
@NonNull
@Override
public String toString() {
- return "SyncInformation{" +
- "organisation=" + organisation +
- ", syncUserEmail='" + syncUserEmail + '\'' +
- ", syncUserPassword='" + syncUserPassword + '\'' +
- ", syncUserAuthkey='" + syncUserAuthkey + '\'' +
- ", baseUrl='" + baseUrl + '\'' +
- '}';
+ return "Sync Information: \n" +
+ "UUID = " + uuid + "\n" +
+ "Date = " + getSyncDateString() + "\n" +
+ remoteOrganisation.toString() + "\n" +
+ syncUser.toString() + "\n" +
+ syncServer.toString() + "\n" +
+ local.toString();
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/SyncModel.java b/app/src/main/java/lu/circl/mispbump/models/SyncModel.java
deleted file mode 100644
index 97656c3..0000000
--- a/app/src/main/java/lu/circl/mispbump/models/SyncModel.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package lu.circl.mispbump.models;
-
-
-import androidx.annotation.NonNull;
-
-import java.util.UUID;
-
-import lu.circl.mispbump.auxiliary.MispRestClient;
-import lu.circl.mispbump.models.restModels.Organisation;
-import lu.circl.mispbump.models.restModels.Server;
-
-
-public class SyncModel {
-
- private UUID uuid;
-
- private Server server;
- private Organisation organisation;
- private Organisation remoteOrganisation;
-
-
- 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 static void createFromServer(MispRestClient mispRestClient, Server server, InitializeWithServerObject callback) {
- SyncModel syncModel = new SyncModel();
-
- syncModel.server = server;
-
- mispRestClient.getOrganisation(server.getOrg_id(), new MispRestClient.OrganisationCallback() {
- @Override
- public void success(Organisation organisation) {
- syncModel.organisation = organisation;
-
- mispRestClient.getOrganisation(server.getRemote_org_id(), new MispRestClient.OrganisationCallback() {
- @Override
- public void success(Organisation organisation) {
- syncModel.remoteOrganisation = organisation;
-
- callback.success(syncModel);
- }
-
- @Override
- public void failure(String error) {
- callback.failure(error);
- }
- });
- }
-
- @Override
- public void failure(String error) {
- callback.failure(error);
- }
- });
- }
-
-
- @NonNull
- @Override
- public String toString() {
- return server.toString() + "\n" + organisation.toString() + "\n" + remoteOrganisation.toString();
- }
-
- public interface InitializeWithServerObject {
- void success(SyncModel syncModel);
-
- void failure(String error);
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java b/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java
deleted file mode 100644
index 3c73bdb..0000000
--- a/app/src/main/java/lu/circl/mispbump/models/UploadInformation.java
+++ /dev/null
@@ -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 +
- '}';
- }
-}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
index 9eef1b0..d34febf 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Organisation.java
@@ -3,6 +3,8 @@ package lu.circl.mispbump.models.restModels;
import androidx.annotation.NonNull;
+import java.util.Arrays;
+
/**
* Information gathered from Misp API about a organisation.
@@ -20,22 +22,18 @@ public class Organisation {
private String description;
private Boolean local;
private String uuid;
-// private String[] restricted_to_domain;
+ private String[] restricted_to_domain;
private String created_by;
private Integer user_count;
- public Organisation() {
- }
public Organisation toSyncOrganisation() {
Organisation organisation = new Organisation();
- organisation.local = true; // TODO REMOVE FROME HERE!
organisation.name = name;
organisation.uuid = uuid;
organisation.description = description;
organisation.nationality = nationality;
organisation.sector = sector;
- organisation.type = "Sync organisation";
organisation.contacts = contacts;
return organisation;
@@ -130,13 +128,13 @@ public class Organisation {
this.uuid = uuid;
}
-// public String[] getRestricted_to_domain() {
-// return restricted_to_domain;
-// }
+ public String[] getRestricted_to_domain() {
+ return restricted_to_domain;
+ }
-// public void setRestricted_to_domain(String[] restricted_to_domain) {
-// this.restricted_to_domain = restricted_to_domain;
-// }
+ public void setRestricted_to_domain(String[] restricted_to_domain) {
+ this.restricted_to_domain = restricted_to_domain;
+ }
public String getCreated_by() {
return created_by;
@@ -157,21 +155,20 @@ public class Organisation {
@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='" + Arrays.toString(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;
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java b/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
index 43ae978..269bd2a 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/Server.java
@@ -11,25 +11,30 @@ public class Server {
private String url;
private String authkey;
private Integer org_id;
- private Boolean push;
- private Boolean pull;
+ 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;
- private Boolean unpublish_event;
- private Boolean self_signed;
+ 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;
+ private Boolean caching_enabled = false;
private Boolean cache_timestamp;
+ public Server(String url) {
+ this.url = url;
+ }
+
+
public Integer getId() {
return id;
}
@@ -209,29 +214,28 @@ public class Server {
@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;
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/models/restModels/User.java b/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
index 9c1539f..40f840c 100644
--- a/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
+++ b/app/src/main/java/lu/circl/mispbump/models/restModels/User.java
@@ -3,6 +3,8 @@ package lu.circl.mispbump.models.restModels;
import androidx.annotation.NonNull;
+import lu.circl.mispbump.auxiliary.RandomString;
+
public class User {
@@ -30,6 +32,16 @@ public class User {
private String date_modified;
+ 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 Integer getId() {
return id;
}
@@ -210,29 +222,28 @@ public class User {
@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;
}
}
diff --git a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
index 895b1e1..7ae6adf 100644
--- a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
+++ b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
@@ -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";
diff --git a/app/src/main/res/drawable/ic_arrow_down.xml b/app/src/main/res/drawable/ic_arrow_down.xml
new file mode 100644
index 0000000..fb4120e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_cloud_download.xml b/app/src/main/res/drawable/ic_cloud_download.xml
new file mode 100644
index 0000000..33dae95
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cloud_download.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/tooltip_background.xml b/app/src/main/res/drawable/tooltip_background.xml
new file mode 100644
index 0000000..d86b1a2
--- /dev/null
+++ b/app/src/main/res/drawable/tooltip_background.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_network_test.xml b/app/src/main/res/layout/activity_network_test.xml
new file mode 100644
index 0000000..a52bab7
--- /dev/null
+++ b/app/src/main/res/layout/activity_network_test.xml
@@ -0,0 +1,8 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_sync_info_detail.xml b/app/src/main/res/layout/activity_sync_info_detail.xml
new file mode 100644
index 0000000..ed6fd55
--- /dev/null
+++ b/app/src/main/res/layout/activity_sync_info_detail.xml
@@ -0,0 +1,289 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml
index 56efb79..8ea73db 100644
--- a/app/src/main/res/layout/activity_upload.xml
+++ b/app/src/main/res/layout/activity_upload.xml
@@ -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">
-
-
-
-
+ android:theme="@style/ToolbarTheme"
+ app:popupTheme="@style/PopupTheme"/>
-
-
-
-
-
-
-
-
-
-
-
-
+ android:orientation="vertical">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_upload_credentials.xml b/app/src/main/res/layout/fragment_upload_credentials.xml
deleted file mode 100644
index dc2cec0..0000000
--- a/app/src/main/res/layout/fragment_upload_credentials.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_upload_settings.xml b/app/src/main/res/layout/fragment_upload_settings.xml
deleted file mode 100644
index 96b3a08..0000000
--- a/app/src/main/res/layout/fragment_upload_settings.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/material_password_view.xml b/app/src/main/res/layout/material_password_view.xml
index 3350692..6dbff23 100644
--- a/app/src/main/res/layout/material_password_view.xml
+++ b/app/src/main/res/layout/material_password_view.xml
@@ -24,25 +24,13 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
-
-
@@ -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"
diff --git a/app/src/main/res/layout/row_upload_information.xml b/app/src/main/res/layout/row_upload_information.xml
index 6c1b099..260d482 100644
--- a/app/src/main/res/layout/row_upload_information.xml
+++ b/app/src/main/res/layout/row_upload_information.xml
@@ -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">
-
+ app:layout_constraintStart_toStartOf="parent"
+ android:textSize="14sp"
+ tools:text="Aug"/>
+
+
-
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+
diff --git a/app/src/main/res/layout/view_upload_action.xml b/app/src/main/res/layout/view_upload_action.xml
index 5636654..0796856 100644
--- a/app/src/main/res/layout/view_upload_action.xml
+++ b/app/src/main/res/layout/view_upload_action.xml
@@ -10,7 +10,7 @@
android:animateLayoutChanges="true">
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 0a4a7b5..d936fef 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -49,4 +49,5 @@
Allgemein
Besuchen Sie das Github Projekt
App Informationen
+ Synchronisations Details
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 5e0218a..7175677 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -21,8 +21,11 @@
-
-
+
+
+
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 8d311f4..fa4e0ad 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -17,6 +17,10 @@
#F0F0F0
#000
+ #B3000000
+ #80000000
+ #4D000000
+ #1A000000
#4CAF50
#FB8C00
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 55826cb..b49bdc6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -55,4 +55,5 @@
General
App information
Visit the Github project
+ Synchronisation details
diff --git a/build.gradle b/build.gradle
index 76d59b3..02d253b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -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
diff --git a/expandablecardview/.gitignore b/expandablecardview/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/expandablecardview/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/expandablecardview/build.gradle b/expandablecardview/build.gradle
new file mode 100644
index 0000000..8f1186a
--- /dev/null
+++ b/expandablecardview/build.gradle
@@ -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'
+}
diff --git a/expandablecardview/proguard-rules.pro b/expandablecardview/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/expandablecardview/proguard-rules.pro
@@ -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
diff --git a/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java b/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..5363ad2
--- /dev/null
+++ b/expandablecardview/src/androidTest/java/lu/circl/expandablecardview/ExampleInstrumentedTest.java
@@ -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 Testing documentation
+ */
+@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());
+ }
+}
diff --git a/expandablecardview/src/main/AndroidManifest.xml b/expandablecardview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29832b5
--- /dev/null
+++ b/expandablecardview/src/main/AndroidManifest.xml
@@ -0,0 +1 @@
+
diff --git a/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java b/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java
new file mode 100644
index 0000000..6f4ed2f
--- /dev/null
+++ b/expandablecardview/src/main/java/lu/circl/expandablecardview/ExpandableCardView.java
@@ -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);
+ }
+
+}
diff --git a/expandablecardview/src/main/res/drawable/ic_info_outline.xml b/expandablecardview/src/main/res/drawable/ic_info_outline.xml
new file mode 100644
index 0000000..cf53e14
--- /dev/null
+++ b/expandablecardview/src/main/res/drawable/ic_info_outline.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml b/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml
new file mode 100644
index 0000000..ad33063
--- /dev/null
+++ b/expandablecardview/src/main/res/drawable/ic_keyboard_arrow_down.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/expandablecardview/src/main/res/layout/expandable_card_view_header.xml b/expandablecardview/src/main/res/layout/expandable_card_view_header.xml
new file mode 100644
index 0000000..53ce5da
--- /dev/null
+++ b/expandablecardview/src/main/res/layout/expandable_card_view_header.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/expandablecardview/src/main/res/values/attrs.xml b/expandablecardview/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..78a2ccc
--- /dev/null
+++ b/expandablecardview/src/main/res/values/attrs.xml
@@ -0,0 +1,17 @@
+
+
+
+ // general
+
+
+ // header
+
+
+
+
+
+ // content
+
+
+
+
diff --git a/expandablecardview/src/main/res/values/strings.xml b/expandablecardview/src/main/res/values/strings.xml
new file mode 100644
index 0000000..f771913
--- /dev/null
+++ b/expandablecardview/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ ExpandableCardView
+
diff --git a/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java b/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java
new file mode 100644
index 0000000..d16f0c4
--- /dev/null
+++ b/expandablecardview/src/test/java/lu/circl/expandablecardview/ExampleUnitTest.java
@@ -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 Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 4e2d414..faf19fb 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -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
diff --git a/settings.gradle b/settings.gradle
index e7b4def..ff5c4e6 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1 +1 @@
-include ':app'
+include ':app', ':expandablecardview'