mirror of https://github.com/MISP/misp-bump
commit
fad2d28221
|
@ -0,0 +1,116 @@
|
|||
<component name="ProjectCodeStyleConfiguration">
|
||||
<code_scheme name="Project" version="173">
|
||||
<codeStyleSettings language="XML">
|
||||
<indentOptions>
|
||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||
</indentOptions>
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
</component>
|
|
@ -1,4 +1,6 @@
|
|||
# MISPbump
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/72e7c12910284125b6971bb9d9c08229)](https://www.codacy.com/app/felixpk/misp-bump?utm_source=github.com&utm_medium=referral&utm_content=MISP/misp-bump&utm_campaign=Badge_Grade)
|
||||
|
||||
Simple and secure synchronisation of MISP instances
|
||||
|
||||
# What is MISPbump?
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
theme: jekyll-theme-minimal
|
|
@ -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"
|
||||
|
@ -19,6 +19,15 @@ android {
|
|||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = '1.8'
|
||||
targetCompatibility = '1.8'
|
||||
}
|
||||
buildToolsVersion = '29.0.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
@ -29,28 +38,23 @@ dependencies {
|
|||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
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:17.0.2'
|
||||
implementation 'com.google.android.gms:play-services-vision:18.0.0'
|
||||
|
||||
// barcode generation
|
||||
implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar'
|
||||
implementation 'com.google.zxing:core:3.4.0'
|
||||
|
||||
// external
|
||||
implementation 'me.saket:inboxrecyclerview:1.0.0-rc1'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testImplementation 'junit:junit:4.12'
|
||||
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()
|
||||
}
|
||||
|
|
|
@ -3,9 +3,6 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="lu.circl.mispbump">
|
||||
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:hardwareAccelerated="true"
|
||||
|
@ -15,7 +12,8 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:ignore="GoogleAppIndexingWarning">
|
||||
<activity android:name=".activities.StartUpActivity">
|
||||
<activity android:name=".activities.UploadActivity" />
|
||||
<activity android:name=".activities.LauncherActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
@ -35,16 +33,13 @@
|
|||
android:screenOrientation="portrait"
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
<activity
|
||||
android:name=".activities.UploadInfoActivity"
|
||||
android:name=".activities.SyncInfoDetailActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:parentActivityName=".activities.HomeActivity" />
|
||||
<activity
|
||||
android:name=".activities.UploadActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="Upload"
|
||||
android:label="@string/sync_details_activity_label"
|
||||
android:parentActivityName=".activities.HomeActivity" />
|
||||
<activity
|
||||
android:name=".activities.PreferenceActivity"
|
||||
android:label="@string/settings"
|
||||
android:parentActivityName=".activities.HomeActivity" />
|
||||
<activity
|
||||
android:name=".activities.ProfileActivity"
|
||||
|
@ -52,5 +47,8 @@
|
|||
android:parentActivityName=".activities.HomeActivity"
|
||||
android:theme="@style/AppTheme.Translucent" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
</manifest>
|
|
@ -1,11 +1,11 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
|
@ -22,24 +22,22 @@ 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;
|
||||
|
||||
|
||||
public class ExchangeActivity extends AppCompatActivity {
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private QrCodeGenerator qrCodeGenerator;
|
||||
private DiffieHellman diffieHellman;
|
||||
private UploadInformation uploadInformation;
|
||||
|
||||
private CameraFragment cameraFragment;
|
||||
|
||||
|
@ -49,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;
|
||||
|
@ -66,9 +66,11 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
initViews();
|
||||
initCamera();
|
||||
|
||||
uploadInformation = new UploadInformation();
|
||||
publicKeyQr = generatePublicKeyBitmap();
|
||||
|
||||
syncInformation = new SyncInformation();
|
||||
syncInformation.setLocal(generateSyncExchangeInformation());
|
||||
|
||||
setSyncState(SyncState.KEY_EXCHANGE);
|
||||
}
|
||||
|
||||
|
@ -104,43 +106,35 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
private ExchangeInformation generateSyncExchangeInformation() {
|
||||
ExchangeInformation exchangeInformation = new ExchangeInformation();
|
||||
exchangeInformation.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
|
||||
exchangeInformation.setSyncUser(preferenceManager.getUserInfo().toSyncUser());
|
||||
exchangeInformation.setServer(new Server(preferenceManager.getUserCredentials().first));
|
||||
return exchangeInformation;
|
||||
}
|
||||
|
||||
|
||||
private Bitmap generatePublicKeyBitmap() {
|
||||
return qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
|
||||
}
|
||||
|
||||
private Bitmap generateLocalSyncInfoBitmap() {
|
||||
uploadInformation.setLocal(generateLocalSyncInfo());
|
||||
return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(uploadInformation.getLocal())));
|
||||
}
|
||||
|
||||
private SyncInformation generateLocalSyncInfo() {
|
||||
SyncInformation syncInformation = new SyncInformation();
|
||||
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
|
||||
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
|
||||
syncInformation.baseUrl = preferenceManager.getUserCredentials().first;
|
||||
syncInformation.syncUserPassword = new RandomString(16).nextString();
|
||||
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
|
||||
return syncInformation;
|
||||
return qrCodeGenerator.generateQrCode(diffieHellman.encrypt(new Gson().toJson(syncInformation.getLocal())));
|
||||
}
|
||||
|
||||
|
||||
private void showQrCode(final Bitmap bitmap) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread(() -> {
|
||||
qrCode.setImageBitmap(bitmap);
|
||||
qrFrame.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setSyncState(SyncState state) {
|
||||
currentSyncState = state;
|
||||
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
runOnUiThread(() -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
|
||||
|
@ -193,7 +187,6 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
qrContentInfo.setText(R.string.public_key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -244,14 +237,12 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
View view = findViewById(R.id.fragmentContainer);
|
||||
|
||||
if (enabled) {
|
||||
Log.d("DEBUG", "cameraPreview enabled");
|
||||
view.animate()
|
||||
.alpha(1f)
|
||||
.setDuration(250)
|
||||
.start();
|
||||
cameraFragment.setReadQrEnabled(true);
|
||||
} else {
|
||||
Log.d("DEBUG", "cameraPreview disabled");
|
||||
view.animate()
|
||||
.alpha(0f)
|
||||
.setDuration(250)
|
||||
|
@ -262,9 +253,7 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
|
||||
|
||||
private CameraFragment.QrScanCallback onQrScanned() {
|
||||
return new CameraFragment.QrScanCallback() {
|
||||
@Override
|
||||
public void qrScanResult(String qrData) {
|
||||
return qrData -> {
|
||||
cameraFragment.setReadQrEnabled(false);
|
||||
|
||||
switch (currentSyncState) {
|
||||
|
@ -284,34 +273,8 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
break;
|
||||
case DATA_EXCHANGE:
|
||||
try {
|
||||
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
|
||||
|
||||
final List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
|
||||
|
||||
for (final UploadInformation ui : uploadInformationList) {
|
||||
if (ui.getRemote().organisation.getUuid().equals(remoteSyncInfo.organisation.getUuid())) {
|
||||
DialogManager.syncAlreadyExistsDialog(ui.getRemote(), remoteSyncInfo, ExchangeActivity.this, new DialogManager.IDialogFeedback() {
|
||||
@Override
|
||||
public void positive() {
|
||||
// update remote info only
|
||||
uploadInformation.setUuid(ui.getUuid());
|
||||
uploadInformation.setDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void negative() {
|
||||
// replace credentials too
|
||||
uploadInformationList.remove(ui);
|
||||
preferenceManager.setUploadInformationList(uploadInformationList);
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uploadInformation.setRemote(remoteSyncInfo);
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
syncInformation.setRemote(new Gson().fromJson(diffieHellman.decrypt(qrData), ExchangeInformation.class));
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
setSyncState(SyncState.DATA_EXCHANGE_DONE);
|
||||
} catch (JsonSyntaxException e) {
|
||||
if (currentReadQrStatus == ReadQrStatus.PENDING) {
|
||||
|
@ -323,14 +286,11 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private View.OnClickListener onPrevClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
return v -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE:
|
||||
case KEY_EXCHANGE_DONE:
|
||||
|
@ -342,28 +302,22 @@ public class ExchangeActivity extends AppCompatActivity {
|
|||
setSyncState(SyncState.KEY_EXCHANGE_DONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private View.OnClickListener onNextClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
return v -> {
|
||||
switch (currentSyncState) {
|
||||
case KEY_EXCHANGE_DONE:
|
||||
setSyncState(SyncState.DATA_EXCHANGE);
|
||||
break;
|
||||
case DATA_EXCHANGE_DONE:
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.PENDING);
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
Intent i = new Intent(ExchangeActivity.this, UploadInfoActivity.class);
|
||||
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformation.getUuid());
|
||||
Intent i = new Intent(ExchangeActivity.this, SyncInfoDetailActivity.class);
|
||||
i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformation.getUuid());
|
||||
startActivity(i);
|
||||
finish();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -11,38 +11,56 @@ import android.widget.TextView;
|
|||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityOptionsCompat;
|
||||
import androidx.core.util.Pair;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.adapters.UploadInfoAdapter;
|
||||
import lu.circl.mispbump.adapters.SyncInfoAdapter;
|
||||
import lu.circl.mispbump.auxiliary.MispRestClient;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.models.ExchangeInformation;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.restModels.MispServer;
|
||||
import lu.circl.mispbump.models.restModels.MispUser;
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class HomeActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_UPLOAD_INFO = "uploadInformation";
|
||||
|
||||
private List<UploadInformation> uploadInformationList;
|
||||
private List<SyncInformation> syncInformationList;
|
||||
private PreferenceManager preferenceManager;
|
||||
private MispRestClient restClient;
|
||||
|
||||
private RecyclerView recyclerView;
|
||||
private UploadInfoAdapter uploadInfoAdapter;
|
||||
private SyncInfoAdapter syncInfoAdapter;
|
||||
private TextView emptyRecyclerView;
|
||||
|
||||
private SwipeRefreshLayout swipeRefreshLayout;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_home);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(this);
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
initViews();
|
||||
initRecyclerView();
|
||||
checkRequiredInformationAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -53,26 +71,22 @@ public class HomeActivity extends AppCompatActivity {
|
|||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// if (item.getItemId() == R.id.menu_settings) {
|
||||
// startActivity(new Intent(HomeActivity.this, PreferenceActivity.class));
|
||||
// return true;
|
||||
// }
|
||||
if (item.getItemId() == R.id.menu_settings) {
|
||||
startActivity(new Intent(HomeActivity.this, PreferenceActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (item.getItemId() == R.id.menu_profile) {
|
||||
startActivity(new Intent(HomeActivity.this, ProfileActivity.class));
|
||||
return true;
|
||||
}
|
||||
|
||||
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Log.d("DEBUG", "onResume()");
|
||||
|
||||
refreshRecyclerView();
|
||||
}
|
||||
|
||||
|
@ -84,46 +98,188 @@ public class HomeActivity extends AppCompatActivity {
|
|||
setSupportActionBar(myToolbar);
|
||||
|
||||
FloatingActionButton syncFab = findViewById(R.id.home_fab);
|
||||
syncFab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startActivity(new Intent(HomeActivity.this, ExchangeActivity.class));
|
||||
}
|
||||
syncFab.setOnClickListener(v -> startActivity(new Intent(HomeActivity.this, ExchangeActivity.class)));
|
||||
|
||||
swipeRefreshLayout = findViewById(R.id.swipeRefresh);
|
||||
swipeRefreshLayout.setOnRefreshListener(() -> {
|
||||
checkUnimportedSyncs();
|
||||
|
||||
syncInfoAdapter.setItems(syncInformationList);
|
||||
});
|
||||
}
|
||||
|
||||
private void initRecyclerView() {
|
||||
recyclerView = findViewById(R.id.recyclerView);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(HomeActivity.this));
|
||||
uploadInfoAdapter = new UploadInfoAdapter(HomeActivity.this);
|
||||
uploadInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
|
||||
recyclerView.setAdapter(uploadInfoAdapter);
|
||||
syncInfoAdapter = new SyncInfoAdapter(HomeActivity.this);
|
||||
syncInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener());
|
||||
recyclerView.setAdapter(syncInfoAdapter);
|
||||
}
|
||||
|
||||
private void refreshRecyclerView() {
|
||||
uploadInformationList = preferenceManager.getUploadInformationList();
|
||||
syncInformationList = preferenceManager.getSyncInformationList();
|
||||
|
||||
if (uploadInformationList.isEmpty()) {
|
||||
if (syncInformationList.isEmpty()) {
|
||||
emptyRecyclerView.setVisibility(View.VISIBLE);
|
||||
recyclerView.setVisibility(View.GONE);
|
||||
} else {
|
||||
emptyRecyclerView.setVisibility(View.GONE);
|
||||
recyclerView.setVisibility(View.VISIBLE);
|
||||
uploadInfoAdapter.setItems(uploadInformationList);
|
||||
syncInfoAdapter.setItems(syncInformationList);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRequiredInformationAvailable() {
|
||||
if (preferenceManager.getRoles() == null || preferenceManager.getUserInfo() == null || preferenceManager.getUserOrganisation() == null) {
|
||||
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
MispRestClient client = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
// get roles
|
||||
client.getRoles(new MispRestClient.AllRolesCallback() {
|
||||
@Override
|
||||
public void success(Role[] roles) {
|
||||
preferenceManager.setRoles(roles);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
|
||||
// get user and organisation
|
||||
client.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(User user) {
|
||||
preferenceManager.setMyUser(user);
|
||||
|
||||
client.getOrganisation(user.getOrgId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
}
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUnimportedSyncs() {
|
||||
restClient.getAllServers(new MispRestClient.AllRawServersCallback() {
|
||||
@Override
|
||||
public void success(List<MispServer> mispServers) {
|
||||
if (mispServers.size() < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<SyncInformation> syncInformationList = preferenceManager.getSyncInformationList();
|
||||
|
||||
for (MispServer mispServer : mispServers) {
|
||||
|
||||
boolean existsOffline = false;
|
||||
|
||||
for (SyncInformation syncInformation : syncInformationList) {
|
||||
int localServerId = syncInformation.getRemote().getServer().getId();
|
||||
int remoteServerId = mispServer.getServer().getId();
|
||||
|
||||
if (remoteServerId == localServerId) {
|
||||
existsOffline = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!existsOffline) {
|
||||
// mispServer is not locally available
|
||||
SyncInformation syncInformation = new SyncInformation();
|
||||
|
||||
ExchangeInformation local = new ExchangeInformation();
|
||||
local.setOrganisation(preferenceManager.getUserOrganisation().toSyncOrganisation());
|
||||
User syncUser = preferenceManager.getUserInfo().toSyncUser();
|
||||
syncUser.setAuthkey("Could not be recovered");
|
||||
syncUser.setPassword("Could not be recovered");
|
||||
local.setSyncUser(syncUser);
|
||||
local.setServer(new Server(preferenceManager.getUserCredentials().first));
|
||||
|
||||
ExchangeInformation remote = new ExchangeInformation();
|
||||
remote.setServer(mispServer.getServer());
|
||||
|
||||
restClient.getOrganisation(mispServer.getRemoteOrganisation().getId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
remote.setOrganisation(organisation);
|
||||
|
||||
restClient.getAllUsers(new MispRestClient.AllMispUsersCallback() {
|
||||
@Override
|
||||
public void success(List<MispUser> users) {
|
||||
for (MispUser mispUser : users) {
|
||||
|
||||
boolean isSyncUserRole = false;
|
||||
|
||||
Role[] roles = preferenceManager.getRoles();
|
||||
|
||||
for (Role role : roles) {
|
||||
if (role.getId().equals(mispUser.getRole().getId())) {
|
||||
isSyncUserRole = role.isSyncUserRole();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mispUser.getOrganisation().getId().equals(organisation.getId()) && isSyncUserRole) {
|
||||
remote.setSyncUser(mispUser.getUser());
|
||||
|
||||
syncInformation.setLocal(local);
|
||||
syncInformation.setRemote(remote);
|
||||
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
refreshRecyclerView();
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
Snackbar.make(recyclerView, error, Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
Snackbar.make(swipeRefreshLayout, error, Snackbar.LENGTH_SHORT).show();
|
||||
swipeRefreshLayout.setRefreshing(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerItemClickListener() {
|
||||
return new OnRecyclerItemClickListener<Integer>() {
|
||||
@Override
|
||||
public void onClick(View v, Integer index) {
|
||||
Intent i = new Intent(HomeActivity.this, UploadInfoActivity.class);
|
||||
i.putExtra(UploadInfoActivity.EXTRA_UPLOAD_INFO_UUID, uploadInformationList.get(index).getUuid());
|
||||
return (v, index) -> {
|
||||
Intent i = new Intent(HomeActivity.this, SyncInfoDetailActivity.class);
|
||||
i.putExtra(SyncInfoDetailActivity.EXTRA_SYNC_INFO_UUID, syncInformationList.get(index).getUuid());
|
||||
|
||||
ActivityOptionsCompat options = ActivityOptionsCompat.makeClipRevealAnimation(v.findViewById(R.id.rootLayout), (int) v.getX(), (int) v.getY(), v.getWidth(), v.getHeight());
|
||||
startActivity(i, options.toBundle());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
|
@ -7,10 +8,11 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
|
||||
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) {
|
||||
|
@ -24,7 +26,7 @@ public class StartUpActivity extends AppCompatActivity {
|
|||
startActivity(login);
|
||||
}
|
||||
|
||||
// closes the activity to prevent going back to this (empty) activity
|
||||
// close activity to prevent going back
|
||||
finish();
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -28,6 +28,7 @@ import lu.circl.mispbump.models.restModels.Organisation;
|
|||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class LoginActivity extends AppCompatActivity {
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
|
@ -130,9 +131,9 @@ public class LoginActivity extends AppCompatActivity {
|
|||
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(final User user) {
|
||||
preferenceManager.setUserInfo(user);
|
||||
preferenceManager.setMyUser(user);
|
||||
for (Role role : roles) {
|
||||
if (role.getId().equals(user.role_id)) {
|
||||
if (role.getId().equals(user.getRoleId())) {
|
||||
if (!role.getPermAdmin()) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
Snackbar.make(constraintLayout, "No admin is associated with this authkey.", Snackbar.LENGTH_LONG).show();
|
||||
|
@ -141,10 +142,10 @@ public class LoginActivity extends AppCompatActivity {
|
|||
}
|
||||
}
|
||||
|
||||
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
||||
mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
preferenceManager.setUserOrgInfo(organisation);
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
preferenceManager.setUserCredentials(url, authkey);
|
||||
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
@ -188,10 +189,8 @@ public class LoginActivity extends AppCompatActivity {
|
|||
};
|
||||
|
||||
/**
|
||||
* TODO: Check if url is valid.
|
||||
*
|
||||
* @param url url to check
|
||||
* @return true or false
|
||||
* @return true if valid else false
|
||||
*/
|
||||
private boolean isValidUrl(String url) {
|
||||
Uri uri = Uri.parse(url);
|
||||
|
@ -204,12 +203,10 @@ public class LoginActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO: Check if automation key is valid.
|
||||
*
|
||||
* @param automationKey the key to check
|
||||
* @return true or false
|
||||
* @return true if not empty else false
|
||||
*/
|
||||
private boolean isValidAutomationKey(String automationKey) {
|
||||
return !TextUtils.isEmpty(automationKey);
|
||||
return !automationKey.isEmpty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
|
||||
|
||||
public class PreferenceActivity extends AppCompatActivity {
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
|
@ -24,12 +30,36 @@ public class PreferenceActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void initializeViews() {
|
||||
Button deleteSyncs = findViewById(R.id.deleteSyncs);
|
||||
deleteSyncs.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
preferenceManager.clearUploadInformation();
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
|
||||
PreferencesFragment preferencesFragment = new PreferencesFragment();
|
||||
// preferencesFragment.onDeleteAllSyncsListener = preference -> {
|
||||
// preferenceManager.clearUploadInformation();
|
||||
// return true;
|
||||
// };
|
||||
|
||||
fragmentTransaction.add(R.id.fragmentContainer, preferencesFragment, PreferencesFragment.class.getSimpleName());
|
||||
fragmentTransaction.commit();
|
||||
}
|
||||
|
||||
public static class PreferencesFragment extends PreferenceFragmentCompat {
|
||||
|
||||
private Preference.OnPreferenceClickListener onDeleteAllSyncsListener;
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.preference_screen_main, rootKey);
|
||||
|
||||
// Preference deleteAllSyncInfo = findPreference("PREF_DELETE_ALL_SYNCS");
|
||||
// assert deleteAllSyncInfo != null;
|
||||
// deleteAllSyncInfo.setOnPreferenceClickListener(onDeleteAllSyncsListener);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
|
@ -34,6 +34,7 @@ import lu.circl.mispbump.models.restModels.Role;
|
|||
import lu.circl.mispbump.models.restModels.User;
|
||||
import lu.circl.mispbump.security.KeyStoreWrapper;
|
||||
|
||||
|
||||
public class ProfileActivity extends AppCompatActivity {
|
||||
|
||||
private CoordinatorLayout rootLayout;
|
||||
|
@ -43,6 +44,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
private FloatingActionButton fab;
|
||||
private AnimatedVectorDrawable fabLoadingDrawable;
|
||||
|
||||
private View.OnClickListener onFabClicked = view -> {
|
||||
fab.setImageDrawable(fabLoadingDrawable);
|
||||
fabLoadingDrawable.start();
|
||||
updateProfileInformation();
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -52,55 +59,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
init();
|
||||
initToolbar();
|
||||
initViews();
|
||||
|
||||
populateInformationViews();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
rootLayout = findViewById(R.id.rootLayout);
|
||||
|
||||
ImageView headerBg = findViewById(R.id.headerBg);
|
||||
headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
|
||||
|
||||
// populate Toolbar (Actionbar)
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(onFabClicked());
|
||||
|
||||
fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
|
||||
}
|
||||
|
||||
private void populateInformationViews() {
|
||||
Organisation organisation = preferenceManager.getUserOrganisation();
|
||||
|
||||
TextView name = findViewById(R.id.orgName);
|
||||
name.setText(organisation.getName());
|
||||
|
||||
final MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(organisation.getUuid());
|
||||
|
||||
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
||||
nationality.setSubtitle(organisation.getNationality());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
if (organisation.getSector() == null) {
|
||||
sector.setVisibility(View.GONE);
|
||||
} else {
|
||||
sector.setSubtitle(organisation.getSector());
|
||||
}
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(organisation.getDescription());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_profile, menu);
|
||||
|
@ -117,23 +81,51 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private View.OnClickListener onFabClicked() {
|
||||
return new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
fab.setImageDrawable(fabLoadingDrawable);
|
||||
fabLoadingDrawable.start();
|
||||
updateProfile();
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Drawable getRandomHeader() {
|
||||
int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
|
||||
return getDrawable(ids[new Random().nextInt(ids.length)]);
|
||||
private void initViews() {
|
||||
rootLayout = findViewById(R.id.rootLayout);
|
||||
|
||||
ImageView headerBg = findViewById(R.id.headerBg);
|
||||
headerBg.setImageDrawable(new TileDrawable(getRandomHeader(), Shader.TileMode.REPEAT));
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(onFabClicked);
|
||||
|
||||
fabLoadingDrawable = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_sync);
|
||||
}
|
||||
|
||||
public void updateProfile() {
|
||||
private void populateInformationViews() {
|
||||
Organisation organisation = preferenceManager.getUserOrganisation();
|
||||
|
||||
TextView name = findViewById(R.id.orgName);
|
||||
name.setText(organisation.getName());
|
||||
|
||||
final MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(organisation.getUuid());
|
||||
|
||||
MaterialPreferenceText nationality = findViewById(R.id.nationality);
|
||||
nationality.setSubtitle(organisation.getNationality());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
sector.setSubtitle(organisation.getSector());
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(organisation.getDescription());
|
||||
}
|
||||
|
||||
|
||||
public void updateProfileInformation() {
|
||||
mispRestClient.getRoles(new MispRestClient.AllRolesCallback() {
|
||||
@Override
|
||||
public void success(Role[] roles) {
|
||||
|
@ -149,12 +141,12 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(final User user) {
|
||||
preferenceManager.setUserInfo(user);
|
||||
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
|
||||
preferenceManager.setMyUser(user);
|
||||
mispRestClient.getOrganisation(user.getRoleId(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
fabLoadingDrawable.stop();
|
||||
preferenceManager.setUserOrgInfo(organisation);
|
||||
preferenceManager.setMyOrganisation(organisation);
|
||||
Snackbar.make(rootLayout, "Successfully update profile", Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
|
@ -179,25 +171,23 @@ public class ProfileActivity extends AppCompatActivity {
|
|||
|
||||
builder.setTitle("Clear all saved data and logout");
|
||||
builder.setMessage("Do you really want to delete all data and logout?");
|
||||
builder.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton("Discard", (dialog, which) -> dialog.cancel());
|
||||
|
||||
builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
builder.setPositiveButton("Delete & Logout", (dialog, which) -> {
|
||||
preferenceManager.clearAllData();
|
||||
KeyStoreWrapper.deleteAllStoredKeys();
|
||||
|
||||
Intent login = new Intent(getApplicationContext(), LoginActivity.class);
|
||||
startActivity(login);
|
||||
finish();
|
||||
}
|
||||
});
|
||||
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
|
||||
private Drawable getRandomHeader() {
|
||||
int[] ids = {R.drawable.ic_bank_note, R.drawable.ic_polka_dots, R.drawable.ic_wiggle, R.drawable.ic_circuit_board};
|
||||
return getDrawable(ids[new Random().nextInt(ids.length)]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,277 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
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.MaterialPreferenceSwitch;
|
||||
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;
|
||||
private boolean dataLocallyChanged;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_sync_info_detail_v2);
|
||||
|
||||
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();
|
||||
|
||||
if (dataLocallyChanged) {
|
||||
syncInformation.setSyncedWithRemote(false);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
TextView uploadText = findViewById(R.id.fab_upload_text);
|
||||
TextView downloadText = findViewById(R.id.fab_download_text);
|
||||
|
||||
View menuBackground = findViewById(R.id.menu_background);
|
||||
|
||||
uploadLayout.setVisibility(View.GONE);
|
||||
downloadLayout.setVisibility(View.GONE);
|
||||
|
||||
int animationSpeed = 200;
|
||||
|
||||
ValueAnimator openAnimation = ValueAnimator.ofFloat(0f, 1f);
|
||||
openAnimation.setDuration(animationSpeed);
|
||||
openAnimation.setInterpolator(new DecelerateInterpolator());
|
||||
openAnimation.addUpdateListener(updateAnimation -> {
|
||||
float x = (float) updateAnimation.getAnimatedValue();
|
||||
|
||||
fabUpload.setAlpha(x);
|
||||
fabUpload.setTranslationY((1 - x) * 50);
|
||||
uploadText.setAlpha(x);
|
||||
uploadText.setTranslationX((1 - x) * -200);
|
||||
|
||||
fabDownload.setAlpha(x);
|
||||
fabDownload.setTranslationY((1 - x) * 50);
|
||||
downloadText.setAlpha(x);
|
||||
downloadText.setTranslationX((1 - x) * -200);
|
||||
|
||||
menuBackground.setAlpha(x * 0.9f);
|
||||
});
|
||||
openAnimation.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
uploadLayout.setVisibility(View.VISIBLE);
|
||||
downloadLayout.setVisibility(View.VISIBLE);
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
}
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animator) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animator) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
ValueAnimator closeAnimation = ValueAnimator.ofFloat(1f, 0f);
|
||||
closeAnimation.setDuration(animationSpeed);
|
||||
closeAnimation.setInterpolator(new DecelerateInterpolator());
|
||||
closeAnimation.addUpdateListener(updateAnimation -> {
|
||||
float x = (float) updateAnimation.getAnimatedValue();
|
||||
|
||||
fabUpload.setAlpha(x);
|
||||
fabUpload.setTranslationY((1 - x) * 50);
|
||||
uploadText.setAlpha(x);
|
||||
uploadText.setTranslationX((1 - x) * -200);
|
||||
|
||||
fabDownload.setAlpha(x);
|
||||
fabDownload.setTranslationY((1 - x) * 50);
|
||||
downloadText.setAlpha(x);
|
||||
downloadText.setTranslationX((1 - x) * -200);
|
||||
|
||||
menuBackground.setAlpha(x * 0.9f);
|
||||
});
|
||||
closeAnimation.addListener(new Animator.AnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
uploadLayout.setVisibility(View.VISIBLE);
|
||||
downloadLayout.setVisibility(View.VISIBLE);
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animator) {
|
||||
uploadLayout.setVisibility(View.GONE);
|
||||
downloadLayout.setVisibility(View.GONE);
|
||||
}
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animator) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animator) {
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
AnimatedVectorDrawable open = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_arrow_cloud_down);
|
||||
AnimatedVectorDrawable close = (AnimatedVectorDrawable) getDrawable(R.drawable.animated_arrow_down_cloud);
|
||||
|
||||
View.OnClickListener expandCollapseClick = view -> {
|
||||
if (fabMenuExpanded) {
|
||||
menuBackground.setClickable(false);
|
||||
|
||||
fab.setImageDrawable(close);
|
||||
close.start();
|
||||
|
||||
closeAnimation.start();
|
||||
fabMenuExpanded = false;
|
||||
} else {
|
||||
menuBackground.setClickable(true);
|
||||
|
||||
fab.setImageDrawable(open);
|
||||
open.start();
|
||||
|
||||
openAnimation.start();
|
||||
fabMenuExpanded = true;
|
||||
}
|
||||
};
|
||||
|
||||
menuBackground.setOnClickListener(expandCollapseClick);
|
||||
menuBackground.setClickable(false);
|
||||
fab.setOnClickListener(expandCollapseClick);
|
||||
|
||||
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 -> {
|
||||
// TODO download content from MISP instance
|
||||
Snackbar.make(view, "Not implemented yet", Snackbar.LENGTH_LONG).show();
|
||||
});
|
||||
}
|
||||
|
||||
private void populateContent() {
|
||||
|
||||
// information
|
||||
|
||||
MaterialPreferenceText name = findViewById(R.id.name);
|
||||
name.setSubtitle(syncInformation.getRemote().getOrganisation().getName());
|
||||
|
||||
MaterialPreferenceText uuid = findViewById(R.id.uuid);
|
||||
uuid.setSubtitle(syncInformation.getRemote().getOrganisation().getUuid());
|
||||
|
||||
MaterialPreferenceText sector = findViewById(R.id.sector);
|
||||
sector.setSubtitle(syncInformation.getRemote().getOrganisation().getSector());
|
||||
|
||||
MaterialPreferenceText description = findViewById(R.id.description);
|
||||
description.setSubtitle(syncInformation.getRemote().getOrganisation().getDescription());
|
||||
|
||||
// settings
|
||||
|
||||
MaterialPreferenceSwitch allowSelfSigned = findViewById(R.id.switch_allow_self_signed);
|
||||
allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned());
|
||||
allowSelfSigned.setOnCheckedChangeListener((cb, b) -> {
|
||||
syncInformation.getRemote().getServer().setSelfSigned(b);
|
||||
dataLocallyChanged = true;
|
||||
});
|
||||
|
||||
MaterialPreferenceSwitch allowPush = findViewById(R.id.switch_allow_push);
|
||||
allowPush.setChecked(syncInformation.getRemote().getServer().getPush());
|
||||
allowPush.setOnCheckedChangeListener((cb, b) -> {
|
||||
syncInformation.getRemote().getServer().setPush(b);
|
||||
dataLocallyChanged = true;
|
||||
});
|
||||
|
||||
MaterialPreferenceSwitch allowPull = findViewById(R.id.switch_allow_pull);
|
||||
allowPull.setChecked(syncInformation.getRemote().getServer().getPull());
|
||||
allowPull.setOnCheckedChangeListener((cb, b) -> {
|
||||
syncInformation.getRemote().getServer().setPull(b);
|
||||
dataLocallyChanged = true;
|
||||
});
|
||||
|
||||
MaterialPreferenceSwitch allowCache = findViewById(R.id.switch_allow_cache);
|
||||
allowCache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
allowCache.setOnCheckedChangeListener((cb, b) -> {
|
||||
syncInformation.getRemote().getServer().setCachingEnabled(b);
|
||||
dataLocallyChanged = true;
|
||||
});
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
|
@ -1,38 +1,95 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.MispRestClient;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.customViews.UploadAction;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
import lu.circl.mispbump.customViews.ProgressActionView;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Role;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class UploadActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_UPLOAD_INFO = "uploadInformation";
|
||||
public static final String EXTRA_SYNC_INFO_UUID = "EXTRA_SYNC_INFO_UUID";
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private UploadInformation uploadInformation;
|
||||
private MispRestClient mispRest;
|
||||
private SyncInformation syncInformation;
|
||||
|
||||
private ProgressActionView availableAction, organisationAction, userAction, serverAction;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
|
||||
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
mispRest = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
parseExtra();
|
||||
initToolbar();
|
||||
initProgressActionViews();
|
||||
startUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
String syncInfoUuid = i.getStringExtra(EXTRA_SYNC_INFO_UUID);
|
||||
syncInformation = preferenceManager.getSyncInformation(UUID.fromString(syncInfoUuid));
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(myToolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setDisplayShowTitleEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void initProgressActionViews() {
|
||||
availableAction = findViewById(R.id.availableProgressAction);
|
||||
organisationAction = findViewById(R.id.organisationProgressAction);
|
||||
userAction = findViewById(R.id.userProgressAction);
|
||||
serverAction = findViewById(R.id.serverProgressAction);
|
||||
|
||||
availableAction.pending();
|
||||
organisationAction.pending();
|
||||
userAction.pending();
|
||||
serverAction.pending();
|
||||
}
|
||||
|
||||
private MispRestClient restClient;
|
||||
private UploadAction availableAction, orgAction, userAction, serverAction;
|
||||
|
||||
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
|
||||
@Override
|
||||
|
@ -90,187 +147,70 @@ public class UploadActivity extends AppCompatActivity {
|
|||
}
|
||||
};
|
||||
|
||||
private FloatingActionButton fab;
|
||||
|
||||
private boolean errorWhileUpload;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
|
||||
Pair<String, String> credentials = preferenceManager.getUserCredentials();
|
||||
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
|
||||
|
||||
parseExtra();
|
||||
initViews();
|
||||
startUpload();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
saveCurrentState();
|
||||
finish();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
saveCurrentState();
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
|
||||
UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO);
|
||||
|
||||
for (UploadInformation ui : preferenceManager.getUploadInformationList()) {
|
||||
if (ui.getUuid().compareTo(currentUUID) == 0) {
|
||||
uploadInformation = ui;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadInformation == null) {
|
||||
throw new RuntimeException("Could not find UploadInfo with UUID {" + currentUUID.toString() + "}");
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
|
||||
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.hide();
|
||||
|
||||
// toolbar
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
|
||||
ab.setDisplayShowTitleEnabled(false);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
|
||||
availableAction = findViewById(R.id.availableAction);
|
||||
orgAction = findViewById(R.id.orgAction);
|
||||
userAction = findViewById(R.id.userAction);
|
||||
serverAction = findViewById(R.id.serverAction);
|
||||
}
|
||||
|
||||
private void saveCurrentState() {
|
||||
if (errorWhileUpload) {
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||
}
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
}
|
||||
|
||||
private void setUploadActionState(UploadAction uploadAction, UploadAction.UploadState state, @Nullable String error) {
|
||||
uploadAction.setCurrentUploadState(state);
|
||||
uploadAction.setError(error);
|
||||
|
||||
switch (state) {
|
||||
case PENDING:
|
||||
if (fab.isShown()) {
|
||||
fab.hide();
|
||||
}
|
||||
break;
|
||||
case LOADING:
|
||||
errorWhileUpload = false;
|
||||
if (fab.isShown()) {
|
||||
fab.hide();
|
||||
}
|
||||
break;
|
||||
case DONE:
|
||||
errorWhileUpload = false;
|
||||
break;
|
||||
case ERROR:
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
|
||||
|
||||
fab.setImageResource(R.drawable.ic_autorenew);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.LOADING, null);
|
||||
startUpload();
|
||||
}
|
||||
});
|
||||
if (!fab.isShown()) {
|
||||
fab.show();
|
||||
}
|
||||
errorWhileUpload = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private User generateSyncUser(Organisation organisation) {
|
||||
User syncUser = new User();
|
||||
syncUser.org_id = organisation.getId();
|
||||
syncUser.role_id = User.ROLE_SYNC_USER;
|
||||
syncUser.email = uploadInformation.getRemote().syncUserEmail;
|
||||
syncUser.password = uploadInformation.getRemote().syncUserPassword;
|
||||
syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
|
||||
syncUser.termsaccepted = true;
|
||||
User syncUser = syncInformation.getRemote().getSyncUser();
|
||||
|
||||
syncUser.setOrgId(organisation.getId());
|
||||
syncUser.setTermsAccepted(true);
|
||||
|
||||
Role[] roles = preferenceManager.getRoles();
|
||||
for (Role role : roles) {
|
||||
if (role.isSyncUserRole()) {
|
||||
syncUser.setRoleId(role.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return syncUser;
|
||||
}
|
||||
|
||||
private Server generateSyncServer() {
|
||||
Server server = new Server();
|
||||
server.name = uploadInformation.getRemote().organisation.getName() + "'s Sync Server";
|
||||
server.url = uploadInformation.getRemote().baseUrl;
|
||||
server.remote_org_id = uploadInformation.getRemote().organisation.getId();
|
||||
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
|
||||
server.pull = uploadInformation.isPull();
|
||||
server.push = uploadInformation.isPush();
|
||||
server.caching_enabled = uploadInformation.isCached();
|
||||
server.self_signed = uploadInformation.isAllowSelfSigned();
|
||||
Server server = syncInformation.getRemote().getServer();
|
||||
server.setName(syncInformation.getRemote().getOrganisation().getName() + "'s Sync Server");
|
||||
server.setRemoteOrgId(syncInformation.getRemote().getOrganisation().getId());
|
||||
server.setAuthkey(syncInformation.getRemote().getSyncUser().getAuthkey());
|
||||
server.setPull(syncInformation.getRemote().getServer().getPull());
|
||||
server.setPush(syncInformation.getRemote().getServer().getPush());
|
||||
server.setCachingEnabled(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
server.setSelfSigned(syncInformation.getRemote().getServer().getCachingEnabled());
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start upload to misp instance.
|
||||
*/
|
||||
private void startUpload() {
|
||||
availableAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
|
||||
restClient.isAvailable(availableCallback);
|
||||
availableAction.start();
|
||||
mispRest.isAvailable(availableCallback);
|
||||
}
|
||||
|
||||
private void mispAvailable(boolean available, String error) {
|
||||
if (available) {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.DONE, null);
|
||||
restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
|
||||
availableAction.done();
|
||||
organisationAction.start();
|
||||
|
||||
mispRest.addOrganisation(syncInformation.getRemote().getOrganisation(), organisationCallback);
|
||||
} else {
|
||||
setUploadActionState(availableAction, UploadAction.UploadState.ERROR, error);
|
||||
availableAction.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
private void organisationAdded(Organisation organisation) {
|
||||
if (organisation != null) {
|
||||
setUploadActionState(orgAction, UploadAction.UploadState.DONE, null);
|
||||
uploadInformation.getRemote().organisation.setId(organisation.getId());
|
||||
restClient.addUser(generateSyncUser(organisation), userCallback);
|
||||
organisationAction.done();
|
||||
userAction.start();
|
||||
|
||||
syncInformation.getRemote().getOrganisation().setId(organisation.getId());
|
||||
mispRest.addUser(generateSyncUser(organisation), userCallback);
|
||||
} else {
|
||||
// search by UUID because the error does not give the actual ID
|
||||
restClient.getOrganisation(uploadInformation.getRemote().organisation.getUuid(), new MispRestClient.OrganisationCallback() {
|
||||
mispRest.getOrganisation(syncInformation.getRemote().getOrganisation().getUuid(), new MispRestClient.OrganisationCallback() {
|
||||
@Override
|
||||
public void success(Organisation organisation) {
|
||||
organisationAdded(organisation);
|
||||
organisationAction.done("Organisation already on MISP instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
setUploadActionState(orgAction, UploadAction.UploadState.ERROR, error);
|
||||
organisationAction.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -278,18 +218,21 @@ public class UploadActivity extends AppCompatActivity {
|
|||
|
||||
private void userAdded(User user) {
|
||||
if (user != null) {
|
||||
setUploadActionState(userAction, UploadAction.UploadState.DONE, null);
|
||||
restClient.getAllServers(allServersCallback);
|
||||
userAction.done();
|
||||
serverAction.start();
|
||||
|
||||
mispRest.getAllServers(allServersCallback);
|
||||
} else {
|
||||
restClient.getUser(uploadInformation.getRemote().syncUserEmail, new MispRestClient.UserCallback() {
|
||||
mispRest.getUser(syncInformation.getLocal().getSyncUser().getEmail(), new MispRestClient.UserCallback() {
|
||||
@Override
|
||||
public void success(User user) {
|
||||
userAdded(user);
|
||||
userAction.done("User already on MISP instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failure(String error) {
|
||||
setUploadActionState(userAction, UploadAction.UploadState.ERROR, error);
|
||||
userAction.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -300,35 +243,25 @@ public class UploadActivity extends AppCompatActivity {
|
|||
Server serverToUpload = generateSyncServer();
|
||||
|
||||
for (Server server : servers) {
|
||||
if (server.remote_org_id.equals(serverToUpload.remote_org_id)) {
|
||||
if (server.getRemoteOrgId().equals(serverToUpload.getRemoteOrgId())) {
|
||||
// server already exists: override id to update instead
|
||||
serverToUpload.id = server.id;
|
||||
serverToUpload.setId(server.getId());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
restClient.addServer(serverToUpload, serverCallback);
|
||||
mispRest.addServer(serverToUpload, serverCallback);
|
||||
} else {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not retrieve server information");
|
||||
serverAction.error("Unknown error while creating the Sync Server");
|
||||
}
|
||||
}
|
||||
|
||||
private void serverAdded(Server server) {
|
||||
if (server != null) {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.DONE, null);
|
||||
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
|
||||
saveCurrentState();
|
||||
|
||||
fab.setImageResource(R.drawable.ic_check);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
fab.show();
|
||||
serverAction.done();
|
||||
preferenceManager.addSyncInformation(syncInformation);
|
||||
} else {
|
||||
setUploadActionState(serverAction, UploadAction.UploadState.ERROR, "Could not add server");
|
||||
serverAction.error("Could not create Sync Server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,266 +0,0 @@
|
|||
package lu.circl.mispbump.activities;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.auxiliary.DialogManager;
|
||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||
import lu.circl.mispbump.fragments.UploadCredentialsFragment;
|
||||
import lu.circl.mispbump.fragments.UploadSettingsFragment;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
public class UploadInfoActivity extends AppCompatActivity {
|
||||
|
||||
public static String EXTRA_UPLOAD_INFO_UUID = "uploadInformationUuid";
|
||||
|
||||
private PreferenceManager preferenceManager;
|
||||
private UploadInformation uploadInformation;
|
||||
private ViewPagerAdapter viewPagerAdapter;
|
||||
|
||||
private FloatingActionButton fab;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_upload_information);
|
||||
|
||||
preferenceManager = PreferenceManager.getInstance(UploadInfoActivity.this);
|
||||
|
||||
// tint statusBar
|
||||
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
|
||||
// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
|
||||
|
||||
parseExtra();
|
||||
initToolbar();
|
||||
initViewPager();
|
||||
initViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
// refresh current uploadInformation
|
||||
if (uploadInformation != null) {
|
||||
uploadInformation = preferenceManager.getUploadInformation(uploadInformation.getUuid());
|
||||
initContent();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
saveCurrentSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_upload_info, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.delete:
|
||||
DialogManager.deleteSyncInformationDialog(UploadInfoActivity.this, new DialogManager.IDialogFeedback() {
|
||||
@Override
|
||||
public void positive() {
|
||||
preferenceManager.removeUploadInformation(uploadInformation.getUuid());
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void negative() {}
|
||||
});
|
||||
|
||||
return true;
|
||||
|
||||
case android.R.id.home:
|
||||
saveCurrentSettings();
|
||||
finish();
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void parseExtra() {
|
||||
Intent i = getIntent();
|
||||
|
||||
UUID currentUUID = (UUID) i.getSerializableExtra(EXTRA_UPLOAD_INFO_UUID);
|
||||
uploadInformation = preferenceManager.getUploadInformation(currentUUID);
|
||||
|
||||
if (uploadInformation == null) {
|
||||
throw new RuntimeException("Could not find UploadInformation with UUID {" + currentUUID.toString() + "}");
|
||||
}
|
||||
}
|
||||
|
||||
private void initToolbar() {
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
ActionBar ab = getSupportActionBar();
|
||||
assert ab != null;
|
||||
|
||||
TextView toolbarTitle = findViewById(R.id.toolbarTitle);
|
||||
toolbarTitle.setText(uploadInformation.getRemote().organisation.getName());
|
||||
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_close);
|
||||
|
||||
ab.setDisplayShowTitleEnabled(false);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void initViewPager() {
|
||||
ViewPager viewPager = findViewById(R.id.viewPager);
|
||||
TabLayout tabLayout = findViewById(R.id.tabLayout);
|
||||
|
||||
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), uploadInformation);
|
||||
viewPager.setAdapter(viewPagerAdapter);
|
||||
|
||||
viewPager.addOnPageChangeListener(onPageChangeListener());
|
||||
|
||||
tabLayout.setupWithViewPager(viewPager);
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
fab = findViewById(R.id.fab);
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// for the UploadActivity to have the latest settings of this UploadInfoObject
|
||||
saveCurrentSettings();
|
||||
|
||||
Intent i = new Intent(UploadInfoActivity.this, UploadActivity.class);
|
||||
i.putExtra(UploadActivity.EXTRA_UPLOAD_INFO, uploadInformation.getUuid());
|
||||
startActivity(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void initContent() {
|
||||
switch (uploadInformation.getCurrentSyncStatus()) {
|
||||
case COMPLETE:
|
||||
|
||||
break;
|
||||
|
||||
case FAILURE:
|
||||
|
||||
break;
|
||||
|
||||
case PENDING:
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void saveCurrentSettings() {
|
||||
uploadInformation.setAllowSelfSigned(viewPagerAdapter.uploadSettingsFragment.getAllowSelfSigned());
|
||||
uploadInformation.setPull(viewPagerAdapter.uploadSettingsFragment.getPull());
|
||||
uploadInformation.setPush(viewPagerAdapter.uploadSettingsFragment.getPush());
|
||||
uploadInformation.setCached(viewPagerAdapter.uploadSettingsFragment.getCache());
|
||||
|
||||
preferenceManager.addUploadInformation(uploadInformation);
|
||||
}
|
||||
|
||||
|
||||
private ViewPager.OnPageChangeListener onPageChangeListener() {
|
||||
return new ViewPager.OnPageChangeListener() {
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (position == 0) {
|
||||
float scale = (1 - positionOffset);
|
||||
fab.setScaleX(scale);
|
||||
fab.setScaleY(scale);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class ViewPagerAdapter extends FragmentPagerAdapter {
|
||||
|
||||
private UploadSettingsFragment uploadSettingsFragment;
|
||||
private UploadCredentialsFragment uploadCredentialsFragment;
|
||||
|
||||
ViewPagerAdapter(@NonNull FragmentManager fm, UploadInformation uploadInformation) {
|
||||
super(fm, ViewPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
uploadSettingsFragment = new UploadSettingsFragment(uploadInformation);
|
||||
uploadCredentialsFragment = new UploadCredentialsFragment(uploadInformation);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return uploadSettingsFragment;
|
||||
|
||||
case 1:
|
||||
return uploadCredentialsFragment;
|
||||
|
||||
default:
|
||||
uploadSettingsFragment = new UploadSettingsFragment();
|
||||
return uploadSettingsFragment;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return getString(R.string.settings);
|
||||
|
||||
case 1:
|
||||
return getString(R.string.credentials);
|
||||
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
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.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.SyncInformation;
|
||||
|
||||
|
||||
public class SyncInfoAdapter extends RecyclerView.Adapter<SyncInfoAdapter.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<SyncInformation> items;
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener;
|
||||
|
||||
|
||||
public SyncInfoAdapter(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public SyncInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
|
||||
return new SyncInfoAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final SyncInfoAdapter.ViewHolder holder, final int position) {
|
||||
final SyncInformation item = items.get(position);
|
||||
|
||||
SimpleDateFormat monthFormatter = new SimpleDateFormat("MMM", Locale.getDefault());
|
||||
SimpleDateFormat dayFormatter = new SimpleDateFormat("dd", Locale.getDefault());
|
||||
|
||||
holder.dateMonth.setText(monthFormatter.format(item.getSyncDate()));
|
||||
holder.dateDay.setText(dayFormatter.format(item.getSyncDate()));
|
||||
|
||||
holder.orgName.setText(item.getRemote().getOrganisation().getName());
|
||||
|
||||
if (item.isSyncedWithRemote()) {
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
|
||||
} else {
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||
}
|
||||
|
||||
// switch (item.getCurrentSyncStatus()) {
|
||||
// case COMPLETE:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
|
||||
// break;
|
||||
// case FAILURE:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||
// break;
|
||||
// case PENDING:
|
||||
// ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
// holder.syncStatus.setImageResource(R.drawable.ic_pending);
|
||||
// break;
|
||||
// }
|
||||
|
||||
holder.rootView.setOnClickListener(view -> onRecyclerPositionClickListener.onClick(view, position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (items == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return items.size();
|
||||
}
|
||||
|
||||
|
||||
public void setItems(List<SyncInformation> items) {
|
||||
this.items = items;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener) {
|
||||
this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
|
||||
}
|
||||
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
View rootView;
|
||||
ImageView syncStatus;
|
||||
TextView orgName, dateMonth, dateDay;
|
||||
|
||||
ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
|
||||
rootView = itemView;
|
||||
|
||||
orgName = itemView.findViewById(R.id.orgName);
|
||||
|
||||
dateMonth = itemView.findViewById(R.id.date_month);
|
||||
dateDay = itemView.findViewById(R.id.date_day);
|
||||
|
||||
syncStatus = itemView.findViewById(R.id.syncStatus);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
package lu.circl.mispbump.adapters;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.widget.ImageViewCompat;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.interfaces.OnRecyclerItemClickListener;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
public class UploadInfoAdapter extends RecyclerView.Adapter<UploadInfoAdapter.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<UploadInformation> items;
|
||||
|
||||
private OnRecyclerItemClickListener<UploadInformation> onRecyclerItemClickListener;
|
||||
private OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener;
|
||||
|
||||
|
||||
public UploadInfoAdapter(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public UploadInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.row_upload_information, viewGroup, false);
|
||||
return new UploadInfoAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final UploadInfoAdapter.ViewHolder holder, final int position) {
|
||||
|
||||
final UploadInformation item = items.get(position);
|
||||
|
||||
holder.date.setText(item.getDateString());
|
||||
holder.orgName.setText(item.getRemote().organisation.getName());
|
||||
|
||||
switch (item.getCurrentSyncStatus()) {
|
||||
case COMPLETE:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_green)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_check_outline);
|
||||
break;
|
||||
case FAILURE:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_red)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_error_outline);
|
||||
break;
|
||||
case PENDING:
|
||||
ImageViewCompat.setImageTintList(holder.syncStatus, ColorStateList.valueOf(context.getColor(R.color.status_amber)));
|
||||
holder.syncStatus.setImageResource(R.drawable.ic_pending);
|
||||
break;
|
||||
}
|
||||
|
||||
holder.rootView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onRecyclerItemClickListener.onClick(view, item);
|
||||
}
|
||||
});
|
||||
|
||||
holder.rootView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onRecyclerPositionClickListener.onClick(view, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return items.size();
|
||||
}
|
||||
|
||||
|
||||
public void setItems(List<UploadInformation> items) {
|
||||
this.items = items;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
// callbacks
|
||||
|
||||
public void setOnRecyclerItemClickListener(OnRecyclerItemClickListener<UploadInformation> onRecyclerItemClickListener) {
|
||||
this.onRecyclerItemClickListener = onRecyclerItemClickListener;
|
||||
}
|
||||
|
||||
public void setOnRecyclerPositionClickListener(OnRecyclerItemClickListener<Integer> onRecyclerPositionClickListener) {
|
||||
this.onRecyclerPositionClickListener = onRecyclerPositionClickListener;
|
||||
}
|
||||
|
||||
// viewHolder
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
View rootView;
|
||||
ImageView syncStatus;
|
||||
TextView orgName, date;
|
||||
|
||||
ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
rootView = itemView;
|
||||
orgName = itemView.findViewById(R.id.orgName);
|
||||
date = itemView.findViewById(R.id.date);
|
||||
syncStatus = itemView.findViewById(R.id.syncStatus);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package lu.circl.mispbump.auxiliary;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
|
@ -13,6 +13,7 @@ import lu.circl.mispbump.R;
|
|||
import lu.circl.mispbump.models.SyncInformation;
|
||||
import lu.circl.mispbump.security.DiffieHellman;
|
||||
|
||||
|
||||
/**
|
||||
* Creates and show dialogs.
|
||||
* Automatically takes care of using the UI Thread.
|
||||
|
@ -26,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("");
|
||||
|
||||
|
@ -142,33 +143,22 @@ public class DialogManager {
|
|||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||
|
||||
adb.setTitle("Sync information received");
|
||||
adb.setMessage(syncInformation.organisation.getName());
|
||||
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setMessage(syncInformation.getRemote().getOrganisation().getName());
|
||||
adb.setPositiveButton("Accept", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Reject", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setNegativeButton("Reject", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,31 +172,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("Continue?");
|
||||
adb.setMessage("Only continue if your partner already scanned this QR code");
|
||||
adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setPositiveButton("Continue", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Show QR code again", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setNegativeButton("Show QR code again", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,23 +195,12 @@ public class DialogManager {
|
|||
*/
|
||||
public static void loginHelpDialog(Context context) {
|
||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||
// adb.setTitle(R.string.app_name);
|
||||
adb.setMessage(R.string.login_help_text);
|
||||
adb.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
adb.setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss());
|
||||
|
||||
Activity act = (Activity) context;
|
||||
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
public static void instanceNotAvailableDialog(Context context, final IDialogFeedback callback) {
|
||||
|
@ -240,31 +208,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("MISP not available");
|
||||
adb.setMessage("Your MISP instance is not available. Would you like to save?");
|
||||
adb.setPositiveButton("Retry now", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setPositiveButton("Retry now", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Save & retry later", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setNegativeButton("Save & retry later", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
public static void deleteSyncInformationDialog(Context context, final IDialogFeedback callback) {
|
||||
|
@ -272,31 +229,20 @@ public class DialogManager {
|
|||
|
||||
adb.setTitle("Delete Sync Information?");
|
||||
adb.setMessage("This sync information will be deleted permanently");
|
||||
adb.setPositiveButton("Delete", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setPositiveButton("Delete", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.positive();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
adb.setNegativeButton("Discard", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
adb.setNegativeButton("Discard", (dialog, which) -> {
|
||||
if (callback != null) {
|
||||
callback.negative();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Activity act = (Activity) context;
|
||||
act.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
adb.create().show();
|
||||
}
|
||||
});
|
||||
act.runOnUiThread(() -> adb.create().show());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -304,8 +250,7 @@ public class DialogManager {
|
|||
*/
|
||||
public interface IDialogFeedback {
|
||||
void positive();
|
||||
|
||||
void negative();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,23 +1,21 @@
|
|||
package lu.circl.mispbump.auxiliary;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import lu.circl.mispbump.interfaces.MispRestInterface;
|
||||
import lu.circl.mispbump.interfaces.MispService;
|
||||
import lu.circl.mispbump.models.restModels.MispOrganisation;
|
||||
import lu.circl.mispbump.models.restModels.MispRole;
|
||||
import lu.circl.mispbump.models.restModels.MispServer;
|
||||
|
@ -27,7 +25,6 @@ import lu.circl.mispbump.models.restModels.Role;
|
|||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
import lu.circl.mispbump.models.restModels.Version;
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
|
@ -37,6 +34,7 @@ import retrofit2.Response;
|
|||
import retrofit2.Retrofit;
|
||||
import retrofit2.converter.gson.GsonConverterFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the RetroFit2 Misp client.
|
||||
* In order to conveniently use this api some wrapper interfaces are implemented to return the requested API endpoint as java object.
|
||||
|
@ -45,7 +43,7 @@ public class MispRestClient {
|
|||
|
||||
|
||||
private static MispRestClient instance;
|
||||
private MispRestInterface mispRestInterface;
|
||||
private MispService mispService;
|
||||
|
||||
public static MispRestClient getInstance(String url, String authkey) {
|
||||
if (instance == null) {
|
||||
|
@ -65,13 +63,18 @@ public class MispRestClient {
|
|||
.client(getCustomClient(true, true, authkey))
|
||||
.build();
|
||||
|
||||
mispRestInterface = retrofit.create(MispRestInterface.class);
|
||||
mispService = retrofit.create(MispService.class);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public MispService getService() {
|
||||
return mispService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param unsafe whether to accept all certificates or only trusted ones
|
||||
* @param logging whether to log Retrofit calls (for debugging)
|
||||
|
@ -88,12 +91,14 @@ public class MispRestClient {
|
|||
new X509TrustManager() {
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
@Override
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@SuppressLint("TrustAllX509TrustManager")
|
||||
@Override
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
|
||||
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,12 +116,7 @@ public class MispRestClient {
|
|||
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
|
||||
|
||||
builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
|
||||
builder.hostnameVerifier(new HostnameVerifier() {
|
||||
@Override
|
||||
public boolean verify(String hostname, SSLSession session) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
builder.hostnameVerifier((hostname, session) -> true);
|
||||
}
|
||||
|
||||
if (logging) {
|
||||
|
@ -125,16 +125,13 @@ public class MispRestClient {
|
|||
builder.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
// create authorization interceptor
|
||||
builder.addInterceptor(new Interceptor() {
|
||||
@Override
|
||||
public okhttp3.Response intercept(Chain chain) throws IOException {
|
||||
// create interceptor
|
||||
builder.addInterceptor(chain -> {
|
||||
Request.Builder ongoing = chain.request().newBuilder();
|
||||
ongoing.addHeader("Accept", "application/json");
|
||||
ongoing.addHeader("Content-Type", "application/json");
|
||||
ongoing.addHeader("Authorization", authkey);
|
||||
return chain.proceed(ongoing.build());
|
||||
}
|
||||
});
|
||||
|
||||
return builder.build();
|
||||
|
@ -151,7 +148,7 @@ public class MispRestClient {
|
|||
* @param callback {@link AvailableCallback}
|
||||
*/
|
||||
public void isAvailable(final AvailableCallback callback) {
|
||||
Call<Version> call = mispRestInterface.pyMispVersion();
|
||||
Call<Version> call = mispService.pyMispVersion();
|
||||
call.enqueue(new Callback<Version>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Version> call, @NonNull Response<Version> response) {
|
||||
|
@ -175,10 +172,10 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
public void getRoles(final AllRolesCallback callback) {
|
||||
Call<List<MispRole>> call = mispRestInterface.getRoles();
|
||||
Call<List<MispRole>> call = mispService.getRoles();
|
||||
call.enqueue(new Callback<List<MispRole>>() {
|
||||
@Override
|
||||
public void onResponse(Call<List<MispRole>> call, Response<List<MispRole>> response) {
|
||||
public void onResponse(@NonNull Call<List<MispRole>> call, @NonNull Response<List<MispRole>> response) {
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
|
@ -198,7 +195,7 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Call<List<MispRole>> call, Throwable t) {
|
||||
public void onFailure(@NonNull Call<List<MispRole>> call, @NonNull Throwable t) {
|
||||
callback.failure(extractError(t));
|
||||
}
|
||||
});
|
||||
|
@ -211,7 +208,7 @@ public class MispRestClient {
|
|||
* @param callback {@link UserCallback} wrapper to return user directly
|
||||
*/
|
||||
public void getMyUser(final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.getMyUserInformation();
|
||||
Call<MispUser> call = mispService.getMyUserInformation();
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -220,7 +217,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
if (response.body() != null) {
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
} else {
|
||||
callback.failure("response body was null");
|
||||
}
|
||||
|
@ -241,9 +238,8 @@ public class MispRestClient {
|
|||
* @param userId user identifier
|
||||
* @param callback {@link UserCallback} wrapper to return user directly
|
||||
*/
|
||||
|
||||
public void getUser(int userId, final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.getUser(userId);
|
||||
Call<MispUser> call = mispService.getUser(userId);
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -252,7 +248,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
if (response.body() != null) {
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
} else {
|
||||
callback.failure("response body was null");
|
||||
}
|
||||
|
@ -272,7 +268,7 @@ public class MispRestClient {
|
|||
@Override
|
||||
public void success(User[] users) {
|
||||
for (User user : users) {
|
||||
if (user.email.equals(emailAddress)) {
|
||||
if (user.getEmail().equals(emailAddress)) {
|
||||
callback.success(user);
|
||||
return;
|
||||
}
|
||||
|
@ -288,8 +284,29 @@ public class MispRestClient {
|
|||
});
|
||||
}
|
||||
|
||||
public void getAllUsers(final AllMispUsersCallback callback) {
|
||||
Call<List<MispUser>> call = mispService.getAllUsers();
|
||||
|
||||
call.enqueue(new Callback<List<MispUser>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List<MispUser>> call, @NonNull Response<List<MispUser>> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure("Failed onResponse");
|
||||
return;
|
||||
}
|
||||
|
||||
callback.success(response.body());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<MispUser>> call, @NonNull Throwable t) {
|
||||
callback.failure(extractError(t));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getAllUsers(final AllUsersCallback callback) {
|
||||
Call<List<MispUser>> call = mispRestInterface.getAllUsers();
|
||||
Call<List<MispUser>> call = mispService.getAllUsers();
|
||||
|
||||
call.enqueue(new Callback<List<MispUser>>() {
|
||||
@Override
|
||||
|
@ -305,7 +322,7 @@ public class MispRestClient {
|
|||
User[] users = new User[mispUsers.size()];
|
||||
|
||||
for (int i = 0; i < users.length; i++) {
|
||||
users[i] = mispUsers.get(i).user;
|
||||
users[i] = mispUsers.get(i).getUser();
|
||||
}
|
||||
|
||||
callback.success(users);
|
||||
|
@ -325,7 +342,7 @@ public class MispRestClient {
|
|||
* @param callback {@link UserCallback} wrapper to return the created user directly
|
||||
*/
|
||||
public void addUser(User user, final UserCallback callback) {
|
||||
Call<MispUser> call = mispRestInterface.addUser(user);
|
||||
Call<MispUser> call = mispService.addUser(user);
|
||||
|
||||
call.enqueue(new Callback<MispUser>() {
|
||||
@Override
|
||||
|
@ -334,7 +351,7 @@ public class MispRestClient {
|
|||
callback.failure(extractError(response));
|
||||
} else {
|
||||
assert response.body() != null;
|
||||
callback.success(response.body().user);
|
||||
callback.success(response.body().getUser());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -355,7 +372,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
|
||||
*/
|
||||
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
||||
Call<MispOrganisation> call = mispRestInterface.getOrganisation(orgId);
|
||||
Call<MispOrganisation> call = mispService.getOrganisation(orgId);
|
||||
|
||||
call.enqueue(new Callback<MispOrganisation>() {
|
||||
@Override
|
||||
|
@ -400,7 +417,7 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
public void getAllOrganisations(final AllOrganisationsCallback callback) {
|
||||
Call<List<MispOrganisation>> call = mispRestInterface.getAllOrganisations();
|
||||
Call<List<MispOrganisation>> call = mispService.getAllOrganisations();
|
||||
|
||||
call.enqueue(new Callback<List<MispOrganisation>>() {
|
||||
@Override
|
||||
|
@ -436,7 +453,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
|
||||
*/
|
||||
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
||||
Call<MispOrganisation> call = mispRestInterface.addOrganisation(organisation);
|
||||
Call<MispOrganisation> call = mispService.addOrganisation(organisation);
|
||||
|
||||
call.enqueue(new Callback<MispOrganisation>() {
|
||||
@Override
|
||||
|
@ -464,7 +481,7 @@ public class MispRestClient {
|
|||
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
|
||||
*/
|
||||
public void getAllServers(final AllServersCallback callback) {
|
||||
Call<List<MispServer>> call = mispRestInterface.getAllServers();
|
||||
Call<List<MispServer>> call = mispService.getAllServers();
|
||||
|
||||
call.enqueue(new Callback<List<MispServer>>() {
|
||||
@Override
|
||||
|
@ -472,17 +489,35 @@ public class MispRestClient {
|
|||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
} else {
|
||||
|
||||
List<MispServer> mispServers = response.body();
|
||||
assert mispServers != null;
|
||||
|
||||
Server[] servers = new Server[mispServers.size()];
|
||||
|
||||
for (int i = 0; i < servers.length; i++) {
|
||||
servers[i] = mispServers.get(i).server;
|
||||
servers[i] = mispServers.get(i).getServer();
|
||||
}
|
||||
callback.success(servers);
|
||||
}
|
||||
}
|
||||
|
||||
callback.success(servers);
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<List<MispServer>> call, @NonNull Throwable t) {
|
||||
callback.failure(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getAllServers(final AllRawServersCallback callback) {
|
||||
Call<List<MispServer>> call = mispService.getAllServers();
|
||||
|
||||
call.enqueue(new Callback<List<MispServer>>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<List<MispServer>> call, @NonNull Response<List<MispServer>> response) {
|
||||
if (!response.isSuccessful()) {
|
||||
callback.failure(extractError(response));
|
||||
} else {
|
||||
callback.success(response.body());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,7 +535,7 @@ public class MispRestClient {
|
|||
* @param callback {@link ServerCallback} wrapper to return the created server directly
|
||||
*/
|
||||
public void addServer(Server server, final ServerCallback callback) {
|
||||
Call<Server> call = mispRestInterface.addServer(server);
|
||||
Call<Server> call = mispService.addServer(server);
|
||||
|
||||
call.enqueue(new Callback<Server>() {
|
||||
@Override
|
||||
|
@ -586,7 +621,6 @@ public class MispRestClient {
|
|||
}
|
||||
|
||||
// interfaces
|
||||
|
||||
public interface AvailableCallback {
|
||||
void available();
|
||||
|
||||
|
@ -605,6 +639,12 @@ public class MispRestClient {
|
|||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllMispUsersCallback {
|
||||
void success(List<MispUser> users);
|
||||
|
||||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface OrganisationCallback {
|
||||
void success(Organisation organisation);
|
||||
|
||||
|
@ -629,6 +669,12 @@ public class MispRestClient {
|
|||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllRawServersCallback {
|
||||
void success(List<MispServer> mispServers);
|
||||
|
||||
void failure(String error);
|
||||
}
|
||||
|
||||
public interface AllRolesCallback {
|
||||
void success(Role[] roles);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.auxiliary;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
|
@ -20,12 +21,13 @@ 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;
|
||||
import lu.circl.mispbump.security.KeyStoreWrapper;
|
||||
|
||||
|
||||
public class PreferenceManager {
|
||||
|
||||
private static final String PREFERENCES_FILE = "user_settings";
|
||||
|
@ -34,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";
|
||||
|
||||
|
@ -81,10 +83,10 @@ public class PreferenceManager {
|
|||
public Role[] getRoles() {
|
||||
Type type = new TypeToken<Role[]>() {
|
||||
}.getType();
|
||||
String rolesString = preferences.getString(MISP_ROLES, "");
|
||||
|
||||
assert rolesString != null;
|
||||
if (rolesString.isEmpty()) {
|
||||
String rolesString = preferences.getString(MISP_ROLES, null);
|
||||
|
||||
if (rolesString == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new Gson().fromJson(rolesString, type);
|
||||
|
@ -97,23 +99,13 @@ public class PreferenceManager {
|
|||
*
|
||||
* @param user {@link User}
|
||||
*/
|
||||
public void setUserInfo(User user) {
|
||||
public void setMyUser(User user) {
|
||||
try {
|
||||
String userStr = new Gson().toJson(user);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
||||
String encryptedUserInfo = keyStoreWrapper.encrypt(userStr);
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(USER_INFOS, encryptedUserInfo);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS);
|
||||
editor.putString(USER_INFOS, keyStoreWrapper.encrypt(new Gson().toJson(user)));
|
||||
editor.apply();
|
||||
} catch (NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvalidKeyException e) {
|
||||
e.printStackTrace();
|
||||
} catch (BadPaddingException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalBlockSizeException e) {
|
||||
} catch (BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -133,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();
|
||||
}
|
||||
|
||||
|
@ -156,7 +138,7 @@ public class PreferenceManager {
|
|||
*
|
||||
* @param organisation Object representation of json organisation information
|
||||
*/
|
||||
public void setUserOrgInfo(Organisation organisation) {
|
||||
public void setMyOrganisation(Organisation organisation) {
|
||||
try {
|
||||
String orgStr = new Gson().toJson(organisation);
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS);
|
||||
|
@ -229,7 +211,8 @@ public class PreferenceManager {
|
|||
|
||||
try {
|
||||
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
|
||||
Type type = new TypeToken<Pair<String, String>>() {}.getType();
|
||||
Type type = new TypeToken<Pair<String, String>>() {
|
||||
}.getType();
|
||||
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
|
||||
return new Gson().fromJson(serializedCreds, type);
|
||||
} catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
|
||||
|
@ -240,58 +223,57 @@ public class PreferenceManager {
|
|||
}
|
||||
|
||||
|
||||
private List<UploadInformation> cachedUploadInformationList;
|
||||
private List<SyncInformation> cachedSyncInformationList;
|
||||
|
||||
private void loadUploadInformationList() {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
|
||||
private void loadSyncInformationList() {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
|
||||
String storedSyncInfoString = preferences.getString(SYNC_INFO, null);
|
||||
|
||||
Type type = new TypeToken<List<UploadInformation>>() {
|
||||
}.getType();
|
||||
Type type = new TypeToken<List<SyncInformation>>() {}.getType();
|
||||
|
||||
if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
|
||||
cachedUploadInformationList = new ArrayList<>();
|
||||
if (storedSyncInfoString == null || storedSyncInfoString.isEmpty()) {
|
||||
cachedSyncInformationList = new ArrayList<>();
|
||||
} else {
|
||||
try {
|
||||
storedUploadInfoString = ksw.decrypt(storedUploadInfoString);
|
||||
cachedUploadInformationList = new Gson().fromJson(storedUploadInfoString, type);
|
||||
storedSyncInfoString = ksw.decrypt(storedSyncInfoString);
|
||||
cachedSyncInformationList = new Gson().fromJson(storedSyncInfoString, type);
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveUploadInformationList() {
|
||||
private void saveSyncInformationList() {
|
||||
try {
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
|
||||
String cipherText = ksw.encrypt(new Gson().toJson(cachedUploadInformationList));
|
||||
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.SYNC_INFORMATION_ALIAS);
|
||||
String cipherText = ksw.encrypt(new Gson().toJson(cachedSyncInformationList));
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(UPLOAD_INFO, cipherText);
|
||||
editor.putString(SYNC_INFO, cipherText);
|
||||
editor.apply();
|
||||
} catch (IllegalBlockSizeException | BadPaddingException | InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public List<UploadInformation> getUploadInformationList() {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
public List<SyncInformation> getSyncInformationList() {
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
return cachedUploadInformationList;
|
||||
return cachedSyncInformationList;
|
||||
}
|
||||
|
||||
public void setUploadInformationList(List<UploadInformation> uploadInformationList) {
|
||||
cachedUploadInformationList = uploadInformationList;
|
||||
saveUploadInformationList();
|
||||
public void setSyncInformationList(List<SyncInformation> uploadInformationList) {
|
||||
cachedSyncInformationList = uploadInformationList;
|
||||
saveSyncInformationList();
|
||||
}
|
||||
|
||||
public UploadInformation getUploadInformation(UUID uuid) {
|
||||
if (cachedUploadInformationList == null) {
|
||||
loadUploadInformationList();
|
||||
public SyncInformation getSyncInformation(UUID uuid) {
|
||||
if (cachedSyncInformationList == null) {
|
||||
loadSyncInformationList();
|
||||
}
|
||||
|
||||
for (UploadInformation ui : cachedUploadInformationList) {
|
||||
for (SyncInformation ui : cachedSyncInformationList) {
|
||||
if (ui.getUuid().compareTo(uuid) == 0) {
|
||||
return ui;
|
||||
}
|
||||
|
@ -300,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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.auxiliary;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Point;
|
||||
|
@ -13,6 +14,7 @@ import com.google.zxing.common.BitMatrix;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
public class QrCodeGenerator {
|
||||
|
||||
private Activity callingActivity;
|
||||
|
@ -32,7 +34,7 @@ public class QrCodeGenerator {
|
|||
size = displaySize.y;
|
||||
}
|
||||
|
||||
size = (int)(size * 0.8);
|
||||
size = (int) (size * 0.8);
|
||||
|
||||
try {
|
||||
MultiFormatWriter multiFormatWriter = new MultiFormatWriter();
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package lu.circl.mispbump.auxiliary;
|
||||
|
||||
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
|
||||
public class RandomString {
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
private static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
package lu.circl.mispbump.auxiliary
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapShader
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.ColorFilter
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PixelFormat
|
||||
import android.graphics.Shader
|
||||
import android.graphics.*
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import android.content.Context;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.TextureView;
|
||||
|
||||
|
||||
/**
|
||||
* A {@link TextureView} that can be adjusted to a specified aspect ratio.
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -9,7 +10,6 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
|||
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
|
||||
import java.util.ConcurrentModificationException;
|
||||
|
||||
/**
|
||||
* Can disable touch input on bottom sheet.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
@ -8,6 +9,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
|
||||
public class ExtendedViewPager extends ViewPager {
|
||||
|
||||
private boolean swipeEnabled;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
|
@ -7,6 +8,7 @@ import android.widget.FrameLayout;
|
|||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
|
||||
public class FixedAspectRatioFrameLayout extends FrameLayout {
|
||||
private int mAspectRatioWidth;
|
||||
private int mAspectRatioHeight;
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
import android.text.method.PasswordTransformationMethod;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -13,10 +15,10 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
|||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
|
||||
public class MaterialPasswordView extends ConstraintLayout {
|
||||
|
||||
private TextView titleView, passwordView;
|
||||
private OnCopyClickListener onCopyClickListener;
|
||||
|
||||
|
||||
public MaterialPasswordView(Context context, AttributeSet attrs) {
|
||||
|
@ -29,14 +31,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);
|
||||
|
||||
|
@ -45,14 +39,19 @@ public class MaterialPasswordView extends ConstraintLayout {
|
|||
passwordView.setText(password);
|
||||
|
||||
ImageButton visibleToggle = findViewById(R.id.visibleToggle);
|
||||
visibleToggle.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
AnimatedVectorDrawable lookAway = (AnimatedVectorDrawable) context.getDrawable(R.drawable.animated_eye_to_up);
|
||||
AnimatedVectorDrawable lookCenter = (AnimatedVectorDrawable) context.getDrawable(R.drawable.animated_eye_to_center);
|
||||
|
||||
visibleToggle.setOnClickListener(v -> {
|
||||
if (passwordView.getTransformationMethod() == null) {
|
||||
passwordView.setTransformationMethod(new PasswordTransformationMethod());
|
||||
visibleToggle.setImageDrawable(lookCenter);
|
||||
lookCenter.start();
|
||||
} else {
|
||||
passwordView.setTransformationMethod(null);
|
||||
}
|
||||
visibleToggle.setImageDrawable(lookAway);
|
||||
lookAway.start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -82,13 +81,4 @@ public class MaterialPasswordView extends ConstraintLayout {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void addOnCopyClickedListener(OnCopyClickListener listener) {
|
||||
onCopyClickListener = listener;
|
||||
}
|
||||
|
||||
|
||||
public interface OnCopyClickListener {
|
||||
void onClick(String title, String password);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
|
@ -13,18 +14,18 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
|||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
public class MaterialPreferenceSwitch extends ConstraintLayout {
|
||||
|
||||
private View rootView;
|
||||
public class MaterialPreferenceSwitch extends ConstraintLayout {
|
||||
|
||||
private TextView titleView, subTitleView;
|
||||
private Switch switchView;
|
||||
private CompoundButton.OnCheckedChangeListener onCheckedChangeListener;
|
||||
|
||||
public MaterialPreferenceSwitch(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
View view = LayoutInflater.from(context).inflate(R.layout.material_preference_switch, this);
|
||||
rootView = view.findViewById(R.id.rootLayout);
|
||||
View rootView = view.findViewById(R.id.rootLayout);
|
||||
|
||||
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MaterialPreferenceSwitch);
|
||||
String title = a.getString(R.styleable.MaterialPreferenceSwitch_title);
|
||||
|
@ -40,22 +41,29 @@ public class MaterialPreferenceSwitch extends ConstraintLayout {
|
|||
|
||||
switchView = view.findViewById(R.id.material_preference_switch);
|
||||
|
||||
rootView.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
rootView.setOnClickListener(v -> {
|
||||
if (switchView.isEnabled()) {
|
||||
switchView.setChecked(!switchView.isChecked());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
switchView.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
|
||||
if (onCheckedChangeListener != null) {
|
||||
onCheckedChangeListener.onCheckedChanged(buttonView, isChecked);
|
||||
}
|
||||
|
||||
if (isChecked) {
|
||||
if (!onText.isEmpty()) {
|
||||
subTitleView.setText(onText);
|
||||
} else {
|
||||
subTitleView.setVisibility(GONE);
|
||||
}
|
||||
} else {
|
||||
if (!offText.isEmpty()) {
|
||||
subTitleView.setText(offText);
|
||||
} else {
|
||||
subTitleView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -73,4 +81,8 @@ public class MaterialPreferenceSwitch extends ConstraintLayout {
|
|||
return switchView.isChecked();
|
||||
}
|
||||
|
||||
public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
|
||||
this.onCheckedChangeListener = onCheckedChangeListener;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.customViews;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
@ -14,6 +15,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
|||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
|
||||
public class MaterialPreferenceText extends ConstraintLayout {
|
||||
|
||||
private View rootView;
|
||||
|
@ -32,7 +34,7 @@ public class MaterialPreferenceText extends ConstraintLayout {
|
|||
|
||||
icon = view.findViewById(R.id.material_preference_src);
|
||||
int imageRes = a.getResourceId(R.styleable.MaterialPreferenceText_pref_icon, 0x0);
|
||||
if (imageRes != 0x0){
|
||||
if (imageRes != 0x0) {
|
||||
icon.setImageResource(imageRes);
|
||||
} else {
|
||||
icon.setVisibility(GONE);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
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;
|
||||
|
@ -15,6 +15,7 @@ import androidx.core.widget.ImageViewCompat;
|
|||
|
||||
import lu.circl.mispbump.R;
|
||||
|
||||
|
||||
public class UploadAction extends ConstraintLayout {
|
||||
|
||||
private Context context;
|
||||
|
@ -43,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);
|
||||
|
@ -64,6 +65,7 @@ public class UploadAction extends ConstraintLayout {
|
|||
|
||||
/**
|
||||
* Displays an error message for the upload action.
|
||||
*
|
||||
* @param error a string to show or null to hide
|
||||
*/
|
||||
public void setError(String error) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
|
@ -62,6 +63,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.customViews.AutoFitTextureView;
|
||||
|
||||
|
||||
public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
|
||||
private class ImageProcessingThread extends Thread {
|
||||
|
|
|
@ -1,75 +0,0 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentPagerAdapter;
|
||||
|
||||
public class SyncFragmentAdapter extends FragmentPagerAdapter {
|
||||
|
||||
public CameraFragment cameraFragment_1, cameraFragment_2;
|
||||
private UploadSettingsFragment uploadSettingsFragment;
|
||||
|
||||
public SyncFragmentAdapter(@NonNull FragmentManager fm) {
|
||||
super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);
|
||||
}
|
||||
|
||||
private CameraFragment.QrScanCallback scanCallback;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
if (cameraFragment_1 == null) {
|
||||
cameraFragment_1 = new CameraFragment();
|
||||
}
|
||||
|
||||
if (scanCallback != null) {
|
||||
cameraFragment_1.setOnQrAvailableListener(scanCallback);
|
||||
}
|
||||
|
||||
return cameraFragment_1;
|
||||
|
||||
case 1:
|
||||
if (cameraFragment_2 == null) {
|
||||
cameraFragment_2 = new CameraFragment();
|
||||
}
|
||||
|
||||
if (scanCallback != null) {
|
||||
cameraFragment_1.setOnQrAvailableListener(scanCallback);
|
||||
}
|
||||
|
||||
return cameraFragment_2;
|
||||
|
||||
case 2:
|
||||
if (uploadSettingsFragment == null) {
|
||||
uploadSettingsFragment = new UploadSettingsFragment();
|
||||
}
|
||||
|
||||
return uploadSettingsFragment;
|
||||
|
||||
default:
|
||||
return new CameraFragment();
|
||||
}
|
||||
}
|
||||
|
||||
public void setQrReceivedCallback(CameraFragment.QrScanCallback qrScanCallback) {
|
||||
this.scanCallback = qrScanCallback;
|
||||
}
|
||||
|
||||
public void disableCameraPreview() {
|
||||
if (cameraFragment_1 != null) {
|
||||
// cameraFragment_1.disablePreview();
|
||||
}
|
||||
|
||||
if (cameraFragment_2 != null) {
|
||||
// cameraFragment_2.disablePreview();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return 3;
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import lu.circl.mispbump.R;
|
||||
import lu.circl.mispbump.customViews.MaterialPasswordView;
|
||||
import lu.circl.mispbump.customViews.MaterialPreferenceText;
|
||||
import lu.circl.mispbump.models.UploadInformation;
|
||||
|
||||
public class UploadCredentialsFragment extends Fragment {
|
||||
|
||||
private View rootLayout;
|
||||
private UploadInformation uploadInformation;
|
||||
|
||||
public UploadCredentialsFragment() {}
|
||||
public UploadCredentialsFragment(UploadInformation uploadInformation) {
|
||||
this.uploadInformation = uploadInformation;
|
||||
}
|
||||
|
||||
private MaterialPasswordView.OnCopyClickListener onCopyClickListener = new MaterialPasswordView.OnCopyClickListener() {
|
||||
@Override
|
||||
public void onClick(String title, String password) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
ClipData clip = ClipData.newPlainText(title, password);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
Snackbar.make(rootLayout, "Copied to clipboard", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View v = inflater.inflate(R.layout.fragment_upload_credentials, container, false);
|
||||
|
||||
rootLayout = v.findViewById(R.id.rootLayout);
|
||||
|
||||
MaterialPreferenceText baseUrl = v.findViewById(R.id.baseUrl);
|
||||
baseUrl.setSubtitle(uploadInformation.getRemote().baseUrl);
|
||||
|
||||
MaterialPreferenceText email = v.findViewById(R.id.email);
|
||||
email.setSubtitle(uploadInformation.getLocal().syncUserEmail);
|
||||
|
||||
MaterialPasswordView authkey = v.findViewById(R.id.authkey);
|
||||
authkey.setPassword(uploadInformation.getRemote().syncUserAuthkey);
|
||||
authkey.addOnCopyClickedListener(onCopyClickListener);
|
||||
|
||||
MaterialPasswordView password = v.findViewById(R.id.password);
|
||||
password.setPassword(uploadInformation.getRemote().syncUserPassword);
|
||||
password.addOnCopyClickedListener(onCopyClickListener);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package lu.circl.mispbump.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.interfaces;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import lu.circl.mispbump.models.restModels.MispOrganisation;
|
||||
|
@ -16,10 +17,11 @@ import retrofit2.http.GET;
|
|||
import retrofit2.http.POST;
|
||||
import retrofit2.http.Path;
|
||||
|
||||
|
||||
/**
|
||||
* RetroFit2 interface for communication with misp instances
|
||||
*/
|
||||
public interface MispRestInterface {
|
||||
public interface MispService {
|
||||
|
||||
// settings routes
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package lu.circl.mispbump.interfaces;
|
||||
|
||||
|
||||
import android.view.View;
|
||||
|
||||
|
||||
public interface OnRecyclerItemClickListener<T> {
|
||||
void onClick(View v, T item);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
import lu.circl.mispbump.models.restModels.Server;
|
||||
import lu.circl.mispbump.models.restModels.User;
|
||||
|
||||
|
||||
public class ExchangeInformation {
|
||||
|
||||
private Organisation organisation;
|
||||
private User syncUser;
|
||||
private Server server;
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
public User getSyncUser() {
|
||||
return syncUser;
|
||||
}
|
||||
public void setSyncUser(User syncUser) {
|
||||
this.syncUser = syncUser;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Exchange Information: \n" + organisation.toString() + "\n" + syncUser.toString() + "\n" + server.toString();
|
||||
}
|
||||
}
|
|
@ -1,29 +1,96 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
import lu.circl.mispbump.models.restModels.Organisation;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
|
||||
/**
|
||||
* A Class that holds the information needed synchronize two misp instances.
|
||||
* This class can be serialized and passed via QR code.
|
||||
* Class that holds the information needed synchronize two misp instances.
|
||||
*/
|
||||
public class SyncInformation {
|
||||
|
||||
public Organisation organisation;
|
||||
public String syncUserEmail;
|
||||
public String syncUserPassword;
|
||||
public String syncUserAuthkey;
|
||||
public String baseUrl;
|
||||
private UUID uuid;
|
||||
private Date date, lastModified;
|
||||
|
||||
public SyncInformation() {}
|
||||
private ExchangeInformation remote;
|
||||
private ExchangeInformation local;
|
||||
|
||||
private boolean syncedWithRemote;
|
||||
|
||||
|
||||
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 void setSyncedWithRemote(boolean syncedWithRemote) {
|
||||
this.syncedWithRemote = syncedWithRemote;
|
||||
}
|
||||
public boolean isSyncedWithRemote() {
|
||||
return syncedWithRemote;
|
||||
}
|
||||
|
||||
public ExchangeInformation getRemote() {
|
||||
return remote;
|
||||
}
|
||||
public void setRemote(ExchangeInformation remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
public ExchangeInformation getLocal() {
|
||||
return local;
|
||||
}
|
||||
public void setLocal(ExchangeInformation local) {
|
||||
this.local = local;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SyncInformation{" +
|
||||
"organisation=" + organisation +
|
||||
", syncUserEmail='" + syncUserEmail + '\'' +
|
||||
", syncUserPassword='" + syncUserPassword + '\'' +
|
||||
", syncUserAuthkey='" + syncUserAuthkey + '\'' +
|
||||
", baseUrl='" + baseUrl + '\'' +
|
||||
'}';
|
||||
return "Sync Information: \n" +
|
||||
"UUID = " + uuid + "\n" +
|
||||
"Sync Date = " + getSyncDateString() + "\n" +
|
||||
remote.toString() +
|
||||
local.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,117 +0,0 @@
|
|||
package lu.circl.mispbump.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
public class UploadInformation {
|
||||
|
||||
public enum SyncStatus {
|
||||
COMPLETE,
|
||||
FAILURE,
|
||||
PENDING
|
||||
}
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
private SyncStatus currentSyncStatus = SyncStatus.PENDING;
|
||||
|
||||
private boolean allowSelfSigned, pull, push, cached;
|
||||
|
||||
private SyncInformation local;
|
||||
private SyncInformation remote;
|
||||
|
||||
private Date date;
|
||||
|
||||
public UploadInformation() {
|
||||
uuid = UUID.randomUUID();
|
||||
date = Calendar.getInstance().getTime();
|
||||
}
|
||||
|
||||
// getter and setter
|
||||
|
||||
public void setCurrentSyncStatus(SyncStatus status) {
|
||||
currentSyncStatus = status;
|
||||
}
|
||||
public SyncStatus getCurrentSyncStatus() {
|
||||
return currentSyncStatus;
|
||||
}
|
||||
|
||||
public void setLocal(SyncInformation local) {
|
||||
this.local = local;
|
||||
}
|
||||
public SyncInformation getLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public void setRemote(SyncInformation remote) {
|
||||
this.remote = remote;
|
||||
}
|
||||
public SyncInformation getRemote() {
|
||||
return remote;
|
||||
}
|
||||
|
||||
public UUID getUuid() {
|
||||
return uuid;
|
||||
}
|
||||
public void setUuid(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public void setDate() {
|
||||
setDate(Calendar.getInstance().getTime());
|
||||
}
|
||||
public void setDate(Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
public Date getDate() {
|
||||
return date;
|
||||
}
|
||||
public String getDateString() {
|
||||
SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
|
||||
return df.format(date);
|
||||
}
|
||||
|
||||
public boolean isAllowSelfSigned() {
|
||||
return allowSelfSigned;
|
||||
}
|
||||
public void setAllowSelfSigned(boolean allowSelfSigned) {
|
||||
this.allowSelfSigned = allowSelfSigned;
|
||||
}
|
||||
|
||||
public boolean isPull() {
|
||||
return pull;
|
||||
}
|
||||
public void setPull(boolean pull) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
public boolean isPush() {
|
||||
return push;
|
||||
}
|
||||
public void setPush(boolean push) {
|
||||
this.push = push;
|
||||
}
|
||||
|
||||
public boolean isCached() {
|
||||
return cached;
|
||||
}
|
||||
public void setCached(boolean cached) {
|
||||
this.cached = cached;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "UploadInformation{" +
|
||||
"currentSyncStatus=" + currentSyncStatus +
|
||||
", local=" + local.toString() +
|
||||
", remote=" + remote.toString() +
|
||||
", date=" + date +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class MispOrganisation {
|
||||
@SerializedName("Organisation")
|
||||
@Expose
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class MispRole {
|
||||
@SerializedName("Role")
|
||||
@Expose
|
||||
|
|
|
@ -1,30 +1,59 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
import java.util.List;
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class MispServer {
|
||||
|
||||
public MispServer() {}
|
||||
@SerializedName("Server")
|
||||
private Server server;
|
||||
|
||||
public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
|
||||
@SerializedName("Organisation")
|
||||
private Organisation organisation;
|
||||
|
||||
@SerializedName("RemoteOrg")
|
||||
private Organisation remoteOrganisation;
|
||||
|
||||
@SerializedName("User")
|
||||
private List<User> user;
|
||||
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
this.organisation = organisation;
|
||||
this.remoteOrg = remoteOrganisation;
|
||||
}
|
||||
|
||||
@SerializedName("Server")
|
||||
@Expose
|
||||
public Server server;
|
||||
@SerializedName("Organisation")
|
||||
@Expose
|
||||
public Organisation organisation;
|
||||
@SerializedName("RemoteOrg")
|
||||
@Expose
|
||||
public Organisation remoteOrg;
|
||||
@SerializedName("User")
|
||||
@Expose
|
||||
public List<User> user;
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
public Organisation getRemoteOrganisation() {
|
||||
return remoteOrganisation;
|
||||
}
|
||||
public void setRemoteOrganisation(Organisation remoteOrganisation) {
|
||||
this.remoteOrganisation = remoteOrganisation;
|
||||
}
|
||||
|
||||
public List<User> getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(List<User> user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return server.toString() + "\n" + organisation.toString() + "\n" + remoteOrganisation.toString();
|
||||
}
|
||||
}
|
|
@ -1,15 +1,40 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class MispUser {
|
||||
|
||||
@SerializedName("User")
|
||||
@Expose
|
||||
public User user;
|
||||
private User user;
|
||||
|
||||
public MispUser(User user) {
|
||||
@SerializedName("Role")
|
||||
private Role role;
|
||||
|
||||
@SerializedName("Organisation")
|
||||
private Organisation organisation;
|
||||
|
||||
|
||||
public User getUser() {
|
||||
return user;
|
||||
}
|
||||
public void setUser(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
public Role getRole() {
|
||||
return role;
|
||||
}
|
||||
public void setRole(Role role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public Organisation getOrganisation() {
|
||||
return organisation;
|
||||
}
|
||||
public void setOrganisation(Organisation organisation) {
|
||||
this.organisation = organisation;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,11 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
/**
|
||||
* Information gathered from Misp API about a organisation.
|
||||
*/
|
||||
|
@ -20,27 +26,14 @@ public class Organisation {
|
|||
private String created_by;
|
||||
private Integer user_count;
|
||||
|
||||
public Organisation() {
|
||||
}
|
||||
|
||||
public Organisation(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Organisation(String name, String description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Organisation toSyncOrganisation() {
|
||||
Organisation organisation = new Organisation();
|
||||
organisation.local = true;
|
||||
organisation.name = name;
|
||||
organisation.uuid = uuid;
|
||||
organisation.description = description;
|
||||
organisation.nationality = nationality;
|
||||
organisation.sector = sector;
|
||||
organisation.type = "Sync organisation";
|
||||
organisation.contacts = contacts;
|
||||
|
||||
return organisation;
|
||||
|
@ -63,19 +56,19 @@ public class Organisation {
|
|||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDate_created() {
|
||||
public String getDateCreated() {
|
||||
return date_created;
|
||||
}
|
||||
|
||||
public void setDate_created(String date_created) {
|
||||
public void setDateCreated(String date_created) {
|
||||
this.date_created = date_created;
|
||||
}
|
||||
|
||||
public String getDate_modified() {
|
||||
public String getDateModified() {
|
||||
return date_modified;
|
||||
}
|
||||
|
||||
public void setDate_modified(String date_modified) {
|
||||
public void setDateModified(String date_modified) {
|
||||
this.date_modified = date_modified;
|
||||
}
|
||||
|
||||
|
@ -135,47 +128,47 @@ public class Organisation {
|
|||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public String[] getRestricted_to_domain() {
|
||||
public String[] getRestrictedToDomain() {
|
||||
return restricted_to_domain;
|
||||
}
|
||||
|
||||
public void setRestricted_to_domain(String[] restricted_to_domain) {
|
||||
public void setRestrictedToDomain(String[] restricted_to_domain) {
|
||||
this.restricted_to_domain = restricted_to_domain;
|
||||
}
|
||||
|
||||
public String getCreated_by() {
|
||||
public String getCreatedBy() {
|
||||
return created_by;
|
||||
}
|
||||
|
||||
public void setCreated_by(String created_by) {
|
||||
public void setCreatedBy(String created_by) {
|
||||
this.created_by = created_by;
|
||||
}
|
||||
|
||||
public Integer getUser_count() {
|
||||
public Integer getUserCount() {
|
||||
return user_count;
|
||||
}
|
||||
|
||||
public void setUser_count(Integer user_count) {
|
||||
public void setUserCount(Integer user_count) {
|
||||
this.user_count = user_count;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Organisation{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", date_created='" + date_created + '\'' +
|
||||
", date_modified='" + date_modified + '\'' +
|
||||
", type='" + type + '\'' +
|
||||
", nationality='" + nationality + '\'' +
|
||||
", sector='" + sector + '\'' +
|
||||
", contacts='" + contacts + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
", local=" + local +
|
||||
", uuid='" + uuid + '\'' +
|
||||
", restricted_to_domain='" + restricted_to_domain + '\'' +
|
||||
", created_by='" + created_by + '\'' +
|
||||
", user_count=" + user_count +
|
||||
'}';
|
||||
return "Organisation: \n" +
|
||||
"\t id = " + id + "\n" +
|
||||
"\t name = " + name + '\n' +
|
||||
"\t date_created = " + date_created + '\n' +
|
||||
"\t date_modified = " + date_modified + '\n' +
|
||||
"\t type = " + type + '\n' +
|
||||
"\t nationality = " + nationality + '\n' +
|
||||
"\t sector = " + sector + '\n' +
|
||||
"\t contacts = " + contacts + '\n' +
|
||||
"\t description = " + description + '\n' +
|
||||
"\t local = " + local + '\n' +
|
||||
"\t uuid = " + uuid + '\n' +
|
||||
"\t restricted_to_domain = " + Arrays.toString(restricted_to_domain) + '\n' +
|
||||
"\t created_by = " + created_by + '\n' +
|
||||
"\t user_count = " + user_count;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class Role {
|
||||
@SerializedName("id")
|
||||
private Integer id;
|
||||
|
@ -62,6 +64,13 @@ public class Role {
|
|||
@SerializedName("permission_description")
|
||||
private String permissionDescription;
|
||||
|
||||
|
||||
public boolean isSyncUserRole() {
|
||||
return permSync && permAuth && permTagger && permTagEditor && permSharingGroup
|
||||
&& permDelegate && permSighting && permPublishZmq && permPublishKafka;
|
||||
}
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
|
|
@ -1,109 +1,241 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
||||
public class Server {
|
||||
|
||||
public Server() {}
|
||||
private Integer id;
|
||||
private String name;
|
||||
private String url;
|
||||
private String authkey;
|
||||
private Integer org_id;
|
||||
private Boolean push = false;
|
||||
private Boolean pull = false;
|
||||
private Object lastpulledid;
|
||||
private Object lastpushedid;
|
||||
private Object organization;
|
||||
private Integer remote_org_id;
|
||||
private Boolean publish_without_email = false;
|
||||
private Boolean unpublish_event = false;
|
||||
private Boolean self_signed = false;
|
||||
private String pull_rules;
|
||||
private String push_rules;
|
||||
private Object cert_file;
|
||||
private Object client_cert_file;
|
||||
private Boolean internal;
|
||||
private Boolean skip_proxy;
|
||||
private Boolean caching_enabled = false;
|
||||
private Boolean cache_timestamp;
|
||||
|
||||
public Server(String name, String url, String authkey, Integer remote_org_id) {
|
||||
this.name = name;
|
||||
|
||||
public Server(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getAuthkey() {
|
||||
return authkey;
|
||||
}
|
||||
|
||||
public void setAuthkey(String authkey) {
|
||||
this.authkey = authkey;
|
||||
}
|
||||
|
||||
public Integer getOrgId() {
|
||||
return org_id;
|
||||
}
|
||||
|
||||
public void setOrgId(Integer org_id) {
|
||||
this.org_id = org_id;
|
||||
}
|
||||
|
||||
public Boolean getPush() {
|
||||
return push;
|
||||
}
|
||||
|
||||
public void setPush(Boolean push) {
|
||||
this.push = push;
|
||||
}
|
||||
|
||||
public Boolean getPull() {
|
||||
return pull;
|
||||
}
|
||||
|
||||
public void setPull(Boolean pull) {
|
||||
this.pull = pull;
|
||||
}
|
||||
|
||||
public Object getLastpulledId() {
|
||||
return lastpulledid;
|
||||
}
|
||||
|
||||
public void setLastpulledId(Object lastpulledid) {
|
||||
this.lastpulledid = lastpulledid;
|
||||
}
|
||||
|
||||
public Object getLastpushedId() {
|
||||
return lastpushedid;
|
||||
}
|
||||
|
||||
public void setLastpushedId(Object lastpushedid) {
|
||||
this.lastpushedid = lastpushedid;
|
||||
}
|
||||
|
||||
public Object getOrganization() {
|
||||
return organization;
|
||||
}
|
||||
|
||||
public void setOrganization(Object organization) {
|
||||
this.organization = organization;
|
||||
}
|
||||
|
||||
public Integer getRemoteOrgId() {
|
||||
return remote_org_id;
|
||||
}
|
||||
|
||||
public void setRemoteOrgId(Integer remote_org_id) {
|
||||
this.remote_org_id = remote_org_id;
|
||||
}
|
||||
|
||||
@SerializedName("id")
|
||||
public Integer id;
|
||||
public Boolean getPublishWithoutEmail() {
|
||||
return publish_without_email;
|
||||
}
|
||||
|
||||
@SerializedName("name")
|
||||
public String name;
|
||||
public void setPublishWithoutEmail(Boolean publish_without_email) {
|
||||
this.publish_without_email = publish_without_email;
|
||||
}
|
||||
|
||||
@SerializedName("url")
|
||||
public String url;
|
||||
public Boolean getUnpublishEvent() {
|
||||
return unpublish_event;
|
||||
}
|
||||
|
||||
@SerializedName("authkey")
|
||||
public String authkey;
|
||||
public void setUnpublishEvent(Boolean unpublish_event) {
|
||||
this.unpublish_event = unpublish_event;
|
||||
}
|
||||
|
||||
@SerializedName("org_id")
|
||||
public Integer org_id;
|
||||
public Boolean getSelfSigned() {
|
||||
return self_signed;
|
||||
}
|
||||
|
||||
@SerializedName("push")
|
||||
public Boolean push;
|
||||
public void setSelfSigned(Boolean self_signed) {
|
||||
this.self_signed = self_signed;
|
||||
}
|
||||
|
||||
@SerializedName("pull")
|
||||
public Boolean pull;
|
||||
public String getPullRules() {
|
||||
return pull_rules;
|
||||
}
|
||||
|
||||
@SerializedName("lastpulledid")
|
||||
public Object lastpulledid;
|
||||
public void setPullRules(String pull_rules) {
|
||||
this.pull_rules = pull_rules;
|
||||
}
|
||||
|
||||
@SerializedName("lastpushedid")
|
||||
public Object lastpushedid;
|
||||
public String getPushRules() {
|
||||
return push_rules;
|
||||
}
|
||||
|
||||
@SerializedName("organization")
|
||||
public Object organization;
|
||||
public void setPushRules(String push_rules) {
|
||||
this.push_rules = push_rules;
|
||||
}
|
||||
|
||||
@SerializedName("remote_org_id")
|
||||
public Integer remote_org_id;
|
||||
public Object getCertFile() {
|
||||
return cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("publish_without_email")
|
||||
public Boolean publish_without_email = false;
|
||||
public void setCertFile(Object cert_file) {
|
||||
this.cert_file = cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("unpublish_event")
|
||||
public Boolean unpublish_event;
|
||||
public Object getClientCertFile() {
|
||||
return client_cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("self_signed")
|
||||
public Boolean self_signed = false;
|
||||
public void setClientCertFile(Object client_cert_file) {
|
||||
this.client_cert_file = client_cert_file;
|
||||
}
|
||||
|
||||
@SerializedName("pull_rules")
|
||||
public String pull_rules;
|
||||
public Boolean getInternal() {
|
||||
return internal;
|
||||
}
|
||||
|
||||
@SerializedName("push_rules")
|
||||
public String push_rules;
|
||||
public void setInternal(Boolean internal) {
|
||||
this.internal = internal;
|
||||
}
|
||||
|
||||
@SerializedName("cert_file")
|
||||
public Object cert_file;
|
||||
public Boolean getSkipProxy() {
|
||||
return skip_proxy;
|
||||
}
|
||||
|
||||
@SerializedName("client_cert_file")
|
||||
public Object client_cert_file;
|
||||
public void setSkipProxy(Boolean skip_proxy) {
|
||||
this.skip_proxy = skip_proxy;
|
||||
}
|
||||
|
||||
@SerializedName("internal")
|
||||
public Boolean internal;
|
||||
public Boolean getCachingEnabled() {
|
||||
return caching_enabled;
|
||||
}
|
||||
|
||||
@SerializedName("skip_proxy")
|
||||
public Boolean skip_proxy = false;
|
||||
public void setCachingEnabled(Boolean caching_enabled) {
|
||||
this.caching_enabled = caching_enabled;
|
||||
}
|
||||
|
||||
@SerializedName("caching_enabled")
|
||||
public Boolean caching_enabled;
|
||||
public Boolean getCacheTimestamp() {
|
||||
return cache_timestamp;
|
||||
}
|
||||
|
||||
@SerializedName("cache_timestamp")
|
||||
public Boolean cache_timestamp;
|
||||
public void setCacheTimestamp(Boolean cache_timestamp) {
|
||||
this.cache_timestamp = cache_timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Server{" +
|
||||
"id=" + id +
|
||||
", name='" + name + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
", authkey='" + authkey + '\'' +
|
||||
", org_id=" + org_id +
|
||||
", push=" + push +
|
||||
", pull=" + pull +
|
||||
", lastpulledid=" + lastpulledid +
|
||||
", lastpushedid=" + lastpushedid +
|
||||
", organization=" + organization +
|
||||
", remote_org_id=" + remote_org_id +
|
||||
", publish_without_email=" + publish_without_email +
|
||||
", unpublish_event=" + unpublish_event +
|
||||
", self_signed=" + self_signed +
|
||||
", pull_rules='" + pull_rules + '\'' +
|
||||
", push_rules='" + push_rules + '\'' +
|
||||
", cert_file=" + cert_file +
|
||||
", client_cert_file=" + client_cert_file +
|
||||
", internal=" + internal +
|
||||
", skip_proxy=" + skip_proxy +
|
||||
", caching_enabled=" + caching_enabled +
|
||||
", cache_timestamp=" + cache_timestamp +
|
||||
'}';
|
||||
return "Server: \n" +
|
||||
"\t id = " + id + '\n' +
|
||||
"\t name = " + name + '\n' +
|
||||
"\t url = " + url + '\n' +
|
||||
"\t authkey = " + authkey + '\n' +
|
||||
"\t org_id = " + org_id + '\n' +
|
||||
"\t push = " + push + '\n' +
|
||||
"\t pull = " + pull + '\n' +
|
||||
"\t lastpulledid = " + lastpulledid + '\n' +
|
||||
"\t lastpushedid = " + lastpushedid + '\n' +
|
||||
"\t organization = " + organization + '\n' +
|
||||
"\t remote_org_id = " + remote_org_id + '\n' +
|
||||
"\t publish_without_email = " + publish_without_email + '\n' +
|
||||
"\t unpublish_event = " + unpublish_event + '\n' +
|
||||
"\t self_signed = " + self_signed + '\n' +
|
||||
"\t pull_rules = " + pull_rules + '\n' +
|
||||
"\t push_rules = " + push_rules + '\n' +
|
||||
"\t cert_file = " + cert_file + '\n' +
|
||||
"\t client_cert_file = " + client_cert_file + '\n' +
|
||||
"\t internal = " + internal + '\n' +
|
||||
"\t skip_proxy = " + skip_proxy + '\n' +
|
||||
"\t caching_enabled = " + caching_enabled + '\n' +
|
||||
"\t cache_timestamp = " + cache_timestamp;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,125 +1,249 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import lu.circl.mispbump.auxiliary.RandomString;
|
||||
|
||||
|
||||
public class User {
|
||||
|
||||
public static final int ROLE_ADMIN = 1;
|
||||
public static final int ROLE_ORG_ADMIN = 2;
|
||||
public static final int ROLE_USER = 3;
|
||||
public static final int ROLE_PUBLISHER = 4;
|
||||
public static final int ROLE_SYNC_USER = 5;
|
||||
public static final int ROLE_READ_ONLY = 6;
|
||||
private Integer id;
|
||||
private String password;
|
||||
private Integer org_id;
|
||||
private String email;
|
||||
private Boolean autoalert;
|
||||
private String authkey;
|
||||
private String invited_by;
|
||||
private Object gpgkey;
|
||||
private String certif_public;
|
||||
private String nids_sid;
|
||||
private Boolean termsaccepted;
|
||||
private String newsread;
|
||||
private Integer role_id;
|
||||
private String change_pw;
|
||||
private Boolean contactalert;
|
||||
private Boolean disabled;
|
||||
private Object expiration;
|
||||
private String current_login;
|
||||
private String last_login;
|
||||
private Boolean force_logout;
|
||||
private Object date_created;
|
||||
private String date_modified;
|
||||
|
||||
public User() {
|
||||
|
||||
public User toSyncUser() {
|
||||
User user = new User();
|
||||
user.email = email;
|
||||
user.authkey = new RandomString(40).nextString();
|
||||
user.password = new RandomString(16).nextString();
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public User(Integer org_id, String email, Integer role_id) {
|
||||
this.org_id = org_id;
|
||||
this.email = email;
|
||||
this.role_id = role_id;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public User(Integer org_id, String email, Integer role_id, String password) {
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Integer getOrgId() {
|
||||
return org_id;
|
||||
}
|
||||
|
||||
public void setOrgId(Integer org_id) {
|
||||
this.org_id = org_id;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public Boolean getAutoalert() {
|
||||
return autoalert;
|
||||
}
|
||||
|
||||
public void setAutoalert(Boolean autoalert) {
|
||||
this.autoalert = autoalert;
|
||||
}
|
||||
|
||||
public String getAuthkey() {
|
||||
return authkey;
|
||||
}
|
||||
|
||||
public void setAuthkey(String authkey) {
|
||||
this.authkey = authkey;
|
||||
}
|
||||
|
||||
public String getInvitedBy() {
|
||||
return invited_by;
|
||||
}
|
||||
|
||||
public void setInvitedBy(String invited_by) {
|
||||
this.invited_by = invited_by;
|
||||
}
|
||||
|
||||
public Object getGpgKey() {
|
||||
return gpgkey;
|
||||
}
|
||||
|
||||
public void setGpgKey(Object gpgkey) {
|
||||
this.gpgkey = gpgkey;
|
||||
}
|
||||
|
||||
public String getCertIfPublic() {
|
||||
return certif_public;
|
||||
}
|
||||
|
||||
public void setCertIfPublic(String certif_public) {
|
||||
this.certif_public = certif_public;
|
||||
}
|
||||
|
||||
public String getNidsSid() {
|
||||
return nids_sid;
|
||||
}
|
||||
|
||||
public void setNidsSid(String nids_sid) {
|
||||
this.nids_sid = nids_sid;
|
||||
}
|
||||
|
||||
public Boolean getTermsAccepted() {
|
||||
return termsaccepted;
|
||||
}
|
||||
|
||||
public void setTermsAccepted(Boolean termsaccepted) {
|
||||
this.termsaccepted = termsaccepted;
|
||||
}
|
||||
|
||||
public String getNewsRead() {
|
||||
return newsread;
|
||||
}
|
||||
|
||||
public void setNewsRead(String newsread) {
|
||||
this.newsread = newsread;
|
||||
}
|
||||
|
||||
public Integer getRoleId() {
|
||||
return role_id;
|
||||
}
|
||||
|
||||
public void setRoleId(Integer role_id) {
|
||||
this.role_id = role_id;
|
||||
}
|
||||
|
||||
@SerializedName("id")
|
||||
@Expose
|
||||
public Integer id;
|
||||
@SerializedName("password")
|
||||
@Expose
|
||||
public String password;
|
||||
@SerializedName("org_id")
|
||||
@Expose
|
||||
public Integer org_id;
|
||||
@SerializedName("email")
|
||||
@Expose
|
||||
public String email;
|
||||
@SerializedName("autoalert")
|
||||
@Expose
|
||||
public Boolean autoalert;
|
||||
@SerializedName("authkey")
|
||||
@Expose
|
||||
public String authkey;
|
||||
@SerializedName("invited_by")
|
||||
@Expose
|
||||
public String invited_by;
|
||||
@SerializedName("gpgkey")
|
||||
@Expose
|
||||
public Object gpgkey;
|
||||
@SerializedName("certif_public")
|
||||
@Expose
|
||||
public String certif_public;
|
||||
@SerializedName("nids_sid")
|
||||
@Expose
|
||||
public String nids_sid;
|
||||
@SerializedName("termsaccepted")
|
||||
@Expose
|
||||
public Boolean termsaccepted;
|
||||
@SerializedName("newsread")
|
||||
@Expose
|
||||
public String newsread;
|
||||
@SerializedName("role_id")
|
||||
@Expose
|
||||
public Integer role_id;
|
||||
@SerializedName("change_pw")
|
||||
@Expose
|
||||
public String change_pw;
|
||||
@SerializedName("contactalert")
|
||||
@Expose
|
||||
public Boolean contactalert;
|
||||
@SerializedName("disabled")
|
||||
@Expose
|
||||
public Boolean disabled;
|
||||
@SerializedName("expiration")
|
||||
@Expose
|
||||
public Object expiration;
|
||||
@SerializedName("current_login")
|
||||
@Expose
|
||||
public String current_login;
|
||||
@SerializedName("last_login")
|
||||
@Expose
|
||||
public String last_login;
|
||||
@SerializedName("force_logout")
|
||||
@Expose
|
||||
public Boolean force_logout;
|
||||
@SerializedName("date_created")
|
||||
@Expose
|
||||
public Object date_created;
|
||||
@SerializedName("date_modified")
|
||||
@Expose
|
||||
public String date_modified;
|
||||
public String getChangePw() {
|
||||
return change_pw;
|
||||
}
|
||||
|
||||
public void setChangePw(String change_pw) {
|
||||
this.change_pw = change_pw;
|
||||
}
|
||||
|
||||
public Boolean getContactalert() {
|
||||
return contactalert;
|
||||
}
|
||||
|
||||
public void setContactalert(Boolean contactalert) {
|
||||
this.contactalert = contactalert;
|
||||
}
|
||||
|
||||
public Boolean getDisabled() {
|
||||
return disabled;
|
||||
}
|
||||
|
||||
public void setDisabled(Boolean disabled) {
|
||||
this.disabled = disabled;
|
||||
}
|
||||
|
||||
public Object getExpiration() {
|
||||
return expiration;
|
||||
}
|
||||
|
||||
public void setExpiration(Object expiration) {
|
||||
this.expiration = expiration;
|
||||
}
|
||||
|
||||
public String getCurrentLogin() {
|
||||
return current_login;
|
||||
}
|
||||
|
||||
public void setCurrentLogin(String current_login) {
|
||||
this.current_login = current_login;
|
||||
}
|
||||
|
||||
public String getLastLogin() {
|
||||
return last_login;
|
||||
}
|
||||
|
||||
public void setLastLogin(String last_login) {
|
||||
this.last_login = last_login;
|
||||
}
|
||||
|
||||
public Boolean getForceLogout() {
|
||||
return force_logout;
|
||||
}
|
||||
|
||||
public void setForceLogout(Boolean force_logout) {
|
||||
this.force_logout = force_logout;
|
||||
}
|
||||
|
||||
public Object getDateCreated() {
|
||||
return date_created;
|
||||
}
|
||||
|
||||
public void setDateCreated(Object date_created) {
|
||||
this.date_created = date_created;
|
||||
}
|
||||
|
||||
public String getDateModified() {
|
||||
return date_modified;
|
||||
}
|
||||
|
||||
public void setDateModified(String date_modified) {
|
||||
this.date_modified = date_modified;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "User{" +
|
||||
"id='" + id + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", org_id='" + org_id + '\'' +
|
||||
", email='" + email + '\'' +
|
||||
", autoalert=" + autoalert +
|
||||
", authkey='" + authkey + '\'' +
|
||||
", invited_by='" + invited_by + '\'' +
|
||||
", gpgkey=" + gpgkey +
|
||||
", certif_public='" + certif_public + '\'' +
|
||||
", nids_sid='" + nids_sid + '\'' +
|
||||
", termsaccepted=" + termsaccepted +
|
||||
", newsread='" + newsread + '\'' +
|
||||
", role_id='" + role_id + '\'' +
|
||||
", change_pw='" + change_pw + '\'' +
|
||||
", contactalert=" + contactalert +
|
||||
", disabled=" + disabled +
|
||||
", expiration=" + expiration +
|
||||
", current_login='" + current_login + '\'' +
|
||||
", last_login='" + last_login + '\'' +
|
||||
", force_logout=" + force_logout +
|
||||
", date_created=" + date_created +
|
||||
", date_modified='" + date_modified + '\'' +
|
||||
'}';
|
||||
return "User: \n" +
|
||||
"\t id = " + id + '\n' +
|
||||
"\t password = " + password + '\n' +
|
||||
"\t org_id = " + org_id + '\n' +
|
||||
"\t email = " + email + '\n' +
|
||||
"\t autoalert = " + autoalert + '\n' +
|
||||
"\t authkey = " + authkey + '\n' +
|
||||
"\t invited_by = " + invited_by + '\n' +
|
||||
"\t gpgkey = " + gpgkey + '\n' +
|
||||
"\t certif_public = " + certif_public + '\n' +
|
||||
"\t nids_sid = " + nids_sid + '\n' +
|
||||
"\t termsaccepted = " + termsaccepted + '\n' +
|
||||
"\t newsread = " + newsread + '\n' +
|
||||
"\t role_id = " + role_id + '\n' +
|
||||
"\t change_pw = " + change_pw + '\n' +
|
||||
"\t contactalert = " + contactalert + '\n' +
|
||||
"\t disabled = " + disabled + '\n' +
|
||||
"\t expiration = " + expiration + '\n' +
|
||||
"\t current_login = " + current_login + '\n' +
|
||||
"\t last_login = " + last_login + '\n' +
|
||||
"\t force_logout = " + force_logout + '\n' +
|
||||
"\t date_created = " + date_created + '\n' +
|
||||
"\t date_modified = " + date_modified;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
package lu.circl.mispbump.models.restModels;
|
||||
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
|
||||
public class Version {
|
||||
|
||||
@SerializedName("version")
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.security;
|
||||
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
@ -22,6 +23,7 @@ import javax.crypto.NoSuchPaddingException;
|
|||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
|
||||
/**
|
||||
* This class provides the functionality generate a shared secret key.
|
||||
* Furthermore it contains the encryption/decryption methods.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package lu.circl.mispbump.security;
|
||||
|
||||
|
||||
import android.security.keystore.KeyGenParameterSpec;
|
||||
import android.security.keystore.KeyProperties;
|
||||
import android.util.Base64;
|
||||
|
@ -25,12 +26,13 @@ import javax.crypto.NoSuchPaddingException;
|
|||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.GCMParameterSpec;
|
||||
|
||||
|
||||
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";
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<alpha
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:duration="@android:integer/config_shortAnimTime" />
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
/>
|
||||
</set>
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<alpha
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:duration="@android:integer/config_shortAnimTime" />
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
/>
|
||||
</set>
|
|
@ -1,5 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="100%p" android:toYDelta="0" android:duration="300"/>
|
||||
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="300" />
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromYDelta="100%p"
|
||||
android:toYDelta="0"
|
||||
android:duration="300"
|
||||
/>
|
||||
<alpha
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:duration="300"
|
||||
/>
|
||||
</set>
|
|
@ -1,5 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromYDelta="0" android:toYDelta="-100%p" android:duration="300"/>
|
||||
<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="300" />
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromYDelta="0"
|
||||
android:toYDelta="-100%p"
|
||||
android:duration="300"
|
||||
/>
|
||||
<alpha
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:duration="300"
|
||||
/>
|
||||
</set>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<scale
|
||||
android:duration="500"
|
||||
|
@ -8,6 +9,7 @@
|
|||
android:pivotX="50%"
|
||||
android:pivotY="10%"
|
||||
android:toXScale="1.0"
|
||||
android:toYScale="1.0" />
|
||||
android:toYScale="1.0"
|
||||
/>
|
||||
|
||||
</set>
|
|
@ -1,7 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromXDelta="50%p" android:toXDelta="0"
|
||||
android:duration="@android:integer/config_mediumAnimTime"/>
|
||||
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="50%p"
|
||||
android:toXDelta="0"
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
/>
|
||||
<alpha
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
/>
|
||||
</set>
|
|
@ -1,7 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate android:fromXDelta="0" android:toXDelta="-50%p"
|
||||
android:duration="@android:integer/config_mediumAnimTime"/>
|
||||
<alpha android:fromAlpha="1.0" android:toAlpha="0.0"
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<translate
|
||||
android:fromXDelta="0"
|
||||
android:toXDelta="-50%p"
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
/>
|
||||
<alpha
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
android:duration="@android:integer/config_mediumAnimTime"
|
||||
/>
|
||||
</set>
|
|
@ -7,4 +7,5 @@
|
|||
android:propertyName="rotation"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="-180"
|
||||
android:valueType="floatType"/>
|
||||
android:valueType="floatType"
|
||||
/>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||
|
@ -7,6 +8,7 @@
|
|||
android:propertyName="x"
|
||||
android:valueFrom="1000"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
android:valueType="floatType"
|
||||
/>
|
||||
|
||||
</set>
|
|
@ -1,5 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:interpolator="@android:interpolator/accelerate_cubic"
|
||||
|
@ -7,6 +8,7 @@
|
|||
android:propertyName="x"
|
||||
android:valueFrom="-1000"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType" />
|
||||
android:valueType="floatType"
|
||||
/>
|
||||
|
||||
</set>
|
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="1000"
|
||||
android:valueType="floatType" />
|
||||
android:valueType="floatType"
|
||||
/>
|
||||
|
||||
</set>
|
|
@ -1,11 +1,13 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<objectAnimator
|
||||
android:duration="300"
|
||||
android:propertyName="x"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="-1000"
|
||||
android:valueType="floatType" />
|
||||
android:valueType="floatType"
|
||||
/>
|
||||
|
||||
</set>
|
|
@ -1,27 +1,33 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108">
|
||||
android:viewportWidth="108"
|
||||
>
|
||||
<path
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1">
|
||||
android:strokeWidth="1"
|
||||
>
|
||||
<aapt:attr name="android:fillColor">
|
||||
<gradient
|
||||
android:endX="78.5885"
|
||||
android:endY="90.9159"
|
||||
android:startX="48.7653"
|
||||
android:startY="61.0927"
|
||||
android:type="linear">
|
||||
android:type="linear"
|
||||
>
|
||||
<item
|
||||
android:color="#44000000"
|
||||
android:offset="0.0" />
|
||||
android:offset="0.0"
|
||||
/>
|
||||
<item
|
||||
android:color="#00000000"
|
||||
android:offset="1.0" />
|
||||
android:offset="1.0"
|
||||
/>
|
||||
</gradient>
|
||||
</aapt:attr>
|
||||
</path>
|
||||
|
@ -30,5 +36,6 @@
|
|||
android:fillType="nonZero"
|
||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1" />
|
||||
android:strokeWidth="1"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group
|
||||
android:name="group"
|
||||
android:pivotX="12"
|
||||
android:pivotY="12">
|
||||
<path
|
||||
android:name="cloud"
|
||||
android:pathData="M 19.35 10.04 C 18.67 6.59 15.64 4 12 4 C 9.11 4 6.6 5.64 5.35 8.04 C 2.34 8.36 0 10.91 0 14 C 0 17.31 2.69 20 6 20 L 19 20 C 21.76 20 24 17.76 24 15 C 24 12.36 21.95 10.22 19.35 10.04 Z M 19 18 L 6 18 C 3.79 18 2 16.21 2 14 C 2 11.79 3.79 10 6 10 L 6.71 10 C 7.37 7.69 9.48 6 12 6 C 15.04 6 17.5 8.46 17.5 11.5 L 17.5 12 L 19 12 C 20.66 12 22 13.34 22 15 C 22 16.66 20.66 18 19 18 Z"
|
||||
android:fillColor="#000"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="cloud">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="300"
|
||||
android:valueFrom="M 14.588 4.459 C 15.395 4.755 16.136 5.187 16.785 5.726 C 17.434 6.266 17.99 6.913 18.427 7.641 C 18.863 8.369 19.18 9.178 19.35 10.04 C 19.35 10.04 19.35 10.04 19.35 10.04 C 21.95 10.22 24 12.36 24 15 C 24 17.76 21.76 20 19 20 C 14.667 20 10.333 20 6 20 C 2.69 20 0 17.31 0 14 C 0 10.91 2.34 8.36 5.35 8.04 C 6.6 5.64 9.11 4 12 4 C 12.91 4 13.782 4.162 14.588 4.459 M 6.71 10 L 6 10 C 3.79 10 2 11.79 2 14 C 2 16.21 3.79 18 6 18 L 19 18 L 19 18 C 20.66 18 22 16.66 22 15 C 22 13.34 20.66 12 19 12 L 17.5 12 L 17.5 11.5 C 17.5 8.46 15.04 6 12 6 C 9.48 6 7.37 7.69 6.71 10"
|
||||
android:valueTo="M 8.12 9.29 C 9.413 10.583 10.707 11.877 12 13.17 C 13.293 11.877 14.587 10.583 15.88 9.29 C 16.27 8.9 16.9 8.9 17.29 9.29 C 17.68 9.68 17.68 10.31 17.29 10.7 C 16.525 11.465 15.76 12.23 14.995 12.995 C 14.23 13.76 13.465 14.525 12.7 15.29 C 12.31 15.68 11.68 15.68 11.29 15.29 C 9.76 13.76 8.23 12.23 6.7 10.7 C 6.31 10.31 6.31 9.68 6.7 9.29 C 7.09 8.91 7.73 8.9 8.12 9.29 C 8.12 9.29 8.12 9.29 8.12 9.29 M 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 L 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 L 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="group">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="rotation"
|
||||
android:duration="300"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="360"
|
||||
android:valueType="floatType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -0,0 +1,44 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<group
|
||||
android:name="group"
|
||||
android:pivotX="12"
|
||||
android:pivotY="12">
|
||||
<path
|
||||
android:name="cloud"
|
||||
android:pathData="M 19.35 10.04 C 18.67 6.59 15.64 4 12 4 C 9.11 4 6.6 5.64 5.35 8.04 C 2.34 8.36 0 10.91 0 14 C 0 17.31 2.69 20 6 20 L 19 20 C 21.76 20 24 17.76 24 15 C 24 12.36 21.95 10.22 19.35 10.04 Z M 19 18 L 6 18 C 3.79 18 2 16.21 2 14 C 2 11.79 3.79 10 6 10 L 6.71 10 C 7.37 7.69 9.48 6 12 6 C 15.04 6 17.5 8.46 17.5 11.5 L 17.5 12 L 19 12 C 20.66 12 22 13.34 22 15 C 22 16.66 20.66 18 19 18 Z"
|
||||
android:fillColor="#000"
|
||||
android:strokeWidth="1" />
|
||||
</group>
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="cloud">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="400"
|
||||
android:valueFrom="M 17.29 9.29 C 16.9 8.9 16.27 8.9 15.88 9.29 C 14.587 10.583 13.293 11.877 12 13.17 C 10.707 11.877 9.413 10.583 8.12 9.29 C 8.12 9.29 8.12 9.29 8.12 9.29 C 7.73 8.9 7.09 8.91 6.7 9.29 C 6.31 9.68 6.31 10.31 6.7 10.7 C 8.23 12.23 9.76 13.76 11.29 15.29 C 11.68 15.68 12.31 15.68 12.7 15.29 C 13.465 14.525 14.23 13.76 14.995 12.995 C 15.76 12.23 16.525 11.465 17.29 10.7 C 17.68 10.31 17.68 9.68 17.29 9.29 M 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 L 11.75 12.75 L 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 C 11.75 12.75 11.75 12.75 11.75 12.75 L 11.75 12.75"
|
||||
android:valueTo="M 19.35 10.04 C 19.18 9.178 18.863 8.369 18.427 7.641 C 17.99 6.913 17.434 6.266 16.785 5.726 C 16.136 5.187 15.395 4.755 14.588 4.459 C 13.782 4.162 12.91 4 12 4 C 9.11 4 6.6 5.64 5.35 8.04 C 2.34 8.36 0 10.91 0 14 C 0 17.31 2.69 20 6 20 C 10.333 20 14.667 20 19 20 C 21.76 20 24 17.76 24 15 C 24 12.36 21.95 10.22 19.35 10.04 C 19.35 10.04 19.35 10.04 19.35 10.04 M 19 18 L 6 18 C 3.79 18 2 16.21 2 14 C 2 11.79 3.79 10 6 10 L 6.71 10 C 7.37 7.69 9.48 6 12 6 C 15.04 6 17.5 8.46 17.5 11.5 L 17.5 12 L 19 12 C 20.66 12 22 13.34 22 15 C 22 16.66 20.66 18 19 18 L 19 18"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
<target android:name="group">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="rotation"
|
||||
android:duration="400"
|
||||
android:valueFrom="0"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -0,0 +1,27 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="down"
|
||||
android:pathData="M 8.12 9.29 L 12 13.17 L 15.88 9.29 C 16.27 8.9 16.9 8.9 17.29 9.29 C 17.68 9.68 17.68 10.31 17.29 10.7 L 12.7 15.29 C 12.31 15.68 11.68 15.68 11.29 15.29 L 6.7 10.7 C 6.31 10.31 6.31 9.68 6.7 9.29 C 7.09 8.91 7.73 8.9 8.12 9.29 Z"
|
||||
android:fillColor="#FF000000" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="down">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="250"
|
||||
android:valueFrom="M 8.12 9.29 L 12 13.17 L 15.88 9.29 C 16.27 8.9 16.9 8.9 17.29 9.29 C 17.68 9.68 17.68 10.31 17.29 10.7 L 12.7 15.29 C 12.31 15.68 11.68 15.68 11.29 15.29 L 6.7 10.7 C 6.31 10.31 6.31 9.68 6.7 9.29 C 7.09 8.91 7.73 8.9 8.12 9.29 Z"
|
||||
android:valueTo="M 8.12 14.71 L 12 10.83 L 15.88 14.71 C 16.27 15.1 16.9 15.1 17.29 14.71 C 17.68 14.32 17.68 13.69 17.29 13.3 L 12.7 8.71 C 12.31 8.32 11.68 8.32 11.29 8.71 L 6.7 13.3 C 6.31 13.69 6.31 14.32 6.7 14.71 C 7.09 15.09 7.73 15.1 8.12 14.71 Z"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -0,0 +1,27 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="down"
|
||||
android:pathData="M 8.12 9.29 L 12 13.17 L 15.88 9.29 C 16.27 8.9 16.9 8.9 17.29 9.29 C 17.68 9.68 17.68 10.31 17.29 10.7 L 12.7 15.29 C 12.31 15.68 11.68 15.68 11.29 15.29 L 6.7 10.7 C 6.31 10.31 6.31 9.68 6.7 9.29 C 7.09 8.91 7.73 8.9 8.12 9.29 Z"
|
||||
android:fillColor="#FF000000" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="down">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="250"
|
||||
android:valueFrom="M 8.12 14.71 L 12 10.83 L 15.88 14.71 C 16.27 15.1 16.9 15.1 17.29 14.71 C 17.68 14.32 17.68 13.69 17.29 13.3 L 12.7 8.71 C 12.31 8.32 11.68 8.32 11.29 8.71 L 6.7 13.3 C 6.31 13.69 6.31 14.32 6.7 14.71 C 7.09 15.09 7.73 15.1 8.12 14.71 Z"
|
||||
android:valueTo="M 8.12 9.29 L 12 13.17 L 15.88 9.29 C 16.27 8.9 16.9 8.9 17.29 9.29 C 17.68 9.68 17.68 10.31 17.29 10.7 L 12.7 15.29 C 12.31 15.68 11.68 15.68 11.29 15.29 L 6.7 10.7 C 6.31 10.31 6.31 9.68 6.7 9.29 C 7.09 8.91 7.73 8.9 8.12 9.29 Z"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -0,0 +1,27 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="eye_visible"
|
||||
android:pathData="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 Z"
|
||||
android:fillColor="#FF000000" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="eye_visible">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="300"
|
||||
android:valueFrom="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 14.411 6.703 C 12.751 6.703 11.411 8.043 11.411 9.703 C 11.411 11.363 12.751 12.703 14.411 12.703 C 16.071 12.703 17.411 11.363 17.411 9.703 C 17.411 8.043 16.071 6.703 14.411 6.703 Z"
|
||||
android:valueTo="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 Z"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -0,0 +1,27 @@
|
|||
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:aapt="http://schemas.android.com/aapt">
|
||||
<aapt:attr name="android:drawable">
|
||||
<vector
|
||||
android:name="vector"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:name="eye_visible"
|
||||
android:pathData="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 Z"
|
||||
android:fillColor="#FF000000" />
|
||||
</vector>
|
||||
</aapt:attr>
|
||||
<target android:name="eye_visible">
|
||||
<aapt:attr name="android:animation">
|
||||
<objectAnimator
|
||||
android:propertyName="pathData"
|
||||
android:duration="300"
|
||||
android:valueFrom="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 12 9 C 10.34 9 9 10.34 9 12 C 9 13.66 10.34 15 12 15 C 13.66 15 15 13.66 15 12 C 15 10.34 13.66 9 12 9 Z"
|
||||
android:valueTo="M 12 4.5 C 7 4.5 2.73 7.61 1 12 C 2.73 16.39 7 19.5 12 19.5 C 17 19.5 21.27 16.39 23 12 C 21.27 7.61 17 4.5 12 4.5 Z M 12 17 C 9.24 17 7 14.76 7 12 C 7 9.24 9.24 7 12 7 C 14.76 7 17 9.24 17 12 C 17 14.76 14.76 17 12 17 Z M 14.411 6.703 C 12.751 6.703 11.411 8.043 11.411 9.703 C 11.411 11.363 12.751 12.703 14.411 12.703 C 16.071 12.703 17.411 11.363 17.411 9.703 C 17.411 8.043 16.071 6.703 14.411 6.703 Z"
|
||||
android:valueType="pathType"
|
||||
android:interpolator="@android:interpolator/fast_out_slow_in" />
|
||||
</aapt:attr>
|
||||
</target>
|
||||
</animated-vector>
|
|
@ -1,8 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<animated-vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_sync_black_24dp">
|
||||
android:drawable="@drawable/ic_sync_black_24dp"
|
||||
>
|
||||
<target
|
||||
android:name="rotation"
|
||||
android:animation="@animator/rotation_cw"/>
|
||||
android:animation="@animator/rotation_cw"
|
||||
/>
|
||||
</animated-vector>
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#B4B4B4"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#B4B4B4"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,5c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM12,19.2c-2.5,0 -4.71,-1.28 -6,-3.22 0.03,-1.99 4,-3.08 6,-3.08 1.99,0 5.97,1.09 6,3.08 -1.29,1.94 -3.5,3.22 -6,3.22z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12.72,2.03C6.63,1.6 1.6,6.63 2.03,12.72 2.39,18.01 7.01,22 12.31,22H16c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-3.67c-3.73,0 -7.15,-2.42 -8.08,-6.03 -1.49,-5.8 3.91,-11.21 9.71,-9.71C17.58,5.18 20,8.6 20,12.33v1.1c0,0.79 -0.71,1.57 -1.5,1.57s-1.5,-0.78 -1.5,-1.57v-1.25c0,-2.51 -1.78,-4.77 -4.26,-5.12 -3.4,-0.49 -6.27,2.45 -5.66,5.87 0.34,1.91 1.83,3.49 3.72,3.94 1.84,0.43 3.59,-0.16 4.74,-1.33 0.89,1.22 2.67,1.86 4.3,1.21 1.34,-0.53 2.16,-1.9 2.16,-3.34v-1.09c0,-5.31 -3.99,-9.93 -9.28,-10.29zM12,15c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3z"
|
||||
android:fillAlpha=".9"/>
|
||||
android:fillAlpha=".9"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"/>
|
||||
android:pathData="M19,11H7.83l4.88,-4.88c0.39,-0.39 0.39,-1.03 0,-1.42 -0.39,-0.39 -1.02,-0.39 -1.41,0l-6.59,6.59c-0.39,0.39 -0.39,1.02 0,1.41l6.59,6.59c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L7.83,13H19c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M8.12,9.29L12,13.17l3.88,-3.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-4.59,4.59c-0.39,0.39 -1.02,0.39 -1.41,0L6.7,10.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.38 1.03,-0.39 1.42,0z"/>
|
||||
</vector>
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M5,13h11.17l-4.88,4.88c-0.39,0.39 -0.39,1.03 0,1.42 0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l-6.58,-6.6c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L16.17,11H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"/>
|
||||
android:pathData="M5,13h11.17l-4.88,4.88c-0.39,0.39 -0.39,1.03 0,1.42 0.39,0.39 1.02,0.39 1.41,0l6.59,-6.59c0.39,-0.39 0.39,-1.02 0,-1.41l-6.58,-6.6c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L16.17,11H5c-0.55,0 -1,0.45 -1,1s0.45,1 1,1z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,4c-4.42,0 -8,3.58 -8,8 0,1.04 0.2,2.04 0.57,2.95 0.27,0.67 1.13,0.85 1.64,0.34 0.27,-0.27 0.38,-0.68 0.23,-1.04C6.15,13.56 6,12.79 6,12c0,-3.31 2.69,-6 6,-6zM17.79,8.71c-0.27,0.27 -0.38,0.69 -0.23,1.04 0.28,0.7 0.44,1.46 0.44,2.25 0,3.31 -2.69,6 -6,6v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35L12,20c4.42,0 8,-3.58 8,-8 0,-1.04 -0.2,-2.04 -0.57,-2.95 -0.27,-0.67 -1.13,-0.85 -1.64,-0.34z"/>
|
||||
android:pathData="M12,6v1.79c0,0.45 0.54,0.67 0.85,0.35l2.79,-2.79c0.2,-0.2 0.2,-0.51 0,-0.71l-2.79,-2.79c-0.31,-0.31 -0.85,-0.09 -0.85,0.36L12,4c-4.42,0 -8,3.58 -8,8 0,1.04 0.2,2.04 0.57,2.95 0.27,0.67 1.13,0.85 1.64,0.34 0.27,-0.27 0.38,-0.68 0.23,-1.04C6.15,13.56 6,12.79 6,12c0,-3.31 2.69,-6 6,-6zM17.79,8.71c-0.27,0.27 -0.38,0.69 -0.23,1.04 0.28,0.7 0.44,1.46 0.44,2.25 0,3.31 -2.69,6 -6,6v-1.79c0,-0.45 -0.54,-0.67 -0.85,-0.35l-2.79,2.79c-0.2,0.2 -0.2,0.51 0,0.71l2.79,2.79c0.31,0.31 0.85,0.09 0.85,-0.35L12,20c4.42,0 8,-3.58 8,-8 0,-1.04 -0.2,-2.04 -0.57,-2.95 -0.27,-0.67 -1.13,-0.85 -1.64,-0.34z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="100dp"
|
||||
android:height="20dp"
|
||||
android:viewportWidth="100"
|
||||
android:viewportHeight="20">
|
||||
android:viewportHeight="20"
|
||||
>
|
||||
<path
|
||||
android:pathData="M21.184,20C21.541,19.87 21.904,19.736 22.272,19.598C22.635,19.463 23.871,19 24.04,18.937C33.64,15.348 39.647,14 50,14C60.271,14 65.362,15.222 74.629,18.928C75.584,19.311 76.498,19.668 77.379,20L83.604,20C81.093,19.269 78.465,18.309 75.371,17.072C65.888,13.278 60.562,12 50,12C39.374,12 33.145,13.397 23.34,17.063C23.169,17.127 21.934,17.59 21.573,17.725C19.098,18.648 16.913,19.399 14.849,20L21.184,20L21.184,20ZM21.184,0C13.258,2.892 8.077,4 0,4L0,4L0,2C5.744,2 9.951,1.426 14.849,0L21.184,0L21.184,0ZM77.379,0C85.239,2.966 90.502,4 100,4L100,2C93.158,2 88.614,1.458 83.604,0L77.379,0L77.379,0ZM0,14C8.441,14 13.718,12.79 22.272,9.598C22.635,9.463 23.871,9 24.04,8.937C33.64,5.348 39.647,4 50,4C60.271,4 65.362,5.222 74.629,8.928C84.112,12.722 89.438,14 100,14L100,12C89.729,12 84.638,10.778 75.371,7.072C65.888,3.278 60.562,2 50,2C39.374,2 33.145,3.397 23.34,7.063C23.169,7.127 21.934,7.59 21.573,7.725C13.224,10.84 8.164,12 0,12L0,14L0,14L0,14Z"
|
||||
android:strokeWidth="1"
|
||||
android:fillColor="@color/colorAccent"
|
||||
android:fillAlpha="0.5"
|
||||
android:fillType="evenOdd"
|
||||
android:strokeColor="#00000000"/>
|
||||
android:strokeColor="#00000000"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,7 +1,17 @@
|
|||
<vector android:height="100dp" android:viewportHeight="100.00009"
|
||||
android:viewportWidth="100.00009" android:width="100dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillAlpha="1" android:fillColor="#ffffff"
|
||||
<vector
|
||||
android:height="100dp"
|
||||
android:viewportHeight="100.00009"
|
||||
android:viewportWidth="100.00009"
|
||||
android:width="100dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillAlpha="1"
|
||||
android:fillColor="#ffffff"
|
||||
android:fillType="nonZero"
|
||||
android:pathData="m0,0v4.233c0,-2.345 1.888,-4.233 4.233,-4.233zM95.767,0c2.345,0 4.233,1.888 4.233,4.233L100,0ZM0,95.767v4.233h4.233c-2.345,0 -4.233,-1.888 -4.233,-4.233zM100,95.767c0,2.345 -1.888,4.233 -4.233,4.233h4.233z"
|
||||
android:strokeAlpha="1" android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||
android:strokeAlpha="1"
|
||||
android:strokeColor="#00000000"
|
||||
android:strokeWidth="1"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"/>
|
||||
android:pathData="M9,16.17L5.53,12.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l4.18,4.18c0.39,0.39 1.02,0.39 1.41,0L20.29,7.71c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.02,-0.39 -1.41,0L9,16.17z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.88,8.29L10,14.17l-1.88,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0L17.3,9.7c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0z"/>
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15.88,8.29L10,14.17l-1.88,-1.88c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41l2.59,2.59c0.39,0.39 1.02,0.39 1.41,0L17.3,9.7c0.39,-0.39 0.39,-1.02 0,-1.41 -0.39,-0.39 -1.03,-0.39 -1.42,0z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"/>
|
||||
android:pathData="M18.3,5.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L12,10.59 7.11,5.7c-0.39,-0.39 -1.02,-0.39 -1.41,0 -0.39,0.39 -0.39,1.02 0,1.41L10.59,12 5.7,16.89c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.39 1.02,0.39 1.41,0L12,13.41l4.89,4.89c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L13.41,12l4.89,-4.89c0.38,-0.38 0.38,-1.02 0,-1.4z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="48dp"
|
||||
android:height="48dp"
|
||||
android:viewportWidth="48"
|
||||
android:viewportHeight="48">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M38.71,20.07C37.35,13.19 31.28,8 24,8c-5.78,0 -10.79,3.28 -13.3,8.07C4.69,16.72 0,21.81 0,28c0,6.63 5.37,12 12,12h26c5.52,0 10,-4.48 10,-10 0,-5.28 -4.11,-9.56 -9.29,-9.93zM34,26L24,36 14,26h6v-8h8v8h6z"/>
|
||||
</vector>
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFF" android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM14,13v4h-4v-4H7l5,-5 5,5h-3z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,9c0,-1.1 -0.9,-2 -2,-2L8,7c-1.1,0 -2,0.9 -2,2v10zM9.17,11.17c0.39,-0.39 1.02,-0.39 1.41,0L12,12.59l1.42,-1.42c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L13.41,14l1.42,1.42c0.39,0.39 0.39,1.02 0,1.41 -0.39,0.39 -1.02,0.39 -1.41,0L12,15.41l-1.42,1.42c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,14l-1.42,-1.42c-0.39,-0.38 -0.39,-1.02 0,-1.41zM15.5,4l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L9.91,3c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4L6,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5z"/>
|
||||
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2L18,9c0,-1.1 -0.9,-2 -2,-2L8,7c-1.1,0 -2,0.9 -2,2v10zM9.17,11.17c0.39,-0.39 1.02,-0.39 1.41,0L12,12.59l1.42,-1.42c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41L13.41,14l1.42,1.42c0.39,0.39 0.39,1.02 0,1.41 -0.39,0.39 -1.02,0.39 -1.41,0L12,15.41l-1.42,1.42c-0.39,0.39 -1.02,0.39 -1.41,0 -0.39,-0.39 -0.39,-1.02 0,-1.41L10.59,14l-1.42,-1.42c-0.39,-0.38 -0.39,-1.02 0,-1.41zM15.5,4l-0.71,-0.71c-0.18,-0.18 -0.44,-0.29 -0.7,-0.29L9.91,3c-0.26,0 -0.52,0.11 -0.7,0.29L8.5,4L6,4c-0.55,0 -1,0.45 -1,1s0.45,1 1,1h12c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1h-2.5z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FF000000" android:pathData="M12,7L12,3L2,3v18h20L22,7L12,7zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2L12,9h8v10zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,7L12,3L2,3v18h20L22,7L12,7zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2L12,9h8v10zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"/>
|
||||
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM19.6,8.25l-7.07,4.42c-0.32,0.2 -0.74,0.2 -1.06,0L4.4,8.25c-0.25,-0.16 -0.4,-0.43 -0.4,-0.72 0,-0.67 0.73,-1.07 1.3,-0.72L12,11l6.7,-4.19c0.57,-0.35 1.3,0.05 1.3,0.72 0,0.29 -0.15,0.56 -0.4,0.72z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M12,7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM13,17h-2v-2h2v2z"/>
|
||||
android:pathData="M12,7c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1L11,8c0,-0.55 0.45,-1 1,-1zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM13,17h-2v-2h2v2z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
|
||||
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M15,1L4,1c-1.1,0 -2,0.9 -2,2v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,4c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15.59,5.59l4.83,4.83c0.37,0.37 0.58,0.88 0.58,1.41L21,21c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h6.17c0.53,0 1.04,0.21 1.42,0.59zM15,12h4.5L14,6.5L14,11c0,0.55 0.45,1 1,1z"/>
|
||||
android:pathData="M15,1L4,1c-1.1,0 -2,0.9 -2,2v13c0,0.55 0.45,1 1,1s1,-0.45 1,-1L4,4c0,-0.55 0.45,-1 1,-1h10c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1zM15.59,5.59l4.83,4.83c0.37,0.37 0.58,0.88 0.58,1.41L21,21c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h6.17c0.53,0 1.04,0.21 1.42,0.59zM15,12h4.5L14,6.5L14,11c0,0.55 0.45,1 1,1z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12,2A10,10 0,0 0,2 12C2,16.42 4.87,20.17 8.84,21.5C9.34,21.58 9.5,21.27 9.5,21C9.5,20.77 9.5,20.14 9.5,19.31C6.73,19.91 6.14,17.97 6.14,17.97C5.68,16.81 5.03,16.5 5.03,16.5C4.12,15.88 5.1,15.9 5.1,15.9C6.1,15.97 6.63,16.93 6.63,16.93C7.5,18.45 8.97,18 9.54,17.76C9.63,17.11 9.89,16.67 10.17,16.42C7.95,16.17 5.62,15.31 5.62,11.5C5.62,10.39 6,9.5 6.65,8.79C6.55,8.54 6.2,7.5 6.75,6.15C6.75,6.15 7.59,5.88 9.5,7.17C10.29,6.95 11.15,6.84 12,6.84C12.85,6.84 13.71,6.95 14.5,7.17C16.41,5.88 17.25,6.15 17.25,6.15C17.8,7.5 17.45,8.54 17.35,8.79C18,9.5 18.38,10.39 18.38,11.5C18.38,15.32 16.04,16.16 13.81,16.41C14.17,16.72 14.5,17.33 14.5,18.26C14.5,19.6 14.5,20.68 14.5,21C14.5,21.27 14.66,21.59 15.17,21.5C19.14,20.16 22,16.42 22,12A10,10 0,0 0,12 2Z"/>
|
||||
</vector>
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v2h-2zM12.61,6.04c-2.06,-0.3 -3.88,0.97 -4.43,2.79 -0.18,0.58 0.26,1.17 0.87,1.17h0.2c0.41,0 0.74,-0.29 0.88,-0.67 0.32,-0.89 1.27,-1.5 2.3,-1.28 0.95,0.2 1.65,1.13 1.57,2.1 -0.1,1.34 -1.62,1.63 -2.45,2.88 0,0.01 -0.01,0.01 -0.01,0.02 -0.01,0.02 -0.02,0.03 -0.03,0.05 -0.09,0.15 -0.18,0.32 -0.25,0.5 -0.01,0.03 -0.03,0.05 -0.04,0.08 -0.01,0.02 -0.01,0.04 -0.02,0.07 -0.12,0.34 -0.2,0.75 -0.2,1.25h2c0,-0.42 0.11,-0.77 0.28,-1.07 0.02,-0.03 0.03,-0.06 0.05,-0.09 0.08,-0.14 0.18,-0.27 0.28,-0.39 0.01,-0.01 0.02,-0.03 0.03,-0.04 0.1,-0.12 0.21,-0.23 0.33,-0.34 0.96,-0.91 2.26,-1.65 1.99,-3.56 -0.24,-1.74 -1.61,-3.21 -3.35,-3.47z"/>
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v2h-2zM12.61,6.04c-2.06,-0.3 -3.88,0.97 -4.43,2.79 -0.18,0.58 0.26,1.17 0.87,1.17h0.2c0.41,0 0.74,-0.29 0.88,-0.67 0.32,-0.89 1.27,-1.5 2.3,-1.28 0.95,0.2 1.65,1.13 1.57,2.1 -0.1,1.34 -1.62,1.63 -2.45,2.88 0,0.01 -0.01,0.01 -0.01,0.02 -0.01,0.02 -0.02,0.03 -0.03,0.05 -0.09,0.15 -0.18,0.32 -0.25,0.5 -0.01,0.03 -0.03,0.05 -0.04,0.08 -0.01,0.02 -0.01,0.04 -0.02,0.07 -0.12,0.34 -0.2,0.75 -0.2,1.25h2c0,-0.42 0.11,-0.77 0.28,-1.07 0.02,-0.03 0.03,-0.06 0.05,-0.09 0.08,-0.14 0.18,-0.27 0.28,-0.39 0.01,-0.01 0.02,-0.03 0.03,-0.04 0.1,-0.12 0.21,-0.23 0.33,-0.34 0.96,-0.91 2.26,-1.65 1.99,-3.56 -0.24,-1.74 -1.61,-3.21 -3.35,-3.47z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,16h2v2h-2zM12.61,6.04c-2.06,-0.3 -3.88,0.97 -4.43,2.79 -0.18,0.58 0.26,1.17 0.87,1.17h0.2c0.41,0 0.74,-0.29 0.88,-0.67 0.32,-0.89 1.27,-1.5 2.3,-1.28 0.95,0.2 1.65,1.13 1.57,2.1 -0.1,1.34 -1.62,1.63 -2.45,2.88 0,0.01 -0.01,0.01 -0.01,0.02 -0.01,0.02 -0.02,0.03 -0.03,0.05 -0.09,0.15 -0.18,0.32 -0.25,0.5 -0.01,0.03 -0.03,0.05 -0.04,0.08 -0.01,0.02 -0.01,0.04 -0.02,0.07 -0.12,0.34 -0.2,0.75 -0.2,1.25h2c0,-0.42 0.11,-0.77 0.28,-1.07 0.02,-0.03 0.03,-0.06 0.05,-0.09 0.08,-0.14 0.18,-0.27 0.28,-0.39 0.01,-0.01 0.02,-0.03 0.03,-0.04 0.1,-0.12 0.21,-0.23 0.33,-0.34 0.96,-0.91 2.26,-1.65 1.99,-3.56 -0.24,-1.74 -1.61,-3.21 -3.35,-3.47z"
|
||||
/>
|
||||
</vector>
|
|
@ -1,5 +1,13 @@
|
|||
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFF" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
|
||||
<vector
|
||||
android:height="24dp"
|
||||
android:tint="#FFFFFF"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FFF"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<vector
|
||||
android:height="24dp"
|
||||
android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0"
|
||||
android:width="24dp"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"
|
||||
/>
|
||||
</vector>
|
|
@ -1,9 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
android:viewportHeight="24"
|
||||
>
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M12.65,10C11.7,7.31 8.9,5.5 5.77,6.12c-2.29,0.46 -4.15,2.29 -4.63,4.58C0.32,14.57 3.26,18 7,18c2.61,0 4.83,-1.67 5.65,-4H17v2c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-8.35zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
|
||||
android:pathData="M12.65,10C11.7,7.31 8.9,5.5 5.77,6.12c-2.29,0.46 -4.15,2.29 -4.63,4.58C0.32,14.57 3.26,18 7,18c2.61,0 4.83,-1.67 5.65,-4H17v2c0,1.1 0.9,2 2,2s2,-0.9 2,-2v-2c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2h-8.35zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"
|
||||
/>
|
||||
</vector>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue