diff --git a/app/build.gradle b/app/build.gradle index f7bd235..46df4c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,5 +57,4 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation project(path: ':expandablecardview') } diff --git a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java index e714148..9d8d778 100644 --- a/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java +++ b/app/src/main/java/lu/circl/mispbump/activities/HomeActivity.java @@ -111,7 +111,7 @@ public class HomeActivity extends AppCompatActivity { private void initRecyclerView() { recyclerView = findViewById(R.id.recyclerView); recyclerView.setLayoutManager(new LinearLayoutManager(HomeActivity.this)); - syncInfoAdapter = new SyncInfoAdapter(); + syncInfoAdapter = new SyncInfoAdapter(HomeActivity.this); syncInfoAdapter.setOnRecyclerPositionClickListener(onRecyclerItemClickListener()); recyclerView.setAdapter(syncInfoAdapter); } diff --git a/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java index e5e18f3..6901aff 100644 --- a/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java +++ b/app/src/main/java/lu/circl/mispbump/activities/LauncherActivity.java @@ -26,7 +26,7 @@ public class LauncherActivity extends AppCompatActivity { startActivity(login); } - // closes the activity to prevent going back to this (empty) activity + // close activity to prevent going back finish(); } diff --git a/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java b/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java index 37cdf3e..9c04cae 100644 --- a/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java +++ b/app/src/main/java/lu/circl/mispbump/activities/LoginActivity.java @@ -189,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); @@ -205,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 !automationKey.equals(""); + return !automationKey.isEmpty(); } } diff --git a/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java index 8722aaa..dbbb585 100644 --- a/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java +++ b/app/src/main/java/lu/circl/mispbump/activities/SyncInfoDetailActivity.java @@ -1,19 +1,16 @@ package lu.circl.mispbump.activities; +import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Intent; -import android.graphics.Color; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.Drawable; +import android.graphics.drawable.AnimatedVectorDrawable; import android.os.Bundle; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroupOverlay; -import android.widget.CheckBox; +import android.view.animation.DecelerateInterpolator; import android.widget.LinearLayout; +import android.widget.TextView; -import androidx.annotation.NonNull; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; @@ -25,6 +22,7 @@ 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; @@ -37,12 +35,13 @@ public class SyncInfoDetailActivity extends AppCompatActivity { 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); + setContentView(R.layout.activity_sync_info_detail_v2); preferenceManager = PreferenceManager.getInstance(SyncInfoDetailActivity.this); syncInformation = preferenceManager.getSyncInformation(getExtraUuid()); @@ -59,6 +58,11 @@ public class SyncInfoDetailActivity extends AppCompatActivity { @Override protected void onPause() { super.onPause(); + + if (dataLocallyChanged) { + syncInformation.setSyncedWithRemote(false); + } + preferenceManager.addSyncInformation(syncInformation); } @@ -85,25 +89,121 @@ public class SyncInfoDetailActivity extends AppCompatActivity { 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); - fab.setOnClickListener(view -> { - if (fabMenuExpanded) { - uploadLayout.setVisibility(View.GONE); - downloadLayout.setVisibility(View.GONE); + int animationSpeed = 200; - fabMenuExpanded = false; - } else { + 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) { - fabMenuExpanded = true; } }); - fabUpload.setOnClickListener(view -> { + 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); @@ -134,24 +234,61 @@ public class SyncInfoDetailActivity extends AppCompatActivity { // settings - CheckBox allowSelfSigned = findViewById(R.id.checkbox_self_signed); + MaterialPreferenceSwitch allowSelfSigned = findViewById(R.id.switch_allow_self_signed); allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned()); - allowSelfSigned.setOnCheckedChangeListener((compoundButton, b) -> { + allowSelfSigned.setOnCheckedChangeListener((cb, b) -> { syncInformation.getRemote().getServer().setSelfSigned(b); - + dataLocallyChanged = true; }); - CheckBox push = findViewById(R.id.checkbox_push); - push.setChecked(syncInformation.getRemote().getServer().getPush()); - push.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setPush(b)); + 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; + }); - CheckBox pull = findViewById(R.id.checkbox_pull); - pull.setChecked(syncInformation.getRemote().getServer().getPull()); - pull.setOnCheckedChangeListener((compundButton, b) -> syncInformation.getRemote().getServer().setPull(b)); + 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; + }); - CheckBox cache = findViewById(R.id.checkbox_cache); - cache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled()); - cache.setOnCheckedChangeListener((compoundButton, b) -> syncInformation.getRemote().getServer().setCachingEnabled(b)); + 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; + }); + +// CheckBox allowSelfSigned = findViewById(R.id.checkbox_self_signed); +// allowSelfSigned.setChecked(syncInformation.getRemote().getServer().getSelfSigned()); +// allowSelfSigned.setOnCheckedChangeListener((compoundButton, b) -> { +// syncInformation.getRemote().getServer().setSelfSigned(b); +// dataLocallyChanged = true; +// }); + +// CheckBox push = findViewById(R.id.checkbox_push); +// push.setChecked(syncInformation.getRemote().getServer().getPush()); +// push.setOnCheckedChangeListener((compoundButton, b) -> { +// syncInformation.getRemote().getServer().setPush(b); +// dataLocallyChanged = true; +// }); +// +// CheckBox pull = findViewById(R.id.checkbox_pull); +// pull.setChecked(syncInformation.getRemote().getServer().getPull()); +// pull.setOnCheckedChangeListener((compundButton, b) -> { +// syncInformation.getRemote().getServer().setPull(b); +// dataLocallyChanged = true; +// }); +// +// CheckBox cache = findViewById(R.id.checkbox_cache); +// cache.setChecked(syncInformation.getRemote().getServer().getCachingEnabled()); +// cache.setOnCheckedChangeListener((compoundButton, b) -> { +// syncInformation.getRemote().getServer().setCachingEnabled(b); +// dataLocallyChanged = true; +// }); // credentials @@ -164,27 +301,4 @@ public class SyncInfoDetailActivity extends AppCompatActivity { MaterialPasswordView authkey = findViewById(R.id.authkey); authkey.setPassword(syncInformation.getLocal().getSyncUser().getAuthkey()); } - - - public static void applyDim(@NonNull ViewGroup parent, float dimAmount) { -// ViewGroup root = (ViewGroup) getWindow().getDecorView().getRootView(); - Drawable dim = new ColorDrawable(Color.BLACK); - dim.setBounds(0, 0, parent.getWidth(), parent.getHeight()); - - ValueAnimator valueAnimator = ValueAnimator.ofFloat(dimAmount); - - valueAnimator.addUpdateListener(valueAnim -> { - float value = (float) valueAnim.getAnimatedValue(); - dim.setAlpha((int) (255 * value)); - ViewGroupOverlay overlay = parent.getOverlay(); - overlay.add(dim); - }); - - valueAnimator.start(); - } - - public static void clearDim(@NonNull ViewGroup parent) { - ViewGroupOverlay overlay = parent.getOverlay(); - overlay.clear(); - } } diff --git a/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java index 4586d91..a5a097a 100644 --- a/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java +++ b/app/src/main/java/lu/circl/mispbump/adapters/SyncInfoAdapter.java @@ -1,6 +1,8 @@ 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; @@ -8,6 +10,7 @@ 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; @@ -21,10 +24,16 @@ import lu.circl.mispbump.models.SyncInformation; public class SyncInfoAdapter extends RecyclerView.Adapter { + private Context context; private List items; private OnRecyclerItemClickListener onRecyclerPositionClickListener; + public SyncInfoAdapter(Context context) { + this.context = context; + } + + @NonNull @Override public SyncInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) { @@ -44,6 +53,14 @@ public class SyncInfoAdapter extends RecyclerView.Adapter { + if (switchView.isEnabled()) { + switchView.setChecked(!switchView.isChecked()); } }); - switchView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (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); } } }); @@ -75,4 +81,8 @@ public class MaterialPreferenceSwitch extends ConstraintLayout { return switchView.isChecked(); } + public void setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener onCheckedChangeListener) { + this.onCheckedChangeListener = onCheckedChangeListener; + } + } diff --git a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java index 93ffabd..d60d202 100644 --- a/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java +++ b/app/src/main/java/lu/circl/mispbump/models/SyncInformation.java @@ -21,6 +21,8 @@ public class SyncInformation { private ExchangeInformation remote; private ExchangeInformation local; + private boolean syncedWithRemote; + public SyncInformation() { uuid = UUID.randomUUID(); @@ -60,6 +62,12 @@ public class SyncInformation { return df.format(date); } + public void setSyncedWithRemote(boolean syncedWithRemote) { + this.syncedWithRemote = syncedWithRemote; + } + public boolean isSyncedWithRemote() { + return syncedWithRemote; + } public ExchangeInformation getRemote() { return remote; diff --git a/app/src/main/res/layout/activity_sync_info_detail.xml b/app/src/main/res/layout/activity_sync_info_detail.xml deleted file mode 100644 index ed6fd55..0000000 --- a/app/src/main/res/layout/activity_sync_info_detail.xml +++ /dev/null @@ -1,289 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/activity_sync_info_detail_v2.xml b/app/src/main/res/layout/activity_sync_info_detail_v2.xml new file mode 100644 index 0000000..5ab8915 --- /dev/null +++ b/app/src/main/res/layout/activity_sync_info_detail_v2.xml @@ -0,0 +1,324 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d936fef..4a3d7b9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -50,4 +50,7 @@ Besuchen Sie das Github Projekt App Informationen Synchronisations Details + Informationen + Änderungen hochladen + Änderungen herunterladen diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b49bdc6..494ae58 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,4 +56,7 @@ App information Visit the Github project Synchronisation details + Information + Upload Changes + Download Changes diff --git a/build.gradle b/build.gradle index 02d253b..6990763 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.5.0' + classpath 'com.android.tools.build:gradle:3.5.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/settings.gradle b/settings.gradle index ff5c4e6..e7b4def 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':expandablecardview' +include ':app'