Merge pull request #2 from cybertier/reorganize-sync-process

Reorganize sync process
pull/5/head
Felix PK 2019-07-14 19:21:39 +02:00 committed by GitHub
commit 8bdab947f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 359 additions and 191 deletions

View File

@ -1,6 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="JavadocReference" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuspiciousNameCombination" enabled="false" level="WARNING" enabled_by_default="false">
<group names="x,width,left,right" />
<group names="y,height,top,bottom" />

View File

@ -25,7 +25,7 @@ dependencies {
// android
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0-beta01'
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'

View File

@ -12,7 +12,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
@ -43,9 +43,9 @@ public class ExchangeActivity extends AppCompatActivity {
private CameraFragment cameraFragment;
private CoordinatorLayout rootLayout;
private View qrFrame;
private TextView qrInfo;
private ConstraintLayout rootLayout;
private View qrFrame, scanFeedbackView, continueHintView, fragmentContainer;
private TextView scanFeedbackText, qrContentInfo;
private ImageView qrCode;
private ImageButton prevButton, nextButton;
@ -76,10 +76,15 @@ public class ExchangeActivity extends AppCompatActivity {
private void initViews() {
rootLayout = findViewById(R.id.rootLayout);
fragmentContainer = findViewById(R.id.fragmentContainer);
qrFrame = findViewById(R.id.qrFrame);
qrCode = findViewById(R.id.qrCode);
qrInfo = findViewById(R.id.qrInfo);
scanFeedbackView = findViewById(R.id.scanFeedbackView);
scanFeedbackText = findViewById(R.id.scanFeedbackText);
continueHintView = findViewById(R.id.continueHint);
qrContentInfo = findViewById(R.id.qrContentInfo);
prevButton = findViewById(R.id.prevButton);
prevButton.setOnClickListener(onPrevClicked());
@ -126,15 +131,12 @@ public class ExchangeActivity extends AppCompatActivity {
@Override
public void run() {
qrCode.setImageBitmap(bitmap);
qrFrame.setVisibility(View.VISIBLE); // TODO animate
qrFrame.setVisibility(View.VISIBLE);
}
});
}
private void setSyncState(SyncState state) {
Log.d("DEBUG", "current sync state: " + state);
currentSyncState = state;
runOnUiThread(new Runnable() {
@ -147,8 +149,11 @@ public class ExchangeActivity extends AppCompatActivity {
nextButton.setVisibility(View.GONE);
setCameraPreviewEnabled(true);
setReadQrStatus(ReadQrStatus.PENDING);
showQrCode(publicKeyQr);
setReadQrStatus(ReadQrStatus.PENDING);
scanFeedbackText.setText(R.string.scan_qr_hint);
qrContentInfo.setText(R.string.public_key);
break;
case KEY_EXCHANGE_DONE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_close));
@ -157,8 +162,11 @@ public class ExchangeActivity extends AppCompatActivity {
nextButton.setVisibility(View.VISIBLE);
setCameraPreviewEnabled(false);
setReadQrStatus(ReadQrStatus.SUCCESS);
showQrCode(publicKeyQr);
setReadQrStatus(ReadQrStatus.SUCCESS);
scanFeedbackText.setText(R.string.public_key_received_hint);
qrContentInfo.setText(R.string.public_key);
break;
case DATA_EXCHANGE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
@ -166,8 +174,11 @@ public class ExchangeActivity extends AppCompatActivity {
nextButton.setVisibility(View.GONE);
setCameraPreviewEnabled(true);
setReadQrStatus(ReadQrStatus.PENDING);
showQrCode(dataQr);
setReadQrStatus(ReadQrStatus.PENDING);
scanFeedbackText.setText(R.string.scan_qr_hint);
qrContentInfo.setText(R.string.sync_information);
break;
case DATA_EXCHANGE_DONE:
prevButton.setImageDrawable(getDrawable(R.drawable.ic_arrow_back));
@ -176,8 +187,11 @@ public class ExchangeActivity extends AppCompatActivity {
nextButton.setVisibility(View.VISIBLE);
setCameraPreviewEnabled(false);
setReadQrStatus(ReadQrStatus.SUCCESS);
showQrCode(dataQr);
setReadQrStatus(ReadQrStatus.SUCCESS);
scanFeedbackText.setText(R.string.sync_info_received_hint);
qrContentInfo.setText(R.string.public_key);
break;
}
}
@ -185,7 +199,6 @@ public class ExchangeActivity extends AppCompatActivity {
}
private void setReadQrStatus(ReadQrStatus status) {
currentReadQrStatus = status;
final Drawable drawable;
@ -206,17 +219,26 @@ public class ExchangeActivity extends AppCompatActivity {
break;
default:
drawable = getDrawable(R.drawable.ic_info_outline);
color = getColor(R.color.status_green);
color = getColor(R.color.status_amber);
break;
}
runOnUiThread(new Runnable() {
@Override
public void run() {
qrInfo.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
qrInfo.setCompoundDrawableTintList(ColorStateList.valueOf(color));
}
});
scanFeedbackText.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
scanFeedbackText.setCompoundDrawableTintList(ColorStateList.valueOf(color));
if (currentReadQrStatus == ReadQrStatus.SUCCESS) {
continueHintView.setVisibility(View.VISIBLE);
scanFeedbackView.setBackgroundTintList(ColorStateList.valueOf(getColor(R.color.white)));
qrFrame.setBackgroundTintList(ColorStateList.valueOf(getColor(R.color.white)));
fragmentContainer.animate().alpha(0).setDuration(250).start();
} else {
continueHintView.setVisibility(View.GONE);
scanFeedbackView.setBackgroundTintList(ColorStateList.valueOf(getColor(R.color.white_80)));
qrFrame.setBackgroundTintList(ColorStateList.valueOf(getColor(R.color.white_80)));
fragmentContainer.animate().alpha(1).setDuration(250).start();
}
}
private void setCameraPreviewEnabled(boolean enabled) {

View File

@ -33,7 +33,6 @@ import lu.circl.mispbump.models.restModels.User;
public class LoginActivity extends AppCompatActivity {
private PreferenceManager preferenceManager;
private MispRestClient mispRestClient;
private ConstraintLayout constraintLayout;
private TextInputLayout serverAutomationKey;
@ -46,7 +45,6 @@ public class LoginActivity extends AppCompatActivity {
setContentView(R.layout.activity_login);
preferenceManager = PreferenceManager.getInstance(this);
mispRestClient = MispRestClient.getInstance(LoginActivity.this);
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
@ -97,7 +95,6 @@ public class LoginActivity extends AppCompatActivity {
private View.OnClickListener onClickDownload = new View.OnClickListener() {
@Override
public void onClick(View v) {
final String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString();
final String authkey = Objects.requireNonNull(serverAutomationKey.getEditText()).getText().toString();
@ -120,7 +117,7 @@ public class LoginActivity extends AppCompatActivity {
return;
}
mispRestClient.initMispRestInterface(url);
final MispRestClient mispRestClient = MispRestClient.getInstance(url, authkey);
// display progress bar
progressBar.setVisibility(View.VISIBLE);

View File

@ -46,8 +46,8 @@ public class ProfileActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
mispRestClient = MispRestClient.getInstance(this);
preferenceManager = PreferenceManager.getInstance(this);
mispRestClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey());
init();
populateInformationViews();

View File

@ -2,14 +2,15 @@ package lu.circl.mispbump.activities;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.models.restModels.User;
/**
* This activity navigates to the next activity base on the user status.
* This is the first activity that gets loaded when the user starts the app.
* Starts either the login or home activity.
*/
public class StartUpActivity extends AppCompatActivity {

View File

@ -99,7 +99,7 @@ public class UploadActivity extends AppCompatActivity {
setContentView(R.layout.activity_upload);
preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
restClient = MispRestClient.getInstance(this);
restClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey());
parseExtra();
initViews();

View File

@ -1,7 +1,8 @@
package lu.circl.mispbump.auxiliary;
import android.annotation.SuppressLint;
import android.content.Context;
import androidx.annotation.NonNull;
import org.json.JSONException;
import org.json.JSONObject;
@ -45,98 +46,25 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class MispRestClient {
public interface AvailableCallback {
void available();
void unavailable(String error);
}
public interface UserCallback {
void success(User user);
void failure(String error);
}
public interface AllUsersCallback {
void success(User[] users);
void failure(String error);
}
public interface OrganisationCallback {
void success(Organisation organisation);
void failure(String error);
}
public interface AllOrganisationsCallback {
void success(Organisation[] organisations);
void failure(String error);
}
public interface ServerCallback {
void success(Server server);
void failure(String error);
}
public interface AllServersCallback {
void success(Server[] servers);
void failure(String error);
}
private static MispRestClient instance;
private PreferenceManager preferenceManager;
private MispRestInterface mispRestInterface;
public static MispRestClient getInstance(Context context) {
public static MispRestClient getInstance(String url, String authkey) {
if (instance == null) {
instance = new MispRestClient(context);
instance = new MispRestClient();
}
instance.initMispRestInterface(url, authkey);
return instance;
}
public static MispRestClient getInstance(Context context, String url) {
if (instance == null) {
instance = new MispRestClient(context, url);
}
return instance;
}
private MispRestClient(Context context) {
this(context, null);
}
/**
* Initializes the rest client to communicate with a MISP instance.
*
* @param context needed to access the preferences for loading credentials
*/
private MispRestClient(Context context, String url) {
preferenceManager = PreferenceManager.getInstance(context);
if (url == null) {
url = preferenceManager.getServerUrl();
}
initMispRestInterface(url);
}
public void initMispRestInterface(String url) {
public void initMispRestInterface(String url, String authkey) {
try {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(getCustomClient(true, false))
.client(getCustomClient(true, false, authkey))
.build();
mispRestInterface = retrofit.create(MispRestInterface.class);
@ -151,7 +79,7 @@ public class MispRestClient {
* @param logging whether to log Retrofit calls (for debugging)
* @return {@link OkHttpClient}
*/
private OkHttpClient getCustomClient(boolean unsafe, boolean logging) {
private OkHttpClient getCustomClient(boolean unsafe, boolean logging, final String authkey) {
try {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
@ -206,7 +134,7 @@ public class MispRestClient {
Request.Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Accept", "application/json");
ongoing.addHeader("Content-Type", "application/json");
ongoing.addHeader("Authorization", preferenceManager.getAutomationKey());
ongoing.addHeader("Authorization", authkey);
return chain.proceed(ongoing.build());
}
});
@ -228,7 +156,7 @@ public class MispRestClient {
Call<Version> call = mispRestInterface.pyMispVersion();
call.enqueue(new Callback<Version>() {
@Override
public void onResponse(Call<Version> call, Response<Version> response) {
public void onResponse(@NonNull Call<Version> call, @NonNull Response<Version> response) {
if (!response.isSuccessful()) {
if (response.code() == 403) {
callback.available();
@ -242,7 +170,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<Version> call, Throwable t) {
public void onFailure(@NonNull Call<Version> call, @NonNull Throwable t) {
callback.unavailable(extractError(t));
}
});
@ -259,7 +187,7 @@ public class MispRestClient {
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
public void onResponse(@NonNull Call<MispUser> call, @NonNull Response<MispUser> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -272,7 +200,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
public void onFailure(@NonNull Call<MispUser> call, @NonNull Throwable t) {
t.printStackTrace();
callback.failure(t.getMessage());
}
@ -291,7 +219,7 @@ public class MispRestClient {
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
public void onResponse(@NonNull Call<MispUser> call, @NonNull Response<MispUser> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -304,7 +232,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
public void onFailure(@NonNull Call<MispUser> call, @NonNull Throwable t) {
t.printStackTrace();
callback.failure(t.getMessage());
}
@ -337,7 +265,7 @@ public class MispRestClient {
call.enqueue(new Callback<List<MispUser>>() {
@Override
public void onResponse(Call<List<MispUser>> call, Response<List<MispUser>> response) {
public void onResponse(@NonNull Call<List<MispUser>> call, @NonNull Response<List<MispUser>> response) {
if (!response.isSuccessful()) {
callback.failure("Failed onResponse");
return;
@ -356,7 +284,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<List<MispUser>> call, Throwable t) {
public void onFailure(@NonNull Call<List<MispUser>> call, @NonNull Throwable t) {
callback.failure(extractError(t));
}
});
@ -373,7 +301,7 @@ public class MispRestClient {
call.enqueue(new Callback<MispUser>() {
@Override
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
public void onResponse(@NonNull Call<MispUser> call, @NonNull Response<MispUser> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -383,7 +311,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<MispUser> call, Throwable t) {
public void onFailure(@NonNull Call<MispUser> call, @NonNull Throwable t) {
callback.failure(t.getMessage());
}
});
@ -403,7 +331,7 @@ public class MispRestClient {
call.enqueue(new Callback<MispOrganisation>() {
@Override
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
public void onResponse(@NonNull Call<MispOrganisation> call, @NonNull Response<MispOrganisation> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -416,7 +344,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<MispOrganisation> call, Throwable t) {
public void onFailure(@NonNull Call<MispOrganisation> call, @NonNull Throwable t) {
callback.failure(t.getMessage());
}
});
@ -448,7 +376,7 @@ public class MispRestClient {
call.enqueue(new Callback<List<MispOrganisation>>() {
@Override
public void onResponse(Call<List<MispOrganisation>> call, Response<List<MispOrganisation>> response) {
public void onResponse(@NonNull Call<List<MispOrganisation>> call, @NonNull Response<List<MispOrganisation>> response) {
if (!response.isSuccessful()) {
// TODO handle
return;
@ -468,7 +396,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<List<MispOrganisation>> call, Throwable t) {
public void onFailure(@NonNull Call<List<MispOrganisation>> call, @NonNull Throwable t) {
callback.failure(extractError(t));
}
});
@ -485,7 +413,7 @@ public class MispRestClient {
call.enqueue(new Callback<MispOrganisation>() {
@Override
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
public void onResponse(@NonNull Call<MispOrganisation> call, @NonNull Response<MispOrganisation> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -495,7 +423,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<MispOrganisation> call, Throwable t) {
public void onFailure(@NonNull Call<MispOrganisation> call, @NonNull Throwable t) {
callback.failure(t.getMessage());
}
});
@ -517,7 +445,7 @@ public class MispRestClient {
call.enqueue(new Callback<List<MispServer>>() {
@Override
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
public void onResponse(@NonNull Call<List<MispServer>> call, @NonNull Response<List<MispServer>> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -536,7 +464,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<List<MispServer>> call, Throwable t) {
public void onFailure(@NonNull Call<List<MispServer>> call, @NonNull Throwable t) {
callback.failure(t.getMessage());
}
});
@ -553,7 +481,7 @@ public class MispRestClient {
call.enqueue(new Callback<Server>() {
@Override
public void onResponse(Call<Server> call, Response<Server> response) {
public void onResponse(@NonNull Call<Server> call, @NonNull Response<Server> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
@ -562,7 +490,7 @@ public class MispRestClient {
}
@Override
public void onFailure(Call<Server> call, Throwable t) {
public void onFailure(@NonNull Call<Server> call, @NonNull Throwable t) {
callback.failure(t.getMessage());
throw new RuntimeException(t);
}
@ -648,4 +576,48 @@ public class MispRestClient {
return t.getMessage();
}
// interfaces
public interface AvailableCallback {
void available();
void unavailable(String error);
}
public interface UserCallback {
void success(User user);
void failure(String error);
}
public interface AllUsersCallback {
void success(User[] users);
void failure(String error);
}
public interface OrganisationCallback {
void success(Organisation organisation);
void failure(String error);
}
public interface AllOrganisationsCallback {
void success(Organisation[] organisations);
void failure(String error);
}
public interface ServerCallback {
void success(Server server);
void failure(String error);
}
public interface AllServersCallback {
void success(Server[] servers);
void failure(String error);
}
}

View File

@ -210,7 +210,7 @@ public class PreferenceManager {
* @return decrypted automation key associated with the current user. If no user exists an empty
* String is returned.
*/
public String getAutomationKey() {
public String getAuthKey() {
if (!preferences.contains(AUTOMATION_KEY)) {
return "";
@ -284,12 +284,12 @@ public class PreferenceManager {
public String getServerUrl() {
if (!preferences.contains(SERVER_URL)) {
return "";
return null;
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, ""));
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, null));
} catch (NoSuchPaddingException e) {
e.printStackTrace();
@ -305,7 +305,7 @@ public class PreferenceManager {
e.printStackTrace();
}
return "";
return null;
}
/**

View File

@ -0,0 +1,59 @@
package lu.circl.mispbump.customViews;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import lu.circl.mispbump.R;
public class FixedAspectRatioFrameLayout extends FrameLayout {
private int mAspectRatioWidth;
private int mAspectRatioHeight;
public FixedAspectRatioFrameLayout(Context context) {
super(context);
}
public FixedAspectRatioFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public FixedAspectRatioFrameLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FixedAspectRatioFrameLayout);
mAspectRatioWidth = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioWidth, 1);
mAspectRatioHeight = a.getInt(R.styleable.FixedAspectRatioFrameLayout_aspectRatioHeight, 1);
a.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int originalWidth = MeasureSpec.getSize(widthMeasureSpec);
int originalHeight = MeasureSpec.getSize(heightMeasureSpec);
int calculatedHeight = originalWidth * mAspectRatioHeight / mAspectRatioWidth;
int finalWidth, finalHeight;
if (calculatedHeight > originalHeight) {
finalWidth = originalHeight * mAspectRatioWidth / mAspectRatioHeight;
finalHeight = originalHeight;
} else {
finalWidth = originalWidth;
finalHeight = calculatedHeight;
}
super.onMeasure(
MeasureSpec.makeMeasureSpec(finalWidth, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(finalHeight, MeasureSpec.EXACTLY));
}
}

View File

@ -0,0 +1,7 @@
<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"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:fillColor="#FFF"
android:pathData="M11.19,1.36l-7,3.11C3.47,4.79 3,5.51 3,6.3L3,11c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12L21,6.3c0,-0.79 -0.47,-1.51 -1.19,-1.83l-7,-3.11c-0.51,-0.23 -1.11,-0.23 -1.62,0zM9.29,16.29L6.7,13.7c-0.39,-0.39 -0.39,-1.02 0,-1.41 0.39,-0.39 1.02,-0.39 1.41,0L10,14.17l5.88,-5.88c0.39,-0.39 1.02,-0.39 1.41,0 0.39,0.39 0.39,1.02 0,1.41l-6.59,6.59c-0.38,0.39 -1.02,0.39 -1.41,0z"/>
</vector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<size android:width="256dp" android:height="256dp"/>
<corners android:radius="12dp"/>
<solid android:color="@color/white"/>
<!--<corners android:radius="12dp"/>-->
</shape>
</item>
</layer-list>

View File

@ -1,98 +1,178 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark">
<FrameLayout
android:id="@+id/fragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/qrFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/rect_rounded"
android:backgroundTint="#99FFFFFF"
android:gravity="center_vertical"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:padding="8dp"
tools:layout_height="256dp"
tools:layout_width="256dp">
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="25dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:gravity="center"
app:layout_constraintBottom_toTopOf="@id/navbar_bottom">
<ImageView
android:id="@+id/qrCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/qr_code" />
<TextView
android:id="@+id/qrInfo"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/qrFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_info_outline"
android:drawablePadding="8dp"
android:drawableTint="@color/status_amber"
android:gravity="center_vertical"
android:padding="8dp"
android:text="@string/activity_exchange_scan_partner_qr_hint"
android:textColor="@color/black" />
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="16dp"
android:background="@drawable/rect_rounded"
android:backgroundTint="@color/white_80"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/navbar_bottom">
<TextView
android:id="@+id/qrInfoStatic"
<TextView
android:id="@+id/qrContentInfo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/public_key"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/qrCode" />
<ImageButton
android:id="@+id/qrInfoButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_info_outline"
android:tint="@color/black"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<ImageView
android:id="@+id/qrCode"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:src="@color/white"
app:layout_constraintBottom_toTopOf="@+id/qrInfoButton"
app:layout_constraintDimensionRatio="1:1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<LinearLayout
android:id="@+id/scanFeedbackView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawableStart="@drawable/ic_info_outline"
android:drawablePadding="8dp"
android:drawableTint="@color/colorIconDark"
android:gravity="center_vertical"
android:lines="2"
android:padding="8dp"
android:text="@string/activity_exchange_continue_if_scanned"
android:textColor="@color/black" />
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginBottom="16dp"
android:background="@drawable/rect_rounded"
android:backgroundTint="@color/white_80">
<TextView
android:id="@+id/scanFeedbackText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:drawableStart="@drawable/ic_check_outline"
android:drawableTint="@color/status_green"
android:drawablePadding="8dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
android:gravity="center_vertical"
tools:text="Public key received"/>
</LinearLayout>
<LinearLayout
android:visibility="gone"
android:id="@+id/continueHint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:background="@drawable/rect_rounded"
android:backgroundTint="@color/white">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:drawableStart="@drawable/ic_info_outline"
android:drawableTint="@color/status_amber"
android:drawablePadding="8dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
android:gravity="center_vertical"
android:text="Continue if your partner scanned this QR code"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/bottom"
android:layout_width="match_parent"
android:id="@+id/navbar_bottom"
android:layout_width="0dp"
android:layout_height="56dp"
android:layout_gravity="bottom"
android:background="@drawable/rect_rounded_top"
android:backgroundTint="@color/colorPrimary"
android:orientation="horizontal">
android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<ImageButton
android:id="@+id/prevButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="?attr/selectableItemBackground"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_prev"
android:padding="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_arrow_back"
android:contentDescription="@string/button_prev" />
app:srcCompat="@drawable/ic_arrow_back" />
<View
<TextView
android:visibility="invisible"
android:id="@+id/hint"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:layout_weight="1"
android:text="Scan each others QR codes"
android:textAlignment="center"
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
android:textColor="@color/white" />
<ImageButton
android:id="@+id/nextButton"
android:layout_width="56dp"
android:layout_height="56dp"
android:background="?attr/selectableItemBackground"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/button_continue"
android:padding="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_arrow_forward"
android:contentDescription="@string/button_continue" />
app:srcCompat="@drawable/ic_arrow_forward" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -39,4 +39,9 @@
<string name="upload_action_add_org">Organisation hinzufügen</string>
<string name="upload_action_add_server">Server hinzufügen</string>
<string name="upload_action_add_user">Benutzer hinzufügen</string>
<string name="public_key">Öffentlicher Schlüssel</string>
<string name="scan_qr_hint">Scannen Sie den QR code ihres Partners</string>
<string name="public_key_received_hint">Öffentlicher Schlüssel empfangen</string>
<string name="sync_info_received_hint">Synchronisations-Informationen empfangen</string>
<string name="sync_information">Synchronisations-Informationen</string>
</resources>

View File

@ -24,4 +24,9 @@
<declare-styleable name="UploadAction">
<attr name="description" format="string"/>
</declare-styleable>
<declare-styleable name="FixedAspectRatioFrameLayout">
<attr name="aspectRatioWidth" format="integer"/>
<attr name="aspectRatioHeight" format="integer"/>
</declare-styleable>
</resources>

View File

@ -10,6 +10,7 @@
<color name="dividerColor">#33000000</color>
<color name="white">#FFFFFF</color>
<color name="white_80">#CCFFFFFF</color>
<color name="white_50">#80FFFFFF</color>
<color name="grey">#BDBDBD</color>

View File

@ -45,4 +45,9 @@
<string name="upload_action_add_org">Add organisation</string>
<string name="upload_action_add_user">Add sync user</string>
<string name="upload_action_add_server">Add sync server</string>
<string name="public_key">Public Key</string>
<string name="scan_qr_hint">Scan your partners QR code</string>
<string name="public_key_received_hint">Received public key</string>
<string name="sync_info_received_hint">Received sync information</string>
<string name="sync_information">Sync Information</string>
</resources>