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

Commit a2183bf

Browse files
committed
Started working on cloud backup
1 parent a39d2bb commit a2183bf

File tree

15 files changed

+470
-58
lines changed

15 files changed

+470
-58
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
.cxx
1515
local.properties
1616
google-services.json
17-
/release
17+
release

app/build.gradle

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ android {
1515
applicationId "com.jjewuz.justnotes"
1616
minSdk 26
1717
targetSdk 34
18-
versionCode 142
19-
versionName "3.9.1"
18+
versionCode 143
19+
versionName "3.9.2"
2020

2121
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
2222

@@ -63,13 +63,17 @@ dependencies {
6363
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
6464
implementation 'androidx.drawerlayout:drawerlayout:1.2.0'
6565
implementation 'com.google.firebase:firebase-analytics-ktx:21.5.0'
66+
implementation 'com.google.firebase:firebase-firestore:24.9.1'
67+
implementation 'com.google.firebase:firebase-storage:20.3.0'
68+
implementation 'com.google.firebase:firebase-auth:22.2.0'
6669
testImplementation 'junit:junit:'
6770
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
6871
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
6972
implementation 'androidx.work:work-runtime-ktx:2.8.1'
7073
implementation 'com.google.android.play:core:1.10.3'
7174
implementation 'com.google.android.play:core-ktx:1.8.1'
7275
implementation 'com.google.android.gms:play-services-oss-licenses:17.0.1'
76+
implementation 'com.google.firebase:firebase-messaging:23.3.1'
7377

7478
implementation "androidx.biometric:biometric-ktx:1.2.0-alpha05"
7579

app/free/release/app-free-release.apk

-2.96 MB
Binary file not shown.

app/free/release/output-metadata.json

Lines changed: 0 additions & 20 deletions
This file was deleted.

app/release/output-metadata.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
"type": "SINGLE",
1212
"filters": [],
1313
"attributes": [],
14-
"versionCode": 141,
15-
"versionName": "3.9.0",
14+
"versionCode": 142,
15+
"versionName": "3.9.1",
1616
"outputFile": "app-release.apk"
1717
}
1818
],

app/src/main/AndroidManifest.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
tools:ignore="ScopedStorage" />
1010
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
1111
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
12+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
1213
<uses-permission android:name="com.google.android.gms.permission.AD_ID" />
1314

1415
<queries>
@@ -64,6 +65,13 @@
6465
android:name="autoStoreLocales"
6566
android:value="true" />
6667
</service>
68+
<service
69+
android:name=".MyFirebaseMessagingService"
70+
android:exported="false">
71+
<intent-filter>
72+
<action android:name="com.google.firebase.MESSAGING_EVENT" />
73+
</intent-filter>
74+
</service>
6775
</application>
6876

6977
</manifest>

app/src/main/java/com/jjewuz/justnotes/BackupFragment.kt

Lines changed: 213 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,33 @@ package com.jjewuz.justnotes
22

33
import android.app.Activity
44
import android.content.ContentValues
5+
import android.content.Context
56
import android.content.Intent
67
import android.os.Bundle
78
import android.util.Log
8-
import androidx.fragment.app.Fragment
99
import android.view.View
10+
import android.widget.Toast
11+
import androidx.core.net.toUri
12+
import androidx.fragment.app.Fragment
13+
import androidx.transition.Fade
14+
import androidx.transition.TransitionManager
15+
import com.google.firebase.Firebase
16+
import com.google.firebase.auth.FirebaseAuth
17+
import com.google.firebase.auth.FirebaseUser
18+
import com.google.firebase.auth.auth
19+
import com.google.firebase.storage.storage
1020
import com.jjewuz.justnotes.databinding.FragmentBackupBinding
1121
import de.raphaelebner.roomdatabasebackup.core.RoomBackup
22+
import java.io.File
23+
1224

1325
class BackupFragment : Fragment(R.layout.fragment_backup) {
1426

15-
private var fragmentBackupBinding: FragmentBackupBinding? = null
27+
private var fragmentBackupBinding: FragmentBackupBinding? = null
28+
29+
private lateinit var auth: FirebaseAuth
30+
31+
private var isLocal = false
1632

1733

1834
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
@@ -21,14 +37,89 @@ class BackupFragment : Fragment(R.layout.fragment_backup) {
2137
val binding = view.let { FragmentBackupBinding.bind(it) }
2238
fragmentBackupBinding = binding
2339

40+
val sharedPref = requireActivity().getSharedPreferences("prefs", Context.MODE_PRIVATE)
41+
isLocal = sharedPref.getBoolean("isLocal", true)
42+
43+
auth = Firebase.auth
44+
45+
binding.deleteBtn?.visibility = View.GONE
46+
47+
val currentUser = auth.currentUser
48+
if (currentUser != null) {
49+
binding.authLayout?.visibility = View.GONE
50+
binding.deleteBtn?.visibility = View.VISIBLE
51+
updateUI(currentUser, binding)
52+
}
53+
54+
if (isLocal) {
55+
binding.toggleButton?.check(R.id.button1)
56+
binding.cloudLayout?.visibility = View.GONE
57+
binding.localLayout?.visibility = View.VISIBLE
58+
} else {
59+
binding.toggleButton?.check(R.id.button2)
60+
binding.cloudLayout?.visibility = View.VISIBLE
61+
binding.localLayout?.visibility = View.GONE
62+
}
63+
64+
binding.toggleButton?.addOnButtonCheckedListener { _, checkedId, isChecked ->
65+
when (checkedId) {
66+
R.id.button1 -> {
67+
if (isChecked) {
68+
with(sharedPref.edit()) {
69+
putBoolean("isLocal", true)
70+
apply()
71+
}
72+
binding.cloudLayout?.visibility = View.GONE
73+
binding.localLayout?.visibility = View.VISIBLE
74+
isLocal = true
75+
}
76+
77+
}
78+
79+
R.id.button2 -> {
80+
if (isChecked) {
81+
with(sharedPref.edit()) {
82+
putBoolean("isLocal", false)
83+
apply()
84+
}
85+
binding.cloudLayout?.visibility = View.VISIBLE
86+
binding.localLayout?.visibility = View.GONE
87+
isLocal = false
88+
}
89+
}
90+
}
91+
}
92+
93+
binding.regBtn?.setOnClickListener {
94+
register(binding.emailEditText?.text.toString(), binding.passwordEditText?.text.toString(), binding)
95+
}
96+
97+
binding.logBtn?.setOnClickListener {
98+
login(binding.emailEditText?.text.toString(), binding.passwordEditText?.text.toString(), binding)
99+
}
100+
101+
binding.resetBtn?.setOnClickListener {
102+
resetPassword(binding.emailEditText?.text.toString())
103+
}
24104

25105
binding.backup.setOnClickListener {
26-
val mainActivity = (activity as MainActivity)
27-
val backup = mainActivity.backup
106+
backup(isLocal)
107+
}
108+
109+
binding.rest.setOnClickListener {
110+
restore(isLocal)
111+
}
112+
113+
}
114+
115+
private fun backup(local: Boolean){
116+
val mainActivity = (activity as MainActivity)
117+
val backup = mainActivity.backup
118+
val storageRef = Firebase.storage.reference
28119

120+
if (local) {
29121
backup
30122
.database(NoteDatabase.getDatabase(requireContext()))
31-
.enableLogDebug(true)
32123
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG)
33124
.apply {
34125
onCompleteListener { success, message, exitCode ->
@@ -37,15 +128,43 @@ class BackupFragment : Fragment(R.layout.fragment_backup) {
37128
}
38129
}
39130
.backup()
131+
} else {
132+
val userId = Firebase.auth.currentUser?.uid
133+
backup
134+
.database(NoteDatabase.getDatabase(requireContext()))
135+
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL)
136+
.customBackupFileName("database_test")
137+
.backupIsEncrypted(true)
138+
.customEncryptPassword(userId.toString())
139+
.apply {
140+
onCompleteListener { success, message, exitCode ->
141+
Log.d(
142+
ContentValues.TAG,
143+
"success: $success, message: $message, exitCode: $exitCode"
144+
)
145+
if (success) {
146+
}
147+
}
148+
}
149+
.backup()
150+
151+
storageRef.child("user/$userId/test.aes").putFile(
152+
File(
153+
requireContext().filesDir,
154+
"databasebackup/database_test.aes"
155+
).toUri()
156+
)
40157
}
158+
}
41159

42-
binding.rest.setOnClickListener {
43-
val mainActivity = (activity as MainActivity)
44-
val backup = mainActivity.backup
160+
private fun restore(local: Boolean){
161+
val mainActivity = (activity as MainActivity)
162+
val backup = mainActivity.backup
163+
val storageRef = Firebase.storage.reference
45164

165+
if (local) {
46166
backup
47167
.database(NoteDatabase.getDatabase(requireContext()))
48-
.enableLogDebug(true)
49168
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_CUSTOM_DIALOG)
50169
.apply {
51170
onCompleteListener { success, message, exitCode ->
@@ -56,10 +175,94 @@ class BackupFragment : Fragment(R.layout.fragment_backup) {
56175
}
57176
}
58177
.restore()
178+
} else {
179+
val userId = Firebase.auth.currentUser?.uid
180+
val storagePath = File(requireContext().filesDir, "databasebackup")
181+
if (!storagePath.exists()) {
182+
storagePath.mkdirs()
183+
}
184+
185+
val myFile = File(storagePath, "database_test.aes")
186+
187+
val dbRef = storageRef.child("user/$userId/test.aes")
188+
dbRef.getFile(myFile)
189+
190+
backup
191+
.database(NoteDatabase.getDatabase(requireContext()))
192+
.backupLocation(RoomBackup.BACKUP_FILE_LOCATION_INTERNAL)
193+
.backupIsEncrypted(true)
194+
.customEncryptPassword(userId.toString())
195+
.apply {
196+
onCompleteListener { success, message, exitCode ->
197+
Log.d(ContentValues.TAG, "success: $success, message: $message, exitCode: $exitCode")
198+
if (success) {
199+
killAndRestartApp(requireActivity())
200+
}
201+
}
202+
}
203+
.restore()
204+
}
205+
}
206+
207+
private fun register(email: String, password: String, binding: FragmentBackupBinding){
208+
auth.createUserWithEmailAndPassword(email, password)
209+
.addOnCompleteListener(requireActivity()) { task ->
210+
if (task.isSuccessful) {
211+
val user = auth.currentUser
212+
updateUI(user, binding)
213+
} else {
214+
Toast.makeText(
215+
requireContext(),
216+
"Authentication failed.",
217+
Toast.LENGTH_SHORT,
218+
).show()
219+
updateUI(null, binding)
220+
}
221+
}
222+
}
223+
224+
private fun login(email: String, password: String, binding: FragmentBackupBinding){
225+
auth.signInWithEmailAndPassword(email, password)
226+
.addOnCompleteListener(requireActivity()) { task ->
227+
if (task.isSuccessful) {
228+
val user = auth.currentUser
229+
updateUI(user, binding)
230+
} else {
231+
Toast.makeText(
232+
requireContext(),
233+
"Authentication failed.",
234+
Toast.LENGTH_SHORT,
235+
).show()
236+
updateUI(null, binding)
237+
}
238+
}
239+
240+
}
241+
242+
private fun resetPassword(email: String){
243+
auth.sendPasswordResetEmail(email)
244+
.addOnCompleteListener(requireActivity()) { task ->
245+
if (task.isSuccessful) {
246+
Toast.makeText(requireContext(), "Email sent.", Toast.LENGTH_SHORT).show()
247+
}
248+
}
249+
}
250+
251+
private fun updateUI(user: FirebaseUser?, binding: FragmentBackupBinding){
252+
user?.let {
253+
val name = it.displayName
254+
val email = it.email
255+
val photoUrl = it.photoUrl
256+
257+
binding.userEmailTxt?.text = email
258+
binding.authLayout?.visibility = View.GONE
259+
260+
val emailVerified = it.isEmailVerified
261+
val uid = it.uid
59262
}
60263
}
61264

62-
fun killAndRestartApp(activity: Activity) {
265+
private fun killAndRestartApp(activity: Activity) {
63266

64267
val intent = Intent(requireActivity(), MainActivity::class.java)
65268
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK

0 commit comments

Comments
 (0)