Skip to content

Commit 78a5fa1

Browse files
committed
File dialog for spectrum destination to save
1 parent ba9f516 commit 78a5fa1

File tree

9 files changed

+228
-15
lines changed

9 files changed

+228
-15
lines changed

app/build.gradle.kts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ android {
1212
applicationId = "io.github.vikulin.opengammakit"
1313
minSdk = 24
1414
targetSdk = 35
15-
versionCode = 19
16-
versionName = "1.1.8.1"
15+
versionCode = 20
16+
versionName = "1.1.9"
1717
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
1818
setProperty("archivesBaseName", "ogk-inspector-$versionName")
1919
}

app/src/main/kotlin/io/github/vikulin/opengammakit/SpectrumFragment.kt

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ import io.github.vikulin.opengammakit.model.ModifierInfo
6767
import io.github.vikulin.opengammakit.model.GammaKitEntry
6868
import io.github.vikulin.opengammakit.view.FwhmSpectrumSelectionDialogFragment
6969
import io.github.vikulin.opengammakit.view.SaveSelectedSpectrumDialogFragment
70+
import io.github.vikulin.opengammakit.view.SaveSpectrumDataIntoFileDialogFragment
7071
import io.github.vikulin.opengammakit.view.SpectrumFileChooserDialogFragment
7172
import kotlin.math.log10
7273

@@ -76,7 +77,8 @@ class SpectrumFragment : SerialConnectionFragment(),
7677
SpectrumRecordingTimeDialogFragment.ChooseSpectrumRecordingTimeDialogListener,
7778
FwhmSpectrumSelectionDialogFragment.ChooseSpectrumDialogListener,
7879
SpectrumFileChooserDialogFragment.ChooseFileDialogListener,
79-
SaveSelectedSpectrumDialogFragment.ChooseSpectrumDialogListener{
80+
SaveSelectedSpectrumDialogFragment.ChooseSpectrumDialogListener,
81+
SaveSpectrumDataIntoFileDialogFragment.SaveSpectrumDataIntoFileListener {
8082

8183
private lateinit var spectrumChart: LineChart
8284
private lateinit var measureTimer: Chronometer
@@ -321,7 +323,8 @@ class SpectrumFragment : SerialConnectionFragment(),
321323
val spectrumFileChooserDialog = SaveSelectedSpectrumDialogFragment.newInstance(spectrumDataSet)
322324
spectrumFileChooserDialog.show(childFragmentManager, "save_spectrum_file_dialog_fragment")
323325
} else {
324-
saveGammaKitDataAsJson(requireContext(), spectrumDataSet)
326+
val saveSpectrumIntoFileDialog = SaveSpectrumDataIntoFileDialogFragment.newInstance(spectrumDataSet)
327+
saveSpectrumIntoFileDialog.show(childFragmentManager, "save_spectrum_into_file_dialog_fragment")
325328
}
326329
}
327330

@@ -1175,13 +1178,12 @@ class SpectrumFragment : SerialConnectionFragment(),
11751178
}
11761179
}
11771180

1178-
fun saveGammaKitDataAsJson(context: Context, gammaKitData: OpenGammaKitData) {
1179-
val jsonFileName = "gamma_data_${System.currentTimeMillis()}.json"
1181+
fun saveGammaKitDataAsJson(context: Context, jsonFileName: String, fileLocation: String, gammaKitData: OpenGammaKitData) {
11801182

11811183
val contentValues = ContentValues().apply {
11821184
put(MediaStore.Files.FileColumns.DISPLAY_NAME, jsonFileName)
11831185
put(MediaStore.Files.FileColumns.MIME_TYPE, "application/json")
1184-
put(MediaStore.Files.FileColumns.RELATIVE_PATH, "Documents/OpenGammaKit/")
1186+
put(MediaStore.Files.FileColumns.RELATIVE_PATH, fileLocation)
11851187
}
11861188

11871189
val contentResolver = context.contentResolver
@@ -1526,8 +1528,8 @@ class SpectrumFragment : SerialConnectionFragment(),
15261528
derivedSpectra = selectedDerivedSpectra
15271529
)
15281530

1529-
// Call save method with the modified data
1530-
saveGammaKitDataAsJson(requireContext(), modifiedData)
1531+
val saveSpectrumIntoFileDialog = SaveSpectrumDataIntoFileDialogFragment.newInstance(modifiedData)
1532+
saveSpectrumIntoFileDialog.show(childFragmentManager, "save_spectrum_into_file_dialog_fragment")
15311533
}
15321534

15331535
private fun toggleSavitzkyGolayFilter() {
@@ -1666,6 +1668,14 @@ class SpectrumFragment : SerialConnectionFragment(),
16661668
}
16671669
}
16681670

1671+
override fun onSaveToFile(
1672+
fileName: String,
1673+
locationUri: String,
1674+
spectrumData: OpenGammaKitData
1675+
) {
1676+
saveGammaKitDataAsJson(requireContext(), fileName, locationUri, spectrumData)
1677+
}
1678+
16691679
companion object {
16701680
fun getLineColor(context: Context, index: Int): Int {
16711681
val colors = listOf(
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package io.github.vikulin.opengammakit.view
2+
3+
import android.content.Context
4+
import android.os.Bundle
5+
import android.view.*
6+
import android.widget.*
7+
import androidx.activity.result.contract.ActivityResultContracts
8+
import androidx.documentfile.provider.DocumentFile
9+
import androidx.fragment.app.DialogFragment
10+
import io.github.vikulin.opengammakit.R
11+
import io.github.vikulin.opengammakit.model.OpenGammaKitData
12+
import java.text.SimpleDateFormat
13+
import java.util.Date
14+
import java.util.Locale
15+
16+
class SaveSpectrumDataIntoFileDialogFragment : DialogFragment() {
17+
18+
private lateinit var fileNameEditText: TextView
19+
private lateinit var selectedLocationText: TextView
20+
21+
companion object {
22+
private const val SPECTRUM_DATA = "spectrum_data_to_save"
23+
24+
fun newInstance(spectrumData: OpenGammaKitData): SaveSpectrumDataIntoFileDialogFragment {
25+
val fragment = SaveSpectrumDataIntoFileDialogFragment()
26+
val args = Bundle()
27+
args.putSerializable(SPECTRUM_DATA, spectrumData)
28+
fragment.arguments = args
29+
return fragment
30+
}
31+
}
32+
33+
interface SaveSpectrumDataIntoFileListener {
34+
fun onSaveToFile(fileName: String, locationUri: String, spectrumData: OpenGammaKitData)
35+
}
36+
37+
private var saveSpectrumListener: SaveSpectrumDataIntoFileListener? = null
38+
39+
override fun onAttach(context: Context) {
40+
super.onAttach(context)
41+
saveSpectrumListener = when {
42+
parentFragment is SaveSpectrumDataIntoFileListener -> parentFragment as SaveSpectrumDataIntoFileListener
43+
context is SaveSpectrumDataIntoFileListener -> context
44+
else -> throw IllegalStateException("Host must implement SaveSpectrumListener")
45+
}
46+
}
47+
48+
override fun onDetach() {
49+
super.onDetach()
50+
saveSpectrumListener = null
51+
}
52+
53+
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
54+
val view = inflater.inflate(R.layout.dialog_spectrum_file_save, container, false)
55+
56+
fileNameEditText = view.findViewById<EditText>(R.id.fileNameEditText)
57+
val selectLocationButton = view.findViewById<ImageButton>(R.id.selectLocationButton)
58+
selectedLocationText = view.findViewById<TextView>(R.id.selectedLocationText)
59+
val saveButton = view.findViewById<Button>(R.id.saveButton)
60+
val formatter = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
61+
val timestamp = formatter.format(Date())
62+
val fileName = "spectrum_$timestamp.json"
63+
fileNameEditText.setText(fileName)
64+
selectedLocationText.text = "Documents/OpenGammaKit/"
65+
selectLocationButton.setOnClickListener {
66+
val name = fileNameEditText.text.toString().trim()
67+
if (name.isEmpty()) {
68+
Toast.makeText(context, "Enter a file name first", Toast.LENGTH_SHORT).show()
69+
} else {
70+
createDocumentLauncher.launch(name)
71+
}
72+
}
73+
74+
val spectrumData = arguments?.getSerializable(SPECTRUM_DATA) as? OpenGammaKitData
75+
?: return view
76+
saveButton.setOnClickListener {
77+
val fileName = fileNameEditText.text.toString().trim()
78+
val uri = selectedLocationText.text
79+
80+
when {
81+
fileName.isEmpty() -> {
82+
Toast.makeText(context, "Please enter a file name", Toast.LENGTH_SHORT).show()
83+
}
84+
uri == null -> {
85+
Toast.makeText(context, "Please select a save location", Toast.LENGTH_SHORT).show()
86+
}
87+
else -> {
88+
saveSpectrumListener?.onSaveToFile(fileName, uri.toString(), spectrumData)
89+
dismiss()
90+
}
91+
}
92+
}
93+
94+
return view
95+
}
96+
97+
98+
private val createDocumentLauncher =
99+
registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) { uri ->
100+
if (uri != null) {
101+
// Get URI path and remove file name + extension if present
102+
val rawPath = uri.path ?: uri.toString()
103+
val cleanedPath = rawPath
104+
.substringBeforeLast('/')
105+
.substringAfterLast(':')
106+
val fileName = rawPath.substringAfterLast('/')
107+
fileNameEditText.text = fileName
108+
selectedLocationText.text = cleanedPath
109+
110+
val docFile = DocumentFile.fromSingleUri(requireContext(), uri)
111+
if (docFile?.delete() != true) {
112+
Toast.makeText(requireContext(), "Delete not supported", Toast.LENGTH_SHORT).show()
113+
}
114+
} else {
115+
Toast.makeText(requireContext(), "File creation canceled", Toast.LENGTH_SHORT).show()
116+
}
117+
}
118+
}

app/src/main/res/layout/dialog_spectrum_file_chooser.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
android:layout_width="match_parent"
66
android:layout_height="wrap_content"
77
android:padding="20dp"
8-
android:orientation="vertical"
98
android:background="@drawable/dialog_rounded_corner">
109

1110
<TextView
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<androidx.constraintlayout.widget.ConstraintLayout
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
xmlns:app="http://schemas.android.com/apk/res-auto"
5+
android:layout_width="match_parent"
6+
android:layout_height="wrap_content"
7+
android:padding="20dp"
8+
android:background="@drawable/dialog_rounded_corner">
9+
10+
<TextView
11+
android:id="@+id/dialogTitle"
12+
android:layout_width="match_parent"
13+
android:layout_height="wrap_content"
14+
android:gravity="center"
15+
android:text="Choose file name and location"
16+
android:textColor="@color/colorPrimaryText"
17+
android:textSize="18sp"
18+
app:layout_constraintTop_toTopOf="parent"
19+
app:layout_constraintStart_toStartOf="parent"
20+
app:layout_constraintEnd_toEndOf="parent" />
21+
22+
<EditText
23+
android:id="@+id/fileNameEditText"
24+
android:layout_width="0dp"
25+
android:layout_height="wrap_content"
26+
android:hint="Enter file name"
27+
android:inputType="text"
28+
android:textSize="16sp"
29+
android:layout_marginTop="12dp"
30+
app:layout_constraintTop_toBottomOf="@id/dialogTitle"
31+
app:layout_constraintStart_toStartOf="parent"
32+
app:layout_constraintEnd_toEndOf="parent" />
33+
34+
<TextView
35+
android:id="@+id/locationLabel"
36+
android:layout_width="0dp"
37+
android:layout_height="wrap_content"
38+
android:text="Save location:"
39+
android:layout_marginTop="12dp"
40+
app:layout_constraintTop_toBottomOf="@id/fileNameEditText"
41+
app:layout_constraintStart_toStartOf="parent"
42+
app:layout_constraintEnd_toEndOf="parent" />
43+
44+
<LinearLayout
45+
android:id="@+id/locationSelectorLayout"
46+
android:layout_width="0dp"
47+
android:layout_height="wrap_content"
48+
android:orientation="horizontal"
49+
android:layout_marginTop="4dp"
50+
app:layout_constraintTop_toBottomOf="@id/locationLabel"
51+
app:layout_constraintStart_toStartOf="parent"
52+
app:layout_constraintEnd_toEndOf="parent">
53+
54+
<TextView
55+
android:id="@+id/selectedLocationText"
56+
android:layout_width="0dp"
57+
android:layout_height="wrap_content"
58+
android:layout_weight="1"
59+
android:hint="Enter folder path"
60+
android:layout_gravity="center_vertical"
61+
android:ellipsize="end"
62+
android:maxLines="1" />
63+
64+
<ImageButton
65+
android:id="@+id/selectLocationButton"
66+
android:layout_width="wrap_content"
67+
android:layout_height="wrap_content"
68+
android:src="@drawable/ic_file_picker"
69+
android:contentDescription="Select folder"
70+
android:background="?attr/selectableItemBackgroundBorderless"
71+
app:tint="@color/colorPrimary"/>
72+
</LinearLayout>
73+
74+
<Button
75+
android:id="@+id/saveButton"
76+
android:layout_width="0dp"
77+
android:layout_height="wrap_content"
78+
android:text="Save"
79+
android:textAllCaps="false"
80+
android:layout_marginTop="16dp"
81+
app:layout_constraintTop_toBottomOf="@id/locationSelectorLayout"
82+
app:layout_constraintStart_toStartOf="parent"
83+
app:layout_constraintEnd_toEndOf="parent"
84+
app:layout_constraintBottom_toBottomOf="parent" />
85+
86+
</androidx.constraintlayout.widget.ConstraintLayout>

app/src/main/res/layout/dialog_spectrum_save.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<androidx.recyclerview.widget.RecyclerView
2323
android:id="@+id/spectrumRecyclerView"
2424
android:layout_width="match_parent"
25-
android:layout_height="200dp"
25+
android:layout_height="wrap_content"
2626
android:layout_marginTop="12dp"
2727
app:layout_constraintTop_toBottomOf="@id/dialogTitle"
2828
app:layout_constraintStart_toStartOf="parent"

app/src/main/res/layout/dialog_spectrum_selection.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<androidx.recyclerview.widget.RecyclerView
2323
android:id="@+id/spectrumRecyclerView"
2424
android:layout_width="match_parent"
25-
android:layout_height="200dp"
25+
android:layout_height="wrap_content"
2626
app:layout_constraintEnd_toEndOf="parent"
2727
app:layout_constraintStart_toStartOf="parent"
2828
app:layout_constraintTop_toBottomOf="@id/dialogTitle" />

app/src/main/res/layout/item_save_spectrum.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
android:layout_height="wrap_content"
2121
android:text="Spectrum #1"
2222
android:textColor="@color/colorPrimaryText"
23-
android:textSize="18sp"
23+
android:textSize="14sp"
2424
android:layout_weight="1"
2525
android:gravity="center_vertical" />
2626

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
2-
agp = "8.9.2"
2+
agp = "8.10.0"
33
kotlin = "2.0.21"
4-
coreKtx = "1.15.0"
4+
coreKtx = "1.16.0"
55
junit = "4.13.2"
66
junitVersion = "1.2.1"
77
espressoCore = "3.6.1"

0 commit comments

Comments
 (0)