Skip to content
This repository was archived by the owner on Jan 6, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 0 additions & 16 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
compile 'com.journeyapps:zxing-android-embedded:3.0.3@aar'
compile 'com.google.zxing:core:3.2.1'
compile 'commons-codec:commons-codec:1.5'
compile 'com.github.clans:fab:1.6.2'

androidTestCompile 'com.android.support:support-annotations:23.1.1'
androidTestCompile 'com.android.support.test:runner:0.4.1'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package net.bierbaumer.otp_authenticator;

import android.content.Context;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.util.AttributeSet;
import android.view.View;

import com.github.clans.fab.FloatingActionMenu;

import java.util.List;

public class FloatingActionMenuBehavior extends CoordinatorLayout.Behavior {
private float mTranslationY;

public FloatingActionMenuBehavior(Context context, AttributeSet attrs) {
super();
}

@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
return dependency instanceof Snackbar.SnackbarLayout;
}

@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
if (child instanceof FloatingActionMenu && dependency instanceof Snackbar.SnackbarLayout) {
this.updateTranslation(parent, child, dependency);
}

return false;
}

private void updateTranslation(CoordinatorLayout parent, View child, View dependency) {
float translationY = this.getTranslationY(parent, child);
if (translationY != this.mTranslationY) {
ViewCompat.animate(child)
.cancel();
if (Math.abs(translationY - this.mTranslationY) == (float) dependency.getHeight()) {
ViewCompat.animate(child)
.translationY(translationY)
.setListener((ViewPropertyAnimatorListener) null);
} else {
ViewCompat.setTranslationY(child, translationY);
}

this.mTranslationY = translationY;
}

}

private float getTranslationY(CoordinatorLayout parent, View child) {
float minOffset = 0.0F;
List dependencies = parent.getDependencies(child);
int i = 0;

for (int z = dependencies.size(); i < z; ++i) {
View view = (View) dependencies.get(i);
if (view instanceof Snackbar.SnackbarLayout && parent.doViewsOverlap(child, view)) {
minOffset = Math.min(minOffset, ViewCompat.getTranslationY(view) - (float) view.getHeight());
}
}

return minOffset;
}
}
119 changes: 109 additions & 10 deletions app/src/main/java/net/bierbaumer/otp_authenticator/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
Expand All @@ -29,15 +30,21 @@
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
//import android.widget.Spinner; ToDo: Preparation to support other key types, see https://github.com/0xbb/otp-authenticator/issues/10

import com.github.clans.fab.FloatingActionButton;
import com.github.clans.fab.FloatingActionMenu;
import com.google.zxing.client.android.Intents;
import com.google.zxing.integration.android.IntentIntegrator;

import org.apache.commons.codec.binary.Base32;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity implements ActionMode.Callback {
private ArrayList<Entry> entries;
private EntriesAdapter adapter;
private FloatingActionMenu fam;
private FloatingActionButton fab;

private Handler handler;
Expand Down Expand Up @@ -69,7 +76,7 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String permissi
// permission was granted
doScanQRCode();
} else {
Snackbar.make(fab, R.string.msg_camera_permission, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
Snackbar.make(fam, R.string.msg_camera_permission, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
Expand All @@ -88,11 +95,11 @@ public void onDismissed(Snackbar snackbar, int event) {

private Entry nextSelection = null;
private void showNoAccount(){
Snackbar noAccountSnackbar = Snackbar.make(fab, R.string.no_accounts, Snackbar.LENGTH_INDEFINITE)
Snackbar noAccountSnackbar = Snackbar.make(fam, R.string.no_accounts, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.button_add, new View.OnClickListener() {
@Override
public void onClick(View view) {
scanQRCode();
fam.open(true);
}
});
noAccountSnackbar.show();
Expand All @@ -107,11 +114,38 @@ protected void onCreate(Bundle savedInstanceState) {
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);

fab = (FloatingActionButton) findViewById(R.id.action_scan);
fam = (FloatingActionMenu) findViewById(R.id.action_scan);
fam.setClosedOnTouchOutside(true);
fam.setOnMenuToggleListener(new FloatingActionMenu.OnMenuToggleListener() {
@Override
public void onMenuToggle(boolean opened) {
Integer icon;
if (opened) {
icon = R.drawable.ic_image_camera_alt_135dgr;
fam.setOnMenuButtonClickListener(new FloatingActionMenu.OnClickListener() {
@Override
public void onClick(View view) {
scanQRCode();
}
});
} else {
icon = R.drawable.ic_add_white_24dp;
fam.setOnMenuButtonClickListener(new FloatingActionMenu.OnClickListener() {
@Override
public void onClick(View view) {
fam.open(true);
}
});
}
fam.getMenuIconView().setImageResource(icon);
}
});
fab = (FloatingActionButton) findViewById(R.id.action_enter);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
scanQRCode();
public void onClick(View v) {
fam.close(true);
addAccount();
}
});

Expand Down Expand Up @@ -162,6 +196,71 @@ public void run() {
};
}

protected void addAccount() {
LayoutInflater inflater = getLayoutInflater();
View aa_layout = inflater.inflate(R.layout.dialog_add_account, null);
final EditText account_label = (EditText) aa_layout.findViewById(R.id.account_label);
final EditText account_key = (EditText) aa_layout.findViewById(R.id.account_key);

/* ToDo: Preparation to support other key types, see https://github.com/0xbb/otp-authenticator/issues/10
Spinner keyType = (Spinner) addAccountLayout.findViewById(R.id.key_type);
ArrayAdapter keyTypeAdapter = ArrayAdapter.createFromResource(this, R.array.spinner_key_type, android.R.layout.simple_spinner_item);
keyTypeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
keyType.setAdapter(keyTypeAdapter);
*/

AlertDialog.Builder aa_dialog = new AlertDialog.Builder(this);
aa_dialog.setTitle(R.string.add_account_title);
aa_dialog.setView(aa_layout);
aa_dialog.setNegativeButton(R.string.add_account_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (entries.isEmpty()) {
showNoAccount();
}
}
});
aa_dialog.setPositiveButton(R.string.add_account_ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
Entry e = new Entry();
e.setLabel(account_label.getText().toString());
e.setSecret(new Base32().decode(account_key.getText().toString()));
entries.add(e);
SettingsHelper.store(getApplicationContext(), entries);
adapter.notifyDataSetChanged();
Snackbar.make(fam, R.string.msg_account_added, Snackbar.LENGTH_LONG).show();
} catch (Exception e) {
Snackbar.make(fam, R.string.msg_invalid_key, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
if (entries.isEmpty()) {
showNoAccount();
}
}
}).show();
}
}
});
final AlertDialog dialog = aa_dialog.create();
TextWatcher aa_validator = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {}
@Override
public void afterTextChanged(Editable s) {
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(s.length() == 0 ? false : true);
}
};
account_key.addTextChangedListener(aa_validator);
dialog.show();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
}

@Override
public void onResume() {
super.onResume();
Expand Down Expand Up @@ -189,9 +288,9 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)

adapter.notifyDataSetChanged();

Snackbar.make(fab, R.string.msg_account_added, Snackbar.LENGTH_LONG).show();
Snackbar.make(fam, R.string.msg_account_added, Snackbar.LENGTH_LONG).show();
} catch (Exception e) {
Snackbar.make(fab, R.string.msg_invalid_qr_code, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
Snackbar.make(fam, R.string.msg_invalid_qr_code, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
Expand Down Expand Up @@ -262,7 +361,7 @@ public boolean onActionItemClicked(final ActionMode actionMode, MenuItem menuIte
public void onClick(DialogInterface dialog, int whichButton) {
entries.remove(adapter.getCurrentSelection());

Snackbar.make(fab, R.string.msg_account_removed, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
Snackbar.make(fam, R.string.msg_account_removed, Snackbar.LENGTH_LONG).setCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar snackbar, int event) {
super.onDismissed(snackbar, event);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 21 additions & 5 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,28 @@

<include layout="@layout/content_main" />

<android.support.design.widget.FloatingActionButton
<com.github.clans.fab.FloatingActionMenu
xmlns:fab="http://schemas.android.com/apk/res-auto"
android:id="@+id/action_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/fab_margin"
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_add_white_24dp"></android.support.design.widget.FloatingActionButton>
android:paddingBottom="10dp"
fab:layout_behavior="net.bierbaumer.otp_authenticator.FloatingActionMenuBehavior"
fab:menu_backgroundColor="#BF000000"
fab:menu_colorNormal="@color/colorAccent"
fab:menu_colorPressed="@color/colorAccent"
fab:menu_fab_label="@string/fam_label_scan">

<com.github.clans.fab.FloatingActionButton
android:id="@+id/action_enter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_hardware_keyboard"
fab:fab_size="mini"
fab:fab_label="@string/fab_label_enter"/>

</com.github.clans.fab.FloatingActionMenu>

</android.support.design.widget.CoordinatorLayout>
40 changes: 40 additions & 0 deletions app/src/main/res/layout/dialog_add_account.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">

<!-- Name -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText android:id="@+id/account_label"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/add_account_label"/>
</android.support.design.widget.TextInputLayout>

<!-- Key -->
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText android:id="@+id/account_key"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textVisiblePassword|textCapCharacters|textMultiLine"
android:hint="@string/add_account_key"/>
</android.support.design.widget.TextInputLayout>

<!-- ToDo: Preparation to support other key types, see https://github.com/0xbb/otp-authenticator/issues/10
<Spinner
android:id="@+id/key_type"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
-->

</LinearLayout>
</ScrollView>
Loading