Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]
### Added
- Option to customize recording filename pattern with datetime placeholders ([#15])
- Added support for custom fonts

### Changed
Expand Down Expand Up @@ -132,6 +133,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- Initial release

[#15]: https://github.com/FossifyOrg/Voice-Recorder/issues/15
[#16]: https://github.com/FossifyOrg/Voice-Recorder/issues/16
[#22]: https://github.com/FossifyOrg/Voice-Recorder/issues/22
[#33]: https://github.com/FossifyOrg/Voice-Recorder/issues/33
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.fossify.commons.helpers.sumByInt
import org.fossify.commons.models.RadioItem
import org.fossify.voicerecorder.R
import org.fossify.voicerecorder.databinding.ActivitySettingsBinding
import org.fossify.voicerecorder.dialogs.FilenamePatternDialog
import org.fossify.voicerecorder.dialogs.MoveRecordingsDialog
import org.fossify.voicerecorder.extensions.config
import org.fossify.voicerecorder.extensions.deleteTrashedRecordings
Expand Down Expand Up @@ -67,6 +68,7 @@ class SettingsActivity : SimpleActivity() {
setupLanguage()
setupChangeDateTimeFormat()
setupSaveRecordingsFolder()
setupFilenamePattern()
setupExtension()
setupBitrate()
setupSamplingRate()
Expand All @@ -81,6 +83,7 @@ class SettingsActivity : SimpleActivity() {
binding.settingsColorCustomizationSectionLabel,
binding.settingsGeneralSettingsLabel,
binding.settingsRecordingSectionLabel,
binding.settingsAudioSectionLabel,
binding.settingsRecycleBinLabel
).forEach {
it.setTextColor(getProperPrimaryColor())
Expand Down Expand Up @@ -166,6 +169,15 @@ class SettingsActivity : SimpleActivity() {
}
}

private fun setupFilenamePattern() {
binding.settingsFilenamePattern.text = config.filenamePattern
binding.settingsFilenamePatternHolder.setOnClickListener {
FilenamePatternDialog(this) { newPattern ->
binding.settingsFilenamePattern.text = newPattern
}
}
}

private fun setupExtension() {
binding.settingsExtension.text = config.getExtensionText()
binding.settingsExtensionHolder.setOnClickListener {
Expand Down Expand Up @@ -211,7 +223,7 @@ class SettingsActivity : SimpleActivity() {
val currentBitrate = config.bitrate
val closestBitrate = availableBitrates.minByOrNull { abs(it - currentBitrate) }
?: DEFAULT_BITRATE

config.bitrate = closestBitrate
binding.settingsBitrate.text = getBitrateText(config.bitrate)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package org.fossify.voicerecorder.dialogs

import org.fossify.commons.activities.BaseSimpleActivity
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.extensions.viewBinding
import org.fossify.voicerecorder.databinding.DatetimePatternInfoLayoutBinding

class DateTimePatternInfoDialog(activity: BaseSimpleActivity) {
val binding by activity.viewBinding(DatetimePatternInfoLayoutBinding::inflate)

init {
activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok) { _, _ -> { } }
.apply {
activity.setupDialogStuff(binding.root, this)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.fossify.voicerecorder.dialogs

import androidx.appcompat.app.AlertDialog
import androidx.core.widget.doAfterTextChanged
import org.fossify.commons.extensions.getAlertDialogBuilder
import org.fossify.commons.extensions.setupDialogStuff
import org.fossify.commons.extensions.viewBinding
import org.fossify.voicerecorder.R
import org.fossify.voicerecorder.activities.SimpleActivity
import org.fossify.voicerecorder.databinding.DialogFilenamePatternBinding
import org.fossify.voicerecorder.extensions.config

class FilenamePatternDialog(private val activity: SimpleActivity, private val callback: (String) -> Unit) {
private val binding by activity.viewBinding(DialogFilenamePatternBinding::inflate)
private val config = activity.config
private var dialog: AlertDialog? = null

init {
binding.apply {
filenamePatternValue.setText(config.filenamePattern)
filenamePatternHint.setEndIconOnClickListener {
DateTimePatternInfoDialog(activity)
}
filenamePatternHint.setEndIconOnLongClickListener {
DateTimePatternInfoDialog(activity)
true
}

filenamePatternValue.doAfterTextChanged { validatePattern(it?.toString().orEmpty()) }
}

activity.getAlertDialogBuilder()
.setPositiveButton(org.fossify.commons.R.string.ok, null)
.setNegativeButton(org.fossify.commons.R.string.cancel, null)
.apply {
activity.setupDialogStuff(binding.root, this, R.string.filename_pattern) { alertDialog ->
dialog = alertDialog
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
val newPattern = binding.filenamePatternValue.text.toString()
config.filenamePattern = newPattern
callback(newPattern)
alertDialog.dismiss()
}
}
}
}

private fun validatePattern(pattern: String) {
binding.filenamePatternHint.error = when {
pattern.isEmpty() -> activity.getString(org.fossify.commons.R.string.filename_cannot_be_empty)
!containsAllDateTimePlaceholders(pattern) -> activity.getString(R.string.filename_pattern_must_contain_all)
else -> null
}
val isValid = binding.filenamePatternHint.error.isNullOrEmpty()
dialog?.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = isValid
}

private fun containsAllDateTimePlaceholders(pattern: String): Boolean {
return pattern.contains("%Y") && pattern.contains("%M") && pattern.contains("%D") &&
pattern.contains("%h") && pattern.contains("%m") && pattern.contains("%s")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Environment
import android.provider.DocumentsContract
import androidx.core.graphics.createBitmap
import androidx.documentfile.provider.DocumentFile
import org.fossify.commons.extensions.createFirstParentTreeUri
import org.fossify.commons.extensions.createSAFDirectorySdk30
Expand All @@ -33,6 +34,8 @@ import org.fossify.voicerecorder.helpers.MyWidgetRecordDisplayProvider
import org.fossify.voicerecorder.helpers.TOGGLE_WIDGET_UI
import org.fossify.voicerecorder.models.Recording
import java.io.File
import java.util.Calendar
import java.util.Locale
import kotlin.math.roundToLong

val Context.config: Config get() = Config.newInstance(applicationContext)
Expand All @@ -42,7 +45,7 @@ val Context.trashFolder

fun Context.drawableToBitmap(drawable: Drawable): Bitmap {
val size = (60 * resources.displayMetrics.density).toInt()
val mutableBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
val mutableBitmap = createBitmap(size, size)
val canvas = Canvas(mutableBitmap)
drawable.setBounds(0, 0, size, size)
drawable.draw(canvas)
Expand Down Expand Up @@ -235,3 +238,24 @@ fun Context.createDocumentFile(path: String): Uri? {
null
}
}

// move to commons in the future
fun Context.getFormattedFilename(): String {
val pattern = config.filenamePattern
val calendar = Calendar.getInstance()

val year = calendar.get(Calendar.YEAR).toString()
val month = String.format(Locale.ROOT, "%02d", calendar.get(Calendar.MONTH) + 1)
val day = String.format(Locale.ROOT, "%02d", calendar.get(Calendar.DAY_OF_MONTH))
val hour = String.format(Locale.ROOT, "%02d", calendar.get(Calendar.HOUR_OF_DAY))
val minute = String.format(Locale.ROOT, "%02d", calendar.get(Calendar.MINUTE))
val second = String.format(Locale.ROOT, "%02d", calendar.get(Calendar.SECOND))

return pattern
.replace("%Y", year, false)
.replace("%M", month, false)
.replace("%D", day, false)
.replace("%h", hour, false)
.replace("%m", minute, false)
.replace("%s", second, false)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package org.fossify.voicerecorder.helpers
import android.annotation.SuppressLint
import android.content.Context
import android.media.MediaRecorder
import androidx.core.content.edit
import org.fossify.commons.helpers.BaseConfig
import org.fossify.voicerecorder.R
import org.fossify.voicerecorder.extensions.getDefaultRecordingsFolder
import androidx.core.content.edit

class Config(context: Context) : BaseConfig(context) {
companion object {
Expand Down Expand Up @@ -96,4 +96,8 @@ class Config(context: Context) : BaseConfig(context) {
set(wasMicModeWarningShown) = prefs.edit {
putBoolean(WAS_MIC_MODE_WARNING_SHOWN, wasMicModeWarningShown)
}

var filenamePattern: String
get() = prefs.getString(FILENAME_PATTERN, DEFAULT_FILENAME_PATTERN)!!
set(filenamePattern) = prefs.edit { putString(FILENAME_PATTERN, filenamePattern) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,7 @@ const val USE_RECYCLE_BIN = "use_recycle_bin"
const val LAST_RECYCLE_BIN_CHECK = "last_recycle_bin_check"
const val KEEP_SCREEN_ON = "keep_screen_on"
const val WAS_MIC_MODE_WARNING_SHOWN = "was_mic_mode_warning_shown"
const val FILENAME_PATTERN = "filename_pattern"

const val DEFAULT_RECORDINGS_FOLDER = "Recordings"
const val DEFAULT_FILENAME_PATTERN = "%Y%M%D_%h%m%s"
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.media.MediaScannerConnection
import android.net.Uri
Expand All @@ -16,7 +15,6 @@ import androidx.core.app.NotificationCompat
import androidx.core.content.FileProvider
import org.fossify.commons.extensions.createDocumentUriUsingFirstParentTreeUri
import org.fossify.commons.extensions.createSAFFileSdk30
import org.fossify.commons.extensions.getCurrentFormattedDateTime
import org.fossify.commons.extensions.getDocumentFile
import org.fossify.commons.extensions.getFilenameFromPath
import org.fossify.commons.extensions.getLaunchIntent
Expand All @@ -31,6 +29,7 @@ import org.fossify.voicerecorder.BuildConfig
import org.fossify.voicerecorder.R
import org.fossify.voicerecorder.activities.SplashActivity
import org.fossify.voicerecorder.extensions.config
import org.fossify.voicerecorder.extensions.getFormattedFilename
import org.fossify.voicerecorder.extensions.updateWidgets
import org.fossify.voicerecorder.helpers.CANCEL_RECORDING
import org.fossify.voicerecorder.helpers.EXTENSION_MP3
Expand Down Expand Up @@ -105,7 +104,7 @@ class RecorderService : Service() {
}

val recordingFolder = defaultFolder.absolutePath
recordingPath = "$recordingFolder/${getCurrentFormattedDateTime()}.${config.getExtension()}"
recordingPath = "$recordingFolder/${getFormattedFilename()}.${config.getExtension()}"
resultUri = null

try {
Expand Down Expand Up @@ -280,8 +279,7 @@ class RecorderService : Service() {
private fun showNotification(): Notification {
val channelId = "simple_recorder"
val label = getString(R.string.app_name)
val notificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

NotificationChannel(channelId, label, NotificationManager.IMPORTANCE_DEFAULT).apply {
setSound(null, null)
Expand Down
38 changes: 36 additions & 2 deletions app/src/main/res/layout/activity_settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
<org.fossify.commons.views.PurchaseThankYouItem
android:id="@+id/settings_purchase_thank_you_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content" />

<RelativeLayout
android:id="@+id/settings_use_english_holder"
Expand Down Expand Up @@ -209,6 +209,29 @@

</RelativeLayout>

<RelativeLayout
android:id="@+id/settings_filename_pattern_holder"
style="@style/SettingsHolderTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<org.fossify.commons.views.MyTextView
android:id="@+id/settings_filename_pattern_label"
style="@style/SettingsTextLabelStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/filename_pattern" />

<org.fossify.commons.views.MyTextView
android:id="@+id/settings_filename_pattern"
style="@style/SettingsTextValueStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/settings_filename_pattern_label"
tools:text="%Y%M%D_%h%m%s" />

</RelativeLayout>

<RelativeLayout
android:id="@+id/settings_extension_holder"
style="@style/SettingsHolderTextViewStyle"
Expand All @@ -232,6 +255,17 @@

</RelativeLayout>

<include
android:id="@+id/settings_recording_divider"
layout="@layout/divider" />

<TextView
android:id="@+id/settings_audio_section_label"
style="@style/SettingsSectionLabelStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/audio" />

<RelativeLayout
android:id="@+id/settings_bitrate_holder"
style="@style/SettingsHolderTextViewStyle"
Expand Down Expand Up @@ -301,7 +335,7 @@
</RelativeLayout>

<include
android:id="@+id/settings_recording_divider"
android:id="@+id/settings_audio_divider"
layout="@layout/divider" />

<TextView
Expand Down
9 changes: 9 additions & 0 deletions app/src/main/res/layout/datetime_pattern_info_layout.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<org.fossify.commons.views.MyTextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/date_time_pattern_info"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingHorizontal="@dimen/big_margin"
android:paddingTop="@dimen/big_margin"
android:text="@string/date_time_pattern_info"
android:textIsSelectable="true" />
36 changes: 36 additions & 0 deletions app/src/main/res/layout/dialog_filename_pattern.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dialog_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_margin"
android:paddingTop="@dimen/activity_margin"
android:paddingRight="@dimen/activity_margin">

<org.fossify.commons.views.MyTextInputLayout
android:id="@+id/filename_pattern_hint"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/filename_pattern"
app:boxStrokeErrorColor="@color/color_error"
app:endIconDrawable="@drawable/ic_info_vector"
app:endIconMode="custom"
app:errorEnabled="true"
app:errorIconDrawable="@null"
app:errorTextColor="@color/color_error">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/filename_pattern_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textNoSuggestions"
android:singleLine="true"
android:textCursorDrawable="@null"
android:textSize="@dimen/bigger_text_size"
tools:text="Recording %Y%M%D_%h%m%s" />

</org.fossify.commons.views.MyTextInputLayout>
</LinearLayout>
4 changes: 4 additions & 0 deletions app/src/main/res/values-night/colors.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="color_error">@color/md_red_400</color>
</resources>
1 change: 1 addition & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="default_widget_bg_color">#FFF57C00</color>
<color name="color_error">@color/md_red_500_dark</color>
</resources>
Loading