Skip to content

Commit

Permalink
Merge pull request #21 from alexmercerind/feat/backup
Browse files Browse the repository at this point in the history
feat: `SettingsActivity` history import/export
  • Loading branch information
alexmercerind authored Jan 1, 2024
2 parents cf0a684 + df3597e commit f5b8e02
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 47 deletions.
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

<application
android:name=".Audire"
Expand Down
21 changes: 11 additions & 10 deletions app/src/main/java/com/alexmercerind/audire/models/HistoryItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@ package com.alexmercerind.audire.models
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import com.google.gson.annotations.SerializedName
import java.io.Serializable

@Entity(tableName = "history_item")
data class HistoryItem(
@PrimaryKey(autoGenerate = true) val id: Int?,
@ColumnInfo(name = "timestamp") val timestamp: Long,
@ColumnInfo(name = "title") val title: String,
@ColumnInfo(name = "artists") val artists: String,
@ColumnInfo(name = "cover") val cover: String,
@ColumnInfo(name = "album") val album: String?,
@ColumnInfo(name = "label") val label: String?,
@ColumnInfo(name = "year") val year: String?,
@ColumnInfo(name = "lyrics") val lyrics: String?,
@ColumnInfo(name = "liked", defaultValue = "0") val liked: Boolean
@SerializedName("id") @PrimaryKey(autoGenerate = true) val id: Int?,
@SerializedName("timestamp") @ColumnInfo(name = "timestamp") val timestamp: Long,
@SerializedName("title") @ColumnInfo(name = "title") val title: String,
@SerializedName("artists") @ColumnInfo(name = "artists") val artists: String,
@SerializedName("cover") @ColumnInfo(name = "cover") val cover: String,
@SerializedName("album") @ColumnInfo(name = "album") val album: String?,
@SerializedName("label") @ColumnInfo(name = "label") val label: String?,
@SerializedName("year") @ColumnInfo(name = "year") val year: String?,
@SerializedName("lyrics") @ColumnInfo(name = "lyrics") val lyrics: String?,
@SerializedName("liked") @ColumnInfo(name = "liked", defaultValue = "0") val liked: Boolean
) : Serializable
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package com.alexmercerind.audire.repository

import android.app.Application
import android.net.Uri
import com.alexmercerind.audire.models.HistoryItem
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

class ImportExportRepository(private val application: Application) {
private val gson = Gson()

suspend fun import(uri: Uri) {
val input = application.contentResolver.openInputStream(uri)
input?.use {
val json = it.readBytes().toString(Charsets.UTF_16)
val historyItems: List<HistoryItem> = gson.fromJson(
json, object : TypeToken<List<HistoryItem>>() {}.type
)
for (historyItem in historyItems) {
HistoryRepository(application).insert(historyItem)
}
}
}

suspend fun export(uri: Uri, historyItems: List<HistoryItem>) {
val output = application.contentResolver.openOutputStream(uri)
output?.use {
val json = gson.toJson(historyItems)
it.write(json.toByteArray(Charsets.UTF_16))
}
}
}
38 changes: 38 additions & 0 deletions app/src/main/java/com/alexmercerind/audire/ui/SettingsActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.os.Bundle
import android.util.Log
import android.view.Gravity
import android.widget.PopupMenu
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
Expand All @@ -14,6 +15,7 @@ import com.alexmercerind.audire.R
import com.alexmercerind.audire.databinding.ActivitySettingsBinding
import com.alexmercerind.audire.utils.Constants
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
Expand All @@ -27,6 +29,35 @@ class SettingsActivity : AppCompatActivity() {
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)

val exportLauncher =
registerForActivityResult(ActivityResultContracts.CreateDocument(getString(R.string.settings_backup_file_mime))) { uri ->
if (uri != null) {
lifecycleScope.launch(Dispatchers.IO) {
try {
settingsViewModel.export(uri)
Snackbar.make(binding.root, R.string.settings_backup_export_success, Snackbar.LENGTH_LONG).show()
} catch (e: Throwable) {
e.printStackTrace()
Snackbar.make(binding.root, R.string.settings_backup_export_fail, Snackbar.LENGTH_LONG).show()
}
}
}
}
val importLauncher =
registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
if (uri != null) {
lifecycleScope.launch(Dispatchers.IO) {
try {
settingsViewModel.import(uri)
Snackbar.make(binding.root, R.string.settings_backup_import_success, Snackbar.LENGTH_LONG).show()
} catch (e: Throwable) {
e.printStackTrace()
Snackbar.make(binding.root, R.string.settings_backup_import_fail, Snackbar.LENGTH_LONG).show()
}
}
}
}

lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
settingsViewModel.theme.filterNotNull().distinctUntilChanged().collect {
Expand Down Expand Up @@ -97,5 +128,12 @@ class SettingsActivity : AppCompatActivity() {
}
}
}

binding.settingsBackupExportLinearLayout.setOnClickListener {
exportLauncher.launch(getString(R.string.settings_backup_file_name))
}
binding.settingsBackupImportLinearLayout.setOnClickListener {
importLauncher.launch(arrayOf(getString(R.string.settings_backup_file_mime)))
}
}
}
23 changes: 18 additions & 5 deletions app/src/main/java/com/alexmercerind/audire/ui/SettingsViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
package com.alexmercerind.audire.ui

import android.app.Application
import android.net.Uri
import androidx.lifecycle.AndroidViewModel
import com.alexmercerind.audire.repository.HistoryRepository
import com.alexmercerind.audire.repository.ImportExportRepository
import com.alexmercerind.audire.repository.SettingsRepository
import kotlinx.coroutines.flow.first

class SettingsViewModel(application: Application) : AndroidViewModel(application) {
private val repository = SettingsRepository(application)
private val historyRepository = HistoryRepository(application)
private val settingsRepository = SettingsRepository(application)
private val importExportRepository = ImportExportRepository(application)

val theme = repository.theme
val theme = settingsRepository.theme

val systemColorScheme = repository.systemColorScheme
val systemColorScheme = settingsRepository.systemColorScheme

fun setTheme(value: String) = repository.setTheme(value)
fun setTheme(value: String) = settingsRepository.setTheme(value)

fun setSystemColorScheme(value: Boolean) = repository.setSystemColorScheme(value)
fun setSystemColorScheme(value: Boolean) = settingsRepository.setSystemColorScheme(value)

suspend fun import(uri: Uri) = importExportRepository.import(uri)

suspend fun export(uri: Uri) = importExportRepository.export(
uri,
historyRepository.getAll().first()
)
}
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/baseline_file_download_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>
5 changes: 5 additions & 0 deletions app/src/main/res/drawable/baseline_file_upload_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,16h6v-6h4l-7,-7 -7,7h4zM5,18h14v2L5,20z"/>
</vector>
108 changes: 107 additions & 1 deletion app/src/main/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
android:padding="16dp"
android:text="@string/settings_appearance"
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
android:textColor="?attr/colorOnSurfaceVariant" />
android:textColor="?attr/colorPrimary" />

<LinearLayout
android:id="@+id/settingsAppearanceThemeLinearLayout"
Expand Down Expand Up @@ -138,6 +138,112 @@
android:layout_height="wrap_content" />
</LinearLayout>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/settings_backup"
android:textAppearance="@style/TextAppearance.Material3.LabelLarge"
android:textColor="?attr/colorPrimary" />

<LinearLayout
android:id="@+id/settingsBackupExportLinearLayout"
android:layout_width="match_parent"
android:layout_height="72dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical|start"
android:orientation="horizontal">

<Space
android:layout_width="24dp"
android:layout_height="wrap_content" />

<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/baseline_file_upload_24"
app:tint="?attr/colorOnSurfaceVariant" />

<Space
android:layout_width="24dp"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_backup_export"
android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
android:textColor="?attr/colorOnSurface" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_backup_export_supporting_text"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>

<Space
android:layout_width="16dp"
android:layout_height="wrap_content" />
</LinearLayout>

<LinearLayout
android:id="@+id/settingsBackupImportLinearLayout"
android:layout_width="match_parent"
android:layout_height="72dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
android:gravity="center_vertical|start"
android:orientation="horizontal">

<Space
android:layout_width="24dp"
android:layout_height="wrap_content" />

<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/baseline_file_download_24"
app:tint="?attr/colorOnSurfaceVariant" />

<Space
android:layout_width="24dp"
android:layout_height="wrap_content" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_backup_import"
android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
android:textColor="?attr/colorOnSurface" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/settings_backup_import_supporting_text"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="?attr/colorOnSurfaceVariant" />
</LinearLayout>

<Space
android:layout_width="16dp"
android:layout_height="wrap_content" />
</LinearLayout>

</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
24 changes: 0 additions & 24 deletions app/src/main/res/menu-v26/history_material_toolbar_menu.xml

This file was deleted.

10 changes: 8 additions & 2 deletions app/src/main/res/menu/history_material_toolbar_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,23 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<!-- https://stackoverflow.com/questions/26780046/menuitem-tinting-on-appcompat-toolbar#comment101591006_54961263 -->
<item
android:id="@+id/search"
android:icon="@drawable/baseline_search_24"
android:title="@string/search" />
android:title="@string/search"
app:iconTint="?attr/colorOnSurfaceVariant"
app:showAsAction="ifRoom" />
<item
android:id="@+id/settings"
android:icon="@drawable/baseline_settings_24"
android:title="@string/settings"
app:iconTint="?attr/colorOnSurfaceVariant"
app:showAsAction="never" />
<item
android:id="@+id/about"
android:icon="@drawable/baseline_info_24"
android:title="@string/about" />
android:title="@string/about"
app:iconTint="?attr/colorOnSurfaceVariant"
app:showAsAction="never" />
</menu>
12 changes: 7 additions & 5 deletions app/src/main/res/menu/identify_material_toolbar_menu.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">

<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/settings"
android:icon="@drawable/baseline_settings_24"
android:title="@string/settings"
app:iconTint="?attr/colorOnSurfaceVariant"
app:showAsAction="never" />
<item
android:id="@+id/about"
android:icon="@drawable/baseline_info_24"
android:title="@string/about" />
</menu>
android:title="@string/about"
app:iconTint="?attr/colorOnSurfaceVariant"
app:showAsAction="never" />
</menu>
11 changes: 11 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@
<string name="settings_appearance_theme_light">Light</string>
<string name="settings_appearance_theme_system">System</string>
<string name="settings_application_restart_required">Application restart is required</string>
<string name="settings_backup">Backup</string>
<string name="settings_backup_export">Export history</string>
<string name="settings_backup_export_fail">Export failed</string>
<string name="settings_backup_export_success">Export successful</string>
<string name="settings_backup_export_supporting_text">Backup history to JSON file</string>
<string name="settings_backup_file_mime">application/json</string>
<string name="settings_backup_file_name">History</string>
<string name="settings_backup_import">Import history</string>
<string name="settings_backup_import_fail">Import failed</string>
<string name="settings_backup_import_success">Import successful</string>
<string name="settings_backup_import_supporting_text">Restore history from JSON file</string>
<string name="spotify">Spotify</string>
<string name="year">Year</string>
<string name="yes">Yes</string>
Expand Down

0 comments on commit f5b8e02

Please sign in to comment.