Skip to content
This repository was archived by the owner on Jun 27, 2020. It is now read-only.

Commit eeabe19

Browse files
author
Evgenii
authored
Merge pull request #113 from evgenii-kanivets/dev
[10h]. Dropbox backups. Merge import/export.
2 parents b09a1ce + 80e47c1 commit eeabe19

29 files changed

+737
-194
lines changed

app/build.gradle

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,18 @@ android {
4343
}
4444
}
4545

46+
apply plugin: 'com.getkeepsafe.dexcount'
47+
4648
dependencies {
4749
compile fileTree(dir: 'libs', include: ['*.jar'])
4850
compile 'com.android.support:support-v4:23.2.1'
4951
compile 'com.android.support:appcompat-v7:23.2.1'
5052
compile 'com.android.support:design:23.2.1'
51-
// View annotation bindings
52-
compile 'com.jakewharton:butterknife:7.0.1'
53-
// Dependency injection tool
54-
compile 'com.google.dagger:dagger:2.0.1'
55-
// Charts
56-
compile 'com.github.PhilJay:MPAndroidChart:v2.2.4'
57-
// Advanced logging tool
58-
compile 'com.jakewharton.timber:timber:4.1.2'
53+
54+
compile 'com.jakewharton:butterknife:7.0.1' // View annotation bindings
55+
compile 'com.google.dagger:dagger:2.0.1' // Dependency injection tool
56+
compile 'com.github.PhilJay:MPAndroidChart:v2.2.4' // Charts
57+
compile 'com.jakewharton.timber:timber:4.1.2' // Advanced logging tool
5958

6059
apt 'com.google.dagger:dagger-compiler:2.0.1'
6160
provided 'org.glassfish:javax.annotation:10.0-b28'
164 KB
Binary file not shown.

app/libs/json_simple-1.1.jar

15.7 KB
Binary file not shown.

app/src/main/AndroidManifest.xml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
package="com.blogspot.e_kanivets.moneytracker">
44

5+
<!-- Used only for Dropbox backup -->
6+
<uses-permission android:name="android.permission.INTERNET" />
7+
58
<application
69
android:name=".MtApp"
710
android:allowBackup="true"
@@ -58,11 +61,6 @@
5861
android:label="@string/title_exchange_rates"
5962
android:screenOrientation="portrait"
6063
android:theme="@style/Theme.Default" />
61-
<activity
62-
android:name=".activity.external.ExportActivity"
63-
android:label="@string/title_export"
64-
android:screenOrientation="portrait"
65-
android:theme="@style/Theme.Default" />
6664
<activity
6765
android:name=".activity.SettingsActivity"
6866
android:label="@string/title_settings"
@@ -74,10 +72,28 @@
7472
android:screenOrientation="portrait"
7573
android:theme="@style/Theme.Default" />
7674
<activity
77-
android:name=".activity.external.ImportActivity"
78-
android:label="@string/title_import"
75+
android:name=".activity.external.ImportExportActivity"
76+
android:label="@string/title_import_export"
77+
android:screenOrientation="portrait"
78+
android:theme="@style/Theme.Default" />
79+
<activity
80+
android:name=".activity.external.BackupActivity"
81+
android:label="@string/backup_data"
7982
android:screenOrientation="portrait"
8083
android:theme="@style/Theme.Default" />
84+
<activity
85+
android:name="com.dropbox.client2.android.AuthActivity"
86+
android:configChanges="orientation|keyboard"
87+
android:launchMode="singleTask"
88+
android:theme="@android:style/Theme.Translucent.NoTitleBar">
89+
<intent-filter>
90+
<data android:scheme="db-5lqugcckdy9y6lj" />
91+
<action android:name="android.intent.action.VIEW" />
92+
93+
<category android:name="android.intent.category.BROWSABLE" />
94+
<category android:name="android.intent.category.DEFAULT" />
95+
</intent-filter>
96+
</activity>
8197

8298
<provider
8399
android:name="android.support.v4.content.FileProvider"

app/src/main/java/com/blogspot/e_kanivets/moneytracker/MtApp.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
* @author Evgenii Kanivets
1717
*/
1818
public class MtApp extends Application {
19-
2019
private static MtApp mtApp;
2120

2221
public static MtApp get() {
@@ -30,7 +29,7 @@ public void onCreate() {
3029
super.onCreate();
3130

3231
mtApp = this;
33-
component = buildComponent();
32+
buildAppComponent();
3433

3534
if (BuildConfig.DEBUG) Timber.plant(new Timber.DebugTree());
3635
else Timber.plant(new ReleaseTree());
@@ -40,6 +39,10 @@ public AppComponent getAppComponent() {
4039
return component;
4140
}
4241

42+
public void buildAppComponent() {
43+
component = buildComponent();
44+
}
45+
4346
private AppComponent buildComponent() {
4447
return DaggerAppComponent.builder()
4548
.cachedRepoModule(new CachedRepoModule(get()))

app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseActivity.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import android.support.annotation.LayoutRes;
66
import android.support.annotation.Nullable;
77
import android.support.annotation.StringRes;
8+
import android.support.v7.app.AlertDialog;
89
import android.support.v7.app.AppCompatActivity;
910
import android.support.v7.widget.Toolbar;
1011
import android.widget.Toast;
@@ -77,6 +78,18 @@ public void stopProgress() {
7778
getProgressBar().dismiss();
7879
}
7980

81+
public void showAlert(@Nullable String title, @Nullable String message) {
82+
AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);
83+
builder.setTitle(title);
84+
builder.setMessage(message);
85+
builder.setPositiveButton(android.R.string.ok, null);
86+
builder.setCancelable(false);
87+
88+
AlertDialog dialog = builder.create();
89+
dialog.setCanceledOnTouchOutside(false);
90+
dialog.show();
91+
}
92+
8093
private ProgressDialog getProgressBar() {
8194
if (progressDialog == null) progressDialog = new ProgressDialog(this);
8295
return progressDialog;

app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseDrawerActivity.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010

1111
import com.blogspot.e_kanivets.moneytracker.R;
1212
import com.blogspot.e_kanivets.moneytracker.activity.ChartsActivity;
13-
import com.blogspot.e_kanivets.moneytracker.activity.external.ExportActivity;
14-
import com.blogspot.e_kanivets.moneytracker.activity.external.ImportActivity;
13+
import com.blogspot.e_kanivets.moneytracker.activity.external.BackupActivity;
14+
import com.blogspot.e_kanivets.moneytracker.activity.external.ImportExportActivity;
1515
import com.blogspot.e_kanivets.moneytracker.activity.SettingsActivity;
1616
import com.blogspot.e_kanivets.moneytracker.activity.account.AccountsActivity;
1717
import com.blogspot.e_kanivets.moneytracker.activity.exchange_rate.ExchangeRatesActivity;
@@ -30,7 +30,8 @@ public abstract class BaseDrawerActivity extends BaseActivity
3030
private static final int REQUEST_ACCOUNTS = 1;
3131
private static final int REQUEST_RATES = 2;
3232
private static final int REQUEST_SETTINGS = 3;
33-
private static final int REQUEST_IMPORT = 4;
33+
private static final int REQUEST_IMPORT_EXPORT = 4;
34+
protected static final int REQUEST_BACKUP = 5;
3435

3536
@Bind(R.id.drawer_layout)
3637
DrawerLayout drawer;
@@ -84,13 +85,14 @@ public boolean onNavigationItemSelected(MenuItem item) {
8485
startActivity(new Intent(BaseDrawerActivity.this, ChartsActivity.class));
8586
break;
8687

87-
case R.id.nav_import:
88-
startActivityForResult(new Intent(BaseDrawerActivity.this, ImportActivity.class),
89-
REQUEST_IMPORT);
88+
case R.id.nav_backup:
89+
startActivityForResult(new Intent(BaseDrawerActivity.this, BackupActivity.class),
90+
REQUEST_BACKUP);
9091
break;
9192

92-
case R.id.nav_export:
93-
startActivity(new Intent(BaseDrawerActivity.this, ExportActivity.class));
93+
case R.id.nav_import_export:
94+
startActivityForResult(new Intent(BaseDrawerActivity.this, ImportExportActivity.class),
95+
REQUEST_IMPORT_EXPORT);
9496
break;
9597

9698
case R.id.nav_settings:
@@ -124,7 +126,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
124126
update();
125127
break;
126128

127-
case REQUEST_IMPORT:
129+
case REQUEST_IMPORT_EXPORT:
128130
update();
129131
break;
130132

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
package com.blogspot.e_kanivets.moneytracker.activity.external;
2+
3+
import android.content.DialogInterface;
4+
import android.support.annotation.NonNull;
5+
import android.support.v7.app.AlertDialog;
6+
import android.view.View;
7+
import android.widget.ArrayAdapter;
8+
import android.widget.ListView;
9+
10+
import com.blogspot.e_kanivets.moneytracker.MtApp;
11+
import com.blogspot.e_kanivets.moneytracker.R;
12+
import com.blogspot.e_kanivets.moneytracker.activity.base.BaseBackActivity;
13+
import com.blogspot.e_kanivets.moneytracker.controller.BackupController;
14+
import com.blogspot.e_kanivets.moneytracker.controller.PreferenceController;
15+
import com.dropbox.client2.DropboxAPI;
16+
import com.dropbox.client2.android.AndroidAuthSession;
17+
import com.dropbox.client2.session.AppKeyPair;
18+
19+
import java.util.List;
20+
21+
import javax.inject.Inject;
22+
23+
import butterknife.Bind;
24+
import butterknife.OnClick;
25+
import butterknife.OnItemClick;
26+
import timber.log.Timber;
27+
28+
public class BackupActivity extends BaseBackActivity {
29+
private static final String APP_KEY = "5lqugcckdy9y6lj";
30+
private static final String APP_SECRET = "psbu50k9713u68j";
31+
32+
@Inject
33+
PreferenceController preferenceController;
34+
@Inject
35+
BackupController backupController;
36+
37+
private DropboxAPI<AndroidAuthSession> dbApi;
38+
39+
@Bind(R.id.btn_backup_now)
40+
View btnBackupNow;
41+
@Bind(R.id.list_view)
42+
ListView listView;
43+
44+
@Override
45+
protected int getContentViewId() {
46+
return R.layout.activity_backup;
47+
}
48+
49+
@Override
50+
protected boolean initData() {
51+
getAppComponent().inject(BackupActivity.this);
52+
53+
AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
54+
String accessToken = preferenceController.readDropboxAccessToken();
55+
56+
AndroidAuthSession session = new AndroidAuthSession(appKeys);
57+
dbApi = new DropboxAPI<>(session);
58+
if (accessToken == null) dbApi.getSession().startOAuth2Authentication(BackupActivity.this);
59+
else {
60+
dbApi.getSession().setOAuth2AccessToken(accessToken);
61+
fetchBackups();
62+
}
63+
64+
return super.initData();
65+
}
66+
67+
@Override
68+
protected void initViews() {
69+
super.initViews();
70+
btnBackupNow.setEnabled(preferenceController.readDropboxAccessToken() != null);
71+
}
72+
73+
@Override
74+
protected void onResume() {
75+
super.onResume();
76+
77+
if (dbApi.getSession().authenticationSuccessful()) {
78+
try {
79+
// Required to complete auth, sets the access token on the session
80+
dbApi.getSession().finishAuthentication();
81+
preferenceController.writeDropboxAccessToken(dbApi.getSession().getOAuth2AccessToken());
82+
btnBackupNow.setEnabled(true);
83+
fetchBackups();
84+
} catch (IllegalStateException e) {
85+
Timber.e("Error authenticating: %s", e.getMessage());
86+
}
87+
}
88+
}
89+
90+
@OnClick(R.id.btn_backup_now)
91+
public void backupNow() {
92+
startProgress();
93+
backupController.makeBackup(dbApi, new BackupController.OnBackupListener() {
94+
@Override
95+
public void onBackupSuccess() {
96+
Timber.d("Backup success.");
97+
stopProgress();
98+
fetchBackups();
99+
}
100+
101+
@Override
102+
public void onBackupFailure(String reason) {
103+
Timber.d("Backup failure.");
104+
stopProgress();
105+
showToast(R.string.failed_create_backup);
106+
107+
if (BackupController.OnBackupListener.ERROR_AUTHENTICATION.equals(reason)) logout();
108+
}
109+
});
110+
}
111+
112+
@OnItemClick(R.id.list_view)
113+
public void restoreBackupClicked(int position) {
114+
final String backupName = listView.getAdapter().getItem(position).toString();
115+
116+
AlertDialog.Builder builder = new AlertDialog.Builder(BackupActivity.this);
117+
builder.setTitle(getString(R.string.warning));
118+
builder.setMessage(getString(R.string.want_erase_and_restore, backupName));
119+
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
120+
@Override
121+
public void onClick(DialogInterface dialog, int which) {
122+
restoreBackup(backupName);
123+
}
124+
});
125+
builder.setNegativeButton(android.R.string.cancel, null);
126+
builder.show();
127+
}
128+
129+
private void restoreBackup(final String backupName) {
130+
startProgress();
131+
backupController.restoreBackup(dbApi, backupName, new BackupController.OnRestoreBackupListener() {
132+
@Override
133+
public void onRestoreSuccess() {
134+
Timber.d("Restore success.");
135+
stopProgress();
136+
137+
AlertDialog.Builder builder = new AlertDialog.Builder(BackupActivity.this);
138+
builder.setTitle(getString(R.string.backup_is_restored));
139+
builder.setMessage(getString(R.string.backup_restored, backupName));
140+
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
141+
@Override
142+
public void onDismiss(DialogInterface dialog) {
143+
MtApp.get().buildAppComponent();
144+
setResult(RESULT_OK);
145+
finish();
146+
}
147+
});
148+
builder.setPositiveButton(android.R.string.ok, null);
149+
builder.show();
150+
}
151+
152+
@Override
153+
public void onRestoreFailure(String reason) {
154+
Timber.d("Restore failure.");
155+
stopProgress();
156+
showToast(R.string.failed_restore_backup);
157+
158+
if (BackupController.OnRestoreBackupListener.ERROR_AUTHENTICATION.equals(reason))
159+
logout();
160+
}
161+
});
162+
}
163+
164+
private void fetchBackups() {
165+
startProgress();
166+
backupController.fetchBackups(dbApi, new BackupController.OnFetchBackupListListener() {
167+
@Override
168+
public void onBackupsFetched(@NonNull List<String> backupList) {
169+
stopProgress();
170+
ArrayAdapter<String> adapter = new ArrayAdapter<>(BackupActivity.this,
171+
android.R.layout.simple_list_item_1, backupList);
172+
listView.setAdapter(adapter);
173+
}
174+
});
175+
}
176+
177+
private void logout() {
178+
preferenceController.writeDropboxAccessToken(null);
179+
dbApi.getSession().startOAuth2Authentication(BackupActivity.this);
180+
btnBackupNow.setEnabled(false);
181+
}
182+
}

0 commit comments

Comments
 (0)