Skip to content

Commit

Permalink
Add Backup option to the bottom sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
tughi committed Mar 19, 2023
1 parent bad21df commit 512ab22
Show file tree
Hide file tree
Showing 11 changed files with 291 additions and 11 deletions.
13 changes: 7 additions & 6 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,25 @@ android {
}
}


dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'androidx.appcompat:appcompat:1.6.0'
implementation 'androidx.browser:browser:1.4.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.core:core-ktx:1.9.0'
implementation 'androidx.fragment:fragment-ktx:1.5.3'
implementation 'androidx.fragment:fragment-ktx:1.5.5'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
implementation 'androidx.preference:preference-ktx:1.2.0'
implementation 'androidx.sqlite:sqlite-framework:2.2.0'
implementation 'androidx.sqlite:sqlite-ktx:2.2.0'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
implementation 'androidx.webkit:webkit:1.5.0'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.webkit:webkit:1.6.0'
implementation 'com.google.android.material:material:1.8.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'commons-codec:commons-codec:1.13'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.7.20'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'

implementation project(':sax-framework')
}
8 changes: 8 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@

<activity android:name=".activities.optionpicker.OptionPickerActivity" />

<activity
android:name=".activities.backup.BackupActivity"
android:label="@string/backup__title" />

<service
android:name=".services.BackupService"
android:exported="false" />

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.tughi.aggregator.activities.backup

import android.content.ComponentName
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.IBinder
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ProgressBar
import androidx.lifecycle.MutableLiveData
import com.tughi.aggregator.AppActivity
import com.tughi.aggregator.R
import com.tughi.aggregator.services.BackupService
import kotlin.math.roundToInt

class BackupActivity : AppActivity() {
private var service: BackupService? = null
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, binder: IBinder?) {
service = (binder as BackupService.LocalBinder).getService().also { service ->
service.status.observe(this@BackupActivity) { status ->
serviceStatus.value = status
}
}
}

override fun onServiceDisconnected(name: ComponentName?) {
service = null
}
}

private val serviceStatus = MutableLiveData<BackupService.Status>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.action_back)
}

setContentView(R.layout.backup_activity)

val actionsWrapper = findViewById<ViewGroup>(R.id.actions_wrapper)
val backupButton = actionsWrapper.findViewById<Button>(R.id.backup)
backupButton.setOnClickListener {
startService(Intent(this, BackupService::class.java))
}

val progressWrapper = findViewById<ViewGroup>(R.id.progress_wrapper)
val progressBar = progressWrapper.findViewById<ProgressBar>(R.id.progress)
val cancelButton = progressWrapper.findViewById<Button>(R.id.cancel)
cancelButton.setOnClickListener {
service?.cancel()
}

serviceStatus.observe(this) { status ->
if (status.busy) {
actionsWrapper.visibility = View.GONE
progressWrapper.visibility = View.VISIBLE
progressBar.isIndeterminate = false
progressBar.progress = (status.progress * 100).roundToInt()
} else {
actionsWrapper.visibility = View.VISIBLE
progressWrapper.visibility = View.GONE
progressBar.isIndeterminate = true
}
}
}

override fun onResume() {
super.onResume()

Intent(this, BackupService::class.java).also { intent ->
bindService(intent, serviceConnection, BIND_AUTO_CREATE)
}
}

override fun onPause() {
unbindService(serviceConnection)

super.onPause()
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
finish()
}
else -> {
return super.onOptionsItemSelected(item)
}
}
return true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.tughi.aggregator.App
import com.tughi.aggregator.AppActivity
import com.tughi.aggregator.BuildConfig
import com.tughi.aggregator.R
import com.tughi.aggregator.activities.backup.BackupActivity
import com.tughi.aggregator.activities.theme.ThemeActivity
import com.tughi.aggregator.contentScope
import com.tughi.aggregator.preferences.UpdateSettings
Expand Down Expand Up @@ -100,6 +101,10 @@ class MainActivity : AppActivity() {
startActivity(Intent(this, ThemeActivity::class.java))
}

bottomSheetView.findViewById<View>(R.id.backup).setOnClickListener {
startActivity(Intent(this, BackupActivity::class.java))
}

bottomSheetView.findViewById<View>(R.id.support).setOnClickListener {
bottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
openURL("http://tughi.github.io/aggregator-android/support")
Expand Down
64 changes: 64 additions & 0 deletions app/src/main/java/com/tughi/aggregator/services/BackupService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.tughi.aggregator.services

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.util.Log
import androidx.lifecycle.MutableLiveData
import com.tughi.aggregator.contentScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class BackupService : Service() {
private val binder = LocalBinder()

private var currentJob: Job? = null

val status = MutableLiveData(Status(false))

override fun onBind(intent: Intent?): IBinder {
return binder
}

override fun onCreate() {
super.onCreate()

Log.i(BackupService::class.java.simpleName, "onCreate")
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val job = contentScope.launch {
backup()
}

job.invokeOnCompletion {
currentJob = null
status.postValue(Status(false))
}

currentJob = job

return START_NOT_STICKY
}

private suspend fun backup() {
val duration = 13000
val steps = 100L
for (step in 1..steps) {
status.postValue(Status(true, step / steps.toFloat()))
delay(duration / steps)
}
}

fun cancel() {
currentJob?.cancel()
}

inner class LocalBinder : Binder() {
fun getService() = this@BackupService
}

data class Status(val busy: Boolean, val progress: Float = 0f)
}
10 changes: 10 additions & 0 deletions app/src/main/res/drawable/action_backup.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M9,3L5,6.99h3L8,14h2L10,6.99h3L9,3zM16,17.01L16,10h-2v7.01h-3L15,21l4,-3.99h-3z" />
</vector>
67 changes: 67 additions & 0 deletions app/src/main/res/layout/backup_activity.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TODO: Explain why is this feature su great!"
android:textAppearance="?textAppearanceBody1" />

<LinearLayout
android:id="@+id/actions_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<Button
android:id="@+id/backup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Backup" />

<Button
android:id="@+id/restore"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Restore" />

</LinearLayout>

<LinearLayout
android:id="@+id/progress_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="In progress ..."
android:textAppearance="?textAppearanceCaption" />

<ProgressBar
android:id="@+id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:indeterminate="true" />

<Button
android:id="@+id/cancel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Cancel" />

</LinearLayout>

</LinearLayout>
24 changes: 22 additions & 2 deletions app/src/main/res/layout/main_activity.xml
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintEnd_toStartOf="@id/backup"
app:layout_constraintTop_toTopOf="parent">

<TextView
Expand All @@ -76,13 +76,33 @@
</com.tughi.aggregator.widgets.BottomSheetOption>

<com.tughi.aggregator.widgets.BottomSheetOption
android:id="@+id/support"
android:id="@+id/backup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
app:layout_constraintEnd_toStartOf="@id/guideline"
app:layout_constraintStart_toStartOf="@id/guideline"
app:layout_constraintTop_toTopOf="parent">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical|center_horizontal"
android:text="@string/backup__title"
android:textAlignment="center"
android:textAppearance="?textAppearanceCaption"
app:drawableTopCompat="@drawable/action_backup" />

</com.tughi.aggregator.widgets.BottomSheetOption>

<com.tughi.aggregator.widgets.BottomSheetOption
android:id="@+id/support"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="?selectableItemBackgroundBorderless"
app:layout_constraintStart_toEndOf="@id/backup"
app:layout_constraintTop_toTopOf="parent">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
<string name="action__update">Update</string>
<string name="action__yes">Yes</string>

<string name="backup__title">Backup</string>

<string name="cleanup_mode">Cleanup mode</string>
<string name="cleanup_mode__age__3_days">3 days</string>
<string name="cleanup_mode__age__3_days__description">Deletes entries older than 3 days.</string>
Expand Down
4 changes: 1 addition & 3 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.7.20'

repositories {
google()
mavenCentral()
}

dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
6 changes: 6 additions & 0 deletions metadata/en-US/changelogs/299033.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
- Changed OPML support
* allows selection of already aggregated feeds for import
* implemented export feature

* TODO: Added feature to dump data for loading it on a different device
* TODO: Remove automatic backup (replaced by dump feature)
* TODO: The app clears state of affected feeds when the default clean-up mode is changed

* TODO: Fix app-launch updates by using an OnBackPressedCallback to detect when the user leaves the MainActivity

0 comments on commit 512ab22

Please sign in to comment.